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