home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapter57 / xsharp21.exe / SCAN.ASM < prev    next >
Assembly Source File  |  1992-06-10  |  8KB  |  169 lines

  1. ; Scan converts an edge from (X1,Y1) to (X2,Y2), not including the
  2. ; point at (X2,Y2). If SkipFirst == 1, the point at (X1,Y1) isn't
  3. ; drawn; if SkipFirst == 0, it is. For each scan line, the pixel
  4. ; closest to the scanned edge without being to the left of the scanned
  5. ; edge is chosen. Uses an all-integer approach for speed & precision.
  6. ;
  7. ; C near-callable as:
  8. ;    void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart,
  9. ;         int SkipFirst, struct HLine **EdgePointPtr);
  10. ;
  11. ; Edges must not go bottom to top; that is, Y1 must be <= Y2.
  12. ; Updates the pointer pointed to by EdgePointPtr to point to the next
  13. ;  free entry in the array of HLine structures.
  14.  
  15. HLine   struc
  16. XStart  dw      ?       ;X coordinate of leftmost pixel in scan line
  17. XEnd    dw      ?       ;X coordinate of rightmost pixel in scan line
  18. HLine   ends
  19.  
  20. Parms   struc
  21.                 dw      2 dup(?) ;return address & pushed BP
  22. X1              dw      ?       ;X start coord of edge
  23. Y1              dw      ?       ;Y start coord of edge
  24. X2              dw      ?       ;X end coord of edge
  25. Y2              dw      ?       ;Y end coord of edge
  26. SetXStart       dw      ?       ;1 to set the XStart field of each
  27.                                 ; HLine struc, 0 to set XEnd
  28. SkipFirst       dw      ?       ;1 to skip scanning the first point
  29.                                 ; of the edge, 0 to scan first point
  30. EdgePointPtr    dw      ?       ;pointer to a pointer to the array of
  31.                                 ; HLine structures in which to store
  32.                                 ; the scanned X coordinates
  33. Parms   ends
  34.  
  35. ;Offsets from BP in stack frame of local variables.
  36. AdvanceAmt      equ     -2
  37. Height          equ     -4
  38. LOCAL_SIZE      equ     4       ;total size of local variables
  39.  
  40.         .model small
  41.         .code
  42.         public _ScanEdge
  43.         align   2
  44. _ScanEdge       proc
  45.         push    bp              ;preserve caller's stack frame
  46.         mov     bp,sp           ;point to our stack frame
  47.         sub     sp,LOCAL_SIZE   ;allocate space for local variables
  48.         push    si              ;preserve caller's register variables
  49.         push    di
  50.         mov     di,[bp+EdgePointPtr]
  51.         mov     di,[di]         ;point to the HLine array
  52.         cmp     [bp+SetXStart],1 ;set the XStart field of each HLine
  53.                                 ; struc?
  54.         jz      HLinePtrSet     ;yes, DI points to the first XStart
  55.         add     di,XEnd         ;no, point to the XEnd field of the
  56.                                 ; first HLine struc
  57. HLinePtrSet:
  58.         mov     bx,[bp+Y2]
  59.         sub     bx,[bp+Y1]      ;edge height
  60.         jle     ToScanEdgeExit  ;guard against 0-length & horz edges
  61.         mov     [bp+Height],bx  ;Height = Y2 - Y1
  62.         sub     cx,cx           ;assume ErrorTerm starts at 0 (true if
  63.                                 ; we're moving right as we draw)
  64.         mov     dx,1            ;assume AdvanceAmt = 1 (move right)
  65.         mov     ax,[bp+X2]
  66.         sub     ax,[bp+X1]      ;DeltaX = X2 - X1
  67.         jz      IsVertical      ;it's a vertical edge--special case it
  68.         jns     SetAdvanceAmt   ;DeltaX >= 0
  69.         mov     cx,1            ;DeltaX < 0 (move left as we draw)
  70.         sub     cx,bx           ;ErrorTerm = -Height + 1
  71.         neg     dx              ;AdvanceAmt = -1 (move left)
  72.         neg     ax              ;Width = abs(DeltaX)
  73. SetAdvanceAmt:
  74.         mov     [bp+AdvanceAmt],dx
  75. ; Figure out whether the edge is diagonal, X-major (more horizontal),
  76. ; or Y-major (more vertical) and handle appropriately.
  77.         cmp     ax,bx           ;if Width==Height, it's a diagonal edge
  78.         jz      IsDiagonal      ;it's a diagonal edge--special case
  79.         jb      YMajor          ;it's a Y-major (more vertical) edge
  80.                                 ;it's an X-major (more horz) edge
  81.         sub     dx,dx           ;prepare DX:AX (Width) for division
  82.         div     bx              ;Width/Height
  83.                                 ;DX = error term advance per scan line
  84.         mov     si,ax           ;SI = minimum # of pixels to advance X
  85.                                 ; on each scan line
  86.         test    [bp+AdvanceAmt],8000h ;move left or right?
  87.         jz      XMajorAdvanceAmtSet ;right, already set
  88.         neg     si              ;left, negate the distance to advance
  89.                                 ; on each scan line
  90. XMajorAdvanceAmtSet:            ;
  91.         mov     ax,[bp+X1]      ;starting X coordinate
  92.         cmp     [bp+SkipFirst],1 ;skip the first point?
  93.         jz      XMajorSkipEntry ;yes
  94. XMajorLoop:
  95.         mov     [di],ax         ;store the current X value
  96.         add     di,size HLine   ;point to the next HLine struc
  97. XMajorSkipEntry:
  98.         add     ax,si           ;set X for the next scan line
  99.         add     cx,dx           ;advance error term
  100.         jle     XMajorNoAdvance ;not time for X coord to advance one
  101.                                 ; extra
  102.         add     ax,[bp+AdvanceAmt] ;advance X coord one extra
  103.         sub     cx,[bp+Height]  ;adjust error term back
  104. XMajorNoAdvance:
  105.         dec     bx              ;count off this scan line
  106.         jnz     XMajorLoop
  107.         jmp     ScanEdgeDone
  108.         align   2
  109. ToScanEdgeExit:
  110.         jmp     ScanEdgeExit
  111.         align   2
  112. IsVertical:
  113.         mov     ax,[bp+X1]      ;starting (and only) X coordinate
  114.         sub     bx,[bp+SkipFirst] ;loop count = Height - SkipFirst
  115.         jz      ScanEdgeExit    ;no scan lines left after skipping 1st
  116. VerticalLoop:
  117.         mov     [di],ax         ;store the current X value
  118.         add     di,size HLine   ;point to the next HLine struc
  119.         dec     bx              ;count off this scan line
  120.         jnz     VerticalLoop
  121.         jmp     ScanEdgeDone
  122.         align   2
  123. IsDiagonal:
  124.         mov     ax,[bp+X1]      ;starting X coordinate
  125.         cmp     [bp+SkipFirst],1 ;skip the first point?
  126.         jz      DiagonalSkipEntry ;yes
  127. DiagonalLoop:   
  128.         mov     [di],ax         ;store the current X value
  129.         add     di,size HLine   ;point to the next HLine struc
  130. DiagonalSkipEntry:
  131.         add     ax,dx           ;advance the X coordinate
  132.         dec     bx              ;count off this scan line
  133.         jnz     DiagonalLoop
  134.         jmp     ScanEdgeDone
  135.         align   2
  136. YMajor:
  137.         push    bp              ;preserve stack frame pointer
  138.         mov     si,[bp+X1]      ;starting X coordinate
  139.         cmp     [bp+SkipFirst],1 ;skip the first point?
  140.         mov     bp,bx           ;put Height in BP for error term calcs
  141.         jz      YMajorSkipEntry ;yes, skip the first point
  142. YMajorLoop:
  143.         mov     [di],si         ;store the current X value
  144.         add     di,size HLine   ;point to the next HLine struc
  145. YMajorSkipEntry:
  146.         add     cx,ax           ;advance the error term
  147.         jle     YMajorNoAdvance ;not time for X coord to advance
  148.         add     si,dx           ;advance the X coordinate
  149.         sub     cx,bp           ;adjust error term back
  150. YMajorNoAdvance:
  151.         dec     bx              ;count off this scan line
  152.         jnz     YMajorLoop
  153.         pop     bp              ;restore stack frame pointer
  154. ScanEdgeDone:
  155.         cmp     [bp+SetXStart],1 ;were we working with XStart field?
  156.         jz      UpdateHLinePtr  ;yes, DI points to the next XStart
  157.         sub     di,XEnd         ;no, point back to the XStart field
  158. UpdateHLinePtr:
  159.         mov     bx,[bp+EdgePointPtr] ;point to pointer to HLine array
  160.         mov     [bx],di         ;update caller's HLine array pointer
  161. ScanEdgeExit:
  162.         pop     di              ;restore caller's register variables
  163.         pop     si
  164.         mov     sp,bp           ;deallocate local variables
  165.         pop     bp              ;restore caller's stack frame
  166.         ret
  167. _ScanEdge       endp
  168.         end
  169.