|
|
1.1 ! root 1: ;---------------------------Module-Header------------------------------; ! 2: ; Module Name: lines.asm ! 3: ; ! 4: ; ASM version of the line DDA calculator. ! 5: ; ! 6: ; Copyright (c) 1992 Microsoft Corporation ! 7: ;-----------------------------------------------------------------------; ! 8: ! 9: .386 ! 10: ! 11: .model small,c ! 12: ! 13: assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT ! 14: assume fs:nothing,gs:nothing ! 15: ! 16: .xlist ! 17: include stdcall.inc ;calling convention cmacros ! 18: include i386\strucs.inc ! 19: include i386\lines.inc ! 20: .list ! 21: ! 22: .data ! 23: ! 24: public gaflRoundTable ! 25: gaflRoundTable label dword ! 26: dd FL_H_ROUND_DOWN + FL_V_ROUND_DOWN ; no flips ! 27: dd FL_H_ROUND_DOWN + FL_V_ROUND_DOWN ; D flip ! 28: dd FL_H_ROUND_DOWN ; V flip ! 29: dd FL_V_ROUND_DOWN ; D & V flip ! 30: dd FL_V_ROUND_DOWN ; slope one ! 31: dd 0baadf00dh ! 32: dd FL_H_ROUND_DOWN ; slope one & V flip ! 33: dd 0baadf00dh ! 34: ! 35: .code ! 36: ! 37: ;--------------------------------Macro----------------------------------; ! 38: ; testb ebx, <mask> ! 39: ; ! 40: ; Substitutes a byte compare if the mask is entirely in the lo-byte or ! 41: ; hi-byte (thus saving 3 bytes of code space). ! 42: ; ! 43: ;-----------------------------------------------------------------------; ! 44: ! 45: TESTB macro targ,mask,thirdarg ! 46: local mask2,delta ! 47: ! 48: ifnb <thirdarg> ! 49: .err TESTB mask must be enclosed in brackets! ! 50: endif ! 51: ! 52: delta = 0 ! 53: mask2 = mask ! 54: ! 55: if mask2 AND 0ffff0000h ! 56: test targ,mask ; If bit set in hi-word, ! 57: exitm ; test entire dword ! 58: endif ! 59: ! 60: if mask2 AND 0ff00h ! 61: if mask2 AND 0ffh ; If bit set in lo-byte and ! 62: test targ,mask ; hi-byte, test entire dword ! 63: exitm ! 64: endif ! 65: ! 66: mask2 = mask2 SHR 8 ! 67: delta = 1 ! 68: endif ! 69: ! 70: ifidni <targ>,<EBX> ! 71: if delta ! 72: test bh,mask2 ! 73: else ! 74: test bl,mask2 ! 75: endif ! 76: exitm ! 77: endif ! 78: ! 79: .err Too bad TESTB doesn't support targets other than ebx! ! 80: endm ! 81: ! 82: ;---------------------------Public-Routine------------------------------; ! 83: ; bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls, ! 84: ; prclClip, apfn[], flStart) ! 85: ; ! 86: ; Handles lines with trivial or simple clipping. ! 87: ; ! 88: ;-----------------------------------------------------------------------; ! 89: ! 90: cProc bLines,36,< \ ! 91: uses esi edi ebx, \ ! 92: ppdev: ptr, \ ! 93: pptfxFirst: ptr, \ ! 94: pptfxBuf: ptr, \ ! 95: prun: ptr, \ ! 96: cptfx: dword, \ ! 97: pls: ptr, \ ! 98: prclClip: ptr, \ ! 99: apfn: ptr, \ ! 100: flStart: dword > ! 101: ! 102: local pptfxBufEnd: ptr ; Last point in pptfxBuf ! 103: local M0: dword ; Normalized x0 in device coords ! 104: local dM: dword ; Delta-x in device coords ! 105: local N0: dword ; Normalized y0 in device coords ! 106: local dN: dword ; Delta-y in device coords ! 107: local fl: dword ; Flags for current line ! 108: local x: dword ; Normalized start pixel x-coord ! 109: local y: dword ; Normalized start pixel y-coord ! 110: local eqGamma_lo: dword ; Upper 32 bits of Gamma ! 111: local eqGamma_hi: dword ; Lower 32 bits of Gamma ! 112: local x0: dword ; Start pixel x-offset ! 113: local y0: dword ; Start pixel y-offset ! 114: local ulSlopeOneAdjustment: dword ; Special offset if line of slope 1 ! 115: local cStylePels: dword ; # of pixels in line (before clip) ! 116: local xStart: dword ; Start pixel x-offset before clip ! 117: local pfn: ptr ; Pointer to strip drawing function ! 118: local cPels: dword ; # pixels to be drawn (after clip) ! 119: local i: dword ; # pixels in strip ! 120: local r: dword ; Remainder (or "error") term ! 121: local d_I: dword ; Delta-I ! 122: local d_R: dword ; Delta-R ! 123: local plStripEnd: ptr ; Last strip in buffer ! 124: local ptlStart[size POINTL]: byte ; Unnormalized start coord ! 125: local dN_Original: dword ; dN before half-flip ! 126: local xClipLeft: dword ; Left side of clip rectangle ! 127: local xClipRight: dword ; Right side of clip rectangle ! 128: local strip[size STRIPS]: byte ; Our strip buffer ! 129: ! 130: mov ecx, cptfx ! 131: mov edx, pptfxBuf ! 132: lea eax, [edx + ecx * (size POINTL) - (size POINTL)] ! 133: mov pptfxBufEnd, eax ; pptfxBufEnd is inclusive of end point ! 134: ! 135: mov eax, [edx].ptl_x ; Load up end point (M1, N1) ! 136: mov edi, [edx].ptl_y ! 137: ! 138: mov edx, pptfxFirst ; Load up start point (M0, N0) ! 139: mov esi, [edx].ptl_x ! 140: mov ecx, [edx].ptl_y ! 141: ! 142: mov ebx, flStart ! 143: ! 144: ;-----------------------------------------------------------------------; ! 145: ; Flip to the first octant. ; ! 146: ;-----------------------------------------------------------------------; ! 147: ! 148: ; Register state: esi = M0 ! 149: ; ecx = N0 ! 150: ; eax = dM (M1) ! 151: ; edi = dN (N1) ! 152: ; ebx = fl ! 153: ! 154: ; Make sure we go left to right: ! 155: ! 156: the_main_loop: ! 157: cmp esi, eax ! 158: jle short is_left_to_right ; skip if M0 <= M1 ! 159: xchg esi, eax ; swap M0, M1 ! 160: xchg ecx, edi ; swap N0, N1 ! 161: or ebx, FL_FLIP_H ! 162: ! 163: is_left_to_right: ! 164: ! 165: ; Compute the deltas, remembering that the DDI says we should get ! 166: ; deltas less than 2^31. If we get more, we ensure we don't crash ! 167: ; later on by simply skipping the line: ! 168: ! 169: sub eax, esi ; eax = dM ! 170: jo next_line ; dM must be less than 2^31 ! 171: sub edi, ecx ; edi = dN ! 172: jo next_line ; dN must be less than 2^31 ! 173: ! 174: jge short is_top_to_bottom ; skip if dN >= 0 ! 175: neg ecx ; N0 = -N0 ! 176: neg edi ; N1 = -N1 ! 177: or ebx, FL_FLIP_V ! 178: ! 179: is_top_to_bottom: ! 180: cmp edi, eax ! 181: jb short done_flips ; skip if dN < dM ! 182: jne short slope_more_than_one ! 183: ! 184: ; We must special case slopes of one: ! 185: ! 186: or ebx, FL_FLIP_SLOPE_ONE ! 187: jmp short done_flips ! 188: ! 189: slope_more_than_one: ! 190: xchg eax, edi ; swap dM, dN ! 191: xchg esi, ecx ; swap M0, N0 ! 192: or ebx, FL_FLIP_D ! 193: ! 194: done_flips: ! 195: ! 196: mov edx, ebx ! 197: and edx, FL_ROUND_MASK ! 198: .errnz FL_ROUND_SHIFT - 2 ! 199: or ebx, [gaflRoundTable + edx] ; get our rounding flags ! 200: ! 201: mov dM, eax ; save some info ! 202: mov dN, edi ! 203: mov fl, ebx ! 204: ! 205: mov edx, esi ; x = LFLOOR(M0) ! 206: sar edx, FLOG2 ! 207: mov x, edx ! 208: ! 209: mov edx, ecx ; y = LFLOOR(N0) ! 210: sar edx, FLOG2 ! 211: mov y, edx ! 212: ! 213: ;-----------------------------------------------------------------------; ! 214: ; Compute the fractional remainder term ; ! 215: ;-----------------------------------------------------------------------; ! 216: ! 217: public compute_fractional ! 218: compute_fractional: ! 219: and esi, F - 1 ; M0 = FXFRAC(M0) ! 220: and ecx, F - 1 ; N0 = FXFRAC(N0) ! 221: ! 222: mov M0, esi ; save M0, N0 for later ! 223: mov N0, ecx ! 224: ! 225: lea edx, [ecx + F/2] ! 226: mul edx ; [edx:eax] = dM * (N0 + F/2) ! 227: xchg eax, edi ! 228: mov ecx, edx ; [ecx:edi] = dM * (N0 + F/2) ! 229: ; (we just nuked N0) ! 230: ! 231: mul esi ; [edx:eax] = dN * M0 ! 232: ! 233: ; Now gamma = dM * (N0 + F/2) - dN * M0 - bRoundDown ! 234: ! 235: .errnz FL_V_ROUND_DOWN - 8000h ! 236: ror bh, 8 ! 237: sbb edi, eax ! 238: sbb ecx, edx ! 239: ! 240: shrd edi, ecx, FLOG2 ! 241: sar ecx, FLOG2 ; gamma = [ecx:edi] >>= 4 ! 242: ! 243: mov eqGamma_hi, ecx ! 244: mov eqGamma_lo, edi ! 245: ! 246: mov eax, N0 ! 247: ! 248: ; Register state: ! 249: ; eax = N0 ! 250: ; ebx = fl ! 251: ; ecx = eqGamma_hi ! 252: ; edx = garbage ! 253: ; esi = M0 ! 254: ; edi = eqGamma_lo ! 255: ! 256: testb ebx, FL_FLIP_H ! 257: jnz line_runs_right_to_left ! 258: ! 259: ;-----------------------------------------------------------------------; ! 260: ; Figure out which pixels are at the ends of a left-to-right line. ; ! 261: ; --------> ; ! 262: ;-----------------------------------------------------------------------; ! 263: ! 264: public line_runs_left_to_right ! 265: line_runs_left_to_right: ! 266: or esi, esi ! 267: jz short LtoR_check_slope_one ! 268: ; skip ahead if M0 == 0 ! 269: ; (in that case, x0 = 0 which is to be ! 270: ; kept in esi, and is already ! 271: ; conventiently zero) ! 272: ! 273: or eax, eax ! 274: jnz short LtoR_N0_not_zero ! 275: ! 276: .errnz FL_H_ROUND_DOWN - 80h ! 277: ror bl, 8 ! 278: sbb esi, -F/2 ! 279: shr esi, FLOG2 ! 280: jmp short LtoR_check_slope_one ! 281: ; esi = x0 = rounded M0 ! 282: ! 283: LtoR_N0_not_zero: ! 284: sub eax, F/2 ! 285: sbb edx, edx ! 286: xor eax, edx ! 287: sub eax, edx ! 288: cmp esi, eax ! 289: sbb esi, esi ! 290: inc esi ; esi = x0 = (abs(N0 - F/2) <= M0) ! 291: ! 292: public LtoR_check_slope_one ! 293: LtoR_check_slope_one: ! 294: mov ulSlopeOneAdjustment, 0 ! 295: mov eax, ebx ! 296: and eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN ! 297: cmp eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN ! 298: jne short LtoR_compute_y0_from_x0 ! 299: ! 300: ; We have to special case lines that are exactly of slope 1 or -1: ! 301: ! 302: mov eax, N0 ! 303: add eax, dN ! 304: and eax, F - 1 ; eax = N1 ! 305: jz short LtoR_slope_one_check_start_point ! 306: ! 307: mov edx, M0 ! 308: add edx, dM ! 309: and edx, F - 1 ; edx = M1 ! 310: ! 311: add eax, F/2 ! 312: cmp edx, eax ; cmp M1, N1 + F/2 ! 313: jne short LtoR_slope_one_check_start_point ! 314: mov ulSlopeOneAdjustment, -1 ! 315: ! 316: LtoR_slope_one_check_start_point: ! 317: mov eax, M0 ! 318: or eax, eax ! 319: jz short LtoR_compute_y0_from_x0 ! 320: ! 321: add eax, F/2 ! 322: cmp eax, N0 ; cmp M0 + 8, N0 ! 323: jne short LtoR_compute_y0_from_x0 ! 324: ! 325: xor esi, esi ; x0 = 0 ! 326: ! 327: LtoR_compute_y0_from_x0: ! 328: ! 329: ; ecx = eqGamma_hi ! 330: ; esi = x0 ! 331: ; edi = eqGamma_lo ! 332: ! 333: mov eax, dN ! 334: mov edx, dM ! 335: ! 336: mov x0, esi ! 337: mov y0, 0 ! 338: cmp ecx, 0 ! 339: jl short LtoR_compute_x1 ! 340: ! 341: neg esi ! 342: and esi, eax ! 343: sub edx, esi ! 344: cmp edi, edx ! 345: mov edx, dM ! 346: jl short LtoR_compute_x1 ! 347: mov y0, 1 ; y0 = floor((dN * x0 + eqGamma) / dM) ! 348: ! 349: LtoR_compute_x1: ! 350: ! 351: ; Register state: ! 352: ; eax = dN ! 353: ; ebx = fl ! 354: ; ecx = garbage ! 355: ; edx = dM ! 356: ; esi = garbage ! 357: ; edi = garbage ! 358: ! 359: mov esi, M0 ! 360: add esi, edx ! 361: mov ecx, esi ! 362: shr esi, FLOG2 ! 363: dec esi ; x1 = ((M0 + dM) >> 4) - 1 ! 364: add esi, ulSlopeOneAdjustment ! 365: and ecx, F-1 ; M1 = (M0 + dM) & 15 ! 366: jz done_first_pel_last_pel ! 367: ! 368: add eax, N0 ! 369: and eax, F-1 ; N1 = (N0 + dN) & 15 ! 370: jnz short LtoR_N1_not_zero ! 371: ! 372: .errnz FL_H_ROUND_DOWN - 80h ! 373: ror bl, 8 ! 374: sbb ecx, -F/2 ! 375: shr ecx, FLOG2 ; ecx = LROUND(M1, fl & FL_ROUND_DOWN) ! 376: add esi, ecx ! 377: jmp done_first_pel_last_pel ! 378: ! 379: LtoR_N1_not_zero: ! 380: sub eax, F/2 ! 381: sbb edx, edx ! 382: xor eax, edx ! 383: sub eax, edx ! 384: cmp eax, ecx ! 385: jg done_first_pel_last_pel ! 386: inc esi ! 387: jmp done_first_pel_last_pel ! 388: ! 389: ;-----------------------------------------------------------------------; ! 390: ; Figure out which pixels are at the ends of a right-to-left line. ; ! 391: ; <-------- ; ! 392: ;-----------------------------------------------------------------------; ! 393: ! 394: ; Compute x0: ! 395: ! 396: public line_runs_right_to_left ! 397: line_runs_right_to_left: ! 398: mov x0, 1 ; x0 = 1 ! 399: or eax, eax ! 400: jnz short RtoL_N0_not_zero ! 401: ! 402: xor edx, edx ; ulDelta = 0 ! 403: .errnz FL_H_ROUND_DOWN - 80h ! 404: ror bl, 8 ! 405: sbb esi, -F/2 ! 406: shr esi, FLOG2 ; esi = LROUND(M0, fl & FL_H_ROUND_DOWN) ! 407: jz short RtoL_check_slope_one ! 408: ! 409: mov x0, 2 ! 410: mov edx, dN ! 411: jmp short RtoL_check_slope_one ! 412: ! 413: RtoL_N0_not_zero: ! 414: sub eax, F/2 ! 415: sbb edx, edx ! 416: xor eax, edx ! 417: sub eax, edx ! 418: add eax, esi ; eax = ABS(N0 - F/2) + M0 ! 419: xor edx, edx ; ulDelta = 0 ! 420: cmp eax, F ! 421: jle short RtoL_check_slope_one ! 422: ! 423: mov x0, 2 ; x0 = 2 ! 424: mov edx, dN ; ulDelta = dN ! 425: ! 426: public RtoL_check_slope_one ! 427: RtoL_check_slope_one: ! 428: mov ulSlopeOneAdjustment, 0 ! 429: mov eax, ebx ! 430: and eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN ! 431: cmp eax, FL_FLIP_SLOPE_ONE ! 432: jne short RtoL_compute_y0_from_x0 ! 433: ! 434: ; We have to special case lines that are exactly of slope 1 or -1: ! 435: ! 436: mov eax, N0 ! 437: add eax, dN ! 438: and eax, F - 1 ; eax = N1 ! 439: jz short RtoL_slope_one_check_start_point ! 440: ! 441: mov esi, M0 ! 442: add esi, dM ! 443: and esi, F - 1 ; esi = M1 ! 444: ! 445: add eax, F/2 ! 446: cmp esi, eax ; cmp M1, N1 + F/2 ! 447: jne short RtoL_slope_one_check_start_point ! 448: mov ulSlopeOneAdjustment, 1 ! 449: ! 450: RtoL_slope_one_check_start_point: ! 451: mov eax, M0 ! 452: or eax, eax ! 453: jz short RtoL_compute_y0_from_x0 ! 454: ! 455: add eax, F/2 ! 456: cmp eax, N0 ; cmp M0 + 8, N0 ! 457: jne short RtoL_compute_y0_from_x0 ! 458: ! 459: mov x0, 2 ; x0 = 2 ! 460: mov edx, dN ; ulDelta = dN ! 461: ! 462: RtoL_compute_y0_from_x0: ! 463: ! 464: ; eax = garbage ! 465: ; ebx = fl ! 466: ; ecx = eqGamma_hi ! 467: ; edx = ulDelta ! 468: ; esi = garbage ! 469: ; edi = eqGamma_lo ! 470: ! 471: mov eax, dN ; eax = dN ! 472: mov y0, 0 ; y0 = 0 ! 473: ! 474: add edi, edx ! 475: adc ecx, 0 ; eqGamma += ulDelta ! 476: ; NOTE: Setting flags here! ! 477: mov edx, dM ; edx = dM ! 478: jl short RtoL_compute_x1 ; NOTE: Looking at the flags here! ! 479: jg short RtoL_y0_is_2 ! 480: ! 481: lea ecx, [edx + edx] ! 482: sub ecx, eax ; ecx = 2 * dM - dN ! 483: cmp edi, ecx ! 484: jge short RtoL_y0_is_2 ! 485: ! 486: sub ecx, edx ; ecx = dM - dN ! 487: cmp edi, ecx ! 488: jl short RtoL_compute_x1 ! 489: ! 490: mov y0, 1 ! 491: jmp short RtoL_compute_x1 ! 492: ! 493: RtoL_y0_is_2: ! 494: mov y0, 2 ! 495: ! 496: RtoL_compute_x1: ! 497: ! 498: ; Register state: ! 499: ; eax = dN ! 500: ; ebx = fl ! 501: ; ecx = garbage ! 502: ; edx = dM ! 503: ; esi = garbage ! 504: ; edi = garbage ! 505: ! 506: mov esi, M0 ! 507: add esi, edx ! 508: mov ecx, esi ! 509: shr esi, FLOG2 ; x1 = (M0 + dM) >> 4 ! 510: add esi, ulSlopeOneAdjustment ! 511: and ecx, F-1 ; M1 = (M0 + dM) & 15 ! 512: ! 513: add eax, N0 ! 514: and eax, F-1 ; N1 = (N0 + dN) & 15 ! 515: jnz short RtoL_N1_not_zero ! 516: ! 517: .errnz FL_H_ROUND_DOWN - 80h ! 518: ror bl, 8 ! 519: sbb ecx, -F/2 ! 520: shr ecx, FLOG2 ; ecx = LROUND(M1, fl & FL_ROUND_DOWN) ! 521: add esi, ecx ! 522: jmp done_first_pel_last_pel ! 523: ! 524: RtoL_N1_not_zero: ! 525: sub eax, F/2 ! 526: sbb edx, edx ! 527: xor eax, edx ! 528: sub eax, edx ! 529: add eax, ecx ; eax = ABS(N1 - F/2) + M1 ! 530: cmp eax, F+1 ! 531: sbb esi, -1 ! 532: ! 533: done_first_pel_last_pel: ! 534: ! 535: ; Register state: ! 536: ; eax = garbage ! 537: ; ebx = fl ! 538: ; ecx = garbage ! 539: ; edx = garbage ! 540: ; esi = x1 ! 541: ; edi = garbage ! 542: ! 543: mov ecx, x0 ! 544: lea edx, [esi + 1] ! 545: sub edx, ecx ; edx = x1 - x0 + 1 ! 546: ! 547: jle next_line ! 548: mov cStylePels, edx ! 549: mov xStart, ecx ! 550: ! 551: ;-----------------------------------------------------------------------; ! 552: ; See if clipping or styling needs to be done. ; ! 553: ;-----------------------------------------------------------------------; ! 554: ! 555: testb ebx, FL_CLIP ! 556: jnz do_some_clipping ! 557: ! 558: ; Register state: ! 559: ; eax = garbage ! 560: ; ebx = fl ! 561: ; ecx = x0 ! 562: ; edx = garbage ! 563: ; esi = x1 ! 564: ; edi = garbage ! 565: ! 566: done_clipping: ! 567: mov eax, y0 ! 568: ! 569: sub esi, ecx ! 570: inc esi ; esi = cPels = x1 - x0 + 1 ! 571: mov cPels, esi ! 572: ! 573: add ecx, x ; ecx = ptlStart.ptl_x ! 574: add eax, y ; eax = ptlStart.ptl_y ! 575: ! 576: testb ebx, FL_FLIP_D ! 577: jz short do_v_unflip ! 578: xchg ecx, eax ! 579: ! 580: do_v_unflip: ! 581: testb ebx, FL_FLIP_V ! 582: jz short done_unflips ! 583: neg eax ! 584: ! 585: done_unflips: ! 586: testb ebx, FL_STYLED ! 587: jnz do_some_styling ! 588: ! 589: done_styling: ! 590: lea edx, [strip.ST_alStrips + (STRIP_MAX * 4)] ! 591: mov plStripEnd, edx ! 592: ! 593: ;-----------------------------------------------------------------------; ! 594: ; Setup to do DDA. ; ! 595: ;-----------------------------------------------------------------------; ! 596: ! 597: ; Register state: ! 598: ; eax = ptlStart.ptl_y ! 599: ; ebx = fl ! 600: ; ecx = ptlStart.ptl_x ! 601: ; edx = garbage ! 602: ; esi = garbage ! 603: ; edi = garbage ! 604: ! 605: mov strip.ST_ptlStart.ptl_x, ecx ! 606: mov strip.ST_ptlStart.ptl_y, eax ! 607: ! 608: mov eax, dM ! 609: mov ecx, dN ! 610: mov esi, eqGamma_lo ! 611: mov edi, eqGamma_hi ! 612: ! 613: ! 614: ; Register state: ! 615: ; eax = dM ! 616: ; ebx = fl ! 617: ; ecx = dN ! 618: ; edx = garbage ! 619: ; esi = eqGamma_lo ! 620: ; edi = eqGamma_hi ! 621: ! 622: lea edx, [ecx + ecx] ; if (2 * dN > dM) ! 623: cmp edx, eax ! 624: mov edx, y0 ; Load y0 again ! 625: jbe short after_half_flip ! 626: ! 627: test ebx, (FL_STYLED + FL_DONT_DO_HALF_FLIP) ! 628: jnz short after_half_flip ! 629: ! 630: or ebx, FL_FLIP_HALF ! 631: mov fl, ebx ! 632: ! 633: ; Do a half flip! ! 634: ! 635: not esi ! 636: not edi ! 637: add esi, eax ! 638: adc edi, 0 ; eqGamma = -eqGamma - 1 + dM ! 639: ! 640: neg ecx ! 641: add ecx, eax ; dN = dM - dN ! 642: ! 643: neg edx ! 644: add edx, x0 ; y0 = x0 - y0 ! 645: ! 646: after_half_flip: ! 647: mov strip.ST_flFlips, ebx ! 648: mov eax, dM ! 649: ! 650: ; Register state: ! 651: ; eax = dM ! 652: ; ebx = fl ! 653: ; ecx = dN ! 654: ; edx = y0 ! 655: ; esi = eqGamma_lo ! 656: ; edi = eqGamma_hi ! 657: ! 658: or ecx, ecx ! 659: jz short zero_slope ! 660: ! 661: compute_dda_stuff: ! 662: inc edx ! 663: mul edx ! 664: stc ; set the carry to accomplish -1 ! 665: sbb eax, esi ! 666: sbb edx, edi ; (y0 + 1) * dM - eqGamma - 1 ! 667: div ecx ! 668: ! 669: mov esi, eax ; esi = i ! 670: mov edi, edx ; edi = r ! 671: ! 672: xor edx, edx ! 673: mov eax, dM ! 674: div ecx ; edx = d_R, eax = d_I ! 675: mov d_I, eax ! 676: ! 677: sub esi, x0 ! 678: inc esi ! 679: ! 680: done_dda_stuff: ! 681: ! 682: ; Register state: ! 683: ; eax = d_I ! 684: ; ebx = fl ! 685: ; ecx = dN ! 686: ; edx = d_R ! 687: ; esi = i ! 688: ; edi = r ! 689: ! 690: ; We're going to decide if we can call the short-vector routines. They ! 691: ; can only take strips that have a maximum length of 15 pixels each. ! 692: ; We happen to know that the longest strip in our line could be is d_I + 1. ! 693: ! 694: and ebx, FL_STRIP_MASK ! 695: mov eax, apfn ! 696: ! 697: .errnz FL_STRIP_SHIFT ! 698: lea eax, [eax + ebx * 4] ! 699: ! 700: cmp d_I, MAX_SHORT_STROKE_LENGTH ! 701: sbb ebx, ebx ; ffffffffh when < 15, 0 when >= 15 ! 702: and ebx, NUM_STRIP_DRAW_DIRECTIONS * 4 ! 703: ; Look four entries further into table ! 704: ! 705: mov eax, [eax + ebx] ! 706: mov pfn, eax ! 707: ! 708: lea eax, [strip.ST_alStrips] ! 709: mov ebx, cPels ! 710: ! 711: ;-----------------------------------------------------------------------; ! 712: ; Do our main DDA loop. ; ! 713: ;-----------------------------------------------------------------------; ! 714: ! 715: ; Register state: ! 716: ; eax = plStrip ! 717: ; ebx = cPels ! 718: ; ecx = dN ! 719: ; edx = d_R ! 720: ; esi = i ! 721: ; edi = r ! 722: ! 723: dda_loop: ! 724: sub ebx, esi ! 725: jle final_strip ! 726: ! 727: mov [eax], esi ! 728: add eax, 4 ! 729: cmp plStripEnd, eax ! 730: jbe short output_strips ! 731: ! 732: done_output_strips: ! 733: mov esi, d_I ! 734: add edi, edx ! 735: cmp edi, ecx ! 736: jb short dda_loop ! 737: ! 738: sub edi, ecx ! 739: inc esi ! 740: jmp short dda_loop ! 741: ! 742: zero_slope: ! 743: mov esi, 7fffffffh ; Make run maximum length (cPels ! 744: ; actually decideds how long the line ! 745: ; is) ! 746: mov d_I, 7fffffffh ; Make delta maximum length so that ! 747: ; we don't try to do short vectors ! 748: mov eax, cPels ; We need this when we decide if to do ! 749: dec eax ; short strip routines. ! 750: jmp short done_dda_stuff ! 751: ! 752: ;-----------------------------------------------------------------------; ! 753: ; Empty strips buffer. ; ! 754: ;-----------------------------------------------------------------------; ! 755: ! 756: output_strips: ! 757: mov d_R, edx ! 758: mov cPels, ebx ! 759: mov i, esi ! 760: mov r, edi ! 761: mov dN, ecx ! 762: ! 763: lea edx, [strip.ST_alStrips] ! 764: sub eax, edx ! 765: shr eax, 2 ! 766: mov strip.ST_cStrips, eax ! 767: ! 768: mov eax, ppdev ! 769: lea edx, [strip] ! 770: mov ecx, pls ! 771: ! 772: ptrCall <dword ptr pfn>, \ ! 773: <eax, edx, ecx> ! 774: ! 775: mov esi, i ! 776: mov edi, r ! 777: mov ebx, cPels ! 778: mov edx, d_R ! 779: mov ecx, dN ! 780: lea eax, [strip.ST_alStrips] ! 781: jmp done_output_strips ! 782: ! 783: ;-----------------------------------------------------------------------; ! 784: ; Empty strips buffer and go on to next line. ; ! 785: ;-----------------------------------------------------------------------; ! 786: ! 787: final_strip: ! 788: add ebx, esi ! 789: mov [eax], ebx ! 790: add eax, 4 ! 791: ! 792: very_final_strip: ! 793: lea edx, [strip.ST_alStrips] ! 794: sub eax, edx ! 795: shr eax, 2 ! 796: mov strip.ST_cStrips, eax ! 797: ! 798: mov eax, ppdev ! 799: lea edx, [strip] ! 800: mov ecx, pls ! 801: ! 802: ptrCall <dword ptr pfn>, \ ! 803: <eax, edx, ecx> ! 804: ! 805: next_line: ! 806: mov ebx, flStart ! 807: testb ebx, FL_COMPLEX_CLIP ! 808: jnz short see_if_done_complex_clipping ! 809: ! 810: mov edx, pptfxBuf ! 811: cmp edx, pptfxBufEnd ! 812: je short all_done ! 813: ! 814: mov esi, [edx].ptl_x ! 815: mov ecx, [edx].ptl_y ! 816: add edx, size POINTL ! 817: mov pptfxBuf, edx ! 818: mov eax, [edx].ptl_x ! 819: mov edi, [edx].ptl_y ! 820: jmp the_main_loop ! 821: ! 822: all_done: ! 823: mov eax, 1 ! 824: ! 825: cRet bLines ! 826: ! 827: see_if_done_complex_clipping: ! 828: mov ebx, fl ! 829: dec cptfx ! 830: jz short all_done ! 831: jmp continue_complex_clipping ! 832: ! 833: ;---------------------------Private-Routine-----------------------------; ! 834: ; do_some_styling ! 835: ; ! 836: ; Inputs: ! 837: ; eax = ptlStart.ptl_y ! 838: ; ebx = fl ! 839: ; ecx = ptlStart.ptl_x ! 840: ; Preserves: ! 841: ; eax, ebx, ecx ! 842: ; Output: ! 843: ; Exits to done_styling. ! 844: ; ! 845: ;-----------------------------------------------------------------------; ! 846: ! 847: do_some_styling: ! 848: mov ptlStart.ptl_x, ecx ! 849: ! 850: mov esi, pls ! 851: mov edi, [esi].LS_spNext ; spThis ! 852: mov edx, edi ! 853: add edx, cStylePels ; spNext ! 854: ! 855: ; For styles, we don't bother to keep the style position normalized. ! 856: ; (we do ensure that it's positive, though). If a figure is over 2 ! 857: ; billion pels long, we'll be a pel off in our style state (oops!). ! 858: ! 859: and edx, 7fffffffh ! 860: mov [esi].LS_spNext, edx ! 861: mov ptlStart.ptl_y, eax ! 862: ! 863: ; Do arbitrary styles: ! 864: ! 865: do_arbitrary_style: ! 866: testb ebx, FL_FLIP_H ! 867: jz short arbitrary_left_to_right ! 868: ! 869: sub edx, x0 ! 870: add edx, xStart ! 871: mov eax, edx ! 872: xor edx, edx ! 873: div [esi].LS_spTotal ! 874: ! 875: neg edx ! 876: jge short continue_right_to_left ! 877: add edx, [esi].LS_spTotal ! 878: not eax ! 879: ! 880: continue_right_to_left: ! 881: mov edi, dword ptr [esi].LS_jStartMask ! 882: not edi ! 883: mov ecx, [esi].LS_aspRtoL ! 884: jmp short compute_arbitrary_stuff ! 885: ! 886: arbitrary_left_to_right: ! 887: add edi, x0 ! 888: sub edi, xStart ! 889: mov eax, edi ! 890: xor edx, edx ! 891: div [esi].LS_spTotal ! 892: mov edi, dword ptr [esi].LS_jStartMask ! 893: mov ecx, [esi].LS_aspLtoR ! 894: ! 895: compute_arbitrary_stuff: ! 896: ; eax = sp / spTotal ! 897: ; ebx = fl ! 898: ; ecx = pspStart ! 899: ; edx = sp % spTotal ! 900: ; esi = pla ! 901: ; edi = jStyleMask ! 902: ! 903: and eax, [esi].LS_cStyle ; if odd length style and second run ! 904: and al, 1 ; through style array, flip the ! 905: jz short odd_style_array_done ; meaning of the elements ! 906: not edi ! 907: ! 908: odd_style_array_done: ! 909: mov [esi].LS_pspStart, ecx ! 910: mov eax, [esi].LS_cStyle ! 911: lea eax, [ecx + eax * 4 - 4] ! 912: mov [esi].LS_pspEnd, eax ! 913: ! 914: find_psp: ! 915: sub edx, [ecx] ! 916: jl short found_psp ! 917: add ecx, 4 ! 918: jmp short find_psp ! 919: ! 920: found_psp: ! 921: mov [esi].LS_psp, ecx ! 922: neg edx ! 923: mov [esi].LS_spRemaining, edx ! 924: ! 925: sub ecx, [esi].LS_pspStart ! 926: test ecx, 4 ; size STYLEPOS ! 927: jz short done_arbitrary ! 928: not edi ! 929: ! 930: done_arbitrary: ! 931: mov dword ptr [esi].LS_jStyleMask, edi ! 932: mov eax, ptlStart.ptl_y ! 933: mov ecx, ptlStart.ptl_x ! 934: jmp done_styling ! 935: ! 936: ! 937: ;---------------------------Private-Routine-----------------------------; ! 938: ; do_some_clipping ! 939: ; ! 940: ; Inputs: ! 941: ; eax = garbage ! 942: ; ebx = fl ! 943: ; ecx = x0 ! 944: ; edx = garbage ! 945: ; esi = x1 ! 946: ; edi = garbage ! 947: ; ! 948: ; Decides whether to do simple or complex clipping. ! 949: ; ! 950: ;-----------------------------------------------------------------------; ! 951: ! 952: align 4 ! 953: ! 954: public do_some_clipping ! 955: do_some_clipping: ! 956: testb ebx, FL_COMPLEX_CLIP ! 957: jnz initialize_complex_clipping ! 958: ! 959: ;-----------------------------------------------------------------------; ! 960: ; simple_clipping ! 961: ; ! 962: ; Inputs: ! 963: ; ebx = fl ! 964: ; ecx = x0 ! 965: ; esi = x1 ! 966: ; Output: ! 967: ; ebx = fl ! 968: ; ecx = new x0 (stack variable updated too) ! 969: ; esi = new x1 ! 970: ; y0 stack variable updated ! 971: ; Uses: ! 972: ; All registers ! 973: ; Exits: ! 974: ; to done_clipping ! 975: ; ! 976: ; This routine handles clipping the line to the clip rectangle (it's ! 977: ; faster to handle this case in the driver than to call the engine to ! 978: ; clip for us). ! 979: ; ! 980: ; Fractional end-point lines complicate our lives a bit when doing ! 981: ; clipping: ! 982: ; ! 983: ; 1) For styling, we must know the unclipped line's length in pels, so ! 984: ; that we can correctly update the styling state when the line is ! 985: ; clipped. For this reason, I do clipping after doing the hard work ! 986: ; of figuring out which pixels are at the ends of the line (this is ! 987: ; wasted work if the line is not styled and is completely clipped, ! 988: ; but I think it's simpler this way). Another reason is that we'll ! 989: ; have calculated eqGamma already, which we use for the intercept ! 990: ; calculations. ! 991: ; ! 992: ; With the assumption that most lines will not be completely clipped ! 993: ; away, this strategy isn't too painful. ! 994: ; ! 995: ; 2) x0, y0 are not necessarily zero, where (x0, y0) is the start pel of ! 996: ; the line. ! 997: ; ! 998: ; 3) We know x0, y0 and x1, but not y1. We haven't needed to calculate ! 999: ; y1 until now. We'll need the actual value, and not an upper bound ! 1000: ; like y1 = LFLOOR(dM) + 2 because we have to be careful when ! 1001: ; calculating x(y) that y0 <= y <= y1, otherwise we can cause an ! 1002: ; overflow on the divide (which, needless to say, is bad). ! 1003: ; ! 1004: ;-----------------------------------------------------------------------; ! 1005: ! 1006: public simple_clipping ! 1007: simple_clipping: ! 1008: mov edi, prclClip ; get pointer to normalized clip rect ! 1009: and ebx, FL_RECTLCLIP_MASK ; (it's lower-right exclusive) ! 1010: ! 1011: .errnz (FL_RECTLCLIP_SHIFT - 2); ((ebx AND FL_RECTLCLIP_MASK) shr ! 1012: .errnz (size RECTL) - 16 ; FL_RECTLCLIP_SHIFT) is our index ! 1013: lea edi, [edi + ebx*4] ; into the array of rectangles ! 1014: ! 1015: mov edx, [edi].xRight ; load the rect coordinates ! 1016: mov eax, [edi].xLeft ! 1017: mov ebx, [edi].yBottom ! 1018: mov edi, [edi].yTop ! 1019: ! 1020: ; Translate to our origin and so some quick completely clipped tests: ! 1021: ! 1022: sub edx, x ! 1023: cmp ecx, edx ! 1024: jge totally_clipped ; totally clipped if x0 >= xRight ! 1025: ! 1026: sub eax, x ! 1027: cmp esi, eax ! 1028: jl totally_clipped ; totally clipped if x1 < xLeft ! 1029: ! 1030: sub ebx, y ! 1031: cmp y0, ebx ! 1032: jge totally_clipped ; totally clipped if y0 >= yBottom ! 1033: ! 1034: sub edi, y ! 1035: ! 1036: ; Save some state: ! 1037: ! 1038: mov xClipRight, edx ! 1039: mov xClipLeft, eax ! 1040: ! 1041: cmp esi, edx ; if (x1 >= xRight) x1 = xRight - 1 ! 1042: jl short calculate_y1 ! 1043: lea esi, [edx - 1] ! 1044: ! 1045: calculate_y1: ! 1046: mov eax, esi ; y1 = (x1 * dN + eqGamma) / dM ! 1047: mul dN ! 1048: add eax, eqGamma_lo ! 1049: adc edx, eqGamma_hi ! 1050: div dM ! 1051: ! 1052: cmp edi, eax ; if (yTop > y1) clipped ! 1053: jg short totally_clipped ! 1054: ! 1055: cmp ebx, eax ; if (yBottom > y1) know x1 ! 1056: jg short x1_computed ! 1057: ! 1058: mov eax, ebx ; x1 = (yBottom * dM + eqBeta) / dN ! 1059: mul dM ! 1060: stc ! 1061: sbb eax, eqGamma_lo ! 1062: sbb edx, eqGamma_hi ! 1063: div dN ! 1064: mov esi, eax ! 1065: ! 1066: ; At this point, we've taken care of calculating the intercepts with the ! 1067: ; right and bottom edges. Now we work on the left and top edges: ! 1068: ! 1069: x1_computed: ! 1070: mov edx, y0 ! 1071: ! 1072: mov eax, xClipLeft ; don't have to compute y intercept ! 1073: cmp eax, ecx ; at left edge if line starts to ! 1074: jle short top_intercept ; right of left edge ! 1075: ! 1076: mov ecx, eax ; x0 = xLeft ! 1077: mul dN ; y0 = (xLeft * dN + eqGamma) / dM ! 1078: add eax, eqGamma_lo ! 1079: adc edx, eqGamma_hi ! 1080: div dM ! 1081: ! 1082: cmp ebx, eax ; if (yBottom <= y0) clipped ! 1083: jle short totally_clipped ! 1084: ! 1085: mov edx, eax ! 1086: mov y0, eax ! 1087: ! 1088: top_intercept: ! 1089: mov ebx, fl ; get ready to leave ! 1090: mov x0, ecx ! 1091: ! 1092: cmp edi, edx ; if (yTop <= y0) done clipping ! 1093: jle done_clipping ! 1094: ! 1095: mov eax, edi ; x0 = (yTop * dM + eqBeta) / dN + 1 ! 1096: mul dM ! 1097: stc ! 1098: sbb eax, eqGamma_lo ! 1099: sbb edx, eqGamma_hi ! 1100: div dN ! 1101: lea ecx, [eax + 1] ! 1102: ! 1103: cmp xClipRight, ecx ; if (xRight <= x0) clipped ! 1104: jle short totally_clipped ! 1105: ! 1106: mov y0, edi ; y0 = yTop ! 1107: mov x0, ecx ! 1108: jmp done_clipping ; all done! ! 1109: ! 1110: totally_clipped: ! 1111: ! 1112: ; The line is completely clipped. See if we have to update our style state: ! 1113: ! 1114: mov ebx, fl ! 1115: testb ebx, FL_STYLED ! 1116: jz next_line ! 1117: ! 1118: ; Adjust our style state: ! 1119: ! 1120: mov esi, pls ! 1121: mov eax, [esi].LS_spNext ! 1122: add eax, cStylePels ! 1123: mov [esi].LS_spNext, eax ! 1124: ! 1125: cmp eax, [esi].LS_spTotal2 ! 1126: jb next_line ! 1127: ! 1128: ; Have to normalize first: ! 1129: ! 1130: xor edx, edx ! 1131: div [esi].LS_spTotal2 ! 1132: mov [esi].LS_spNext, edx ! 1133: ! 1134: jmp next_line ! 1135: ! 1136: ;-----------------------------------------------------------------------; ! 1137: ! 1138: initialize_complex_clipping: ! 1139: mov eax, dN ; save a copy of original dN ! 1140: mov dN_Original, eax ! 1141: ! 1142: ;---------------------------Private-Routine-----------------------------; ! 1143: ; continue_complex_clipping ! 1144: ; ! 1145: ; Inputs: ! 1146: ; ebx = fl ! 1147: ; Output: ! 1148: ; ebx = fl ! 1149: ; ecx = x0 ! 1150: ; esi = x1 ! 1151: ; Uses: ! 1152: ; All registers. ! 1153: ; Exits: ! 1154: ; to done_clipping ! 1155: ; ! 1156: ; This routine handles the necessary initialization for the next ! 1157: ; run in the CLIPLINE structure. ! 1158: ; ! 1159: ; NOTE: This routine is jumped to from two places! ! 1160: ;-----------------------------------------------------------------------; ! 1161: ! 1162: public continue_complex_clipping ! 1163: continue_complex_clipping: ! 1164: mov edi, prun ! 1165: mov ecx, xStart ! 1166: testb ebx, FL_FLIP_H ! 1167: jz short complex_left_to_right ! 1168: ! 1169: complex_right_to_left: ! 1170: ! 1171: ; Figure out x0 and x1 for right-to-left lines: ! 1172: ! 1173: add ecx, cStylePels ! 1174: dec ecx ! 1175: mov esi, ecx ; esi = ecx = xStart + cStylePels - 1 ! 1176: sub ecx, [edi].RUN_iStop ; New x0 ! 1177: sub esi, [edi].RUN_iStart ; New x1 ! 1178: jmp short complex_reset_variables ! 1179: ! 1180: complex_left_to_right: ! 1181: ! 1182: ; Figure out x0 and x1 for left-to-right lines: ! 1183: ! 1184: mov esi, ecx ; esi = ecx = xStart ! 1185: add ecx, [edi].RUN_iStart ; New x0 ! 1186: add esi, [edi].RUN_iStop ; New x1 ! 1187: ! 1188: complex_reset_variables: ! 1189: mov x0, ecx ! 1190: ! 1191: ; The half flip mucks with some of our variables, and we have to reset ! 1192: ; them every pass. We would have to reset eqGamma too, but it never ! 1193: ; got saved to memory in its modified form. ! 1194: ! 1195: add edi, size RUN ! 1196: mov prun, edi ; Increment run pointer for next time ! 1197: ! 1198: mov edi, pls ! 1199: mov eax, [edi].LS_spComplex ! 1200: mov [edi].LS_spNext, eax ; pls->spNext = pls->spComplex ! 1201: ! 1202: mov eax, dN_Original ; dN = dN_Original ! 1203: mov dN, eax ! 1204: ! 1205: mul ecx ! 1206: add eax, eqGamma_lo ! 1207: adc edx, eqGamma_hi ; [edx:eax] = dN*x0 + eqGamma ! 1208: ! 1209: div dM ! 1210: mov y0, eax ! 1211: jmp done_clipping ! 1212: ! 1213: endProc bLines ! 1214: end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.