From 1bd8808d5660cbede81165a25a6cd59e5c5c69b5 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Mon, 9 Dec 2002 14:30:25 +0000 Subject: * Remaniement du code des gradients (incompatibilit�s). * Utilisation des display lists pour am�liorer les perfs en GL. * Adaptation pour g�rer la nouvelle fa�on de traiter les contours. * Nombreuses corrections de bug suite � l'introduction du code sur les contours. * Fin de r�alisation des paths. --- generic/Curve.c | 360 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 236 insertions(+), 124 deletions(-) diff --git a/generic/Curve.c b/generic/Curve.c index ee50dcd..07e686e 100644 --- a/generic/Curve.c +++ b/generic/Curve.c @@ -19,6 +19,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. + * * You should have received a copy of the GNU Library General Public * License along with this code; if not, write to the Free @@ -26,7 +27,6 @@ * */ - #include "Draw.h" #include "Item.h" #include "Geo.h" @@ -38,7 +38,7 @@ #include #include - +#include static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; @@ -175,10 +175,12 @@ Init(Item item, CurveItem cv = (CurveItem) item; int i, num_points, count; ZnPoint *p, *points; - char *controls; + char *controls, *c; cv->outlines.num_contours = 0; + cv->outlines.contours = NULL; cv->tristrip.num_strips = 0; + cv->tristrip.strips = NULL; cv->gradient = NULL; cv->grad_geo = NULL; @@ -212,30 +214,54 @@ Init(Item item, if (controls) { count = 0; if ((controls[0]) || (controls[num_points-1])) { - goto control_err; + goto contr_err; } for (i = 1; i < num_points-1; i++) { switch (controls[i]) { case 'c': count++; if (count > 2) { - goto control_err; + goto contr_err; } break; case 0: count = 0; break; default: - control_err: + contr_err: ZnFree(controls); Tcl_AppendResult(wi->interp, " curve coords expected", NULL); return ZN_ERROR; } } } + /* + * Do not allow a hole to be added as the first contour, it breaks + * backward compatibility. Instead silently convert it to a plain + * contour. + */ p = ZnMalloc(num_points * sizeof(ZnPoint)); - memcpy(p, points, num_points * sizeof(ZnPoint)); - POLY_CONTOUR1(&cv->shape, p, num_points); + if (! TestCCW(points, num_points)) { + if (controls) { + c = ZnMalloc(num_points * sizeof(char)); + for (i = 0; i < num_points; i++) { + c[num_points-i-1] = controls[i]; + } + ZnFree(controls); + controls = c; + } + for (i = 0; i < num_points; i++) { + p[num_points-i-1] = points[i]; + } + /*printf("revert hole to contour, numpoints: %d %g@%g\n", + num_points, points[0].x, points[0].y);*/ + } + else { + /*printf("plain contour, numpoints: %d %g@%g\n", + num_points, points[0].x, points[0].y);*/ + memcpy(p, points, num_points * sizeof(ZnPoint)); + } + POLY_CONTOUR1(&cv->shape, p, num_points, False); cv->shape.contours[0].controls = controls; } (*args)++; @@ -331,7 +357,9 @@ Clone(Item item) cv->fill_color = ZnGetGradientByValue(cv->fill_color); cv->marker_color = ZnGetGradientByValue(cv->marker_color); cv->tristrip.num_strips = 0; + cv->tristrip.strips = NULL; cv->outlines.num_contours = 0; + cv->outlines.contours = NULL; } @@ -541,13 +569,13 @@ CurveTessVertex(void *vertex_data, cv->tristrip.strips[cv->tristrip.num_strips-1].points = ZnMalloc(size * sizeof(ZnPoint)); memcpy(cv->tristrip.strips[cv->tristrip.num_strips-1].points, ZnListArray(wi->work_pts), size * sizeof(ZnPoint)); - + /*printf("Fin de fragment intermediaire %d, num points: %d\n", cv->tristrip.num_strips-1, size);*/ /* Allocate a new fragment */ ZnListEmpty(wi->work_pts); cv->tristrip.num_strips++; cv->tristrip.strips = ZnRealloc(cv->tristrip.strips, cv->tristrip.num_strips * sizeof(ZnStrip)); - cv->tristrip.strips[cv->tristrip.num_strips-1].fan = GL_TRIANGLES; + cv->tristrip.strips[cv->tristrip.num_strips-1].fan = False; } ZnListAdd(wi->work_pts, &p, ZnListTail); } @@ -577,7 +605,7 @@ CurveTessEnd(void *data) memcpy(cv->tristrip.strips[num-1].points, ZnListArray(wi->work_pts), size * sizeof(ZnPoint)); } - /* printf("Fin de fragment %d\n", num);*/ + /*printf("Fin de fragment %d, num points: %d\n", num, size);*/ } static void CurveTessCombine(GLdouble coords[3], @@ -596,7 +624,7 @@ CurveTessCombine(GLdouble coords[3], wi->tess_combine_list = cdata; *out_data = &cdata->v; /*printf("Création d'un nouveau sommet en %g %g\n", - cdata->v[0], cdata->v[1]);*/ + cdata->v[0], cdata->v[1]);*/ } static void CurveTessError(GLenum errno, @@ -617,6 +645,7 @@ UpdateTristrip(CurveItem cv, GLdouble v[3]; int i, j; + /*printf("UpdateTristrips sur %d\n", ((Item) cv)->id);*/ gluTessCallback(wi->tess, GLU_TESS_BEGIN_DATA, (void (*)()) CurveTessBegin); gluTessCallback(wi->tess, GLU_TESS_VERTEX_DATA, (void (*)()) CurveTessVertex); gluTessCallback(wi->tess, GLU_TESS_END_DATA, (void (*)()) CurveTessEnd); @@ -651,6 +680,7 @@ UpdateTristrip(CurveItem cv, } wi->tess_combine_list = NULL; } + /*printf("Fin UpdateTristrips sur %d\n", ((Item) cv)->id);*/ } static void @@ -662,6 +692,7 @@ UpdateOutlines(CurveItem cv, GLdouble v[3]; int i, j; + /*printf("UpdateOutlines sur %d\n", ((Item) cv)->id);*/ gluTessCallback(wi->tess, GLU_TESS_BEGIN_DATA, (void (*)()) CurveTessBegin); gluTessCallback(wi->tess, GLU_TESS_VERTEX_DATA, (void (*)()) CurveTessVertex); gluTessCallback(wi->tess, GLU_TESS_END_DATA, (void (*)()) CurveTessEnd); @@ -692,6 +723,7 @@ UpdateOutlines(CurveItem cv, } wi->tess_combine_list = NULL; } + /*printf("Fin UpdateOutlines sur %d\n", ((Item) cv)->id);*/ } @@ -720,7 +752,7 @@ ComputeCoordinates(Item item, ResetBBox(&item->item_bounding_box); - /* printf("Curve CC: flags %x\n", cv->flags);*/ + /*printf("Curve CC: flags %x\n", cv->flags);*/ SetRenderFlags(cv); num_contours = cv->shape.num_contours; @@ -759,8 +791,8 @@ ComputeCoordinates(Item item, if ((num_contours == 1) && (c1->num_points > 2) && ISSET(cv->flags, CLOSED_BIT) && - ((c1->points[0].x != c1->points[c2->num_points-1].x) || - (c1->points[0].y != c1->points[c2->num_points-1].y)) && + ((c1->points[0].x != c1->points[c1->num_points-1].x) || + (c1->points[0].y != c1->points[c1->num_points-1].y)) && (c1->num_points > 2)) { c2->num_points++; } @@ -788,7 +820,7 @@ ComputeCoordinates(Item item, c2->points[j].x, c2->points[j].y);*/ GetBezierPoints(&c2->points[segment_start], &c2->points[segment_start+1], &c2->points[j-1], - &c2->points[j], wi->work_pts, 2.0); + &c2->points[j], wi->work_pts, 0.5); } else { /*printf("lineto %g@%g\n", c2->points[j].x, c2->points[j].y);*/ @@ -798,6 +830,17 @@ ComputeCoordinates(Item item, } } /* + * Must test if the last point is a control and the contour + * is closed (either a mono contour with -closed or + * multiple contours). + */ + if (c1->controls[c1->num_points-1]) { + GetBezierPoints(&c2->points[segment_start], + &c2->points[segment_start+1], &c2->points[c1->num_points-1], + &c2->points[0], wi->work_pts, 0.5); + } + + /* * Replce the original path by the expanded, closing it as * needed (one open contour). */ @@ -816,8 +859,8 @@ ComputeCoordinates(Item item, UpdateTristrip(cv, &dev); if (num_contours == 1) { - POLY_CONTOUR1(&cv->outlines, dev.contours[0].points, dev.contours[0].num_points); - cv->outlines.contours[0].cw = dev.contours[0].cw; + POLY_CONTOUR1(&cv->outlines, dev.contours[0].points, dev.contours[0].num_points, + dev.contours[0].cw); } else { UpdateOutlines(cv, &dev); @@ -913,20 +956,20 @@ ComputeCoordinates(Item item, item->item_bounding_box.corner.x += 1; item->item_bounding_box.corner.y += 1; } - + +#ifdef GLX if (!ZnGradientFlat(cv->fill_color)) { if (!cv->grad_geo) { - cv->grad_geo = ZnMalloc(4*sizeof(ZnPoint)); + cv->grad_geo = ZnMalloc(6*sizeof(ZnPoint)); } if (cv->fill_color->type == ZN_AXIAL_GRADIENT) { ZnComputeAxialGradient(wi, &cv->shape, cv->fill_color->g.angle, cv->grad_geo); } else if (cv->fill_color->type == ZN_RADIAL_GRADIENT) { - ZnComputeRadialGradient(wi, &cv->outlines, &item->item_bounding_box, - &cv->fill_color->g.p, cv->grad_geo); + ZnComputeRadialGradient(wi, &cv->shape, False, &cv->fill_color->g.p, cv->grad_geo); } else if (cv->fill_color->type == ZN_PATH_GRADIENT) { - ZnTransformPoint(wi->current_transfo, &cv->fill_color->g.p, &cv->grad_geo[0]); + ZnComputePathGradient(wi, &cv->shape, &cv->fill_color->g.p, cv->grad_geo); } } else { @@ -935,6 +978,7 @@ ComputeCoordinates(Item item, cv->grad_geo = NULL; } } +#endif } @@ -1141,15 +1185,31 @@ Draw(Item item) for (i = 0; i < cv->tristrip.num_strips; i++) { num_points = cv->tristrip.strips[i].num_points; points = cv->tristrip.strips[i].points; - 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); + if (cv->tristrip.strips[i].fan) { + XPoint xpoints[3]; + xpoints[0].x = REAL_TO_INT(points[0].x); + xpoints[0].y = REAL_TO_INT(points[0].y); + xpoints[1].x = REAL_TO_INT(points[1].x); + xpoints[1].y = REAL_TO_INT(points[1].y); + for (j = 2; j < num_points; j++) { + xpoints[2].x = REAL_TO_INT(points[j].x); + xpoints[2].y = REAL_TO_INT(points[j].y); + XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, + xpoints, 3, Convex, CoordModeOrigin); + xpoints[1] = xpoints[2]; + } } - for (j = 0; j < num_points-2; j++) { - XFillPolygon(wi->dpy, wi->draw_buffer, wi->gc, - &xpoints[j], 3, Convex, CoordModeOrigin); + else { + ZnListAssertSize(wi->work_xpts, num_points); + xpoints = 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); + } } } } @@ -1198,7 +1258,7 @@ Draw(Item item) num2 = num_points = cv->outlines.contours[j].num_points; points = cv->outlines.contours[j].points; ZnListAssertSize(wi->work_xpts, num_points); - xpoints = (XPoint *) ZnListArray(wi->work_xpts); + xpoints = ZnListArray(wi->work_xpts); for (i = 0; i < num2; i++) { xpoints[i].x = REAL_TO_INT(points[i].x); xpoints[i].y = REAL_TO_INT(points[i].y); @@ -1319,7 +1379,7 @@ Render(Item item) ZnPoint *points; XColor *color; int alpha; - + if ((cv->outlines.num_contours == 0) || (ISCLEAR(cv->flags, FILLED_OK) && !cv->line_width && @@ -1327,99 +1387,108 @@ Render(Item item) return; } - /* - * Fill if requested. - */ - if (ISSET(cv->flags, FILLED_OK)) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - if (!ZnGradientFlat(cv->fill_color)) { - ZnRenderGradient(wi, cv->fill_color, CurveRenderCB, cv, cv->grad_geo, - &cv->outlines); - } - else if (cv->tile != ZnUnspecifiedImage) { /* Fill tiled */ - ZnRenderTile(wi, cv->tile, cv->fill_color, CurveRenderCB, cv, - (ZnPoint *) &item->item_bounding_box); - } - else { - if (cv->fill_pattern != ZnUnspecifiedImage) { /* Fill stippled */ - /* - * Setup polygon stippling. - */ - glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple(ZnImagePattern(cv->fill_pattern, NULL)); + if (!item->gl_list) { + item->gl_list = glGenLists(1); + glNewList(item->gl_list, GL_COMPILE); + + /* + * Fill if requested. + */ + if (ISSET(cv->flags, FILLED_OK)) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + if (!ZnGradientFlat(cv->fill_color)) { + ZnRenderGradient(wi, cv->fill_color, CurveRenderCB, cv, cv->grad_geo, + &cv->outlines); + } + else if (cv->tile != ZnUnspecifiedImage) { /* Fill tiled */ + ZnRenderTile(wi, cv->tile, cv->fill_color, CurveRenderCB, cv, + (ZnPoint *) &item->item_bounding_box); + } + else { + if (cv->fill_pattern != ZnUnspecifiedImage) { /* Fill stippled */ + /* + * Setup polygon stippling. + */ + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(ZnImagePattern(cv->fill_pattern, NULL)); + } + color = ZnGetGradientColor(cv->fill_color, 0.0, &alpha); + alpha = ZnComposeAlpha(alpha, wi->alpha); + glColor4us(color->red, color->green, color->blue, alpha); + CurveRenderCB(cv); + glDisable(GL_POLYGON_STIPPLE); } - color = ZnGetGradientColor(cv->fill_color, 0.0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - glColor4us(color->red, color->green, color->blue, alpha); - 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. + * Draw the lines between points */ - ZnGetGradientColor(cv->line_color, 0, &alpha); - alpha = ZnComposeAlpha(alpha, wi->alpha); - if (ISSET(cv->flags, RELIEF_OK)) { - for (j = 0; j < cv->outlines.num_contours; j++) { - num_points = cv->outlines.contours[j].num_points; - points = cv->outlines.contours[j].points; - /*printf("Render: item %d, num_points %d %g@%g %g@%g, cw %d i/o %d\n", - item->id, - num_points, points[0].x, points[0].y, - points[num_points-1].x, points[num_points-1].y, - cv->outlines.contours[j].cw);*/ - ZnRenderPolygonRelief(wi, cv->relief, cv->gradient, ISSET(cv->flags, SMOOTH_RELIEF_BIT), - points, num_points, cv->line_width); + if (cv->line_width) { + /* + * Drawing with relief disables: ends, line style and line pattern. + */ + ZnGetGradientColor(cv->line_color, 0, &alpha); + alpha = ZnComposeAlpha(alpha, wi->alpha); + if (ISSET(cv->flags, RELIEF_OK)) { + for (j = 0; j < cv->outlines.num_contours; j++) { + num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; + /*printf("Render: item %d, num_points %d %g@%g %g@%g, cw %d i/o %d\n", + item->id, + num_points, points[0].x, points[0].y, + points[num_points-1].x, points[num_points-1].y, + cv->outlines.contours[j].cw);*/ + ZnRenderPolygonRelief(wi, cv->relief, cv->gradient, ISSET(cv->flags, SMOOTH_RELIEF_BIT), + points, num_points, cv->line_width); + } + } + else { + ZnLineEnd first = ISSET(cv->flags, FIRST_END_OK) ? cv->first_end : NULL; + ZnLineEnd last = ISSET(cv->flags, LAST_END_OK) ? cv->last_end : NULL; + + for (j = 0; j < cv->outlines.num_contours; j++) { + ZnRenderPolyline(wi, + cv->outlines.contours[j].points, + cv->outlines.contours[j].num_points, + cv->line_width, cv->line_style, cv->cap_style, cv->join_style, + first, last, cv->line_color); + } } } - else { - ZnLineEnd first = ISSET(cv->flags, FIRST_END_OK) ? cv->first_end : NULL; - ZnLineEnd last = ISSET(cv->flags, LAST_END_OK) ? cv->last_end : 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)) { + int h_width, h_height; + ZnPoint ptmp; + ZnSizeOfImage(cv->marker, &h_width, & h_height); + h_width = (h_width+1.0)/2.0; + h_height = (h_height+1.0)/2.0; for (j = 0; j < cv->outlines.num_contours; j++) { - ZnRenderPolyline(wi, - cv->outlines.contours[j].points, - cv->outlines.contours[j].num_points, - cv->line_width, cv->line_style, cv->cap_style, cv->join_style, - first, last, cv->line_color); + num_points = cv->outlines.contours[j].num_points; + points = cv->outlines.contours[j].points; + if (ISSET(cv->flags, FIRST_END_OK)) { + num_points--; + points++; + } + if (ISSET(cv->flags, LAST_END_OK)) { + num_points--; + } + for (; num_points > 0; num_points--, points++) { + ptmp.x = points->x - h_width; + ptmp.y = points->y - h_height; + ZnRenderIcon(wi, cv->marker, cv->marker_color, &ptmp, True); + } } } + + glEndList(); } - /* - * 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)) { - int h_width, h_height; - ZnPoint ptmp; - - ZnSizeOfImage(cv->marker, &h_width, & h_height); - h_width = (h_width+1.0)/2.0; - h_height = (h_height+1.0)/2.0; - for (j = 0; j < cv->outlines.num_contours; j++) { - num_points = cv->outlines.contours[j].num_points; - points = cv->outlines.contours[j].points; - if (ISSET(cv->flags, FIRST_END_OK)) { - num_points--; - points++; - } - if (ISSET(cv->flags, LAST_END_OK)) { - num_points--; - } - for (; num_points > 0; num_points--, points++) { - ptmp.x = points->x - h_width; - ptmp.y = points->y - h_height; - ZnRenderIcon(wi, cv->marker, cv->marker_color, &ptmp, True); - } - } - } + glCallList(item->gl_list); #endif } @@ -1668,7 +1737,8 @@ GetContours(Item item, if (cv->outlines.num_contours == 1) { POLY_CONTOUR1(poly, cv->outlines.contours[0].points, - cv->outlines.contours[0].num_points); + cv->outlines.contours[0].num_points, + cv->outlines.contours[0].cw); } else if (cv->outlines.num_contours > 1) { poly->num_contours = cv->outlines.num_contours; @@ -1728,7 +1798,7 @@ Coords(Item item, * is also legal, resulting in the contour being removed. */ if ((cv->shape.num_contours == 0) && (*num_pts)) { - POLY_CONTOUR1(&cv->shape, NULL, 0); + POLY_CONTOUR1(&cv->shape, NULL, 0, False); c = &cv->shape.contours[0]; } if (*num_pts) { @@ -1767,6 +1837,7 @@ Coords(Item item, Tcl_AppendResult(item->wi->interp, " coord index out of range", NULL); return ZN_ERROR; } + /*printf("--->%g@%g\n", (*pts)[0].x, (*pts)[0].y);*/ c->points[index] = (*pts)[0]; if (!c->controls && *controls && (*controls)[0]) { c->controls = ZnMalloc(c->num_points*sizeof(char)); @@ -1779,10 +1850,29 @@ Coords(Item item, else { if ((*controls)[0]) { /* Check if the edit is allowable, there should be - * no more than 2 consecutive control points . + * no more than 2 consecutive control points. The first + * point must not be a control and the last one can + * be one only if the curve is closed. */ - for (num_controls = 0, i = index-1; !c->controls[i]; i--, num_controls++); - for (i = index+1; !c->controls[i]; i++, num_controls++); + num_controls = 0; + if (!index) { + control_first: + Tcl_AppendResult(item->wi->interp, " the first point must not be a control", NULL); + return ZN_ERROR; + } + else if (index == c->num_points-1) { + if (ISCLEAR(cv->flags, CLOSED_BIT) && + (cv->shape.num_contours == 1)) { + control_last: + Tcl_AppendResult(item->wi->interp, " the last point must not be a control", NULL); + return ZN_ERROR; + } + } + else { + for (i = index-1; c->controls[i] && (i >= 0); i--, num_controls++); + } + for (i = index+1; c->controls[i] && (i < c->num_points); i++, num_controls++); + printf("******* num controls(): %d\n", num_controls); if (num_controls > 1) { control_err: Tcl_AppendResult(item->wi->interp, " too many consecutive control points in a curve", NULL); @@ -1838,7 +1928,7 @@ Coords(Item item, * created. */ if (cv->shape.num_contours == 0) { - POLY_CONTOUR1(&cv->shape, NULL, 0); + POLY_CONTOUR1(&cv->shape, NULL, 0, False); c = &cv->shape.contours[0]; } if (cmd == COORDS_ADD_LAST) { @@ -1852,11 +1942,25 @@ Coords(Item item, } if (*controls) { /* Check if the edit is allowable, there should be - * no more than 2 consecutive control points . + * no more than 2 consecutive control points. The first + * point must not be a control and the last one can + * be one only if the curve is closed. */ + if ((index == 0) && (*controls)[0]) { + goto control_first; + } + else if ((index == c->num_points-1) && (*controls)[*num_pts-1] && + ISCLEAR(cv->flags, CLOSED_BIT) && (cv->shape.num_contours == 1)) { + goto control_last; + } + + num_controls = 0; if (c->controls) { - for (num_controls = 0, i = index-1; !c->controls[i]; i--, num_controls++); + if (index) { + for (i = index-1; c->controls[i] && (i >= 0); i--, num_controls++); + } } + printf("******* num controls: %d\n", num_controls); for (i = 0; i < *num_pts; i++) { if (!(*controls)[i]) { num_controls = 0; @@ -1868,16 +1972,24 @@ Coords(Item item, } } } + printf("******* num controls(2): %d\n", num_controls); if (c->controls) { - for (i = index+1; !c->controls[i]; i++, num_controls++); + for (i = index; c->controls[i] && (i < c->num_points); i++, num_controls++); } + printf("******* num controls(3): %d\n", num_controls); if (num_controls > 2) { goto control_err; } } c->points = ZnRealloc(c->points, (c->num_points+*num_pts)*sizeof(ZnPoint)); if (*controls || c->controls) { - c->controls = ZnRealloc(c->controls, (c->num_points+*num_pts)*sizeof(char)); + if (c->controls) { + c->controls = ZnRealloc(c->controls, (c->num_points+*num_pts)*sizeof(char)); + } + else { + c->controls = ZnMalloc((c->num_points+*num_pts)*sizeof(char)); + memset(c->controls, 0, (c->num_points+*num_pts)*sizeof(char)); + } } /* * Make a hole if needed. -- cgit v1.1