home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / video / 6 / 6_4.asm < prev    next >
Encoding:
Assembly Source File  |  1988-08-11  |  8.4 KB  |  365 lines

  1.         TITLE    'Listing 6-4'
  2.         NAME    Line06
  3.         PAGE    55,132
  4.  
  5. ;
  6. ; Name:        Line06
  7. ;
  8. ; Function:    Draw a line in 640x200 2-color mode
  9. ;
  10. ; Caller:    Microsoft C:
  11. ;
  12. ;            void Line06(x1,y1,x2,y2,n);
  13. ;
  14. ;            int x1,y1,x2,y2;    /* pixel coordinates */
  15. ;
  16. ;            int n;            /* pixel value */
  17. ;
  18.  
  19. ARGx1        EQU    word ptr [bp+4]    ; stack frame addressing
  20. ARGy1        EQU    word ptr [bp+6]
  21. ARGx2        EQU    word ptr [bp+8]
  22. ARGy2        EQU    word ptr [bp+10]
  23. ARGn        EQU    byte ptr [bp+12]
  24. VARleafincr    EQU    word ptr [bp-2]
  25. VARincr1    EQU    word ptr [bp-4]
  26. VARincr2    EQU    word ptr [bp-6]
  27. VARroutine    EQU    word ptr [bp-8]
  28.  
  29. ByteOffsetShift    EQU    3        ; used to convert pixels to byte offset
  30.  
  31. DGROUP        GROUP    _DATA
  32.  
  33. _TEXT        SEGMENT    byte public 'CODE'
  34.         ASSUME    cs:_TEXT,ds:DGROUP
  35.  
  36.         EXTRN    PixelAddr06:near
  37.  
  38.         PUBLIC    _Line06
  39. _Line06        PROC    near
  40.  
  41.         push    bp        ; preserve caller registers
  42.         mov    bp,sp
  43.         sub    sp,8        ; stack space for local variables
  44.         push    si
  45.         push    di
  46.  
  47.  
  48.         mov    si,2000h    ; increment for video buffer interleave
  49.         mov    di,80-2000h    ; increment from last to first interleave
  50.  
  51.         mov    cx,ARGx2
  52.         sub    cx,ARGx1    ; CX := x2 - x1
  53.         jz    VertLine06    ; jump if vertical line
  54.  
  55. ; force x1 < x2
  56.  
  57.         jns    L01        ; jump if x2 > x1
  58.  
  59.         neg    cx        ; CX := x1 - x2
  60.         
  61.         mov    bx,ARGx2    ; exchange x1 and x2
  62.         xchg    bx,ARGx1
  63.         mov    ARGx2,bx
  64.  
  65.         mov    bx,ARGy2    ; exchange y1 and y2
  66.         xchg    bx,ARGy1
  67.         mov    ARGy2,bx
  68.  
  69. ; calculate dy = ABS(y2-y1)
  70.  
  71. L01:        mov    bx,ARGy2
  72.         sub    bx,ARGy1    ; BX := y2 - y1
  73.         jnz    L02
  74.  
  75.         jmp    HorizLine06    ; jump if horizontal line
  76.  
  77. L02:        jns    L03
  78.  
  79.         neg    bx        ; BX := y1 - y2
  80.         neg    si        ; negate increments for buffer interleave
  81.         neg    di
  82.         xchg    si,di        ; exchange increments
  83.  
  84. ; select appropriate routine for slope of line
  85.  
  86. L03:        mov    VARleafincr,di    ; save increment for buffer interleave
  87.  
  88.         mov    VARroutine,offset LoSlopeLine06
  89.         cmp    bx,cx
  90.         jle    L04        ; jump if dy <= dx (slope <= 1)
  91.         mov    VARroutine,offset HiSlopeLine06
  92.         xchg    bx,cx        ; exchange dy and dx
  93.  
  94. ; calculate initial decision variable and increments
  95.  
  96. L04:        shl    bx,1        ; BX := 2 * dy
  97.         mov    VARincr1,bx    ; incr1 := 2 * dy
  98.         sub    bx,cx
  99.         mov    di,bx        ; DI := d = 2 * dy - dx
  100.         sub    bx,cx
  101.         mov    VARincr2,bx    ; incr2 := 2 * (dy - dx)
  102.  
  103. ; calculate first pixel address
  104.  
  105.         push    cx        ; preserve this register
  106.         mov    ax,ARGy1    ; AX := y
  107.         mov    bx,ARGx1    ; BX := x
  108.         call    PixelAddr06    ; AH := bit mask
  109.                     ; ES:BX -> buffer
  110.                     ; CL := # bits to shift left
  111.  
  112.         mov    al,ARGn        ; AL := unshifted pixel value
  113.         shl    ax,cl        ; AH := bit mask in proper position
  114.                     ; AL := pixel value in proper position
  115.  
  116.         mov    dx,ax        ; DH := bit mask
  117.                     ; DL := pixel value
  118.         not    dh        ; DH := inverse bit mask
  119.  
  120.         pop    cx        ; restore this register
  121.         inc    cx        ; CX := # of pixels to draw
  122.  
  123.         test    bx,2000h    ; set zero flag if BX in 1st interleave
  124.         jz    L05
  125.  
  126.         xchg    si,VARleafincr    ; exchange increment values if 1st pixel
  127.                     ;  lies in 1st interleave
  128.  
  129. L05:        jmp    VARroutine    ; jump to appropriate routine for slope
  130.  
  131.  
  132. ; routine for vertical lines
  133.  
  134. VertLine06:    mov    ax,ARGy1    ; AX := y1
  135.         mov    bx,ARGy2    ; BX := y2
  136.         mov    cx,bx
  137.         sub    cx,ax        ; CX := dy
  138.         jge    L31        ; jump if dy >= 0
  139.  
  140.         neg    cx        ; force dy >= 0
  141.         mov    ax,bx        ; AX := y2
  142.  
  143. L31:        inc    cx        ; CX := # of pixels to draw
  144.         mov    bx,ARGx1    ; BX := x
  145.         push    cx        ; preserve this register
  146.         call    PixelAddr06    ; AH := bit mask
  147.                     ; ES:BX -> video buffer
  148.                     ; CL := # bits to shift left
  149.         mov    al,ARGn        ; AL := pixel value
  150.         shl    ax,cl        ; AH := bit mask in proper position
  151.                     ; AL := pixel value in proper position
  152.         not    ah        ; AH := inverse bit mask
  153.         pop    cx        ; restore this register
  154.  
  155.         test    bx,si        ; set zero flag if BX in 1st interleave
  156.         jz    L32
  157.  
  158.         xchg    si,di        ; exchange increment values if 1st pixel
  159.                     ;  lies in 1st interleave
  160.  
  161. L32:        test    al,al
  162.         jz    L34        ; jump if pixel value = 0
  163.  
  164. L33:        or    es:[bx],al    ; set pixel values in buffer
  165.         add    bx,si        ; increment to next portion of interleave
  166.         xchg    si,di        ; toggle between increment values
  167.         loop    L33        ; loop down the line
  168.         jmp    short L35
  169.  
  170. L34:        and    es:[bx],ah    ; reset pixel values in buffer
  171.         add    bx,si        ; increment to next portion of interleave
  172.         xchg    si,di        ; toggle between increment values
  173.         loop    L34
  174.  
  175. L35:        jmp    Lexit
  176.  
  177.  
  178. ; routine for horizontal lines (slope = 0)
  179.  
  180. HorizLine06:    mov    ax,ARGy1
  181.         mov    bx,ARGx1
  182.         call    PixelAddr06    ; AH := bit mask
  183.                     ; ES:BX -> video buffer
  184.                     ; CL := # bits to shift left
  185.         mov    di,bx        ; ES:DI -> buffer
  186.  
  187.         mov    dh,ah
  188.         not    dh        ; DH := unshifted bit mask for leftmost
  189.                     ;        byte
  190.         mov    dl,0FFh        ; DL := unshifted bit mask for
  191.                     ;     rightmost byte
  192.  
  193.         shl    dh,cl        ; DH := reverse bit mask for first byte
  194.         not    dh        ; DH := bit mask for first byte
  195.  
  196.         mov    cx,ARGx2
  197.         and    cl,7
  198.         xor    cl,7        ; CL := number of bits to shift left
  199.         shl    dl,cl        ; DL := bit mask for last byte
  200.  
  201. ; determine byte offset of first and last pixel in the line
  202.  
  203.         mov    ax,ARGx2    ; AX := x2
  204.         mov    bx,ARGx1    ; BX := x1
  205.  
  206.         mov    cl,ByteOffsetShift    ; number of bits to shift to
  207.                         ;  convert pixels to bytes
  208.  
  209.         shr    ax,cl        ; AX := byte offset of x2
  210.         shr    bx,cl        ; BX := byte offset of x1
  211.         mov    cx,ax
  212.         sub    cx,bx        ; CX := (# bytes in line) - 1
  213.  
  214. ; propagate pixel value throughout one byte
  215.  
  216.         mov    bx,offset DGROUP:PropagatedPixel
  217.         mov    al,ARGn        ; AL := pixel value
  218.         xlat
  219.  
  220. ; set pixels in leftmost byte of the line
  221.  
  222.         or    dh,dh
  223.         js    L43        ; jump if byte-aligned (x1 is leftmost
  224.                     ;  pixel in byte)
  225.         or    cx,cx
  226.         jnz    L42        ; jump if more than one byte in the line
  227.  
  228.         and    dl,dh        ; bit mask for the line
  229.         jmp    short L44
  230.  
  231. L42:        mov    ah,al
  232.         and    ah,dh        ; AH := masked pixel bits
  233.         not    dh        ; DH := reverse bit mask for 1st byte
  234.         and    es:[di],dh    ; zero masked pixels in buffer
  235.         or    es:[di],ah    ; update masked pixels in buffer
  236.         inc    di
  237.         dec    cx
  238.  
  239. ; use a fast 8086 machine instruction to draw the remainder of the line
  240.  
  241. L43:        rep    stosb        ; update all pixels in the line
  242.  
  243. ; set pixels in the rightmost byte of the line
  244.  
  245. L44:        and    al,dl        ; AL := masked pixels for last byte
  246.         not    dl
  247.         and    es:[di],dl    ; zero masked pixels in buffer
  248.         or    es:[di],al    ; update masked pixels in buffer
  249.  
  250.         jmp    Lexit
  251.  
  252.  
  253. ; routine for dy <= dx (slope <= 1)    ; ES:BX -> video buffer
  254.                                         ; CX = # pixels to draw
  255.                     ; DH = inverse bit mask
  256.                     ; DL = pixel value in proper position
  257.                     ; SI = buffer interleave increment
  258.                     ; DI = decision variable
  259. LoSlopeLine06:
  260.  
  261. L10:        mov    ah,es:[bx]    ; AH := byte from video buffer
  262.  
  263. L11:        and    ah,dh        ; zero pixel value at current bit offset
  264.         or    ah,dl        ; set pixel value in byte
  265.  
  266.         ror    dl,1        ; rotate pixel value
  267.         ror    dh,1        ; rotate bit mask
  268.         jnc    L14        ; jump if bit mask rotated to
  269.                     ;  leftmost pixel position
  270.  
  271. ; bit mask not shifted out
  272.  
  273.         or    di,di        ; test sign of d
  274.         jns    L12        ; jump if d >= 0
  275.  
  276.         add    di,VARincr1    ; d := d + incr1
  277.         loop    L11
  278.  
  279.         mov    es:[bx],ah    ; store remaining pixels in buffer
  280.         jmp    short Lexit
  281.  
  282. L12:        add    di,VARincr2    ; d := d + incr2
  283.         mov    es:[bx],ah    ; update buffer
  284.  
  285.         add    bx,si        ; increment y
  286.         xchg    si,VARleafincr    ; exchange interleave increment values
  287.         loop    L10
  288.         jmp    short Lexit
  289.  
  290. ; bit mask shifted out
  291.  
  292. L14:        mov    es:[bx],ah    ; update buffer
  293.         inc    bx        ; BX := offset of next byte
  294.  
  295.         or    di,di        ; test sign of d
  296.         jns    L15        ; jump if non-negative
  297.  
  298.         add    di,VARincr1    ; d := d + incr1
  299.         loop    L10
  300.         jmp    short Lexit
  301.  
  302. L15:        add    di,VARincr2    ; d := d + incr2
  303.  
  304.         add    bx,si        ; increment y
  305.         xchg    si,VARleafincr
  306.  
  307.         loop    L10
  308.         jmp    short Lexit
  309.  
  310.  
  311. ; routine for dy > dx (slope > 1)    ; ES:BX -> video buffer
  312.                                         ; CX = # pixels to draw
  313.                     ; DH = inverse bit mask
  314.                     ; DL = pixel value in proper position
  315.                     ; SI = buffer interleave increment
  316.                     ; DI = decision variable
  317. HiSlopeLine06:
  318.  
  319. L21:        and    es:[bx],dh    ; zero pixel value in video buffer
  320.         or    es:[bx],dl    ; set pixel value in byte
  321.  
  322.         add    bx,si        ; increment y
  323.         xchg    si,VARleafincr    ; exchange interleave increment values
  324.  
  325. L22:        or    di,di        ; test sign of d
  326.         jns    L23        ; jump if d >= 0
  327.  
  328.         add    di,VARincr1    ; d := d + incr1
  329.         loop    L21
  330.  
  331.         jmp    short Lexit
  332.  
  333.  
  334. L23:        add    di,VARincr2    ; d := d + incr2
  335.  
  336.         ror    dl,1        ; rotate pixel value
  337.         ror    dh,1        ; rotate bit mask
  338.         cmc            ; cf set if bit mask not rotated to
  339.                     ;  leftmost pixel position
  340.  
  341.         adc    bx,0        ; BX := offset of next byte
  342.  
  343.         loop    L21
  344.  
  345.  
  346. Lexit:        pop    di        ; restore registers and return
  347.         pop    si
  348.         mov    sp,bp
  349.         pop    bp
  350.         ret
  351.  
  352. _Line06        ENDP
  353.  
  354. _TEXT        ENDS
  355.  
  356.  
  357. _DATA        SEGMENT    word public 'DATA'
  358.  
  359. PropagatedPixel    DB    00000000b    ; 0
  360.         DB    11111111b    ; 1
  361.  
  362. _DATA        ENDS
  363.  
  364.         END
  365.