diff options
Diffstat (limited to 'generic/Draw.c')
-rw-r--r-- | generic/Draw.c | 2245 |
1 files changed, 0 insertions, 2245 deletions
diff --git a/generic/Draw.c b/generic/Draw.c deleted file mode 100644 index 3c0a37c..0000000 --- a/generic/Draw.c +++ /dev/null @@ -1,2245 +0,0 @@ -/* - * Draw.c -- Implementation of common drawing routines. - * - * Authors : Patrick Lecoanet. - * Creation date : Sat Dec 10 12:51:30 1994 - * - * $Id$ - */ - -/* - * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- - * - * See the file "Copyright" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - */ - - -/* - ********************************************************************************** - * - * The algorihms used to draw the arrows, to do the 3d effects and to - * smooth the polygons are adapted from Tk. - * - ********************************************************************************** - */ - -#include "Types.h" -#include "Draw.h" -#include "Geo.h" -#include "List.h" -#include "WidgetInfo.h" -#include "Image.h" -#include "tkZinc.h" - -#include <math.h> -#include <stdarg.h> - - -#define POLYGON_RELIEF_DRAW 0 -#define POLYGON_RELIEF_RENDER 1 -#define POLYGON_RELIEF_DIST 2 -#define POLYGON_RELIEF_BBOX 3 -#define POLYGON_RELIEF_IN_BBOX 4 - -#define TOP_CONTRAST 13 -#define BOTTOM_CONTRAST 6 -#define MAX_INTENSITY 65535 - -#define ARROW_SHAPE_B 10.0 -#define ARROW_SHAPE_C 5.0 -#define OPEN_ARROW_SHAPE_A 4.0 -#define CLOSED_ARROW_SHAPE_A ARROW_SHAPE_B - -#define LIGHTNING_SHAPE_A_RATIO 10.0 -#define LIGHTNING_SHAPE_B_RATIO 8.0 - -#define LIGHTNING_POINTS 4 -#define CORNER_POINTS 3 -#define DOUBLE_CORNER_POINTS 4 -#define STRAIGHT_POINTS 2 - - -/* - ********************************************************************************** - * - * ZnSetLineStyle -- - * - ********************************************************************************** - */ -void -ZnSetLineStyle(ZnWInfo *wi, - ZnLineStyle line_style) -{ - if (wi->render) { -#ifdef GL - switch (line_style) { - case ZN_LINE_DASHED : - glLineStipple(1, 0xF0F0); - glEnable(GL_LINE_STIPPLE); - break; - case ZN_LINE_MIXED : - glLineStipple(1, 0x27FF); - glEnable(GL_LINE_STIPPLE); - break; - case ZN_LINE_DOTTED : - glLineStipple(1, 0x18C3); - glEnable(GL_LINE_STIPPLE); - break; - default: - glDisable(GL_LINE_STIPPLE); - } -#endif - } - else { - XGCValues values; - static const char dashed[] = { 8 }; - static const char dotted[] = { 2, 5 }; - static const char mixed[] = { 8, 5, 2, 5 }; - - values.line_style = LineOnOffDash; - switch (line_style) { - case ZN_LINE_DASHED : - XSetDashes(wi->dpy, wi->gc, 0, dashed, 1); - break; - case ZN_LINE_MIXED : - XSetDashes(wi->dpy, wi->gc, 0, mixed, 4); - break; - case ZN_LINE_DOTTED : - XSetDashes(wi->dpy, wi->gc, 0, dotted, 2); - break; - default: - values.line_style = LineSolid; - break; - } - XChangeGC(wi->dpy, wi->gc, GCLineStyle, &values); - } -} - - -/* - ********************************************************************************** - * - * ZnLineShapePoints -- - * Compute the points describing the given line shape between point p1 and p2. - * If bbox is non null, it is filled with the bounding box of the shape. - * - * For the time being this procedure handles straight lines, right and left - * lightnings, right and left corners, right and left double corners.. - * - * - * Here are the parameters for lightnings: - * - * ******* - * ******* * - * ****** * - * ****** ******+ * - * ****** ****** * *| - * ****** ****** * * | LIGHTNING_SHAPE_A - * ****** ****** * * | - * ****** * * | - * ..******.........................+.+.*........................******.. - * | * * ****** - * | * * ****** ****** - * | * * ****** ****** - * | * * ****** ****** - * | * ******* ****** - * | * ****** - * | * ****** - * | ******** - * | | | | - * | |----| | LIGHTNING_SHAPE_B - * | | - * |--------------------------------| LENGTH / 2 - * - ********************************************************************************** - */ -void -ZnLineShapePoints(ZnPoint *p1, - ZnPoint *p2, - ZnDim line_width, - ZnLineShape shape, - ZnBBox *bbox, - ZnList to_points) -{ - ZnPoint *points; - unsigned int num_points, i; - - /* - * Compute all line points according to shape. - */ - if ((shape == ZN_LINE_LEFT_LIGHTNING) || - (shape == ZN_LINE_RIGHT_LIGHTNING)) { - double alpha, theta; - double length, length2; - double shape_a, shape_b; - double dx, dy; - double temp; - - num_points = LIGHTNING_POINTS; - ZnListAssertSize(to_points, num_points); - points = (ZnPoint *) ZnListArray(to_points); - - points[0] = *p1; - points[3] = *p2; - - dx = p2->x - p1->x; - dy = p2->y - p1->y; - length = hypot(dx, dy); - shape_a = length/LIGHTNING_SHAPE_A_RATIO + line_width/2.0; - shape_b = length/LIGHTNING_SHAPE_B_RATIO + line_width/2.0; - - if (shape == ZN_LINE_LEFT_LIGHTNING) - alpha = atan2(shape_a, shape_b); - else - alpha = -atan2(shape_a, shape_b); - length2 = hypot(shape_a, shape_b); - theta = atan2(-dy, dx); - - dx = p1->x + dx/2; - dy = p1->y + dy/2; - temp = cos(theta + alpha) * length2; - points[1].x = dx + temp; - points[2].x = dx - temp; - temp = sin(theta + alpha) * length2; - points[1].y = dy - temp; - points[2].y = dy + temp; - } - else if (shape == ZN_LINE_LEFT_CORNER || - shape == ZN_LINE_RIGHT_CORNER) { - num_points = CORNER_POINTS; - ZnListAssertSize(to_points, num_points); - points = (ZnPoint *) ZnListArray(to_points); - - points[0] = *p1; - points[2] = *p2; - - if (shape == ZN_LINE_LEFT_CORNER) { - points[1].x = p1->x; - points[1].y = p2->y; - } - else { - points[1].x = p2->x; - points[1].y = p1->y; - } - } - else if (shape == ZN_LINE_DOUBLE_LEFT_CORNER || - shape == ZN_LINE_DOUBLE_RIGHT_CORNER) { - int dx, dy; - - num_points = DOUBLE_CORNER_POINTS; - ZnListAssertSize(to_points, num_points); - points = (ZnPoint *) ZnListArray(to_points); - - points[0] = *p1; - points[3] = *p2; - - if (shape == ZN_LINE_DOUBLE_LEFT_CORNER) { - dy = (int) (p2->y - p1->y); - points[1].x = p1->x; - points[2].x = p2->x; - points[1].y = points[2].y = p1->y + dy/2; - } - else { - dx = (int) (p2->x - p1->x); - points[1].x = points[2].x = p1->x + dx/2; - points[1].y = p1->y; - points[2].y = p2->y; - } - } - else /* if (shape) == ZN_LINE_STRAIGHT) */ { - num_points = STRAIGHT_POINTS; - ZnListAssertSize(to_points, num_points); - points = (ZnPoint *) ZnListArray(to_points); - - points[0] = *p1; - points[1] = *p2; - } - - /* - * Fill in the bbox, if requested. - */ - if (bbox) { - ZnResetBBox(bbox); - for (i = 0; i < num_points; i++) { - ZnAddPointToBBox(bbox, points[i].x, points[i].y); - } - - /* Enlarge to take line_width into account. */ - if (line_width > 1) { - ZnDim lw_2 = (line_width+1)/2; - - bbox->orig.x -= lw_2; - bbox->orig.y -= lw_2; - bbox->corner.x += lw_2; - bbox->corner.y += lw_2; - } - } -} - - -/* - ********************************************************************************** - * - * ZnDrawLineShape -- - * Draw a line given the points describing its path. It is designed to work - * with GetLineShape albeit it does fairly trivial things. In the future some - * shapes might need cooperation between the two and the clients will be ready - * for that. - * - * - ********************************************************************************** - */ -void -ZnDrawLineShape(ZnWInfo *wi, - ZnPoint *p, - unsigned int num_p, - ZnLineStyle line_style, - int foreground_pixel, - ZnDim line_width, - ZnLineShape shape) -{ - XPoint *xpoints; - unsigned int i; - XGCValues values; - - /* - * Setup GC. - */ - ZnSetLineStyle(wi, line_style); - values.foreground = foreground_pixel; - values.line_width = (line_width == 1) ? 0 : (int) line_width; - values.fill_style = FillSolid; - values.join_style = JoinRound; - values.cap_style = CapRound; - XChangeGC(wi->dpy, wi->gc, - GCFillStyle|GCLineWidth|GCJoinStyle|GCCapStyle|GCForeground, &values); - ZnListAssertSize(ZnWorkXPoints, num_p); - xpoints = (XPoint *) ZnListArray(ZnWorkXPoints); - for (i = 0; i < num_p; i++) { - xpoints[i].x = (short) p[i].x; - xpoints[i].y = (short) p[i].y; - } - XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, xpoints, (int) num_p, CoordModeOrigin); -} - - -/* - ********************************************************************************** - * - * ZnGetLineEnd -- - * Compute the points describing the given line end style at point p1 for - * the line p1,p2. Point p1 is adjusted to fit the line end. - * If bbox is non null, it is filled with the bounding box of the end. - * - * For the time being this procedure handles open/filled arrows. - * - * Here are the parameters describing arrows. - * - * * | ARROW_SHAPE_C - * ** | - * * *************************** - * * * - * * * +p1 +p2 - * | * |* - * | * *************************** - * | | ** - * | | * - * | | | - * |---| | ARROW_SHAPE_A - * | | - * |-------| ARROW_SHAPE_B - * - ********************************************************************************** - */ -void -ZnGetLineEnd(ZnPoint *p1, - ZnPoint *p2, - ZnDim line_width, - int cap_style, - ZnLineEnd end_style, - ZnPoint *points) -{ - ZnReal dx, dy, length, temp, backup; - ZnReal frac_height, sin_theta, cos_theta; - ZnReal vert_x, vert_y; - ZnReal shape_a, shape_b, shape_c; - - if (end_style != NULL) { - shape_a = end_style->shape_a + 0.001; - shape_b = end_style->shape_b + 0.001; - shape_c = end_style->shape_c + line_width/2.0 + 0.001; - - frac_height = (line_width/2.0) / shape_c; - dx = p1->x - p2->x; - dy = p1->y - p2->y; - length = hypot(dx, dy); - if (length == 0) { - sin_theta = cos_theta = 0.0; - } - else { - sin_theta = dy/length; - cos_theta = dx/length; - } - - if (cap_style != CapProjecting) { - temp = frac_height; - } - else { - temp = line_width / shape_c; - } - backup = temp * shape_b + shape_a * (1.0 - temp) / 2.0; - points[0].x = points[5].x = p1->x + backup * cos_theta; - points[0].y = points[5].y = p1->y + backup * sin_theta; - - vert_x = points[0].x - shape_a*cos_theta; - vert_y = points[0].y - shape_a*sin_theta; - temp = shape_c*sin_theta; - points[1].x = ZnNearestInt(points[0].x - shape_b*cos_theta + temp); - points[4].x = ZnNearestInt(points[1].x - 2*temp); - temp = shape_c*cos_theta; - points[1].y = ZnNearestInt(points[0].y - shape_b*sin_theta - temp); - points[4].y = ZnNearestInt(points[1].y + 2*temp); - points[2].x = ZnNearestInt(points[1].x*frac_height + vert_x*(1.0-frac_height)); - points[2].y = ZnNearestInt(points[1].y*frac_height + vert_y*(1.0-frac_height)); - points[3].x = ZnNearestInt(points[4].x*frac_height + vert_x*(1.0-frac_height)); - points[3].y = ZnNearestInt(points[4].y*frac_height + vert_y*(1.0-frac_height)); - } -} - -static ZnReal -SegmentPosInRelief(ZnReal x1, - ZnReal y1, - ZnReal x2, - ZnReal y2, - ZnReliefStyle relief, - int light_angle) -{ - ZnReal angle, angle_step, origin, position; - int num_colors, color_index; - - num_colors = ZN_RELIEF_STEPS*2+1; - angle_step = M_PI / (num_colors-1); - origin = -(ZnDegRad(light_angle))-(angle_step/2.0); - if (relief == ZN_RELIEF_SUNKEN) { - origin += M_PI; - } - - angle = ZnProjectionToAngle(y1 - y2, x2 - x1) + M_PI - origin; - while (angle < 0.0) { - angle += 2*M_PI; - } - while (angle > 2*M_PI) { - angle -= 2*M_PI; - } - - color_index = (int) (angle/angle_step); - if (color_index > num_colors-1) { - color_index = 2*(num_colors-1)-color_index; - } - if ((color_index < 0) || (color_index >= num_colors)) { - fprintf(stderr, "Color index out of gradient (should not happen).\n"); - if (color_index < 0) { - color_index = 0; - } - if (color_index >= num_colors) { - color_index = num_colors-1; - } - } - position = 100*color_index/num_colors; - /*printf("position %g, angle %g(%g), origin %g\n", - position, - RadianToDegrees(angle), - angle, - RadianToDegrees(origin));*/ - return position; -} - -/* - * ReliefColorOfSegment -- - * ReliefPixelOfSegment -- - */ -static XColor * -ReliefColorOfSegment(ZnReal x1, - ZnReal y1, - ZnReal x2, - ZnReal y2, - ZnReliefStyle relief, - ZnGradient *gradient, - int light_angle) -{ - return ZnGetGradientColor(gradient, - SegmentPosInRelief(x1, y1, x2, y2, relief, light_angle), - NULL); -} - -static int -ReliefPixelOfSegment(ZnReal x1, - ZnReal y1, - ZnReal x2, - ZnReal y2, - ZnReliefStyle relief, - ZnGradient *gradient, - int light_angle) -{ - return ZnGetGradientPixel(gradient, - SegmentPosInRelief(x1, y1, x2, y2, relief, light_angle)); -} - - -/* - ********************************************************************************** - * - * ZnDrawRectangleRelief -- - * Draw the bevels inside bbox. - * - ********************************************************************************** - */ -void -ZnDrawRectangleRelief(ZnWInfo *wi, - ZnReliefStyle relief, - ZnGradient *gradient, - XRectangle *bbox, - ZnDim line_width) -{ - XPoint bevel[4]; - - /* - * If we haven't enough space to draw, exit. - */ - if ((bbox->width < 2*line_width) || (bbox->height < 2*line_width)) { - return; - } - - /* - * Grooves and ridges are drawn with two recursives calls with - * half the width of the original one. - */ - if ((relief == ZN_RELIEF_RIDGE) || (relief == ZN_RELIEF_GROOVE)) { - ZnDim new_line_width; - unsigned int offset; - XRectangle internal_bbox; - - new_line_width = line_width/2.0; - offset = (unsigned) (line_width - new_line_width); - ZnDrawRectangleRelief(wi, - (ZnReliefStyle) ((relief==ZN_RELIEF_GROOVE)?ZN_RELIEF_SUNKEN:ZN_RELIEF_RAISED), - gradient, bbox, new_line_width); - internal_bbox = *bbox; - internal_bbox.x += offset; - internal_bbox.y += offset; - internal_bbox.width -= offset*2; - internal_bbox.height -= offset*2; - ZnDrawRectangleRelief(wi, - (ZnReliefStyle) ((relief==ZN_RELIEF_GROOVE)?ZN_RELIEF_RAISED:ZN_RELIEF_SUNKEN), - gradient, &internal_bbox, new_line_width); - return; - } - - XSetFillStyle(wi->dpy, wi->gc, FillSolid); - - bevel[0].x = bbox->x; - bevel[0].y = bevel[1].y = bbox->y; - bevel[1].x = bbox->x + bbox->width; - bevel[2].y = bevel[3].y = bbox->y + (short) line_width; - bevel[2].x = bevel[1].x - (short) line_width; - bevel[3].x = bevel[0].x + (short) line_width; - XSetForeground(wi->dpy, wi->gc, - ReliefPixelOfSegment((ZnReal) bevel[1].x, (ZnReal) bevel[1].y, - (ZnReal) bevel[0].x, (ZnReal) bevel[0].y, - relief, gradient, wi->light_angle)); - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); - - bevel[0] = bevel[1]; - bevel[3] = bevel[2]; - bevel[1].y += bbox->height; - bevel[2].y = bevel[1].y - (short) line_width; - XSetForeground(wi->dpy, wi->gc, - ReliefPixelOfSegment((ZnReal) bevel[1].x, (ZnReal) bevel[1].y, - (ZnReal) bevel[0].x, (ZnReal) bevel[0].y, - relief, gradient, wi->light_angle)); - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); - - bevel[0] = bevel[1]; - bevel[3] = bevel[2]; - bevel[1].x -= bbox->width; - bevel[2].x = bevel[1].x + (short) line_width; - XSetForeground(wi->dpy, wi->gc, - ReliefPixelOfSegment((ZnReal) bevel[1].x, (ZnReal) bevel[1].y, - (ZnReal) bevel[0].x, (ZnReal) bevel[0].y, - relief, gradient, wi->light_angle)); - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); - - bevel[0] = bevel[1]; - bevel[3] = bevel[2]; - bevel[1].x = bbox->x; - bevel[1].y = bbox->y; - bevel[2].x = bevel[3].x; - bevel[2].y = bbox->y + (short) line_width; - XSetForeground(wi->dpy, wi->gc, - ReliefPixelOfSegment((ZnReal) bevel[1].x, (ZnReal) bevel[1].y, - (ZnReal) bevel[0].x, (ZnReal) bevel[0].y, - relief, gradient, wi->light_angle)); - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel, 4, Convex, CoordModeOrigin); -} - - -typedef struct { - ZnWInfo *wi; - ZnPoint *pp; - ZnPoint *p0; - ZnPoint *p1; - double dist; - ZnBBox *bbox; - ZnReliefStyle relief; - ZnGradient *gradient; - unsigned short alpha; - ZnBool smooth; - int result; - int count; - ZnBool toggle; -} PolygonData; - -static void -DoPolygon(ZnPoint *p, - unsigned int num_points, - ZnDim line_width, - ZnBool (*cb)(ZnPoint *bevels, PolygonData *pd), - PolygonData *pd) -{ - int i; - unsigned int processed_points; - ZnPoint *p1, *p11=NULL, *p2; - ZnPoint pp1, pp2, new_pp1, new_pp2; - ZnPoint perp, c, shift1, shift2; - ZnPoint bevel_points[4]; - ZnBool folded, closed, colinear; - ZnReal dx, dy; - - if (num_points < 2) { - return; - } - - /* - * If the polygon is closed (last point is the same as first) open it by - * dropping the last point. The algorithm closes the path automatically. - * We remember this to decide if we draw the last bevel or not and if we - * need to generate ends perpendicular to the path.. - */ - closed = False; - if ((p->x == p[num_points-1].x) && (p->y == p[num_points-1].y)) { - closed = True; - num_points--; - } - /*printf("num_points=%d(%s)\n", num_points, closed?"closed":"");*/ - - /* - * We loop on all vertices of the polygon. - * At each step we try to compute the corresponding border - * corner `corner'. Then we build a polygon for the bevel. - * Things look like this: - * - * bevel[1] / - * * / - * | / - * | / - * pp1 * * p[i-1] - * | | bevel[0] - * | | - * | | - * | | bevel[3] - * | | p[i] - * | | p1 p2 - * pp2 * *--------------------* - * | - * | - * corner *----*--------------------* - * bevel[2] new_pp1 new_pp2 - * - * pp1 and pp2 are the ends of a segment // to p1 p2 at line_width - * from it. These points are *NOT* necessarily on the perpendicular - * going through p1 or p2. - * This loop needs a bootstrap phase of two iterations (i.e we need to - * process two points). This is why we start at the point before the last - * and then wrap to the first point. - * The algorithm discards any duplicate contiguous points. - * It makes a special case if two consecutives edges are folded: - * - * bevel[1] pp1 pp2 a bevel[2] - * *-----------*--------------*----------* - * \ - * \ - * p[i-1] \ bevel[3] - * *--------*-------------------------*---* corner - * bevel[0] p2 p1 / - * / - * / - * ----------*-----------*-------------* - * new_pp1 new_pp2 c - * - * In such a case we need to compute a, c, corner from pp1, pp2, new_pp1 - * and new_pp2. We compute the perpendicular to p1,p2 through p1, intersect - * it with pp1,pp2 to obtain a, intersect it with new_pp1, new_pp2 to - * obtain c, shift a,c and intersect it with p1,p2 to obtain corner. - * - */ - - processed_points = 0; - if (!closed) { - i = 0; - p1 = p; - } - else { - i = -2; - p1 = &p[num_points-2]; - } - - for (p2 = p1+1; i < (int) num_points; i++, p2++) { - /* - * When it is time to wrap, do it - */ - if ((i == -1) || (i == (int) num_points-1)) { - p2 = p; - } - /* - * Skip over close vertices. - */ - dx = p2->x - p1->x; - dy = p2->y - p1->y; - if ((ABS(dx) < 1.0) && (ABS(dy) < 1.0)) { - continue; - } - - ZnShiftLine(p1, p2, line_width, &new_pp1, &new_pp2); - bevel_points[3] = *p1; - folded = False; - colinear = False; - /* - * The first two cases are for `open' polygons. We compute - * a bevel closure that is perpendicular to the path. - */ - if ((processed_points == 0) && !closed) { - perp.x = p1->x + (p2->y - p1->y); - perp.y = p1->y - (p2->x - p1->x); - ZnIntersectLines(p1, &perp, &new_pp1, &new_pp2, &bevel_points[2]); - } - else if ((processed_points == num_points-1) && !closed) { - perp.x = p1->x + (p11->y - p1->y); - perp.y = p1->y - (p11->x - p1->x); - ZnIntersectLines(p1, &perp, &pp1, &pp2, &bevel_points[2]); - } - else if (processed_points >= 1) { - ZnReal dotp, dist, odx, ody; - - /* - * The dot product of the two faces tell if the are - * folded or colinear. The - */ - odx = p11->x - p1->x; - ody = p11->y - p1->y; - dotp = odx*dx + ody*dy; - dist = ZnLineToPointDist(p11, p2, p1, NULL); - if ((dist < 4.0) && (dotp <= 0)) { - perp.x = p1->x + (p2->y - p1->y); - perp.y = p1->y - (p2->x - p1->x); - ZnIntersectLines(p1, &perp, &new_pp1, &new_pp2, &bevel_points[2]); - colinear = True; - } - else { - folded = !ZnIntersectLines(&new_pp1, &new_pp2, &pp1, &pp2, &bevel_points[2]); - /*printf("new_pp1 %g@%g, new_pp2 %g@%g, pp1 %g@%g, pp2 %g@%g, inter %g@%g\n", - new_pp1.x, new_pp1.y, new_pp2.x, new_pp2.y, - pp1.x, pp1.y, pp2.x, pp2.y, - bevel_points[2].x, bevel_points[2].y);*/ - folded = folded && (dotp < 0); - if (folded) { - /*printf("DoPolygonRelief: folded edges detected, %g@%g, %g@%g, %g@%g, %g@%g\n", - pp1.x, pp1.y, pp2.x, pp2.y, new_pp1.x, new_pp1.y, - new_pp2.x, new_pp2.y);*/ - perp.x = p1->x + (p2->y - p1->y); - perp.y = p1->y - (p2->x - p1->x); - ZnIntersectLines(p1, &perp, &pp1, &pp2, &bevel_points[2]); - ZnIntersectLines(p1, &perp, &new_pp1, &new_pp2, &c); - ZnShiftLine(p1, &perp, line_width, &shift1, &shift2); - ZnIntersectLines(p1, p2, &shift1, &shift2, &bevel_points[3]); - } - } - } - - if ((processed_points >= 2) || (!closed && (processed_points == 1))) { - if ((processed_points == num_points-1) && !closed) { - pd->p0 = pd->p1 = NULL; - } - else { - pd->p0 = p1; - pd->p1 = p2; - } - if ((*cb)(bevel_points, pd)) { - return; - } - } - - p11 = p1; - p1 = p2; - pp1 = new_pp1; - pp2 = new_pp2; - bevel_points[0] = bevel_points[3]; - if (folded) { - bevel_points[1] = c; - } - else if ((processed_points >= 1) || !closed) { - bevel_points[1] = bevel_points[2]; - } - - processed_points++; - } -} - - -/* - ********************************************************************************** - * - * ZnGetPolygonReliefBBox -- - * Returns the bevelled polygon bounding box. - * - ********************************************************************************** - */ -static ZnBool -PolygonBBoxCB(ZnPoint *bevels, - PolygonData *pd) -{ - int i; - - for (i = 0; i < 4; i++) { - ZnAddPointToBBox(pd->bbox, bevels[i].x, bevels[i].y); - } - return 0; -} - -void -ZnGetPolygonReliefBBox(ZnPoint *points, - unsigned int num_points, - ZnDim line_width, - ZnBBox *bbox) -{ - PolygonData pd; - - pd.bbox = bbox; - ZnResetBBox(bbox); - DoPolygon(points, num_points, line_width, PolygonBBoxCB, &pd); -} - - -/* - ********************************************************************************** - * - * ZnPolygonReliefInBBox -- - * Returns (-1) if the relief is entirely outside the bbox, (1) if it is - * entirely inside or (0) if in between - * - ********************************************************************************** - */ -static ZnBool -PolygonInBBoxCB(ZnPoint *bevels, - PolygonData *pd) -{ - if (pd->count == 0) { - pd->count++; - pd->result = ZnPolygonInBBox(bevels, 4, pd->bbox, NULL); - if (pd->result == 0) { - return 1; - } - } - else { - if (ZnPolygonInBBox(bevels, 4, pd->bbox, NULL) != pd->result) { - pd->result = 0; - return 1; - } - } - return 0; -} - -int -ZnPolygonReliefInBBox(ZnPoint *points, - unsigned int num_points, - ZnDim line_width, - ZnBBox *area) -{ - PolygonData pd; - - pd.bbox = area; - pd.count = 0; - - DoPolygon(points, num_points, line_width, PolygonInBBoxCB, &pd); - - return pd.result; -} - - -/* - ********************************************************************************** - * - * ZnPolygonReliefToPointDist -- - * Returns the distance between the given point and - * the bevelled polygon. - * - ********************************************************************************** - */ -static ZnBool -PolygonDistCB(ZnPoint *bevels, - PolygonData *pd) -{ - double new_dist; - - new_dist = ZnPolygonToPointDist(bevels, 4, pd->pp); - if (new_dist < 0.0) { - new_dist = 0.0; - } - if (new_dist < pd->dist) { - pd->dist = new_dist; - } - return 0; -} - -double -ZnPolygonReliefToPointDist(ZnPoint *points, - unsigned int num_points, - ZnDim line_width, - ZnPoint *pp) -{ - PolygonData pd; - - pd.dist = 1.0e40; - pd.pp = pp; - DoPolygon(points, num_points, line_width, PolygonDistCB, &pd); - - return pd.dist; -} - - -/* - ********************************************************************************** - * - * ZnDrawPolygonRelief -- - * Draw the bevels around path. - * - ********************************************************************************** - */ -static ZnBool -PolygonDrawCB(ZnPoint *bevels, - PolygonData *pd) -{ - ZnWInfo *wi = pd->wi; - XPoint bevel_xpoints[5]; - XGCValues values; - int j; - - values.foreground = ReliefPixelOfSegment(bevels[0].x, bevels[0].y, - bevels[3].x, bevels[3].y, - pd->relief, pd->gradient, - pd->wi->light_angle); - - values.fill_style = FillSolid; - XChangeGC(wi->dpy, wi->gc, GCFillStyle|GCForeground, &values); - - for (j = 0; j < 4; j++) { - bevel_xpoints[j].x = ZnNearestInt(bevels[j].x); - bevel_xpoints[j].y = ZnNearestInt(bevels[j].y); - } - - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, bevel_xpoints, 4, - Convex, CoordModeOrigin); - - return 0; -} - -void -ZnDrawPolygonRelief(ZnWInfo *wi, - ZnReliefStyle relief, - ZnGradient *gradient, - ZnPoint *points, - unsigned int num_points, - ZnDim line_width) -{ - PolygonData pd; - - pd.wi = wi; - pd.gradient = gradient; - - /* - * Grooves and ridges are drawn with two calls. The first - * with the original width, the second with half the width. - */ - if ((relief == ZN_RELIEF_RIDGE) || (relief == ZN_RELIEF_GROOVE)) { - pd.relief = (relief==ZN_RELIEF_GROOVE)?ZN_RELIEF_RAISED:ZN_RELIEF_SUNKEN; - DoPolygon(points, num_points, line_width, PolygonDrawCB, &pd); - pd.relief = (relief==ZN_RELIEF_GROOVE)?ZN_RELIEF_SUNKEN:ZN_RELIEF_RAISED; - DoPolygon(points, num_points, line_width/2, PolygonDrawCB, &pd); - } - else { - pd.relief = relief; - DoPolygon(points, num_points, line_width, PolygonDrawCB, &pd); - } -} - -/* - ********************************************************************************** - * - * ZnRenderPolygonRelief -- - * Draw the bevels around path using alpha enabled rendering. - * - ********************************************************************************** - */ -#ifdef GL -static ZnBool -PolygonRenderCB(ZnPoint *bevels, - PolygonData *pd) -{ - int i; - ZnPoint p[6]; - XColor *c[8]; - XColor *color = ZnGetGradientColor(pd->gradient, 51.0, NULL); - ZnReliefStyle relief, int_relief; - ZnBool two_faces, round, rule; - - rule = pd->relief & ZN_RELIEF_RULE; - round = pd->relief & ZN_RELIEF_ROUND; - two_faces = pd->relief & ZN_RELIEF_TWO_FACES; - relief = pd->relief & ZN_RELIEF_MASK; - for (i = 0; i < 4; i++) { - p[i].x = ZnNearestInt(bevels[i].x); - p[i].y = ZnNearestInt(bevels[i].y); - } - - if (two_faces) { - p[4].x = (p[0].x+p[1].x)/2; - p[4].y = (p[0].y+p[1].y)/2; - p[5].x = (p[2].x+p[3].x)/2; - p[5].y = (p[2].y+p[3].y)/2; - - if (relief == ZN_RELIEF_SUNKEN) { - int_relief = ZN_RELIEF_RAISED; - } - else { - int_relief = ZN_RELIEF_SUNKEN; - } - c[0]=c[1]=c[2]=c[3] = ReliefColorOfSegment(bevels[0].x, bevels[0].y, - bevels[3].x, bevels[3].y, - relief, pd->gradient, - pd->wi->light_angle); - c[4]=c[5]=c[6]=c[7] = ReliefColorOfSegment(bevels[0].x, bevels[0].y, - bevels[3].x, bevels[3].y, - int_relief, pd->gradient, - pd->wi->light_angle); - if (pd->smooth && pd->p0) { - c[2]=c[3] = ReliefColorOfSegment(pd->p0->x, pd->p0->y, - pd->p1->x, pd->p1->y, - relief, pd->gradient, - pd->wi->light_angle); - c[6]=c[7] = ReliefColorOfSegment(pd->p0->x, pd->p0->y, - pd->p1->x, pd->p1->y, - int_relief, pd->gradient, - pd->wi->light_angle); - } - if (round) { - if (!rule) { - c[0]=c[3]=c[5]=c[6]=color; - } - else { - c[1]=c[2]=c[4]=c[7]=color; - } - } - glBegin(GL_QUADS); - glColor4us(c[0]->red, c[0]->green, c[0]->blue, pd->alpha); - glVertex2d(p[0].x, p[0].y); - - glColor4us(c[1]->red, c[1]->green, c[1]->blue, pd->alpha); - glVertex2d(p[4].x, p[4].y); - - glColor4us(c[2]->red, c[2]->green, c[2]->blue, pd->alpha); - glVertex2d(p[5].x, p[5].y); - - glColor4us(c[3]->red, c[3]->green, c[3]->blue, pd->alpha); - glVertex2d(p[3].x, p[3].y); - - glColor4us(c[4]->red, c[4]->green, c[4]->blue, pd->alpha); - glVertex2d(p[4].x, p[4].y); - - glColor4us(c[5]->red, c[5]->green, c[5]->blue, pd->alpha); - glVertex2d(p[1].x, p[1].y); - - glColor4us(c[6]->red, c[6]->green, c[6]->blue, pd->alpha); - glVertex2d(p[2].x, p[2].y); - - glColor4us(c[7]->red, c[7]->green, c[7]->blue, pd->alpha); - glVertex2d(p[5].x, p[5].y); - glEnd(); - } - else { /* Single face */ - c[0]=c[1]=c[2]=c[3] = ReliefColorOfSegment(bevels[0].x, bevels[0].y, - bevels[3].x, bevels[3].y, - relief, pd->gradient, - pd->wi->light_angle); - if (pd->smooth && pd->p0) { - c[2]=c[3] = ReliefColorOfSegment(pd->p0->x, pd->p0->y, - pd->p1->x, pd->p1->y, - relief, pd->gradient, - pd->wi->light_angle); - } - if (round) { - c[1]=c[2] = color; - } - glBegin(GL_QUADS); - glColor4us(c[0]->red, c[0]->green, c[0]->blue, pd->alpha); - glVertex2d(p[0].x, p[0].y); - glColor4us(c[1]->red, c[1]->green, c[1]->blue, pd->alpha); - glVertex2d(p[1].x, p[1].y); - glColor4us(c[2]->red, c[2]->green, c[2]->blue, pd->alpha); - glVertex2d(p[2].x, p[2].y); - glColor4us(c[3]->red, c[3]->green, c[3]->blue, pd->alpha); - glVertex2d(p[3].x, p[3].y); - glEnd(); - } - - return 0; -} - -void -ZnRenderPolygonRelief(ZnWInfo *wi, - ZnReliefStyle relief, - ZnGradient *gradient, - ZnBool smooth, - ZnPoint *points, - unsigned int num_points, - ZnDim line_width) -{ - PolygonData pd; - - pd.wi = wi; - pd.gradient = gradient; - ZnGetGradientColor(gradient, 0.0, &pd.alpha); - pd.alpha = ZnComposeAlpha(pd.alpha, wi->alpha); - pd.smooth = smooth; - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - pd.relief = relief; - pd.count = 0; - - DoPolygon(points, num_points, line_width, PolygonRenderCB, &pd); -} - -void -ZnRenderPolyline(ZnWInfo *wi, - ZnPoint *points, - unsigned int num_points, - ZnDim line_width, - ZnLineStyle line_style, - int cap_style, - int join_style, - ZnLineEnd first_end, - ZnLineEnd last_end, - ZnGradient *gradient) -{ - int num_clips = ZnListSize(wi->clip_stack); - ZnPoint end_points[ZN_LINE_END_POINTS]; - ZnBool need_rcaps, thin, closed, transparent; - int pass, num_passes, i, k, m; - ZnPoint c1, c2; - XColor *color; - unsigned short alpha; - ZnGLContextEntry *ce = ZnGetGLContext(wi->dpy); - - /* - * The code below draws curves thiner than the min - * of GL_SMOOTH_LINE_WIDTH_RANGE and GL_SMOOTH_POINT_SIZE_RANGE - * with a mix of anti-aliased lines and points. The curves that - * are thicker are drawn using regular polygons. - * BUG: The joints are drawn only rounded. - * The caps can be either round or butt (but not projecting). - */ - thin = ((line_width <= ce->max_line_width) && - (line_width <= ce->max_point_width)); - closed = (points->x == points[num_points-1].x) && (points->y == points[num_points-1].y); - color = ZnGetGradientColor(gradient, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - ZnSetLineStyle(wi, line_style); - glLineWidth((GLfloat) line_width); - /* - * Do not use joints under this transparency value. - */ - transparent = alpha < (65535 * 0.8); - if (thin && transparent) { - /* - * This makes a special case for transparent lines. - * In this case we need to avoid drawing twice a - * single pixel. To achieve this we use the stencil - * buffer to protect already drawn pixels, unfortunately - * using antialiasing write in the stencil even if - * the pixel area is not fully covered resulting in - * a crack that can't be covered by points later on. - * To handle this case we need to disable the stencil - * which in turn result in erroneous alpha coverage. - * - * We have chosen to drawn transparent lines with a - * correct coverage but NOT antialiased. - */ - glPointSize((GLfloat)(line_width>1.0?line_width-1:line_width)); - glDisable(GL_LINE_SMOOTH); - } - else { - glPointSize((GLfloat)(line_width>1.0?line_width-1:line_width)); - } - - num_passes = 1; - if (transparent) { - num_passes = 2; - } - - for (pass = 0; pass < num_passes; pass++) { - if (transparent) { - if (pass == 0) { - ZnGlStartClip(num_clips, True); - } - else { - ZnGlRestoreStencil(num_clips, False); - } - } - if (first_end) { - ZnGetLineEnd(&points[0], &points[1], line_width, cap_style, - first_end, end_points); - glBegin(GL_TRIANGLE_FAN); - for (m = 0; m < ZN_LINE_END_POINTS; m++) { - glVertex2d(end_points[m].x, end_points[m].y); - } - glEnd(); - } - if (last_end) { - ZnGetLineEnd(&points[num_points-1], &points[num_points-2], - line_width, cap_style, last_end, end_points); - glBegin(GL_TRIANGLE_FAN); - for (m = 0; m < ZN_LINE_END_POINTS; m++) { - glVertex2d(end_points[m].x, end_points[m].y); - } - glEnd(); - } - if (thin) { - glBegin(GL_LINE_STRIP); - for (i = 0; i < (int) num_points; i++) { - glVertex2d(points[i].x, points[i].y); - } - glEnd(); - } - else { - glBegin(GL_QUADS); - for (i = 0; i < (int) num_points-1; i++) { - ZnGetButtPoints(&points[i+1], &points[i], line_width, False, &c1, &c2); - glVertex2d(c1.x, c1.y); - glVertex2d(c2.x, c2.y); - ZnGetButtPoints(&points[i], &points[i+1], line_width, False, &c1, &c2); - glVertex2d(c1.x, c1.y); - glVertex2d(c2.x, c2.y); - } - glEnd(); - } - - /* if (pass == 0) { - ZnGlRenderClipped(); - } - else { - ZnGlEndClip(num_clips); - break; - }*/ - need_rcaps = ((line_width > 1) && (cap_style == CapRound)); - i = 0; - k = num_points; - if (closed) { - k--; - } - if (!need_rcaps || first_end) { - i++; - } - if ((!need_rcaps && !closed) || last_end) { - k--; - } - - if (thin) { - glBegin(GL_POINTS); - for ( ; i < k; i++) { - glVertex2d(points[i].x, points[i].y); - } - glEnd(); - } - else { - int num_cpoints; - ZnReal lw_2 = line_width / 2.0; - ZnPoint *cpoints = ZnGetCirclePoints(3, ZN_CIRCLE_COARSE, - 0.0, 2*M_PI, &num_cpoints, NULL); - - for ( ; i < k; i++) { - glBegin(GL_TRIANGLE_FAN); - glVertex2d(points[i].x, points[i].y); - for (m = 0; m < num_cpoints; m++) { - glVertex2d(points[i].x + cpoints[m].x*lw_2, - points[i].y + cpoints[m].y*lw_2); - } - glEnd(); - } - } - } - - ZnGlEndClip(num_clips); - if (thin) { - glEnable(GL_LINE_SMOOTH); - } -} - - -void -ZnRenderIcon(ZnWInfo *wi, - ZnImage image, - ZnGradient *gradient, - ZnPoint *origin, - ZnBool modulate) -{ - ZnPoint p[4]; - int width, height; - - ZnSizeOfImage(image, &width, &height); - p[0] = *origin; - p[1].x = origin->x; - p[1].y = origin->y + height; - p[2].x = origin->x + width; - p[2].y = p[1].y; - p[3].x = p[2].x; - p[3].y = origin->y; - ZnRenderImage(wi, image, gradient, p, modulate); -} - - -void -ZnRenderImage(ZnWInfo *wi, - ZnImage image, - ZnGradient *gradient, - ZnPoint *quad, - ZnBool modulate) -{ - XColor *color; - unsigned short alpha; - ZnReal t, s; - GLuint texobj; - - color = ZnGetGradientColor(gradient, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - texobj = ZnImageTex(image, &t, &s); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, texobj); - if (modulate) { - glColor4us(color->red, color->green, color->blue, alpha); - } - else { - glColor4us(65535, 65535, 65535, alpha); - } - glBegin(GL_QUADS); - glTexCoord2d(0.0, 0.0); - glVertex2d(quad[0].x, quad[0].y); - glTexCoord2d(0.0, t); - glVertex2d(quad[1].x, quad[1].y); - glTexCoord2d(s, t); - glVertex2d(quad[2].x, quad[2].y); - glTexCoord2d(s, 0.0); - glVertex2d(quad[3].x, quad[3].y); - glEnd(); - glDisable(GL_TEXTURE_2D); -} - -void -ZnRenderTile(ZnWInfo *wi, - ZnImage tile, - ZnGradient *gradient, - void (*cb)(void *), - void *closure, - ZnPoint *quad) /* Right now it's a ZnBBox */ -{ - ZnReal x, y, nx, ny, lx, ly, s, t, tiles, tilet; - int width, height, num_clips = ZnListSize(wi->clip_stack); - unsigned short alpha; - GLuint texobj; - XColor *color; - - if (gradient) { - color = ZnGetGradientColor(gradient, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - } - else { - color = NULL; - alpha = ZnComposeAlpha(100, wi->alpha); - } - - if (cb) { - /* - * Setup the stencil buffer with the shape to be drawn. - */ - ZnGlStartClip(num_clips, False); - - (*cb)(closure); - ZnGlRestoreStencil(num_clips, True); - } - - /* - * Then texture map the quad through the shape. - * The rectangle is drawn using quads, each - * quad matching the size of the texture tile. - */ - ZnSizeOfImage(tile, &width, &height); - texobj = ZnImageTex(tile, &tilet, &tiles); - glEnable(GL_TEXTURE_2D); - if (color && ZnImageIsBitmap(tile)) { - glColor4us(color->red, color->green, color->blue, alpha); - } - else { - glColor4us(65535, 65535, 65535, alpha); - } - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBindTexture(GL_TEXTURE_2D, texobj); - - y = quad[0].y; - lx = quad[1].x; - ly = quad[1].y; - glBegin(GL_QUADS); - do { - x = quad[0].x; - t = 1.0; - ny = y + height; - if (ny > ly) { - ny = ly; - t = (ly - y) / (ZnReal) height; - } - t *= tilet; - do { - s = 1.0; - nx = x + width; - if (nx > lx) { - nx = lx; - s = (lx - x) / (ZnReal) width; - } - s *= tiles; - glTexCoord2d(0.0, 0.0); - glVertex2d(x, y); - glTexCoord2d(0.0, t); - glVertex2d(x, ny); - glTexCoord2d(s, t); - glVertex2d(nx, ny); - glTexCoord2d(s, 0.0); - glVertex2d(nx, y); - x = nx; - } - while (x != lx); - y = ny; - } - while (y != ly); - glEnd(); - - if (cb) { - ZnGlEndClip(num_clips); - } - glDisable(GL_TEXTURE_2D); -} - - -static void -ComputeAxialGradient(ZnWInfo *wi, - ZnPoly *shape, - ZnReal angle, - ZnPoint *grad_geo) -{ - ZnTransfo *transfo1, *transfo2; - ZnContour *c; - ZnBBox bbox; - ZnPoint *points, p[4]; - unsigned int i; - - transfo1 = ZnTransfoNew(); - transfo2 = ZnTransfoNew(); - ZnRotateDeg(transfo1, angle); - ZnRotateDeg(transfo2, -angle); - c = shape->contours; - ZnResetBBox(&bbox); - for (i = 0; i < shape->num_contours; i++, c++) { - ZnListAssertSize(ZnWorkPoints, c->num_points); - points = ZnListArray(ZnWorkPoints); - ZnTransformPoints(transfo1, c->points, points, c->num_points); - ZnAddPointsToBBox(&bbox, points, c->num_points); - } - bbox.orig.x--; - bbox.orig.y--; - bbox.corner.x++; - bbox.corner.y++; - p[0] = bbox.orig; - p[2] = bbox.corner; - p[1].x = p[2].x; - p[1].y = p[0].y; - p[3].x = p[0].x; - p[3].y = p[2].y; - ZnTransfoSetIdentity(transfo1); - ZnTransfoCompose(transfo1, transfo2, wi->current_transfo); - ZnTransformPoints(transfo1, p, grad_geo, 4); - ZnTransfoFree(transfo1); - ZnTransfoFree(transfo2); -} - -static void -ComputeCircularGradient(ZnWInfo *wi, - ZnPoly *shape, - ZnBool oval, - ZnPoint *focal_pp, /* in percent of bbox */ - ZnReal angle, - ZnPoint *grad_geo) -{ - ZnReal dist, new, x, y, ff; - ZnBBox bbox; - ZnContour *c; - ZnPoint offset, radius, focal_point; - ZnPoint *points; - ZnTransfo t1; - unsigned int i, j; - - /* - * Compute the shape bbox (which should be in the item space). - */ - ZnResetBBox(&bbox); - c = shape->contours; - dist = 0.0; - for (j = 0; j < shape->num_contours; j++, c++) { - ZnAddPointsToBBox(&bbox, c->points, c->num_points); - } - - /* - * Find the gradient focal point in the item space. - * The excursion of the focal point outside the item - * bbox is clamped to avoid distorsions that take - * place due to the rather simple algorithm used to - * compute the maximum radius of the gradient. - */ - focal_pp->x = fmod(focal_pp->x, 500.0); - focal_pp->y = fmod(focal_pp->y, 500.0); - offset.x = focal_pp->x * (bbox.corner.x-bbox.orig.x)/100.0; - offset.y = focal_pp->y * (bbox.corner.y-bbox.orig.y)/100.0; - focal_point.x = (bbox.corner.x+bbox.orig.x)/2 + offset.x; - focal_point.y = (bbox.corner.y+bbox.orig.y)/2 + offset.y; - - /* - * Find the max distance from the focal point. - */ - if (oval) { - /* - * radius.x and radius.y are the shape radiuses. - * ff is the distance from the bbox center to - * the focal point. - */ - radius.x = (bbox.corner.x-bbox.orig.x)/2; - radius.y = (bbox.corner.y-bbox.orig.y)/2; - ff = sqrt(offset.x*offset.x + offset.y*offset.y); - /* - * Compute the farthest point from the focal point - * on a unit circle, then map it to the oval and - * compute the distance between the two points. - */ - if (ff > PRECISION_LIMIT) { - x = offset.x/ff; - y = offset.y/ff; - x *= radius.x; - y *= radius.y; - x = x + offset.x; - y = y + offset.y; - } - else { - x = 0; - y = MAX(radius.x, radius.y); - } - dist = x*x + y*y; - } - else { - /* - * Use the given shape - */ - c = shape->contours; - for (j = 0; j < shape->num_contours; j++, c++) { - for (i = 0, points = c->points; i < c->num_points; i++, points++) { - x = points->x - focal_point.x; - y = points->y - focal_point.y; - new = x*x+y*y; - if (new > dist) { - dist = new; - } - } - } - } - - /* - * Create a transform to map a unit circle to another one that - * could fill the item when centered at the focal point. - */ - dist = sqrt(dist); /* Max radius plus a fuzz factor */ - ZnTransfoSetIdentity(&t1); - ZnScale(&t1, dist, dist); - ZnRotateDeg(&t1, -angle); - - /* - * Then, center the oval on the focal point. - */ - ZnTranslate(&t1, focal_point.x, focal_point.y, False); - /* - * Last, compose with the current transform. - */ - ZnTransfoCompose((ZnTransfo *) grad_geo, &t1, wi->current_transfo); -} - -static void -ComputePathGradient(ZnWInfo *wi, - ZnPoly *shape, - ZnPoint *focal_pp, /* in percent of the bbox */ - ZnPoint *grad_geo) -{ - ZnBBox bbox; - ZnContour *c; - ZnPoint focal_point; - unsigned int j; - - /* - * Compute the shape bbox (which should be in the item space). - */ - ZnResetBBox(&bbox); - c = shape->contours; - for (j = 0; j < shape->num_contours; j++, c++) { - ZnAddPointsToBBox(&bbox, c->points, c->num_points); - } - - /* - * Find the gradient center in the item space. - */ - focal_point.x = (bbox.corner.x+bbox.orig.x)/2 + focal_pp->x * (bbox.corner.x-bbox.orig.x)/100.0; - focal_point.y = (bbox.corner.y+bbox.orig.y)/2 + focal_pp->y * (bbox.corner.y-bbox.orig.y)/100.0; - /* - * Then convert it to device space. - */ - ZnTransformPoint(wi->current_transfo, &focal_point, &grad_geo[0]); -} - -void -ZnComputeGradient(ZnGradient *grad, - ZnWInfo *wi, - ZnPoly *shape, - ZnPoint *grad_geo) -{ - switch (grad->type) { - case ZN_AXIAL_GRADIENT: - ComputeAxialGradient(wi, shape, grad->angle, grad_geo); - break; - case ZN_RADIAL_GRADIENT: - case ZN_CONICAL_GRADIENT: - ComputeCircularGradient(wi, shape, False, &grad->p, grad->angle, grad_geo); - break; - case ZN_PATH_GRADIENT: - ComputePathGradient(wi, shape, &grad->p, grad_geo); - break; - } -} - -void -ZnRenderGradient(ZnWInfo *wi, - ZnGradient *gradient, /* The gradient to be drawn (static - * parameters). */ - void (*cb)(void *), /* A callback called to clip the shape - * containing the gradient. */ - void *closure, /* The callback parameter. */ - ZnPoint *quad, /* The gradient geometric parameters - * (dynamic). */ - ZnPoly *poly /* Used only by ZN_PATH_GRADIENT */ - ) -{ - unsigned short alpha, alpha2; - int angle; - unsigned int i, j; - int type = gradient->type; - XColor *color; - ZnPoint dposa, dposb, dposc, dposd; - ZnPoint p, dcontrol; - ZnReal npos, pos, control; - unsigned int num_clips = ZnListSize(wi->clip_stack); - ZnPoint iquad[4]; - - if (!cb && (type == ZN_AXIAL_GRADIENT)) { /* Render an aligned - * axial gradient in the quad */ - angle = gradient->angle; - /* - * Adjust the quad for 90 180 and 270 degrees axial - * gradients. Other angles not supported. - */ - switch (angle) { - case 90: - iquad[0] = quad[3]; - iquad[3] = quad[2]; - iquad[2] = quad[1]; - iquad[1] = quad[0]; - quad = iquad; - break; - case 180: - iquad[0] = quad[2]; - iquad[3] = quad[1]; - iquad[2] = quad[0]; - iquad[1] = quad[3]; - quad = iquad; - break; - case 270: - iquad[0] = quad[1]; - iquad[3] = quad[0]; - iquad[2] = quad[3]; - iquad[1] = quad[2]; - quad = iquad; - break; - } - } - - if (cb) { - /* - * Draw the gradient shape in the stencil using the provided - * callback (clipping). - */ - ZnGlStartClip(num_clips, False); - (*cb)(closure); - ZnGlRestoreStencil(num_clips, True); - } - - if (type == ZN_AXIAL_GRADIENT) { - /* - * Then fill the axial gradient using the provided - * quad and colors. The stencil will be restored - * to its previous state in the process. - */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i < gradient->num_actual_colors; i++) { - color = gradient->actual_colors[i].rgb; - alpha = ZnComposeAlpha(gradient->actual_colors[i].alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - - pos = gradient->actual_colors[i].position; - control = gradient->actual_colors[i].control; - dposa.x = (quad[1].x - quad[0].x)*pos/100.0; - dposa.y = (quad[1].y - quad[0].y)*pos/100.0; - p.x = quad[0].x + dposa.x; - p.y = quad[0].y + dposa.y; - glVertex2d(p.x, p.y); - - dposb.x = (quad[2].x - quad[3].x)*pos/100.0; - dposb.y = (quad[2].y - quad[3].y)*pos/100.0; - p.x = quad[3].x + dposb.x; - p.y = quad[3].y + dposb.y; - glVertex2d(p.x, p.y); - - if ((control != 50.0) && (i != gradient->num_actual_colors-1)) { - color = gradient->actual_colors[i].mid_rgb; - alpha = ZnComposeAlpha(gradient->actual_colors[i].mid_alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - - npos = gradient->actual_colors[i+1].position; - dposc.x = (quad[1].x - quad[0].x)*npos/100.0; - dposc.y = (quad[1].y - quad[0].y)*npos/100.0; - dcontrol.x = (dposc.x - dposa.x)*control/100.0; - dcontrol.y = (dposc.y - dposa.y)*control/100.0; - p.x = quad[0].x + dposa.x + dcontrol.x; - p.y = quad[0].y + dposa.y + dcontrol.y; - glVertex2d(p.x, p.y); - - dposd.x = (quad[2].x - quad[3].x)*npos/100.0; - dposd.y = (quad[2].y - quad[3].y)*npos/100.0; - dcontrol.x = (dposd.x - dposb.x)*control/100.0; - dcontrol.y = (dposd.y - dposb.y)*control/100.0; - p.x = quad[3].x + dposb.x + dcontrol.x; - p.y = quad[3].y + dposb.y + dcontrol.y; - glVertex2d(p.x, p.y); - } - - } - glEnd(); - } - else if (type == ZN_RADIAL_GRADIENT) { - ZnReal x, y, position, position2, position3; - unsigned int num_p; - ZnPoint *genarc, *tarc, p, focalp; - XColor *color2; - - genarc = ZnGetCirclePoints(3, ZN_CIRCLE_FINE, 0.0, 2*M_PI, &num_p, NULL); - ZnListAssertSize(ZnWorkPoints, num_p); - tarc = ZnListArray(ZnWorkPoints); - ZnTransformPoints((ZnTransfo *) quad, genarc, tarc, num_p); - p.x = p.y = 0; - ZnTransformPoint((ZnTransfo *) quad, &p, &focalp); - - position = 0.0; - color = gradient->actual_colors[0].rgb; - alpha = ZnComposeAlpha(gradient->actual_colors[0].alpha, wi->alpha); - control = gradient->actual_colors[0].control; - for (j = 1; j < gradient->num_actual_colors; j++) { - position2 = gradient->actual_colors[j].position/100.0; - if ((control != 50) && (j != gradient->num_actual_colors-1)) { - glBegin(GL_QUAD_STRIP); - color2 = gradient->actual_colors[j-1].mid_rgb; - alpha2 = ZnComposeAlpha(gradient->actual_colors[j-1].mid_alpha, wi->alpha); - position3 = position + (position2-position)*control/100.0; - for (i = 0; i < num_p; i++) { - x = focalp.x + (tarc[i].x-focalp.x) * position; - y = focalp.y + (tarc[i].y-focalp.y) * position; - glColor4us(color->red, color->green, color->blue, alpha); - glVertex2d(x, y); - x = focalp.x + (tarc[i].x-focalp.x) * position3; - y = focalp.y + (tarc[i].y-focalp.y) * position3; - glColor4us(color2->red, color2->green, color2->blue, alpha); - glVertex2d(x, y); - } - position = position3; - color = color2; - alpha = alpha2; - glEnd(); - } - glBegin(GL_QUAD_STRIP); - color2 = gradient->actual_colors[j].rgb; - alpha2 = ZnComposeAlpha(gradient->actual_colors[j].alpha, wi->alpha); - for (i = 0; i < num_p; i++) { - x = focalp.x + (tarc[i].x-focalp.x) * position; - y = focalp.y + (tarc[i].y-focalp.y) * position; - glColor4us(color->red, color->green, color->blue, alpha); - glVertex2d(x, y); - x = focalp.x + (tarc[i].x-focalp.x) * position2; - y = focalp.y + (tarc[i].y-focalp.y) * position2; - glColor4us(color2->red, color2->green, color2->blue, alpha2); - glVertex2d(x, y); - } - glEnd(); - position = position2; - color = color2; - alpha = alpha2; - control = gradient->actual_colors[j].control; - } - } - else if (type == ZN_PATH_GRADIENT) { - ZnPoint p, pp, p2, pp2, p3, pp3; - unsigned int num_p, k, ii; - ZnPoint *points; - ZnReal position; - - for (k = 0; k < poly->num_contours; k++) { - /*if (poly->contours[k].cw) { - continue; - }*/ - points = poly->contours[k].points; - num_p = poly->contours[k].num_points; - - for (i = 0; i < num_p; i++) { - if (i == num_p-1) { - ii = 0; - } - else { - ii = i+1; - } - - glBegin(GL_QUAD_STRIP); - p.x = p.y = pp.x = pp.y = 0; - control = gradient->actual_colors[0].control; - position = gradient->actual_colors[0].position; - alpha = ZnComposeAlpha(gradient->actual_colors[0].alpha, wi->alpha); - color = gradient->actual_colors[0].rgb; - glColor4us(color->red, color->green, color->blue, alpha); - glVertex2d(quad[0].x+p.x, quad[0].y+p.y); - glVertex2d(quad[0].x+pp.x, quad[0].y+pp.y); - for (j = 0; j < gradient->num_actual_colors-1; j++) { - position = gradient->actual_colors[j+1].position; - p2.x = (points[i].x-quad[0].x)*position/100.0; - p2.y = (points[i].y-quad[0].y)*position/100.0; - pp2.x = (points[ii].x-quad[0].x)*position/100.0; - pp2.y = (points[ii].y-quad[0].y)*position/100.0; - if (control != 50) { - color = gradient->actual_colors[j].mid_rgb; - alpha = ZnComposeAlpha(gradient->actual_colors[j].mid_alpha, wi->alpha); - p3.x = p.x+(p2.x-p.x)*control/100.0; - p3.y = p.y+(p2.y-p.y)*control/100.0; - pp3.x = pp.x+(pp2.x-pp.x)*control/100.0; - pp3.y = pp.y+(pp2.y-pp.y)*control/100.0; - glColor4us(color->red, color->green, color->blue, alpha); - glVertex2d(quad[0].x+p3.x, quad[0].y+p3.y); - glVertex2d(quad[0].x+pp3.x, quad[0].y+pp3.y); - } - control = gradient->actual_colors[j+1].control; - alpha = ZnComposeAlpha(gradient->actual_colors[j+1].alpha, wi->alpha); - color = gradient->actual_colors[j+1].rgb; - p = p2; - pp = pp2; - glColor4us(color->red, color->green, color->blue, alpha); - glVertex2d(quad[0].x+p.x, quad[0].y+p.y); - glVertex2d(quad[0].x+pp.x, quad[0].y+pp.y); - } - glEnd(); - } - } - } - else if (type == ZN_CONICAL_GRADIENT) { - ZnReal position; - unsigned int num_p; - ZnPoint *genarc, *tarc, p, focalp; - XColor col; - - genarc = ZnGetCirclePoints(3, ZN_CIRCLE_FINEST, 0.0, 2*M_PI, &num_p, NULL); - ZnListAssertSize(ZnWorkPoints, num_p); - tarc = ZnListArray(ZnWorkPoints); - ZnTransformPoints((ZnTransfo *) quad, genarc, tarc, num_p); - p.x = p.y = 0; - ZnTransformPoint((ZnTransfo *) quad, &p, &focalp); - - glBegin(GL_TRIANGLE_STRIP); - for (i = 0; i < num_p; i++) { - position = i*100.0/(num_p-1); - ZnInterpGradientColor(gradient, position, &col, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - - /*printf("position: %g --> color: %d %d %d, alpha: %d\n", - position, col.red, col.green, col.blue, alpha);*/ - - glColor4us(col.red, col.green, col.blue, alpha); - glVertex2d(tarc[i].x, tarc[i].y); - glVertex2d(focalp.x, focalp.y); - } - glEnd(); - } - - if (cb) { - /* - * Restore the previous GL state. - */ - ZnGlEndClip(num_clips); - } -} - - -void -ZnRenderHollowDot(ZnWInfo *wi, - ZnPoint *p, - ZnReal size) -{ - int num_clips = ZnListSize(wi->clip_stack); - - ZnGlStartClip(num_clips, False); - - glPointSize((GLfloat) (size-2)); - glBegin(GL_POINTS); - glVertex2d(p->x, p->y); - glEnd(); - - ZnGlRenderClipped(); - - glPointSize((GLfloat) size); - glBegin(GL_POINTS); - glVertex2d(p->x, p->y); - glEnd(); - - ZnGlRestoreStencil(num_clips, False); - - glBegin(GL_POINTS); - glVertex2d(p->x, p->y); - glEnd(); - - ZnGlEndClip(num_clips); -} -#endif - - -#ifdef GL -void -ZnRenderGlyph(ZnTexFontInfo *tfi, - int c) -{ - ZnTexGVI *tgvi; - - tgvi = ZnTexFontGVI(tfi, c); - if (!tgvi) { - return; - } - //printf("%c --> x0,y0: %d %d, tx0,ty0: %g %g, x1,y1: %d %d, tx1,ty1: %g %g, advance: %g\n", - // c, tgvi->v0x, tgvi->v0y, tgvi->t0x, tgvi->t0y, - // tgvi->v1x, tgvi->v1y, tgvi->t1x, tgvi->t1y, - // tgvi->advance); - glBegin(GL_QUADS); - glTexCoord2f(tgvi->t0x, tgvi->t0y); glVertex2s(tgvi->v0x, tgvi->v0y); - glTexCoord2f(tgvi->t0x, tgvi->t1y); glVertex2s(tgvi->v0x, tgvi->v1y); - glTexCoord2f(tgvi->t1x, tgvi->t1y); glVertex2s(tgvi->v1x, tgvi->v1y); - glTexCoord2f(tgvi->t1x, tgvi->t0y); glVertex2s(tgvi->v1x, tgvi->v0y); - glEnd(); - glTranslatef(tgvi->advance, 0.0, 0.0); -} - -#ifdef PTK_800 -void -ZnRenderString(ZnTexFontInfo *tfi, - unsigned char *string, - unsigned int len) -{ - while (len) { - ZnRenderGlyph(tfi, *string); - string++; - len--; - } -} -#else -void -ZnRenderString(ZnTexFontInfo *tfi, - unsigned char *string, - unsigned int len) -{ - unsigned int clen; - Tcl_UniChar c; - - while (len) { - clen = Tcl_UtfToUniChar(string, &c); - - ZnRenderGlyph(tfi, c); - - string += clen; - len -= clen; - } -} -#endif -#endif - -/* - ********************************************************************************** - * - * RenderTriangle -- - * This routine maps an image onto a triangle. - * Image coordinates are chosen for each vertex of the triangle. - * A simple affine tex mapping is used as in Zinc there is no way - * to specify perspective deformation. No filtering is attempted - * on the output pixels. - * - * In the comments below u and v are image coordinates and x and - * y are triangle coordinates. - * RenderAffineScanline is an helper function that draws a whole - * scan line to the image with linear interpolation. - * - ********************************************************************************** - */ -static void -RenderAffineScanline(XImage *image, - XImage *mapped_image, - ZnReal x1, - ZnReal x2, - ZnReal u1, - ZnReal u2, - ZnReal v1, - ZnReal v2, - int y) -{ - ZnReal du, dv, width; - int intx1, intx2, intu, intv; - int i; - - /* Revert span ends if needed */ - if (x2 < x1) { - ZnReal tmp; - tmp = x1; x1 = x2; x2 = tmp; - tmp = u1; u1 = u2; u2 = tmp; - tmp = v1; v1 = v2; v2 = tmp; - } - - /* Compute the interpolation factors */ - width = x2 - x1; - if (width) { - du = (u2 - u1) / width; - dv = (v2 - v1) / width; - } - else { - du = dv = 0; - } - intx1 = (int) floor(x1); - intx2 = (int) floor(x2); - - /* Draw the line */ - for (i = intx1; i < intx2; i++) { - intu = (int) floor(u1); - intv = (int) floor(v1); - XPutPixel(mapped_image, i, y, XGetPixel(image, intu, intv)); - u1 += du; - v1 += dv; - } -} - -static void -RenderTriangle(XImage *image, - XImage *mapped_image, - ZnPoint *tri, - ZnPoint *im_coords) -{ - ZnReal dx_A, dx_B; /* Interpolation factor in x / y */ - ZnReal du_A, du_B; /* in u / y */ - ZnReal dv_A, dv_B; /* in v / y */ - ZnReal x1, x2; /* Span in x */ - ZnReal u1, u2; /* Span in u */ - ZnReal v1, v2; /* Span in v */ - int height_A; /* Scan line # from top top vertex A */ - int height_B; /* Scan line # from top top vertex B */ - int y; /* Current scan line */ - int top, a, b; /* Top triangle vertex and other two */ - int i; - - /* Find top vertex and deduce the others. */ - top = 0; - for (i = 1; i < 3; i++) { - if (tri[i].y <= tri[top].y) - top = i; - } - a = (top+1)%3; - b = top-1; - if (b < 0) - b = 2; - - /* Initialize conversion parameters. */ - y = ZnNearestInt(tri[top].y); - height_A = ZnNearestInt(tri[a].y - tri[top].y); - height_B = ZnNearestInt(tri[b].y - tri[top].y); - x1 = x2 = tri[top].x; - u1 = u2 = im_coords[top].x; - v1 = v2 = im_coords[top].y; - if (height_A) { - dx_A = (tri[a].x - tri[top].x) / height_A; - du_A = (im_coords[a].x - im_coords[top].x) / height_A; - dv_A = (im_coords[a].y - im_coords[top].y) / height_A; - } - else { - dx_A = du_A = dv_A = 0; - } - if (height_B) { - dx_B = (tri[b].x - tri[top].x) / height_B; - du_B = (im_coords[b].x - im_coords[top].x) / height_B; - dv_B = (im_coords[b].y - im_coords[top].y) / height_B; - } - else { - dx_B = du_B = dv_B = 0; - } - - /* Convert from top to bottom */ - for (i = 2; i > 0; ) { - while (height_A && height_B) { - - /* Draw a scanline */ - RenderAffineScanline(image, mapped_image, x1, x2, u1, u2, v1, v2, y); - - /* Step the parameters*/ - y++; - height_A--; - height_B--; - x1 += dx_A; - x2 += dx_B; - u1 += du_A; - u2 += du_B; - v1 += dv_A; - v2 += dv_B; - } - - /* If either height_A or height_B steps to zero, we have - * encountered a vertex (A or B) and we are starting conversion - * along a new edge. Update the parameters before proceeding. */ - if (!height_A) { - int na = (a+1)%3; - - height_A = ZnNearestInt(tri[na].y - tri[a].y); - if (height_A) { - dx_A = (tri[na].x - tri[a].x) / height_A; - du_A = (im_coords[na].x - im_coords[a].x) / height_A; - dv_A = (im_coords[na].y - im_coords[a].y) / height_A; - } - else { - dx_A = du_A = dv_A = 0; - } - x1 = tri[a].x; - u1 = im_coords[a].x; - v1 = im_coords[a].y; - a = na; - /* One less vertex to do */ - i--; - } - - if (!height_B) { - int nb = b - 1; - - if (nb < 0) - nb = 2; - height_B = ZnNearestInt(tri[nb].y - tri[b].y); - if (height_B) { - dx_B = (tri[nb].x - tri[b].x) / height_B; - du_B = (im_coords[nb].x - im_coords[b].x) / height_B; - dv_B = (im_coords[nb].y - im_coords[b].y) / height_B; - } - else { - dx_B = du_B = dv_B = 0; - } - x2 = tri[b].x; - u2 = im_coords[b].x; - v2 = im_coords[b].y; - b = nb; - /* One less vertex to do */ - i--; - } - } -} - - -/* - ********************************************************************************** - * - * MapImage -- - * This procedure maps an image on a parallelogram given in poly. - * The given parallelogram should fit in the destination image. - * The parallelogram vertices must be ordered as for a triangle - * strip: - * - * v0 ------------ v2 - * | | - * | | - * v1 ------------ v3 - * - * The mapping is done by a simple affine mapping of the image on the - * two triangles obtained by cutting the parallelogram along the diogonal - * from the second vertex to the third vertex. - * - ********************************************************************************** - */ -void -ZnMapImage(XImage *image, - XImage *mapped_image, - ZnPoint *poly) -{ - ZnPoint triangle[3]; - ZnPoint im_coords[3]; - - triangle[0] = poly[0]; - triangle[1] = poly[1]; - triangle[2] = poly[2]; - im_coords[0].x = 0.0; - im_coords[0].y = 0.0; - im_coords[1].x = 0.0; - im_coords[1].y = image->height-1; - im_coords[2].x = image->width-1; - im_coords[2].y = 0.0; - RenderTriangle(image, mapped_image, triangle, im_coords); - - triangle[0] = poly[1]; - triangle[1] = poly[2]; - triangle[2] = poly[3]; - im_coords[0].x = 0.0; - im_coords[0].y = image->height-1; - im_coords[1].x = image->width-1; - im_coords[1].y = 0.0; - im_coords[2].x = image->width-1; - im_coords[2].y = image->height-1; - RenderTriangle(image, mapped_image, triangle, im_coords); -} |