Annotation of ntddk/src/video/displays/vga/i386/vgalines.asm, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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