summaryrefslogtreecommitdiff
path: root/src/tga_line.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tga_line.c')
-rw-r--r--src/tga_line.c629
1 files changed, 629 insertions, 0 deletions
diff --git a/src/tga_line.c b/src/tga_line.c
new file mode 100644
index 0000000..b1a510c
--- /dev/null
+++ b/src/tga_line.c
@@ -0,0 +1,629 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/tga/tga_line.c,v 1.2 1999/12/16 02:26:30 robin Exp $ */
+
+/*
+ * Copyright 1999 by Matthew Grossman, Seattle, USA.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Matthew
+ * Grossman not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Matthew Grossman makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * MATTHEW GROSSMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL MATTHEW GROSSMAN BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Author: Matthew Grossman, mattg@oz.net
+ *
+ */
+
+/* tga_line.c */
+/* accelerated solid and dashed lines */
+/* adapted from xaa/xaaLine.c */
+
+#include "X.h"
+#include "misc.h"
+#include "xf86.h"
+#include "xf86_ansic.h"
+#include "xf86_OSproc.h"
+
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "miline.h"
+#include "xf86str.h"
+#include "xaa.h"
+#include "xaalocal.h"
+
+/* #include "tga.h" */
+#include "tga_regs.h"
+
+/* line functions */
+extern void
+TGASetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop,
+ unsigned int planemask);
+extern void
+TGASubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len,
+ int dir);
+extern void
+TGASubsequentSolidLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2,
+ int octant, int flags);
+extern void
+TGASetupForClippedLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2,
+ int octant);
+extern void
+TGASubsequentClippedSolidLine(ScrnInfoPtr pScrn, int x1, int y1, int len,
+ int err);
+
+extern void
+TGASetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop,
+ unsigned int planemask, int length,
+ unsigned char *pattern);
+extern void
+TGASubsequentDashedLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2,
+ int octant, int flags, int phase);
+extern void
+TGASubsequentClippedDashedLine(ScrnInfoPtr pScrn, int x1, int y1, int len,
+ int err, int phase);
+
+
+extern void
+TGASync(ScrnInfoPtr pScrn);
+
+void TGAPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg);
+void TGAPolyLines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit);
+void TGAPolySegmentDashed(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+ xSegment *pSeg);
+void TGAPolyLinesDashed(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+ DDXPointPtr pptInit);
+
+
+void
+#ifdef POLYSEGMENT
+TGAPolySegment(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nseg,
+ xSegment *pSeg
+#else
+ TGAPolyLines(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int mode, /* Origin or Previous */
+ int npt, /* number of points */
+ DDXPointPtr pptInit
+#endif
+ ){
+ XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
+ BoxPtr pboxInit = REGION_RECTS(pGC->pCompositeClip);
+ int nboxInit = REGION_NUM_RECTS(pGC->pCompositeClip);
+ unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
+ int xorg = pDrawable->x;
+ int yorg = pDrawable->y;
+ int nbox;
+ BoxPtr pbox;
+#ifndef POLYSEGMENT
+ DDXPointPtr ppt;
+#endif
+ int x1, x2, y1, y2, tmp, len;
+
+#ifdef POLYSEGMENT
+/* ErrorF("TGAPolySegment called!\n"); */
+#else
+/* ErrorF("TGAPolyLines called\n"); */
+#endif
+
+ if(!nboxInit)
+ return;
+ /****************/
+ /* TGA FUNCTION */
+ /****************/
+ TGASetupForSolidLine(infoRec->pScrn, pGC->fgPixel, pGC->alu,
+ pGC->planemask);
+
+#ifdef POLYSEGMENT
+ while (nseg--)
+#else
+ ppt = pptInit;
+ x2 = ppt->x + xorg;
+ y2 = ppt->y + yorg;
+ while(--npt)
+#endif
+ {
+ nbox = nboxInit;
+ pbox = pboxInit;
+
+#ifdef POLYSEGMENT
+ x1 = pSeg->x1 + xorg;
+ y1 = pSeg->y1 + yorg;
+ x2 = pSeg->x2 + xorg;
+ y2 = pSeg->y2 + yorg;
+ pSeg++;
+#else
+ x1 = x2;
+ y1 = y2;
+ ++ppt;
+ if (mode == CoordModePrevious) {
+ xorg = x1;
+ yorg = y1;
+ }
+ x2 = ppt->x + xorg;
+ y2 = ppt->y + yorg;
+#endif
+
+ if (x1 == x2) { /* vertical line */
+ /* make the line go top to bottom of screen, keeping
+ endpoint semantics
+ */
+ if (y1 > y2) {
+ tmp = y2;
+ y2 = y1 + 1;
+ y1 = tmp + 1;
+#ifdef POLYSEGMENT
+ if (pGC->capStyle != CapNotLast) y1--;
+#endif
+ }
+#ifdef POLYSEGMENT
+ else if (pGC->capStyle != CapNotLast) y2++;
+#endif
+ /* get to first band that might contain part of line */
+ while(nbox && (pbox->y2 <= y1)) {
+ pbox++;
+ nbox--;
+ }
+
+ /* stop when lower edge of box is beyond end of line */
+ while(nbox && (y2 >= pbox->y1)) {
+ if ((x1 >= pbox->x1) && (x1 < pbox->x2)) {
+ tmp = max(y1, pbox->y1);
+ len = min(y2, pbox->y2) - tmp;
+ if (len)
+ TGASubsequentSolidHorVertLine(infoRec->pScrn, x1, tmp,
+ len, DEGREES_270);
+ }
+ nbox--;
+ pbox++;
+ }
+#ifndef POLYSEGMENT
+ y2 = ppt->y + yorg;
+#endif
+ } else if (y1 == y2) { /* horizontal line */
+ /* force line from left to right, keeping endpoint semantics */
+ if (x1 > x2) {
+ tmp = x2;
+ x2 = x1 + 1;
+ x1 = tmp + 1;
+#ifdef POLYSEGMENT
+ if (pGC->capStyle != CapNotLast) x1--;
+#endif
+ }
+#ifdef POLYSEGMENT
+ else if (pGC->capStyle != CapNotLast) x2++;
+#endif
+
+ /* find the correct band */
+ while(nbox && (pbox->y2 <= y1)) {
+ pbox++;
+ nbox--;
+ }
+
+ /* try to draw the line, if we haven't gone beyond it */
+ if (nbox && (pbox->y1 <= y1)) {
+ int orig_y = pbox->y1;
+ /* when we leave this band, we're done */
+ while(nbox && (orig_y == pbox->y1)) {
+ if (pbox->x2 <= x1) {
+ /* skip boxes until one might contain start point */
+ nbox--;
+ pbox++;
+ continue;
+ }
+
+ /* stop if left of box is beyond right of line */
+ if (pbox->x1 >= x2) {
+ nbox = 0;
+ break;
+ }
+
+ tmp = max(x1, pbox->x1);
+ len = min(x2, pbox->x2) - tmp;
+ if (len)
+ TGASubsequentSolidHorVertLine(infoRec->pScrn, tmp,
+ y1, len, DEGREES_0);
+ nbox--;
+ pbox++;
+ }
+ }
+#ifndef POLYSEGMENT
+ x2 = ppt->x + xorg;
+#endif
+ } else{ /* sloped line */
+ unsigned int oc1, oc2;
+ int dmin, dmaj, e, octant;
+
+
+ if((dmaj = x2 - x1) < 0) {
+ dmaj = -dmaj;
+ octant = XDECREASING;
+ } else octant = 0;
+
+ if((dmin = y2 - y1) < 0) {
+ dmin = -dmin;
+ octant |= YDECREASING;
+ }
+
+ if(dmin >= dmaj){
+ tmp = dmin; dmin = dmaj; dmaj = tmp;
+ octant |= YMAJOR;
+ }
+
+ e = -dmaj - ((bias >> octant) & 1);
+ len = dmaj;
+ dmin *= 2;
+ dmaj *= 2;
+
+
+ while(nbox--) {
+ oc1 = oc2 = 0;
+ OUTCODES(oc1, x1, y1, pbox);
+ OUTCODES(oc2, x2, y2, pbox);
+ if (!(oc1 | oc2)) { /* unclipped */
+ TGASubsequentSolidLine(infoRec->pScrn, x1, y1, x2, y2,
+ octant,
+#ifdef POLYSEGMENT
+ (pGC->capStyle != CapNotLast) ? 0 :
+#endif
+ OMIT_LAST
+ );
+ break;
+ } else if (oc1 & oc2) { /* completely clipped */
+ pbox++;
+
+ } else { /* partially clipped */
+ int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
+ int clip1 = 0, clip2 = 0;
+ int err, adx, ady;
+
+ if(octant & YMAJOR) {
+ ady = dmaj /= 2;
+ adx = dmin /= 2;
+ } else {
+ ady = dmin /= 2;
+ adx = dmaj /= 2;
+ }
+
+ if (miZeroClipLine(pbox->x1, pbox->y1,
+ pbox->x2 - 1, pbox->y2 - 1,
+ &new_x1, &new_y1, &new_x2, &new_y2,
+ adx, ady, &clip1, &clip2,
+ octant, bias, oc1, oc2) == -1)
+ {
+ pbox++;
+ continue;
+ }
+
+ if (octant & YMAJOR)
+ len = abs(new_y2 - new_y1);
+ else
+ len = abs(new_x2 - new_x1);
+#ifdef POLYSEGMENT
+ if (clip2 != 0 || pGC->capStyle != CapNotLast)
+ len++;
+#else
+ len += (clip2 != 0);
+#endif
+ if (len) { /* we have a real line */
+ int abserr, clipdx, clipdy;
+
+ /* unwind bresenham error term to first point */
+ if (clip1) {
+ clipdx = abs(new_x1 - x1);
+ clipdy = abs(new_y1 - y1);
+
+ if (octant & YMAJOR)
+ err = e + clipdy*dmin - clipdx*dmaj;
+ else
+ err = e + clipdx*dmin - clipdy*dmaj;
+ } else
+ err = e;
+
+#define range infoRec->SolidBresenhamLineErrorTermBits
+ abserr = abs(err);
+ while((abserr & range) ||
+ (dmaj & range) ||
+ (dmin & range)) {
+ dmin /= 2;
+ dmaj /= 2;
+ abserr /= 2;
+ err /= 2;
+ }
+ TGASetupForClippedLine(infoRec->pScrn, x1, y1, x2,
+ y2, octant);
+ TGASubsequentClippedSolidLine(infoRec->pScrn,
+ new_x1, new_y1, len,
+ err);
+
+
+ }
+ pbox++;
+ }
+ } /* while (nbox--) */
+ } /* sloped line */
+ } /* while (nline--) */
+
+#ifndef POLYSEGMENT
+ /* paint the last point if the end style isn't CapNotLast.
+ (Assume that a projecting, butt, or round cap that is one
+ pixel wide is the same as the single pixel of the endpoint.)
+ */
+
+ if ((pGC->capStyle != CapNotLast) &&
+ ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
+ (ppt->y + yorg != pptInit->y + pDrawable->y) ||
+ (ppt == pptInit + 1)))
+ {
+ nbox = nboxInit;
+ pbox = pboxInit;
+ while (nbox--)
+ {
+ if ((x2 >= pbox->x1) && (y2 >= pbox->y1) &&
+ (x2 < pbox->x2) && (y2 < pbox->y2))
+ {
+ TGASubsequentSolidHorVertLine(infoRec->pScrn, x2, y2, 1,
+ DEGREES_0);
+ break;
+ }
+ else
+ pbox++;
+ }
+ }
+#endif
+
+ TGASync(infoRec->pScrn);
+ return;
+}
+
+#undef range
+
+ void
+#ifdef POLYSEGMENT
+ TGAPolySegmentDashed(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nseg,
+ xSegment *pSeg
+#else
+ TGAPolyLinesDashed(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int mode, /* Origin or Previous */
+ int npt, /* number of points */
+ DDXPointPtr pptInit
+#endif
+ ){
+ XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
+ XAAGCPtr pGCPriv = (XAAGCPtr) (pGC)->devPrivates[XAAGCIndex].ptr;
+ BoxPtr pboxInit = REGION_RECTS(pGC->pCompositeClip);
+ int nboxInit = REGION_NUM_RECTS(pGC->pCompositeClip);
+ unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
+ int xorg = pDrawable->x;
+ int yorg = pDrawable->y;
+ int nbox;
+ BoxPtr pbox;
+#ifndef POLYSEGMENT
+ DDXPointPtr ppt;
+#endif
+ unsigned int oc1, oc2;
+ int dmin, dmaj, e, octant;
+ int x1, x2, y1, y2, tmp, len, offset;
+ int PatternLength, PatternOffset;
+
+#ifdef POLYSEGMENT
+/* ErrorF("TGAPolySegmentDashed called\n"); */
+#else
+/* ErrorF("TGAPolyLinesDashed called\n"); */
+#endif
+
+ if(!nboxInit)
+ return;
+
+ PatternLength = pGCPriv->DashLength;
+ PatternOffset = pGC->dashOffset % PatternLength;
+
+ TGASetupForDashedLine(infoRec->pScrn, pGC->fgPixel,
+ (pGC->lineStyle == LineDoubleDash) ? pGC->bgPixel : -1,
+ pGC->alu, pGC->planemask, PatternLength, pGCPriv->DashPattern);
+
+
+#ifdef POLYSEGMENT
+ while (nseg--)
+#else
+ ppt = pptInit;
+ x2 = ppt->x + xorg;
+ y2 = ppt->y + yorg;
+ while(--npt)
+#endif
+ {
+ nbox = nboxInit;
+ pbox = pboxInit;
+
+#ifdef POLYSEGMENT
+ x1 = pSeg->x1 + xorg;
+ y1 = pSeg->y1 + yorg;
+ x2 = pSeg->x2 + xorg;
+ y2 = pSeg->y2 + yorg;
+ pSeg++;
+#else
+ x1 = x2;
+ y1 = y2;
+ ++ppt;
+ if (mode == CoordModePrevious) {
+ xorg = x1;
+ yorg = y1;
+ }
+ x2 = ppt->x + xorg;
+ y2 = ppt->y + yorg;
+#endif
+
+
+
+ if((dmaj = x2 - x1) < 0) {
+ dmaj = -dmaj;
+ octant = XDECREASING;
+ } else octant = 0;
+
+ if((dmin = y2 - y1) < 0) {
+ dmin = -dmin;
+ octant |= YDECREASING;
+ }
+
+ if(dmin >= dmaj){
+ tmp = dmin; dmin = dmaj; dmaj = tmp;
+ octant |= YMAJOR;
+ }
+
+ e = -dmaj - ((bias >> octant) & 1);
+ len = dmaj;
+ dmin <<= 1;
+ dmaj <<= 1;
+
+
+ while(nbox--) {
+ oc1 = oc2 = 0;
+ OUTCODES(oc1, x1, y1, pbox);
+ OUTCODES(oc2, x2, y2, pbox);
+ if (!(oc1 | oc2)) { /* unclipped */
+ TGASubsequentDashedLine(infoRec->pScrn, x1, y1, x2, y2,
+ octant,
+#ifdef POLYSEGMENT
+ (pGC->capStyle != CapNotLast) ? 0 :
+#endif
+ OMIT_LAST, PatternOffset);
+ break;
+ } else if (oc1 & oc2) { /* completely clipped */
+ pbox++;
+ } else { /* partially clipped */
+ int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
+ int clip1 = 0, clip2 = 0;
+ int err, adx, ady;
+
+ if(octant & YMAJOR) {
+ ady = dmaj >> 1;
+ adx = dmin >> 1;
+ } else {
+ ady = dmin >> 1;
+ adx = dmaj >> 1;
+ }
+
+ if (miZeroClipLine(pbox->x1, pbox->y1,
+ pbox->x2 - 1, pbox->y2 - 1,
+ &new_x1, &new_y1, &new_x2, &new_y2,
+ adx, ady, &clip1, &clip2,
+ octant, bias, oc1, oc2) == -1)
+ {
+ pbox++;
+ continue;
+ }
+
+ if (octant & YMAJOR)
+ len = abs(new_y2 - new_y1);
+ else
+ len = abs(new_x2 - new_x1);
+#ifdef POLYSEGMENT
+ if (clip2 != 0 || pGC->capStyle != CapNotLast)
+ len++;
+#else
+ len += (clip2 != 0);
+#endif
+ if (len) {
+ int abserr, clipdx, clipdy;
+ /* unwind bresenham error term to first point */
+ if (clip1) {
+ clipdx = abs(new_x1 - x1);
+ clipdy = abs(new_y1 - y1);
+
+ if (octant & YMAJOR)
+ err = e + clipdy*dmin - clipdx*dmaj;
+ else
+ err = e + clipdx*dmin - clipdy*dmaj;
+ } else
+ err = e;
+
+#define range infoRec->DashedBresenhamLineErrorTermBits
+ abserr = abs(err);
+ while((abserr & range) ||
+ (dmaj & range) ||
+ (dmin & range)) {
+ dmin >>= 1;
+ dmaj >>= 1;
+ abserr >>= 1;
+ err /= 2;
+ }
+
+ if(octant & YMAJOR)
+ offset = abs(new_y1 - y1);
+ else
+ offset = abs(new_x1 - x1);
+
+ offset += PatternOffset;
+ offset %= PatternLength;
+
+ TGASetupForClippedLine(infoRec->pScrn, x1, x2, y1, y2,
+ octant);
+ TGASubsequentClippedDashedLine(infoRec->pScrn, new_x1,
+ new_y1, len, err,
+ PatternOffset);
+ }
+ pbox++;
+ }
+ } /* while (nbox--) */
+#ifndef POLYSEGMENT
+ len = abs(y2 - y1);
+ tmp = abs(x2 - x1);
+ PatternOffset += (len > tmp) ? len : tmp;
+ PatternOffset %= PatternLength;
+#endif
+ } /* while (nline--) */
+
+#ifndef POLYSEGMENT
+ /* paint the last point if the end style isn't CapNotLast.
+ (Assume that a projecting, butt, or round cap that is one
+ pixel wide is the same as the single pixel of the endpoint.)
+ */
+
+ if ((pGC->capStyle != CapNotLast) &&
+ ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
+ (ppt->y + yorg != pptInit->y + pDrawable->y) ||
+ (ppt == pptInit + 1)))
+ {
+ nbox = nboxInit;
+ pbox = pboxInit;
+ while (nbox--) {
+ if ((x2 >= pbox->x1) && (y2 >= pbox->y1) &&
+ (x2 < pbox->x2) && (y2 < pbox->y2))
+ {
+ TGASubsequentDashedLine(infoRec->pScrn, x2, y2, x2, y2, 0, 0,
+ PatternOffset);
+ break;
+ } else
+ pbox++;
+ }
+ }
+#endif
+
+ TGASync(infoRec->pScrn);
+ return;
+}
+
+