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