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

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