tga_line.c revision 3a56a767
1/*
2 * Copyright 1999 by Matthew Grossman, Seattle, USA.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of Matthew
9 * Grossman not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior
11 * permission.  Matthew Grossman makes no representations about the
12 * suitability of this software for any purpose.  It is provided "as
13 * is" without express or implied warranty.
14 *
15 * MATTHEW GROSSMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL MATTHEW GROSSMAN BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
20 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
21 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22 * SOFTWARE.
23 *
24 * Author:  Matthew Grossman, mattg@oz.net
25 *
26 */
27
28/* tga_line.c */
29/* accelerated solid and dashed lines */
30/* adapted from xaa/xaaLine.c */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <X11/X.h>
37#include "misc.h"
38#include "xf86.h"
39#include "xf86_OSproc.h"
40
41#include "scrnintstr.h"
42#include "pixmapstr.h"
43#include "miline.h"
44#include "xf86str.h"
45
46/*  #include "tga.h" */
47#include "tga_regs.h"
48
49#ifdef HAVE_XAA_H
50#include "xaa.h"
51#include "xaalocal.h"
52/* line functions */
53extern void
54TGASetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop,
55		     unsigned int planemask);
56extern void
57TGASubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len,
58			      int dir);
59extern void
60TGASubsequentSolidLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2,
61		       int octant, int flags);
62extern void
63TGASetupForClippedLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2,
64		       int octant);
65extern void
66TGASubsequentClippedSolidLine(ScrnInfoPtr pScrn, int x1, int y1, int len,
67			      int err);
68
69extern void
70TGASetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop,
71		      unsigned int planemask, int length,
72		      unsigned char *pattern);
73extern void
74TGASubsequentDashedLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2,
75			int octant, int flags, int phase);
76extern void
77TGASubsequentClippedDashedLine(ScrnInfoPtr pScrn, int x1, int y1, int len,
78			       int err, int phase);
79
80
81extern void
82TGASync(ScrnInfoPtr pScrn);
83
84void TGAPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
85		    xSegment *pSeg);
86void TGAPolyLines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
87		  DDXPointPtr pptInit);
88void TGAPolySegmentDashed(DrawablePtr pDrawable, GCPtr pGC, int	nseg,
89			  xSegment *pSeg);
90void TGAPolyLinesDashed(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
91			DDXPointPtr pptInit);
92
93
94void
95#ifdef POLYSEGMENT
96TGAPolySegment(
97	       DrawablePtr	pDrawable,
98	       GCPtr	pGC,
99	       int		nseg,
100	       xSegment	*pSeg
101#else
102	       TGAPolyLines(
103			    DrawablePtr pDrawable,
104			    GCPtr	pGC,
105			    int		mode,		/* Origin or Previous */
106			    int		npt,		/* number of points */
107			    DDXPointPtr pptInit
108#endif
109			    ){
110  XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
111  BoxPtr pboxInit = REGION_RECTS(pGC->pCompositeClip);
112  int nboxInit = REGION_NUM_RECTS(pGC->pCompositeClip);
113  unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
114  int xorg = pDrawable->x;
115  int yorg = pDrawable->y;
116  int nbox;
117  BoxPtr pbox;
118#ifndef POLYSEGMENT
119  DDXPointPtr ppt;
120#endif
121  int x1, x2, y1, y2, tmp, len;
122
123#ifdef POLYSEGMENT
124/*    ErrorF("TGAPolySegment called!\n"); */
125#else
126/*    ErrorF("TGAPolyLines called\n"); */
127#endif
128
129  if(!nboxInit)
130    return;
131  /****************/
132  /* TGA FUNCTION */
133  /****************/
134  TGASetupForSolidLine(infoRec->pScrn, pGC->fgPixel, pGC->alu,
135		       pGC->planemask);
136
137#ifdef POLYSEGMENT
138  while (nseg--)
139#else
140    ppt = pptInit;
141  x2 = ppt->x + xorg;
142  y2 = ppt->y + yorg;
143  while(--npt)
144#endif
145    {
146      nbox = nboxInit;
147      pbox = pboxInit;
148
149#ifdef POLYSEGMENT
150      x1 = pSeg->x1 + xorg;
151      y1 = pSeg->y1 + yorg;
152      x2 = pSeg->x2 + xorg;
153      y2 = pSeg->y2 + yorg;
154      pSeg++;
155#else
156      x1 = x2;
157      y1 = y2;
158      ++ppt;
159      if (mode == CoordModePrevious) {
160	xorg = x1;
161	yorg = y1;
162      }
163      x2 = ppt->x + xorg;
164      y2 = ppt->y + yorg;
165#endif
166
167      if (x1 == x2) { /* vertical line */
168	/* make the line go top to bottom of screen, keeping
169	   endpoint semantics
170	*/
171	if (y1 > y2) {
172	  tmp = y2;
173	  y2 = y1 + 1;
174	  y1 = tmp + 1;
175#ifdef POLYSEGMENT
176	  if (pGC->capStyle != CapNotLast) y1--;
177#endif
178	}
179#ifdef POLYSEGMENT
180	else if (pGC->capStyle != CapNotLast) y2++;
181#endif
182	/* get to first band that might contain part of line */
183	while(nbox && (pbox->y2 <= y1)) {
184	  pbox++;
185	  nbox--;
186	}
187
188	/* stop when lower edge of box is beyond end of line */
189	while(nbox && (y2 >= pbox->y1)) {
190	  if ((x1 >= pbox->x1) && (x1 < pbox->x2)) {
191	    tmp = max(y1, pbox->y1);
192	    len = min(y2, pbox->y2) - tmp;
193	    if (len)
194	      TGASubsequentSolidHorVertLine(infoRec->pScrn, x1, tmp,
195					    len, DEGREES_270);
196	  }
197	  nbox--;
198	  pbox++;
199	}
200#ifndef POLYSEGMENT
201	y2 = ppt->y + yorg;
202#endif
203      } else if (y1 == y2) { /* horizontal line */
204	/* force line from left to right, keeping endpoint semantics */
205	if (x1 > x2) {
206	  tmp = x2;
207	  x2 = x1 + 1;
208	  x1 = tmp + 1;
209#ifdef POLYSEGMENT
210	  if (pGC->capStyle != CapNotLast)  x1--;
211#endif
212	}
213#ifdef POLYSEGMENT
214	else if (pGC->capStyle != CapNotLast) x2++;
215#endif
216
217	/* find the correct band */
218	while(nbox && (pbox->y2 <= y1)) {
219	  pbox++;
220	  nbox--;
221	}
222
223	/* try to draw the line, if we haven't gone beyond it */
224	if (nbox && (pbox->y1 <= y1)) {
225	  int orig_y = pbox->y1;
226	  /* when we leave this band, we're done */
227	  while(nbox && (orig_y == pbox->y1)) {
228	    if (pbox->x2 <= x1) {
229	      /* skip boxes until one might contain start point */
230	      nbox--;
231	      pbox++;
232	      continue;
233	    }
234
235	    /* stop if left of box is beyond right of line */
236	    if (pbox->x1 >= x2) {
237	      nbox = 0;
238	      break;
239	    }
240
241	    tmp = max(x1, pbox->x1);
242	    len = min(x2, pbox->x2) - tmp;
243	    if (len)
244	      TGASubsequentSolidHorVertLine(infoRec->pScrn, tmp,
245					    y1, len, DEGREES_0);
246	    nbox--;
247	    pbox++;
248	  }
249	}
250#ifndef POLYSEGMENT
251	x2 = ppt->x + xorg;
252#endif
253      } else{ /* sloped line */
254	unsigned int oc1, oc2;
255	int dmin, dmaj, e, octant;
256
257
258	if((dmaj = x2 - x1) < 0) {
259	  dmaj = -dmaj;
260	  octant = XDECREASING;
261	} else octant = 0;
262
263	if((dmin = y2 - y1) < 0) {
264	  dmin = -dmin;
265	  octant |= YDECREASING;
266	}
267
268	if(dmin >= dmaj){
269	  tmp = dmin; dmin = dmaj; dmaj = tmp;
270	  octant |= YMAJOR;
271	}
272
273	e = -dmaj - ((bias >> octant) & 1);
274	len = dmaj;
275	dmin *= 2;
276	dmaj *= 2;
277
278
279	while(nbox--) {
280	  oc1 = oc2 = 0;
281	  OUTCODES(oc1, x1, y1, pbox);
282	  OUTCODES(oc2, x2, y2, pbox);
283	  if (!(oc1 | oc2)) {   /* unclipped */
284	    TGASubsequentSolidLine(infoRec->pScrn, x1, y1, x2, y2,
285				   octant,
286#ifdef POLYSEGMENT
287				   (pGC->capStyle != CapNotLast) ? 0 :
288#endif
289				   OMIT_LAST
290				   );
291	    break;
292	  } else if (oc1 & oc2) { /* completely clipped */
293	    pbox++;
294
295	  } else { /* partially clipped */
296	    int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
297	    int clip1 = 0, clip2 = 0;
298	    int err, adx, ady;
299
300	    if(octant & YMAJOR) {
301	      ady = dmaj /= 2;
302	      adx = dmin /= 2;
303	    } else {
304	      ady = dmin /= 2;
305	      adx = dmaj /= 2;
306	    }
307
308	    if (miZeroClipLine(pbox->x1, pbox->y1,
309			       pbox->x2 - 1, pbox->y2 - 1,
310			       &new_x1, &new_y1, &new_x2, &new_y2,
311			       adx, ady, &clip1, &clip2,
312			       octant, bias, oc1, oc2) == -1)
313	      {
314		pbox++;
315		continue;
316	      }
317
318	    if (octant & YMAJOR)
319	      len = abs(new_y2 - new_y1);
320	    else
321	      len = abs(new_x2 - new_x1);
322#ifdef POLYSEGMENT
323	    if (clip2 != 0 || pGC->capStyle != CapNotLast)
324	      len++;
325#else
326	    len += (clip2 != 0);
327#endif
328	    if (len) { /* we have a real line */
329	      int abserr, clipdx, clipdy;
330
331	      /* unwind bresenham error term to first point */
332	      if (clip1) {
333		clipdx = abs(new_x1 - x1);
334		clipdy = abs(new_y1 - y1);
335
336		if (octant & YMAJOR)
337		  err = e + clipdy*dmin - clipdx*dmaj;
338		else
339		  err = e + clipdx*dmin - clipdy*dmaj;
340	      } else
341		err = e;
342
343#define range infoRec->SolidBresenhamLineErrorTermBits
344	      abserr = abs(err);
345	      while((abserr & range) ||
346		    (dmaj & range) ||
347		    (dmin & range)) {
348		dmin /= 2;
349		dmaj /= 2;
350		abserr /= 2;
351		err /= 2;
352	      }
353	      TGASetupForClippedLine(infoRec->pScrn, x1, y1, x2,
354				     y2, octant);
355	      TGASubsequentClippedSolidLine(infoRec->pScrn,
356					    new_x1, new_y1, len,
357					    err);
358
359
360	    }
361	    pbox++;
362	  }
363	} /* while (nbox--) */
364      } /* sloped line */
365    } /* while (nline--) */
366
367#ifndef POLYSEGMENT
368  /* paint the last point if the end style isn't CapNotLast.
369       (Assume that a projecting, butt, or round cap that is one
370        pixel wide is the same as the single pixel of the endpoint.)
371    */
372
373  if ((pGC->capStyle != CapNotLast) &&
374      ((ppt->x + xorg != pptInit->x + pDrawable->x) ||
375       (ppt->y + yorg != pptInit->y + pDrawable->y) ||
376       (ppt == pptInit + 1)))
377    {
378      nbox = nboxInit;
379      pbox = pboxInit;
380      while (nbox--)
381	{
382	  if ((x2 >= pbox->x1) && (y2 >= pbox->y1) &&
383	      (x2 <  pbox->x2) && (y2 <  pbox->y2))
384	    {
385	      TGASubsequentSolidHorVertLine(infoRec->pScrn, x2, y2, 1,
386					    DEGREES_0);
387	      break;
388	    }
389	  else
390	    pbox++;
391	}
392    }
393#endif
394
395  TGASync(infoRec->pScrn);
396  return;
397}
398
399#undef range
400
401  void
402#ifdef POLYSEGMENT
403  TGAPolySegmentDashed(
404		       DrawablePtr	pDrawable,
405		       GCPtr	pGC,
406		       int		nseg,
407		       xSegment	*pSeg
408#else
409		       TGAPolyLinesDashed(
410					  DrawablePtr pDrawable,
411					  GCPtr	pGC,
412					  int		mode,		/* Origin or Previous */
413					  int		npt,		/* number of points */
414					  DDXPointPtr pptInit
415#endif
416					  ){
417    XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC);
418#if TGA_OLDPRIV
419    XAAGCPtr   pGCPriv = (XAAGCPtr) (pGC)->devPrivates[XAAGetGCIndex()].ptr;
420#else
421    XAAGCPtr   pGCPriv = (XAAGCPtr)dixLookupPrivate(&(pGC)->devPrivates, XAAGetGCKey());
422#endif
423    BoxPtr pboxInit = REGION_RECTS(pGC->pCompositeClip);
424    int nboxInit = REGION_NUM_RECTS(pGC->pCompositeClip);
425    unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
426    int xorg = pDrawable->x;
427    int yorg = pDrawable->y;
428    int nbox;
429    BoxPtr pbox;
430#ifndef POLYSEGMENT
431    DDXPointPtr ppt;
432#endif
433    unsigned int oc1, oc2;
434    int dmin, dmaj, e, octant;
435    int x1, x2, y1, y2, tmp, len, offset;
436    int PatternLength, PatternOffset;
437
438#ifdef POLYSEGMENT
439/*      ErrorF("TGAPolySegmentDashed called\n"); */
440#else
441/*      ErrorF("TGAPolyLinesDashed called\n"); */
442#endif
443
444    if(!nboxInit)
445      return;
446
447    PatternLength = pGCPriv->DashLength;
448    PatternOffset = pGC->dashOffset % PatternLength;
449
450    TGASetupForDashedLine(infoRec->pScrn, pGC->fgPixel,
451			  (pGC->lineStyle == LineDoubleDash) ? pGC->bgPixel : -1,
452			  pGC->alu, pGC->planemask, PatternLength, pGCPriv->DashPattern);
453
454
455#ifdef POLYSEGMENT
456    while (nseg--)
457#else
458      ppt = pptInit;
459    x2 = ppt->x + xorg;
460    y2 = ppt->y + yorg;
461    while(--npt)
462#endif
463      {
464	nbox = nboxInit;
465	pbox = pboxInit;
466
467#ifdef POLYSEGMENT
468	x1 = pSeg->x1 + xorg;
469	y1 = pSeg->y1 + yorg;
470	x2 = pSeg->x2 + xorg;
471	y2 = pSeg->y2 + yorg;
472	pSeg++;
473#else
474	x1 = x2;
475	y1 = y2;
476	++ppt;
477	if (mode == CoordModePrevious) {
478	  xorg = x1;
479	  yorg = y1;
480	}
481	x2 = ppt->x + xorg;
482	y2 = ppt->y + yorg;
483#endif
484
485
486
487	if((dmaj = x2 - x1) < 0) {
488	  dmaj = -dmaj;
489	  octant = XDECREASING;
490	} else octant = 0;
491
492	if((dmin = y2 - y1) < 0) {
493	  dmin = -dmin;
494	  octant |= YDECREASING;
495	}
496
497	if(dmin >= dmaj){
498	  tmp = dmin; dmin = dmaj; dmaj = tmp;
499	  octant |= YMAJOR;
500	}
501
502	e = -dmaj - ((bias >> octant) & 1);
503	len = dmaj;
504	dmin <<= 1;
505	dmaj <<= 1;
506
507
508	while(nbox--) {
509	  oc1 = oc2 = 0;
510	  OUTCODES(oc1, x1, y1, pbox);
511	  OUTCODES(oc2, x2, y2, pbox);
512	  if (!(oc1 | oc2)) {   /* unclipped */
513	    TGASubsequentDashedLine(infoRec->pScrn, x1, y1, x2, y2,
514				    octant,
515#ifdef POLYSEGMENT
516				    (pGC->capStyle != CapNotLast) ? 0 :
517#endif
518				    OMIT_LAST, PatternOffset);
519	    break;
520	  } else if (oc1 & oc2) { /* completely clipped */
521	    pbox++;
522	  } else { /* partially clipped */
523	    int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
524	    int clip1 = 0, clip2 = 0;
525	    int err, adx, ady;
526
527	    if(octant & YMAJOR) {
528	      ady = dmaj >> 1;
529	      adx = dmin >> 1;
530	    } else {
531	      ady = dmin >> 1;
532	      adx = dmaj >> 1;
533	    }
534
535	    if (miZeroClipLine(pbox->x1, pbox->y1,
536			       pbox->x2 - 1, pbox->y2 - 1,
537			       &new_x1, &new_y1, &new_x2, &new_y2,
538			       adx, ady, &clip1, &clip2,
539			       octant, bias, oc1, oc2) == -1)
540	      {
541		pbox++;
542		continue;
543	      }
544
545	    if (octant & YMAJOR)
546	      len = abs(new_y2 - new_y1);
547	    else
548	      len = abs(new_x2 - new_x1);
549#ifdef POLYSEGMENT
550	    if (clip2 != 0 || pGC->capStyle != CapNotLast)
551	      len++;
552#else
553	    len += (clip2 != 0);
554#endif
555	    if (len) {
556	      int abserr, clipdx, clipdy;
557	      /* unwind bresenham error term to first point */
558	      if (clip1) {
559		clipdx = abs(new_x1 - x1);
560		clipdy = abs(new_y1 - y1);
561
562		if (octant & YMAJOR)
563		  err = e + clipdy*dmin - clipdx*dmaj;
564		else
565		  err = e + clipdx*dmin - clipdy*dmaj;
566	      } else
567		err = e;
568
569#define range infoRec->DashedBresenhamLineErrorTermBits
570	      abserr = abs(err);
571	      while((abserr & range) ||
572		    (dmaj & range) ||
573		    (dmin & range)) {
574		dmin >>= 1;
575		dmaj >>= 1;
576		abserr >>= 1;
577		err /= 2;
578	      }
579
580	      if(octant & YMAJOR)
581		offset = abs(new_y1 - y1);
582	      else
583		offset = abs(new_x1 - x1);
584
585	      offset += PatternOffset;
586	      offset %= PatternLength;
587
588	      TGASetupForClippedLine(infoRec->pScrn, x1, x2, y1, y2,
589				     octant);
590	      TGASubsequentClippedDashedLine(infoRec->pScrn, new_x1,
591					     new_y1, len, err,
592					     PatternOffset);
593	    }
594	    pbox++;
595	  }
596	} /* while (nbox--) */
597#ifndef POLYSEGMENT
598	len = abs(y2 - y1);
599	tmp = abs(x2 - x1);
600	PatternOffset += (len > tmp) ? len : tmp;
601	PatternOffset %= PatternLength;
602#endif
603      } /* while (nline--) */
604
605#ifndef POLYSEGMENT
606    /* paint the last point if the end style isn't CapNotLast.
607       (Assume that a projecting, butt, or round cap that is one
608        pixel wide is the same as the single pixel of the endpoint.)
609    */
610
611    if ((pGC->capStyle != CapNotLast) &&
612	((ppt->x + xorg != pptInit->x + pDrawable->x) ||
613	 (ppt->y + yorg != pptInit->y + pDrawable->y) ||
614	 (ppt == pptInit + 1)))
615      {
616	nbox = nboxInit;
617	pbox = pboxInit;
618	while (nbox--) {
619	  if ((x2 >= pbox->x1) && (y2 >= pbox->y1) &&
620	      (x2 <  pbox->x2) && (y2 <  pbox->y2))
621	    {
622	      TGASubsequentDashedLine(infoRec->pScrn, x2, y2, x2, y2, 0, 0,
623				      PatternOffset);
624	      break;
625	    } else
626		pbox++;
627	}
628    }
629#endif
630
631    TGASync(infoRec->pScrn);
632    return;
633}
634
635
636#endif
637