Annotation of ntddk/src/video/displays/vga256/i386/lines.asm, revision 1.1

1.1     ! root        1: ;---------------------------Module-Header------------------------------;
        !             2: ; Module Name: lines.asm
        !             3: ;
        !             4: ; Draws a set of connected polylines.
        !             5: ;
        !             6: ; The actual pixel-lighting code is different depending on if the lines
        !             7: ; are styled/unstyled and we're doing an arbitrary ROP or set-style ROP.
        !             8: ;
        !             9: ; Lines are drawn from left to right.  So if a line moves from right
        !            10: ; to left, the endpoints are swapped and the line is drawn from left to
        !            11: ; right.
        !            12: ;
        !            13: ; See s3\lines.cxx for a portable version (sans simple clipping).
        !            14: ;
        !            15: ; Copyright (c) 1992 Microsoft Corporation
        !            16: ;-----------------------------------------------------------------------;
        !            17: 
        !            18:         .386
        !            19: 
        !            20:         .model  small,c
        !            21: 
        !            22:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        !            23:         assume fs:nothing,gs:nothing
        !            24: 
        !            25:         .xlist
        !            26:         include stdcall.inc             ;calling convention cmacros
        !            27:         include i386\egavga.inc
        !            28:         include i386\strucs.inc
        !            29:         include i386\driver.inc
        !            30:         include i386\lines.inc
        !            31:         .list
        !            32: 
        !            33:         .data
        !            34: 
        !            35:         public gaflRoundTable
        !            36: gaflRoundTable       label  dword
        !            37:         dd      FL_H_ROUND_DOWN + FL_V_ROUND_DOWN       ; no flips
        !            38:         dd      FL_H_ROUND_DOWN + FL_V_ROUND_DOWN       ; D flip
        !            39:         dd      FL_H_ROUND_DOWN                         ; V flip
        !            40:         dd      FL_V_ROUND_DOWN                         ; D & V flip
        !            41:         dd      FL_V_ROUND_DOWN                         ; slope one
        !            42:         dd      0baadf00dh
        !            43:         dd      FL_H_ROUND_DOWN                         ; slope one & V flip
        !            44:         dd      0baadf00dh
        !            45: 
        !            46:         .code
        !            47: 
        !            48: ;--------------------------------Macro----------------------------------;
        !            49: ; testb ebx, <mask>
        !            50: ;
        !            51: ; Substitutes a byte compare if the mask is entirely in the lo-byte or
        !            52: ; hi-byte (thus saving 3 bytes of code space).
        !            53: ;
        !            54: ;-----------------------------------------------------------------------;
        !            55: 
        !            56: TESTB   macro   targ,mask,thirdarg
        !            57:         local   mask2,delta
        !            58: 
        !            59: ifnb <thirdarg>
        !            60:         .err    TESTB mask must be enclosed in brackets!
        !            61: endif
        !            62: 
        !            63:         delta = 0
        !            64:         mask2 = mask
        !            65: 
        !            66:         if mask2 AND 0ffff0000h
        !            67:             test targ,mask                      ; If bit set in hi-word,
        !            68:             exitm                               ; test entire dword
        !            69:         endif
        !            70: 
        !            71:         if mask2 AND 0ff00h
        !            72:             if mask2 AND 0ffh                   ; If bit set in lo-byte and
        !            73:                 test targ,mask                  ; hi-byte, test entire dword
        !            74:                 exitm
        !            75:             endif
        !            76: 
        !            77:             mask2 = mask2 SHR 8
        !            78:             delta = 1
        !            79:         endif
        !            80: 
        !            81: ifidni <targ>,<EBX>
        !            82:         if delta
        !            83:             test bh,mask2
        !            84:         else
        !            85:             test bl,mask2
        !            86:         endif
        !            87:         exitm
        !            88: endif
        !            89: 
        !            90:         .err    Too bad TESTB doesn't support targets other than ebx!
        !            91: endm
        !            92: 
        !            93: ;---------------------------Public-Routine------------------------------;
        !            94: ; BOOL bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
        !            95: ;        prclClip, apfn[], flStart)
        !            96: ;
        !            97: ; Do all the DDA calculations for lines.
        !            98: ;
        !            99: ; Doing Lines Right
        !           100: ; -----------------
        !           101: ;
        !           102: ; In NT, all lines are given to the device driver in fractional
        !           103: ; coordinates, in a 28.4 fixed point format.  The lower 4 bits are
        !           104: ; fractional for sub-pixel positioning.
        !           105: ;
        !           106: ; Note that you CANNOT! just round the coordinates to integers
        !           107: ; and pass the results to your favorite integer Bresenham routine!!
        !           108: ; (Unless, of course, you have such a high resolution device that
        !           109: ; nobody will notice -- not likely for a display device.)  The
        !           110: ; fractions give a more accurate rendering of the line -- this is
        !           111: ; important for things like our Bezier curves, which would have 'kinks'
        !           112: ; if the points in its polyline approximation were rounded to integers.
        !           113: ;
        !           114: ; Unfortunately, for fractional lines there is more setup work to do
        !           115: ; a DDA than for integer lines.  However, the main loop is exactly
        !           116: ; the same (and can be done entirely with 32 bit math).
        !           117: ;
        !           118: ; If You've Got Hardware That Does Bresenham
        !           119: ; ------------------------------------------
        !           120: ;
        !           121: ; A lot of hardware limits DDA error terms to 'n' bits.  With fractional
        !           122: ; coordinates, 4 bits are given to the fractional part, letting
        !           123: ; you draw in hardware only those lines that lie entirely in a 2^(n-4)
        !           124: ; by 2^(n-4) pixel space.
        !           125: ;
        !           126: ; And you still have to correctly draw those lines with coordinates
        !           127: ; outside that space!  Remember that the screen is only a viewport
        !           128: ; onto a 28.4 by 28.4 space -- if any part of the line is visible
        !           129: ; you MUST render it precisely, regardless of where the end points lie.
        !           130: ; So even if you do it in software, somewhere you'll have to have a
        !           131: ; 32 bit DDA routine.
        !           132: ;
        !           133: ; Our Implementation
        !           134: ; ------------------
        !           135: ;
        !           136: ; We employ a run length slice algorithm: our DDA calculates the
        !           137: ; number of pixels that are in each row (or 'strip') of pixels.
        !           138: ;
        !           139: ; We've separated the running of the DDA and the drawing of pixels:
        !           140: ; we run the DDA for several iterations and store the results in
        !           141: ; a 'strip' buffer (which are the lengths of consecutive pixel rows of
        !           142: ; the line), then we crank up a 'strip drawer' that will draw all the
        !           143: ; strips in the buffer.
        !           144: ;
        !           145: ; We also employ a 'half-flip' to reduce the number of strip
        !           146: ; iterations we need to do in the DDA and strip drawing loops: when a
        !           147: ; (normalized) line's slope is more than 1/2, we do a final flip
        !           148: ; about the line y = (1/2)x.  So now, instead of each strip being
        !           149: ; consecutive horizontal or vertical pixel rows, each strip is composed
        !           150: ; of those pixels aligned in 45 degree rows.  So a line like (0, 0) to
        !           151: ; (128, 128) would generate only one strip.
        !           152: ;
        !           153: ; We also always draw only left-to-right.
        !           154: ;
        !           155: ; Style lines may have arbitrary style patterns.  We specially
        !           156: ; optimize the default patterns (and call them 'masked' styles).
        !           157: ;
        !           158: ; The DDA Derivation
        !           159: ; ------------------
        !           160: ;
        !           161: ; Here is how I like to think of the DDA calculation.
        !           162: ;
        !           163: ; We employ Knuth's "diamond rule": rendering a one-pixel-wide line
        !           164: ; can be thought of as dragging a one-pixel-wide by one-pixel-high
        !           165: ; diamond along the true line.  Pixel centers lie on the integer
        !           166: ; coordinates, and so we light any pixel whose center gets covered
        !           167: ; by the "drag" region (John D. Hobby, Journal of the Association
        !           168: ; for Computing Machinery, Vol. 36, No. 2, April 1989, pp. 209-229).
        !           169: ;
        !           170: ; We must define which pixel gets lit when the true line falls
        !           171: ; exactly half-way between two pixels.  In this case, we follow
        !           172: ; the rule: when two pels are equidistant, the upper or left pel
        !           173: ; is illuminated, unless the slope is exactly one, in which case
        !           174: ; the upper or right pel is illuminated.  (So we make the edges
        !           175: ; of the diamond exclusive, except for the top and left vertices,
        !           176: ; which are inclusive, unless we have slope one.)
        !           177: ;
        !           178: ; This metric decides what pixels should be on any line BEFORE it is
        !           179: ; flipped around for our calculation.  Having a consistent metric
        !           180: ; this way will let our lines blend nicely with our curves.  The
        !           181: ; metric also dictates that we will never have one pixel turned on
        !           182: ; directly above another that's turned on.  We will also never have
        !           183: ; a gap; i.e., there will be exactly one pixel turned on for each
        !           184: ; column between the start and end points.  All that remains to be
        !           185: ; done is to decide how many pixels should be turned on for each row.
        !           186: ;
        !           187: ; So lines we draw will consist of varying numbers of pixels on
        !           188: ; successive rows, for example:
        !           189: ;
        !           190: ;       ******
        !           191: ;             *****
        !           192: ;                  ******
        !           193: ;                        *****
        !           194: ;
        !           195: ; We'll call each set of pixels on a row a "strip".
        !           196: ;
        !           197: ; (Please remember that our coordinate space has the origin as the
        !           198: ; upper left pixel on the screen; postive y is down and positive x
        !           199: ; is right.)
        !           200: ;
        !           201: ; Device coordinates are specified as fixed point 28.4 numbers,
        !           202: ; where the first 28 bits are the integer coordinate, and the last
        !           203: ; 4 bits are the fraction.  So coordinates may be thought of as
        !           204: ; having the form (x, y) = (M/F, N/F) where F is the constant scaling
        !           205: ; factor F = 2^4 = 16, and M and N are 32 bit integers.
        !           206: ;
        !           207: ; Consider the line from (M0/F, N0/F) to (M1/F, N1/F) which runs
        !           208: ; left-to-right and whose slope is in the first octant, and let
        !           209: ; dM = M1 - M0 and dN = N1 - N0.  Then dM >= 0, dN >= 0 and dM >= dN.
        !           210: ;
        !           211: ; Since the slope of the line is less than 1, the edges of the
        !           212: ; drag region are created by the top and bottom vertices of the
        !           213: ; diamond.  At any given pixel row y of the line, we light those
        !           214: ; pixels whose centers are between the left and right edges.
        !           215: ;
        !           216: ; Let mL(n) denote the line representing the left edge of the drag
        !           217: ; region.  On pixel row j, the column of the first pixel to be
        !           218: ; lit is
        !           219: ;
        !           220: ;       iL(j) = ceiling( mL(j * F) / F)
        !           221: ;
        !           222: ; Since the line's slope is less than one:
        !           223: ;
        !           224: ;       iL(j) = ceiling( mL([j + 1/2] F) / F )
        !           225: ;
        !           226: ; Recall the formula for our line:
        !           227: ;
        !           228: ;       n(m) = (dN / dM) (m - M0) + N0
        !           229: ;
        !           230: ;       m(n) = (dM / dN) (n - N0) + M0
        !           231: ;
        !           232: ; Since the line's slope is less than one, the line representing
        !           233: ; the left edge of the drag region is the original line offset
        !           234: ; by 1/2 pixel in the y direction:
        !           235: ;
        !           236: ;       mL(n) = (dM / dN) (n - F/2 - N0) + M0
        !           237: ;
        !           238: ; From this we can figure out the column of the first pixel that
        !           239: ; will be lit on row j, being careful of rounding (if the left
        !           240: ; edge lands exactly on an integer point, the pixel at that
        !           241: ; point is not lit because of our rounding convention):
        !           242: ;
        !           243: ;       iL(j) = floor( mL(j F) / F ) + 1
        !           244: ;
        !           245: ;             = floor( ((dM / dN) (j F - F/2 - N0) + M0) / F ) + 1
        !           246: ;
        !           247: ;             = floor( F dM j - F/2 dM - N0 dM + dN M0) / F dN ) + 1
        !           248: ;
        !           249: ;                      F dM j - [ dM (N0 + F/2) - dN M0 ]
        !           250: ;             = floor( ---------------------------------- ) + 1
        !           251: ;                                   F dN
        !           252: ;
        !           253: ;                      dM j - [ dM (N0 + F/2) - dN M0 ] / F
        !           254: ;             = floor( ------------------------------------ ) + 1       (1)
        !           255: ;                                     dN
        !           256: ;
        !           257: ;             = floor( (dM j + alpha) / dN ) + 1
        !           258: ;
        !           259: ; where
        !           260: ;
        !           261: ;       alpha = - [ dM (N0 + F/2) - dN M0 ] / F
        !           262: ;
        !           263: ; We use equation (1) to calculate the DDA: there are iL(j+1) - iL(j)
        !           264: ; pixels in row j.  Because we are always calculating iL(j) for
        !           265: ; integer quantities of j, we note that the only fractional term
        !           266: ; is constant, and so we can 'throw away' the fractional bits of
        !           267: ; alpha:
        !           268: ;
        !           269: ;       beta = floor( - [ dM (N0 + F/2) - dN M0 ] / F )                 (2)
        !           270: ;
        !           271: ; so
        !           272: ;
        !           273: ;       iL(j) = floor( (dM j + beta) / dN ) + 1                         (3)
        !           274: ;
        !           275: ; for integers j.
        !           276: ;
        !           277: ; Note if iR(j) is the line's rightmost pixel on row j, that
        !           278: ; iR(j) = iL(j + 1) - 1.
        !           279: ;
        !           280: ; Similarly, rewriting equation (1) as a function of column i,
        !           281: ; we can determine, given column i, on which pixel row j is the line
        !           282: ; lit:
        !           283: ;
        !           284: ;                       dN i + [ dM (N0 + F/2) - dN M0 ] / F
        !           285: ;       j(i) = ceiling( ------------------------------------ ) - 1
        !           286: ;                                       dM
        !           287: ;
        !           288: ; Floors are easier to compute, so we can rewrite this:
        !           289: ;
        !           290: ;                     dN i + [ dM (N0 + F/2) - dN M0 ] / F + dM - 1/F
        !           291: ;       j(i) = floor( ----------------------------------------------- ) - 1
        !           292: ;                                       dM
        !           293: ;
        !           294: ;                     dN i + [ dM (N0 + F/2) - dN M0 ] / F + dM - 1/F - dM
        !           295: ;            = floor( ---------------------------------------------------- )
        !           296: ;                                       dM
        !           297: ;
        !           298: ;                     dN i + [ dM (N0 + F/2) - dN M0 - 1 ] / F
        !           299: ;            = floor( ---------------------------------------- )
        !           300: ;                                       dM
        !           301: ;
        !           302: ; We can once again wave our hands and throw away the fractional bits
        !           303: ; of the remainder term:
        !           304: ;
        !           305: ;       j(i) = floor( (dN i + gamma) / dM )                             (4)
        !           306: ;
        !           307: ; where
        !           308: ;
        !           309: ;       gamma = floor( [ dM (N0 + F/2) - dN M0 - 1 ] / F )              (5)
        !           310: ;
        !           311: ; We now note that
        !           312: ;
        !           313: ;       beta = -gamma - 1 = ~gamma                                      (6)
        !           314: ;
        !           315: ; To draw the pixels of the line, we could evaluate (3) on every scan
        !           316: ; line to determine where the strip starts.  Of course, we don't want
        !           317: ; to do that because that would involve a multiply and divide for every
        !           318: ; scan.  So we do everything incrementally.
        !           319: ;
        !           320: ; We would like to easily compute c , the number of pixels on scan j:
        !           321: ;                                  j
        !           322: ;
        !           323: ;    c  = iL(j + 1) - iL(j)
        !           324: ;     j
        !           325: ;
        !           326: ;       = floor((dM (j + 1) + beta) / dN) - floor((dM j + beta) / dN)   (7)
        !           327: ;
        !           328: ; This may be rewritten as
        !           329: ;
        !           330: ;    c  = floor(i    + r    / dN) - floor(i  + r  / dN)                 (8)
        !           331: ;     j          j+1    j+1                j    j
        !           332: ;
        !           333: ; where i , i    are integers and r  < dN, r    < dN.
        !           334: ;        j   j+1                   j        j+1
        !           335: ;
        !           336: ; Rewriting (7) again:
        !           337: ;
        !           338: ;    c  = floor(i  + r  / dN + dM / dN) - floor(i  + r  / dN)
        !           339: ;     j          j    j                          j    j
        !           340: ;
        !           341: ;
        !           342: ;       = floor((r  + dM) / dN) - floor(r  / dN)
        !           343: ;                 j                      j
        !           344: ;
        !           345: ; This may be rewritten as
        !           346: ;
        !           347: ;    c  = dI + floor((r  + dR) / dN) - floor(r  / dN)
        !           348: ;     j                j                      j
        !           349: ;
        !           350: ; where dI + dR / dN = dM / dN, dI is an integer and dR < dN.
        !           351: ;
        !           352: ; r  is the remainder (or "error") term in the DDA loop: r  / dN
        !           353: ;  j                                                      j
        !           354: ; is the exact fraction of a pixel at which the strip ends.  To go
        !           355: ; on to the next scan and compute c    we need to know r   .
        !           356: ;                                  j+1                  j+1
        !           357: ;
        !           358: ; So in the main loop of the DDA:
        !           359: ;
        !           360: ;    c  = dI + floor((r  + dR) / dN) and r    = (r  + dR) % dN
        !           361: ;     j                j                  j+1     j
        !           362: ;
        !           363: ; and we know r  < dN, r    < dN, and dR < dN.
        !           364: ;              j        j+1
        !           365: ;
        !           366: ; We have derived the DDA only for lines in the first octant; to
        !           367: ; handle other octants we do the common trick of flipping the line
        !           368: ; to the first octant by first making the line left-to-right by
        !           369: ; exchanging the end-points, then flipping about the lines y = 0 and
        !           370: ; y = x, as necessary.  We must record the transformation so we can
        !           371: ; undo them later.
        !           372: ;
        !           373: ; We must also be careful of how the flips affect our rounding.  If
        !           374: ; to get the line to the first octant we flipped about x = 0, we now
        !           375: ; have to be careful to round a y value of 1/2 up instead of down as
        !           376: ; we would for a line originally in the first octant (recall that
        !           377: ; "In the case where two pels are equidistant, the upper or left
        !           378: ; pel is illuminated...").
        !           379: ;
        !           380: ; To account for this rounding when running the DDA, we shift the line
        !           381: ; (or not) in the y direction by the smallest amount possible.  That
        !           382: ; takes care of rounding for the DDA, but we still have to be careful
        !           383: ; about the rounding when determining the first and last pixels to be
        !           384: ; lit in the line.
        !           385: ;
        !           386: ; Determining The First And Last Pixels In The Line
        !           387: ; -------------------------------------------------
        !           388: ;
        !           389: ; Fractional coordinates also make it harder to determine which pixels
        !           390: ; will be the first and last ones in the line.  We've already taken
        !           391: ; the fractional coordinates into account in calculating the DDA, but
        !           392: ; the DDA cannot tell us which are the end pixels because it is quite
        !           393: ; happy to calculate pixels on the line from minus infinity to positive
        !           394: ; infinity.
        !           395: ;
        !           396: ; The diamond rule determines the start and end pixels.  (Recall that
        !           397: ; the sides are exclusive except for the left and top vertices.)
        !           398: ; This convention can be thought of in another way: there are diamonds
        !           399: ; around the pixels, and wherever the true line crosses a diamond,
        !           400: ; that pel is illuminated.
        !           401: ;
        !           402: ; Consider a line where we've done the flips to the first octant, and the
        !           403: ; floor of the start coordinates is the origin:
        !           404: ;
        !           405: ;        +-----------------------> +x
        !           406: ;        |
        !           407: ;        | 0                     1
        !           408: ;        |     0123456789abcdef
        !           409: ;        |
        !           410: ;        |   0 00000000?1111111
        !           411: ;        |   1 00000000 1111111
        !           412: ;        |   2 0000000   111111
        !           413: ;        |   3 000000     11111
        !           414: ;        |   4 00000    ** 1111
        !           415: ;        |   5 0000       ****1
        !           416: ;        |   6 000           1***
        !           417: ;        |   7 00             1  ****
        !           418: ;        |   8 ?                     ***
        !           419: ;        |   9 22             3         ****
        !           420: ;        |   a 222           33             ***
        !           421: ;        |   b 2222         333                ****
        !           422: ;        |   c 22222       3333                    **
        !           423: ;        |   d 222222     33333
        !           424: ;        |   e 2222222   333333
        !           425: ;        |   f 22222222 3333333
        !           426: ;        |
        !           427: ;        | 2                     3
        !           428: ;        v
        !           429: ;        +y
        !           430: ;
        !           431: ; If the start of the line lands on the diamond around pixel 0 (shown by
        !           432: ; the '0' region here), pixel 0 is the first pel in the line.  The same
        !           433: ; is true for the other pels.
        !           434: ;
        !           435: ; A little more work has to be done if the line starts in the
        !           436: ; 'nether-land' between the diamonds (as illustrated by the '*' line):
        !           437: ; the first pel lit is the first diamond crossed by the line (pixel 1 in
        !           438: ; our example).  This calculation is determined by the DDA or slope of
        !           439: ; the line.
        !           440: ;
        !           441: ; If the line starts exactly half way between two adjacent pixels
        !           442: ; (denoted here by the '?' spots), the first pixel is determined by our
        !           443: ; round-down convention (and is dependent on the flips done to
        !           444: ; normalize the line).
        !           445: ;
        !           446: ; Last Pel Exclusive
        !           447: ; ------------------
        !           448: ;
        !           449: ; To eliminate repeatedly lit pels between continuous connected lines,
        !           450: ; we employ a last-pel exclusive convention: if the line ends exactly on
        !           451: ; the diamond around a pel, that pel is not lit.  (This eliminates the
        !           452: ; checks we had in the old code to see if we were re-lighting pels.)
        !           453: ;
        !           454: ; The Half Flip
        !           455: ; -------------
        !           456: ;
        !           457: ; To make our run length algorithm more efficient, we employ a "half
        !           458: ; flip".  If after normalizing to the first octant, the slope is more
        !           459: ; than 1/2, we subtract the y coordinate from the x coordinate.  This
        !           460: ; has the effect of reflecting the coordinates through the line of slope
        !           461: ; 1/2.  Note that the diagonal gets mapped into the x-axis after a half
        !           462: ; flip.
        !           463: ;
        !           464: ; How Many Bits Do We Need, Anyway?
        !           465: ; ---------------------------------
        !           466: ;
        !           467: ; Note that if the line is visible on your screen, you must light up
        !           468: ; exactly the correct pixels, no matter where in the 28.4 x 28.4 device
        !           469: ; space the end points of the line lie (meaning you must handle 32 bit
        !           470: ; DDAs, you can certainly have optimized cases for lesser DDAs).
        !           471: ;
        !           472: ; We move the origin to (floor(M0 / F), floor(N0 / F)), so when we
        !           473: ; calculate gamma from (5), we know that 0 <= M0, N0 < F.  And we
        !           474: ; are in the first octant, so dM >= dN.  Then we know that gamma can
        !           475: ; be in the range [(-1/2)dM, (3/2)dM].  The DDI guarantees us that
        !           476: ; valid lines will have dM and dN values at most 31 bits (unsigned)
        !           477: ; of significance.  So gamma requires 33 bits of significance (we store
        !           478: ; this as a 64 bit number for convenience).
        !           479: ;
        !           480: ; When running through the DDA loop, r  + dR can have a value in the
        !           481: ;                                     j
        !           482: ; range 0 <= r  < 2 dN; thus the result must be a 32 bit unsigned value.
        !           483: ;             j
        !           484: ;
        !           485: ; Testing Lines
        !           486: ; -------------
        !           487: ;
        !           488: ; To be NT compliant, a display driver must exactly adhere to GIQ,
        !           489: ; which means that for any given line, the driver must light exactly
        !           490: ; the same pels as does GDI.  This can be tested using the Guiman tool
        !           491: ; provided elsewhere in the DDK, and 'ZTest', which draws random lines
        !           492: ; on the screen and to a bitmap, and compares the results.
        !           493: ;
        !           494: ; If You've Got Line Hardware
        !           495: ; ---------------------------
        !           496: ;
        !           497: ; If your hardware already adheres to GIQ, you're all set.  Otherwise
        !           498: ; you'll want to look at the S3 sample code and read the following:
        !           499: ;
        !           500: ; 1) You'll want to special case integer-only lines, since they require
        !           501: ;    less processing time and are more common (CAD programs will probably
        !           502: ;    only ever give integer lines).  GDI does not provide a flag saying
        !           503: ;    that all lines in a path are integer lines; consequently, you will
        !           504: ;    have to explicitly check every line.
        !           505: ;
        !           506: ; 2) You are required to correctly draw any line in the 28.4 device
        !           507: ;    space that intersects the viewport.  If you have less than 32 bits
        !           508: ;    of significance in the hardware for the Bresenham terms, extremely
        !           509: ;    long lines would overflow the hardware.  For such (rare) cases, you
        !           510: ;    can fall back to strip-drawing code, of which there is a C version in
        !           511: ;    the S3's lines.cxx (or if your display is a frame buffer, fall back
        !           512: ;    to the engine).
        !           513: ;
        !           514: ; 3) If you can explicitly set the Bresenham terms in your hardware, you
        !           515: ;    can draw non-integer lines using the hardware.  If your hardware has
        !           516: ;    'n' bits of precision, you can draw GIQ lines that are up to 2^(n-5)
        !           517: ;    pels long (4 bits are required for the fractional part, and one bit is
        !           518: ;    used as a sign bit).  Note that integer lines don't require the 4
        !           519: ;    fractional bits, so if you special case them as in 1), you can do
        !           520: ;    integer lines that are up to 2^(n - 1) pels long.  See the S3's
        !           521: ;    fastline.asm for an example.
        !           522: ;
        !           523: ;-----------------------------------------------------------------------;
        !           524: 
        !           525: cProc   bLines,36,< \
        !           526:     uses esi edi ebx,  \
        !           527:     ppdev:     ptr,   \
        !           528:     pptfxFirst: ptr,   \
        !           529:     pptfxBuf:   ptr,   \
        !           530:     prun:       ptr,   \
        !           531:     cptfx:      dword, \
        !           532:     pls:        ptr,   \
        !           533:     prclClip:   ptr,   \
        !           534:     apfn:       ptr,   \
        !           535:     flStart:    dword  >
        !           536: 
        !           537: ; ppdev:     Surface data
        !           538: ; pptfxFirst: Start point of first line
        !           539: ; pptfxBuf:   All subsequent points
        !           540: ; prun:       Array of runs if doing complex clipping
        !           541: ; cptfx:      Number of points in pptfxBuf (i.e., # lines)
        !           542: ; pls:        Line state
        !           543: ; prclClip:   Clip rectangle if doing simple clipping
        !           544: ; apfn:       Pointer to table of strip drawers
        !           545: ; flStart:    Flags for all lines
        !           546: 
        !           547:         local cPelsAfterThisBank:    dword ; For bank switching
        !           548:         local cStripsInNextRun:      dword ; For bank switching
        !           549:         local pptfxBufEnd:           ptr   ; Last point in pptfxBuf
        !           550:         local M0:                    dword ; Normalized x0 in device coords
        !           551:         local dM:                    dword ; Delta-x in device coords
        !           552:         local N0:                    dword ; Normalized y0 in device coords
        !           553:         local dN:                    dword ; Delta-y in device coords
        !           554:         local fl:                    dword ; Flags for current line
        !           555:         local x:                     dword ; Normalized start pixel x-coord
        !           556:         local y:                     dword ; Normalized start pixel y-coord
        !           557:         local eqGamma_lo:            dword ; Upper 32 bits of Gamma
        !           558:         local eqGamma_hi:            dword ; Lower 32 bits of Gamma
        !           559:         local x0:                    dword ; Start pixel x-offset
        !           560:         local y0:                    dword ; Start pixel y-offset
        !           561:         local ulSlopeOneAdjustment:  dword ; Special offset if line of slope 1
        !           562:         local cStylePels:            dword ; # of pixels in line (before clip)
        !           563:         local xStart:                dword ; Start pixel x-offset before clip
        !           564:         local pfn:                   ptr   ; Pointer to strip drawing function
        !           565:         local cPels:                 dword ; # pixels to be drawn (after clip)
        !           566:         local i:                     dword ; # pixels in strip
        !           567:         local r:                     dword ; Remainder (or "error") term
        !           568:         local d_I:                   dword ; Delta-I
        !           569:         local d_R:                   dword ; Delta-R
        !           570:         local plStripEnd:            ptr   ; Last strip in buffer
        !           571:         local ptlStart[size POINTL]: byte  ; Unnormalized start coord
        !           572:         local dN_Original:           dword ; dN before half-flip
        !           573:         local xClipLeft:             dword ; Left side of clip rectangle
        !           574:         local xClipRight:            dword ; Right side of clip rectangle
        !           575:         local strip[size STRIPS]:    byte  ; Our strip buffer
        !           576: 
        !           577: ; Do some initializing:
        !           578: 
        !           579:         mov     esi, pls
        !           580:         mov     ecx, cptfx
        !           581:         mov     edx, pptfxBuf
        !           582:         lea     eax, [edx + ecx * (size POINTL) - (size POINTL)]
        !           583:         mov     pptfxBufEnd, eax        ; pptfxBufEnd is inclusive of end point
        !           584: 
        !           585:         mov     eax, [esi].LS_chAndXor  ; copy chAndXor from LINESTATE to STRIPS
        !           586:         mov     strip.ST_chAndXor, eax  ;   buffer
        !           587: 
        !           588:         mov     eax, [edx].ptl_x        ; Load up end point (M1, N1)
        !           589:         mov     edi, [edx].ptl_y
        !           590: 
        !           591:         mov     edx, pptfxFirst         ; Load up start point (M0, N0)
        !           592:         mov     esi, [edx].ptl_x
        !           593:         mov     ecx, [edx].ptl_y
        !           594: 
        !           595:         mov     ebx, flStart
        !           596: 
        !           597: ;-----------------------------------------------------------------------;
        !           598: ; Flip to the first octant.                                             ;
        !           599: ;-----------------------------------------------------------------------;
        !           600: 
        !           601: ; Register state:       esi = M0
        !           602: ;                       ecx = N0
        !           603: ;                       eax = dM (M1)
        !           604: ;                       edi = dN (N1)
        !           605: ;                       ebx = fl
        !           606: 
        !           607: ; Make sure we go left to right:
        !           608: 
        !           609:         public  the_main_loop
        !           610: the_main_loop:
        !           611:         cmp     esi, eax
        !           612:         jle     short is_left_to_right  ; skip if M0 <= M1
        !           613:         xchg    esi, eax                ; swap M0, M1
        !           614:         xchg    ecx, edi                ; swap N0, N1
        !           615:         or      ebx, FL_FLIP_H
        !           616: 
        !           617: is_left_to_right:
        !           618: 
        !           619: ; Compute the deltas, remembering that the DDI says we should get
        !           620: ; deltas less than 2^31.  If we get more, we ensure we don't crash
        !           621: ; later on by simply skipping the line:
        !           622: 
        !           623:         sub     eax, esi                ; eax = dM
        !           624:         jo      next_line               ; dM must be less than 2^31
        !           625:         sub     edi, ecx                ; edi = dN
        !           626:         jo      next_line               ; dN must be less than 2^31
        !           627: 
        !           628:         jge     short is_top_to_bottom  ; skip if dN >= 0
        !           629:         neg     ecx                     ; N0 = -N0
        !           630:         neg     edi                     ; N1 = -N1
        !           631:         or      ebx, FL_FLIP_V
        !           632: 
        !           633: is_top_to_bottom:
        !           634:         cmp     edi, eax
        !           635:         jb      short done_flips        ; skip if dN < dM
        !           636:         jne     short slope_more_than_one
        !           637: 
        !           638: ; We must special case slopes of one (because of our rounding convention):
        !           639: 
        !           640:         or      ebx, FL_FLIP_SLOPE_ONE
        !           641:         jmp     short done_flips
        !           642: 
        !           643: slope_more_than_one:
        !           644:         xchg    eax, edi                ; swap dM, dN
        !           645:         xchg    esi, ecx                ; swap M0, N0
        !           646:         or      ebx, FL_FLIP_D
        !           647: 
        !           648: done_flips:
        !           649: 
        !           650:         mov     edx, ebx
        !           651:         and     edx, FL_ROUND_MASK
        !           652:         .errnz  FL_ROUND_SHIFT - 2
        !           653:         or      ebx, [gaflRoundTable + edx]  ; get our rounding flags
        !           654: 
        !           655:         mov     dM, eax                 ; save some info
        !           656:         mov     dN, edi
        !           657:         mov     fl, ebx
        !           658: 
        !           659: ; We're going to shift our origin so that it's at the closest integer
        !           660: ; coordinate to the left/above our fractional start point (it makes
        !           661: ; the math quicker):
        !           662: 
        !           663:         mov     edx, esi                ; x = LFLOOR(M0)
        !           664:         sar     edx, FLOG2
        !           665:         mov     x, edx
        !           666: 
        !           667:         mov     edx, ecx                ; y = LFLOOR(N0)
        !           668:         sar     edx, FLOG2
        !           669:         mov     y, edx
        !           670: 
        !           671: ;-----------------------------------------------------------------------;
        !           672: ; Compute the fractional remainder term                                 ;
        !           673: ;-----------------------------------------------------------------------;
        !           674: 
        !           675: ; By shifting the origin we've contrived to eliminate the integer
        !           676: ; portion of our fractional start point, giving us start point
        !           677: ; fractional coordinates in the range [0, F - 1]:
        !           678: 
        !           679:         and     esi, F - 1              ; M0 = FXFRAC(M0)
        !           680:         and     ecx, F - 1              ; N0 = FXFRAC(N0)
        !           681: 
        !           682: ; We now compute Gamma:
        !           683: 
        !           684:         mov     M0, esi                 ; save M0, N0 for later
        !           685:         mov     N0, ecx
        !           686: 
        !           687:         lea     edx, [ecx + F/2]
        !           688:         mul     edx                     ; [edx:eax] = dM * (N0 + F/2)
        !           689:         xchg    eax, edi
        !           690:         mov     ecx, edx                ; [ecx:edi] = dM * (N0 + F/2)
        !           691:                                         ; (we just nuked N0)
        !           692: 
        !           693:         mul     esi                     ; [edx:eax] = dN * M0
        !           694: 
        !           695: ; Now gamma = dM * (N0 + F/2) - dN * M0 - bRoundDown
        !           696: 
        !           697:         .errnz  FL_V_ROUND_DOWN - 8000h
        !           698:         ror     bh, 8
        !           699:         sbb     edi, eax
        !           700:         sbb     ecx, edx
        !           701: 
        !           702:         shrd    edi, ecx, FLOG2
        !           703:         sar     ecx, FLOG2              ; gamma = [ecx:edi] >>= 4
        !           704: 
        !           705:         mov     eqGamma_hi, ecx
        !           706:         mov     eqGamma_lo, edi
        !           707: 
        !           708:         mov     eax, N0
        !           709: 
        !           710: ; Register state:
        !           711: ;                       eax = N0
        !           712: ;                       ebx = fl
        !           713: ;                       ecx = eqGamma_hi
        !           714: ;                       edx = garbage
        !           715: ;                       esi = M0
        !           716: ;                       edi = eqGamma_lo
        !           717: 
        !           718:         testb   ebx, FL_FLIP_H
        !           719:         jnz     line_runs_right_to_left
        !           720: 
        !           721: ;-----------------------------------------------------------------------;
        !           722: ; Figure out which pixels are at the ends of a left-to-right line.      ;
        !           723: ;                               -------->                               ;
        !           724: ;-----------------------------------------------------------------------;
        !           725: 
        !           726:         public line_runs_left_to_right
        !           727: line_runs_left_to_right:
        !           728:         or      esi, esi
        !           729:         jz      short LtoR_check_slope_one
        !           730:                                         ; skip ahead if M0 == 0
        !           731:                                         ;   (in that case, x0 = 0 which is to be
        !           732:                                         ;   kept in esi, and is already
        !           733:                                         ;   conventiently zero)
        !           734: 
        !           735:         or      eax, eax
        !           736:         jnz     short LtoR_N0_not_zero
        !           737: 
        !           738:         .errnz  FL_H_ROUND_DOWN - 80h
        !           739:         ror     bl, 8
        !           740:         sbb     esi, -F/2
        !           741:         shr     esi, FLOG2
        !           742:         jmp     short LtoR_check_slope_one
        !           743:                                         ; esi = x0 = rounded M0
        !           744: 
        !           745: LtoR_N0_not_zero:
        !           746:         sub     eax, F/2
        !           747:         sbb     edx, edx
        !           748:         xor     eax, edx
        !           749:         sub     eax, edx
        !           750:         cmp     esi, eax
        !           751:         sbb     esi, esi
        !           752:         inc     esi                     ; esi = x0 = (abs(N0 - F/2) <= M0)
        !           753: 
        !           754:         public  LtoR_check_slope_one
        !           755: LtoR_check_slope_one:
        !           756:         mov     ulSlopeOneAdjustment, 0
        !           757:         mov     eax, ebx
        !           758:         and     eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
        !           759:         cmp     eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
        !           760:         jne     short LtoR_compute_y0_from_x0
        !           761: 
        !           762: ; We have to special case lines that are exactly of slope 1 or -1:
        !           763: 
        !           764:         mov     eax, N0
        !           765:         add     eax, dN
        !           766:         and     eax, F - 1              ; eax = N1
        !           767:         jz      short LtoR_slope_one_check_start_point
        !           768: 
        !           769:         mov     edx, M0
        !           770:         add     edx, dM
        !           771:         and     edx, F - 1              ; edx = M1
        !           772: 
        !           773:         add     eax, F/2
        !           774:         cmp     edx, eax                ; cmp M1, N1 + F/2
        !           775:         jne     short LtoR_slope_one_check_start_point
        !           776:         mov     ulSlopeOneAdjustment, -1
        !           777: 
        !           778: LtoR_slope_one_check_start_point:
        !           779:         mov     eax, M0
        !           780:         or      eax, eax
        !           781:         jz      short LtoR_compute_y0_from_x0
        !           782: 
        !           783:         add     eax, F/2
        !           784:         cmp     eax, N0                 ; cmp M0 + 8, N0
        !           785:         jne     short LtoR_compute_y0_from_x0
        !           786: 
        !           787:         xor     esi, esi                ; x0 = 0
        !           788: 
        !           789: LtoR_compute_y0_from_x0:
        !           790: 
        !           791: ; ecx = eqGamma_hi
        !           792: ; esi = x0
        !           793: ; edi = eqGamma_lo
        !           794: 
        !           795:         mov     eax, dN
        !           796:         mov     edx, dM
        !           797: 
        !           798:         mov     x0, esi
        !           799:         mov     y0, 0
        !           800:         cmp     ecx, 0
        !           801:         jl      short LtoR_compute_x1
        !           802: 
        !           803:         neg     esi
        !           804:         and     esi, eax
        !           805:         sub     edx, esi
        !           806:         cmp     edi, edx
        !           807:         mov     edx, dM
        !           808:         jl      short LtoR_compute_x1
        !           809:         mov     y0, 1                   ; y0 = floor((dN * x0 + eqGamma) / dM)
        !           810: 
        !           811: LtoR_compute_x1:
        !           812: 
        !           813: ; Register state:
        !           814: ;                       eax = dN
        !           815: ;                       ebx = fl
        !           816: ;                       ecx = garbage
        !           817: ;                       edx = dM
        !           818: ;                       esi = garbage
        !           819: ;                       edi = garbage
        !           820: 
        !           821:         mov     esi, M0
        !           822:         add     esi, edx
        !           823:         mov     ecx, esi
        !           824:         shr     esi, FLOG2
        !           825:         dec     esi                     ; x1 = ((M0 + dM) >> 4) - 1
        !           826:         add     esi, ulSlopeOneAdjustment
        !           827:         and     ecx, F-1                ; M1 = (M0 + dM) & 15
        !           828:         jz      done_first_pel_last_pel
        !           829: 
        !           830:         add     eax, N0
        !           831:         and     eax, F-1                ; N1 = (N0 + dN) & 15
        !           832:         jnz     short LtoR_N1_not_zero
        !           833: 
        !           834:         .errnz  FL_H_ROUND_DOWN - 80h
        !           835:         ror     bl, 8
        !           836:         sbb     ecx, -F/2
        !           837:         shr     ecx, FLOG2              ; ecx = LROUND(M1, fl & FL_ROUND_DOWN)
        !           838:         add     esi, ecx
        !           839:         jmp     done_first_pel_last_pel
        !           840: 
        !           841: LtoR_N1_not_zero:
        !           842:         sub     eax, F/2
        !           843:         sbb     edx, edx
        !           844:         xor     eax, edx
        !           845:         sub     eax, edx
        !           846:         cmp     eax, ecx
        !           847:         jg      done_first_pel_last_pel
        !           848:         inc     esi
        !           849:         jmp     done_first_pel_last_pel
        !           850: 
        !           851: ;-----------------------------------------------------------------------;
        !           852: ; Figure out which pixels are at the ends of a right-to-left line.      ;
        !           853: ;                               <--------                               ;
        !           854: ;-----------------------------------------------------------------------;
        !           855: 
        !           856: ; Compute x0:
        !           857: 
        !           858:         public  line_runs_right_to_left
        !           859: line_runs_right_to_left:
        !           860:         mov     x0, 1                   ; x0 = 1
        !           861:         or      eax, eax
        !           862:         jnz     short RtoL_N0_not_zero
        !           863: 
        !           864:         xor     edx, edx                ; ulDelta = 0
        !           865:         .errnz  FL_H_ROUND_DOWN - 80h
        !           866:         ror     bl, 8
        !           867:         sbb     esi, -F/2
        !           868:         shr     esi, FLOG2              ; esi = LROUND(M0, fl & FL_H_ROUND_DOWN)
        !           869:         jz      short RtoL_check_slope_one
        !           870: 
        !           871:         mov     x0, 2
        !           872:         mov     edx, dN
        !           873:         jmp     short RtoL_check_slope_one
        !           874: 
        !           875: RtoL_N0_not_zero:
        !           876:         sub     eax, F/2
        !           877:         sbb     edx, edx
        !           878:         xor     eax, edx
        !           879:         sub     eax, edx
        !           880:         add     eax, esi                ; eax = ABS(N0 - F/2) + M0
        !           881:         xor     edx, edx                ; ulDelta = 0
        !           882:         cmp     eax, F
        !           883:         jle     short RtoL_check_slope_one
        !           884: 
        !           885:         mov     x0, 2                   ; x0 = 2
        !           886:         mov     edx, dN                 ; ulDelta = dN
        !           887: 
        !           888:         public  RtoL_check_slope_one
        !           889: RtoL_check_slope_one:
        !           890:         mov     ulSlopeOneAdjustment, 0
        !           891:         mov     eax, ebx
        !           892:         and     eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
        !           893:         cmp     eax, FL_FLIP_SLOPE_ONE
        !           894:         jne     short RtoL_compute_y0_from_x0
        !           895: 
        !           896: ; We have to special case lines that are exactly of slope 1 or -1:
        !           897: 
        !           898:         mov     eax, N0
        !           899:         add     eax, dN
        !           900:         and     eax, F - 1              ; eax = N1
        !           901:         jz      short RtoL_slope_one_check_start_point
        !           902: 
        !           903:         mov     esi, M0
        !           904:         add     esi, dM
        !           905:         and     esi, F - 1              ; esi = M1
        !           906: 
        !           907:         add     eax, F/2
        !           908:         cmp     esi, eax                ; cmp M1, N1 + F/2
        !           909:         jne     short RtoL_slope_one_check_start_point
        !           910:         mov     ulSlopeOneAdjustment, 1
        !           911: 
        !           912: RtoL_slope_one_check_start_point:
        !           913:         mov     eax, M0
        !           914:         or      eax, eax
        !           915:         jz      short RtoL_compute_y0_from_x0
        !           916: 
        !           917:         add     eax, F/2
        !           918:         cmp     eax, N0                 ; cmp M0 + 8, N0
        !           919:         jne     short RtoL_compute_y0_from_x0
        !           920: 
        !           921:         mov     x0, 2                   ; x0 = 2
        !           922:         mov     edx, dN                 ; ulDelta = dN
        !           923: 
        !           924: RtoL_compute_y0_from_x0:
        !           925: 
        !           926: ; eax = garbage
        !           927: ; ebx = fl
        !           928: ; ecx = eqGamma_hi
        !           929: ; edx = ulDelta
        !           930: ; esi = garbage
        !           931: ; edi = eqGamma_lo
        !           932: 
        !           933:         mov     eax, dN                 ; eax = dN
        !           934:         mov     y0, 0                   ; y0 = 0
        !           935: 
        !           936:         add     edi, edx
        !           937:         adc     ecx, 0                  ; eqGamma += ulDelta
        !           938:                                         ; NOTE: Setting flags here!
        !           939:         mov     edx, dM                 ; edx = dM
        !           940:         jl      short RtoL_compute_x1   ; NOTE: Looking at the flags here!
        !           941:         jg      short RtoL_y0_is_2
        !           942: 
        !           943:         lea     ecx, [edx + edx]
        !           944:         sub     ecx, eax                ; ecx = 2 * dM - dN
        !           945:         cmp     edi, ecx
        !           946:         jge     short RtoL_y0_is_2
        !           947: 
        !           948:         sub     ecx, edx                ; ecx = dM - dN
        !           949:         cmp     edi, ecx
        !           950:         jl      short RtoL_compute_x1
        !           951: 
        !           952:         mov     y0, 1
        !           953:         jmp     short RtoL_compute_x1
        !           954: 
        !           955: RtoL_y0_is_2:
        !           956:         mov     y0, 2
        !           957: 
        !           958: RtoL_compute_x1:
        !           959: 
        !           960: ; Register state:
        !           961: ;                       eax = dN
        !           962: ;                       ebx = fl
        !           963: ;                       ecx = garbage
        !           964: ;                       edx = dM
        !           965: ;                       esi = garbage
        !           966: ;                       edi = garbage
        !           967: 
        !           968:         mov     esi, M0
        !           969:         add     esi, edx
        !           970:         mov     ecx, esi
        !           971:         shr     esi, FLOG2              ; x1 = (M0 + dM) >> 4
        !           972:         add     esi, ulSlopeOneAdjustment
        !           973:         and     ecx, F-1                ; M1 = (M0 + dM) & 15
        !           974: 
        !           975:         add     eax, N0
        !           976:         and     eax, F-1                ; N1 = (N0 + dN) & 15
        !           977:         jnz     short RtoL_N1_not_zero
        !           978: 
        !           979:         .errnz  FL_H_ROUND_DOWN - 80h
        !           980:         ror     bl, 8
        !           981:         sbb     ecx, -F/2
        !           982:         shr     ecx, FLOG2              ; ecx = LROUND(M1, fl & FL_ROUND_DOWN)
        !           983:         add     esi, ecx
        !           984:         jmp     done_first_pel_last_pel
        !           985: 
        !           986: RtoL_N1_not_zero:
        !           987:         sub     eax, F/2
        !           988:         sbb     edx, edx
        !           989:         xor     eax, edx
        !           990:         sub     eax, edx
        !           991:         add     eax, ecx                ; eax = ABS(N1 - F/2) + M1
        !           992:         cmp     eax, F+1
        !           993:         sbb     esi, -1
        !           994: 
        !           995: done_first_pel_last_pel:
        !           996: 
        !           997: ; Register state:
        !           998: ;                       eax = garbage
        !           999: ;                       ebx = fl
        !          1000: ;                       ecx = garbage
        !          1001: ;                       edx = garbage
        !          1002: ;                       esi = x1
        !          1003: ;                       edi = garbage
        !          1004: 
        !          1005:         mov     ecx, x0
        !          1006:         lea     edx, [esi + 1]
        !          1007:         sub     edx, ecx                ; edx = x1 - x0 + 1
        !          1008: 
        !          1009:         jle     next_line
        !          1010:         mov     cStylePels, edx
        !          1011:         mov     xStart, ecx
        !          1012: 
        !          1013: ;-----------------------------------------------------------------------;
        !          1014: ; See if clipping or styling needs to be done.                          ;
        !          1015: ;-----------------------------------------------------------------------;
        !          1016: 
        !          1017:         testb   ebx, FL_CLIP
        !          1018:         jnz     do_some_clipping
        !          1019: 
        !          1020: ; Register state:
        !          1021: ;                       eax = garbage
        !          1022: ;                       ebx = fl
        !          1023: ;                       ecx = x0        (stack variable correct too)
        !          1024: ;                       edx = garbage
        !          1025: ;                       esi = x1
        !          1026: ;                       edi = garbage
        !          1027: 
        !          1028: done_clipping:
        !          1029:         mov     eax, y0
        !          1030: 
        !          1031:         sub     esi, ecx
        !          1032:         inc     esi                     ; esi = cPels = x1 - x0 + 1
        !          1033:         mov     cPels, esi
        !          1034: 
        !          1035:         mov     esi, ppdev
        !          1036:         add     ecx, x                  ; ecx = ptlStart.ptl_x
        !          1037:         add     eax, y                  ; eax = ptlStart.ptl_y
        !          1038: 
        !          1039:         mov     esi, [esi].pdev_lNextScan ; we'll compute the sign of lNextScan
        !          1040: 
        !          1041:         testb   ebx, FL_FLIP_D
        !          1042:         jz      short do_v_unflip
        !          1043:         xchg    ecx, eax
        !          1044: 
        !          1045: do_v_unflip:
        !          1046:         testb   ebx, FL_FLIP_V
        !          1047:         jz      short done_unflips
        !          1048:         neg     eax
        !          1049:         neg     esi
        !          1050: 
        !          1051: done_unflips:
        !          1052:         mov     strip.ST_lNextScan, esi ; lNextScan now right for y-direction
        !          1053:         testb   ebx, FL_STYLED
        !          1054:         jnz     do_some_styling
        !          1055: 
        !          1056: done_styling:
        !          1057:         lea     edx, [strip.ST_alStrips + (STRIP_MAX * 4)]
        !          1058:         mov     plStripEnd, edx
        !          1059: 
        !          1060:         mov     cPelsAfterThisBank, 0
        !          1061:         mov     cStripsInNextRun, 7fffffffh
        !          1062: 
        !          1063: ;-----------------------------------------------------------------------;
        !          1064: ; Do banking setup.                                                     ;
        !          1065: ;-----------------------------------------------------------------------;
        !          1066: 
        !          1067:         public  bank_setup
        !          1068: bank_setup:
        !          1069: 
        !          1070: ; Register state:
        !          1071: ;                       eax = ptlStart.ptl_y
        !          1072: ;                       ebx = fl
        !          1073: ;                       ecx = ptlStart.ptl_x
        !          1074: ;                       edx = garbage
        !          1075: ;                       esi = garbage
        !          1076: ;                       edi = garbage
        !          1077: 
        !          1078:         mov     esi, ppdev
        !          1079:         cmp     eax, [esi].pdev_rcl1WindowClip.yTop
        !          1080:         jl      short bank_get_initial_bank   ; ptlStart.y < rcl1WindowClip.yTop
        !          1081: 
        !          1082:         cmp     eax, [esi].pdev_rcl1WindowClip.yBottom
        !          1083:         jl      short bank_got_initial_bank   ; ptlStart.y < rcl1WindowClip.yBot
        !          1084: 
        !          1085: bank_get_initial_bank:
        !          1086:         mov     ptlStart.ptl_y, eax     ; Save ptlStart.ptl_y
        !          1087:         mov     edi, ecx                ; Save ptlStart.ptl_x
        !          1088: 
        !          1089:         .errnz  JustifyTop
        !          1090:         .errnz  JustifyBottom - 1
        !          1091:         .errnz  FL_FLIP_V - 8
        !          1092: 
        !          1093:         mov     ecx, ebx                ; JustifyTop if line goes down,
        !          1094:         shr     ecx, 3                  ; JustifyBottom if line goes up
        !          1095:         and     ecx, 1
        !          1096: 
        !          1097: bank_justified:
        !          1098:         ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
        !          1099:                 <esi, eax, ecx>
        !          1100: 
        !          1101:         mov     eax, ptlStart.ptl_y
        !          1102:         mov     ecx, edi
        !          1103: 
        !          1104: bank_got_initial_bank:
        !          1105:         testb   ebx, FL_FLIP_D
        !          1106:         jz      short bank_major_x
        !          1107: 
        !          1108: bank_major_y:
        !          1109:         testb   ebx, FL_FLIP_V
        !          1110:         jz      short bank_major_y_down
        !          1111: bank_major_y_up:
        !          1112:         lea     edi, [eax + 1]
        !          1113:         sub     edi, [esi].pdev_rcl1WindowClip.yTop
        !          1114:         jmp     short bank_done_y_major
        !          1115: bank_major_y_down:
        !          1116:         mov     edi, [esi].pdev_rcl1WindowClip.yBottom
        !          1117:         sub     edi, eax
        !          1118: bank_done_y_major:
        !          1119:         mov     esi, cPels
        !          1120:         sub     esi, edi                ; edi = cPelsInBank
        !          1121:         mov     cPelsAfterThisBank, esi
        !          1122:         jle     short done_bank_setup
        !          1123:         mov     cPels, edi
        !          1124:         jmp     short done_bank_setup
        !          1125: 
        !          1126: bank_major_x:
        !          1127:         mov     edi, dN
        !          1128:         shr     edi, FLOG2
        !          1129:         add     edi, y
        !          1130: 
        !          1131: ; We're guessing at the y-position of the end pixel (it's too much work
        !          1132: ; to compute the actual value) to see if the line spans more than one
        !          1133: ; bank.  We have to add at least a slop value of '3' because the actual
        !          1134: ; start pixel may be may 2 off from 'y' because of end-pixel exclusiveness,
        !          1135: ; and we have to add 1 more because we're taking the floor of (dN / F), to
        !          1136: ; account for rounding:
        !          1137: 
        !          1138:         add     edi, 3                  ; yEnd = edi = y + LFLOOR(dN) + 3
        !          1139:         testb   ebx, FL_FLIP_V
        !          1140:         jz      short bank_major_x_down
        !          1141: bank_major_x_up:
        !          1142:         mov     edx, 1
        !          1143:         sub     edx, [esi].pdev_rcl1WindowClip.yTop    ; edx = -yNextBankStart
        !          1144: 
        !          1145:         cmp     edi, edx
        !          1146:         lea     edx, [edx + eax]        ; edx = cStripsInNextRun
        !          1147:         jl      short bank_major_x_done
        !          1148: 
        !          1149: ; Line may go over bank boundary, so don't do a half flip:
        !          1150: 
        !          1151:         or      ebx, FL_DONT_DO_HALF_FLIP
        !          1152:         jmp     short bank_major_x_done
        !          1153: 
        !          1154: bank_major_x_down:
        !          1155:         mov     esi, [esi].pdev_rcl1WindowClip.yBottom  ; esi = yNextBankStart
        !          1156: 
        !          1157:         mov     edx, esi
        !          1158:         sub     edx, eax                ; edx = cStripsInNextRun
        !          1159: 
        !          1160:         cmp     edi, esi
        !          1161:         jl      short bank_major_x_done
        !          1162:         or      ebx, FL_DONT_DO_HALF_FLIP
        !          1163: 
        !          1164: bank_major_x_done:
        !          1165:         sub     edx, STRIP_MAX
        !          1166:         mov     cStripsInNextRun, edx
        !          1167:         jge     short done_bank_setup
        !          1168: 
        !          1169:         lea     edx, [strip.ST_alStrips + edx * 4 + (STRIP_MAX * 4)]
        !          1170:         mov     plStripEnd, edx
        !          1171: 
        !          1172: done_bank_setup:
        !          1173: 
        !          1174: ;-----------------------------------------------------------------------;
        !          1175: ; Setup to do DDA.                                                      ;
        !          1176: ;-----------------------------------------------------------------------;
        !          1177: 
        !          1178: ; Register state:
        !          1179: ;                       eax = ptlStart.ptl_y
        !          1180: ;                       ebx = fl
        !          1181: ;                       ecx = ptlStart.ptl_x
        !          1182: ;                       edx = garbage
        !          1183: ;                       esi = garbage
        !          1184: ;                       edi = garbage
        !          1185: 
        !          1186:         mov     esi, ppdev
        !          1187:         mov     edi, eax                ; Now edi = ptlStart.ptl_y
        !          1188:         imul    [esi].pdev_lNextScan
        !          1189:         add     eax, [esi].pdev_pvBitmapStart
        !          1190:         add     eax, ecx
        !          1191:         mov     strip.ST_pjScreen, eax  ; pjScreen = pchBits + ptlStart.y *
        !          1192:                                         ;   cjDelta + ptlStart.x
        !          1193: 
        !          1194:         mov     eax, dM
        !          1195:         mov     ecx, dN
        !          1196:         mov     esi, eqGamma_lo
        !          1197:         mov     edi, eqGamma_hi
        !          1198: 
        !          1199: ; Register state:
        !          1200: ;                       eax = dM
        !          1201: ;                       ebx = fl
        !          1202: ;                       ecx = dN
        !          1203: ;                       edx = garbage
        !          1204: ;                       esi = eqGamma_lo
        !          1205: ;                       edi = eqGamma_hi
        !          1206: 
        !          1207:         lea     edx, [ecx + ecx]        ; if (2 * dN > dM)
        !          1208:         cmp     edx, eax
        !          1209:         mov     edx, y0                 ; Load y0 again
        !          1210:         jbe     short after_half_flip
        !          1211: 
        !          1212:         test    ebx, FL_DONT_DO_HALF_FLIP
        !          1213:         jnz     short after_half_flip
        !          1214: 
        !          1215:         or      ebx, FL_FLIP_HALF
        !          1216:         mov     fl, ebx
        !          1217: 
        !          1218: ; Do a half flip!
        !          1219: 
        !          1220:         not     esi
        !          1221:         not     edi
        !          1222:         add     esi, eax
        !          1223:         adc     edi, 0                  ; eqGamma = -eqGamma - 1 + dM
        !          1224: 
        !          1225:         neg     ecx
        !          1226:         add     ecx, eax                ; dN = dM - dN
        !          1227: 
        !          1228:         neg     edx
        !          1229:         add     edx, x0                 ; y0 = x0 - y0
        !          1230: 
        !          1231: after_half_flip:
        !          1232:         mov     strip.ST_flFlips, ebx
        !          1233:         and     ebx, FL_STRIP_MASK
        !          1234: 
        !          1235:         .errnz  FL_STRIP_SHIFT
        !          1236:         mov     eax, apfn
        !          1237:         lea     eax, [eax + ebx * 4]
        !          1238:         mov     eax, [eax]
        !          1239:         mov     pfn, eax
        !          1240:         mov     eax, dM
        !          1241: 
        !          1242: ; Register state:
        !          1243: ;                       eax = dM
        !          1244: ;                       ebx = garbage
        !          1245: ;                       ecx = dN
        !          1246: ;                       edx = y0
        !          1247: ;                       esi = eqGamma_lo
        !          1248: ;                       edi = eqGamma_hi
        !          1249: 
        !          1250:         or      ecx, ecx
        !          1251:         jz      short zero_slope
        !          1252: 
        !          1253: compute_dda_stuff:
        !          1254:         inc     edx
        !          1255:         mul     edx
        !          1256:         stc                             ; set the carry to accomplish -1
        !          1257:         sbb     eax, esi
        !          1258:         sbb     edx, edi                ; (y0 + 1) * dM - eqGamma - 1
        !          1259:         div     ecx
        !          1260: 
        !          1261:         mov     esi, eax                ; esi = i
        !          1262:         mov     edi, edx                ; edi = r
        !          1263: 
        !          1264:         xor     edx, edx
        !          1265:         mov     eax, dM
        !          1266:         div     ecx                     ; edx = d_R, eax = d_I
        !          1267:         mov     d_I, eax
        !          1268: 
        !          1269:         sub     esi, x0
        !          1270:         inc     esi
        !          1271: 
        !          1272: done_dda_stuff:
        !          1273:         lea     eax, [strip.ST_alStrips]
        !          1274:         mov     ebx, cPels
        !          1275: 
        !          1276: ;-----------------------------------------------------------------------;
        !          1277: ; Do our main DDA loop.                                                 ;
        !          1278: ;-----------------------------------------------------------------------;
        !          1279: 
        !          1280:         sub     edi, ecx                ; offset remainder term from [0..dN)
        !          1281:                                         ;   to [-dN..0) so test in inner
        !          1282:                                         ;   loop is quicker
        !          1283:         align   4
        !          1284: 
        !          1285: ; Register state:
        !          1286: ;                       eax = plStrip   ; current pointer into strip array
        !          1287: ;                       ebx = cPels     ; total number of pels in line
        !          1288: ;                       ecx = dN        ; delta-N = rise in line
        !          1289: ;                       edx = d_R       ; d_I + d_R/dN = exact strip length
        !          1290: ;                       esi = i         ; length of current strip
        !          1291: ;                       edi = r         ; remainder term for current strip
        !          1292: ;                                       ;   in range [-dN..0)
        !          1293: 
        !          1294:         public  dda_loop
        !          1295: dda_loop:
        !          1296:         sub     ebx, esi                ; subtract strip length from line length
        !          1297:         jle     final_strip             ; if negative, done with line
        !          1298: 
        !          1299:         mov     [eax], esi              ; write strip length to strip array
        !          1300:         add     eax, 4
        !          1301:         cmp     plStripEnd, eax         ; is the strip array buffer full?
        !          1302:         jbe     short output_strips     ; if so, empty it
        !          1303: 
        !          1304: ; The output_strips routine jumps to here when done:
        !          1305: 
        !          1306: done_output_strips:
        !          1307:         mov     esi, d_I                ; our normal strip length
        !          1308:         add     edi, edx                ; adjust our remainder term
        !          1309:         jl      short dda_loop
        !          1310: 
        !          1311:         sub     edi, ecx                ; our remainder became 1 or more, so
        !          1312:         inc     esi                     ;   we increment this strip length
        !          1313:                                         ;   and adjust the remainder term
        !          1314: 
        !          1315: ; We've unrolled our loop a bit, so this should look familiar to the above:
        !          1316: 
        !          1317:         sub     ebx, esi                ; subtract strip length from line length
        !          1318:         jle     final_strip             ; if negative, done with line
        !          1319: 
        !          1320:         mov     [eax], esi              ; write strip length to strip array
        !          1321:         add     eax, 4                  ; adjust strip pointer
        !          1322: 
        !          1323: ; Note that banking requires us to check if the strip array is full here
        !          1324: ; too (and note that if output_strips is called it will return to
        !          1325: ; done_output_strips):
        !          1326: 
        !          1327:         cmp     plStripEnd, eax
        !          1328:         jbe     short output_strips
        !          1329: 
        !          1330:         mov     esi, d_I                ; our normal strip length
        !          1331:         add     edi, edx                ; adjust our remainder term
        !          1332:         jl      short dda_loop
        !          1333: 
        !          1334:         sub     edi, ecx                ; our remainder became 1 or more, so
        !          1335:         inc     esi                     ; adjust
        !          1336:         jmp     short dda_loop
        !          1337: 
        !          1338: zero_slope:
        !          1339:         mov     esi, 7fffffffh
        !          1340:         jmp     short done_dda_stuff
        !          1341: 
        !          1342: ;-----------------------------------------------------------------------;
        !          1343: ; Empty strips buffer & possibly do x-major bank switch.                ;
        !          1344: ;-----------------------------------------------------------------------;
        !          1345: 
        !          1346: output_strips:
        !          1347:         mov     d_R, edx
        !          1348:         mov     cPels, ebx
        !          1349:         mov     i, esi
        !          1350:         mov     r, edi
        !          1351:         mov     dN, ecx
        !          1352: 
        !          1353:         lea     edx, [strip]
        !          1354:         mov     ecx, pls
        !          1355: 
        !          1356: ; Call our strip routine:
        !          1357: 
        !          1358:         ptrCall <dword ptr pfn>, \
        !          1359:                 <edx, ecx, eax>
        !          1360: 
        !          1361: ; It may be that we ran out of run in our strips buffer, and don't
        !          1362: ; actually have to switch banks.  See if that's the case:
        !          1363: 
        !          1364:         mov     eax, cStripsInNextRun
        !          1365:         or      eax, eax
        !          1366:         jg      short done_strip_bank_switch
        !          1367: 
        !          1368: ; We have to switch banks.  See if we're going up or down:
        !          1369: 
        !          1370:         mov     esi, ppdev
        !          1371:         test    fl, FL_FLIP_V
        !          1372:         jz      short bank_x_down
        !          1373: 
        !          1374: bank_x_up:
        !          1375:         mov     edi, strip.ST_pjScreen
        !          1376:         sub     edi, [esi].pdev_pvBitmapStart
        !          1377:         mov     ebx, [esi].pdev_rcl1WindowClip.yTop
        !          1378:         dec     ebx                     ; we want yTop - 1 to be mapped in
        !          1379: 
        !          1380: ; Map in the next higher bank:
        !          1381: 
        !          1382:         ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
        !          1383:                 <esi, ebx, JustifyBottom>; ebx, esi and edi are preserved
        !          1384: 
        !          1385:         lea     eax, [ebx + 1]
        !          1386:         sub     eax, [esi].pdev_rcl1WindowClip.yTop
        !          1387:                                         ; eax = # of scans can do in bank
        !          1388: 
        !          1389:         add     edi, [esi].pdev_pvBitmapStart
        !          1390:         mov     strip.ST_pjScreen, edi
        !          1391: 
        !          1392:         jmp     short done_strip_bank_switch
        !          1393: 
        !          1394: bank_x_down:
        !          1395:         mov     edi, strip.ST_pjScreen
        !          1396:         sub     edi, [esi].pdev_pvBitmapStart
        !          1397:         mov     ebx, [esi].pdev_rcl1WindowClip.yBottom
        !          1398: 
        !          1399: ; Map in the next lower bank:
        !          1400: 
        !          1401:         ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
        !          1402:                 <esi, ebx, JustifyTop>  ; ebx, esi and edi are preserved
        !          1403: 
        !          1404:         mov     eax, [esi].pdev_rcl1WindowClip.yBottom
        !          1405:         sub     eax, ebx                ; eax = # scans can do in bank
        !          1406: 
        !          1407:         add     edi, [esi].pdev_pvBitmapStart
        !          1408:         mov     strip.ST_pjScreen,edi
        !          1409: 
        !          1410: done_strip_bank_switch:
        !          1411: 
        !          1412: ; eax = cStripsInNextRun
        !          1413: 
        !          1414:         lea     edx, [strip.ST_alStrips + (STRIP_MAX * 4)]
        !          1415:         sub     eax, STRIP_MAX
        !          1416:         mov     cStripsInNextRun, eax
        !          1417:         jge     short get_ready_for_more_strips
        !          1418:         lea     edx, [edx + eax * 4]
        !          1419: 
        !          1420: get_ready_for_more_strips:
        !          1421:         mov     plStripEnd, edx
        !          1422: 
        !          1423:         mov     esi, i
        !          1424:         mov     edi, r
        !          1425:         mov     ebx, cPels
        !          1426:         mov     edx, d_R
        !          1427:         mov     ecx, dN
        !          1428:         lea     eax, [strip.ST_alStrips]
        !          1429:         jmp     done_output_strips
        !          1430: 
        !          1431: ;-----------------------------------------------------------------------;
        !          1432: ; Empty strips buffer.  Either get new line or do y-major bank switch.  ;
        !          1433: ;-----------------------------------------------------------------------;
        !          1434: 
        !          1435: final_strip:
        !          1436:         add     ebx, esi
        !          1437:         mov     [eax], ebx
        !          1438:         add     eax, 4
        !          1439: 
        !          1440:         cmp     cPelsAfterThisBank, 0
        !          1441:         jg      short bank_y_major
        !          1442: 
        !          1443: very_final_strip:
        !          1444:         lea     edx, [strip]
        !          1445:         mov     ecx, pls
        !          1446: 
        !          1447:         ptrCall <dword ptr pfn>, \
        !          1448:                 <edx, ecx, eax>
        !          1449: 
        !          1450: ; NOTE: next_line is jumped to from various places, and it cannot assume
        !          1451: ;       any registers are loaded.
        !          1452: 
        !          1453: next_line:
        !          1454:         mov     ebx, flStart
        !          1455:         testb   ebx, FL_COMPLEX_CLIP
        !          1456:         jnz     short see_if_done_complex_clipping
        !          1457: 
        !          1458:         mov     edx, pptfxBuf
        !          1459:         cmp     edx, pptfxBufEnd
        !          1460:         je      short all_done
        !          1461: 
        !          1462:         mov     esi, [edx].ptl_x
        !          1463:         mov     ecx, [edx].ptl_y
        !          1464:         add     edx, size POINTL
        !          1465:         mov     pptfxBuf, edx
        !          1466:         mov     eax, [edx].ptl_x
        !          1467:         mov     edi, [edx].ptl_y
        !          1468:         jmp     the_main_loop
        !          1469: 
        !          1470: all_done:
        !          1471:         mov     eax, 1
        !          1472: 
        !          1473:         cRet    bLines
        !          1474: 
        !          1475: see_if_done_complex_clipping:
        !          1476:         mov     ebx, fl
        !          1477:         dec     cptfx
        !          1478:         jz      short all_done
        !          1479: 
        !          1480:         and     ebx, NOT FL_FLIP_HALF   ; Make sure the next run doesn't have
        !          1481:         mov     fl, ebx                 ;   to do a half-flip if it doesn't
        !          1482:                                         ;   want to
        !          1483:         jmp     continue_complex_clipping
        !          1484: 
        !          1485: ;-----------------------------------------------------------------------;
        !          1486: ; Switch banks for a y-major line.                                      ;
        !          1487: ;-----------------------------------------------------------------------;
        !          1488: 
        !          1489:         public  bank_y_major
        !          1490: bank_y_major:
        !          1491:         mov     d_R, edx
        !          1492:         mov     i, esi
        !          1493:         mov     r, edi
        !          1494:         mov     dN, ecx
        !          1495:         sub     ebx, esi                ; Undo our offset
        !          1496: 
        !          1497: bank_y_output_strips:
        !          1498:         lea     edx, [strip]
        !          1499:         mov     ecx, pls
        !          1500: 
        !          1501:         ptrCall <dword ptr pfn>, \
        !          1502:                 <edx, ecx, eax>
        !          1503: 
        !          1504:         mov     esi, ppdev
        !          1505:         test    fl, FL_FLIP_V
        !          1506:         jz      short bank_y_down
        !          1507: 
        !          1508: bank_y_up:
        !          1509:         mov     edi, strip.ST_pjScreen
        !          1510:         sub     edi, [esi].pdev_pvBitmapStart
        !          1511:         mov     ecx, [esi].pdev_rcl1WindowClip.yTop
        !          1512:         push    ecx
        !          1513:         dec     ecx                     ; we want yTop - 1 to be mapped in
        !          1514: 
        !          1515: ; Map in the next higher bank:
        !          1516: 
        !          1517:         ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
        !          1518:                 <esi, ecx, JustifyBottom>; ebx, esi and edi are preserved
        !          1519: 
        !          1520:         pop     ecx
        !          1521:         sub     ecx, [esi].pdev_rcl1WindowClip.yTop
        !          1522:                                         ; ecx = # of scans can do in bank
        !          1523: 
        !          1524:         add     edi, [esi].pdev_pvBitmapStart
        !          1525:         mov     strip.ST_pjScreen, edi
        !          1526: 
        !          1527:         mov     edx, cPelsAfterThisBank                 ; edx = cPelsAfterBank
        !          1528:         lea     eax, [strip.ST_alStrips]                ; eax = plStrip
        !          1529:         or      ebx, ebx                                ; ebx = cPels
        !          1530:         jge     bank_y_done_partial_strip
        !          1531:         jmp     short bank_y_done_switch
        !          1532: 
        !          1533: bank_y_down:
        !          1534:         mov     edi, strip.ST_pjScreen
        !          1535:         sub     edi, [esi].pdev_pvBitmapStart
        !          1536:         mov     ecx, [esi].pdev_rcl1WindowClip.yBottom
        !          1537:         push    ecx
        !          1538: 
        !          1539: ; Map in the next lower bank:
        !          1540: 
        !          1541:         ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
        !          1542:                 <esi, ecx, JustifyTop>  ; ebx, esi and edi are preserved
        !          1543: 
        !          1544:         pop     eax
        !          1545:         mov     ecx, [esi].pdev_rcl1WindowClip.yBottom
        !          1546:         sub     ecx, eax                ; ecx = # scans can do in bank
        !          1547: 
        !          1548:         add     edi, [esi].pdev_pvBitmapStart
        !          1549:         mov     strip.ST_pjScreen,edi
        !          1550: 
        !          1551:         mov     edx, cPelsAfterThisBank                 ; edx = cPelsAfterBank
        !          1552:         lea     eax, [strip.ST_alStrips]                ; eax = plStrip
        !          1553:         or      ebx, ebx                                ; ebx = cPels
        !          1554:         jge     short bank_y_done_partial_strip
        !          1555: 
        !          1556: bank_y_done_switch:
        !          1557: 
        !          1558: ; Handle a single strip stretching over multiple banks:
        !          1559: 
        !          1560:         test    fl, FL_FLIP_HALF
        !          1561:         jz      short bank_y_no_half_flip
        !          1562: 
        !          1563: ; We now have to adjust for the fact that the strip drawers always leave
        !          1564: ; the state ready for the next new strip (e.g., if we're doing vertical
        !          1565: ; strips, it advances pjScreen one to the right after drawing each strip).
        !          1566: ; But the problem is that since we crossed a bank, we have to continue the
        !          1567: ; *old* strip, so we have to undo that advance:
        !          1568: 
        !          1569: bank_y_half_flip:
        !          1570:         inc     strip.ST_pjScreen
        !          1571:         jmp     short bank_y_done_bit_adjust
        !          1572: 
        !          1573: bank_y_no_half_flip:
        !          1574:         dec     strip.ST_pjScreen
        !          1575: 
        !          1576: bank_y_done_bit_adjust:
        !          1577:         mov     esi, ebx
        !          1578:         neg     esi                             ; esi = # pels left in strip
        !          1579: 
        !          1580: ; eax = pointer to first strip entry
        !          1581: ; ebx = negative esi
        !          1582: ; ecx = # of pels we can put down in this window
        !          1583: ; edx = # of pels remaining to do in line
        !          1584: ; esi = # of pels left in strip
        !          1585: 
        !          1586: ; We have three special cases to check here:
        !          1587: ;
        !          1588: ;       1) If the strip spans the entire next window
        !          1589: ;       2) This is the last strip in the line
        !          1590: ;       3) Neither of the above
        !          1591: 
        !          1592:         cmp     edx,ecx                         ;if line shorter than bank,
        !          1593:         jle     short bank_y_check_if_last_strip;  know strip doesn't span bank
        !          1594: 
        !          1595:         cmp     esi,ecx                         ;if line spans bank, don't have
        !          1596:         jl      short bank_y_continue_strip     ;  to check if last strip
        !          1597: 
        !          1598: ; If ((# of pels in line > window size) && (# of pels in strip > window size))
        !          1599: ; then the strip spans this bank:
        !          1600: 
        !          1601:         mov     [eax], ecx
        !          1602:         add     eax, 4
        !          1603:         add     ebx, ecx
        !          1604:         sub     edx, ecx
        !          1605:         mov     cPelsAfterThisBank, edx
        !          1606:         jmp     bank_y_output_strips
        !          1607: 
        !          1608: bank_y_check_if_last_strip:
        !          1609:         cmp     esi, edx                        ;if strip is shorter than line,
        !          1610:         jl      short bank_y_continue_strip     ;  we know this isn't the last
        !          1611:                                                 ;  strip
        !          1612: 
        !          1613: ; Handle case where this is the last strip in the line and it overlaps a bank:
        !          1614: 
        !          1615:         mov     [eax], edx
        !          1616:         add     eax, 4
        !          1617:         jmp     very_final_strip
        !          1618: 
        !          1619: bank_y_continue_strip:
        !          1620:         mov     [eax], esi
        !          1621:         add     eax, 4
        !          1622: 
        !          1623: bank_y_done_partial_strip:
        !          1624:         add     ebx, edx                ; cPels += cPelsAfterThisBank
        !          1625:         sub     edx, ecx                ; cPelsAfterThisBank -= cyWindow
        !          1626: 
        !          1627:         jle     short bank_y_get_ready
        !          1628:         sub     ebx, edx
        !          1629: 
        !          1630: bank_y_get_ready:
        !          1631:         mov     cPelsAfterThisBank, edx
        !          1632:         mov     edi, r
        !          1633:         mov     edx, d_R
        !          1634:         mov     ecx, dN
        !          1635:         jmp     done_output_strips
        !          1636: 
        !          1637: ;---------------------------Private-Routine-----------------------------;
        !          1638: ; do_some_styling
        !          1639: ;
        !          1640: ; Inputs:
        !          1641: ;       eax = ptlStart.ptl_y
        !          1642: ;       ebx = fl
        !          1643: ;       ecx = ptlStart.ptl_x
        !          1644: ; Preserves:
        !          1645: ;       eax, ebx, ecx
        !          1646: ; Output:
        !          1647: ;       Exits to done_styling.
        !          1648: ;
        !          1649: ;-----------------------------------------------------------------------;
        !          1650: 
        !          1651:         public  do_some_styling
        !          1652: do_some_styling:
        !          1653:         mov     esi, pls
        !          1654:         mov     ptlStart.ptl_x, ecx
        !          1655: 
        !          1656:         mov     edi, [esi].LS_spNext    ; spThis
        !          1657:         mov     edx, edi
        !          1658:         add     edx, cStylePels         ; spNext
        !          1659: 
        !          1660: do_non_alternate_style:
        !          1661: 
        !          1662: ; For styles, we don't bother to keep the style position normalized.
        !          1663: ; (we do ensure that it's positive, though).  If a figure is over 2
        !          1664: ; billion pels long, we'll be a pel off in our style state (oops!).
        !          1665: 
        !          1666:         and     edx, 7fffffffh
        !          1667:         mov     [esi].LS_spNext, edx
        !          1668:         mov     ptlStart.ptl_y, eax
        !          1669: 
        !          1670:         testb   ebx, FL_FLIP_H
        !          1671:         jz      short arbitrary_left_to_right
        !          1672: 
        !          1673:         sub     edx, x0
        !          1674:         add     edx, xStart
        !          1675:         mov     eax, edx
        !          1676:         xor     edx, edx
        !          1677:         div     [esi].LS_spTotal
        !          1678: 
        !          1679:         neg     edx
        !          1680:         jge     short continue_right_to_left
        !          1681:         add     edx, [esi].LS_spTotal
        !          1682:         not     eax
        !          1683: 
        !          1684: continue_right_to_left:
        !          1685:         mov     edi, dword ptr [esi].LS_bStartIsGap
        !          1686:         not     edi
        !          1687:         mov     ecx, [esi].LS_aspRtoL
        !          1688:         jmp     short compute_arbitrary_stuff
        !          1689: 
        !          1690: arbitrary_left_to_right:
        !          1691:         add     edi, x0
        !          1692:         sub     edi, xStart
        !          1693:         mov     eax, edi
        !          1694:         xor     edx, edx
        !          1695:         div     [esi].LS_spTotal
        !          1696:         mov     edi, dword ptr [esi].LS_bStartIsGap
        !          1697:         mov     ecx, [esi].LS_aspLtoR
        !          1698: 
        !          1699: compute_arbitrary_stuff:
        !          1700: ;       eax = sp / spTotal
        !          1701: ;       ebx = fl
        !          1702: ;       ecx = pspStart
        !          1703: ;       edx = sp % spTotal
        !          1704: ;       esi = pls
        !          1705: ;       edi = bIsGap
        !          1706: 
        !          1707:         and     eax, [esi].LS_cStyle        ; if odd length style and second run
        !          1708:         and     al, 1                       ; through style array, flip the
        !          1709:         jz      short odd_style_array_done  ; meaning of the elements
        !          1710:         not     edi
        !          1711: 
        !          1712: odd_style_array_done:
        !          1713:         mov     eax, [esi].LS_cStyle
        !          1714:         mov     strip.ST_pspStart, ecx
        !          1715:         lea     eax, [ecx + eax * 4 - 4]
        !          1716:         mov     strip.ST_pspEnd, eax
        !          1717: 
        !          1718: find_psp:
        !          1719:         sub     edx, [ecx]
        !          1720:         jl      short found_psp
        !          1721:         add     ecx, 4
        !          1722:         jmp     short find_psp
        !          1723: 
        !          1724: found_psp:
        !          1725:         mov     strip.ST_psp, ecx
        !          1726:         neg     edx
        !          1727:         mov     strip.ST_spRemaining, edx
        !          1728: 
        !          1729:         sub     ecx, strip.ST_pspStart
        !          1730:         test    ecx, 4                      ; size STYLEPOS
        !          1731:         jz      short done_arbitrary
        !          1732:         not     edi
        !          1733: 
        !          1734: done_arbitrary:
        !          1735:         mov     dword ptr strip.ST_bIsGap, edi
        !          1736:         mov     eax, ptlStart.ptl_y
        !          1737:         mov     ecx, ptlStart.ptl_x
        !          1738:         jmp     done_styling
        !          1739: 
        !          1740: ;---------------------------Private-Routine-----------------------------;
        !          1741: ; do_some_clipping
        !          1742: ;
        !          1743: ; Inputs:
        !          1744: ;       eax = garbage
        !          1745: ;       ebx = fl
        !          1746: ;       ecx = x0
        !          1747: ;       edx = garbage
        !          1748: ;       esi = x1
        !          1749: ;       edi = garbage
        !          1750: ;
        !          1751: ; Decides whether to do simple or complex clipping.
        !          1752: ;
        !          1753: ;-----------------------------------------------------------------------;
        !          1754: 
        !          1755:         align 4
        !          1756: 
        !          1757:         public  do_some_clipping
        !          1758: do_some_clipping:
        !          1759:         testb   ebx, FL_COMPLEX_CLIP
        !          1760:         jnz     initialize_complex_clipping
        !          1761: 
        !          1762: ;-----------------------------------------------------------------------;
        !          1763: ; simple_clipping
        !          1764: ;
        !          1765: ; Inputs:
        !          1766: ;       ebx = fl
        !          1767: ;       ecx = x0
        !          1768: ;       esi = x1
        !          1769: ; Output:
        !          1770: ;       ebx = fl
        !          1771: ;       ecx = new x0 (stack variable updated too)
        !          1772: ;       esi = new x1
        !          1773: ;       y0 stack variable updated
        !          1774: ; Uses:
        !          1775: ;       All registers
        !          1776: ; Exits:
        !          1777: ;       to done_clipping
        !          1778: ;
        !          1779: ; This routine handles clipping the line to the clip rectangle (it's
        !          1780: ; faster to handle this case in the driver than to call the engine to
        !          1781: ; clip for us).
        !          1782: ;
        !          1783: ; Fractional end-point lines complicate our lives a bit when doing
        !          1784: ; clipping:
        !          1785: ;
        !          1786: ; 1) For styling, we must know the unclipped line's length in pels, so
        !          1787: ;    that we can correctly update the styling state when the line is
        !          1788: ;    clipped.  For this reason, I do clipping after doing the hard work
        !          1789: ;    of figuring out which pixels are at the ends of the line (this is
        !          1790: ;    wasted work if the line is not styled and is completely clipped,
        !          1791: ;    but I think it's simpler this way).  Another reason is that we'll
        !          1792: ;    have calculated eqGamma already, which we use for the intercept
        !          1793: ;    calculations.
        !          1794: ;
        !          1795: ;    With the assumption that most lines will not be completely clipped
        !          1796: ;    away, this strategy isn't too painful.
        !          1797: ;
        !          1798: ; 2) x0, y0 are not necessarily zero, where (x0, y0) is the start pel of
        !          1799: ;    the line.
        !          1800: ;
        !          1801: ; 3) We know x0, y0 and x1, but not y1.  We haven't needed to calculate
        !          1802: ;    y1 until now.  We'll need the actual value, and not an upper bound
        !          1803: ;    like y1 = LFLOOR(dM) + 2 because we have to be careful when
        !          1804: ;    calculating x(y) that y0 <= y <= y1, otherwise we can cause an
        !          1805: ;    overflow on the divide (which, needless to say, is bad).
        !          1806: ;
        !          1807: ;-----------------------------------------------------------------------;
        !          1808: 
        !          1809:         public  simple_clipping
        !          1810: simple_clipping:
        !          1811:         mov     edi, prclClip           ; get pointer to normalized clip rect
        !          1812:         and     ebx, FL_RECTLCLIP_MASK  ;   (it's lower-right exclusive)
        !          1813: 
        !          1814:         .errnz  (FL_RECTLCLIP_SHIFT - 2); ((ebx AND FL_RECTLCLIP_MASK) shr
        !          1815:         .errnz  (size RECTL) - 16       ;   FL_RECTLCLIP_SHIFT) is our index
        !          1816:         lea     edi, [edi + ebx*4]      ;   into the array of rectangles
        !          1817: 
        !          1818:         mov     edx, [edi].xRight       ; load the rect coordinates
        !          1819:         mov     eax, [edi].xLeft
        !          1820:         mov     ebx, [edi].yBottom
        !          1821:         mov     edi, [edi].yTop
        !          1822: 
        !          1823: ; Translate to our origin and so some quick completely clipped tests:
        !          1824: 
        !          1825:         sub     edx, x
        !          1826:         cmp     ecx, edx
        !          1827:         jge     totally_clipped         ; totally clipped if x0 >= xRight
        !          1828: 
        !          1829:         sub     eax, x
        !          1830:         cmp     esi, eax
        !          1831:         jl      totally_clipped         ; totally clipped if x1 < xLeft
        !          1832: 
        !          1833:         sub     ebx, y
        !          1834:         cmp     y0, ebx
        !          1835:         jge     totally_clipped         ; totally clipped if y0 >= yBottom
        !          1836: 
        !          1837:         sub     edi, y
        !          1838: 
        !          1839: ; Save some state:
        !          1840: 
        !          1841:         mov     xClipRight, edx
        !          1842:         mov     xClipLeft, eax
        !          1843: 
        !          1844:         cmp     esi, edx                ; if (x1 >= xRight) x1 = xRight - 1
        !          1845:         jl      short calculate_y1
        !          1846:         lea     esi, [edx - 1]
        !          1847: 
        !          1848: calculate_y1:
        !          1849:         mov     eax, esi                ; y1 = (x1 * dN + eqGamma) / dM
        !          1850:         mul     dN
        !          1851:         add     eax, eqGamma_lo
        !          1852:         adc     edx, eqGamma_hi
        !          1853:         div     dM
        !          1854: 
        !          1855:         cmp     edi, eax                ; if (yTop > y1) clipped
        !          1856:         jg      short totally_clipped
        !          1857: 
        !          1858:         cmp     ebx, eax                ; if (yBottom > y1) know x1
        !          1859:         jg      short x1_computed
        !          1860: 
        !          1861:         mov     eax, ebx                ; x1 = (yBottom * dM + eqBeta) / dN
        !          1862:         mul     dM
        !          1863:         stc
        !          1864:         sbb     eax, eqGamma_lo
        !          1865:         sbb     edx, eqGamma_hi
        !          1866:         div     dN
        !          1867:         mov     esi, eax
        !          1868: 
        !          1869: ; At this point, we've taken care of calculating the intercepts with the
        !          1870: ; right and bottom edges.  Now we work on the left and top edges:
        !          1871: 
        !          1872: x1_computed:
        !          1873:         mov     edx, y0
        !          1874: 
        !          1875:         mov     eax, xClipLeft          ; don't have to compute y intercept
        !          1876:         cmp     eax, ecx                ;   at left edge if line starts to
        !          1877:         jle     short top_intercept     ;   right of left edge
        !          1878: 
        !          1879:         mov     ecx, eax                ; x0 = xLeft
        !          1880:         mul     dN                      ; y0 = (xLeft * dN + eqGamma) / dM
        !          1881:         add     eax, eqGamma_lo
        !          1882:         adc     edx, eqGamma_hi
        !          1883:         div     dM
        !          1884: 
        !          1885:         cmp     ebx, eax                ; if (yBottom <= y0) clipped
        !          1886:         jle     short totally_clipped
        !          1887: 
        !          1888:         mov     edx, eax
        !          1889:         mov     y0, eax
        !          1890: 
        !          1891: top_intercept:
        !          1892:         mov     ebx, fl                 ; get ready to leave
        !          1893:         mov     x0, ecx
        !          1894: 
        !          1895:         cmp     edi, edx                ; if (yTop <= y0) done clipping
        !          1896:         jle     done_clipping
        !          1897: 
        !          1898:         mov     eax, edi                ; x0 = (yTop * dM + eqBeta) / dN + 1
        !          1899:         mul     dM
        !          1900:         stc
        !          1901:         sbb     eax, eqGamma_lo
        !          1902:         sbb     edx, eqGamma_hi
        !          1903:         div     dN
        !          1904:         lea     ecx, [eax + 1]
        !          1905: 
        !          1906:         cmp     xClipRight, ecx         ; if (xRight <= x0) clipped
        !          1907:         jle     short totally_clipped
        !          1908: 
        !          1909:         mov     y0, edi                 ; y0 = yTop
        !          1910:         mov     x0, ecx
        !          1911:         jmp     done_clipping           ; all done!
        !          1912: 
        !          1913: totally_clipped:
        !          1914: 
        !          1915: ; The line is completely clipped.  See if we have to update our style state:
        !          1916: 
        !          1917:         mov     ebx, fl
        !          1918:         testb   ebx, FL_STYLED
        !          1919:         jz      next_line
        !          1920: 
        !          1921: ; Adjust our style state:
        !          1922: 
        !          1923:         mov     esi, pls
        !          1924:         mov     eax, [esi].LS_spNext
        !          1925:         add     eax, cStylePels
        !          1926:         mov     [esi].LS_spNext, eax
        !          1927: 
        !          1928:         cmp     eax, [esi].LS_spTotal2
        !          1929:         jb      next_line
        !          1930: 
        !          1931: ; Have to normalize first:
        !          1932: 
        !          1933:         xor     edx, edx
        !          1934:         div     [esi].LS_spTotal2
        !          1935:         mov     [esi].LS_spNext, edx
        !          1936: 
        !          1937:         jmp     next_line
        !          1938: 
        !          1939: ;-----------------------------------------------------------------------;
        !          1940: 
        !          1941: initialize_complex_clipping:
        !          1942:         mov     eax, dN                 ; save a copy of original dN
        !          1943:         mov     dN_Original, eax
        !          1944: 
        !          1945: ;---------------------------Private-Routine-----------------------------;
        !          1946: ; continue_complex_clipping
        !          1947: ;
        !          1948: ; Inputs:
        !          1949: ;       ebx = fl
        !          1950: ; Output:
        !          1951: ;       ebx = fl
        !          1952: ;       ecx = x0
        !          1953: ;       esi = x1
        !          1954: ; Uses:
        !          1955: ;       All registers.
        !          1956: ; Exits:
        !          1957: ;       to done_clipping
        !          1958: ;
        !          1959: ; This routine handles the necessary initialization for the next
        !          1960: ; run in the CLIPLINE structure.
        !          1961: ;
        !          1962: ; NOTE: This routine is jumped to from two places!
        !          1963: ;-----------------------------------------------------------------------;
        !          1964: 
        !          1965:         public  continue_complex_clipping
        !          1966: continue_complex_clipping:
        !          1967:         mov     edi, prun
        !          1968:         mov     ecx, xStart
        !          1969:         testb   ebx, FL_FLIP_H
        !          1970:         jz      short complex_left_to_right
        !          1971: 
        !          1972: complex_right_to_left:
        !          1973: 
        !          1974: ; Figure out x0 and x1 for right-to-left lines:
        !          1975: 
        !          1976:         add     ecx, cStylePels
        !          1977:         dec     ecx
        !          1978:         mov     esi, ecx                ; esi = ecx = xStart + cStylePels - 1
        !          1979:         sub     ecx, [edi].RUN_iStop    ; New x0
        !          1980:         sub     esi, [edi].RUN_iStart   ; New x1
        !          1981:         jmp     short complex_reset_variables
        !          1982: 
        !          1983: complex_left_to_right:
        !          1984: 
        !          1985: ; Figure out x0 and x1 for left-to-right lines:
        !          1986: 
        !          1987:         mov     esi, ecx                ; esi = ecx = xStart
        !          1988:         add     ecx, [edi].RUN_iStart   ; New x0
        !          1989:         add     esi, [edi].RUN_iStop    ; New x1
        !          1990: 
        !          1991: complex_reset_variables:
        !          1992:         mov     x0, ecx
        !          1993: 
        !          1994: ; The half flip mucks with some of our variables, and we have to reset
        !          1995: ; them every pass.  We would have to reset eqGamma too, but it never
        !          1996: ; got saved to memory in its modified form.
        !          1997: 
        !          1998:         add     edi, size RUN
        !          1999:         mov     prun, edi               ; Increment run pointer for next time
        !          2000: 
        !          2001:         mov     edi, pls
        !          2002:         mov     eax, [edi].LS_spComplex
        !          2003:         mov     [edi].LS_spNext, eax    ; pls->spNext = pls->spComplex
        !          2004: 
        !          2005:         mov     eax, dN_Original        ; dN = dN_Original
        !          2006:         mov     dN, eax
        !          2007: 
        !          2008:         mul     ecx
        !          2009:         add     eax, eqGamma_lo
        !          2010:         adc     edx, eqGamma_hi         ; [edx:eax] = dN*x0 + eqGamma
        !          2011: 
        !          2012:         div     dM
        !          2013:         mov     y0, eax
        !          2014:         jmp     done_clipping
        !          2015: 
        !          2016: endProc bLines
        !          2017: 
        !          2018:         end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.