|
|
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.