Back to index

scribus-ng  1.3.4.dfsg+svn20071115
art_render_misc.c
Go to the documentation of this file.
00001 /* This file is part of the KDE project.
00002  * art_render_misc.c: Here I store some routines I feel should be in libart :)
00003  *
00004  * Copyright (C) 2002, The Karbon Developers
00005  *
00006  * This code is adapted from :
00007  *
00008  * art_render_gradient.c: Gradient image source for modular rendering.
00009  *
00010  * Libart_LGPL - library of basic graphic primitives
00011  * Copyright (C) 2000 Raph Levien
00012  *
00013  * This library is free software; you can redistribute it and/or
00014  * modify it under the terms of the GNU Library General Public
00015  * License as published by the Free Software Foundation; either
00016  * version 2 of the License, or (at your option) any later version.
00017  *
00018  * This library is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  * Library General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU Library General Public
00024  * License along with this library; if not, write to the
00025  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00026  * Boston, MA 02111-1307, USA.
00027  *
00028  * Authors: Raph Levien <raph@acm.org>
00029  *          Alexander Larsson <alla@lysator.liu.se>
00030  */
00031 
00032 #include "scconfig.h"
00033 
00034 #include "art_render_misc.h"
00035 
00036 #include <math.h>
00037 
00038 typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin;
00039 typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad;
00040 typedef struct _ArtImageSourceGradCon ArtImageSourceGradCon;
00041 
00042 struct _ArtImageSourceGradLin {
00043   ArtImageSource super;
00044   const ArtGradientLinear *gradient;
00045 };
00046 
00047 struct _ArtImageSourceGradRad {
00048   ArtImageSource super;
00049   const ArtGradientRadial *gradient;
00050   double a;
00051 };
00052 
00053 struct _ArtImageSourceGradCon {
00054   ArtImageSource super;
00055   const ArtGradientConical *gradient;
00056 };
00057 
00058 
00059 #define EPSILON 1e-6
00060 
00073 static void
00074 art_karbon_render_gradient_setpix (ArtRender *render,
00075                          art_u8 *dst,
00076                          int n_stops, ArtGradientStop *stops,
00077                          double offset)
00078 {
00079   int ix;
00080   int j;
00081   double off0, off1;
00082   int n_ch = render->n_chan + 1;
00083 
00084   for (ix = 0; ix < n_stops; ix++)
00085     if (stops[ix].offset > offset)
00086       break;
00087   /* stops[ix - 1].offset < offset < stops[ix].offset */
00088   if (ix > 0 && ix < n_stops)
00089     {
00090       off0 = stops[ix - 1].offset;
00091       off1 = stops[ix].offset;
00092       if (fabs (off1 - off0) > EPSILON)
00093        {
00094          double interp;
00095 
00096          interp = (offset - off0) / (off1 - off0);
00097          for (j = 0; j < n_ch; j++)
00098            {
00099              int z0, z1;
00100              int z;
00101              z0 = stops[ix - 1].color[j];
00102              z1 = stops[ix].color[j];
00103              z = floor (z0 + (z1 - z0) * interp + 0.5);
00104              if (render->buf_depth == 8)
00105               dst[j] = ART_PIX_8_FROM_MAX (z);
00106              else /* (render->buf_depth == 16) */
00107               ((art_u16 *)dst)[j] = z;
00108            }
00109          return;
00110        }
00111     }
00112   else if (ix == n_stops)
00113     ix--;
00114 
00115   for (j = 0; j < n_ch; j++)
00116     {
00117       int z;
00118       z = stops[ix].color[j];
00119       if (render->buf_depth == 8)
00120        dst[j] = ART_PIX_8_FROM_MAX (z);
00121       else /* (render->buf_depth == 16) */
00122        ((art_u16 *)dst)[j] = z;
00123     }
00124 }
00125 
00126 static void
00127 art_karbon_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render)
00128 {
00129   art_free (self);
00130 }
00131 
00132 static void
00133 art_karbon_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render,
00134                                art_u8 *dest, int y)
00135 {
00136   ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
00137   const ArtGradientLinear *gradient = z->gradient;
00138   int pixstride = (render->n_chan + 1) * (render->depth >> 3);
00139   int x;
00140   int width = render->x1 - render->x0;
00141   double offset, d_offset;
00142   double actual_offset;
00143   int n_stops = gradient->n_stops;
00144   ArtGradientStop *stops = gradient->stops;
00145   art_u8 *bufp = render->image_buf;
00146   ArtGradientSpread spread = gradient->spread;
00147 
00148   offset = render->x0 * gradient->a + y * gradient->b + gradient->c;
00149   d_offset = gradient->a;
00150 
00151   for (x = 0; x < width; x++)
00152     {
00153       if (spread == ART_GRADIENT_PAD)
00154        actual_offset = offset;
00155       else if (spread == ART_GRADIENT_REPEAT)
00156        actual_offset = offset - floor (offset);
00157       else /* (spread == ART_GRADIENT_REFLECT) */
00158        {
00159          double tmp;
00160 
00161          tmp = offset - 2 * floor (0.5 * offset);
00162          actual_offset = tmp > 1 ? 2 - tmp : tmp;
00163        }
00164       art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset);
00165       offset += d_offset;
00166       bufp += pixstride;
00167     }
00168 }
00169 
00170 static void
00171 art_karbon_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render,
00172                                   ArtImageSourceFlags *p_flags,
00173                                   int *p_buf_depth, ArtAlphaType *p_alpha)
00174 {
00175   self->super.render = art_karbon_render_gradient_linear_render;
00176   *p_flags = 0;
00177   *p_buf_depth = render->depth;
00178   *p_alpha = ART_ALPHA_PREMUL;
00179 }
00180 
00189 void
00190 art_karbon_render_gradient_linear (ArtRender *render,
00191                          const ArtGradientLinear *gradient,
00192                          ArtFilterLevel level)
00193 {
00194   ArtImageSourceGradLin *image_source = art_new (ArtImageSourceGradLin, 1);
00195 
00196   image_source->super.super.render = NULL;
00197   image_source->super.super.done = art_karbon_render_gradient_linear_done;
00198   image_source->super.negotiate = art_karbon_render_gradient_linear_negotiate;
00199 
00200   image_source->gradient = gradient;
00201 
00202   art_render_add_image_source (render, &image_source->super);
00203 }
00204 
00205 static void
00206 art_karbon_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render)
00207 {
00208   art_free (self);
00209 }
00210 
00211 static void
00212 art_karbon_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render,
00213                                art_u8 *dest, int y)
00214 {
00215   ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self;
00216   const ArtGradientRadial *gradient = z->gradient;
00217   int pixstride = (render->n_chan + 1) * (render->depth >> 3);
00218   int x;
00219   int x0 = render->x0;
00220   int width = render->x1 - x0;
00221   int n_stops = gradient->n_stops;
00222   ArtGradientStop *stops = gradient->stops;
00223   art_u8 *bufp = render->image_buf;
00224   double fx = gradient->fx;
00225   double fy = gradient->fy;
00226   double dx, dy;
00227   const double *affine = gradient->affine;
00228   double aff0 = affine[0];
00229   double aff1 = affine[1];
00230   const double a = z->a;
00231   const double arecip = 1.0 / a;
00232   double b, db;
00233   double c, dc, ddc;
00234   double b_a, db_a;
00235   double rad, drad, ddrad;
00236   ArtGradientSpread spread = gradient->spread;
00237 
00238   dx = x0 * aff0 + y * affine[2] + affine[4] - fx;
00239   dy = x0 * aff1 + y * affine[3] + affine[5] - fy;
00240   b = dx * fx + dy * fy;
00241   db = aff0 * fx + aff1 * fy;
00242   c = dx * dx + dy * dy;
00243   dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1;
00244   ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1;
00245 
00246   b_a = b * arecip;
00247   db_a = db * arecip;
00248 
00249   rad = b_a * b_a + c * arecip;
00250   drad = 2 * b_a * db_a + db_a * db_a + dc * arecip;
00251   ddrad = 2 * db_a * db_a + ddc * arecip;
00252 
00253   for (x = 0; x < width; x++)
00254     {
00255       double z;
00256 
00257       if (rad > 0)
00258        z = b_a + sqrt (rad);
00259       else
00260        z = b_a;
00261 
00262     if (spread == ART_GRADIENT_REPEAT)
00263          z = z - floor (z);
00264     else if (spread == ART_GRADIENT_REFLECT)
00265     {
00266          double tmp;
00267 
00268          tmp = z - 2 * floor (0.5 * z);
00269          z = tmp > 1 ? 2 - tmp : tmp;
00270     }
00271 
00272       art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, z);
00273       bufp += pixstride;
00274       b_a += db_a;
00275       rad += drad;
00276       drad += ddrad;
00277     }
00278 }
00279 
00280 static void
00281 art_karbon_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render,
00282                                   ArtImageSourceFlags *p_flags,
00283                                   int *p_buf_depth, ArtAlphaType *p_alpha)
00284 {
00285   self->super.render = art_karbon_render_gradient_radial_render;
00286   *p_flags = 0;
00287   *p_buf_depth = render->depth;
00288   *p_alpha = ART_ALPHA_PREMUL;
00289 }
00290 
00299 void
00300 art_karbon_render_gradient_radial (ArtRender *render,
00301                          const ArtGradientRadial *gradient,
00302                          ArtFilterLevel level)
00303 {
00304   ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1);
00305   double fx = gradient->fx;
00306   double fy = gradient->fy;
00307 
00308   image_source->super.super.render = NULL;
00309   image_source->super.super.done = art_karbon_render_gradient_radial_done;
00310   image_source->super.negotiate = art_karbon_render_gradient_radial_negotiate;
00311 
00312   image_source->gradient = gradient;
00313   /* todo: sanitycheck fx, fy? */
00314   image_source->a = 1 - fx * fx - fy * fy;
00315 
00316   art_render_add_image_source (render, &image_source->super);
00317 }
00318 
00319 /* Conical */
00320 
00321 static void
00322 art_render_gradient_conical_done (ArtRenderCallback *self, ArtRender *render)
00323 {
00324   art_free (self);
00325 }
00326 
00327 static void
00328 art_render_gradient_conical_render (ArtRenderCallback *self, ArtRender *render,
00329                                art_u8 *dest, int y)
00330 {
00331   ArtImageSourceGradCon *z = (ArtImageSourceGradCon *)self;
00332   const ArtGradientConical *gradient = z->gradient;
00333   int pixstride = (render->n_chan + 1) * (render->depth >> 3);
00334   int x;
00335   int x0 = render->x0;
00336   int width = render->x1 - x0;
00337   int n_stops = gradient->n_stops;
00338   ArtGradientStop *stops = gradient->stops;
00339   art_u8 *bufp = render->image_buf;
00340   double cx = gradient->cx;
00341   double cy = gradient->cy;
00342   double r = gradient->r;
00343   double dx, dy;
00344   ArtGradientSpread spread = gradient->spread;
00345 
00346   dy = fabs(y) - fabs(cy);
00347 
00348   for (x = 0; x < width; x++)
00349     {
00350       double z;
00351        dx = fabs(x0 + x) - fabs(cx);
00352 
00353        z = (fabs(dx) + fabs(dy)) / (r);
00354 
00355     if (spread == ART_GRADIENT_REPEAT)
00356          z = z - floor (z);
00357     else if (spread == ART_GRADIENT_REFLECT)
00358     {
00359          double tmp;
00360 
00361          tmp = z - 2 * floor (0.5 * z);
00362          z = tmp > 1 ? 2 - tmp : tmp;
00363     }
00364 
00365       art_karbon_render_gradient_setpix (render, bufp, n_stops, stops, z);
00366       bufp += pixstride;
00367     }
00368 }
00369 
00370 static void
00371 art_render_gradient_conical_negotiate (ArtImageSource *self, ArtRender *render,
00372                                   ArtImageSourceFlags *p_flags,
00373                                   int *p_buf_depth, ArtAlphaType *p_alpha)
00374 {
00375   self->super.render = art_render_gradient_conical_render;
00376   *p_flags = 0;
00377   *p_buf_depth = render->depth;
00378   *p_alpha = ART_ALPHA_PREMUL;
00379 }
00380 
00389 void
00390 art_karbon_render_gradient_conical (ArtRender *render,
00391                          const ArtGradientConical *gradient,
00392                          ArtFilterLevel level)
00393 {
00394   ArtImageSourceGradCon *image_source = art_new (ArtImageSourceGradCon, 1);
00395 
00396   image_source->super.super.render = NULL;
00397   image_source->super.super.done = art_render_gradient_conical_done;
00398   image_source->super.negotiate = art_render_gradient_conical_negotiate;
00399 
00400   image_source->gradient = gradient;
00401 
00402   art_render_add_image_source (render, &image_source->super);
00403 }
00404