diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/Arc.c | 317 |
1 files changed, 190 insertions, 127 deletions
diff --git a/generic/Arc.c b/generic/Arc.c index 89dd651..54476e0 100644 --- a/generic/Arc.c +++ b/generic/Arc.c @@ -481,6 +481,64 @@ Tangent(ArcItem arc, ********************************************************************************** */ static void +UpdateRenderShape(ArcItem arc) +{ + ZnPoint *p_list, p, p2, o, o2; + ZnReal width, height, d; + int num_p, i, quality; + ZnTransfo *t = ((Item) arc)->wi->current_transfo; + + if (!arc->render_shape) { + arc->render_shape = ZnListNew(8, sizeof(ZnPoint)); + } + + o.x = (arc->coords[1].x + arc->coords[0].x)/2.0; + o.y = (arc->coords[1].y + arc->coords[0].y)/2.0; + width = (arc->coords[1].x - arc->coords[0].x)/2.0; + height = (arc->coords[1].y - arc->coords[0].y)/2.0; + d = MAX(width, height); + quality = ZN_CIRCLE_COARSE; + p_list = GetCirclePoints(ISCLEAR(arc->flags, PIE_SLICE_BIT) ? 1 : 2, + quality, + DegreesToRadian(arc->start_angle), + DegreesToRadian(arc->start_angle+arc->angle_extent), + &num_p, + arc->render_shape); + + /* + * Adapt the number of arc circles to the radius of the arc. + */ + p.x = o.x + p_list->x*d; + p.y = o.y + p_list->y*d; + ZnTransformPoint(t, &o, &o2); + ZnTransformPoint(t, &p, &p2); + d = hypot(o2.x-p2.x, o2.y-p2.y); + if (d > 100.0) { + quality = ZN_CIRCLE_FINEST; + } + else if (d > 30.0) { + quality = ZN_CIRCLE_FINE; + } + else if (d > 9.0) { + quality = ZN_CIRCLE_MEDIUM; + } + if (quality != ZN_CIRCLE_COARSE) { + p_list = GetCirclePoints(ISCLEAR(arc->flags, PIE_SLICE_BIT) ? 1 : 2, + quality, + DegreesToRadian(arc->start_angle), + DegreesToRadian(arc->start_angle+arc->angle_extent), + &num_p, + arc->render_shape); + } + + for (i = 0; i < num_p; i++, p_list++) { + p.x = o.x + p_list->x*width; + p.y = o.y + p_list->y*height; + ZnTransformPoint(t, &p, p_list); + } +} + +static void ComputeCoordinates(Item item, ZnBool force) { @@ -488,10 +546,9 @@ ComputeCoordinates(Item item, ArcItem arc = (ArcItem) item; ZnReal angle, sin1, cos1, sin2, cos2; ZnReal tmp, w_2, h_2, center_x, center_y; - int num_p, i; + int num_p; ZnPoint *p_list, p; ZnPoint end_points[LINE_END_POINTS]; - ZnReal width, height, ox, oy; ResetBBox(&item->item_bounding_box); /* @@ -501,38 +558,19 @@ ComputeCoordinates(Item item, return; } - ZnTransformPoint(wi->current_transfo, &arc->coords[0], &arc->orig); - ZnTransformPoint(wi->current_transfo, &arc->coords[1], &arc->corner); /* * Special case for ellipse rotation and gradient. */ - ZnTransfoDecompose(wi->current_transfo, NULL, NULL, &angle, NULL); - width = arc->coords[1].x - arc->coords[0].x; - height = arc->coords[1].y - arc->coords[0].y; - if (((angle >= PRECISION_LIMIT) && ((width - height) > PRECISION_LIMIT)) || - !ZnGradientFlat(arc->fill_color) || wi->render) { + if (!wi->render) { + ZnTransfoDecompose(wi->current_transfo, NULL, NULL, &angle, NULL); + } + if (wi->render || (angle >= PRECISION_LIMIT)) { SET(arc->flags, USING_POLY_BIT); - if (!arc->render_shape) { - arc->render_shape = ZnListNew(20, sizeof(ZnPoint)); - } - p_list = GetCirclePoints((ISCLEAR(arc->flags, CLOSED_BIT) ? 0 : - ISCLEAR(arc->flags, PIE_SLICE_BIT) ? 1 : 2), - ZN_CIRCLE_FINEST, - DegreesToRadian(arc->start_angle), - DegreesToRadian(arc->start_angle+arc->angle_extent), - &num_p, - arc->render_shape); - ox = (arc->corner.x + arc->orig.x)/2.0; - oy = (arc->corner.y + arc->orig.y)/2.0; - width = (arc->corner.x - arc->orig.x)/2.0; - height = (arc->corner.y - arc->orig.y)/2.0; - - for (i = 0; i < num_p; i++, p_list++) { - p_list->x = ox + p_list->x*width; - p_list->y = oy + p_list->y*height; - AddPointToBBox(&item->item_bounding_box, p_list->x, p_list->y); - } + UpdateRenderShape(arc); + p_list = ZnListArray(arc->render_shape); + num_p = ZnListSize(arc->render_shape); + AddPointsToBBox(&item->item_bounding_box, p_list, num_p); tmp = (arc->line_width + 1.0) / 2.0 + 1.0; item->item_bounding_box.orig.x -= tmp; @@ -555,68 +593,31 @@ ComputeCoordinates(Item item, } if (!ZnGradientFlat(arc->fill_color)) { + ZnPoly shape; + + if (!arc->grad_geo) { + arc->grad_geo = ZnMalloc(4*sizeof(ZnPoint)); + } if (arc->fill_color->type == ZN_AXIAL_GRADIENT) { - int angle = arc->fill_color->g.angle; - ZnTransfo *transfo1, *transfo2; - ZnPoint p[4], p1[4]; - ZnBBox bbox; + ZnPoint p[4]; - if (!arc->grad_geo) { - arc->grad_geo = ZnMalloc(4*sizeof(ZnPoint)); - } - transfo1 = ZnTransfoNew(); - transfo2 = ZnTransfoNew(); - ZnRotateDeg(transfo1, angle); - ZnRotateDeg(transfo2, -angle); p[0] = arc->coords[0]; p[2] = arc->coords[1]; p[1].x = p[2].x; p[1].y = p[0].y; p[3].x = p[0].x; p[3].y = p[2].y; - ZnTransformPoints(transfo1, p, p1, 4); - ResetBBox(&bbox); - AddPointsToBBox(&bbox, p1, 4); - p1[0] = bbox.orig; - p1[2] = bbox.corner; - p1[1].x = p1[2].x; - p1[1].y = p1[0].y; - p1[3].x = p1[0].x; - p1[3].y = p1[2].y; - ZnTransfoSetIdentity(transfo1); - ZnTransfoCompose(transfo1, transfo2, wi->current_transfo); - ZnTransformPoints(transfo1, p1, arc->grad_geo, 4); - ZnTransfoFree(transfo1); - ZnTransfoFree(transfo2); + POLY_CONTOUR1(&shape, p, 4); + ComputeAxialGradient(wi, &shape, arc->fill_color->g.angle, arc->grad_geo); } else if (arc->fill_color->type == ZN_RADIAL_GRADIENT) { - ZnReal dist, new, x, y, fact; - ZnPoint p1[2]; - ZnBBox *bbox = &item->item_bounding_box; - ZnTransfo *transfo1; - - if (!arc->grad_geo) { - arc->grad_geo = ZnMalloc(2*sizeof(ZnPoint)); - } - ZnTransformPoint(wi->current_transfo, &arc->fill_color->g.p, &arc->grad_geo[0]); - transfo1 = ZnTransfoNew(); - ZnTranslate(transfo1, -arc->grad_geo[0].x, -arc->grad_geo[0].y); - fact = (bbox->corner.x-bbox->orig.x)/(bbox->corner.y-bbox->orig.y); - ZnScale(transfo1, 1.0, fact); - ZnTransformPoint(transfo1, &arc->orig, &p1[0]); - ZnTransformPoint(transfo1, &arc->corner, &p1[1]); - dist = 0.0; - for (i = 0; i < 2; i++) { - x = p1[i].x; - y = p1[i].y; - new = x*x+y*y; - if (new > dist) { - dist = new; - } - } - arc->grad_geo[1].x = sqrt(dist) + 2; /* Max radius plus a fuzz factor */ - arc->grad_geo[1].y = arc->grad_geo[1].x / fact; - ZnTransfoFree(transfo1); + POLY_CONTOUR1(&shape, ZnListArray(arc->render_shape), + ZnListSize(arc->render_shape)); + ComputeRadialGradient(wi, &shape, &item->item_bounding_box, + &arc->fill_color->g.p, arc->grad_geo); + } + else if (arc->fill_color->type == ZN_PATH_GRADIENT) { + ZnTransformPoint(wi->current_transfo, &arc->fill_color->g.p, &arc->grad_geo[0]); } } else { @@ -635,6 +636,8 @@ ComputeCoordinates(Item item, ******* ******** ********** */ CLEAR(arc->flags, USING_POLY_BIT); + ZnTransformPoint(wi->current_transfo, &arc->coords[0], &arc->orig); + ZnTransformPoint(wi->current_transfo, &arc->coords[1], &arc->corner); if (arc->orig.x > arc->corner.x) { tmp = arc->orig.x; @@ -1134,6 +1137,12 @@ Draw(Item item) &values); } if (ISSET(arc->flags, USING_POLY_BIT)) { + if (ISCLEAR(arc->flags, CLOSED_BIT) && arc->angle_extent != 360) { + num_points--; + if (ISSET(arc->flags, PIE_SLICE_BIT)) { + num_points--; + } + } XDrawLines(wi->dpy, wi->draw_buffer, wi->gc, xp, num_points, CoordModeOrigin); if (ISSET(arc->flags, FIRST_END_OK)) { @@ -1260,7 +1269,10 @@ Render(Item item) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (!ZnGradientFlat(arc->fill_color)) { - RenderGradient(wi, arc->fill_color, ArcRenderCB, arc, arc->grad_geo); + ZnPoly poly; + + POLY_CONTOUR1(&poly, ZnListArray(arc->render_shape), ZnListSize(arc->render_shape)); + RenderGradient(wi, arc->fill_color,ArcRenderCB, arc, arc->grad_geo, &poly); } else if (arc->tile != ZnUnspecifiedImage) { /* Fill tiled */ RenderTile(wi, GetImageTexture(wi->win, arc->tile_name, arc->tile), @@ -1300,6 +1312,12 @@ Render(Item item) } else { glBegin(GL_LINE_STRIP); + if (arc->angle_extent != 360) { + num_points--; + if (ISSET(arc->flags, PIE_SLICE_BIT)) { + num_points--; + } + } } for (i = 0; i < num_points; i++) { glVertex2f(p[i].x, p[i].y); @@ -1376,6 +1394,12 @@ Pick(Item item, } } if (arc->line_width > 0) { + if (ISCLEAR(arc->flags, CLOSED_BIT) && arc->angle_extent != 360) { + num_points--; + if (ISSET(arc->flags, PIE_SLICE_BIT)) { + num_points--; + } + } new_dist = PolylineToPointDist(points, num_points, arc->line_width, CapRound, JoinRound, p); if (new_dist < dist) { @@ -1384,30 +1408,31 @@ Pick(Item item, if (dist <= 0.0) { return 0.0; } - } - /* - * Check line ends. - */ - if (ISSET(arc->flags, FIRST_END_OK)) { - GetLineEnd(&points[0], &points[1], arc->line_width, CapRound, - arc->first_end, end_points); - new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p); - if (new_dist < dist) { - dist = new_dist; - } - if (dist <= 0.0) { - return 0.0; - } - } - if (ISSET(arc->flags, LAST_END_OK)) { - GetLineEnd(&points[num_points-1], &points[num_points-2], arc->line_width, - CapRound, arc->last_end, end_points); - new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p); - if (new_dist < dist) { - dist = new_dist; + + /* + * Check line ends. + */ + if (ISSET(arc->flags, FIRST_END_OK)) { + GetLineEnd(&points[0], &points[1], arc->line_width, CapRound, + arc->first_end, end_points); + new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p); + if (new_dist < dist) { + dist = new_dist; + } + if (dist <= 0.0) { + return 0.0; + } } - if (dist <= 0.0) { - return 0.0; + if (ISSET(arc->flags, LAST_END_OK)) { + GetLineEnd(&points[num_points-1], &points[num_points-2], arc->line_width, + CapRound, arc->last_end, end_points); + new_dist = PolygonToPointDist(end_points, LINE_END_POINTS, p); + if (new_dist < dist) { + dist = new_dist; + } + if (dist <= 0.0) { + return 0.0; + } } } return dist; @@ -1618,41 +1643,78 @@ Pick(Item item, * * GetClipVertices -- * Get the clipping shape. + * Never ever call TRI_FREE on the tristrip returned by GetClipVertices. * ********************************************************************************** */ -static ZnBool -GetClipVertices(Item item, - ZnPoly *poly) +static void +UpdateRenderShapeX(ArcItem arc) { - ArcItem arc = (ArcItem) item; ZnReal ox, oy, width_2, height_2; int i, num_p; ZnPoint *p_list; + if (!arc->render_shape) { + arc->render_shape = ZnListNew(8, sizeof(ZnPoint)); + } + p_list = GetCirclePoints(ISCLEAR(arc->flags, PIE_SLICE_BIT) ? 1 : 2, + ZN_CIRCLE_FINE, + DegreesToRadian(arc->start_angle), + DegreesToRadian(arc->start_angle+arc->angle_extent), + &num_p, arc->render_shape); + ox = (arc->corner.x + arc->orig.x) / 2.0; + oy = (arc->corner.y + arc->orig.y) / 2.0; + width_2 = (arc->corner.x - arc->orig.x) / 2.0; + height_2 = (arc->corner.y - arc->orig.y) / 2.0; + for (i = 0; i < num_p; i++, p_list++) { + p_list->x = ox + p_list->x*width_2; + p_list->y = oy + p_list->y*height_2; + } +} + +static ZnBool +GetClipVertices(Item item, + ZnTriStrip *tristrip) +{ + ArcItem arc = (ArcItem) item; + if (ISCLEAR(arc->flags, USING_POLY_BIT)) { - if (!arc->render_shape) { - arc->render_shape = ZnListNew(4, sizeof(ZnPoint)); - } - p_list = GetCirclePoints((ISCLEAR(arc->flags, CLOSED_BIT) ? 0 : - ISCLEAR(arc->flags, PIE_SLICE_BIT) ? 1 : 2), - ZN_CIRCLE_FINEST, - DegreesToRadian(arc->start_angle), - DegreesToRadian(arc->start_angle+arc->angle_extent), - &num_p, arc->render_shape); - ox = (arc->corner.x + arc->orig.x) / 2.0; - oy = (arc->corner.y + arc->orig.y) / 2.0; - width_2 = (arc->corner.x - arc->orig.x) / 2.0; - height_2 = (arc->corner.y - arc->orig.y) / 2.0; - for (i = 0; i < num_p; i++, p_list++) { - p_list->x = ox + p_list->x*width_2; - p_list->y = oy + p_list->y*height_2; - } + UpdateRenderShapeX(arc); SET(arc->flags, USING_POLY_BIT); } + + TRI_STRIP1(tristrip, ZnListArray(arc->render_shape), + ZnListSize(arc->render_shape)); + tristrip->fan = True; + tristrip->center.x = (item->item_bounding_box.corner.x + item->item_bounding_box.orig.x) / 2.0; + tristrip->center.y = (item->item_bounding_box.corner.y + item->item_bounding_box.orig.y) / 2.0; + + return False; +} + + +/* + ********************************************************************************** + * + * GetContours -- + * Get the external contour(s). + * Never ever call POLY_FREE on the tristrip returned by GetContours. + * + ********************************************************************************** + */ +static ZnBool +GetContours(Item item, + ZnPoly *poly) +{ + ArcItem arc = (ArcItem) item; + + if (ISCLEAR(arc->flags, USING_POLY_BIT) || !arc->render_shape) { + UpdateRenderShapeX(arc); + } + POLY_CONTOUR1(poly, ZnListArray(arc->render_shape), ZnListSize(arc->render_shape)); - + return False; } @@ -1763,6 +1825,7 @@ static ItemClassStruct ARC_ITEM_CLASS = { NULL, /* GetFieldSet */ NULL, /* GetAnchor */ GetClipVertices, + GetContours, Coords, NULL, /* InsertChars */ NULL, /* DeleteChars */ |