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