Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2036 lines
69 KiB

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