From 19e87a00961b24e446ee247569db5300b3974b04 Mon Sep 17 00:00:00 2001 From: Sebastian Rasmussen Date: Wed, 29 Dec 2010 19:14:58 +0000 Subject: Support radial shadings as another special case in the fitz renderer. --- draw/meshdraw.c | 177 +++++++++++++++++++++++++++++++++++++++++++----------- fitz/fitz.h | 2 +- mupdf/pdf_shade.c | 88 ++++----------------------- 3 files changed, 156 insertions(+), 111 deletions(-) diff --git a/draw/meshdraw.c b/draw/meshdraw.c index df4dfe41..434be9a1 100644 --- a/draw/meshdraw.c +++ b/draw/meshdraw.c @@ -306,18 +306,56 @@ fz_drawtriangle(fz_pixmap *pix, float *av, float *bv, float *cv, int n, fz_bbox } } +static void +fz_drawquad(fz_pixmap *pix, + fz_point p0, fz_point p1, fz_point p2, fz_point p3, + float c0, float c1, float c2, float c3, + int n, fz_bbox bbox) +{ + float v[4][3]; + + v[0][0] = p0.x; + v[0][1] = p0.y; + v[0][2] = c0; + + v[1][0] = p1.x; + v[1][1] = p1.y; + v[1][2] = c1; + + v[2][0] = p2.x; + v[2][1] = p2.y; + v[2][2] = c2; + + v[3][0] = p3.x; + v[3][1] = p3.y; + v[3][2] = c3; + + fz_drawtriangle(pix, v[0], v[2], v[3], n, bbox); + fz_drawtriangle(pix, v[0], v[3], v[1], n, bbox); +} + /* - * mesh drawing + * linear, radial and mesh drawing */ -#define HUGENUM 32000 +#define HUGENUM 32000 /* how far to extend axial/radial shadings */ +#define RADSEGS 32 /* how many segments to generate for radial meshes */ + +static fz_point +fz_pointoncircle(fz_point p, float r, float theta) +{ + p.x = p.x + cosf(theta) * r; + p.y = p.y + sinf(theta) * r; + + return p; +} static void fz_renderlinear(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) { - float v[4][3]; - float e[2][3]; fz_point p0, p1; + fz_point v0, v1, v2, v3; + fz_point e0, e1; float theta; p0.x = shade->mesh[0]; @@ -331,51 +369,118 @@ fz_renderlinear(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) theta = atan2f(p1.y - p0.y, p1.x - p0.x); theta += (float)M_PI * 0.5f; - v[0][0] = p0.x + HUGENUM * cosf(theta); - v[0][1] = p0.y + HUGENUM * sinf(theta); - v[0][2] = 0; + v0 = fz_pointoncircle(p0, HUGENUM, theta); + v1 = fz_pointoncircle(p1, HUGENUM, theta); + v2 = fz_pointoncircle(p0, -HUGENUM, theta); + v3 = fz_pointoncircle(p1, -HUGENUM, theta); + + fz_drawquad(dest, v0, v1, v2, v3, 0, 255, 0, 255, 3, bbox); + + if (shade->extend[0]) + { + e0.x = v0.x - (p1.x - p0.x) * HUGENUM; + e0.y = v0.y - (p1.y - p0.y) * HUGENUM; + + e1.x = v2.x - (p1.x - p0.x) * HUGENUM; + e1.y = v2.y - (p1.y - p0.y) * HUGENUM; - v[1][0] = p1.x + HUGENUM * cosf(theta); - v[1][1] = p1.y + HUGENUM * sinf(theta); - v[1][2] = 255; + fz_drawquad(dest, e0, v0, v2, e1, 0, 0, 0, 0, 3, bbox); + } - v[2][0] = p0.x - HUGENUM * cosf(theta); - v[2][1] = p0.y - HUGENUM * sinf(theta); - v[2][2] = 0; + if (shade->extend[1]) + { + e0.x = v1.x - (p1.x - p0.x) * HUGENUM; + e0.y = v1.y - (p1.y - p0.y) * HUGENUM; - v[3][0] = p1.x - HUGENUM * cosf(theta); - v[3][1] = p1.y - HUGENUM * sinf(theta); - v[3][2] = 255; + e1.x = v3.x - (p1.x - p0.x) * HUGENUM; + e1.y = v3.y - (p1.y - p0.y) * HUGENUM; - fz_drawtriangle(dest, v[0], v[1], v[2], 3, bbox); - fz_drawtriangle(dest, v[1], v[2], v[3], 3, bbox); + fz_drawquad(dest, e0, v1, v3, e1, 255, 255, 255, 255, 3, bbox); + } +} + +static void +fz_renderannulus(fz_matrix ctm, + fz_point p0, float r0, float c0, + fz_point p1, float r1, float c1, + fz_pixmap *dest, fz_bbox bbox) +{ + fz_point t0, t1, t2, t3, b0, b1, b2, b3; + float theta, step; + int i; + + theta = atan2f(p1.y - p0.y, p1.x - p0.x); + step = (float)M_PI * 2 / RADSEGS; + + for (i = 0; i < RADSEGS / 2; i++) + { + t0 = fz_pointoncircle(p0, r0, theta + i * step); + t1 = fz_pointoncircle(p0, r0, theta + i * step + step); + t2 = fz_pointoncircle(p1, r1, theta + i * step); + t3 = fz_pointoncircle(p1, r1, theta + i * step + step); + b0 = fz_pointoncircle(p0, r0, theta - i * step); + b1 = fz_pointoncircle(p0, r0, theta - i * step - step); + b2 = fz_pointoncircle(p1, r1, theta - i * step); + b3 = fz_pointoncircle(p1, r1, theta - i * step - step); + + t0 = fz_transformpoint(ctm, t0); + t1 = fz_transformpoint(ctm, t1); + t2 = fz_transformpoint(ctm, t2); + t3 = fz_transformpoint(ctm, t3); + b0 = fz_transformpoint(ctm, b0); + b1 = fz_transformpoint(ctm, b1); + b2 = fz_transformpoint(ctm, b2); + b3 = fz_transformpoint(ctm, b3); + + fz_drawquad(dest, t0, t1, t2, t3, c0, c0, c1, c1, 3, bbox); + fz_drawquad(dest, b0, b1, b2, b3, c0, c0, c1, c1, 3, bbox); + } +} + +static void +fz_renderradial(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) +{ + fz_point p0, p1; + float r0, r1; + fz_point e; + float er, rs; + + p0.x = shade->mesh[0]; + p0.y = shade->mesh[1]; + r0 = shade->mesh[2]; + + p1.x = shade->mesh[3]; + p1.y = shade->mesh[4]; + r1 = shade->mesh[5]; + + fz_renderannulus(ctm, p0, r0, 0, p1, r1, 255, dest, bbox); if (shade->extend[0]) { - e[0][0] = v[0][0] - (p1.x - p0.x) * HUGENUM; - e[0][1] = v[0][1] - (p1.y - p0.y) * HUGENUM; - e[0][2] = v[0][2]; + if (r0 < r1) + rs = r0 / (r0 - r1); + else + rs = -HUGENUM; - e[1][0] = v[2][0] - (p1.x - p0.x) * HUGENUM; - e[1][1] = v[2][1] - (p1.y - p0.y) * HUGENUM; - e[1][2] = v[2][2]; + e.x = p0.x + (p1.x - p0.x) * rs; + e.y = p0.y + (p1.y - p0.y) * rs; + er = r0 + (r1 - r0) * rs; - fz_drawtriangle(dest, e[0], v[0], v[2], 3, bbox); - fz_drawtriangle(dest, e[0], v[2], e[1], 3, bbox); + fz_renderannulus(ctm, e, er, 0, p0, r0, 0, dest, bbox); } if (shade->extend[1]) { - e[0][0] = v[1][0] + (p1.x - p0.x) * HUGENUM; - e[0][1] = v[1][1] + (p1.y - p0.y) * HUGENUM; - e[0][2] = v[1][2]; + if (r0 > r1) + rs = r1 / (r1 - r0); + else + rs = -HUGENUM; - e[1][0] = v[3][0] + (p1.x - p0.x) * HUGENUM; - e[1][1] = v[3][1] + (p1.y - p0.y) * HUGENUM; - e[1][2] = v[3][2]; + e.x = p1.x + (p0.x - p1.x) * rs; + e.y = p1.y + (p0.y - p1.y) * rs; + er = r1 + (r0 - r1) * rs; - fz_drawtriangle(dest, e[0], v[1], v[3], 3, bbox); - fz_drawtriangle(dest, e[0], v[3], e[1], 3, bbox); + fz_renderannulus(ctm, p1, r1, 255, e, er, 255, dest, bbox); } } @@ -450,7 +555,9 @@ fz_rendershade(fz_shade *shade, fz_matrix ctm, fz_pixmap *dest, fz_bbox bbox) case FZ_LINEAR: fz_renderlinear(shade, ctm, temp, bbox); break; - /* TODO: FZ_RADIAL */ + case FZ_RADIAL: + fz_renderradial(shade, ctm, temp, bbox); + break; case FZ_MESH: fz_rendermesh(shade, ctm, temp, bbox); break; diff --git a/fitz/fitz.h b/fitz/fitz.h index 3275dc4e..e35bf0f9 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -823,7 +823,7 @@ struct fz_shade_s int meshlen; int meshcap; - float *mesh; /* [x y t] or [x y c1 ... cn] */ + float *mesh; /* [x y 0], [x y r], [x y t] or [x y c1 ... cn] */ }; fz_shade *fz_keepshade(fz_shade *shade); diff --git a/mupdf/pdf_shade.c b/mupdf/pdf_shade.c index caa0b98e..ef19d1a4 100644 --- a/mupdf/pdf_shade.c +++ b/mupdf/pdf_shade.c @@ -507,62 +507,12 @@ pdf_loadaxialshading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, p p2.x = x1; p2.y = y1; - p2.c[0] = 1; + p2.c[0] = 0; pdf_addvertex(shade, &p2); return fz_okay; } -static void -pdf_buildannulusmesh(fz_shade *shade, - float x0, float y0, float r0, float c0, - float x1, float y1, float r1, float c1) -{ - struct vertex a, b, c, d; - float start = atan2(y1 - y0, x1 - x0); - float step = (float)M_PI * 2 / RADSEGS; - float angle; - int i; - - a.c[0] = c0; - b.c[0] = c0; - c.c[0] = c1; - d.c[0] = c1; - - for (i = 0; i < RADSEGS / 2; i ++) - { - /* top side */ - angle = start + i * step; - a.x = x0 + cosf(angle) * r0; - a.y = y0 + sinf(angle) * r0; - b.x = x0 + cosf(angle + step) * r0; - b.y = y0 + sinf(angle + step) * r0; - c.x = x1 + cosf(angle) * r1; - c.y = y1 + sinf(angle) * r1; - d.x = x1 + cosf(angle + step) * r1; - d.y = y1 + sinf(angle + step) * r1; - if (r1 > 0) /* a == b, c != d */ - pdf_addtriangle(shade, &a, &c, &d); - if (r0 > 0) /* a != b, c == d */ - pdf_addtriangle(shade, &a, &d, &b); - - /* bottom side */ - angle = start - i * step; - a.x = x0 + cosf(angle) * r0; - a.y = y0 + sinf(angle) * r0; - b.x = x0 + cosf(angle - step) * r0; - b.y = y0 + sinf(angle - step) * r0; - c.x = x1 + cosf(angle) * r1; - c.y = y1 + sinf(angle) * r1; - d.x = x1 + cosf(angle - step) * r1; - d.y = y1 + sinf(angle - step) * r1; - if (r1 > 0) /* a == b, c != d */ - pdf_addtriangle(shade, &a, &c, &d); - if (r0 > 0) /* a != b, c == d */ - pdf_addtriangle(shade, &a, &d, &b); - } -} - static fz_error pdf_loadradialshading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, pdf_function **func) { @@ -571,9 +521,7 @@ pdf_loadradialshading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, float d0, d1; int e0, e1; float x0, y0, r0, x1, y1, r1; - float ex0, ey0, er0; - float ex1, ey1, er1; - float rs; + struct vertex p1, p2; pdf_logshade("load type3 (radial) shading\n"); @@ -608,30 +556,20 @@ pdf_loadradialshading(fz_shade *shade, pdf_xref *xref, fz_obj *dict, int funcs, if (error) return fz_rethrow(error, "unable to sample shading function"); - if (r0 < r1) - rs = r0 / (r0 - r1); - else - rs = -HUGENUM; - - ex0 = x0 + (x1 - x0) * rs; - ey0 = y0 + (y1 - y0) * rs; - er0 = r0 + (r1 - r0) * rs; - - if (r0 > r1) - rs = r1 / (r1 - r0); - else - rs = -HUGENUM; + shade->type = FZ_RADIAL; - ex1 = x1 + (x0 - x1) * rs; - ey1 = y1 + (y0 - y1) * rs; - er1 = r1 + (r0 - r1) * rs; + shade->extend[0] = e0; + shade->extend[1] = e1; - if (e0) - pdf_buildannulusmesh(shade, ex0, ey0, er0, 0, x0, y0, r0, 0); - pdf_buildannulusmesh(shade, x0, y0, r0, 0, x1, y1, r1, 1); - if (e1) - pdf_buildannulusmesh(shade, x1, y1, r1, 1, ex1, ey1, er1, 1); + p1.x = x0; + p1.y = y0; + p1.c[0] = r0; + pdf_addvertex(shade, &p1); + p2.x = x1; + p2.y = y1; + p2.c[0] = r1; + pdf_addvertex(shade, &p2); return fz_okay; } -- cgit v1.2.3