index 9de84d707a1819b17936ab901de6697c0cb09bc2..cb03c048bd547995109312a60426b574440bfce4 100644 (file)
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* MenTaLguY <mental@rydia.net>
+ *...Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
*
+ * Copyright (C) 2009 Jasper van de Gronde
* Copyright (C) 2007 MenTaLguY
* Copyright (C) 2001-2002 Lauris Kaplinski
* Copyright (C) 2001-2002 Ximian, Inc.
* Derived in part from public domain code by Lauris Kaplinski
*/
+#include <cstring>
#include <libnr/nr-pixops.h>
#include <libnr/nr-pixblock-pixel.h>
#include <libnr/nr-blit.h>
#include <libnr/nr-gradient.h>
+#include <libnr/nr-matrix-ops.h>
#include <glib/gtypes.h>
#include <stdio.h>
template <>
struct Spread<NR_GRADIENT_SPREAD_PAD> {
+static double index_at(NR::Coord r, double const unity = 1.0) {
+ return r<0.0?0.0:r>unity?unity:r;
+}
static unsigned char const *color_at(NR::Coord r,
unsigned char const *vector)
{
- return vector_index((int)CLAMP(r, 0, (double)(NR_GRADIENT_VECTOR_LENGTH - 1)), vector);
+ return vector_index((int)(index_at(r, NR_GRADIENT_VECTOR_LENGTH - 1)+.5), vector);
+ //return vector_index((int)CLAMP(r, 0, (double)(NR_GRADIENT_VECTOR_LENGTH - 1)), vector);
}
};
template <>
struct Spread<NR_GRADIENT_SPREAD_REPEAT> {
+static double index_at(NR::Coord r, double const unity = 1.0) {
+ return r<0.0?(unity+fmod(r,unity)):fmod(r,unity);
+}
static unsigned char const *color_at(NR::Coord r,
unsigned char const *vector)
{
- return vector_index((int)((long long)r & NRG_MASK), vector);
+ return vector_index((int)(index_at(r, NR_GRADIENT_VECTOR_LENGTH - 1)+.5), vector);
+ //return vector_index((int)((long long)r & NRG_MASK), vector);
}
};
template <>
struct Spread<NR_GRADIENT_SPREAD_REFLECT> {
+static double index_at(NR::Coord r, double const unity = 1.0) {
+ r = r<0.0?(2*unity+fmod(r,2*unity)):fmod(r,2*unity);
+ if (r>unity) r=2*unity-r;
+ return r;
+}
static unsigned char const *color_at(NR::Coord r,
unsigned char const *vector)
{
- int idx = (int) ((long long)r & NRG_2MASK);
- if (idx > NRG_MASK) idx = NRG_2MASK - idx;
- return vector_index(idx, vector);
+ return vector_index((int)(index_at(r, NR_GRADIENT_VECTOR_LENGTH - 1)+.5), vector);
+ //int idx = (int) ((long long)r & NRG_2MASK);
+ //if (idx > NRG_MASK) idx = NRG_2MASK - idx;
+ //return vector_index(idx, vector);
}
};
-template <NR_PIXBLOCK_MODE mode, bool empty=false>
+template <NR_PIXBLOCK_MODE mode> struct ModeTraits;
+
+template <>
+struct ModeTraits<NR_PIXBLOCK_MODE_R8G8B8A8N> {
+static const unsigned bpp=4;
+};
+
+template <>
+struct ModeTraits<NR_PIXBLOCK_MODE_R8G8B8A8P> {
+static const unsigned bpp=4;
+};
+
+template <>
+struct ModeTraits<NR_PIXBLOCK_MODE_R8G8B8> {
+static const unsigned bpp=3;
+};
+
+template <>
+struct ModeTraits<NR_PIXBLOCK_MODE_A8> {
+static const unsigned bpp=1;
+};
+
+template <NR_PIXBLOCK_MODE mode, bool empty>
struct Compose {
+static const unsigned bpp=ModeTraits<mode>::bpp;
static void compose(NRPixBlock *pb, unsigned char *dest,
NRPixBlock *spb, unsigned char const *src)
{
template <>
struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, true> {
-static void compose(NRPixBlock *pb, unsigned char *dest,
- NRPixBlock *spb, unsigned char const *src)
+static const unsigned bpp=4;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
+{
+ std::memcpy(dest, src, 4);
+}
+};
+
+template <>
+struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, true> {
+static const unsigned bpp=4;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
{
- dest[0] = src[0];
- dest[1] = src[1];
- dest[2] = src[2];
+ dest[0] = NR_PREMUL_111(src[0], src[3]);
+ dest[1] = NR_PREMUL_111(src[1], src[3]);
+ dest[2] = NR_PREMUL_111(src[2], src[3]);
dest[3] = src[3];
}
};
+template <>
+struct Compose<NR_PIXBLOCK_MODE_R8G8B8, true> {
+static const unsigned bpp=3;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
+{
+ dest[0] = NR_COMPOSEN11_1111(src[0], src[3], 255);
+ dest[1] = NR_COMPOSEN11_1111(src[1], src[3], 255);
+ dest[2] = NR_COMPOSEN11_1111(src[2], src[3], 255);
+}
+};
+
+template <>
+struct Compose<NR_PIXBLOCK_MODE_A8, true> {
+static const unsigned bpp=1;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
+{
+ dest[0] = src[3];
+}
+};
+
template <>
struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, false> {
-static void compose(NRPixBlock *pb, unsigned char *dest,
- NRPixBlock *spb, unsigned char const *src)
+static const unsigned bpp=4;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
{
unsigned int ca;
ca = NR_COMPOSEA_112(src[3], dest[3]);
template <>
struct Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, false> {
-static void compose(NRPixBlock *pb, unsigned char *dest,
- NRPixBlock *spb, unsigned char const *src)
+static const unsigned bpp=4;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
{
dest[0] = NR_COMPOSENPP_1111(src[0], src[3], dest[0]);
dest[1] = NR_COMPOSENPP_1111(src[1], src[3], dest[1]);
template <>
struct Compose<NR_PIXBLOCK_MODE_R8G8B8, false> {
-static void compose(NRPixBlock *pb, unsigned char *dest,
- NRPixBlock *spb, unsigned char const *src)
+static const unsigned bpp=3;
+static void compose(NRPixBlock */*pb*/, unsigned char *dest,
+ NRPixBlock */*spb*/, unsigned char const *src)
{
dest[0] = NR_COMPOSEN11_1111(src[0], src[3], dest[0]);
dest[1] = NR_COMPOSEN11_1111(src[1], src[3], dest[1]);
case NR_PIXBLOCK_MODE_R8G8B8A8N:
if (pb->empty) {
typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, true> compose;
- Subtype::template render<compose, spread, 4>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
} else {
typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8N, false> compose;
- Subtype::template render<compose, spread, 4>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
}
break;
case NR_PIXBLOCK_MODE_R8G8B8A8P:
if (pb->empty) {
typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, true> compose;
- Subtype::template render<compose, spread, 4>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
} else {
typedef Compose<NR_PIXBLOCK_MODE_R8G8B8A8P, false> compose;
- Subtype::template render<compose, spread, 4>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
}
break;
case NR_PIXBLOCK_MODE_R8G8B8:
if (pb->empty) {
typedef Compose<NR_PIXBLOCK_MODE_R8G8B8, true> compose;
- Subtype::template render<compose, spread, 3>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
} else {
typedef Compose<NR_PIXBLOCK_MODE_R8G8B8, false> compose;
- Subtype::template render<compose, spread, 3>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
}
break;
case NR_PIXBLOCK_MODE_A8:
if (pb->empty) {
typedef Compose<NR_PIXBLOCK_MODE_A8, true> compose;
- Subtype::template render<compose, spread, 1>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
} else {
typedef Compose<NR_PIXBLOCK_MODE_A8, false> compose;
- Subtype::template render<compose, spread, 1>(gr, pb);
+ Subtype::template render<compose, spread>(gr, pb);
}
break;
}
template <typename Subtype>
static void
-render(NRRenderer *r, NRPixBlock *pb, NRPixBlock *m)
+render(NRRenderer *r, NRPixBlock *pb, NRPixBlock */*m*/)
{
- NRGradientRenderer *gr;
-
- gr = static_cast<NRGradientRenderer *>(r);
+ NRGradientRenderer *gr = static_cast<NRGradientRenderer *>(r);
switch (gr->spread) {
case NR_GRADIENT_SPREAD_REPEAT:
namespace {
struct Linear {
-template <typename compose, typename spread, unsigned bpp>
+template <typename compose, typename spread>
static void render(NRGradientRenderer *gr, NRPixBlock *pb) {
NRLGradientRenderer *lgr = static_cast<NRLGradientRenderer *>(gr);
for (x = 0; x < width; x++) {
unsigned char const *s=spread::color_at(pos, lgr->vector);
compose::compose(pb, d, &spb, s);
- d += bpp;
+ d += compose::bpp;
pos += lgr->dx;
}
}
nr_lgradient_renderer_setup (NRLGradientRenderer *lgr,
const unsigned char *cv,
unsigned int spread,
- const NRMatrix *gs2px,
+ const NR::Matrix *gs2px,
float x0, float y0,
float x1, float y1)
{
- NRMatrix n2gs, n2px, px2n;
+ NR::Matrix n2gs, n2px, px2n;
lgr->render = &render<Linear>;
lgr->vector = cv;
lgr->spread = spread;
- n2gs.c[0] = x1 - x0;
- n2gs.c[1] = y1 - y0;
- n2gs.c[2] = y1 - y0;
- n2gs.c[3] = x0 - x1;
- n2gs.c[4] = x0;
- n2gs.c[5] = y0;
+ n2gs[0] = x1 - x0;
+ n2gs[1] = y1 - y0;
+ n2gs[2] = y1 - y0;
+ n2gs[3] = x0 - x1;
+ n2gs[4] = x0;
+ n2gs[5] = y0;
- nr_matrix_multiply (&n2px, &n2gs, gs2px);
- nr_matrix_invert (&px2n, &n2px);
+ n2px = n2gs * (*gs2px);
+ px2n = n2px.inverse();
- lgr->x0 = n2px.c[4] - 0.5;
- lgr->y0 = n2px.c[5] - 0.5;
- lgr->dx = px2n.c[0] * NR_GRADIENT_VECTOR_LENGTH;
- lgr->dy = px2n.c[2] * NR_GRADIENT_VECTOR_LENGTH;
+ lgr->x0 = n2px[4] - 0.5; // These -0.5 offsets make sure that the gradient is sampled in the MIDDLE of each pixel.
+ lgr->y0 = n2px[5] - 0.5;
+ lgr->dx = px2n[0] * (NR_GRADIENT_VECTOR_LENGTH-1);
+ lgr->dy = px2n[2] * (NR_GRADIENT_VECTOR_LENGTH-1);
return (NRRenderer *) lgr;
}
namespace {
struct SymmetricRadial {
-template <typename compose, typename spread, unsigned bpp>
+template <typename compose, typename spread>
static void render(NRGradientRenderer *gr, NRPixBlock *pb)
{
NRRGradientRenderer *rgr = static_cast<NRRGradientRenderer *>(gr);
- NR::Coord const dx = rgr->px2gs.c[0];
- NR::Coord const dy = rgr->px2gs.c[1];
+ NR::Coord const dx = rgr->px2gs[0];
+ NR::Coord const dy = rgr->px2gs[1];
NRPixBlock spb;
nr_pixblock_setup_extern(&spb, NR_PIXBLOCK_MODE_R8G8B8A8N,
for (int y = pb->area.y0; y < pb->area.y1; y++) {
unsigned char *d = NR_PIXBLOCK_PX(pb) + (y - pb->area.y0) * pb->rs;
- NR::Coord gx = rgr->px2gs.c[0] * pb->area.x0 + rgr->px2gs.c[2] * y + rgr->px2gs.c[4];
- NR::Coord gy = rgr->px2gs.c[1] * pb->area.x0 + rgr->px2gs.c[3] * y + rgr->px2gs.c[5];
+ NR::Coord gx = rgr->px2gs[0] * pb->area.x0 + rgr->px2gs[2] * y + rgr->px2gs[4];
+ NR::Coord gy = rgr->px2gs[1] * pb->area.x0 + rgr->px2gs[3] * y + rgr->px2gs[5];
for (int x = pb->area.x0; x < pb->area.x1; x++) {
NR::Coord const pos = sqrt(((gx*gx) + (gy*gy)));
unsigned char const *s=spread::color_at(pos, rgr->vector);
compose::compose(pb, d, &spb, s);
- d += bpp;
+ d += compose::bpp;
gx += dx;
gy += dy;
}
};
struct Radial {
-template <typename compose, typename spread, unsigned bpp>
+template <typename compose, typename spread>
static void render(NRGradientRenderer *gr, NRPixBlock *pb)
{
NRRGradientRenderer *rgr = static_cast<NRRGradientRenderer *>(gr);
for (int y = y0; y < y1; y++) {
unsigned char *d = NR_PIXBLOCK_PX(pb) + (y - y0) * rs;
- NR::Coord gx = rgr->px2gs.c[0] * x0 + rgr->px2gs.c[2] * y + rgr->px2gs.c[4];
- NR::Coord gy = rgr->px2gs.c[1] * x0 + rgr->px2gs.c[3] * y + rgr->px2gs.c[5];
- NR::Coord const dx = rgr->px2gs.c[0];
- NR::Coord const dy = rgr->px2gs.c[1];
+ NR::Coord gx = rgr->px2gs[0] * x0 + rgr->px2gs[2] * y + rgr->px2gs[4];
+ NR::Coord gy = rgr->px2gs[1] * x0 + rgr->px2gs[3] * y + rgr->px2gs[5];
+ NR::Coord const dx = rgr->px2gs[0];
+ NR::Coord const dy = rgr->px2gs[1];
for (int x = x0; x < x1; x++) {
NR::Coord const gx2 = gx * gx;
NR::Coord const gxy2 = gx2 + gy * gy;
NR::Coord const pxgx = gx + sqrt(qgx2_4);
/* We can safely divide by 0 here */
/* If we are sure pxgx cannot be -0 */
- NR::Coord const pos = gxy2 / pxgx * NR_GRADIENT_VECTOR_LENGTH;
+ NR::Coord const pos = gxy2 / pxgx * (NR_GRADIENT_VECTOR_LENGTH-1);
unsigned char const *s;
if (pos < (1U << 31)) {
} else {
s = vector_index(NR_GRADIENT_VECTOR_LENGTH - 1, rgr->vector);
}
-
- compose::compose(pb, d, &spb, s);
- d += bpp;
+ compose::compose(pb, d, &spb, s);
+ d += compose::bpp;
gx += dx;
gy += dy;
nr_rgradient_renderer_setup(NRRGradientRenderer *rgr,
unsigned char const *cv,
unsigned spread,
- NRMatrix const *gs2px,
+ NR::Matrix const *gs2px,
float cx, float cy,
float fx, float fy,
float r)
NR_DF_TEST_CLOSE(cy, fy, NR_EPSILON)) {
rgr->render = render<SymmetricRadial>;
- nr_matrix_invert(&rgr->px2gs, gs2px);
- rgr->px2gs.c[0] *= (NR_GRADIENT_VECTOR_LENGTH / r);
- rgr->px2gs.c[1] *= (NR_GRADIENT_VECTOR_LENGTH / r);
- rgr->px2gs.c[2] *= (NR_GRADIENT_VECTOR_LENGTH / r);
- rgr->px2gs.c[3] *= (NR_GRADIENT_VECTOR_LENGTH / r);
- rgr->px2gs.c[4] -= cx;
- rgr->px2gs.c[5] -= cy;
- rgr->px2gs.c[4] *= (NR_GRADIENT_VECTOR_LENGTH / r);
- rgr->px2gs.c[5] *= (NR_GRADIENT_VECTOR_LENGTH / r);
+ rgr->px2gs = gs2px->inverse();
+ rgr->px2gs[0] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r;
+ rgr->px2gs[1] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r;
+ rgr->px2gs[2] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r;
+ rgr->px2gs[3] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r;
+ rgr->px2gs[4] -= cx;
+ rgr->px2gs[5] -= cy;
+ rgr->px2gs[4] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r;
+ rgr->px2gs[5] *= (NR_GRADIENT_VECTOR_LENGTH-1) / r;
+ rgr->px2gs[4] += 0.5*(rgr->px2gs[0]+rgr->px2gs[2]); // These offsets make sure the gradient is sampled in the MIDDLE of each pixel
+ rgr->px2gs[5] += 0.5*(rgr->px2gs[1]+rgr->px2gs[3]);
rgr->cx = 0.0;
rgr->cy = 0.0;
fy = cy + (fy - cy ) * r / (float) df;
}
- NRMatrix n2gs;
- n2gs.c[0] = cx - fx;
- n2gs.c[1] = cy - fy;
- n2gs.c[2] = cy - fy;
- n2gs.c[3] = fx - cx;
- n2gs.c[4] = fx;
- n2gs.c[5] = fy;
+ NR::Matrix n2gs;
+ n2gs[0] = cx - fx;
+ n2gs[1] = cy - fy;
+ n2gs[2] = cy - fy;
+ n2gs[3] = fx - cx;
+ n2gs[4] = fx;
+ n2gs[5] = fy;
- NRMatrix n2px;
- nr_matrix_multiply(&n2px, &n2gs, gs2px);
- nr_matrix_invert(&rgr->px2gs, &n2px);
+ NR::Matrix n2px;
+ n2px = n2gs * (*gs2px);
+ rgr->px2gs = n2px.inverse();
+ rgr->px2gs[4] += 0.5*(rgr->px2gs[0]+rgr->px2gs[2]); // These offsets make sure the gradient is sampled in the MIDDLE of each pixel
+ rgr->px2gs[5] += 0.5*(rgr->px2gs[1]+rgr->px2gs[3]);
rgr->cx = 1.0;
rgr->cy = 0.0;
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :