/* $XFree86: xc/programs/Xserver/hw/xfree86/xaa/xf86fpoly.c,v 3.0.2.2 1998/02/21 06:07:09 robin Exp $ */ /* * Copyright 1996 The XFree86 Project * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * HARM HANEMAAYER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Written by Harm Hanemaayer (H.Hanemaayer@inter.nl.net). */ /* * Filled solid polygons, based on cfbply1rct.c. * * Fill polygons using calls to low-level span fill. Because the math * between spans can be done concurrently with the drawing of the span * with a graphics coprocessor operation, this is faster than just * using miFillPoly, which first calculates all the spans and then * calls FillSpans. * * The function accepts one clipping rectangle. */ #include "X.h" #include "Xprotostr.h" #include "miscstruct.h" #include "gcstruct.h" #include "pixmapstr.h" #include "scrnintstr.h" #include "mi.h" #define PSZ 8 /* PSZ doesn't matter */ #include "cfb.h" #include "xf86.h" #include "xf86xaa.h" #define Setup(c,x,vertex,dx,dy,e,sign,step,DX) {\ x = intToX(vertex); \ if (dy = intToY(c) - y) { \ DX = dx = intToX(c) - x; \ step = 0; \ if (dx >= 0) \ { \ e = 0; \ sign = 1; \ if (dx >= dy) {\ step = dx / dy; \ dx %= dy; \ } \ } \ else \ { \ e = 1 - dy; \ sign = -1; \ dx = -dx; \ if (dx >= dy) { \ step = - (dx / dy); \ dx %= dy; \ } \ } \ } \ x += origin; \ vertex = c; \ } #define Step(x,dx,dy,e,sign,step) {\ x += step; \ if ((e += dx) > 0) \ { \ x += sign; \ e -= dy; \ } \ } #define FixError(x, dx, dy, e, sign, step, h) { \ e += (h) * dx; \ x += (h) * step; \ if(e > 0) { \ x += e * sign/dy; \ e %= dy; \ if(e) { \ x += sign; \ e -= dy; \ } \ } \ } void xf86FillPolygonSolid1Rect(pDrawable, pGC, shape, mode, count, ptsIn) DrawablePtr pDrawable; GCPtr pGC; int shape; int mode; int count; DDXPointPtr ptsIn; { cfbPrivGCPtr devPriv; int maxy; int origin; register int vertex1, vertex2; int c; BoxPtr extents; int clip; int y; int *vertex1p, *vertex2p; int *endp; int x1, x2; int dx1, dx2; int dy1, dy2; int e1, e2; int step1, step2; int sign1, sign2; int h; int yoffset; int DX1, DX2; /* for trapezoid fills */ if (mode == CoordModePrevious) { register DDXPointPtr ppt = ptsIn + 1; for (c = 1; c < count; c++, ppt++) { ppt->x += (ppt-1)->x; ppt->y += (ppt-1)->y; } mode = CoordModeOrigin; } devPriv = cfbGetGCPrivate(pGC); if (REGION_NUM_RECTS(devPriv->pCompositeClip) != 1) { miFillPolygon (pDrawable, pGC, shape, mode, count, ptsIn); return; } origin = *((int *) &pDrawable->x); origin -= (origin & 0x8000) << 1; extents = &devPriv->pCompositeClip->extents; vertex1 = *((int *) &extents->x1) - origin; vertex2 = *((int *) &extents->x2) - origin - 0x00010001; clip = 0; y = 32767; maxy = 0; vertex2p = (int *) ptsIn; endp = vertex2p + count; if (shape == Convex) { while (count--) { c = *vertex2p; clip |= (c - vertex1) | (vertex2 - c); c = intToY(c); if (c < y) { y = c; vertex1p = vertex2p; } vertex2p++; if (c > maxy) maxy = c; } } else { int yFlip = 0; dx1 = 1; x2 = -1; x1 = -1; while (count--) { c = *vertex2p; clip |= (c - vertex1) | (vertex2 - c); c = intToY(c); if (c < y) { y = c; vertex1p = vertex2p; } vertex2p++; if (c > maxy) maxy = c; if (c == x1) continue; if (dx1 > 0) { if (x2 < 0) x2 = c; else dx2 = dx1 = (c - x1) >> 31; } else if ((c - x1) >> 31 != dx1) { dx1 = ~dx1; yFlip++; } x1 = c; } x1 = (x2 - c) >> 31; if (x1 != dx1) yFlip++; if (x1 != dx2) yFlip++; if (yFlip != 2) clip = 0x8000; } if (y == maxy) return; if (clip & 0x80008000) { miFillPolygon (pDrawable, pGC, shape, mode, vertex2p - (int *) ptsIn, ptsIn); return; } xf86AccelInfoRec.SetupForFillRectSolid(pGC->fgPixel, pGC->alu, pGC->planemask); origin = intToX(origin); vertex2p = vertex1p; vertex2 = vertex1 = *vertex2p++; if (vertex2p == endp) vertex2p = (int *) ptsIn; yoffset = pDrawable->y; for (;;) { if (y == intToY(vertex1)) { do { if (vertex1p == (int *) ptsIn) vertex1p = endp; c = *--vertex1p; Setup (c,x1,vertex1,dx1,dy1,e1,sign1,step1,DX1) } while (y >= intToY(vertex1)); h = dy1; } else { Step(x1,dx1,dy1,e1,sign1,step1) h = intToY(vertex1) - y; } if (y == intToY(vertex2)) { do { c = *vertex2p++; if (vertex2p == endp) vertex2p = (int *) ptsIn; Setup (c,x2,vertex2,dx2,dy2,e2,sign2,step2,DX2) } while (y >= intToY(vertex2)); if (dy2 < h) h = dy2; } else { Step(x2,dx2,dy2,e2,sign2,step2) if ((c = (intToY(vertex2) - y)) < h) h = c; } /* fill spans for this segment */ if(DX1 | DX2) { if(xf86AccelInfoRec.SubsequentFillTrapezoidSolid && (h > 6)) { if(x1 == x2) { while(x1 == x2) { y++; if (!--h) break; Step(x1,dx1,dy1,e1,sign1,step1) Step(x2,dx2,dy2,e2,sign2,step2) } if(y == maxy) break; if(!h) continue; } if(x1 < x2) xf86AccelInfoRec.SubsequentFillTrapezoidSolid(y + yoffset, h, x1, DX1, dy1, e1, x2 - 1, DX2, dy2, e2); else xf86AccelInfoRec.SubsequentFillTrapezoidSolid(y + yoffset, h, x2, DX2, dy2, e2, x1 - 1, DX1, dy1, e1); y += h; if(--h) { FixError(x1,dx1,dy1,e1,sign1,step1,h); FixError(x2,dx2,dy2,e2,sign2,step2,h); h = 0; } } else { for (;;) { if (x2 > x1) xf86AccelInfoRec.SubsequentFillRectSolid( x1, y + yoffset, x2 - x1, 1); else if (x1 > x2) xf86AccelInfoRec.SubsequentFillRectSolid( x2, y + yoffset, x1 - x2, 1); y++; if (!--h) break; Step(x1,dx1,dy1,e1,sign1,step1) Step(x2,dx2,dy2,e2,sign2,step2) } } } else { if (x2 > x1) xf86AccelInfoRec.SubsequentFillRectSolid( x1, y + yoffset, x2 - x1, h); else if (x1 > x2) xf86AccelInfoRec.SubsequentFillRectSolid( x2, y + yoffset, x1 - x2, h); y += h; h = 0; } if (y == maxy) break; } if (xf86AccelInfoRec.Flags & BACKGROUND_OPERATIONS) xf86AccelInfoRec.Sync(); }