|
|
1.1 ! root 1: /*************************************************************************\ ! 2: * Module Name: Lines.cxx ! 3: * ! 4: * C template for the ASM version of the line DDA calculator. ! 5: * ! 6: * Copyright (c) 1990-1993 Microsoft Corporation ! 7: * Copyright (c) 1992 Digital Equipment Corporation ! 8: \**************************************************************************/ ! 9: ! 10: #define __CPLUSPLUS ! 11: #include "driver.h" ! 12: #include "lines.h" ! 13: #include "equad.hxx" ! 14: ! 15: #define SWAPL(x,y,t) {t = x; x = y; y = t;} // from wingdip.h ! 16: #define ROR_BYTE(x) ((((x) >> 1) & 0x7f) | (((x) & 0x01) << 7)) ! 17: #define ROL_BYTE(x) ((((x) << 1) & 0xfe) | (((x) & 0x80) >> 7)) ! 18: #define MIN(a, b) ((a) < (b) ? (a) : (b)) ! 19: #define ABS(a) ((a) < 0 ? -(a) : (a)) ! 20: ! 21: FLONG gaflRound[] = { ! 22: FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // no flips ! 23: FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // FL_FLIP_D ! 24: FL_H_ROUND_DOWN, // FL_FLIP_V ! 25: FL_V_ROUND_DOWN, // FL_FLIP_V | FL_FLIP_D ! 26: FL_V_ROUND_DOWN, // FL_FLIP_SLOPE_ONE ! 27: 0xbaadf00d, // FL_FLIP_SLOPE_ONE | FL_FLIP_D ! 28: FL_H_ROUND_DOWN, // FL_FLIP_SLOPE_ONE | FL_FLIP_V ! 29: 0xbaadf00d // FL_FLIP_SLOPE_ONE | FL_FLIP_V ! 30: | FL_FLIP_D ! 31: }; ! 32: ! 33: extern "C" ! 34: BOOL ! 35: bIntegerLine ( ! 36: PPDEV ppdev, ! 37: ULONG X1, ! 38: ULONG Y1, ! 39: ULONG X2, ! 40: ULONG Y2 ! 41: ); ! 42: ! 43: /******************************Public*Routine******************************\ ! 44: * BOOL bLines(ppdev, pptfxFirst, pptfxBuf, cptfx, pls, ! 45: * prclClip, apfn[], flStart) ! 46: * ! 47: * Computes the DDA for the line and gets ready to draw it. Puts the ! 48: * pixel data into an array of strips, and calls a strip routine to ! 49: * do the actual drawing. ! 50: * ! 51: * Doing Lines Right ! 52: * ----------------- ! 53: * ! 54: * In NT, all lines are given to the device driver in fractional ! 55: * coordinates, in a 28.4 fixed point format. The lower 4 bits are ! 56: * fractional for sub-pixel positioning. ! 57: * ! 58: * Note that you CANNOT! just round the coordinates to integers ! 59: * and pass the results to your favorite integer Bresenham routine!! ! 60: * (Unless, of course, you have such a high resolution device that ! 61: * nobody will notice -- not likely for a display device.) The ! 62: * fractions give a more accurate rendering of the line -- this is ! 63: * important for things like our Bezier curves, which would have 'kinks' ! 64: * if the points in its polyline approximation were rounded to integers. ! 65: * ! 66: * Unfortunately, for fractional lines there is more setup work to do ! 67: * a DDA than for integer lines. However, the main loop is exactly ! 68: * the same (and can be done entirely with 32 bit math). ! 69: * ! 70: * If You've Got Hardware That Does Bresenham ! 71: * ------------------------------------------ ! 72: * ! 73: * A lot of hardware limits DDA error terms to 'n' bits. With fractional ! 74: * coordinates, 4 bits are given to the fractional part, letting ! 75: * you draw in hardware only those lines that lie entirely in a 2^(n-4) ! 76: * by 2^(n-4) pixel space. ! 77: * ! 78: * And you still have to correctly draw those lines with coordinates ! 79: * outside that space! Remember that the screen is only a viewport ! 80: * onto a 28.4 by 28.4 space -- if any part of the line is visible ! 81: * you MUST render it precisely, regardless of where the end points lie. ! 82: * So even if you do it in software, somewhere you'll have to have a ! 83: * 32 bit DDA routine. ! 84: * ! 85: * Our Implementation ! 86: * ------------------ ! 87: * ! 88: * We employ a run length slice algorithm: our DDA calculates the ! 89: * number of pixels that are in each row (or 'strip') of pixels. ! 90: * ! 91: * We've separated the running of the DDA and the drawing of pixels: ! 92: * we run the DDA for several iterations and store the results in ! 93: * a 'strip' buffer (which are the lengths of consecutive pixel rows of ! 94: * the line), then we crank up a 'strip drawer' that will draw all the ! 95: * strips in the buffer. ! 96: * ! 97: * We also employ a 'half-flip' to reduce the number of strip ! 98: * iterations we need to do in the DDA and strip drawing loops: when a ! 99: * (normalized) line's slope is more than 1/2, we do a final flip ! 100: * about the line y = (1/2)x. So now, instead of each strip being ! 101: * consecutive horizontal or vertical pixel rows, each strip is composed ! 102: * of those pixels aligned in 45 degree rows. So a line like (0, 0) to ! 103: * (128, 128) would generate only one strip. ! 104: * ! 105: * We also always draw only left-to-right. ! 106: * ! 107: * Style lines may have arbitrary style patterns. We specially ! 108: * optimize the default patterns (and call them 'masked' styles). ! 109: * ! 110: * The DDA Derivation ! 111: * ------------------ ! 112: * ! 113: * Here is how I like to think of the DDA calculation. ! 114: * ! 115: * We employ Knuth's "diamond rule": rendering a one-pixel-wide line ! 116: * can be thought of as dragging a one-pixel-wide by one-pixel-high ! 117: * diamond along the true line. Pixel centers lie on the integer ! 118: * coordinates, and so we light any pixel whose center gets covered ! 119: * by the "drag" region (John D. Hobby, Journal of the Association ! 120: * for Computing Machinery, Vol. 36, No. 2, April 1989, pp. 209-229). ! 121: * ! 122: * We must define which pixel gets lit when the true line falls ! 123: * exactly half-way between two pixels. In this case, we follow ! 124: * the rule: when two pels are equidistant, the upper or left pel ! 125: * is illuminated, unless the slope is exactly one, in which case ! 126: * the upper or right pel is illuminated. (So we make the edges ! 127: * of the diamond exclusive, except for the top and left vertices, ! 128: * which are inclusive, unless we have slope one.) ! 129: * ! 130: * This metric decides what pixels should be on any line BEFORE it is ! 131: * flipped around for our calculation. Having a consistent metric ! 132: * this way will let our lines blend nicely with our curves. The ! 133: * metric also dictates that we will never have one pixel turned on ! 134: * directly above another that's turned on. We will also never have ! 135: * a gap; i.e., there will be exactly one pixel turned on for each ! 136: * column between the start and end points. All that remains to be ! 137: * done is to decide how many pixels should be turned on for each row. ! 138: * ! 139: * So lines we draw will consist of varying numbers of pixels on ! 140: * successive rows, for example: ! 141: * ! 142: * ****** ! 143: * ***** ! 144: * ****** ! 145: * ***** ! 146: * ! 147: * We'll call each set of pixels on a row a "strip". ! 148: * ! 149: * (Please remember that our coordinate space has the origin as the ! 150: * upper left pixel on the screen; postive y is down and positive x ! 151: * is right.) ! 152: * ! 153: * Device coordinates are specified as fixed point 28.4 numbers, ! 154: * where the first 28 bits are the integer coordinate, and the last ! 155: * 4 bits are the fraction. So coordinates may be thought of as ! 156: * having the form (x, y) = (M/F, N/F) where F is the constant scaling ! 157: * factor F = 2^4 = 16, and M and N are 32 bit integers. ! 158: * ! 159: * Consider the line from (M0/F, N0/F) to (M1/F, N1/F) which runs ! 160: * left-to-right and whose slope is in the first octant, and let ! 161: * dM = M1 - M0 and dN = N1 - N0. Then dM >= 0, dN >= 0 and dM >= dN. ! 162: * ! 163: * Since the slope of the line is less than 1, the edges of the ! 164: * drag region are created by the top and bottom vertices of the ! 165: * diamond. At any given pixel row y of the line, we light those ! 166: * pixels whose centers are between the left and right edges. ! 167: * ! 168: * Let mL(n) denote the line representing the left edge of the drag ! 169: * region. On pixel row j, the column of the first pixel to be ! 170: * lit is ! 171: * ! 172: * iL(j) = ceiling( mL(j * F) / F) ! 173: * ! 174: * Since the line's slope is less than one: ! 175: * ! 176: * iL(j) = ceiling( mL([j + 1/2] F) / F ) ! 177: * ! 178: * Recall the formula for our line: ! 179: * ! 180: * n(m) = (dN / dM) (m - M0) + N0 ! 181: * ! 182: * m(n) = (dM / dN) (n - N0) + M0 ! 183: * ! 184: * Since the line's slope is less than one, the line representing ! 185: * the left edge of the drag region is the original line offset ! 186: * by 1/2 pixel in the y direction: ! 187: * ! 188: * mL(n) = (dM / dN) (n - F/2 - N0) + M0 ! 189: * ! 190: * From this we can figure out the column of the first pixel that ! 191: * will be lit on row j, being careful of rounding (if the left ! 192: * edge lands exactly on an integer point, the pixel at that ! 193: * point is not lit because of our rounding convention): ! 194: * ! 195: * iL(j) = floor( mL(j F) / F ) + 1 ! 196: * ! 197: * = floor( ((dM / dN) (j F - F/2 - N0) + M0) / F ) + 1 ! 198: * ! 199: * = floor( F dM j - F/2 dM - N0 dM + dN M0) / F dN ) + 1 ! 200: * ! 201: * F dM j - [ dM (N0 + F/2) - dN M0 ] ! 202: * = floor( ---------------------------------- ) + 1 ! 203: * F dN ! 204: * ! 205: * dM j - [ dM (N0 + F/2) - dN M0 ] / F ! 206: * = floor( ------------------------------------ ) + 1 (1) ! 207: * dN ! 208: * ! 209: * = floor( (dM j + alpha) / dN ) + 1 ! 210: * ! 211: * where ! 212: * ! 213: * alpha = - [ dM (N0 + F/2) - dN M0 ] / F ! 214: * ! 215: * We use equation (1) to calculate the DDA: there are iL(j+1) - iL(j) ! 216: * pixels in row j. Because we are always calculating iL(j) for ! 217: * integer quantities of j, we note that the only fractional term ! 218: * is constant, and so we can 'throw away' the fractional bits of ! 219: * alpha: ! 220: * ! 221: * beta = floor( - [ dM (N0 + F/2) - dN M0 ] / F ) (2) ! 222: * ! 223: * so ! 224: * ! 225: * iL(j) = floor( (dM j + beta) / dN ) + 1 (3) ! 226: * ! 227: * for integers j. ! 228: * ! 229: * Note if iR(j) is the line's rightmost pixel on row j, that ! 230: * iR(j) = iL(j + 1) - 1. ! 231: * ! 232: * Similarly, rewriting equation (1) as a function of column i, ! 233: * we can determine, given column i, on which pixel row j is the line ! 234: * lit: ! 235: * ! 236: * dN i + [ dM (N0 + F/2) - dN M0 ] / F ! 237: * j(i) = ceiling( ------------------------------------ ) - 1 ! 238: * dM ! 239: * ! 240: * Floors are easier to compute, so we can rewrite this: ! 241: * ! 242: * dN i + [ dM (N0 + F/2) - dN M0 ] / F + dM - 1/F ! 243: * j(i) = floor( ----------------------------------------------- ) - 1 ! 244: * dM ! 245: * ! 246: * dN i + [ dM (N0 + F/2) - dN M0 ] / F + dM - 1/F - dM ! 247: * = floor( ---------------------------------------------------- ) ! 248: * dM ! 249: * ! 250: * dN i + [ dM (N0 + F/2) - dN M0 - 1 ] / F ! 251: * = floor( ---------------------------------------- ) ! 252: * dM ! 253: * ! 254: * We can once again wave our hands and throw away the fractional bits ! 255: * of the remainder term: ! 256: * ! 257: * j(i) = floor( (dN i + gamma) / dM ) (4) ! 258: * ! 259: * where ! 260: * ! 261: * gamma = floor( [ dM (N0 + F/2) - dN M0 - 1 ] / F ) (5) ! 262: * ! 263: * We now note that ! 264: * ! 265: * beta = -gamma - 1 = ~gamma (6) ! 266: * ! 267: * To draw the pixels of the line, we could evaluate (3) on every scan ! 268: * line to determine where the strip starts. Of course, we don't want ! 269: * to do that because that would involve a multiply and divide for every ! 270: * scan. So we do everything incrementally. ! 271: * ! 272: * We would like to easily compute c , the number of pixels on scan j: ! 273: * j ! 274: * ! 275: * c = iL(j + 1) - iL(j) ! 276: * j ! 277: * ! 278: * = floor((dM (j + 1) + beta) / dN) - floor((dM j + beta) / dN) (7) ! 279: * ! 280: * This may be rewritten as ! 281: * ! 282: * c = floor(i + r / dN) - floor(i + r / dN) (8) ! 283: * j j+1 j+1 j j ! 284: * ! 285: * where i , i are integers and r < dN, r < dN. ! 286: * j j+1 j j+1 ! 287: * ! 288: * Rewriting (7) again: ! 289: * ! 290: * c = floor(i + r / dN + dM / dN) - floor(i + r / dN) ! 291: * j j j j j ! 292: * ! 293: * ! 294: * = floor((r + dM) / dN) - floor(r / dN) ! 295: * j j ! 296: * ! 297: * This may be rewritten as ! 298: * ! 299: * c = dI + floor((r + dR) / dN) - floor(r / dN) ! 300: * j j j ! 301: * ! 302: * where dI + dR / dN = dM / dN, dI is an integer and dR < dN. ! 303: * ! 304: * r is the remainder (or "error") term in the DDA loop: r / dN ! 305: * j j ! 306: * is the exact fraction of a pixel at which the strip ends. To go ! 307: * on to the next scan and compute c we need to know r . ! 308: * j+1 j+1 ! 309: * ! 310: * So in the main loop of the DDA: ! 311: * ! 312: * c = dI + floor((r + dR) / dN) and r = (r + dR) % dN ! 313: * j j j+1 j ! 314: * ! 315: * and we know r < dN, r < dN, and dR < dN. ! 316: * j j+1 ! 317: * ! 318: * We have derived the DDA only for lines in the first octant; to ! 319: * handle other octants we do the common trick of flipping the line ! 320: * to the first octant by first making the line left-to-right by ! 321: * exchanging the end-points, then flipping about the lines y = 0 and ! 322: * y = x, as necessary. We must record the transformation so we can ! 323: * undo them later. ! 324: * ! 325: * We must also be careful of how the flips affect our rounding. If ! 326: * to get the line to the first octant we flipped about x = 0, we now ! 327: * have to be careful to round a y value of 1/2 up instead of down as ! 328: * we would for a line originally in the first octant (recall that ! 329: * "In the case where two pels are equidistant, the upper or left ! 330: * pel is illuminated..."). ! 331: * ! 332: * To account for this rounding when running the DDA, we shift the line ! 333: * (or not) in the y direction by the smallest amount possible. That ! 334: * takes care of rounding for the DDA, but we still have to be careful ! 335: * about the rounding when determining the first and last pixels to be ! 336: * lit in the line. ! 337: * ! 338: * Determining The First And Last Pixels In The Line ! 339: * ------------------------------------------------- ! 340: * ! 341: * Fractional coordinates also make it harder to determine which pixels ! 342: * will be the first and last ones in the line. We've already taken ! 343: * the fractional coordinates into account in calculating the DDA, but ! 344: * the DDA cannot tell us which are the end pixels because it is quite ! 345: * happy to calculate pixels on the line from minus infinity to positive ! 346: * infinity. ! 347: * ! 348: * The diamond rule determines the start and end pixels. (Recall that ! 349: * the sides are exclusive except for the left and top vertices.) ! 350: * This convention can be thought of in another way: there are diamonds ! 351: * around the pixels, and wherever the true line crosses a diamond, ! 352: * that pel is illuminated. ! 353: * ! 354: * Consider a line where we've done the flips to the first octant, and the ! 355: * floor of the start coordinates is the origin: ! 356: * ! 357: * +-----------------------> +x ! 358: * | ! 359: * | 0 1 ! 360: * | 0123456789abcdef ! 361: * | ! 362: * | 0 00000000?1111111 ! 363: * | 1 00000000 1111111 ! 364: * | 2 0000000 111111 ! 365: * | 3 000000 11111 ! 366: * | 4 00000 ** 1111 ! 367: * | 5 0000 ****1 ! 368: * | 6 000 1*** ! 369: * | 7 00 1 **** ! 370: * | 8 ? *** ! 371: * | 9 22 3 **** ! 372: * | a 222 33 *** ! 373: * | b 2222 333 **** ! 374: * | c 22222 3333 ** ! 375: * | d 222222 33333 ! 376: * | e 2222222 333333 ! 377: * | f 22222222 3333333 ! 378: * | ! 379: * | 2 3 ! 380: * v ! 381: * +y ! 382: * ! 383: * If the start of the line lands on the diamond around pixel 0 (shown by ! 384: * the '0' region here), pixel 0 is the first pel in the line. The same ! 385: * is true for the other pels. ! 386: * ! 387: * A little more work has to be done if the line starts in the ! 388: * 'nether-land' between the diamonds (as illustrated by the '*' line): ! 389: * the first pel lit is the first diamond crossed by the line (pixel 1 in ! 390: * our example). This calculation is determined by the DDA or slope of ! 391: * the line. ! 392: * ! 393: * If the line starts exactly half way between two adjacent pixels ! 394: * (denoted here by the '?' spots), the first pixel is determined by our ! 395: * round-down convention (and is dependent on the flips done to ! 396: * normalize the line). ! 397: * ! 398: * Last Pel Exclusive ! 399: * ------------------ ! 400: * ! 401: * To eliminate repeatedly lit pels between continuous connected lines, ! 402: * we employ a last-pel exclusive convention: if the line ends exactly on ! 403: * the diamond around a pel, that pel is not lit. (This eliminates the ! 404: * checks we had in the old code to see if we were re-lighting pels.) ! 405: * ! 406: * The Half Flip ! 407: * ------------- ! 408: * ! 409: * To make our run length algorithm more efficient, we employ a "half ! 410: * flip". If after normalizing to the first octant, the slope is more ! 411: * than 1/2, we subtract the y coordinate from the x coordinate. This ! 412: * has the effect of reflecting the coordinates through the line of slope ! 413: * 1/2. Note that the diagonal gets mapped into the x-axis after a half ! 414: * flip. ! 415: * ! 416: * How Many Bits Do We Need, Anyway? ! 417: * --------------------------------- ! 418: * ! 419: * Note that if the line is visible on your screen, you must light up ! 420: * exactly the correct pixels, no matter where in the 28.4 x 28.4 device ! 421: * space the end points of the line lie (meaning you must handle 32 bit ! 422: * DDAs, you can certainly have optimized cases for lesser DDAs). ! 423: * ! 424: * We move the origin to (floor(M0 / F), floor(N0 / F)), so when we ! 425: * calculate gamma from (5), we know that 0 <= M0, N0 < F. And we ! 426: * are in the first octant, so dM >= dN. Then we know that gamma can ! 427: * be in the range [(-1/2)dM, (3/2)dM]. The DDI guarantees us that ! 428: * valid lines will have dM and dN values at most 31 bits (unsigned) ! 429: * of significance. So gamma requires 33 bits of significance (we store ! 430: * this as a 64 bit number for convenience). ! 431: * ! 432: * When running through the DDA loop, r + dR can have a value in the ! 433: * j ! 434: * range 0 <= r < 2 dN; thus the result must be a 32 bit unsigned value. ! 435: * j ! 436: * ! 437: * Testing Lines ! 438: * ------------- ! 439: * ! 440: * To be NT compliant, a display driver must exactly adhere to GIQ, ! 441: * which means that for any given line, the driver must light exactly ! 442: * the same pels as does GDI. This can be tested using the Guiman tool ! 443: * provided elsewhere in the DDK, and 'ZTest', which draws random lines ! 444: * on the screen and to a bitmap, and compares the results. ! 445: * ! 446: * If You've Got Line Hardware ! 447: * --------------------------- ! 448: * ! 449: * If your hardware already adheres to GIQ, you're all set. Otherwise ! 450: * you'll want to look at the S3 sample code and read the following: ! 451: * ! 452: * 1) You'll want to special case integer-only lines, since they require ! 453: * less processing time and are more common (CAD programs will probably ! 454: * only ever give integer lines). GDI does not provide a flag saying ! 455: * that all lines in a path are integer lines; consequently, you will ! 456: * have to explicitly check every line. ! 457: * ! 458: * 2) You are required to correctly draw any line in the 28.4 device ! 459: * space that intersects the viewport. If you have less than 32 bits ! 460: * of significance in the hardware for the Bresenham terms, extremely ! 461: * long lines would overflow the hardware. For such (rare) cases, you ! 462: * can fall back to strip-drawing code, of which there is a C version in ! 463: * the S3's lines.cxx (or if your display is a frame buffer, fall back ! 464: * to the engine). ! 465: * ! 466: * 3) If you can explicitly set the Bresenham terms in your hardware, you ! 467: * can draw non-integer lines using the hardware. If your hardware has ! 468: * 'n' bits of precision, you can draw GIQ lines that are up to 2^(n-5) ! 469: * pels long (4 bits are required for the fractional part, and one bit is ! 470: * used as a sign bit). Note that integer lines don't require the 4 ! 471: * fractional bits, so if you special case them as in 1), you can do ! 472: * integer lines that are up to 2^(n - 1) pels long. See the S3's ! 473: * fastline.asm for an example. ! 474: * ! 475: \**************************************************************************/ ! 476: ! 477: ! 478: BOOL bLines( ! 479: PPDEV ppdev, ! 480: POINTFIX* pptfxFirst, // Start of first line ! 481: POINTFIX* pptfxBuf, // Pointer to buffer of all remaining lines ! 482: RUN* prun, // Pointer to runs if doing complex clipping ! 483: ULONG cptfx, // Number of points in pptfxBuf or number of runs ! 484: // in prun ! 485: LINESTATE* pls, // Color and style info ! 486: RECTL* prclClip, // Pointer to clip rectangle if doing simple clipping ! 487: PFNSTRIP apfn[], // Array of strip functions ! 488: FLONG flStart) // Flags for each line ! 489: { ! 490: ! 491: ULONG M0; ! 492: ULONG dM; ! 493: ULONG N0; ! 494: ULONG dN; ! 495: ULONG dN_Original; ! 496: FLONG fl; ! 497: LONG x; ! 498: LONG y; ! 499: EQUAD eqBeta; ! 500: EQUAD eqGamma; ! 501: EQUAD euq; ! 502: EQUAD eq; ! 503: ULONG ulDelta; ! 504: ! 505: ULONG x0; ! 506: ULONG y0; ! 507: ULONG x1; ! 508: ULONG cStylePels; // Major length of line in pixels for styling ! 509: ULONG xStart; ! 510: POINTL ptlStart; ! 511: STRIP strip; ! 512: PFNSTRIP pfn; ! 513: LONG cPels; ! 514: LONG* plStrip; ! 515: LONG* plStripEnd; ! 516: LONG cStripsInNextRun; ! 517: ! 518: POINTFIX* pptfxBufEnd = pptfxBuf + cptfx; // Last point in path record ! 519: STYLEPOS spThis; // Style pos for this line ! 520: ! 521: ! 522: do { ! 523: ! 524: /***********************************************************************\ ! 525: * Start the DDA calculations. * ! 526: \***********************************************************************/ ! 527: ! 528: M0 = (LONG) pptfxFirst->x; ! 529: dM = (LONG) pptfxBuf->x; ! 530: ! 531: N0 = (LONG) pptfxFirst->y; ! 532: dN = (LONG) pptfxBuf->y; ! 533: ! 534: fl = flStart; ! 535: ! 536: // Check for non-clipped, non-styled integer endpoint lines - ECR ! 537: ! 538: if ( ( (fl & (FL_CLIP | FL_STYLED)) == 0 ) && ! 539: ( ((M0 | dM | N0 | dN) & (F-1)) == 0 ) ) ! 540: { ! 541: if (bIntegerLine(ppdev, M0, N0, dM, dN)) ! 542: { ! 543: goto Next_Line; ! 544: } ! 545: } ! 546: ! 547: if ((LONG) M0 > (LONG) dM) ! 548: { ! 549: // Ensure that we run left-to-right: ! 550: ! 551: register ULONG ulTmp; ! 552: SWAPL(M0, dM, ulTmp); ! 553: SWAPL(N0, dN, ulTmp); ! 554: fl |= FL_FLIP_H; ! 555: } ! 556: ! 557: // Compute the deltas: ! 558: ! 559: dM -= M0; ! 560: dN -= N0; ! 561: ! 562: // We now have a line running left-to-right from (M0, N0) to ! 563: // (M0 + dM, N0 + dN): ! 564: ! 565: if ((LONG) dN < 0) ! 566: { ! 567: // Line runs from bottom to top, so flip across y = 0: ! 568: ! 569: N0 = -(LONG) N0; ! 570: dN = -(LONG) dN; ! 571: fl |= FL_FLIP_V; ! 572: } ! 573: ! 574: if (dN >= dM) ! 575: { ! 576: if (dN == dM) ! 577: { ! 578: // Have to special case slopes of one: ! 579: ! 580: fl |= FL_FLIP_SLOPE_ONE; ! 581: } ! 582: else ! 583: { ! 584: // Since line has slope greater than 1, flip across x = y: ! 585: ! 586: register ULONG ulTmp; ! 587: SWAPL(dM, dN, ulTmp); ! 588: SWAPL(M0, N0, ulTmp); ! 589: fl |= FL_FLIP_D; ! 590: } ! 591: } ! 592: ! 593: fl |= gaflRound[(fl & FL_ROUND_MASK) >> FL_ROUND_SHIFT]; ! 594: ! 595: x = LFLOOR((LONG) M0); ! 596: y = LFLOOR((LONG) N0); ! 597: ! 598: M0 = FXFRAC(M0); ! 599: N0 = FXFRAC(N0); ! 600: ! 601: // Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]: ! 602: ! 603: { ! 604: ! 605: eqGamma.vImulInit(dM, N0 + F/2); ! 606: eq.vImulInit(M0, dN); ! 607: ! 608: eqGamma -= eq; ! 609: ! 610: if (fl & FL_V_ROUND_DOWN) ! 611: eqGamma -= 1L; // Adjust so y = 1/2 rounds down ! 612: ! 613: eqGamma >>= FLOG2; ! 614: ! 615: eqBeta.HighPart = ~eqGamma.HighPart; ! 616: eqBeta.LowPart = ~eqGamma.LowPart; ! 617: ! 618: } ! 619: ! 620: ! 621: /***********************************************************************\ ! 622: * Figure out which pixels are at the ends of the line. * ! 623: \***********************************************************************/ ! 624: ! 625: // The toughest part of GIQ is determining the start and end pels. ! 626: // ! 627: // Our approach here is to calculate x0 and x1 (the inclusive start ! 628: // and end columns of the line respectively, relative to our normalized ! 629: // origin). Then x1 - x0 + 1 is the number of pels in the line. The ! 630: // start point is easily calculated by plugging x0 into our line equation ! 631: // (which takes care of whether y = 1/2 rounds up or down in value) ! 632: // getting y0, and then undoing the normalizing flips to get back ! 633: // into device space. ! 634: // ! 635: // We look at the fractional parts of the coordinates of the start and ! 636: // end points, and call them (M0, N0) and (M1, N1) respectively, where ! 637: // 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid ! 638: // to determine x0: ! 639: // ! 640: // +-----------------------> +x ! 641: // | ! 642: // | 0 1 ! 643: // | 0123456789abcdef ! 644: // | ! 645: // | 0 ........?xxxxxxx ! 646: // | 1 ..........xxxxxx ! 647: // | 2 ...........xxxxx ! 648: // | 3 ............xxxx ! 649: // | 4 .............xxx ! 650: // | 5 ..............xx ! 651: // | 6 ...............x ! 652: // | 7 ................ ! 653: // | 8 ................ ! 654: // | 9 ......**........ ! 655: // | a ........****...x ! 656: // | b ............**** ! 657: // | c .............xxx**** ! 658: // | d ............xxxx **** ! 659: // | e ...........xxxxx **** ! 660: // | f ..........xxxxxx ! 661: // | ! 662: // | 2 3 ! 663: // v ! 664: // ! 665: // +y ! 666: // ! 667: // This grid accounts for the appropriate rounding of GIQ and last-pel ! 668: // exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands ! 669: // on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down, ! 670: // depending on what flips have been done to normalize the line. ! 671: // ! 672: // For the end point, if (M1, N1) lands on an 'x', x1 = ! 673: // floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 = ! 674: // floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down, ! 675: // depending on what flips have been done to normalize the line. ! 676: // ! 677: // Lines of exactly slope one require a special case for both the start ! 678: // and end. For example, if the line ends such that (M1, N1) is (9, 1), ! 679: // the line has gone exactly through (8, 0) -- which may be considered ! 680: // to be part of 'x' because of rounding! So slopes of exactly slope ! 681: // one going through (8, 0) must also be considered as belonging in 'x'. ! 682: // ! 683: // For lines that go left-to-right, we have the following grid: ! 684: // ! 685: // +-----------------------> +x ! 686: // | ! 687: // | 0 1 ! 688: // | 0123456789abcdef ! 689: // | ! 690: // | 0 xxxxxxxx?....... ! 691: // | 1 xxxxxxx......... ! 692: // | 2 xxxxxx.......... ! 693: // | 3 xxxxx........... ! 694: // | 4 xxxx............ ! 695: // | 5 xxx............. ! 696: // | 6 xx.............. ! 697: // | 7 x............... ! 698: // | 8 x............... ! 699: // | 9 x.....**........ ! 700: // | a xx......****.... ! 701: // | b xxx.........**** ! 702: // | c xxxx............**** ! 703: // | d xxxxx........... **** ! 704: // | e xxxxxx.......... **** ! 705: // | f xxxxxxx......... ! 706: // | ! 707: // | 2 3 ! 708: // v ! 709: // ! 710: // +y ! 711: // ! 712: // This grid accounts for the appropriate rounding of GIQ and last-pel ! 713: // exclusion. If (M0, N0) lands on an 'x', x0 = 0. If (M0, N0) lands ! 714: // on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down, ! 715: // depending on what flips have been done to normalize the line. ! 716: // ! 717: // For the end point, if (M1, N1) lands on an 'x', x1 = ! 718: // floor((M0 + dM) / 16) - 1. If (M1, N1) lands on a '.', x1 = ! 719: // floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down, ! 720: // depending on what flips have been done to normalize the line. ! 721: // ! 722: // Lines of exactly slope one must be handled similarly to the right-to- ! 723: // left case. ! 724: ! 725: { ! 726: ! 727: // Calculate x0, x1 ! 728: ! 729: ULONG N1 = FXFRAC(N0 + dN); ! 730: ULONG M1 = FXFRAC(M0 + dM); ! 731: ! 732: x1 = LFLOOR(M0 + dM); ! 733: ! 734: if (fl & FL_FLIP_H) ! 735: { ! 736: // --------------------------------------------------------------- ! 737: // Line runs right-to-left: <---- ! 738: ! 739: // Compute x1: ! 740: ! 741: if (N1 == 0) ! 742: { ! 743: if (LROUND(M1, fl & FL_H_ROUND_DOWN)) ! 744: { ! 745: x1++; ! 746: } ! 747: } ! 748: else if (ABS((LONG) (N1 - F/2)) + M1 > F) ! 749: { ! 750: x1++; ! 751: } ! 752: ! 753: if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN)) ! 754: == (FL_FLIP_SLOPE_ONE)) ! 755: { ! 756: // Have to special-case diagonal lines going through our ! 757: // the point exactly equidistant between two horizontal ! 758: // pixels, if we're supposed to round x=1/2 down: ! 759: ! 760: if ((N1 > 0) && (M1 == N1 + 8)) ! 761: x1++; ! 762: ! 763: // Don't you love special cases? Is this a rhetorical question? ! 764: ! 765: if ((M0 > 0) && (N0 == M0 + 8)) ! 766: { ! 767: x0 = 2; ! 768: ulDelta = dN; ! 769: goto right_to_left_compute_y0; ! 770: } ! 771: } ! 772: ! 773: // Compute x0: ! 774: ! 775: x0 = 1; ! 776: ulDelta = 0; ! 777: if (N0 == 0) ! 778: { ! 779: if (LROUND(M0, fl & FL_H_ROUND_DOWN)) ! 780: { ! 781: x0 = 2; ! 782: ulDelta = dN; ! 783: } ! 784: } ! 785: else if (ABS((LONG) (N0 - F/2)) + M0 > F) ! 786: { ! 787: x0 = 2; ! 788: ulDelta = dN; ! 789: } ! 790: ! 791: // Compute y0: ! 792: ! 793: right_to_left_compute_y0: ! 794: ! 795: y0 = 0; ! 796: eq = eqGamma; ! 797: eq += ulDelta; ! 798: if (eq.lHigh() >= 0) ! 799: { ! 800: if (eq.lHigh() > 0 || eq.ulLow() >= 2 * dM - dN) ! 801: y0 = 2; ! 802: else if (eq.ulLow() >= dM - dN) ! 803: y0 = 1; ! 804: } ! 805: } ! 806: else ! 807: { ! 808: // --------------------------------------------------------------- ! 809: // Line runs left-to-right: ----> ! 810: ! 811: // Compute x1: ! 812: ! 813: x1--; ! 814: ! 815: if (M1 > 0) ! 816: { ! 817: if (N1 == 0) ! 818: { ! 819: if (LROUND(M1, fl & FL_H_ROUND_DOWN)) ! 820: x1++; ! 821: } ! 822: else if (ABS((LONG) (N1 - F/2)) <= (LONG) M1) ! 823: { ! 824: x1++; ! 825: } ! 826: } ! 827: ! 828: if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN)) ! 829: == (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN)) ! 830: { ! 831: // Have to special-case diagonal lines going through our ! 832: // the point exactly equidistant between two horizontal ! 833: // pixels, if we're supposed to round x=1/2 down: ! 834: ! 835: if ((N1 > 0) && (M1 == N1 + 8)) ! 836: x1--; ! 837: ! 838: if ((M0 > 0) && (N0 == M0 + 8)) ! 839: { ! 840: x0 = 0; ! 841: goto left_to_right_compute_y0; ! 842: } ! 843: } ! 844: ! 845: // Compute x0: ! 846: ! 847: x0 = 0; ! 848: if (M0 > 0) ! 849: { ! 850: if (N0 == 0) ! 851: { ! 852: if (LROUND(M0, fl & FL_H_ROUND_DOWN)) ! 853: x0 = 1; ! 854: } ! 855: else if (ABS((LONG) (N0 - F/2)) <= (LONG) M0) ! 856: { ! 857: x0 = 1; ! 858: } ! 859: } ! 860: ! 861: // Compute y0: ! 862: ! 863: left_to_right_compute_y0: ! 864: ! 865: y0 = 0; ! 866: if (eqGamma.lHigh() >= 0 && ! 867: eqGamma.ulLow() >= dM - (dN & (-(LONG) x0))) ! 868: { ! 869: y0 = 1; ! 870: } ! 871: } ! 872: } ! 873: ! 874: cStylePels = x1 - x0 + 1; ! 875: if ((LONG) cStylePels <= 0) ! 876: goto Next_Line; ! 877: ! 878: xStart = x0; ! 879: ! 880: /***********************************************************************\ ! 881: * Complex clipping. * ! 882: \***********************************************************************/ ! 883: #ifdef SIMPLE_CLIP ! 884: if (fl & FL_COMPLEX_CLIP) ! 885: #else ! 886: if (fl & FL_CLIP) ! 887: #endif // SIMPLE_CLIP ! 888: { ! 889: dN_Original = dN; ! 890: ! 891: Continue_Complex_Clipping: ! 892: ! 893: if (fl & FL_FLIP_H) ! 894: { ! 895: // Line runs right-to-left <----- ! 896: ! 897: x0 = xStart + cStylePels - prun->iStop - 1; ! 898: x1 = xStart + cStylePels - prun->iStart - 1; ! 899: } ! 900: else ! 901: { ! 902: // Line runs left-to-right -----> ! 903: ! 904: x0 = xStart + prun->iStart; ! 905: x1 = xStart + prun->iStop; ! 906: } ! 907: ! 908: prun++; ! 909: ! 910: // Reset some variables we'll nuke a little later: ! 911: ! 912: dN = dN_Original; ! 913: pls->spNext = pls->spComplex; ! 914: ! 915: // No overflow since large integer math is used ! 916: ! 917: euq.vMulInit(x0, dN); ! 918: euq += eqGamma; ! 919: ! 920: y0 = euq.ulDiv(dM); ! 921: ! 922: ASSERTS3((LONG) y0 >= 0, "y0 weird: Goofed up end pel calc?"); ! 923: } ! 924: ! 925: ///////////////////////////////////////////////////////////////////////// ! 926: // The following clip code works great -- we simply aren't using it yet. ! 927: ///////////////////////////////////////////////////////////////////////// ! 928: ! 929: #ifdef SIMPLE_CLIP ! 930: /***********************************************************************\ ! 931: * Simple rectangular clipping. * ! 932: \***********************************************************************/ ! 933: ! 934: if (fl & FL_SIMPLE_CLIP) ! 935: { ! 936: ULONG y1; ! 937: LONG xRight; ! 938: LONG xLeft; ! 939: LONG yBottom; ! 940: LONG yTop; ! 941: ! 942: // Note that y0 and y1 are actually the lower and upper bounds, ! 943: // respectively, of the y coordinates of the line (the line may ! 944: // have actually shrunk due to first/last pel clipping). ! 945: // ! 946: // Also note that x0, y0 are not necessarily zero. ! 947: ! 948: RECTL* prcl = &prclClip[(fl & FL_RECTLCLIP_MASK) >> ! 949: FL_RECTLCLIP_SHIFT]; ! 950: ! 951: // Normalize to the same point we've normalized for the DDA ! 952: // calculations: ! 953: ! 954: xRight = prcl->right - x; ! 955: xLeft = prcl->left - x; ! 956: yBottom = prcl->bottom - y; ! 957: yTop = prcl->top - y; ! 958: ! 959: if (yBottom <= (LONG) y0 || ! 960: xRight <= (LONG) x0 || ! 961: xLeft > (LONG) x1) ! 962: { ! 963: Totally_Clipped: ! 964: ! 965: if (fl & FL_STYLED) ! 966: { ! 967: pls->spNext += cStylePels; ! 968: if (pls->spNext >= pls->spTotal2) ! 969: pls->spNext %= pls->spTotal2; ! 970: } ! 971: ! 972: goto Next_Line; ! 973: } ! 974: ! 975: if ((LONG) x1 >= xRight) ! 976: x1 = xRight - 1; ! 977: ! 978: // We have to know the correct y1, which we haven't bothered to ! 979: // calculate up until now. This multiply and divide is quite ! 980: // expensive; we could replace it with code similar to that which ! 981: // we used for computing y0. ! 982: // ! 983: // The reason why we need the actual value, and not an upper ! 984: // bounds guess like y1 = LFLOOR(dM) + 2 is that we have to be ! 985: // careful when calculating x(y) that y0 <= y <= y1, otherwise ! 986: // we can overflow on the divide (which, needless to say, is very ! 987: // bad). ! 988: ! 989: euq.vMulInit(x1, dN); ! 990: euq += eqGamma; ! 991: y1 = euq.ulDiv(dM); ! 992: ! 993: if (yTop > (LONG) y1) ! 994: goto Totally_Clipped; ! 995: ! 996: if (yBottom <= (LONG) y1) ! 997: { ! 998: y1 = yBottom; ! 999: ! 1000: euq.vMulInit(y1, dM); ! 1001: euq += eqBeta; ! 1002: x1 = euq.ulDiv(dN); ! 1003: } ! 1004: ! 1005: // At this point, we've taken care of calculating the intercepts ! 1006: // with the right and bottom edges. Now we work on the left and ! 1007: // top edges: ! 1008: ! 1009: if (xLeft > (LONG) x0) ! 1010: { ! 1011: x0 = xLeft; ! 1012: ! 1013: euq.vMulInit(x0, dN); ! 1014: euq += eqGamma; ! 1015: y0 = euq.ulDiv(dM); ! 1016: ! 1017: if (yBottom <= (LONG) y0) ! 1018: goto Totally_Clipped; ! 1019: } ! 1020: ! 1021: if (yTop > (LONG) y0) ! 1022: { ! 1023: y0 = yTop; ! 1024: ! 1025: euq.vMulInit(y0, dM); ! 1026: euq += eqBeta; ! 1027: x0 = euq.ulDiv(dN) + 1; ! 1028: ! 1029: if (xRight <= (LONG) x0) ! 1030: goto Totally_Clipped; ! 1031: } ! 1032: ! 1033: ASSERTS3(x0 <= x1, "Improper rectangle clip"); ! 1034: } ! 1035: #endif // SIMPLE_CLIP ! 1036: ! 1037: /***********************************************************************\ ! 1038: * Done clipping. Unflip if necessary. * ! 1039: \***********************************************************************/ ! 1040: ! 1041: ptlStart.x = x + x0; ! 1042: ptlStart.y = y + y0; ! 1043: ! 1044: if (fl & FL_FLIP_D) ! 1045: { ! 1046: register LONG lTmp; ! 1047: SWAPL(ptlStart.x, ptlStart.y, lTmp); ! 1048: } ! 1049: ! 1050: ! 1051: if (fl & FL_FLIP_V) ! 1052: { ! 1053: ptlStart.y = -ptlStart.y; ! 1054: } ! 1055: ! 1056: cPels = x1 - x0 + 1; ! 1057: ! 1058: /***********************************************************************\ ! 1059: * Style calculations. * ! 1060: \***********************************************************************/ ! 1061: ! 1062: if (fl & FL_STYLED) ! 1063: { ! 1064: STYLEPOS sp; ! 1065: ! 1066: spThis = pls->spNext; ! 1067: pls->spNext += cStylePels; ! 1068: ! 1069: #ifdef ALTERNATESTYLED ! 1070: if (fl & FL_ALTERNATESTYLED) ! 1071: { ! 1072: pls->spNext &= 1; ! 1073: if (fl & FL_FLIP_H) ! 1074: { ! 1075: sp = pls->spNext - x0 + xStart + 1; ! 1076: } ! 1077: else ! 1078: { ! 1079: sp = spThis + x0 - xStart; ! 1080: } ! 1081: pls->ulStyleMask = (BYTE) (0x55555555L >> ! 1082: (ptlStart.x & 0x7) + (sp & 1)); ! 1083: ! 1084: pls->spRemaining = 1; ! 1085: } ! 1086: else ! 1087: #endif // ALTERNATESTYLED ! 1088: ! 1089: { ! 1090: if (pls->spNext >= pls->spTotal2) ! 1091: pls->spNext %= pls->spTotal2; ! 1092: ! 1093: ! 1094: if (fl & FL_FLIP_H) ! 1095: sp = pls->spNext - x0 + xStart; ! 1096: else ! 1097: sp = spThis + x0 - xStart; ! 1098: #ifdef MASKSTYLED ! 1099: if (fl & FL_MASKSTYLED) ! 1100: { ! 1101: ULONG cShifts; ! 1102: ULONG cRemainder; ! 1103: ULONG ulStyleMask; ! 1104: ! 1105: if (fl & FL_FLIP_H) ! 1106: { ! 1107: cShifts = (sp + 2) / STYLE_DENSITY; ! 1108: cRemainder = (sp + 2) % STYLE_DENSITY; ! 1109: cShifts &= 7L; ! 1110: ulStyleMask = (pls->ulStyleMaskRtoL >> cShifts); ! 1111: pls->spRemaining = cRemainder + 1; ! 1112: } ! 1113: else ! 1114: { ! 1115: cRemainder = sp % STYLE_DENSITY; ! 1116: cShifts = sp / STYLE_DENSITY; ! 1117: cShifts &= 7L; ! 1118: ulStyleMask = (pls->ulStyleMaskLtoR >> ! 1119: (8 - cShifts)); ! 1120: pls->spRemaining = STYLE_DENSITY - cRemainder; ! 1121: } ! 1122: ! 1123: pls->ulStyleMask = (BYTE) (ulStyleMask >> ! 1124: (ptlStart.x & 0x7)); ! 1125: } ! 1126: else ! 1127: #endif // MASKSTYLED ! 1128: { ! 1129: ASSERTS3(fl & FL_ARBITRARYSTYLED, "Oops"); ! 1130: ! 1131: // Normalize our target style position: ! 1132: ! 1133: if ((sp < 0) || (sp >= pls->spTotal2)) ! 1134: { ! 1135: sp %= pls->spTotal2; ! 1136: ! 1137: // The modulus of a negative number is not well-defined ! 1138: // in C -- if it's negative we'll adjust it so that it's ! 1139: // back in the range [0, spTotal2): ! 1140: ! 1141: if (sp < 0) ! 1142: sp += pls->spTotal2; ! 1143: } ! 1144: ! 1145: // Since we always draw the line left-to-right, but styling is ! 1146: // always done in the direction of the original line, we have ! 1147: // to figure out where we are in the style array for the left ! 1148: // edge of this line. ! 1149: ! 1150: if (fl & FL_FLIP_H) ! 1151: { ! 1152: // Line originally ran right-to-left: ! 1153: ! 1154: sp = -sp; ! 1155: if (sp < 0) ! 1156: sp += pls->spTotal2; ! 1157: ! 1158: pls->ulStyleMask = ~pls->ulStartMask; ! 1159: pls->pspStart = &pls->aspRtoL[0]; ! 1160: pls->pspEnd = &pls->aspRtoL[pls->cStyle - 1]; ! 1161: } ! 1162: else ! 1163: { ! 1164: // Line originally ran left-to-right: ! 1165: ! 1166: pls->ulStyleMask = pls->ulStartMask; ! 1167: pls->pspStart = &pls->aspLtoR[0]; ! 1168: pls->pspEnd = &pls->aspLtoR[pls->cStyle - 1]; ! 1169: } ! 1170: ! 1171: if (sp >= pls->spTotal) ! 1172: { ! 1173: sp -= pls->spTotal; ! 1174: if (pls->cStyle & 1) ! 1175: pls->ulStyleMask = ~pls->ulStyleMask; ! 1176: } ! 1177: ! 1178: pls->psp = pls->pspStart; ! 1179: while (sp >= *pls->psp) ! 1180: sp -= *pls->psp++; ! 1181: ! 1182: ASSERTS3(pls->psp <= pls->pspEnd, ! 1183: "Flew off into NeverNeverLand"); ! 1184: ! 1185: pls->spRemaining = *pls->psp - sp; ! 1186: if ((pls->psp - pls->pspStart) & 1) ! 1187: pls->ulStyleMask = ~pls->ulStyleMask; ! 1188: } ! 1189: } ! 1190: } ! 1191: ! 1192: plStrip = &strip.alStrips[0]; ! 1193: plStripEnd = &strip.alStrips[STRIP_MAX]; // Is exclusive ! 1194: cStripsInNextRun = 0x7fffffff; ! 1195: ! 1196: strip.ptlStart = ptlStart; ! 1197: ! 1198: if (2 * dN > dM && ! 1199: !(fl & FL_STYLED) && // !!! Remove this! [andrewgo] ! 1200: !(fl & FL_DONT_DO_HALF_FLIP)) ! 1201: { ! 1202: // Do a half flip! Remember that we may doing this on the ! 1203: // same line multiple times for complex clipping (meaning the ! 1204: // affected variables should be reset for every clip run): ! 1205: ! 1206: fl |= FL_FLIP_HALF; ! 1207: ! 1208: eqBeta = eqGamma; ! 1209: eqBeta -= dM; ! 1210: ! 1211: dN = dM - dN; ! 1212: y0 = x0 - y0; // Note this may overflow, but that's okay ! 1213: } ! 1214: ! 1215: // Now, run the DDA starting at (ptlStart.x, ptlStart.y)! ! 1216: ! 1217: strip.flFlips = fl; ! 1218: pfn = apfn[(fl & FL_STRIP_MASK) >> FL_STRIP_SHIFT]; ! 1219: ! 1220: // Now calculate the DDA variables needed to figure out how many pixels ! 1221: // go in the very first strip: ! 1222: ! 1223: { ! 1224: register LONG i; ! 1225: register ULONG r; ! 1226: register ULONG dI; ! 1227: register ULONG dR; ! 1228: ! 1229: if (dN == 0) ! 1230: i = 0x7fffffff; ! 1231: else ! 1232: { ! 1233: euq.vMulInit(y0 + 1, dM); ! 1234: euq += eqBeta; ! 1235: ! 1236: #ifdef FIREWALLS ! 1237: if (euq.bNegative()) ! 1238: { ! 1239: RIP("Oops!"); ! 1240: } ! 1241: #endif ! 1242: ! 1243: i = euq.ulDiv(dN, &r) - x0 + 1; ! 1244: ! 1245: dI = dM / dN; ! 1246: dR = dM % dN; // 0 <= dR < dN ! 1247: ! 1248: ASSERTS3(dI > 0, "Weird dI"); ! 1249: } ! 1250: ! 1251: ASSERTS3(i > 0 && i <= 0x7fffffff, "Weird initial strip length"); ! 1252: ASSERTS3(cPels > 0, "Zero pel line"); ! 1253: ! 1254: /***********************************************************************\ ! 1255: * Run the DDA! * ! 1256: \***********************************************************************/ ! 1257: ! 1258: while(TRUE) ! 1259: { ! 1260: cPels -= i; ! 1261: if (cPels <= 0) ! 1262: break; ! 1263: ! 1264: *plStrip++ = i; ! 1265: ! 1266: if (plStrip == plStripEnd) ! 1267: { ! 1268: strip.cStrips = plStrip - &strip.alStrips[0]; ! 1269: (*pfn)(ppdev, &strip, pls); ! 1270: plStrip = &strip.alStrips[0]; ! 1271: } ! 1272: ! 1273: i = dI; ! 1274: r += dR; ! 1275: ! 1276: if (r >= dN) ! 1277: { ! 1278: r -= dN; ! 1279: i++; ! 1280: } ! 1281: } ! 1282: ! 1283: *plStrip++ = cPels + i; ! 1284: ! 1285: strip.cStrips = plStrip - &strip.alStrips[0]; ! 1286: (*pfn)(ppdev, &strip, pls); ! 1287: ! 1288: ! 1289: } ! 1290: ! 1291: Next_Line: ! 1292: ! 1293: if (fl & FL_COMPLEX_CLIP) ! 1294: { ! 1295: cptfx--; ! 1296: if (cptfx != 0) ! 1297: goto Continue_Complex_Clipping; ! 1298: ! 1299: break; ! 1300: } ! 1301: else ! 1302: { ! 1303: pptfxFirst = pptfxBuf; ! 1304: pptfxBuf++; ! 1305: } ! 1306: ! 1307: } while (pptfxBuf < pptfxBufEnd); ! 1308: ! 1309: return(TRUE); ! 1310: ! 1311: } ! 1312: ! 1313: #ifdef HARDWAREGIQ ! 1314: ! 1315: ///////////////////////////////////////////////////////////////////////// ! 1316: // The following GIQ code works great -- we simply aren't using it yet. ! 1317: ///////////////////////////////////////////////////////////////////////// ! 1318: ! 1319: typedef struct _DDALINE /* dl */ ! 1320: { ! 1321: LONG iDir; ! 1322: POINTL ptlStart; ! 1323: LONG cPels; ! 1324: LONG dMajor; ! 1325: LONG dMinor; ! 1326: LONG lErrorTerm; ! 1327: } DDALINE; ! 1328: ! 1329: #define HW_FLIP_D 0x0001L // Diagonal flip ! 1330: #define HW_FLIP_V 0x0002L // Vertical flip ! 1331: #define HW_FLIP_H 0x0004L // Horizontal flip ! 1332: #define HW_FLIP_SLOPE_ONE 0x0008L // Normalized line has exactly slope one ! 1333: #define HW_FLIP_MASK (HW_FLIP_D | HW_FLIP_V | HW_FLIP_H) ! 1334: ! 1335: #define HW_X_ROUND_DOWN 0x0100L // x = 1/2 rounds down in value ! 1336: #define HW_Y_ROUND_DOWN 0x0200L // y = 1/2 rounds down in value ! 1337: ! 1338: LONG gaiDir[] = { 0, 1, 7, 6, 3, 2, 4, 5 }; ! 1339: ! 1340: FLONG gaflHardwareRound[] = { ! 1341: HW_X_ROUND_DOWN | HW_Y_ROUND_DOWN, // | | | ! 1342: HW_X_ROUND_DOWN | HW_Y_ROUND_DOWN, // | | | FLIP_D ! 1343: HW_X_ROUND_DOWN, // | | FLIP_V | ! 1344: HW_Y_ROUND_DOWN, // | | FLIP_V | FLIP_D ! 1345: HW_Y_ROUND_DOWN, // | FLIP_H | | ! 1346: HW_X_ROUND_DOWN, // | FLIP_H | | FLIP_D ! 1347: 0, // | FLIP_H | FLIP_V | ! 1348: 0, // | FLIP_H | FLIP_V | FLIP_D ! 1349: HW_Y_ROUND_DOWN, // SLOPE_ONE | | | ! 1350: 0xffffffff, // SLOPE_ONE | | | FLIP_D ! 1351: HW_X_ROUND_DOWN, // SLOPE_ONE | | FLIP_V | ! 1352: 0xffffffff, // SLOPE_ONE | | FLIP_V | FLIP_D ! 1353: HW_Y_ROUND_DOWN, // SLOPE_ONE | FLIP_H | | ! 1354: 0xffffffff, // SLOPE_ONE | FLIP_H | | FLIP_D ! 1355: HW_X_ROUND_DOWN, // SLOPE_ONE | FLIP_H | FLIP_V | ! 1356: 0xffffffff // SLOPE_ONE | FLIP_H | FLIP_V | FLIP_D ! 1357: }; ! 1358: ! 1359: /******************************Public*Routine******************************\ ! 1360: * BOOL bHardwareLine(pptfxStart, pptfxEnd, cBits, pdl) ! 1361: * ! 1362: * This routine is useful for folks who have line drawing hardware where ! 1363: * they can explicitly set the Bresenham terms -- they can use this routine ! 1364: * to draw fractional coordinate GIQ lines with the hardware. ! 1365: * ! 1366: * Fractional coordinate lines require an extra 4 bits of precision in the ! 1367: * Bresenham terms. For example, if your hardware has 13 bits of precision ! 1368: * for the terms, you can only draw GIQ lines up to 255 pels long using this ! 1369: * routine. ! 1370: * ! 1371: * Input: ! 1372: * pptfxStart - Points to GIQ coordinate of start of line ! 1373: * pptfxEnd - Points to GIQ coordinate of end of line ! 1374: * cBits - The number of bits of precision your hardware can support. ! 1375: * ! 1376: * Output: ! 1377: * returns - TRUE if the line can be drawn directly using the line ! 1378: * hardware (in which case pdl contains the Bresenham terms ! 1379: * for drawing the line). ! 1380: * FALSE if the line is too long, and the strips code must be ! 1381: * used. ! 1382: * pdl - Returns the Bresenham line terms for drawing the line. ! 1383: * ! 1384: * DDALINE: ! 1385: * iDir - Direction of the line, as an octant numbered as follows: ! 1386: * ! 1387: * \ 5 | 6 / ! 1388: * \ | / ! 1389: * 4 \ | / 7 ! 1390: * \ / ! 1391: * -----+----- ! 1392: * /|\ ! 1393: * 3 / | \ 0 ! 1394: * / | \ ! 1395: * / 2 | 1 \ ! 1396: * ! 1397: * ptlStart - Start pixel of line. ! 1398: * cPels - # of pels in line. *NOTE* You must check if this is <= 0! ! 1399: * dMajor - Major axis delta. ! 1400: * dMinor - Minor axis delta. ! 1401: * lErrorTerm - Error term. ! 1402: * ! 1403: * What you do with the last 3 terms may be a little tricky. They are ! 1404: * actually the terms for the formula of the normalized line ! 1405: * ! 1406: * dMinor * x + (lErrorTerm + dMajor) ! 1407: * y(x) = floor( ---------------------------------- ) ! 1408: * dMajor ! 1409: * ! 1410: * where y(x) is the y coordinate of the pixel to be lit as a function of ! 1411: * the x-coordinate. ! 1412: * ! 1413: * Every time the line advances one in the major direction 'x', dMinor ! 1414: * gets added to the current error term. If the resulting value is >= 0, ! 1415: * we know we have to move one pixel in the minor direction 'y', and ! 1416: * dMajor must be subtracted from the current error term. ! 1417: * ! 1418: * If you're trying to figure out what this means for your hardware, you can ! 1419: * think of the DDALINE terms as having been computed equivalently as ! 1420: * follows: ! 1421: * ! 1422: * pdl->dMinor = 2 * (minor axis delta) ! 1423: * pdl->dMajor = 2 * (major axis delta) ! 1424: * pdl->lErrorTerm = - (major axis delta) - fixup ! 1425: * ! 1426: * That is, if your documentation tells you that for integer lines, a ! 1427: * register is supposed to be initialized with the value ! 1428: * '2 * (minor axis delta)', you'll actually use pdl->dMinor. ! 1429: * ! 1430: * Example: Setting up the 8514 ! 1431: * ! 1432: * AXSTPSIGN is supposed to be the axial step constant register, defined ! 1433: * as 2 * (minor axis delta). You set: ! 1434: * ! 1435: * AXSTPSIGN = pdl->dMinor ! 1436: * ! 1437: * DGSTPSIGN is supposed to be the diagonal step constant register, ! 1438: * defined as 2 * (minor axis delta) - 2 * (major axis delta). You set: ! 1439: * ! 1440: * DGSTPSIGN = pdl->dMinor - pdl->dMajor ! 1441: * ! 1442: * ERR_TERM is supposed to be the adjusted error term, defined as ! 1443: * 2 * (minor axis delta) - (major axis delta) - fixup. You set: ! 1444: * ! 1445: * ERR_TERM = pdl->lErrorTerm + pdl->dMinor ! 1446: * ! 1447: * Implementation: ! 1448: * ! 1449: * You'll want to special case integer lines before calling this routine ! 1450: * (since they're very common, take less time to the computation of line ! 1451: * terms, and can handle longer lines than this routine because 4 bits ! 1452: * aren't being given to the fraction). ! 1453: * ! 1454: * If a GIQ line is too long to be handled by this routine, you can just ! 1455: * use the slower strip routines for that line. Note that you cannot ! 1456: * just fail the call -- you must be able to accurately draw any line ! 1457: * in the 28.4 device space when it intersects the viewport. ! 1458: * ! 1459: * Testing: ! 1460: * ! 1461: * Use Guiman, or some other test that draws random fractional coordinate ! 1462: * lines and compares them to what GDI itself draws to a bitmap. ! 1463: * ! 1464: \**************************************************************************/ ! 1465: ! 1466: BOOL bHardwareLine( ! 1467: POINTFIX* pptfxStart, // Start of line ! 1468: POINTFIX* pptfxEnd, // End of line ! 1469: LONG cBits, // # bits precision in hardware Bresenham terms ! 1470: DDALINE* pdl) // Returns Bresenham terms for doing line ! 1471: { ! 1472: FLONG fl; // Various flags ! 1473: ULONG M0; // Normalized fractional unit x start coordinate (0 <= M0 < F) ! 1474: ULONG N0; // Normalized fractional unit y start coordinate (0 <= N0 < F) ! 1475: ULONG M1; // Normalized fractional unit x end coordinate (0 <= M1 < F) ! 1476: ULONG N1; // Normalized fractional unit x end coordinate (0 <= N1 < F) ! 1477: ULONG dM; // Normalized fractional unit x-delta (0 <= dM) ! 1478: ULONG dN; // Normalized fractional unit y-delta (0 <= dN <= dM) ! 1479: LONG x; // Normalized x coordinate of origin ! 1480: LONG y; // Normalized y coordinate of origin ! 1481: LONG x0; // Normalized x offset from origin to start pixel (inclusive) ! 1482: LONG y0; // Normalized y offset from origin to start pixel (inclusive) ! 1483: LONG x1; // Normalized x offset from origin to end pixel (inclusive) ! 1484: LONG lGamma;// Bresenham error term at origin ! 1485: ! 1486: /***********************************************************************\ ! 1487: * Normalize line to the first octant. ! 1488: \***********************************************************************/ ! 1489: ! 1490: fl = 0; ! 1491: ! 1492: M0 = pptfxStart->x; ! 1493: dM = pptfxEnd->x; ! 1494: ! 1495: if ((LONG) dM < (LONG) M0) ! 1496: { ! 1497: // Line runs from right to left, so flip across x = 0: ! 1498: ! 1499: M0 = -(LONG) M0; ! 1500: dM = -(LONG) dM; ! 1501: fl |= HW_FLIP_H; ! 1502: } ! 1503: ! 1504: // Compute the delta. The DDI says we can never have a valid delta ! 1505: // with a magnitude more than 2^31 - 1, but the engine never actually ! 1506: // checks its transforms. To ensure that we'll never puke on our shoes, ! 1507: // we check for that case and simply refuse to draw the line: ! 1508: ! 1509: dM -= M0; ! 1510: if ((LONG) dM < 0) ! 1511: return(FALSE); ! 1512: ! 1513: N0 = pptfxStart->y; ! 1514: dN = pptfxEnd->y; ! 1515: ! 1516: if ((LONG) dN < (LONG) N0) ! 1517: { ! 1518: // Line runs from bottom to top, so flip across y = 0: ! 1519: ! 1520: N0 = -(LONG) N0; ! 1521: dN = -(LONG) dN; ! 1522: fl |= HW_FLIP_V; ! 1523: } ! 1524: ! 1525: // Compute another delta: ! 1526: ! 1527: dN -= N0; ! 1528: if ((LONG) dN < 0) ! 1529: return(FALSE); ! 1530: ! 1531: if (dN >= dM) ! 1532: { ! 1533: if (dN == dM) ! 1534: { ! 1535: // Have to special case slopes of one: ! 1536: ! 1537: fl |= HW_FLIP_SLOPE_ONE; ! 1538: } ! 1539: else ! 1540: { ! 1541: // Since line has slope greater than 1, flip across x = y: ! 1542: ! 1543: register ULONG ulTmp; ! 1544: ulTmp = dM; dM = dN; dN = ulTmp; ! 1545: ulTmp = M0; M0 = N0; N0 = ulTmp; ! 1546: fl |= HW_FLIP_D; ! 1547: } ! 1548: } ! 1549: ! 1550: // Figure out if we can do the line in hardware, given that we have a ! 1551: // limited number of bits of precision for the Bresenham terms. ! 1552: // ! 1553: // Remember that one bit has to be kept as a sign bit: ! 1554: ! 1555: if ((LONG) dM >= (1L << (cBits - 1))) ! 1556: return(FALSE); ! 1557: ! 1558: fl |= gaflHardwareRound[fl]; ! 1559: ! 1560: /***********************************************************************\ ! 1561: * Calculate the error term at pixel 0. ! 1562: \***********************************************************************/ ! 1563: ! 1564: x = LFLOOR((LONG) M0); ! 1565: y = LFLOOR((LONG) N0); ! 1566: ! 1567: M0 = FXFRAC(M0); ! 1568: N0 = FXFRAC(N0); ! 1569: ! 1570: // NOTE NOTE NOTE: If this routine were to handle any line in the 28.4 ! 1571: // space, it will overflow its math (the following part requires 36 bits ! 1572: // of precision)! But we get here for lines that the hardware can handle ! 1573: // (see the expression (dM >= (1L << (cBits - 1))) above?), so if cBits ! 1574: // is less than 28, we're safe. ! 1575: // ! 1576: // If you're going to use this routine to handle all lines in the 28.4 ! 1577: // device space, you will HAVE to make sure the math doesn't overflow, ! 1578: // otherwise you won't be NT compliant! (See lines.cxx for an example ! 1579: // how to do that. You don't have to worry about this if you simply ! 1580: // default to the strips code for long lines, because those routines ! 1581: // already do the math correctly.) ! 1582: ! 1583: // Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]. Note ! 1584: // that M0 and N0 have at most 4 bits of significance (and if the ! 1585: // arguments are properly ordered, on a 486 each multiply would be no ! 1586: // more than 13 cycles): ! 1587: ! 1588: lGamma = (N0 + F/2) * dM - M0 * dN; ! 1589: ! 1590: if (fl & HW_Y_ROUND_DOWN) ! 1591: lGamma--; ! 1592: ! 1593: lGamma >>= FLOG2; ! 1594: ! 1595: /***********************************************************************\ ! 1596: * Figure out which pixels are at the ends of the line. ! 1597: \***********************************************************************/ ! 1598: ! 1599: // The toughest part of GIQ is determining the start and end pels. ! 1600: // ! 1601: // Our approach here is to calculate x0 and x1 (the inclusive start ! 1602: // and end columns of the line respectively, relative to our normalized ! 1603: // origin). Then x1 - x0 + 1 is the number of pels in the line. The ! 1604: // start point is easily calculated by plugging x0 into our line equation ! 1605: // (which takes care of whether y = 1/2 rounds up or down in value) ! 1606: // getting y0, and then undoing the normalizing flips to get back ! 1607: // into device space. ! 1608: // ! 1609: // We look at the fractional parts of the coordinates of the start and ! 1610: // end points, and call them (M0, N0) and (M1, N1) respectively, where ! 1611: // 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid ! 1612: // to determine x0: ! 1613: // ! 1614: // +-----------------------> +x ! 1615: // | ! 1616: // | 0 1 ! 1617: // | 0123456789abcdef ! 1618: // | ! 1619: // | 0 ........?xxxxxxx ! 1620: // | 1 ..........xxxxxx ! 1621: // | 2 ...........xxxxx ! 1622: // | 3 ............xxxx ! 1623: // | 4 .............xxx ! 1624: // | 5 ..............xx ! 1625: // | 6 ...............x ! 1626: // | 7 ................ ! 1627: // | 8 ................ ! 1628: // | 9 ......**........ ! 1629: // | a ........****...x ! 1630: // | b ............**** ! 1631: // | c .............xxx**** ! 1632: // | d ............xxxx **** ! 1633: // | e ...........xxxxx **** ! 1634: // | f ..........xxxxxx ! 1635: // | ! 1636: // | 2 3 ! 1637: // v ! 1638: // ! 1639: // +y ! 1640: // ! 1641: // This grid accounts for the appropriate rounding of GIQ and last-pel ! 1642: // exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands ! 1643: // on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down, ! 1644: // depending on what flips have been done to normalize the line. ! 1645: // ! 1646: // For the end point, if (M1, N1) lands on an 'x', x1 = ! 1647: // floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 = ! 1648: // floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down, ! 1649: // depending on what flips have been done to normalize the line. ! 1650: // ! 1651: // Lines of exactly slope one require a special case for both the start ! 1652: // and end. For example, if the line ends such that (M1, N1) is (9, 1), ! 1653: // the line has gone exactly through (8, 0) -- which may be considered ! 1654: // to be part of 'x' because of rounding! So slopes of exactly slope ! 1655: // one going through (8, 0) must also be considered as belonging in 'x' ! 1656: // when an x value of 1/2 is supposed to round up in value. ! 1657: ! 1658: // Calculate x0, x1: ! 1659: ! 1660: N1 = FXFRAC(N0 + dN); ! 1661: M1 = FXFRAC(M0 + dM); ! 1662: ! 1663: x1 = LFLOOR(M0 + dM); ! 1664: ! 1665: // Line runs left-to-right: ! 1666: ! 1667: // Compute x1: ! 1668: ! 1669: x1--; ! 1670: if (M1 > 0) ! 1671: { ! 1672: if (N1 == 0) ! 1673: { ! 1674: if (LROUND(M1, fl & HW_X_ROUND_DOWN)) ! 1675: x1++; ! 1676: } ! 1677: else if (ABS((LONG) (N1 - F/2)) <= (LONG) M1) ! 1678: { ! 1679: x1++; ! 1680: } ! 1681: } ! 1682: ! 1683: if ((fl & (HW_FLIP_SLOPE_ONE | HW_X_ROUND_DOWN)) ! 1684: == (HW_FLIP_SLOPE_ONE | HW_X_ROUND_DOWN)) ! 1685: { ! 1686: // Have to special-case diagonal lines going through our ! 1687: // the point exactly equidistant between two horizontal ! 1688: // pixels, if we're supposed to round x=1/2 down: ! 1689: ! 1690: if ((N1 > 0) && (M1 == N1 + 8)) ! 1691: x1--; ! 1692: ! 1693: if ((M0 > 0) && (N0 == M0 + 8)) ! 1694: { ! 1695: x0 = 0; ! 1696: goto left_to_right_compute_y0; ! 1697: } ! 1698: } ! 1699: ! 1700: // Compute x0: ! 1701: ! 1702: x0 = 0; ! 1703: if (M0 > 0) ! 1704: { ! 1705: if (N0 == 0) ! 1706: { ! 1707: if (LROUND(M0, fl & HW_X_ROUND_DOWN)) ! 1708: x0 = 1; ! 1709: } ! 1710: else if (ABS((LONG) (N0 - F/2)) <= (LONG) M0) ! 1711: { ! 1712: x0 = 1; ! 1713: } ! 1714: } ! 1715: ! 1716: left_to_right_compute_y0: ! 1717: ! 1718: /***********************************************************************\ ! 1719: * Calculate the start pixel. ! 1720: \***********************************************************************/ ! 1721: ! 1722: // We now compute y0 and adjust the error term. We know x0, and we know ! 1723: // the current formula for the pixels to be lit on the line: ! 1724: // ! 1725: // dN * x + lGamma ! 1726: // y(x) = floor( --------------- ) ! 1727: // dM ! 1728: // ! 1729: // The remainder of this expression is the new error term at (x0, y0). ! 1730: // Since x0 is going to be either 0 or 1, we don't actually have to do a ! 1731: // multiply or divide to compute y0. Finally, we subtract dM from the ! 1732: // new error term so that it is in the range [-dM, 0). ! 1733: ! 1734: y0 = 0; ! 1735: lGamma += (dN & (-x0)); ! 1736: lGamma -= dM; ! 1737: if (lGamma >= 0) ! 1738: { ! 1739: y0 = 1; ! 1740: lGamma -= dM; ! 1741: } ! 1742: ! 1743: // Undo our flips to get the start coordinate: ! 1744: ! 1745: x += x0; ! 1746: y += y0; ! 1747: ! 1748: if (fl & HW_FLIP_D) ! 1749: { ! 1750: register LONG lTmp; ! 1751: lTmp = x; x = y; y = lTmp; ! 1752: } ! 1753: ! 1754: if (fl & HW_FLIP_V) ! 1755: { ! 1756: y = -y; ! 1757: } ! 1758: ! 1759: if (fl & HW_FLIP_H) ! 1760: { ! 1761: x = -x; ! 1762: } ! 1763: ! 1764: /***********************************************************************\ ! 1765: * Return the Bresenham terms: ! 1766: \***********************************************************************/ ! 1767: ! 1768: pdl->iDir = gaiDir[fl & HW_FLIP_MASK]; ! 1769: pdl->ptlStart.x = x; ! 1770: pdl->ptlStart.y = y; ! 1771: pdl->cPels = x1 - x0 + 1; // NOTE: You'll have to check if cPels <= 0! ! 1772: pdl->dMajor = dM; ! 1773: pdl->dMinor = dN; ! 1774: pdl->lErrorTerm = lGamma; ! 1775: ! 1776: return(TRUE); ! 1777: } ! 1778: ! 1779: #endif // HARDWAREGIQ
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.