diff options
Diffstat (limited to 'generic/Curve.c')
-rw-r--r-- | generic/Curve.c | 456 |
1 files changed, 313 insertions, 143 deletions
diff --git a/generic/Curve.c b/generic/Curve.c index c8d2a35..3522a87 100644 --- a/generic/Curve.c +++ b/generic/Curve.c @@ -37,6 +37,9 @@ #ifdef GPC #include "gpc/gpc.h" #endif +#ifdef GLX +#include <GL/tube.h> +#endif #include <ctype.h> #include <malloc.h> @@ -88,20 +91,16 @@ typedef struct _CurveItemStruct { ZnColor line_color; ZnColor marker_color; int line_alpha; - int fill_alpha; char *tile_name; /* Private data */ ZnImage tile; ZnPoly dev_shape; ZnGradient *gradient; -#ifdef LIBART - ArtSVP *outline_svp; - ArtSVP *fill_svp; -#endif #ifdef GPC gpc_tristrip tristrip; #endif + ZnPoint *grad_geo; } CurveItemStruct, *CurveItem; static ZnAttrConfig cv_attrs[] = { @@ -116,8 +115,6 @@ static ZnAttrConfig cv_attrs[] = { { ZN_CONFIG_BOOL, "-composescale", NULL, Tk_Offset(CurveItemStruct, header.flags), COMPOSE_SCALE_BIT, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_UINT, "-fillalpha", NULL, - Tk_Offset(CurveItemStruct, fill_alpha), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_GRADIENT, "-fillcolor", NULL, Tk_Offset(CurveItemStruct, fill_color), 0, ZN_DRAW_FLAG|ZN_BORDER_FLAG, False }, @@ -132,7 +129,7 @@ static ZnAttrConfig cv_attrs[] = { ZN_COORDS_FLAG, False }, { ZN_CONFIG_LINE_END, "-lastend", NULL, Tk_Offset(CurveItemStruct, last_end), 0, ZN_COORDS_FLAG, False }, - { ZN_CONFIG_UINT, "-linealpha", NULL, + { ZN_CONFIG_ALPHA, "-linealpha", NULL, Tk_Offset(CurveItemStruct, line_alpha), 0, ZN_DRAW_FLAG, False }, { ZN_CONFIG_COLOR, "-linecolor", NULL, Tk_Offset(CurveItemStruct, line_color), 0, @@ -215,6 +212,7 @@ Init(Item item, cv->tristrip.num_strips = 0; #endif cv->gradient = NULL; + cv->grad_geo = NULL; /* Init attributes */ SET(item->flags, VISIBLE_BIT); @@ -278,15 +276,11 @@ Init(Item item, */ SET(cv->flags, MARKED_BIT); cv->marker = ZnUnspecifiedPattern; - cv->fill_alpha = 255; cv->fill_color = ZnGetGradient(wi->interp, wi->win, ZnNameOfColor(wi->fore_color)); - cv->line_alpha = 255; + cv->line_alpha = 100; cv->line_color = ZnGetColorByValue(wi->win, wi->fore_color); cv->marker_color = ZnGetColorByValue(wi->win, wi->fore_color); -#ifdef LIBART - cv->outline_svp = cv->fill_svp = NULL; -#endif return ZN_OK; } @@ -310,6 +304,7 @@ Clone(Item item) ZnBool *holes; POLY_INIT(&cv->dev_shape); + cv->grad_geo = NULL; if (cv->shape.num_contours) { conts = cv->shape.contours; @@ -362,9 +357,6 @@ Clone(Item item) cv->line_color = ZnGetColorByValue(wi->win, cv->line_color); cv->fill_color = ZnGetGradientByValue(cv->fill_color); cv->marker_color = ZnGetColorByValue(wi->win, cv->marker_color); -#ifdef LIBART - cv->outline_svp = cv->fill_svp = NULL; -#endif } @@ -382,6 +374,9 @@ Destroy(Item item) CurveItem cv = (CurveItem) item; POLY_FREE(&cv->shape); + if (cv->grad_geo) { + ZnFree(cv->grad_geo); + } cv->dev_shape.holes = NULL; POLY_FREE(&cv->dev_shape); @@ -418,14 +413,6 @@ Destroy(Item item) gpc_free_tristrip(&cv->tristrip); } #endif -#ifdef LIBART - if (cv->outline_svp) { - art_svp_free(cv->outline_svp); - } - if (cv->fill_svp) { - art_svp_free(cv->fill_svp); - } -#endif } @@ -494,7 +481,9 @@ Configure(Item item, } if ((cv->relief != RELIEF_FLAT) && !cv->gradient) { cv->gradient = ZnGetReliefGradient(wi->interp, wi->win, - ZnNameOfColor(ZnGetGradientColor(wi->win, cv->fill_color, 50.0))); + ZnNameOfColor(ZnGetGradientColor(wi->win, + cv->fill_color, + 50.0, NULL))); if (cv->gradient == NULL) { status = ZN_ERROR; } @@ -718,51 +707,6 @@ ComputeCoordinates(Item item, lw = cv->line_width; - /* - * PLC Rendering works only with one contour, no relief, no markers, - * round ends, round joins. - */ - if (wi->render) { -#ifdef LIBART - ArtVpath *vpath; - - c2 = cv->dev_shape.contours; - vpath = (ArtVpath *) ZnMalloc((c2->num_points+2) * sizeof(ArtVpath)); - points = c2->points; - for (i = 0; i < c2->num_points; i++, points++) { - vpath[i].code = ART_LINETO; - vpath[i].x = points->x; - vpath[i].y = points->y; - } - if (ISSET(cv->flags, CLOSED_BIT)) { - vpath[0].code = ART_MOVETO; - } - else { - vpath[0].code = ART_MOVETO_OPEN; - } - vpath[i].code = ART_END; - - if (cv->fill_svp) { - art_svp_free(cv->fill_svp); - cv->fill_svp = NULL; - } - if (ISSET(cv->flags, FILLED_BIT)) { - cv->fill_svp = art_svp_from_vpath(vpath); - } - if (cv->outline_svp) { - art_svp_free(cv->outline_svp); - cv->outline_svp = NULL; - } - if (cv->line_width) { - cv->outline_svp = art_svp_vpath_stroke(vpath, - ART_PATH_STROKE_JOIN_ROUND, - ART_PATH_STROKE_CAP_ROUND, - lw, 2, 1); - } - ZnFree(vpath); -#endif - } - if (ISSET(cv->flags, RELIEF_OK)) { holes = cv->shape.holes; c2 = cv->dev_shape.contours; @@ -864,6 +808,77 @@ ComputeCoordinates(Item item, item->item_bounding_box.orig.y -= 1; item->item_bounding_box.corner.x += 1; item->item_bounding_box.corner.y += 1; + + if (!ZnGradientFlat(cv->fill_color)) { + if (!cv->grad_geo) { + cv->grad_geo = ZnMalloc(4*sizeof(ZnPoint)); + } + if (cv->fill_color->type == ZN_AXIAL_GRADIENT) { + int angle = cv->fill_color->g.angle; + ZnTransfo *transfo1, *transfo2; + ZnPoint p[4]; + ZnBBox bbox; + + transfo1 = ZnTransfoNew(); + transfo2 = ZnTransfoNew(); + ZnRotateDeg(transfo1, angle); + ZnRotateDeg(transfo2, -angle); + holes = cv->shape.holes; + c1 = cv->shape.contours; + ResetBBox(&bbox); + for (j = 0; j < num_contours; j++, c1++, holes++) { + if (*holes) { + continue; + } + ZnListAssertSize(wi->work_pts, c1->num_points); + points = ZnListArray(wi->work_pts); + ZnTransformPoints(transfo1, c1->points, points, c1->num_points); + AddPointsToBBox(&bbox, points, c1->num_points); + } + 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, cv->grad_geo, 4); + ZnTransfoFree(transfo1); + ZnTransfoFree(transfo2); + } + else if (cv->fill_color->type == ZN_RADIAL_GRADIENT) { + ZnReal dist, new, x0, x, y0, y; + + ZnTransformPoint(wi->current_transfo, &cv->fill_color->g.p, &cv->grad_geo[0]); + x0 = cv->grad_geo[0].x; + y0 = cv->grad_geo[0].y; + dist = 0.0; + holes = cv->shape.holes; + c1 = cv->dev_shape.contours; + for (j = 0; j < num_contours; j++, c1++, holes++) { + if (*holes) { + continue; + } + points = c1->points; + for (i = 0; i < c1->num_points; i++, points++) { + x = points->x; + y = points->y; + new = (x-x0)*(x-x0) + (y-y0)*(y-y0); + if (new > dist) { + dist = new; + } + } + } + cv->grad_geo[1].x = sqrt(dist) + 2; /* Max radius plus a fuzz factor */ + } + } + else { + if (cv->grad_geo) { + ZnFree(cv->grad_geo); + cv->grad_geo = NULL; + } + } } @@ -1044,67 +1059,61 @@ Draw(Item item) * Fill if requested. */ if (ISSET(cv->flags, FILLED_OK)) { - if (!ZnGradientFlat(cv->fill_color)) { - DrawPolygonGradient(wi, cv->fill_color, &cv->dev_shape, - &item->item_bounding_box); - } - else { - values.foreground = ZnPixel(ZnGetGradientColor(wi->win, cv->fill_color, 50.0)); - gc_mask = GCFillStyle; - if (cv->tile != ZnUnspecifiedImage) { /* Fill tiled */ - Pixmap pmap = GetImagePixmap(wi->win, cv->tile_name, cv->tile, NULL); - values.fill_style = FillTiled; - values.tile = pmap; - values.ts_x_origin = REAL_TO_INT(item->item_bounding_box.orig.x); - values.ts_y_origin = REAL_TO_INT(item->item_bounding_box.orig.y); - gc_mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCTile; - } - else if (cv->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */ - values.fill_style = FillStippled; - values.stipple = cv->fill_pattern; - values.ts_x_origin = REAL_TO_INT(item->item_bounding_box.orig.x); - values.ts_y_origin = REAL_TO_INT(item->item_bounding_box.orig.y); - gc_mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCStipple|GCForeground; - } - else { /* Fill solid */ - values.fill_style = FillSolid; - gc_mask |= GCForeground; - } - XChangeGC(wi->dpy, wi->gc, gc_mask, &values); - + values.foreground = ZnPixel(ZnGetGradientColor(wi->win, cv->fill_color, 0.0, NULL)); + gc_mask = GCFillStyle; + if (cv->tile != ZnUnspecifiedImage) { /* Fill tiled */ + Pixmap pmap = GetImagePixmap(wi->win, cv->tile_name, cv->tile, NULL); + values.fill_style = FillTiled; + values.tile = pmap; + values.ts_x_origin = REAL_TO_INT(item->item_bounding_box.orig.x); + values.ts_y_origin = REAL_TO_INT(item->item_bounding_box.orig.y); + gc_mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCTile; + } + else if (cv->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */ + values.fill_style = FillStippled; + values.stipple = cv->fill_pattern; + values.ts_x_origin = REAL_TO_INT(item->item_bounding_box.orig.x); + values.ts_y_origin = REAL_TO_INT(item->item_bounding_box.orig.y); + gc_mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCStipple|GCForeground; + } + else { /* Fill solid */ + values.fill_style = FillSolid; + gc_mask |= GCForeground; + } + XChangeGC(wi->dpy, wi->gc, gc_mask, &values); + #ifdef GPC - if (cv->tristrip.num_strips == 0) { - gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, &cv->tristrip); - } - for (i = 0; i < cv->tristrip.num_strips; i++) { - num_points = cv->tristrip.strip[i].num_vertices; - points = (ZnPoint *) cv->tristrip.strip[i].vertex; - ZnListAssertSize(wi->work_xpts, num_points); - xpoints = (XPoint *) ZnListArray(wi->work_xpts); - for (j = 0; j < num_points; j++) { - xpoints[j].x = REAL_TO_INT(points[j].x); - xpoints[j].y = REAL_TO_INT(points[j].y); - } - for (j = 0; j < num_points-2; j++) { - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, - &xpoints[j], 3, Convex, CoordModeOrigin); - } - } -#else - num_points = cv->dev_shape.contours[0].num_points; - points = cv->dev_shape.contours[0].points; + if (cv->tristrip.num_strips == 0) { + gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, &cv->tristrip); + } + for (i = 0; i < cv->tristrip.num_strips; i++) { + num_points = cv->tristrip.strip[i].num_vertices; + points = (ZnPoint *) cv->tristrip.strip[i].vertex; ZnListAssertSize(wi->work_xpts, num_points); xpoints = (XPoint *) ZnListArray(wi->work_xpts); - for (i = 0; i < num_points; i++) { - xpoints[i].x = REAL_TO_INT(points[i].x); - xpoints[i].y = REAL_TO_INT(points[i].y); + for (j = 0; j < num_points; j++) { + xpoints[j].x = REAL_TO_INT(points[j].x); + xpoints[j].y = REAL_TO_INT(points[j].y); + } + for (j = 0; j < num_points-2; j++) { + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, + &xpoints[j], 3, Convex, CoordModeOrigin); } - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, - xpoints, num_points, Complex, CoordModeOrigin); -#endif } +#else + num_points = cv->dev_shape.contours[0].num_points; + points = cv->dev_shape.contours[0].points; + ZnListAssertSize(wi->work_xpts, num_points); + xpoints = (XPoint *) ZnListArray(wi->work_xpts); + for (i = 0; i < num_points; i++) { + xpoints[i].x = REAL_TO_INT(points[i].x); + xpoints[i].y = REAL_TO_INT(points[i].y); + } + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, + xpoints, num_points, Complex, CoordModeOrigin); +#endif } - + /* * Draw the lines between points */ @@ -1146,7 +1155,7 @@ Draw(Item item) } } else { - SetLineStyle(wi->dpy, wi->gc, cv->line_style); + SetLineStyle(wi, cv->line_style); values.foreground = ZnPixel(cv->line_color); values.line_width = (cv->line_width == 1) ? 0 : cv->line_width; values.join_style = cv->join_style; @@ -1254,28 +1263,189 @@ Draw(Item item) * ********************************************************************************** */ +#ifdef GLX +void +CurveRenderCB(void *closure) +{ + CurveItem cv = (CurveItem) closure; + int i, j, num_points; + ZnPoint *points; + +#ifdef GPC + if (cv->tristrip.num_strips == 0) { + gpc_polygon_to_tristrip((gpc_polygon *) &cv->dev_shape, &cv->tristrip); + } +#else +#error "GPC needed to render filled curves with GLX" +#endif + for (i = 0; i < cv->tristrip.num_strips; i++) { + num_points = cv->tristrip.strip[i].num_vertices; + points = (ZnPoint *) cv->tristrip.strip[i].vertex; + glBegin(GL_TRIANGLE_STRIP); + for (j = 0; j < num_points; j++) { + glVertex2f(points[j].x, points[j].y); + } + glEnd(); + } +} +#endif static void Render(Item item) { -#ifdef LIBART - WidgetInfo *wi = item->wi; +#ifdef GLX + WidgetInfo *wi = item->wi; CurveItem cv = (CurveItem) item; - XColor *color = ZnGetGradientColor(wi->win, cv->fill_color, 50.0); - ArtPixBuf *pixbuf = NULL; + int i, j, num_points; + ZnPoint *points; + XColor *color; + int alpha; + + if ((cv->dev_shape.num_contours == 0) || + (ISCLEAR(cv->flags, FILLED_OK) && + !cv->line_width && + ISCLEAR(cv->flags, MARKER_OK))) { + return; + } + + /* + * Fill if requested. + */ + if (ISSET(cv->flags, FILLED_OK)) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + if (!ZnGradientFlat(cv->fill_color)) { + RenderGradient(wi, cv->fill_color, CurveRenderCB, cv, cv->grad_geo); + } + else if (cv->tile != ZnUnspecifiedImage) { /* Fill tiled */ + RenderTile(wi, GetImageTexture(wi->win, cv->tile_name, cv->tile), + cv->fill_color, CurveRenderCB, cv, (ZnPoint *) &item->item_bounding_box); + } + else { + if (cv->fill_pattern != ZnUnspecifiedPattern) { /* Fill stippled */ + /* + * Setup polygon stippling. + */ + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(GetBitmapMask(wi->dpy, cv->fill_pattern)->pixels); + } + color = ZnGetGradientColor(wi->win, cv->fill_color, 0.0, &alpha); + glColor4us(color->red, color->green, color->blue, alpha*65535/100); + CurveRenderCB(cv); + glDisable(GL_POLYGON_STIPPLE); + } + } + + /* + * Draw the lines between points + */ + if (cv->line_width) { + /* + * Drawing with relief disables: ends, line style and line pattern. + */ + if (ISSET(cv->flags, RELIEF_OK)) { + } + else { + color = cv->line_color; + glColor4us(color->red, color->green, color->blue, cv->line_alpha*65535/100); + if ((cv->line_width <= wi->max_line_width) && + (cv->line_width <= wi->max_point_width)) { + glLineWidth(cv->line_width); + SetLineStyle(wi, cv->line_style); + for (j = 0; j < cv->dev_shape.num_contours; j++) { + num_points = cv->dev_shape.contours[j].num_points; + points = cv->dev_shape.contours[j].points; + if (ISSET(cv->flags, CLOSED_BIT)) { + glBegin(GL_LINE_LOOP); + } + else { + glBegin(GL_LINE_STRIP); + } + for (i = 0; i < num_points; i++) { + glVertex2f(points[i].x, points[i].y); + } + glEnd(); + } + if (cv->line_width > 1) { + glPointSize(cv->line_width); + for (j = 0; j < cv->dev_shape.num_contours; j++) { + num_points = cv->dev_shape.contours[j].num_points; + points = cv->dev_shape.contours[j].points; + glBegin(GL_POINTS); + for (i = 0; i < num_points; i++) { + glVertex2f(points[i].x, points[i].y); + } + glEnd(); + } + } + } + else { + double lw_2 = (double) cv->line_width / 2.0; + double section[2][2] = { { 0.0, -lw_2 }, { 0.0, lw_2 } }; + double up[3] = { 1.0, 0.0, 0.0 }; + double (*gl_pts)[3]; + int style, num; + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + for (j = 0; j < cv->dev_shape.num_contours; j++) { + num_points = cv->dev_shape.contours[j].num_points; + points = cv->dev_shape.contours[j].points; + ZnListAssertSize(wi->work_doubles, (num_points+3)*3); + gl_pts = (void *) ZnListArray(wi->work_doubles); + if (ISSET(cv->flags, CLOSED_BIT)) { + gl_pts[0][0] = points[num_points-1].x; + gl_pts[0][1] = points[num_points-1].y; + gl_pts[0][2] = 0; + gl_pts[num_points+1][0] = points[0].x; + gl_pts[num_points+1][1] = points[0].y; + gl_pts[num_points+1][2] = 0; + gl_pts[num_points+2][0] = points[1].x; + gl_pts[num_points+2][1] = points[1].y; + gl_pts[num_points+2][2] = 0; + } + else { + gl_pts[0][0] = points[0].x; + gl_pts[1][1] = points[0].y; + gl_pts[2][2] = 0; + gl_pts[num_points+1][0] = points[num_points-1].x; + gl_pts[num_points+1][1] = points[num_points-1].y; + gl_pts[num_points+1][2] = 0; + } + for (i = 0; i < num_points; i++) { + gl_pts[i+1][0] = points[i].x; + gl_pts[i+1][1] = points[i].y; + gl_pts[i+1][2] = 0; + } + switch (cv->join_style) { + case JoinRound: + style = TUBE_JN_ROUND; + break; + case JoinMiter: + style = TUBE_JN_ANGLE; + break; + case JoinBevel: + style = TUBE_JN_CUT; + break; + } + if (cv->cap_style == CapRound) { + style |= TUBE_JN_CAP; + } + style |= TUBE_CONTOUR_CLOSED; + + num = num_points+2; + if (ISSET(cv->flags, CLOSED_BIT)) { + num++; + } + gleSetJoinStyle(style); + gleExtrusion(2, section, NULL, up, num, gl_pts, NULL); + } + } + } + } - if (cv->fill_svp != NULL) { - if (strlen(cv->tile_name) != 0) { - pixbuf = GetImagePixbuf(wi->win, cv->tile_name, cv->tile); - } - ITEM_P.RenderSVP(wi, cv->fill_svp, color->red, color->green, - color->blue, cv->fill_alpha & 0xff, - item->item_bounding_box.orig.x, - item->item_bounding_box.orig.y, pixbuf); - } - if (cv->outline_svp != NULL) { - ITEM_P.RenderSVP(wi, cv->outline_svp, cv->line_color->red, - cv->line_color->green, cv->line_color->blue, - cv->line_alpha & 0xff, 0, 0, NULL); + /* + * Draw the marks at each point. If arrows are specified or + * if last point join first point suppress markers at end points. + */ + if (ISSET(cv->flags, MARKER_OK)) { } #endif } |