Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / gradient.c
dissimilarity index 84%
index 38f19df..383ecf8 100644 (file)
-/* gradient.c - renders gradients
- *
- * Raster graphics library
- *
- * Copyright (c) 1997-2003 Alfredo K. Kojima
- * Copyright (c) 1998-2003 Dan Pascu
- *
- *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <config.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <assert.h>
-
-#include "wraster.h"
-
-
-static RImage *renderHGradient(unsigned width, unsigned height,
-                               int r0, int g0, int b0,
-                               int rf, int gf, int bf);
-static RImage *renderVGradient(unsigned width, unsigned height,
-                               int r0, int g0, int b0,
-                               int rf, int gf, int bf);
-static RImage *renderDGradient(unsigned width, unsigned height,
-                               int r0, int g0, int b0,
-                               int rf, int gf, int bf);
-
-static RImage *renderMHGradient(unsigned width, unsigned height,
-                                RColor **colors, int count);
-static RImage *renderMVGradient(unsigned width, unsigned height,
-                                RColor **colors, int count);
-static RImage *renderMDGradient(unsigned width, unsigned height,
-                                RColor **colors, int count);
-
-RImage*
-RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style)
-{
-    int count;
-
-    count = 0;
-    while (colors[count]!=NULL) count++;
-
-    if (count > 2) {
-        switch (style) {
-        case RHorizontalGradient:
-            return renderMHGradient(width, height, colors, count);
-        case RVerticalGradient:
-            return renderMVGradient(width, height, colors, count);
-        case RDiagonalGradient:
-            return renderMDGradient(width, height, colors, count);
-        }
-    } else if (count > 1) {
-        return RRenderGradient(width, height, colors[0], colors[1], style);
-    } else if (count > 0) {
-        return RRenderGradient(width, height, colors[0], colors[0], style);
-    }
-    assert(0);
-    return NULL;
-}
-
-
-
-RImage*
-RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to,
-                int style)
-{
-    switch (style) {
-    case RHorizontalGradient:
-        return renderHGradient(width, height, from->red, from->green,
-                               from->blue, to->red, to->green, to->blue);
-    case RVerticalGradient:
-        return renderVGradient(width, height, from->red, from->green,
-                               from->blue, to->red, to->green, to->blue);
-
-    case RDiagonalGradient:
-        return renderDGradient(width, height, from->red, from->green,
-                               from->blue, to->red, to->green, to->blue);
-    }
-    assert(0);
-    return NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------
- * renderHGradient--
- *     Renders a horizontal linear gradient of the specified size in the
- * RImage format with a border of the specified type.
- *
- * Returns:
- *     A 24bit RImage with the gradient (no alpha channel).
- *
- * Side effects:
- *     None
- *----------------------------------------------------------------------
- */
-static RImage*
-renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0,
-                int rf, int gf, int bf)
-{
-    int i;
-    long r, g, b, dr, dg, db;
-    unsigned lineSize = width*3;
-    RImage *image;
-    unsigned char *ptr;
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-    ptr = image->data;
-
-    r = r0 << 16;
-    g = g0 << 16;
-    b = b0 << 16;
-
-    dr = ((rf-r0)<<16)/(int)width;
-    dg = ((gf-g0)<<16)/(int)width;
-    db = ((bf-b0)<<16)/(int)width;
-    /* render the first line */
-    for (i=0; i<width; i++) {
-        *(ptr++) = (unsigned char)(r>>16);
-        *(ptr++) = (unsigned char)(g>>16);
-        *(ptr++) = (unsigned char)(b>>16);
-        r += dr;
-        g += dg;
-        b += db;
-    }
-
-    /* copy the first line to the other lines */
-    for (i=1; i<height; i++) {
-        memcpy(&(image->data[i*lineSize]), image->data, lineSize);
-    }
-    return image;
-}
-
-
-
-/*
- *----------------------------------------------------------------------
- * renderVGradient--
- *      Renders a vertical linear gradient of the specified size in the
- * RImage format with a border of the specified type.
- *
- * Returns:
- *      A 24bit RImage with the gradient (no alpha channel).
- *
- * Side effects:
- *      None
- *----------------------------------------------------------------------
- */
-static RImage*
-renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
-                int rf, int gf, int bf)
-{
-    int i, j;
-    long r, g, b, dr, dg, db;
-    RImage *image;
-    unsigned char *ptr;
-    unsigned char rr, gg, bb;
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-    ptr = image->data;
-
-    r = r0<<16;
-    g = g0<<16;
-    b = b0<<16;
-
-    dr = ((rf-r0)<<16)/(int)height;
-    dg = ((gf-g0)<<16)/(int)height;
-    db = ((bf-b0)<<16)/(int)height;
-
-    for (i=0; i<height; i++) {
-        rr = r>>16;
-        gg = g>>16;
-        bb = b>>16;
-        for (j=0; j<width/8; j++) {
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        }
-        switch (width%8) {
-        case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        }
-        r+=dr;
-        g+=dg;
-        b+=db;
-    }
-    return image;
-}
-
-
-/*
- *----------------------------------------------------------------------
- * renderDGradient--
- *      Renders a diagonal linear gradient of the specified size in the
- * RImage format with a border of the specified type.
- *
- * Returns:
- *      A 24bit RImage with the gradient (no alpha channel).
- *
- * Side effects:
- *      None
- *----------------------------------------------------------------------
- */
-
-
-static RImage*
-renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
-                int rf, int gf, int bf)
-{
-    RImage *image, *tmp;
-    int j;
-    float a, offset;
-    unsigned char *ptr;
-
-    if (width == 1)
-        return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
-    else if (height == 1)
-        return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-
-    tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
-    if (!tmp) {
-        RReleaseImage(image);
-        return NULL;
-    }
-
-    ptr = tmp->data;
-
-    a = ((float)(width - 1))/((float)(height - 1));
-    width = width * 3;
-
-    /* copy the first line to the other lines with corresponding offset */
-    for (j=0, offset=0.0; j<width*height; j += width) {
-        memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
-        offset += a;
-    }
-
-    RReleaseImage(tmp);
-    return image;
-}
-
-
-static RImage*
-renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
-{
-    int i, j, k;
-    long r, g, b, dr, dg, db;
-    unsigned lineSize = width*3;
-    RImage *image;
-    unsigned char *ptr;
-    unsigned width2;
-
-
-    assert(count > 2);
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-    ptr = image->data;
-
-    if (count > width)
-        count = width;
-
-    if (count > 1)
-        width2 = width/(count-1);
-    else
-        width2 = width;
-
-    k = 0;
-
-    r = colors[0]->red << 16;
-    g = colors[0]->green << 16;
-    b = colors[0]->blue << 16;
-
-    /* render the first line */
-    for (i=1; i<count; i++) {
-        dr = ((int)(colors[i]->red   - colors[i-1]->red)  <<16)/(int)width2;
-        dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
-        db = ((int)(colors[i]->blue  - colors[i-1]->blue) <<16)/(int)width2;
-        for (j=0; j<width2; j++) {
-            *ptr++ = (unsigned char)(r>>16);
-            *ptr++ = (unsigned char)(g>>16);
-            *ptr++ = (unsigned char)(b>>16);
-            r += dr;
-            g += dg;
-            b += db;
-            k++;
-        }
-        r = colors[i]->red << 16;
-        g = colors[i]->green << 16;
-        b = colors[i]->blue << 16;
-    }
-    for (j=k; j<width; j++) {
-        *ptr++ = (unsigned char)(r>>16);
-        *ptr++ = (unsigned char)(g>>16);
-        *ptr++ = (unsigned char)(b>>16);
-    }
-
-    /* copy the first line to the other lines */
-    for (i=1; i<height; i++) {
-        memcpy(&(image->data[i*lineSize]), image->data, lineSize);
-    }
-    return image;
-}
-
-
-
-
-static RImage*
-renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
-{
-    int i, j, k;
-    long r, g, b, dr, dg, db;
-    unsigned lineSize = width*3;
-    RImage *image;
-    unsigned char *ptr, *tmp;
-    unsigned height2;
-    int x;
-    unsigned char rr, gg, bb;
-
-
-    assert(count > 2);
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-    ptr = image->data;
-
-    if (count > height)
-        count = height;
-
-    if (count > 1)
-        height2 = height/(count-1);
-    else
-        height2 = height;
-
-    k = 0;
-
-    r = colors[0]->red << 16;
-    g = colors[0]->green << 16;
-    b = colors[0]->blue << 16;
-
-    for (i=1; i<count; i++) {
-        dr = ((int)(colors[i]->red   - colors[i-1]->red)  <<16)/(int)height2;
-        dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
-        db = ((int)(colors[i]->blue  - colors[i-1]->blue) <<16)/(int)height2;
-
-        for (j=0; j<height2; j++) {
-            rr = r>>16;
-            gg = g>>16;
-            bb = b>>16;
-
-            for (x=0; x<width/4; x++) {
-                *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-                *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-                *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-                *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            }
-            switch (width%4) {
-            case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            }
-            r += dr;
-            g += dg;
-            b += db;
-            k++;
-        }
-        r = colors[i]->red << 16;
-        g = colors[i]->green << 16;
-        b = colors[i]->blue << 16;
-    }
-
-    rr = r>>16;
-    gg = g>>16;
-    bb = b>>16;
-
-    if (k<height) {
-        tmp = ptr;
-        for (x=0; x<width/4; x++) {
-            *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-            *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-        }
-        switch (width%4) {
-        case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-        case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-        case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
-        default: break;
-        }
-
-        for (j=k+1; j<height; j++) {
-            memcpy(ptr, tmp, lineSize);
-            ptr += lineSize;
-        }
-    }
-
-    return image;
-}
-
-
-static RImage*
-renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
-{
-    RImage *image, *tmp;
-    float a, offset;
-    int j;
-    unsigned char *ptr;
-
-    assert(count > 2);
-
-    if (width == 1)
-        return renderMVGradient(width, height, colors, count);
-    else if (height == 1)
-        return renderMHGradient(width, height, colors, count);
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-
-    if (count > width)
-        count = width;
-    if (count > height)
-        count = height;
-
-    if (count > 2)
-        tmp = renderMHGradient(2*width-1, 1, colors, count);
-    else
-        tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
-                              colors[0]->green<<8, colors[0]->blue<<8,
-                              colors[1]->red<<8, colors[1]->green<<8,
-                              colors[1]->blue<<8);
-
-    if (!tmp) {
-        RReleaseImage(image);
-        return NULL;
-    }
-    ptr = tmp->data;
-
-    a = ((float)(width - 1))/((float)(height - 1));
-    width = width * 3;
-
-    /* copy the first line to the other lines with corresponding offset */
-    for (j=0, offset=0; j<width*height; j += width) {
-        memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
-        offset += a;
-    }
-    RReleaseImage(tmp);
-    return image;
-}
-
-
-
-
-RImage*
-RRenderInterwovenGradient(unsigned width, unsigned height,
-                          RColor colors1[2], int thickness1,
-                          RColor colors2[2], int thickness2)
-{
-    int i, j, k, l, ll;
-    long r1, g1, b1, dr1, dg1, db1;
-    long r2, g2, b2, dr2, dg2, db2;
-    RImage *image;
-    unsigned char *ptr;
-    unsigned char rr, gg, bb;
-
-    image = RCreateImage(width, height, False);
-    if (!image) {
-        return NULL;
-    }
-    ptr = image->data;
-
-    r1 = colors1[0].red<<16;
-    g1 = colors1[0].green<<16;
-    b1 = colors1[0].blue<<16;
-
-    r2 = colors2[0].red<<16;
-    g2 = colors2[0].green<<16;
-    b2 = colors2[0].blue<<16;
-
-    dr1 = ((colors1[1].red-colors1[0].red)<<16)/(int)height;
-    dg1 = ((colors1[1].green-colors1[0].green)<<16)/(int)height;
-    db1 = ((colors1[1].blue-colors1[0].blue)<<16)/(int)height;
-
-    dr2 = ((colors2[1].red-colors2[0].red)<<16)/(int)height;
-    dg2 = ((colors2[1].green-colors2[0].green)<<16)/(int)height;
-    db2 = ((colors2[1].blue-colors2[0].blue)<<16)/(int)height;
-
-    for (i=0,k=0,l=0,ll=thickness1; i<height; i++) {
-        if (k == 0) {
-            rr = r1>>16;
-            gg = g1>>16;
-            bb = b1>>16;
-        } else {
-            rr = r2>>16;
-            gg = g2>>16;
-            bb = b2>>16;
-        }
-        for (j=0; j<width/8; j++) {
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-            *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        }
-        switch (width%8) {
-        case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
-        }
-        if (++l == ll) {
-            if (k == 0) {
-                k = 1;
-                ll = thickness2;
-            } else {
-                k = 0;
-                ll = thickness1;
-            }
-            l = 0;
-        }
-        r1+=dr1;
-        g1+=dg1;
-        b1+=db1;
-
-        r2+=dr2;
-        g2+=dg2;
-        b2+=db2;
-    }
-    return image;
-}
-
+/* gradient.c - renders gradients
+ *
+ * Raster graphics library
+ *
+ * Copyright (c) 1997-2003 Alfredo K. Kojima
+ * Copyright (c) 1998-2003 Dan Pascu
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <assert.h>
+
+#include "wraster.h"
+
+static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
+static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
+static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
+
+static RImage *renderMHGradient(unsigned width, unsigned height, RColor ** colors, int count);
+static RImage *renderMVGradient(unsigned width, unsigned height, RColor ** colors, int count);
+static RImage *renderMDGradient(unsigned width, unsigned height, RColor ** colors, int count);
+
+RImage *RRenderMultiGradient(unsigned width, unsigned height, RColor ** colors, int style)
+{
+       int count;
+
+       count = 0;
+       while (colors[count] != NULL)
+               count++;
+
+       if (count > 2) {
+               switch (style) {
+               case RHorizontalGradient:
+                       return renderMHGradient(width, height, colors, count);
+               case RVerticalGradient:
+                       return renderMVGradient(width, height, colors, count);
+               case RDiagonalGradient:
+                       return renderMDGradient(width, height, colors, count);
+               }
+       } else if (count > 1) {
+               return RRenderGradient(width, height, colors[0], colors[1], style);
+       } else if (count > 0) {
+               return RRenderGradient(width, height, colors[0], colors[0], style);
+       }
+       assert(0);
+       return NULL;
+}
+
+RImage *RRenderGradient(unsigned width, unsigned height, RColor * from, RColor * to, int style)
+{
+       switch (style) {
+       case RHorizontalGradient:
+               return renderHGradient(width, height, from->red, from->green,
+                                      from->blue, to->red, to->green, to->blue);
+       case RVerticalGradient:
+               return renderVGradient(width, height, from->red, from->green,
+                                      from->blue, to->red, to->green, to->blue);
+
+       case RDiagonalGradient:
+               return renderDGradient(width, height, from->red, from->green,
+                                      from->blue, to->red, to->green, to->blue);
+       }
+       assert(0);
+       return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * renderHGradient--
+ *     Renders a horizontal linear gradient of the specified size in the
+ * RImage format with a border of the specified type.
+ *
+ * Returns:
+ *     A 24bit RImage with the gradient (no alpha channel).
+ *
+ * Side effects:
+ *     None
+ *----------------------------------------------------------------------
+ */
+static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
+{
+       int i;
+       long r, g, b, dr, dg, db;
+       unsigned lineSize = width * 3;
+       RImage *image;
+       unsigned char *ptr;
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+       ptr = image->data;
+
+       r = r0 << 16;
+       g = g0 << 16;
+       b = b0 << 16;
+
+       dr = ((rf - r0) << 16) / (int)width;
+       dg = ((gf - g0) << 16) / (int)width;
+       db = ((bf - b0) << 16) / (int)width;
+       /* render the first line */
+       for (i = 0; i < width; i++) {
+               *(ptr++) = (unsigned char)(r >> 16);
+               *(ptr++) = (unsigned char)(g >> 16);
+               *(ptr++) = (unsigned char)(b >> 16);
+               r += dr;
+               g += dg;
+               b += db;
+       }
+
+       /* copy the first line to the other lines */
+       for (i = 1; i < height; i++) {
+               memcpy(&(image->data[i * lineSize]), image->data, lineSize);
+       }
+       return image;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * renderVGradient--
+ *      Renders a vertical linear gradient of the specified size in the
+ * RImage format with a border of the specified type.
+ *
+ * Returns:
+ *      A 24bit RImage with the gradient (no alpha channel).
+ *
+ * Side effects:
+ *      None
+ *----------------------------------------------------------------------
+ */
+static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
+{
+       int i, j;
+       long r, g, b, dr, dg, db;
+       RImage *image;
+       unsigned char *ptr;
+       unsigned char rr, gg, bb;
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+       ptr = image->data;
+
+       r = r0 << 16;
+       g = g0 << 16;
+       b = b0 << 16;
+
+       dr = ((rf - r0) << 16) / (int)height;
+       dg = ((gf - g0) << 16) / (int)height;
+       db = ((bf - b0) << 16) / (int)height;
+
+       for (i = 0; i < height; i++) {
+               rr = r >> 16;
+               gg = g >> 16;
+               bb = b >> 16;
+               for (j = 0; j < width / 8; j++) {
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               }
+               switch (width % 8) {
+               case 7:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 6:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 5:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 4:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 3:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 2:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 1:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               }
+               r += dr;
+               g += dg;
+               b += db;
+       }
+       return image;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * renderDGradient--
+ *      Renders a diagonal linear gradient of the specified size in the
+ * RImage format with a border of the specified type.
+ *
+ * Returns:
+ *      A 24bit RImage with the gradient (no alpha channel).
+ *
+ * Side effects:
+ *      None
+ *----------------------------------------------------------------------
+ */
+
+static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
+{
+       RImage *image, *tmp;
+       int j;
+       float a, offset;
+       unsigned char *ptr;
+
+       if (width == 1)
+               return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
+       else if (height == 1)
+               return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+
+       tmp = renderHGradient(2 * width - 1, 1, r0, g0, b0, rf, gf, bf);
+       if (!tmp) {
+               RReleaseImage(image);
+               return NULL;
+       }
+
+       ptr = tmp->data;
+
+       a = ((float)(width - 1)) / ((float)(height - 1));
+       width = width * 3;
+
+       /* copy the first line to the other lines with corresponding offset */
+       for (j = 0, offset = 0.0; j < width * height; j += width) {
+               memcpy(&(image->data[j]), &ptr[3 * (int)offset], width);
+               offset += a;
+       }
+
+       RReleaseImage(tmp);
+       return image;
+}
+
+static RImage *renderMHGradient(unsigned width, unsigned height, RColor ** colors, int count)
+{
+       int i, j, k;
+       long r, g, b, dr, dg, db;
+       unsigned lineSize = width * 3;
+       RImage *image;
+       unsigned char *ptr;
+       unsigned width2;
+
+       assert(count > 2);
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+       ptr = image->data;
+
+       if (count > width)
+               count = width;
+
+       if (count > 1)
+               width2 = width / (count - 1);
+       else
+               width2 = width;
+
+       k = 0;
+
+       r = colors[0]->red << 16;
+       g = colors[0]->green << 16;
+       b = colors[0]->blue << 16;
+
+       /* render the first line */
+       for (i = 1; i < count; i++) {
+               dr = ((int)(colors[i]->red - colors[i - 1]->red) << 16) / (int)width2;
+               dg = ((int)(colors[i]->green - colors[i - 1]->green) << 16) / (int)width2;
+               db = ((int)(colors[i]->blue - colors[i - 1]->blue) << 16) / (int)width2;
+               for (j = 0; j < width2; j++) {
+                       *ptr++ = (unsigned char)(r >> 16);
+                       *ptr++ = (unsigned char)(g >> 16);
+                       *ptr++ = (unsigned char)(b >> 16);
+                       r += dr;
+                       g += dg;
+                       b += db;
+                       k++;
+               }
+               r = colors[i]->red << 16;
+               g = colors[i]->green << 16;
+               b = colors[i]->blue << 16;
+       }
+       for (j = k; j < width; j++) {
+               *ptr++ = (unsigned char)(r >> 16);
+               *ptr++ = (unsigned char)(g >> 16);
+               *ptr++ = (unsigned char)(b >> 16);
+       }
+
+       /* copy the first line to the other lines */
+       for (i = 1; i < height; i++) {
+               memcpy(&(image->data[i * lineSize]), image->data, lineSize);
+       }
+       return image;
+}
+
+static RImage *renderMVGradient(unsigned width, unsigned height, RColor ** colors, int count)
+{
+       int i, j, k;
+       long r, g, b, dr, dg, db;
+       unsigned lineSize = width * 3;
+       RImage *image;
+       unsigned char *ptr, *tmp;
+       unsigned height2;
+       int x;
+       unsigned char rr, gg, bb;
+
+       assert(count > 2);
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+       ptr = image->data;
+
+       if (count > height)
+               count = height;
+
+       if (count > 1)
+               height2 = height / (count - 1);
+       else
+               height2 = height;
+
+       k = 0;
+
+       r = colors[0]->red << 16;
+       g = colors[0]->green << 16;
+       b = colors[0]->blue << 16;
+
+       for (i = 1; i < count; i++) {
+               dr = ((int)(colors[i]->red - colors[i - 1]->red) << 16) / (int)height2;
+               dg = ((int)(colors[i]->green - colors[i - 1]->green) << 16) / (int)height2;
+               db = ((int)(colors[i]->blue - colors[i - 1]->blue) << 16) / (int)height2;
+
+               for (j = 0; j < height2; j++) {
+                       rr = r >> 16;
+                       gg = g >> 16;
+                       bb = b >> 16;
+
+                       for (x = 0; x < width / 4; x++) {
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                       }
+                       switch (width % 4) {
+                       case 3:
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                       case 2:
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                       case 1:
+                               *ptr++ = rr;
+                               *ptr++ = gg;
+                               *ptr++ = bb;
+                       }
+                       r += dr;
+                       g += dg;
+                       b += db;
+                       k++;
+               }
+               r = colors[i]->red << 16;
+               g = colors[i]->green << 16;
+               b = colors[i]->blue << 16;
+       }
+
+       rr = r >> 16;
+       gg = g >> 16;
+       bb = b >> 16;
+
+       if (k < height) {
+               tmp = ptr;
+               for (x = 0; x < width / 4; x++) {
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+               }
+               switch (width % 4) {
+               case 3:
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+               case 2:
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+               case 1:
+                       *ptr++ = rr;
+                       *ptr++ = gg;
+                       *ptr++ = bb;
+               default:
+                       break;
+               }
+
+               for (j = k + 1; j < height; j++) {
+                       memcpy(ptr, tmp, lineSize);
+                       ptr += lineSize;
+               }
+       }
+
+       return image;
+}
+
+static RImage *renderMDGradient(unsigned width, unsigned height, RColor ** colors, int count)
+{
+       RImage *image, *tmp;
+       float a, offset;
+       int j;
+       unsigned char *ptr;
+
+       assert(count > 2);
+
+       if (width == 1)
+               return renderMVGradient(width, height, colors, count);
+       else if (height == 1)
+               return renderMHGradient(width, height, colors, count);
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+
+       if (count > width)
+               count = width;
+       if (count > height)
+               count = height;
+
+       if (count > 2)
+               tmp = renderMHGradient(2 * width - 1, 1, colors, count);
+       else
+               tmp = renderHGradient(2 * width - 1, 1, colors[0]->red << 8,
+                                     colors[0]->green << 8, colors[0]->blue << 8,
+                                     colors[1]->red << 8, colors[1]->green << 8, colors[1]->blue << 8);
+
+       if (!tmp) {
+               RReleaseImage(image);
+               return NULL;
+       }
+       ptr = tmp->data;
+
+       a = ((float)(width - 1)) / ((float)(height - 1));
+       width = width * 3;
+
+       /* copy the first line to the other lines with corresponding offset */
+       for (j = 0, offset = 0; j < width * height; j += width) {
+               memcpy(&(image->data[j]), &ptr[3 * (int)offset], width);
+               offset += a;
+       }
+       RReleaseImage(tmp);
+       return image;
+}
+
+RImage *RRenderInterwovenGradient(unsigned width, unsigned height,
+                                 RColor colors1[2], int thickness1, RColor colors2[2], int thickness2)
+{
+       int i, j, k, l, ll;
+       long r1, g1, b1, dr1, dg1, db1;
+       long r2, g2, b2, dr2, dg2, db2;
+       RImage *image;
+       unsigned char *ptr;
+       unsigned char rr, gg, bb;
+
+       image = RCreateImage(width, height, False);
+       if (!image) {
+               return NULL;
+       }
+       ptr = image->data;
+
+       r1 = colors1[0].red << 16;
+       g1 = colors1[0].green << 16;
+       b1 = colors1[0].blue << 16;
+
+       r2 = colors2[0].red << 16;
+       g2 = colors2[0].green << 16;
+       b2 = colors2[0].blue << 16;
+
+       dr1 = ((colors1[1].red - colors1[0].red) << 16) / (int)height;
+       dg1 = ((colors1[1].green - colors1[0].green) << 16) / (int)height;
+       db1 = ((colors1[1].blue - colors1[0].blue) << 16) / (int)height;
+
+       dr2 = ((colors2[1].red - colors2[0].red) << 16) / (int)height;
+       dg2 = ((colors2[1].green - colors2[0].green) << 16) / (int)height;
+       db2 = ((colors2[1].blue - colors2[0].blue) << 16) / (int)height;
+
+       for (i = 0, k = 0, l = 0, ll = thickness1; i < height; i++) {
+               if (k == 0) {
+                       rr = r1 >> 16;
+                       gg = g1 >> 16;
+                       bb = b1 >> 16;
+               } else {
+                       rr = r2 >> 16;
+                       gg = g2 >> 16;
+                       bb = b2 >> 16;
+               }
+               for (j = 0; j < width / 8; j++) {
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               }
+               switch (width % 8) {
+               case 7:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 6:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 5:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 4:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 3:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 2:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               case 1:
+                       *(ptr++) = rr;
+                       *(ptr++) = gg;
+                       *(ptr++) = bb;
+               }
+               if (++l == ll) {
+                       if (k == 0) {
+                               k = 1;
+                               ll = thickness2;
+                       } else {
+                               k = 0;
+                               ll = thickness1;
+                       }
+                       l = 0;
+               }
+               r1 += dr1;
+               g1 += dg1;
+               b1 += db1;
+
+               r2 += dr2;
+               g2 += dg2;
+               b2 += db2;
+       }
+       return image;
+}