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 $ */
30 #include "mifillarc.h"
31 #include "gdkprivate-fb.h"
33 #define QUADRANT (90 * 64)
34 #define HALFCIRCLE (180 * 64)
35 #define QUADRANT3 (270 * 64)
38 #define M_PI 3.14159265358979323846
41 #define Dsin(d) sin((double)d*(M_PI/11520.0))
42 #define Dcos(d) cos((double)d*(M_PI/11520.0))
45 miFillArcSetup(arc, info)
47 register miFillArcRec *info;
49 info->y = arc->height >> 1;
50 info->dy = arc->height & 1;
51 info->yorg = arc->y + info->y;
52 info->dx = arc->width & 1;
53 info->xorg = arc->x + (arc->width >> 1) + info->dx;
54 info->dx = 1 - info->dx;
55 if (arc->width == arc->height)
57 /* (2x - 2xorg)^2 = d^2 - (2y - 2yorg)^2 */
58 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
61 info->yk = info->y << 3;
72 info->e = - (info->y << 3);
77 /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
78 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
79 info->ym = (arc->width * arc->width) << 3;
80 info->xm = (arc->height * arc->height) << 3;
81 info->yk = info->y * info->ym;
83 info->yk -= info->ym >> 1;
87 info->e = - (info->xm >> 3);
93 info->xk = -(info->xm >> 1);
94 info->e = info->xk - info->yk;
100 miFillArcDSetup(arc, info)
102 register miFillArcDRec *info;
104 /* h^2 * (2x - 2xorg)^2 = w^2 * h^2 - w^2 * (2y - 2yorg)^2 */
105 /* even: xorg = yorg = 0 odd: xorg = .5, yorg = -.5 */
106 info->y = arc->height >> 1;
107 info->dy = arc->height & 1;
108 info->yorg = arc->y + info->y;
109 info->dx = arc->width & 1;
110 info->xorg = arc->x + (arc->width >> 1) + info->dx;
111 info->dx = 1 - info->dx;
112 info->ym = ((double)arc->width) * (arc->width * 8);
113 info->xm = ((double)arc->height) * (arc->height * 8);
114 info->yk = info->y * info->ym;
116 info->yk -= info->ym / 2.0;
120 info->e = - (info->xm / 8.0);
125 info->yk += info->ym;
126 info->xk = -info->xm / 2.0;
127 info->e = info->xk - info->yk;
132 miGetArcEdge(arc, edge, k, top, left)
134 register miSliceEdgePtr edge;
138 register int xady, y;
140 y = arc->height >> 1;
141 if (!(arc->width & 1))
149 xady = k + y * edge->dx;
151 edge->x = - ((-xady) / edge->dy + 1);
153 edge->x = (xady - 1) / edge->dy;
154 edge->e = xady - edge->x * edge->dy;
155 if ((top && (edge->dx < 0)) || (!top && (edge->dx > 0)))
156 edge->e = edge->dy - edge->e + 1;
159 edge->x += arc->x + (arc->width >> 1);
163 edge->stepx = edge->dx / edge->dy;
164 edge->dx = edge->dx % edge->dy;
169 edge->stepx = - ((-edge->dx) / edge->dy);
170 edge->dx = (-edge->dx) % edge->dy;
174 edge->deltax = -edge->deltax;
175 edge->stepx = -edge->stepx;
180 miEllipseAngleToSlope (angle, width, height, dxp, dyp, d_dxp, d_dyp)
190 double d_dx, d_dy, scale;
191 gboolean negative_dx, negative_dy;
198 *d_dxp = width / 2.0;
207 *d_dyp = - height / 2.0;
214 *d_dxp = - width / 2.0;
223 *d_dyp = height / 2.0;
227 d_dx = Dcos(angle) * width;
228 d_dy = Dsin(angle) * height;
231 *d_dyp = - d_dy / 2.0;
248 dx = floor ((d_dx * 32768) / scale + 0.5);
252 dy = floor ((d_dy * 32768) / scale + 0.5);
261 miGetPieEdge(arc, angle, edge, top, left)
264 register miSliceEdgePtr edge;
270 miEllipseAngleToSlope (angle, arc->width, arc->height, &dx, &dy, 0, 0);
274 edge->x = left ? -65536 : 65536;
282 edge->x = arc->x + (arc->width >> 1);
283 if (left && (arc->width & 1))
285 else if (!left && !(arc->width & 1))
296 k = (arc->height & 1) ? dx : 0;
301 miGetArcEdge(arc, edge, k, top, left);
305 miFillArcSliceSetup(arc, slice, pGC)
307 register miArcSliceRec *slice;
310 register int angle1, angle2;
312 angle1 = arc->angle1;
316 angle1 += arc->angle2;
319 angle2 = angle1 + arc->angle2;
321 angle1 += FULLCIRCLE;
322 while (angle1 >= FULLCIRCLE)
323 angle1 -= FULLCIRCLE;
325 angle2 += FULLCIRCLE;
326 while (angle2 >= FULLCIRCLE)
327 angle2 -= FULLCIRCLE;
328 slice->min_top_y = 0;
329 slice->max_top_y = arc->height >> 1;
330 slice->min_bot_y = 1 - (arc->height & 1);
331 slice->max_bot_y = slice->max_top_y - 1;
332 slice->flip_top = FALSE;
333 slice->flip_bot = FALSE;
334 if (1 /* pGC->arcMode == ArcPieSlice */)
336 slice->edge1_top = (angle1 < HALFCIRCLE);
337 slice->edge2_top = (angle2 <= HALFCIRCLE);
338 if ((angle2 == 0) || (angle1 == HALFCIRCLE))
340 if (angle2 ? slice->edge2_top : slice->edge1_top)
341 slice->min_top_y = slice->min_bot_y;
343 slice->min_top_y = arc->height;
344 slice->min_bot_y = 0;
346 else if ((angle1 == 0) || (angle2 == HALFCIRCLE))
348 slice->min_top_y = slice->min_bot_y;
349 if (angle1 ? slice->edge1_top : slice->edge2_top)
350 slice->min_bot_y = arc->height;
352 slice->min_bot_y = 0;
354 else if (slice->edge1_top == slice->edge2_top)
358 slice->flip_top = slice->edge1_top;
359 slice->flip_bot = !slice->edge1_top;
361 else if (slice->edge1_top)
363 slice->min_top_y = 1;
364 slice->min_bot_y = arc->height;
368 slice->min_bot_y = 0;
369 slice->min_top_y = arc->height;
372 miGetPieEdge(arc, angle1, &slice->edge1,
373 slice->edge1_top, !slice->edge1_top);
374 miGetPieEdge(arc, angle2, &slice->edge2,
375 slice->edge2_top, slice->edge2_top);
379 double w2, h2, x1, y1, x2, y2, dx, dy, scale;
380 int signdx, signdy, y, k;
381 gboolean isInt1 = TRUE, isInt2 = TRUE;
383 w2 = (double)arc->width / 2.0;
384 h2 = (double)arc->height / 2.0;
385 if ((angle1 == 0) || (angle1 == HALFCIRCLE))
387 x1 = angle1 ? -w2 : w2;
390 else if ((angle1 == QUADRANT) || (angle1 == QUADRANT3))
393 y1 = (angle1 == QUADRANT) ? h2 : -h2;
398 x1 = Dcos(angle1) * w2;
399 y1 = Dsin(angle1) * h2;
401 if ((angle2 == 0) || (angle2 == HALFCIRCLE))
403 x2 = angle2 ? -w2 : w2;
406 else if ((angle2 == QUADRANT) || (angle2 == QUADRANT3))
409 y2 = (angle2 == QUADRANT) ? h2 : -h2;
414 x2 = Dcos(angle2) * w2;
415 y2 = Dsin(angle2) * h2;
443 if (isInt1 && isInt2)
445 slice->edge1.dx = dx * 2;
446 slice->edge1.dy = dy * 2;
450 scale = (dx > dy) ? dx : dy;
451 slice->edge1.dx = floor((dx * 32768) / scale + .5);
452 slice->edge1.dy = floor((dy * 32768) / scale + .5);
454 if (!slice->edge1.dy)
461 slice->min_top_y = y;
462 slice->min_bot_y = arc->height;
466 slice->max_bot_y = -y - (arc->height & 1);
473 slice->max_top_y = y;
476 slice->min_top_y = arc->height;
477 slice->min_bot_y = -y - (arc->height & 1);
480 slice->edge1_top = TRUE;
481 slice->edge1.x = 65536;
482 slice->edge1.stepx = 0;
484 slice->edge1.dx = -1;
485 slice->edge2 = slice->edge1;
486 slice->edge2_top = FALSE;
488 else if (!slice->edge1.dx)
492 slice->edge1.x = ceil(x1);
493 slice->edge1_top = signdy < 0;
494 slice->edge1.x += arc->x + (arc->width >> 1);
495 slice->edge1.stepx = 0;
497 slice->edge1.dx = -1;
498 slice->edge2_top = !slice->edge1_top;
499 slice->edge2 = slice->edge1;
504 slice->edge1.dx = -slice->edge1.dx;
506 slice->edge1.dx = -slice->edge1.dx;
507 k = ceil(((x1 + x2) * slice->edge1.dy - (y1 + y2) * slice->edge1.dx) / 2.0);
508 slice->edge2.dx = slice->edge1.dx;
509 slice->edge2.dy = slice->edge1.dy;
510 slice->edge1_top = signdy < 0;
511 slice->edge2_top = !slice->edge1_top;
512 miGetArcEdge(arc, &slice->edge1, k,
513 slice->edge1_top, !slice->edge1_top);
514 miGetArcEdge(arc, &slice->edge2, k,
515 slice->edge2_top, slice->edge2_top);
525 if (miFillArcLower(slw)) \
528 pts->y = yorg + y + dy; \
534 miFillEllipseI(pDraw, pGC, arc)
539 register int x, y, e;
540 int yk, xk, ym, xm, dx, dy, xorg, yorg;
544 register GdkSpan* pts;
546 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * arc->height);
549 miFillArcSetup(arc, &info);
557 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
559 DEALLOCATE_LOCAL(points);
563 miFillEllipseD(pDraw, pGC, arc)
569 int xorg, yorg, dx, dy, slw;
570 double e, yk, xk, ym, xm;
573 register GdkSpan* pts;
575 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * arc->height);
578 miFillArcDSetup(arc, &info);
586 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
587 DEALLOCATE_LOCAL(points);
590 #define ADDSPAN(l,r) \
595 pts->width = r - l + 1; \
599 #define ADDSLICESPANS(flip) \
613 miFillArcSliceI(pDraw, pGC, arc)
618 int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
619 register int x, y, e;
624 register GdkSpan* pts;
626 miFillArcSetup(arc, &info);
627 miFillArcSliceSetup(arc, &slice, pGC);
630 if (slice.flip_top || slice.flip_bot)
631 slw += (arc->height >> 1) + 1;
632 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * slw);
639 MIARCSLICESTEP(slice.edge1);
640 MIARCSLICESTEP(slice.edge2);
641 if (miFillSliceUpper(slice))
644 MIARCSLICEUPPER(xl, xr, slice, slw);
645 ADDSLICESPANS(slice.flip_top);
647 if (miFillSliceLower(slice))
650 MIARCSLICELOWER(xl, xr, slice, slw);
651 ADDSLICESPANS(slice.flip_bot);
655 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
656 DEALLOCATE_LOCAL(points);
660 miFillArcSliceD(pDraw, pGC, arc)
666 int dx, dy, xorg, yorg, slw;
667 double e, yk, xk, ym, xm;
672 register GdkSpan* pts;
674 miFillArcDSetup(arc, &info);
675 miFillArcSliceSetup(arc, &slice, pGC);
678 if (slice.flip_top || slice.flip_bot)
679 slw += (arc->height >> 1) + 1;
680 points = (GdkSpan*)ALLOCATE_LOCAL(sizeof(GdkSpan) * slw);
687 MIARCSLICESTEP(slice.edge1);
688 MIARCSLICESTEP(slice.edge2);
689 if (miFillSliceUpper(slice))
692 MIARCSLICEUPPER(xl, xr, slice, slw);
693 ADDSLICESPANS(slice.flip_top);
695 if (miFillSliceLower(slice))
698 MIARCSLICELOWER(xl, xr, slice, slw);
699 ADDSLICESPANS(slice.flip_bot);
702 gdk_fb_fill_spans(pDraw, pGC, points, pts - points, FALSE);
704 DEALLOCATE_LOCAL(points);
707 /* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
708 * Since we don't have to worry about overlapping segments, we can just
709 * fill each arc as it comes.
712 miPolyFillArc(pDraw, pGC, narcs, parcs)
721 for(i = narcs, arc = parcs; --i >= 0; arc++)
723 if (miFillArcEmpty(arc))
725 if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
727 if (miCanFillArc(arc))
728 miFillEllipseI(pDraw, pGC, arc);
730 miFillEllipseD(pDraw, pGC, arc);
734 if (miCanFillArc(arc))
735 miFillArcSliceI(pDraw, pGC, arc);
737 miFillArcSliceD(pDraw, pGC, arc);