1 /* $XFree86: xc/programs/Xserver/mi/mifillarc.c,v 3.4 1999/04/11 13:11:20 dawes Exp $ */
2 /************************************************************
4 Copyright 1989, 1998 The Open Group
8 The above copyright notice and this permission notice shall be included in
9 all copies or substantial portions of the Software.
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 Except as contained in this notice, the name of The Open Group shall not be
19 used in advertising or otherwise to promote the sale, use or other dealings
20 in this Software without prior written authorization from The Open Group.
22 Author: Bob Scheifler, MIT X Consortium
24 ********************************************************/
26 /* $TOG: mifillarc.c /main/20 1998/02/09 14:46:52 kaleb $ */
31 #include "mifillarc.h"
32 #include "gdkprivate-fb.h"
34 #define QUADRANT (90 * 64)
35 #define HALFCIRCLE (180 * 64)
36 #define QUADRANT3 (270 * 64)
39 #define M_PI 3.14159265358979323846
42 #define Dsin(d) sin((double)d*(M_PI/11520.0))
43 #define Dcos(d) cos((double)d*(M_PI/11520.0))
46 miFillArcSetup(arc, info)
48 register miFillArcRec *info;
50 info->y = arc->height >> 1;
51 info->dy = arc->height & 1;
52 info->yorg = arc->y + info->y;
53 info->dx = arc->width & 1;
54 info->xorg = arc->x + (arc->width >> 1) + info->dx;
55 info->dx = 1 - info->dx;
56 if (arc->width == arc->height)
58 /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
59 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
62 info->yk = info->y << 3;
73 info->e = - (info->y << 3);
78 /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
79 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
80 info->ym = (arc->width * arc->width) << 3;
81 info->xm = (arc->height * arc->height) << 3;
82 info->yk = info->y * info->ym;
84 info->yk -= info->ym >> 1;
88 info->e = - (info->xm >> 3);
94 info->xk = -(info->xm >> 1);
95 info->e = info->xk - info->yk;
101 miFillArcDSetup(arc, info)
103 register miFillArcDRec *info;
105 /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
106 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
107 info->y = arc->height >> 1;
108 info->dy = arc->height & 1;
109 info->yorg = arc->y + info->y;
110 info->dx = arc->width & 1;
111 info->xorg = arc->x + (arc->width >> 1) + info->dx;
112 info->dx = 1 - info->dx;
113 info->ym = ((double)arc->width) * (arc->width * 8);
114 info->xm = ((double)arc->height) * (arc->height * 8);
115 info->yk = info->y * info->ym;
117 info->yk -= info->ym / 2.0;
121 info->e = - (info->xm / 8.0);
126 info->yk += info->ym;
127 info->xk = -info->xm / 2.0;
128 info->e = info->xk - info->yk;
133 miGetArcEdge(arc, edge, k, top, left)
135 register miSliceEdgePtr edge;
139 register int xady, y;
141 y = arc->height >> 1;
142 if (!(arc->width & 1))
150 xady = k + y * edge->dx;
152 edge->x = - ((-xady) / edge->dy + 1);
154 edge->x = (xady - 1) / edge->dy;
155 edge->e = xady - edge->x * edge->dy;
156 if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
157 edge->e = edge->dy - edge->e + 1;
160 edge->x += arc->x + (arc->width >> 1);
164 edge->stepx = edge->dx / edge->dy;
165 edge->dx = edge->dx % edge->dy;
170 edge->stepx = - ((-edge->dx) / edge->dy);
171 edge->dx = (-edge->dx) % edge->dy;
175 edge->deltax = -edge->deltax;
176 edge->stepx = -edge->stepx;
181 miEllipseAngleToSlope (angle, width, height, dxp, dyp, d_dxp, d_dyp)
191 double d_dx, d_dy, scale;
192 gboolean negative_dx, negative_dy;
199 *d_dxp = width / 2.0;
208 *d_dyp = - height / 2.0;
215 *d_dxp = - width / 2.0;
224 *d_dyp = height / 2.0;
228 d_dx = Dcos(angle) * width;
229 d_dy = Dsin(angle) * height;
232 *d_dyp = - d_dy / 2.0;
249 dx = floor ((d_dx * 32768) / scale + 0.5);
253 dy = floor ((d_dy * 32768) / scale + 0.5);
262 miGetPieEdge(arc, angle, edge, top, left)
265 register miSliceEdgePtr edge;
271 miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
275 edge->x = left ? -65536 : 65536;
283 edge->x = arc->x + (arc->width >> 1);
284 if (left && (arc->width & 1))
286 else if (!left && !(arc->width & 1))
297 k = (arc->height & 1) ? dx : 0;
302 miGetArcEdge(arc, edge, k, top, left);
306 miFillArcSliceSetup(arc, slice, pGC)
308 register miArcSliceRec *slice;
311 register int angle1, angle2;
313 angle1 = arc->angle1;
317 angle1 += arc->angle2;
320 angle2 = angle1 + arc->angle2;
322 angle1 += FULLCIRCLE;
323 while (angle1 >= FULLCIRCLE)
324 angle1 -= FULLCIRCLE;
326 angle2 += FULLCIRCLE;
327 while (angle2 >= FULLCIRCLE)
328 angle2 -= FULLCIRCLE;
329 slice->min_top_y = 0;
330 slice->max_top_y = arc->height >> 1;
331 slice->min_bot_y = 1 - (arc->height & 1);
332 slice->max_bot_y = slice->max_top_y - 1;
333 slice->flip_top = FALSE;
334 slice->flip_bot = FALSE;
335 if (1 /* pGC->arcMode == ArcPieSlice */)
337 slice->edge1_top = (angle1 < HALFCIRCLE);
338 slice->edge2_top = (angle2 <= HALFCIRCLE);
339 if ((angle2 == 0) || (angle1 == HALFCIRCLE))
341 if (angle2 ? slice->edge2_top : slice->edge1_top)
342 slice->min_top_y = slice->min_bot_y;
344 slice->min_top_y = arc->height;
345 slice->min_bot_y = 0;
347 else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
349 slice->min_top_y = slice->min_bot_y;
350 if (angle1 ? slice->edge1_top : slice->edge2_top)
351 slice->min_bot_y = arc->height;
353 slice->min_bot_y = 0;
355 else if (slice->edge1_top == slice->edge2_top)
359 slice->flip_top = slice->edge1_top;
360 slice->flip_bot = !slice->edge1_top;
362 else if (slice->edge1_top)
364 slice->min_top_y = 1;
365 slice->min_bot_y = arc->height;
369 slice->min_bot_y = 0;
370 slice->min_top_y = arc->height;
373 miGetPieEdge(arc, angle1, &slice->edge1,
374 slice->edge1_top, !slice->edge1_top);
375 miGetPieEdge(arc, angle2, &slice->edge2,
376 slice->edge2_top, slice->edge2_top);
380 double w2, h2, x1, y1, x2, y2, dx, dy, scale;
381 int signdx, signdy, y, k;
382 gboolean isInt1 = TRUE, isInt2 = TRUE;
384 w2 = (double)arc->width / 2.0;
385 h2 = (double)arc->height / 2.0;
386 if ((angle1 == 0) || (angle1 == HALFCIRCLE))
388 x1 = angle1 ? -w2 : w2;
391 else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
394 y1 = (angle1 == QUADRANT) ? h2 : -h2;
399 x1 = Dcos(angle1) * w2;
400 y1 = Dsin(angle1) * h2;
402 if ((angle2 == 0) || (angle2 == HALFCIRCLE))
404 x2 = angle2 ? -w2 : w2;
407 else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
410 y2 = (angle2 == QUADRANT) ? h2 : -h2;
415 x2 = Dcos(angle2) * w2;
416 y2 = Dsin(angle2) * h2;
444 if (isInt1 && isInt2)
446 slice->edge1.dx = dx * 2;
447 slice->edge1.dy = dy * 2;
451 scale = (dx > dy) ? dx : dy;
452 slice->edge1.dx = floor((dx * 32768) / scale + .5);
453 slice->edge1.dy = floor((dy * 32768) / scale + .5);
455 if (!slice->edge1.dy)
462 slice->min_top_y = y;
463 slice->min_bot_y = arc->height;
467 slice->max_bot_y = -y - (arc->height & 1);
474 slice->max_top_y = y;
477 slice->min_top_y = arc->height;
478 slice->min_bot_y = -y - (arc->height & 1);
481 slice->edge1_top = TRUE;
482 slice->edge1.x = 65536;
483 slice->edge1.stepx = 0;
485 slice->edge1.dx = -1;
486 slice->edge2 = slice->edge1;
487 slice->edge2_top = FALSE;
489 else if (!slice->edge1.dx)
493 slice->edge1.x = ceil(x1);
494 slice->edge1_top = signdy < 0;
495 slice->edge1.x += arc->x + (arc->width >> 1);
496 slice->edge1.stepx = 0;
498 slice->edge1.dx = -1;
499 slice->edge2_top = !slice->edge1_top;
500 slice->edge2 = slice->edge1;
505 slice->edge1.dx = -slice->edge1.dx;
507 slice->edge1.dx = -slice->edge1.dx;
508 k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
509 slice->edge2.dx = slice->edge1.dx;
510 slice->edge2.dy = slice->edge1.dy;
511 slice->edge1_top = signdy < 0;
512 slice->edge2_top = !slice->edge1_top;
513 miGetArcEdge(arc, &slice->edge1, k,
514 slice->edge1_top, !slice->edge1_top);
515 miGetArcEdge(arc, &slice->edge2, k,
516 slice->edge2_top, slice->edge2_top);
526 if (miFillArcLower(slw)) \
529 pts->y = yorg + y + dy; \
535 miFillEllipseI(pDraw, pGC, arc)
540 register int x, y, e;
541 int yk, xk, ym, xm, dx, dy, xorg, yorg;
545 register GdkSpan* pts;
547 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * arc->height);
550 miFillArcSetup(arc, &info);
558 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
560 DEALLOCATE_LOCAL(points);
564 miFillEllipseD(pDraw, pGC, arc)
570 int xorg, yorg, dx, dy, slw;
571 double e, yk, xk, ym, xm;
574 register GdkSpan* pts;
576 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * arc->height);
579 miFillArcDSetup(arc, &info);
587 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
588 DEALLOCATE_LOCAL(points);
591 #define ADDSPAN(l,r) \
596 pts->width = r - l + 1; \
600 #define ADDSLICESPANS(flip) \
614 miFillArcSliceI(pDraw, pGC, arc)
619 int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
620 register int x, y, e;
625 register GdkSpan* pts;
627 miFillArcSetup(arc, &info);
628 miFillArcSliceSetup(arc, &slice, pGC);
631 if (slice.flip_top || slice.flip_bot)
632 slw += (arc->height >> 1) + 1;
633 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * slw);
640 MIARCSLICESTEP(slice.edge1);
641 MIARCSLICESTEP(slice.edge2);
642 if (miFillSliceUpper(slice))
645 MIARCSLICEUPPER(xl, xr, slice, slw);
646 ADDSLICESPANS(slice.flip_top);
648 if (miFillSliceLower(slice))
651 MIARCSLICELOWER(xl, xr, slice, slw);
652 ADDSLICESPANS(slice.flip_bot);
656 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
657 DEALLOCATE_LOCAL(points);
661 miFillArcSliceD(pDraw, pGC, arc)
667 int dx, dy, xorg, yorg, slw;
668 double e, yk, xk, ym, xm;
673 register GdkSpan* pts;
675 miFillArcDSetup(arc, &info);
676 miFillArcSliceSetup(arc, &slice, pGC);
679 if (slice.flip_top || slice.flip_bot)
680 slw += (arc->height >> 1) + 1;
681 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * slw);
688 MIARCSLICESTEP(slice.edge1);
689 MIARCSLICESTEP(slice.edge2);
690 if (miFillSliceUpper(slice))
693 MIARCSLICEUPPER(xl, xr, slice, slw);
694 ADDSLICESPANS(slice.flip_top);
696 if (miFillSliceLower(slice))
699 MIARCSLICELOWER(xl, xr, slice, slw);
700 ADDSLICESPANS(slice.flip_bot);
703 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
705 DEALLOCATE_LOCAL(points);
708 /* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
709 * Since we don't have to worry about overlapping segments, we can just
710 * fill each arc as it comes.
713 miPolyFillArc(pDraw, pGC, narcs, parcs)
722 for(i = narcs, arc = parcs; --i >= 0; arc++)
724 if (miFillArcEmpty(arc))
726 if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
728 if (miCanFillArc(arc))
729 miFillEllipseI(pDraw, pGC, arc);
731 miFillEllipseD(pDraw, pGC, arc);
735 if (miCanFillArc(arc))
736 miFillArcSliceI(pDraw, pGC, arc);
738 miFillArcSliceD(pDraw, pGC, arc);