Commit e8fb762f authored by Raph Levien's avatar Raph Levien

Added new modular rendering architecture and gradients to libart.

parent 5a4c9aed
Mon May 29 13:48:49 2000 Raph Levien <raph@acm.org>
This is a fairly major commit, as it adds both the new, modular
rendering architecture and gradients. Quite a bit of the code
feels like "reference code" now, in that it is (hopefully)
correct, but not necessarily very fast. In addition, there remain
a few things not done, including the use of SVP's as non-driver
mask sources. AlphaGamma and filter level also remain
unimplemented. No compositing modes other than ART_NORMAL are
implemented. All in good time!
* configure.in: added -Wmissing-prototypes flag. Bumped version
number to 2.3.0.
* art_render.h:
* art_render.c: Added new rendering architecture.
* art_render_svp.h:
* art_render_svp.c: Added renderers to use SVP's as mask
sources in new rendering architecture.
* art_render_gradient.h:
* art_render_gradient.c: Added linear and radial gradients
as image sources in new rendering architecture.
* art_svp_wind.c: Added static to trap_epsilon(), #ifdef'd out
traverse().
* art_uta_ops.c: Added #include "art_uta_ops.h".
* art_uta_rect.c: Added #include "art_uta_rect.h".
* art_uta_svp.h: fixed __ART_UTA_SVP_H__ name.
* art_misc.h: Added ART_GNUC_NORETURN attribute, added that
to the prototype for art_die(). Added "static" to function
declarations to avoid warnings when compiled with
* testart.c: Added gradient test.
Thu May 25 23:30:39 2000 Raph Levien <raph@acm.org>
* art_svp_render_aa.h:
......
......@@ -25,6 +25,12 @@ libart_lgpl_la_SOURCES = \
art_rect.c \
art_rect_svp.c \
art_rect_uta.c \
art_render.c \
art_render.h \
art_render_gradient.c \
art_render_gradient.h \
art_render_svp.c \
art_render_svp.h \
art_rgb.c \
art_rgb_affine.c \
art_rgb_affine_private.c \
......
......@@ -66,15 +66,18 @@ typedef int art_boolean;
#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4))
#define ART_GNUC_PRINTF( format_idx, arg_idx ) \
__attribute__((format (printf, format_idx, arg_idx)))
#define ART_GNUC_NORETURN \
__attribute__((noreturn))
#else /* !__GNUC__ */
#define ART_GNUC_PRINTF( format_idx, arg_idx )
#define ART_GNUC_NORETURN
#endif /* !__GNUC__ */
#ifdef __cplusplus
extern "C" {
#endif
void
void ART_GNUC_NORETURN
art_die (const char *fmt, ...) ART_GNUC_PRINTF (1, 2);
void
......
This diff is collapsed.
/*
* art_render.h: Modular rendering architecture.
*
* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 2000 Raph Levien
*
* This library 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 library 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __ART_RENDER_H__
#define __ART_RENDER_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Render object */
#ifndef ART_MAX_DEPTH
#define ART_MAX_DEPTH 16
#endif
#if ART_MAX_DEPTH == 16
typedef art_u16 ArtPixMaxDepth;
#define ART_PIX_MAX_FROM_8(x) ((x) | ((x) << 8))
#define ART_PIX_8_FROM_MAX(x) (((x) + 0x80 - (((x) + 0x80) >> 8)) >> 8)
#else
#if ART_MAX_DEPTH == 8
typedef art_u8 ArtPixMaxDepth;
#define ART_PIX_MAX_FROM_8(x) (x)
#define ART_PIX_8_FROM_MAX(x) (x)
#else
#error ART_MAX_DEPTH must be either 8 or 16
#endif
#endif
#define ART_MAX_CHAN 16
typedef struct _ArtRender ArtRender;
typedef struct _ArtRenderCallback ArtRenderCallback;
typedef struct _ArtRenderMaskRun ArtRenderMaskRun;
typedef struct _ArtImageSource ArtImageSource;
typedef struct _ArtMaskSource ArtMaskSource;
typedef enum {
ART_ALPHA_NONE = 0,
ART_ALPHA_SEPARATE = 1,
ART_ALPHA_PREMUL = 2
} ArtAlphaType;
typedef enum {
ART_COMPOSITE_NORMAL,
ART_COMPOSITE_MULTIPLY,
/* todo: more */
ART_COMPOSITE_CUSTOM
} ArtCompositingMode;
typedef enum {
ART_IMAGE_SOURCE_CAN_CLEAR = 1,
ART_IMAGE_SOURCE_CAN_COMPOSITE = 2
} ArtImageSourceFlags;
struct _ArtRenderMaskRun {
int x;
int alpha;
};
struct _ArtRenderCallback {
void (*render) (ArtRenderCallback *self, ArtRender *render,
art_u8 *dest, int y);
void (*done) (ArtRenderCallback *self, ArtRender *render);
};
struct _ArtImageSource {
ArtRenderCallback super;
void (*negotiate) (ArtImageSource *self, ArtRender *render,
ArtImageSourceFlags *p_flags,
int *p_buf_depth, ArtAlphaType *p_alpha_type);
};
struct _ArtMaskSource {
ArtRenderCallback super;
int (*can_drive) (ArtMaskSource *self, ArtRender *render);
/* For each mask source, ::prepare() is invoked if it is not
a driver, or ::invoke_driver() if it is. */
void (*invoke_driver) (ArtMaskSource *self, ArtRender *render);
void (*prepare) (ArtMaskSource *self, ArtRender *render, art_boolean first);
};
struct _ArtRender {
/* parameters of destination image */
int x0, y0;
int x1, y1;
art_u8 *pixels;
int rowstride;
int n_chan;
int depth;
ArtAlphaType alpha_type;
art_boolean clear;
ArtPixMaxDepth clear_color[ART_MAX_CHAN + 1];
art_u32 opacity; /* [0..0x10000] */
ArtCompositingMode compositing_mode;
ArtAlphaGamma *alphagamma;
art_u8 *alpha_buf;
/* parameters of intermediate buffer */
int buf_depth;
ArtAlphaType buf_alpha;
art_u8 *image_buf;
/* driving alpha scanline data */
/* A "run" is a contiguous sequence of x values with the same alpha value. */
int n_run;
ArtRenderMaskRun *run;
/* A "span" is a contiguous sequence of x values with non-zero alpha. */
int n_span;
int *span_x;
art_boolean need_span;
};
ArtRender *
art_render_new (int x0, int y0, int x1, int y1,
art_u8 *pixels, int rowstride,
int n_chan, int depth, ArtAlphaType alpha_type,
ArtAlphaGamma *alphagamma);
void
art_render_invoke (ArtRender *render);
void
art_render_clear (ArtRender *render, const ArtPixMaxDepth *clear_color);
void
art_render_clear_rgb (ArtRender *render, art_u32 clear_rgb);
void
art_render_mask_solid (ArtRender *render, int opacity);
void
art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color);
/* The next two functions are for custom mask sources only. */
void
art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source);
void
art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y);
/* The following function is for custom image sources only. */
void
art_render_add_image_source (ArtRender *render, ArtImageSource *image_source);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __ART_RENDER_H__ */
/*
* art_render_gradient.c: Gradient image source for modular rendering.
*
* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 2000 Raph Levien
*
* This library 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 library 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors: Raph Levien <raph@acm.org>
* Alexander Larsson <alla@lysator.liu.se>
*/
#include <math.h>
#include "art_misc.h"
#include "art_alphagamma.h"
#include "art_filterlevel.h"
#include "art_render.h"
#include "art_render_gradient.h"
typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin;
typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad;
struct _ArtImageSourceGradLin {
ArtImageSource super;
const ArtGradientLinear *gradient;
};
struct _ArtImageSourceGradRad {
ArtImageSource super;
const ArtGradientRadial *gradient;
double a;
};
#define EPSILON 1e-6
/**
* art_render_gradient_setpix: Set a gradient pixel.
* @render: The render object.
* @dst: Pointer to destination (where to store pixel).
* @n_stops: Number of stops in @stops.
* @stops: The stops for the gradient.
* @offset: The offset.
*
* @n_stops must be > 0.
*
* Sets a gradient pixel, storing it at @dst.
**/
static void
art_render_gradient_setpix (ArtRender *render,
art_u8 *dst,
int n_stops, ArtGradientStop *stops,
double offset)
{
int ix;
int j;
double off0, off1;
int n_ch = render->n_chan + 1;
for (ix = 0; ix < n_stops; ix++)
if (stops[ix].offset > offset)
break;
/* stops[ix - 1].offset < offset < stops[ix].offset */
if (ix > 0 && ix < n_stops)
{
off0 = stops[ix - 1].offset;
off1 = stops[ix].offset;
if (fabs (off1 - off0) > EPSILON)
{
double interp;
interp = (offset - off0) / (off1 - off0);
for (j = 0; j < n_ch; j++)
{
int z0, z1;
int z;
z0 = stops[ix - 1].color[j];
z1 = stops[ix].color[j];
z = floor (z0 + (z1 - z0) * interp + 0.5);
if (render->buf_depth == 8)
dst[j] = ART_PIX_8_FROM_MAX (z);
else /* (render->buf_depth == 16) */
((art_u16 *)dst)[j] = z;
}
return;
}
}
else if (ix == n_stops)
ix--;
for (j = 0; j < n_ch + 1; j++)
{
int z;
z = stops[ix].color[j];
if (render->buf_depth == 8)
dst[j] = ART_PIX_8_FROM_MAX (z);
else /* (render->buf_depth == 16) */
((art_u16 *)dst)[j] = z;
}
}
static void
art_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render)
{
art_free (self);
}
static void
art_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render,
art_u8 *dest, int y)
{
ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
const ArtGradientLinear *gradient = z->gradient;
int pixstride = (render->n_chan + 1) * (render->depth >> 3);
int x;
int width = render->x1 - render->x0;
double offset, d_offset;
double actual_offset;
int n_stops = gradient->n_stops;
ArtGradientStop *stops = gradient->stops;
art_u8 *bufp = render->image_buf;
ArtGradientSpread spread = gradient->spread;
offset = render->x0 * gradient->a + y * gradient->b + gradient->c;
d_offset = gradient->a;
for (x = 0; x < width; x++)
{
if (spread == ART_GRADIENT_PAD)
actual_offset = offset;
else if (spread == ART_GRADIENT_REPEAT)
actual_offset = offset - floor (offset);
else /* (spread == ART_GRADIENT_REFLECT) */
{
double tmp;
tmp = offset - 2 * floor (0.5 * offset);
actual_offset = tmp > 1 ? 2 - tmp : tmp;
}
art_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset);
offset += d_offset;
bufp += pixstride;
}
}
static void
art_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render,
ArtImageSourceFlags *p_flags,
int *p_buf_depth, ArtAlphaType *p_alpha)
{
self->super.render = art_render_gradient_linear_render;
*p_flags = 0;
*p_buf_depth = render->depth;
*p_alpha = ART_ALPHA_PREMUL;
}
/**
* art_render_gradient_linear: Add a linear gradient image source.
* @render: The render object.
* @gradient: The linear gradient.
*
* Adds the linear gradient @gradient as the image source for rendering
* in the render object @render.
**/
void
art_render_gradient_linear (ArtRender *render,
const ArtGradientLinear *gradient,
ArtFilterLevel level)
{
ArtImageSourceGradLin *image_source = art_new (ArtImageSourceGradLin, 1);
image_source->super.super.render = NULL;
image_source->super.super.done = art_render_gradient_linear_done;
image_source->super.negotiate = art_render_gradient_linear_negotiate;
image_source->gradient = gradient;
art_render_add_image_source (render, &image_source->super);
}
static void
art_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render)
{
art_free (self);
}
static void
art_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render,
art_u8 *dest, int y)
{
ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self;
const ArtGradientRadial *gradient = z->gradient;
int pixstride = (render->n_chan + 1) * (render->depth >> 3);
int x;
int x0 = render->x0;
int width = render->x1 - x0;
int n_stops = gradient->n_stops;
ArtGradientStop *stops = gradient->stops;
art_u8 *bufp = render->image_buf;
double fx = gradient->fx;
double fy = gradient->fy;
double dx, dy;
double *affine = gradient->affine;
double aff0 = affine[0];
double aff1 = affine[1];
const double a = z->a;
const double arecip = 1.0 / a;
double b, db;
double c, dc, ddc;
double b_a, db_a;
double rad, drad, ddrad;
dx = x0 * aff0 + y * affine[2] + affine[4] - fx;
dy = x0 * aff1 + y * affine[3] + affine[5] - fy;
b = dx * fx + dy * fy;
db = aff0 * fx + aff1 * fy;
c = dx * dx + dy * dy;
dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1;
ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1;
b_a = b * arecip;
db_a = db * arecip;
rad = b_a * b_a + c * arecip;
drad = 2 * b_a * db_a + db_a * db_a + dc * arecip;
ddrad = 2 * db_a * db_a + ddc * arecip;
for (x = 0; x < width; x++)
{
double z;
if (rad > 0)
z = b_a + sqrt (rad);
else
z = b_a;
art_render_gradient_setpix (render, bufp, n_stops, stops, z);
bufp += pixstride;
b_a += db_a;
rad += drad;
drad += ddrad;
}
}
static void
art_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render,
ArtImageSourceFlags *p_flags,
int *p_buf_depth, ArtAlphaType *p_alpha)
{
self->super.render = art_render_gradient_radial_render;
*p_flags = 0;
*p_buf_depth = render->depth;
*p_alpha = ART_ALPHA_PREMUL;
}
/**
* art_render_gradient_radial: Add a radial gradient image source.
* @render: The render object.
* @gradient: The radial gradient.
*
* Adds the radial gradient @gradient as the image source for rendering
* in the render object @render.
**/
void
art_render_gradient_radial (ArtRender *render,
const ArtGradientRadial *gradient,
ArtFilterLevel level)
{
ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1);
double fx = gradient->fx;
double fy = gradient->fy;
image_source->super.super.render = NULL;
image_source->super.super.done = art_render_gradient_radial_done;
image_source->super.negotiate = art_render_gradient_radial_negotiate;
image_source->gradient = gradient;
/* todo: sanitycheck fx, fy? */
image_source->a = 1 - fx * fx - fy * fy;
art_render_add_image_source (render, &image_source->super);
}
/*
* art_render_gradient.h: Gradient image source for modular rendering.
*
* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 2000 Raph Levien
*
* This library 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 library 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors: Raph Levien <raph@acm.org>
* Alexander Larsson <alla@lysator.liu.se>
*/
#ifndef __ART_RENDER_GRADIENT_H__
#define __ART_RENDER_GRADIENT_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct _ArtGradientLinear ArtGradientLinear;
typedef struct _ArtGradientRadial ArtGradientRadial;
typedef struct _ArtGradientStop ArtGradientStop;
typedef enum {
ART_GRADIENT_PAD,
ART_GRADIENT_REFLECT,
ART_GRADIENT_REPEAT
} ArtGradientSpread;
struct _ArtGradientLinear {
double a;
double b;
double c;
ArtGradientSpread spread;
int n_stops;
ArtGradientStop *stops;
};
struct _ArtGradientRadial {
double affine[6]; /* transforms user coordinates to unit circle */
double fx, fy; /* focal point in unit circle coords */
int n_stops;
ArtGradientStop *stops;
};
struct _ArtGradientStop {
double offset;
ArtPixMaxDepth color[ART_MAX_CHAN + 1];
};
void
art_render_gradient_linear (ArtRender *render,
const ArtGradientLinear *gradient,
ArtFilterLevel level);
void
art_render_gradient_radial (ArtRender *render,
const ArtGradientRadial *gradient,
ArtFilterLevel level);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __ART_RENDER_GRADIENT_H__ */
/*
* art_render_gradient.h: SVP mask source for modular rendering.
*
* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 2000 Raph Levien
*
* This library 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 library 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors: Raph Levien <raph@acm.org>
*/
#ifndef __ART_RENDER_SVP_H__
#define __ART_RENDER_SVP_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void
art_render_svp (ArtRender *render, const ArtSVP *svp);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __ART_RENDER_SVP_H__ */
/*
* art_rgba.c: Functions for manipulating RGBA pixel data.
*
* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 2000 Raph Levien
*
* This library 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 library 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <libart_lgpl/art_misc.h>
#include "art_rgba.h"
#define ART_OPTIMIZE_SPACE
#ifndef ART_OPTIMIZE_SPACE
#include "art_rgba_table.c"
#endif
/**
* art_rgba_rgba_composite: Composite RGBA image over RGBA buffer.
* @dst: Destination RGBA buffer.
* @src: Source RGBA buffer.
* @n: Number of RGBA pixels to composite.
*
* Composites the RGBA pixels in @dst over the @src buffer.
**/
void
art_rgba_rgba_composite (art_u8 *dst, const art_u8 *src, int n)
{
int i;
#ifdef WORDS_BIGENDIAN
art_u32 src_rgba, dst_rgba;
#else
art_u32 src_abgr, dst_abgr;
#endif
art_u8 src_alpha, dst_alpha;
for (i = 0; i < n; i++)
{
#ifdef WORDS_BIGENDIAN
src_rgba = ((art_u32 *)src)[i];
src_alpha = src_rgba & 0xff;
#else
src_abgr = ((art_u32 *)src)[i];
src_alpha = (src_abgr >> 24) & 0xff;
#endif
if (src_alpha)
{
if (src_alpha == 0xff ||
(
#ifdef WORDS_BIGENDIAN
dst_rgba = ((art_u32 *)dst)[i],
dst_alpha = dst_rgba & 0xff,
#else
dst_abgr = ((art_u32 *)dst)[i],
dst_alpha = (dst_abgr >> 24),
#endif
dst_alpha == 0))
#ifdef WORDS_BIGENDIAN
((art_u32 *)dst)[i] = src_rgba;
#else
((art_u32 *)dst)[i] = src_abgr;
#endif
else
{
int r, g, b, a;
int src_r, src_g, src_b;
int dst_r, dst_g, dst_b;
int tmp;
int c;