aboutsummaryrefslogtreecommitdiff
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/Arc.c317
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 */