home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / mresline.aqm / mresline.asm
Assembly Source File  |  1994-03-04  |  44KB  |  2,070 lines

  1.  9-May-86 06:12:38-PDT,21915;000000000001
  2. Return-Path: <dantowitz%eagle4.DEC@decwrl.DEC.COM>
  3. Received: FROM DECWRL.DEC.COM BY USC-ISIB.ARPA WITH TCP ; 9 May 86 06:10:41 PDT
  4. Received: from DEC-RHEA.ARPA (dec-rhea) by decwrl.DEC.COM (4.22.05/4.7.34)
  5.     id AA27526; Fri, 9 May 86 06:11:20 pdt
  6. Message-Id: <8605091311.AA27526@decwrl.DEC.COM>
  7. Date: Friday,  9 May 1986 06:07:42-PDT
  8. From: dantowitz%eagle4.DEC@decwrl.DEC.COM  (David .. LTN2-2/H07 -- DTN:226-6957)
  9. To: Info-IBMPC@USC-ISIB.ARPA, ibmpc%eagle4.DEC@decwrl.DEC.COM
  10. Subject: No Change in CODE, only in "Copyright (C)" notice
  11.  
  12. cseg segment
  13.      assume cs:cseg
  14. m_line proc near
  15.  
  16.  
  17. ;
  18. ;    Version 3.2m  DMD  Medium resolution graphics routine for drawing
  19. ;    April 30, 1986     lines on an IBMPC with the standard color
  20. ;                       graphics board.  Copyright (c) by David Dantowitz,
  21. ;                       April 30, 1986
  22. ;
  23.  
  24.  
  25. ;
  26. ;    This routine was written by David Dantowitz.  The routine
  27. ;    implements Bresenham's algorithm for line drawing.  
  28. ;
  29. ;    This routine may be used at the user's discretion for no charge
  30. ;    what so ever.  This software has been tested and should work
  31. ;    as documented, but no guarantees are made.  The user assumes
  32. ;    full responsibility for the assembly and use of this code.
  33. ;
  34. ;    Portions of this routine may be used in other contexts when proper
  35. ;    copyright and source identifications are made.  This code may
  36. ;    be modified to conform to other calling standards, but other
  37. ;    changes should be made only after consultation with the author.
  38. ;
  39. ;    This routine was written to be as general and as fast as possible,
  40. ;    any ideas for changes that result in improved speed would be 
  41. ;    appreciated by the author.  Support for other color graphics
  42. ;    boards is also possible and again the user is asked to contact
  43. ;    the author.
  44. ;
  45. ;
  46. ;    This implementation breaks lines into the following 8 categories,
  47. ;    the last four of which use Bresenham's algorithm.
  48. ;
  49. ;           horizontal
  50. ;           vertical
  51. ;           slope equal to 1
  52. ;           slope equal to -1
  53. ;           slope between 0 and 1
  54. ;           slope between 1 and infinity
  55. ;           slope between 0 and -1
  56. ;           slope between -1 and negative infinity
  57. ;
  58. ;    This routine does NOT check the points for bounds restrictions.
  59. ;    This is to enable well behaved software to run as fast as 
  60. ;    possible.  This routine is called by first pushing the X and
  61. ;    Y values for the first point and then the X and Y values for
  62. ;    the second point, and lastly the color for the line.
  63. ;    Note that the color is expected to be between 0 and 3.
  64. ;    Also note that all the parameters are words.
  65. ;
  66. ;
  67. ;    To use with TURBO Pascal you must assemble the file into a
  68. ;    .COM file.  To do this perfrom the following commands:
  69. ;
  70. ;    A> MASM MRESLINE;
  71. ;    A> LINK MRESLINE;
  72. ;    A> EXE2BIN MRESLINE.EXE MRESLINE.COM
  73. ;
  74. ;    When assembled into a .COM file (MRESLINE.ASM) this routine 
  75. ;    may be declared in TURBO Pascal with the following declaration:
  76. ;
  77. ;    PROCEDURE Med_res_line(X1, Y1, X2, Y2, Color : Integer); external 'mresline.com';
  78. ;           
  79. ;
  80. ;    Any suggestions for improvements are welcome and may be sent
  81. ;    to me at either of the addresses below.
  82. ;
  83. ;    David Dantowitz
  84. ;    Digital Equipment Corporation
  85. ;    Foster Street
  86. ;    LTN2-2/H07
  87. ;    Littleton, MA   01460
  88. ;
  89. ;    Dantowitz%Eagle1.DEC@decwrl.ARPA
  90. ;
  91. ;    
  92. ;
  93. ;    The views and ideas expressed here are my own and do not
  94. ;    necessarily reflect those of the Digital Equipment Corporation.
  95. ;
  96. ;
  97.  
  98. ;
  99. ;  Save the base pointer
  100. ;
  101.         push bp
  102.         mov bp,sp
  103.  
  104.  
  105. ;
  106. ;  Get the two points
  107. ;
  108.         mov ax,[bp+12]   ;   X1
  109.     mov cx,[bp+10]   ;   Y1
  110.  
  111.     mov bx,[bp+8]    ;   X2
  112.     mov dx,[bp+6]    ;   Y2
  113.  
  114. ;  The difference between X1 and X2 will be represented as dX.
  115. ;  Likewise for Y1 and Y2 (dY).
  116. ;
  117. ;  Note: all lines are drawn with the X value increasing.
  118. ;       
  119. ;  If dX < 0 exchange the two points
  120. ;
  121.  
  122.  
  123.     mov si,bx
  124.           sub si,ax        ; compute dX
  125.  
  126.     jg noswit     ; If dX > 0 then don't switch the points
  127.  
  128.  
  129. ;
  130. ;  Switch the points and reverse the sign of dX (SI)
  131. ;
  132.         neg si
  133.     xchg ax,bx
  134.     xchg cx,dx
  135.  
  136. noswit: mov bx,[bp+4]   ; Color
  137.  
  138.         mov bp,dx
  139.     sub bp,cx       ; compute dY
  140.  
  141.         xor di,di    ; di = 0
  142.  
  143. ;
  144. ;  All vertical lines are drawn with the Y value increasing.
  145.  
  146.  
  147.         cmp si,di            ; dX = 0 ?
  148.         jne noswit_2                    ; not a vertical line
  149.  
  150.  
  151.         cmp bp,di              ; dY > 0 ?
  152.         jg noswit_2            ; no need to switch points
  153.  
  154.         mov cx,dx            ; Just copy lower value, the higher
  155.                                 ; value is implied by dY.
  156.  
  157.         neg bp                      ; Change the sign of dY
  158.  
  159. noswit_2:
  160.  
  161. ; Compute the address of the first byte
  162.  
  163. ;
  164. ; AX = initial X
  165. ; BX = color
  166. ; CX = initial Y
  167. ; SI = dX                                       
  168. ; BP = dY
  169. ;
  170.  
  171.         mov dx,cx                  ; DX = starting Y
  172.  
  173.         and dl,0feh            ; DX = (Y DIV 2) * 2
  174.  
  175.         mov di,dx            ; DI = DX
  176.  
  177.         shl dx,1            ; DX = 4 * DX
  178.         shl dx,1                                     
  179.  
  180.         add di,dx            ; DI = DI + DX  {DI = 5 * (Y DIV 2) * 2)}
  181.  
  182.         shl di,1            ; DI = 8 * DI
  183.         shl di,1
  184.         shl di,1
  185.                                                      
  186. ;
  187. ;   Note that DI presently is equal to 80 * (Y DIV 2) ... the first byte
  188. ;   on the raster line that contains the first pixel of the line.
  189. ;
  190.  
  191. ;
  192. ;   (Screen memory for graphics is divided into two sections.  The even
  193. ;   raster lines have addresses 0 to 1F3Fh (80 bytes/line * 100 lines).
  194. ;   The odd raster lines have addresses 2000h to 3F3Fh.  Thus all lines
  195. ;   with odd Y coordinates have the 2000h bit set.
  196. ;
  197.  
  198.  
  199. ;   If odd then start in the second bank, otherwise start in the first bank.
  200.  
  201.         shr cl,1        
  202.         jnc t1
  203.         xor di,2000h
  204.  
  205.  
  206. t1:     mov cl,al            ; Save the low byte of X
  207.  
  208.         shr ax,1            ; AX = X DIV 4
  209.         shr ax,1
  210.  
  211.         add di,ax            ; DI = DI + AX
  212.  
  213. ; Note that DI now points to the byte that contains the first pixel
  214.  
  215.  
  216. ;
  217. ;   Save the data segment register.  Also load up the screen segment
  218. ;   register value into DS and ES.
  219. ;
  220.  
  221.         push ds
  222.         mov ax,0b800h
  223.         mov ds,ax            ; Used for screen access
  224.         mov es,ax            ; Used for horizontal lines
  225.  
  226. ;
  227. ;   DI now points to the first byte, but which bits are the first pixel ?
  228. ;   the low bits of CL (low bits of X) will tell us.
  229. ;
  230. ;
  231. ;   This sets up the single pixel mask.
  232.  
  233.         and cl,3            ; Just the low 2 bits
  234.  
  235.         shl cl,1            ; two bits/pixel
  236.  
  237. ;
  238. ;
  239. ;   C0 marks the first pixel
  240. ;   30 marks the second pixel
  241. ;   0C marks the third pixel
  242. ;   03 marks the forth pixel
  243. ;
  244.  
  245.         mov ah,0C0h            ; first bit position
  246.  
  247.         shr ah,cl            ; shift appropriately
  248.  
  249.  
  250. ;
  251. ;  We now set up the color mask, it has the following format:
  252. ;
  253. ;    bits :  7 6 5 4 3 2 1 0
  254. ;            C c C c C c C c
  255. ;
  256. ;  Where "C c" are the two bits used to specify the color of the pixel.
  257. ;
  258. ;
  259.         mov al,bl            ; starting color 
  260.                     ; AL = 000000Cc
  261.  
  262.         shl al,1
  263.         shl al,1
  264.         or al,bl            ; AL = 0000CcCc
  265.  
  266.         shl al,1
  267.         shl al,1
  268.         or al,bl            ; AL = 00CcCcCc
  269.  
  270.         shl al,1
  271.         shl al,1
  272.         or al,bl            ; AL = CcCcCcCc
  273.  
  274.         xor bx,bx            ; BX = 0
  275. ;        
  276. ; AH = pixel mask (which pixel within a byte)
  277. ; AL = color mask
  278. ; BX = 0
  279. ; CL = low two bits of X shifted one bit to the left 
  280. ;      (used later for horizontal lines)
  281. ; SI = dX
  282. ; BP = dY
  283. ; DI = points to the byte containing the first pixel
  284. ;
  285.  
  286.         cmp si,bx                ; dX = 0 ?
  287.         je vertical            ; The line is vertical
  288.  
  289.  
  290. ;
  291. ;   Here we know that dX is positive, so the sign of dY will
  292. ;   tell us the sign of the line's slope.
  293. ;  
  294.         cmp bp,bx            ; sign of dY ? 
  295.  
  296.         je horizontal             ; 0 ... horizontal line
  297.  
  298.     jg Slope_gtr_a            ; slope > 0
  299.  
  300.         jmp Slope_less            ; slope < 0
  301.  
  302. Slope_gtr_a:                      ; extra jump due to long distance
  303.         jmp Slope_gtr
  304.  
  305. ;
  306. ;   Version, author identification and copyright notice
  307. ;
  308.         db 'Version 3.2m - Copyright (c) David Dantowitz April 30, 1986'
  309.  
  310.  
  311. vertical label near
  312. ;
  313. ;   Vertical lines are drawn in two parts, the even rasters, then the odd
  314. ;   rasters.  (Note the order is dependent on the line's starting point.)
  315. ;
  316.  
  317.         mov cx,bp            ; # points = dY + 1
  318.         inc cx
  319.  
  320.         mov bp,80            ; a constant (# bytes/raster)
  321.  
  322.         shr cx,1                       ; divide in two (carry set if odd)
  323.         mov dx,cx                     ; save count (second half)
  324.  
  325.         adc cx,bx                       ; add the carry (bx=0)
  326.         mov si,di                         ; save starting point
  327.  
  328.  
  329.         mov bh,ah            ; pixel mask
  330.  
  331.         and bh,al                       ; get the color
  332.  
  333.         not ah                ; old pixel mask (unchanged pixels)
  334.  
  335.         cmp dx,0            ; If DX = 0 then there is only one point
  336.         je second_bank            ; don't draw in odd and even, just one.
  337.  
  338.  
  339. ;
  340. ;  Note that the code below is repeated in a similar fashion for most
  341. ;  of the actual pixel writing.  This code is only commented once.
  342. ;
  343.         
  344. first_bank:
  345.         mov bl,ah            ; copy the old pixel mask
  346.  
  347.         and bl,[di]            ; clear new pixel
  348.  
  349.         or bl,bh            ; add new pixel color
  350.  
  351.         mov [di],bl               ; save byte
  352.  
  353.         add di,bp            ; next line
  354.  
  355.     loop first_bank
  356.  
  357.         xor si,2000h            ; change the bank
  358.         mov cx,dx
  359.  
  360.  
  361.         cmp si,2000h               ; if second bank is even then
  362.         jge second_bank            ; go to the next raster.
  363.  
  364.         add si,bp
  365.         
  366. second_bank:
  367.  
  368.         mov bl,ah            ; copy the old pixel mask
  369.  
  370.         and bl,[si]            ; clear new pixel
  371.  
  372.         or bl,bh            ; add new pixel color
  373.  
  374.         mov [si],bl               ; save byte
  375.  
  376.         add si,bp            ; next line
  377.  
  378.     loop second_bank
  379.  
  380.     jmp ret_line        
  381.       
  382.  
  383. horizontal label near
  384.  
  385. ;
  386. ;  Horizontal lines are drawn mostly using the STOSW instruction.
  387. ;  Only the ends are drawn with explicit code.  Most of the code 
  388. ;  in this routine deals with words, not bytes. 
  389. ;
  390.         
  391. ;        As a reminder
  392. ;
  393. ; AH = pixel mask (which pixel within a byte)
  394. ; AL = color mask
  395. ; BX = 0
  396. ; CL = low two bits of X shifted one bit to the left 
  397. ;      (used here for horizontal lines)
  398. ; SI = dX
  399. ; BP = dY
  400. ; DI = points to the byte containing the first pixel
  401. ;
  402.  
  403. ;
  404. ;  If this is a short line then go to special set up code.
  405. ;
  406.         cmp si,3            ; If dX = 1 or 2 then short_horiz
  407.         jl short_horiz             ; (dX = 0 is a vertical line)
  408.  
  409.         inc si                ; # points = dX + 1
  410.  
  411.         mov ch,bh                       ; (bh = 0)
  412.         shr cx,1                        ; shift back (see note above)
  413.         sub cx,4
  414.  
  415. ;
  416. ;  CX = -(the number of pixels in the first byte)
  417. ;
  418.         add si,cx                       ; sub the first byte's pixels from
  419.                     ; the total count
  420.         
  421. ;
  422. ;  We now set up a pixel mask for the first byte's pixels in AH
  423. ;
  424. ;  old AH   new AH
  425. ;    C0       FF
  426. ;    30       3F
  427. ;    0C       0F
  428. ;    03       03
  429. ;
  430.  
  431.  
  432.         shl ah,1
  433.         mov cl,ah
  434.         dec ah                   
  435.         xor ah,cl
  436.         
  437.  
  438. ;
  439. ;  Set up the masks and write the pixels in the first byte
  440. ;
  441.  
  442.         mov bl,ah
  443.         not bl
  444.         and ah,al
  445.         
  446.  
  447.         and bl,[di]
  448.         or bl,ah
  449.         mov [di],bl
  450.  
  451.         inc di                ; point to the next byte
  452.  
  453.  
  454.         mov ah,al            ; AX = CcCcCcCcCcCcCcCc 
  455.                     ; (a word color mask)
  456.                                         
  457.         mov cx,7
  458.         and cx,si                       ; CX = how many extra pixels 
  459.                                         ;      in the last word
  460.                                         
  461.         jnz h_4                ; If not 0 
  462.     
  463.  
  464. ;
  465. ;  The number of remaining pixels is a multiple of 8, the number of
  466. ;  pixels in a word.
  467. ;
  468.  
  469.         mov cx,si            ; # pixels
  470.  
  471.         shr cx,1
  472.         shr cx,1
  473.         shr cx,1            ; CX = # pixels DIV 8
  474.         
  475. h_2:    cld                ; set direction to increase
  476.  
  477. rep     stosw                 ; save the pixels
  478.  
  479.         jmp ret_line            
  480.  
  481.  
  482. ;
  483. ;  Special initialization code for two or three pixel lines
  484. ;
  485. ;
  486.  
  487. short_horiz:
  488.  
  489.         mov bh,ah            ; BH = AH (pixel mask)
  490.                     ; BL = 0
  491.  
  492.         mov dx,bx            ; Save it in DX
  493.         mov cx,si
  494.  
  495. ;
  496. ;  Now make a mask for all two or three pixels
  497. ;
  498. s_l:    shr bx,1
  499.         shr bx,1
  500.         or dx,bx
  501.         loop s_l
  502.  
  503. ;
  504. ;  DX = the pixel mask for the last few pixels
  505. ;
  506.  
  507.         mov ah,al            ; AX = CcCcCcCcCcCcCcCc 
  508.                     ; (a word color mask)
  509.                                         
  510.         jmp h_3
  511.  
  512.  
  513.  
  514. h_4:
  515. ;
  516. ; CX = the number of pixels in the last word
  517. ;
  518.  
  519. ;
  520. ;  Set up the pixel mask for the last work of pixels
  521. ;
  522.  
  523.         mov dx,0C000h                   ; Initial mask
  524.  
  525.         dec cl               ; Create the mask
  526.         shl cl,1
  527.         sar dx,cl
  528.  
  529. ;
  530. ;  Write as many pixels as possible in multiples of 8, the number
  531. ;  of pixels in a word.
  532. ;
  533.  
  534.         mov cx,si            ; # pixels
  535.  
  536.         shr cx,1
  537.         shr cx,1
  538.         shr cx,1            ; CX = # pixels DIV 8
  539.  
  540.  
  541.         jcxz h_3            ; less than 8 pixels left 
  542.                     ; (no full words)
  543.         
  544.         cld                ; set direction to increase
  545.  
  546. rep     stosw                 ; save the pixels
  547.  
  548.  
  549.         
  550. h_3: 
  551.  
  552. ;
  553. ;  last word of pixels
  554. ;
  555.  
  556. ;  
  557. ;  DX = last word pixel mask
  558. ;  AX = color mask
  559. ;  DI = address of last word
  560. ;
  561.  
  562.         xchg dh,dl            ; swap low and high bytes
  563.  
  564.         mov bx,dx            ; unchanged mask
  565.         not bx
  566.  
  567.         and dx,ax            ; colors
  568.  
  569.         and bx,[di]            ; clear new save others
  570.  
  571.         or bx,dx            ; add new pixels
  572.  
  573.         mov [di],bx            ; save pixels
  574.  
  575.         jmp ret_line        
  576.  
  577.         
  578. Slope_gtr:
  579.  
  580. ;        As a reminder
  581. ;
  582. ; AH = pixel mask (which pixel within a byte)
  583. ; AL = color mask
  584. ; BX = 0
  585. ; SI = dX
  586. ; BP = dY
  587. ; DI = points to the byte containing the first pixel
  588. ;
  589.  
  590.  
  591. ;   Slope > 0
  592. ;
  593. ;   From here we distinguish between slope < 1 and slope > 1
  594. ;
  595. ;
  596.     cmp bp,si
  597.     jg Slope_gtr_1
  598.         jne Slope_less_1
  599.         jmp Slope_1
  600.  
  601. Slope_less_1:
  602.  
  603. ;
  604. ;   The slope is less than 1 and greater than 0.  On each iteration
  605. ; of the loop we increment X.  Depending on the value of the decision
  606. ; variable (DX) we may or may not increment Y.
  607. ;
  608.                                                             
  609.     mov cx,si            ; # points = dX + 1
  610.         inc cx   
  611.  
  612. ;
  613. ;  Initialize the decision variables.
  614. ;
  615.     shl bp,1            ; BP = 2 * dY
  616.     mov dx,bp            ; DX = 2 * dY       
  617.     sub dx,si            ; DX = 2 * dY - dX
  618.     neg si                ; SI = -dX
  619.     shl si,1            ; SI = -2 * dX
  620.     add si,bp            ; SI = 2 * (dY - dX)
  621.  
  622. pix1:    or bh,ah                        ; Add next pixel
  623.  
  624.         ror ah,1            ; shift mask to next pixel
  625.         ror ah,1
  626.  
  627.         jc t1_6                         ; End of the byte ... write it
  628.  
  629.  
  630.     cmp dh,bl                       ; Test the decision variable
  631.                     ; Note BL = 0
  632.     jge t1_5
  633.  
  634.     add dx,bp            ; Change decision variable
  635.     loop pix1
  636.  
  637.     jmp final_dots
  638.         
  639. t1_5:   mov bl,bh                       ; write this byte
  640.         not bl
  641.         and bh,al
  642.         
  643.         and bl,[di]
  644.         or bl,bh
  645.         mov [di],bl
  646.  
  647.         xor bx,bx            ; BX = 0
  648.  
  649.  
  650. t1_3:   xor di,2000h                    ; Switch banks ?
  651.         cmp di,2000h
  652.         jge t1_4
  653.  
  654.         add di,80            ; increment Y
  655.         
  656. t1_4:    add dx,si
  657.     loop pix1
  658.     jmp ret_line
  659.  
  660. t1_6:   mov bl,bh            ; write this byte
  661.         not bl
  662.         and bh,al
  663.         
  664.  
  665.         and bl,[di]
  666.         or bl,bh
  667.         mov [di],bl
  668.         inc di
  669.         xor bx,bx            ; BX = 0
  670.  
  671.     cmp dh,bl                       ; Test the decision variable
  672.                     ; Note BL = 0
  673.         jge t1_3
  674.  
  675.         add dx,bp
  676.         loop pix1                
  677.         jmp ret_line
  678.  
  679.  
  680. Slope_gtr_1:
  681.  
  682. ;        As a reminder
  683. ;
  684. ; AH = pixel mask (which pixel within a byte)
  685. ; AL = color mask
  686. ; BX = 0
  687. ; SI = dX
  688. ; BP = dY
  689. ; DI = points to the byte containing the first pixel
  690. ;
  691.  
  692. ;
  693. ;     The slope is greater than 1.  On each iteration of the loop we 
  694. ;   increment Y.  Depending on the value of the decision variable (DX) 
  695. ;   we may or may not increment X.
  696. ;
  697.     mov cx,bp                    ; # points = dY + 1
  698.     inc cx                                             
  699.  
  700.     shl si,1            ; SI = 2 * dX
  701.     mov dx,si                       ; SI = 2 * dX
  702.     sub dx,bp            ; DX = 2 * dX - dY
  703.     neg bp                          ; BP = -dY
  704.     shl bp,1            ; BP = -2 * dY
  705.     add bp,si            ; BP = 2 * (dX - dY)
  706.                                                             
  707.         mov bh,ah            ; Set up the masks 
  708.         and bh,al            ; (they do not change)
  709.         mov al,ah
  710.         not al
  711.  
  712. ;
  713. ; AL = unchanged pixel mask
  714. ; AH = pixel mask (used as a rotating counter here)
  715. ; BH = color mask
  716.  
  717. pix2:    mov bl,al            ; write the pixel
  718.  
  719.         and bl,[di]
  720.         or bl,bh
  721.         mov [di],bl       
  722.  
  723.  
  724.         xor di,2000h            ; Change banks
  725.         cmp di,2000h
  726.  
  727.         jge t2_1
  728.  
  729.         add di,80            ; next Y
  730.  
  731. t2_1:   cmp dx,0            ; Check decision variable
  732.         jge t2_2
  733.         
  734.         add dx,si
  735.  
  736.         loop pix2
  737.         jmp ret_line
  738.         
  739. t2_2:   ror al,1            ; increment X and rotate masks
  740.         ror bh,1
  741.         ror ah,1
  742.  
  743.         ror al,1
  744.         ror bh,1
  745.         ror ah,1
  746.  
  747.         adc di,0            ; if masks wrap around go to next
  748.                     ; byte
  749.  
  750.         add dx,bp
  751.         loop pix2
  752.         jmp ret_line
  753.         
  754.         
  755.  
  756. Slope_less:
  757.  
  758.     neg bp                ; make dY > 0
  759.  
  760.         cmp bp,si            ; (note: we know that dX > 0)
  761.  
  762.         jg case4                        ; slope < -1
  763.  
  764.         jne not_meqn1            ; slope > -1
  765.  
  766.         jmp Slope_neg_1            ; slope = -1
  767.  
  768.  
  769. not_meqn1:
  770.  
  771. ;
  772. ;  This section of the code is almost the same as for slope < 1 (above).
  773. ;  The only difference is that here Y is decremented, instead of 
  774. ;  incremented.
  775. ;
  776.  
  777.         mov cx,si
  778.         inc cx
  779.         shl bp,1
  780.         mov dx,bp
  781.         sub dx,si
  782.         neg si
  783.         shl si,1
  784.         add si,bp
  785.         
  786.  
  787. pix3:   or bh,ah
  788.         ror ah,1
  789.         ror ah,1
  790.         jc t3_6
  791.  
  792.     cmp dh,bl
  793.     jge t3_5
  794.  
  795.     add dx,bp
  796.     loop pix3
  797.     jmp final_dots
  798.         
  799. t3_5:   mov bl,bh
  800.         not bl
  801.         and bh,al
  802.         
  803.         and bl,[di]
  804.         or bl,bh
  805.         mov [di],bl
  806.         xor bx,bx
  807.  
  808.  
  809. t3_3:   xor di,2000h            ; here's the difference !
  810.         cmp di,2000h
  811.  
  812.         jl t3_4
  813.  
  814.         sub di,80
  815.         
  816. t3_4:    add dx,si
  817.     loop pix3
  818.     jmp ret_line
  819.  
  820.  
  821. t3_6:   mov bl,bh
  822.         not bl
  823.         and bh,al
  824.         
  825.  
  826.         and bl,[di]
  827.         or bl,bh
  828.         mov [di],bl
  829.         inc di
  830.         xor bx,bx
  831.  
  832.         cmp dh,bl
  833.         jge t3_3
  834.         add dx,bp
  835.         loop pix3
  836.         jmp ret_line
  837.  
  838.  
  839. case4:
  840.  
  841. ;
  842. ;  This section of the code is almost the same as for slope > 1 (above).
  843. ;  The only difference is that here Y is decremented, instead of 
  844. ;  incremented.
  845. ;
  846.  
  847.     mov cx,bp
  848.         inc cx
  849.         shl si,1
  850.         mov dx,si
  851.         sub dx,bp
  852.         neg bp
  853.         shl bp,1
  854.         add bp,si
  855.  
  856.         mov bh,ah
  857.         and bh,al
  858.         mov al,ah
  859.         not al
  860.  
  861. pix4:    mov bl,al
  862.         
  863.         and bl,[di]
  864.         or bl,bh
  865.         mov [di],bl       
  866.  
  867.  
  868.         xor di,2000h            ; here's the difference !
  869.         cmp di,2000h
  870.  
  871.         jl t4_1
  872.  
  873.         sub di,80
  874.  
  875. t4_1:   cmp dx,0
  876.         jge t4_2
  877.         
  878.         add dx,si
  879.         loop pix4
  880.         jmp ret_line
  881.         
  882. t4_2:   ror al,1
  883.         ror bh,1
  884.         ror ah,1
  885.  
  886.         ror al,1
  887.         ror bh,1
  888.         ror ah,1
  889.  
  890.         adc di,0
  891.         add dx,bp
  892.         loop pix4
  893.         jmp ret_line
  894.         
  895.         
  896. Slope_1 label near
  897.  
  898. ;
  899. ;  The slope is 1.
  900. ;
  901.  
  902.         mov cx,si            ; # points = dX + 1
  903.         inc cx
  904.  
  905.         xor si,si            ; SI = 0
  906.  
  907.         mov dx,2000h            ; constants
  908.         mov bp,80
  909.  
  910.         mov bh,ah            ; set up initial masks
  911.         and bh,al
  912.         mov al,ah
  913.         not al
  914.  
  915.  
  916. meq1_next:
  917.     mov bl,al
  918.         
  919.         
  920.         and bl,[di]
  921.         or bl,bh
  922.         mov [di],bl       
  923.  
  924.  
  925.         xor di,dx            ; Bank testing
  926.         test di,dx
  927.  
  928.         jne meq1_1
  929.  
  930.         add di,bp
  931.  
  932. meq1_1: ror al,1            ; similar to code above
  933.         ror bh,1
  934.         ror ah,1
  935.  
  936.         ror al,1
  937.         ror bh,1
  938.         ror ah,1
  939.  
  940.         adc di,si
  941.  
  942.         loop meq1_next
  943.     jmp ret_line
  944.         
  945.  
  946.  
  947. Slope_neg_1 label near
  948.  
  949.  
  950. ;
  951. ;  This section of the code is almost the same as for slope = -1 (above).
  952. ;  The only difference is that here Y is decremented, instead of 
  953. ;  incremented.
  954. ;
  955.  
  956.  
  957.         mov cx,si
  958.         inc cx
  959.  
  960.         xor si,si
  961.  
  962.         mov dx,2000h
  963.         mov bp,80
  964.         
  965.         mov bh,ah
  966.         and bh,al
  967.         mov al,ah
  968.         not al
  969.  
  970.  
  971. meqn1_next:
  972.     mov bl,al
  973.         
  974.         and bl,[di]
  975.         or bl,bh
  976.         mov [di],bl       
  977.  
  978.  
  979.         xor di,dx            ; Here's the difference !
  980.         test di,dx
  981.         je meqn1_1
  982.         sub di,bp
  983.  
  984. meqn1_1:
  985.         ror al,1
  986.         ror bh,1
  987.         ror ah,1
  988.  
  989.         ror al,1
  990.         ror bh,1
  991.         ror ah,1
  992.  
  993.         adc di,si
  994.  
  995.         loop meqn1_next
  996.     jmp ret_line        
  997.  
  998.  
  999. final_dots label near
  1000.  
  1001. ;
  1002. ;  This code writes the pixels that remain in the BH register.
  1003. ;
  1004.  
  1005. ;
  1006. ;  BH = pixel buffer
  1007. ;  BL = 0
  1008. ;  AL = color mask
  1009. ;  DI = points to the byte containing the pixels
  1010. ;
  1011.         
  1012.         cmp bh,bl
  1013.         je ret_line
  1014.         mov bl,bh
  1015.         not bl
  1016.         and bh,al
  1017.         
  1018.         and bl,[di]
  1019.         or bl,bh
  1020.         mov [di],bl       
  1021.  
  1022. ret_line label near
  1023.  
  1024.         pop ds                ; Restore the registers
  1025.         pop bp
  1026.         ret 0AH                ; remove arguments from the stack
  1027.  
  1028.  
  1029. m_line endp
  1030. cseg ends
  1031.      end
  1032. 21-May-86 16:20:50-PDT,22021;000000000001
  1033. Return-Path: <dantowitz%eaglea.DEC@decwrl.DEC.COM>
  1034. Received: FROM DECWRL.DEC.COM BY USC-ISIB.ARPA WITH TCP ; 21 May 86 16:16:02 PDT
  1035. Received: from DEC-RHEA.ARPA (dec-rhea) by decwrl.DEC.COM (4.22.05/4.7.34)
  1036.     id AA07163; Wed, 21 May 86 16:13:36 pdt
  1037. Message-Id: <8605212313.AA07163@decwrl.DEC.COM>
  1038. Date: Wednesday, 21 May 1986 16:10:04-PDT
  1039. From: dantowitz%eaglea.DEC@decwrl.DEC.COM  (David .. LTN2-2/H07 -- DTN:226-6957)
  1040. To: Info-IBMPC@USC-ISIB.ARPA  (Distribution list @XRES)
  1041. Subject: "To err ..."  The code is the same, one jump was too far to assemble
  1042.  
  1043. cseg segment
  1044.      assume cs:cseg
  1045. m_line proc near
  1046.  
  1047.  
  1048. ;
  1049. ;    Version 3.3m  DMD  Medium resolution graphics routine for drawing
  1050. ;    April 30, 1986     lines on an IBMPC with the standard color
  1051. ;                       graphics board.  Copyright (c) by David Dantowitz,
  1052. ;                       April 30, 1986
  1053. ;
  1054.  
  1055.  
  1056. ;
  1057. ;    This routine was written by David Dantowitz.  The routine
  1058. ;    implements Bresenham's algorithm for line drawing.  
  1059. ;
  1060. ;    This routine may be used at the user's discretion for no charge
  1061. ;    what so ever.  This software has been tested and should work
  1062. ;    as documented, but no guarantees are made.  The user assumes
  1063. ;    full responsibility for the assembly and use of this code.
  1064. ;
  1065. ;    Portions of this routine may be used in other contexts when proper
  1066. ;    copyright and source identifications are made.  This code may
  1067. ;    be modified to conform to other calling standards, but other
  1068. ;    changes should be made only after consultation with the author.
  1069. ;
  1070. ;    This routine was written to be as general and as fast as possible,
  1071. ;    any ideas for changes that result in improved speed would be 
  1072. ;    appreciated by the author.  Support for other color graphics
  1073. ;    boards is also possible and again the user is asked to contact
  1074. ;    the author.
  1075. ;
  1076. ;
  1077. ;    This implementation breaks lines into the following 8 categories,
  1078. ;    the last four of which use Bresenham's algorithm.
  1079. ;
  1080. ;           horizontal
  1081. ;           vertical
  1082. ;           slope equal to 1
  1083. ;           slope equal to -1
  1084. ;           slope between 0 and 1
  1085. ;           slope between 1 and infinity
  1086. ;           slope between 0 and -1
  1087. ;           slope between -1 and negative infinity
  1088. ;
  1089. ;    This routine does NOT check the points for bounds restrictions.
  1090. ;    This is to enable well behaved software to run as fast as 
  1091. ;    possible.  This routine is called by first pushing the X and
  1092. ;    Y values for the first point and then the X and Y values for
  1093. ;    the second point, and lastly the color for the line.
  1094. ;    Note that the color is expected to be between 0 and 3.
  1095. ;    Also note that all the parameters are words.
  1096. ;
  1097. ;
  1098. ;    To use with TURBO Pascal you must assemble the file into a
  1099. ;    .COM file.  To do this perfrom the following commands:
  1100. ;
  1101. ;    A> MASM MRESLINE;
  1102. ;    A> LINK MRESLINE;
  1103. ;    A> EXE2BIN MRESLINE.EXE MRESLINE.COM
  1104. ;
  1105. ;    When assembled into a .COM file (MRESLINE.ASM) this routine 
  1106. ;    may be declared in TURBO Pascal with the following declaration:
  1107. ;
  1108. ;    PROCEDURE Med_res_line(X1, Y1, X2, Y2, Color : Integer); external 'mresline.com';
  1109. ;           
  1110. ;
  1111. ;    Any suggestions for improvements are welcome and may be sent
  1112. ;    to me at either of the addresses below.
  1113. ;
  1114. ;    David Dantowitz
  1115. ;    Digital Equipment Corporation
  1116. ;    Foster Street
  1117. ;    LTN2-2/H07
  1118. ;    Littleton, MA   01460
  1119. ;
  1120. ;    Dantowitz%Eagle1.DEC@decwrl.ARPA
  1121. ;
  1122. ;    
  1123. ;
  1124. ;    The views and ideas expressed here are my own and do not
  1125. ;    necessarily reflect those of the Digital Equipment Corporation.
  1126. ;
  1127. ;
  1128.  
  1129. ;
  1130. ;  Save the base pointer
  1131. ;
  1132.         push bp
  1133.         mov bp,sp
  1134.  
  1135.  
  1136. ;
  1137. ;  Get the two points
  1138. ;
  1139.         mov ax,[bp+12]   ;   X1
  1140.     mov cx,[bp+10]   ;   Y1
  1141.  
  1142.     mov bx,[bp+8]    ;   X2
  1143.     mov dx,[bp+6]    ;   Y2
  1144.  
  1145. ;  The difference between X1 and X2 will be represented as dX.
  1146. ;  Likewise for Y1 and Y2 (dY).
  1147. ;
  1148. ;  Note: all lines are drawn with the X value increasing.
  1149. ;       
  1150. ;  If dX < 0 exchange the two points
  1151. ;
  1152.  
  1153.  
  1154.     mov si,bx
  1155.           sub si,ax        ; compute dX
  1156.  
  1157.     jg noswit     ; If dX > 0 then don't switch the points
  1158.  
  1159.  
  1160. ;
  1161. ;  Switch the points and reverse the sign of dX (SI)
  1162. ;
  1163.         neg si
  1164.     xchg ax,bx
  1165.     xchg cx,dx
  1166.  
  1167. noswit: mov bx,[bp+4]   ; Color
  1168.  
  1169.         mov bp,dx
  1170.     sub bp,cx       ; compute dY
  1171.  
  1172.         xor di,di    ; di = 0
  1173.  
  1174. ;
  1175. ;  All vertical lines are drawn with the Y value increasing.
  1176.  
  1177.  
  1178.         cmp si,di            ; dX = 0 ?
  1179.         jne noswit_2                    ; not a vertical line
  1180.  
  1181.  
  1182.         cmp bp,di              ; dY > 0 ?
  1183.         jg noswit_2            ; no need to switch points
  1184.  
  1185.         mov cx,dx            ; Just copy lower value, the higher
  1186.                                 ; value is implied by dY.
  1187.  
  1188.         neg bp                      ; Change the sign of dY
  1189.  
  1190. noswit_2:
  1191.  
  1192. ; Compute the address of the first byte
  1193.  
  1194. ;
  1195. ; AX = initial X
  1196. ; BX = color
  1197. ; CX = initial Y
  1198. ; SI = dX                                       
  1199. ; BP = dY
  1200. ;
  1201.  
  1202.         mov dx,cx                  ; DX = starting Y
  1203.  
  1204.         and dl,0feh            ; DX = (Y DIV 2) * 2
  1205.  
  1206.         mov di,dx            ; DI = DX
  1207.  
  1208.         shl dx,1            ; DX = 4 * DX
  1209.         shl dx,1                                     
  1210.  
  1211.         add di,dx            ; DI = DI + DX  {DI = 5 * (Y DIV 2) * 2)}
  1212.  
  1213.         shl di,1            ; DI = 8 * DI
  1214.         shl di,1
  1215.         shl di,1
  1216.                                                      
  1217. ;
  1218. ;   Note that DI presently is equal to 80 * (Y DIV 2) ... the first byte
  1219. ;   on the raster line that contains the first pixel of the line.
  1220. ;
  1221.  
  1222. ;
  1223. ;   (Screen memory for graphics is divided into two sections.  The even
  1224. ;   raster lines have addresses 0 to 1F3Fh (80 bytes/line * 100 lines).
  1225. ;   The odd raster lines have addresses 2000h to 3F3Fh.  Thus all lines
  1226. ;   with odd Y coordinates have the 2000h bit set.
  1227. ;
  1228.  
  1229.  
  1230. ;   If odd then start in the second bank, otherwise start in the first bank.
  1231.  
  1232.         shr cl,1        
  1233.         jnc t1
  1234.         xor di,2000h
  1235.  
  1236.  
  1237. t1:     mov cl,al            ; Save the low byte of X
  1238.  
  1239.         shr ax,1            ; AX = X DIV 4
  1240.         shr ax,1
  1241.  
  1242.         add di,ax            ; DI = DI + AX
  1243.  
  1244. ; Note that DI now points to the byte that contains the first pixel
  1245.  
  1246.  
  1247. ;
  1248. ;   Save the data segment register.  Also load up the screen segment
  1249. ;   register value into DS and ES.
  1250. ;
  1251.  
  1252.         push ds
  1253.         mov ax,0b800h
  1254.         mov ds,ax            ; Used for screen access
  1255.         mov es,ax            ; Used for horizontal lines
  1256.  
  1257. ;
  1258. ;   DI now points to the first byte, but which bits are the first pixel ?
  1259. ;   the low bits of CL (low bits of X) will tell us.
  1260. ;
  1261. ;
  1262. ;   This sets up the single pixel mask.
  1263.  
  1264.         and cl,3            ; Just the low 2 bits
  1265.  
  1266.         shl cl,1            ; two bits/pixel
  1267.  
  1268. ;
  1269. ;
  1270. ;   C0 marks the first pixel
  1271. ;   30 marks the second pixel
  1272. ;   0C marks the third pixel
  1273. ;   03 marks the forth pixel
  1274. ;
  1275.  
  1276.         mov ah,0C0h            ; first bit position
  1277.  
  1278.         shr ah,cl            ; shift appropriately
  1279.  
  1280.  
  1281. ;
  1282. ;  We now set up the color mask, it has the following format:
  1283. ;
  1284. ;    bits :  7 6 5 4 3 2 1 0
  1285. ;            C c C c C c C c
  1286. ;
  1287. ;  Where "C c" are the two bits used to specify the color of the pixel.
  1288. ;
  1289. ;
  1290.         mov al,bl            ; starting color 
  1291.                     ; AL = 000000Cc
  1292.  
  1293.         shl al,1
  1294.         shl al,1
  1295.         or al,bl            ; AL = 0000CcCc
  1296.  
  1297.         shl al,1
  1298.         shl al,1
  1299.         or al,bl            ; AL = 00CcCcCc
  1300.  
  1301.         shl al,1
  1302.         shl al,1
  1303.         or al,bl            ; AL = CcCcCcCc
  1304.  
  1305.         xor bx,bx            ; BX = 0
  1306. ;        
  1307. ; AH = pixel mask (which pixel within a byte)
  1308. ; AL = color mask
  1309. ; BX = 0
  1310. ; CL = low two bits of X shifted one bit to the left 
  1311. ;      (used later for horizontal lines)
  1312. ; SI = dX
  1313. ; BP = dY
  1314. ; DI = points to the byte containing the first pixel
  1315. ;
  1316.  
  1317.         cmp si,bx                ; dX = 0 ?
  1318.         je vertical            ; The line is vertical
  1319.  
  1320.  
  1321. ;
  1322. ;   Here we know that dX is positive, so the sign of dY will
  1323. ;   tell us the sign of the line's slope.
  1324. ;  
  1325.         cmp bp,bx            ; sign of dY ? 
  1326.  
  1327.         je Horizontal_a            ; 0 ... horizontal line
  1328.  
  1329.     jg Slope_gtr_a            ; slope > 0
  1330.  
  1331.         jmp Slope_less            ; slope < 0
  1332.  
  1333. Horizontal_a:                      ; extra jump due to long distance
  1334.         jmp Horizontal
  1335.  
  1336. Slope_gtr_a:                      ; extra jump due to long distance
  1337.         jmp Slope_gtr
  1338.  
  1339. ;
  1340. ;   Version, author identification and copyright notice
  1341. ;
  1342.         db 'Version 3.3m - Copyright (c) David Dantowitz April 30, 1986'
  1343.  
  1344.  
  1345. vertical label near
  1346. ;
  1347. ;   Vertical lines are drawn in two parts, the even rasters, then the odd
  1348. ;   rasters.  (Note the order is dependent on the line's starting point.)
  1349. ;
  1350.  
  1351.         mov cx,bp            ; # points = dY + 1
  1352.         inc cx
  1353.  
  1354.         mov bp,80            ; a constant (# bytes/raster)
  1355.  
  1356.         shr cx,1                       ; divide in two (carry set if odd)
  1357.         mov dx,cx                     ; save count (second half)
  1358.  
  1359.         adc cx,bx                       ; add the carry (bx=0)
  1360.         mov si,di                         ; save starting point
  1361.  
  1362.  
  1363.         mov bh,ah            ; pixel mask
  1364.  
  1365.         and bh,al                       ; get the color
  1366.  
  1367.         not ah                ; old pixel mask (unchanged pixels)
  1368.  
  1369.         cmp dx,0            ; If DX = 0 then there is only one point
  1370.         je second_bank            ; don't draw in odd and even, just one.
  1371.  
  1372.  
  1373. ;
  1374. ;  Note that the code below is repeated in a similar fashion for most
  1375. ;  of the actual pixel writing.  This code is only commented once.
  1376. ;
  1377.         
  1378. first_bank:
  1379.         mov bl,ah            ; copy the old pixel mask
  1380.  
  1381.         and bl,[di]            ; clear new pixel
  1382.  
  1383.         or bl,bh            ; add new pixel color
  1384.  
  1385.         mov [di],bl               ; save byte
  1386.  
  1387.         add di,bp            ; next line
  1388.  
  1389.     loop first_bank
  1390.  
  1391.         xor si,2000h            ; change the bank
  1392.         mov cx,dx
  1393.  
  1394.  
  1395.         cmp si,2000h               ; if second bank is even then
  1396.         jge second_bank            ; go to the next raster.
  1397.  
  1398.         add si,bp
  1399.         
  1400. second_bank:
  1401.  
  1402.         mov bl,ah            ; copy the old pixel mask
  1403.  
  1404.         and bl,[si]            ; clear new pixel
  1405.  
  1406.         or bl,bh            ; add new pixel color
  1407.  
  1408.         mov [si],bl               ; save byte
  1409.  
  1410.         add si,bp            ; next line
  1411.  
  1412.     loop second_bank
  1413.  
  1414.     jmp ret_line        
  1415.       
  1416.  
  1417. horizontal label near
  1418.  
  1419. ;
  1420. ;  Horizontal lines are drawn mostly using the STOSW instruction.
  1421. ;  Only the ends are drawn with explicit code.  Most of the code 
  1422. ;  in this routine deals with words, not bytes. 
  1423. ;
  1424.         
  1425. ;        As a reminder
  1426. ;
  1427. ; AH = pixel mask (which pixel within a byte)
  1428. ; AL = color mask
  1429. ; BX = 0
  1430. ; CL = low two bits of X shifted one bit to the left 
  1431. ;      (used here for horizontal lines)
  1432. ; SI = dX
  1433. ; BP = dY
  1434. ; DI = points to the byte containing the first pixel
  1435. ;
  1436.  
  1437. ;
  1438. ;  If this is a short line then go to special set up code.
  1439. ;
  1440.         cmp si,3            ; If dX = 1 or 2 then short_horiz
  1441.         jl short_horiz             ; (dX = 0 is a vertical line)
  1442.  
  1443.         inc si                ; # points = dX + 1
  1444.  
  1445.         mov ch,bh                       ; (bh = 0)
  1446.         shr cx,1                        ; shift back (see note above)
  1447.         sub cx,4
  1448.  
  1449. ;
  1450. ;  CX = -(the number of pixels in the first byte)
  1451. ;
  1452.         add si,cx                       ; sub the first byte's pixels from
  1453.                     ; the total count
  1454.         
  1455. ;
  1456. ;  We now set up a pixel mask for the first byte's pixels in AH
  1457. ;
  1458. ;  old AH   new AH
  1459. ;    C0       FF
  1460. ;    30       3F
  1461. ;    0C       0F
  1462. ;    03       03
  1463. ;
  1464.  
  1465.  
  1466.         shl ah,1
  1467.         mov cl,ah
  1468.         dec ah                   
  1469.         xor ah,cl
  1470.         
  1471.  
  1472. ;
  1473. ;  Set up the masks and write the pixels in the first byte
  1474. ;
  1475.  
  1476.         mov bl,ah
  1477.         not bl
  1478.         and ah,al
  1479.         
  1480.  
  1481.         and bl,[di]
  1482.         or bl,ah
  1483.         mov [di],bl
  1484.  
  1485.         inc di                ; point to the next byte
  1486.  
  1487.  
  1488.         mov ah,al            ; AX = CcCcCcCcCcCcCcCc 
  1489.                     ; (a word color mask)
  1490.                                         
  1491.         mov cx,7
  1492.         and cx,si                       ; CX = how many extra pixels 
  1493.                                         ;      in the last word
  1494.                                         
  1495.         jnz h_4                ; If not 0 
  1496.     
  1497.  
  1498. ;
  1499. ;  The number of remaining pixels is a multiple of 8, the number of
  1500. ;  pixels in a word.
  1501. ;
  1502.  
  1503.         mov cx,si            ; # pixels
  1504.  
  1505.         shr cx,1
  1506.         shr cx,1
  1507.         shr cx,1            ; CX = # pixels DIV 8
  1508.         
  1509. h_2:    cld                ; set direction to increase
  1510.  
  1511. rep     stosw                 ; save the pixels
  1512.  
  1513.         jmp ret_line            
  1514.  
  1515.  
  1516. ;
  1517. ;  Special initialization code for two or three pixel lines
  1518. ;
  1519. ;
  1520.  
  1521. short_horiz:
  1522.  
  1523.         mov bh,ah            ; BH = AH (pixel mask)
  1524.                     ; BL = 0
  1525.  
  1526.         mov dx,bx            ; Save it in DX
  1527.         mov cx,si
  1528.  
  1529. ;
  1530. ;  Now make a mask for all two or three pixels
  1531. ;
  1532. s_l:    shr bx,1
  1533.         shr bx,1
  1534.         or dx,bx
  1535.         loop s_l
  1536.  
  1537. ;
  1538. ;  DX = the pixel mask for the last few pixels
  1539. ;
  1540.  
  1541.         mov ah,al            ; AX = CcCcCcCcCcCcCcCc 
  1542.                     ; (a word color mask)
  1543.                                         
  1544.         jmp h_3
  1545.  
  1546.  
  1547.  
  1548. h_4:
  1549. ;
  1550. ; CX = the number of pixels in the last word
  1551. ;
  1552.  
  1553. ;
  1554. ;  Set up the pixel mask for the last work of pixels
  1555. ;
  1556.  
  1557.         mov dx,0C000h                   ; Initial mask
  1558.  
  1559.         dec cl               ; Create the mask
  1560.         shl cl,1
  1561.         sar dx,cl
  1562.  
  1563. ;
  1564. ;  Write as many pixels as possible in multiples of 8, the number
  1565. ;  of pixels in a word.
  1566. ;
  1567.  
  1568.         mov cx,si            ; # pixels
  1569.  
  1570.         shr cx,1
  1571.         shr cx,1
  1572.         shr cx,1            ; CX = # pixels DIV 8
  1573.  
  1574.  
  1575.         jcxz h_3            ; less than 8 pixels left 
  1576.                     ; (no full words)
  1577.         
  1578.         cld                ; set direction to increase
  1579.  
  1580. rep     stosw                 ; save the pixels
  1581.  
  1582.  
  1583.         
  1584. h_3: 
  1585.  
  1586. ;
  1587. ;  last word of pixels
  1588. ;
  1589.  
  1590. ;  
  1591. ;  DX = last word pixel mask
  1592. ;  AX = color mask
  1593. ;  DI = address of last word
  1594. ;
  1595.  
  1596.         xchg dh,dl            ; swap low and high bytes
  1597.  
  1598.         mov bx,dx            ; unchanged mask
  1599.         not bx
  1600.  
  1601.         and dx,ax            ; colors
  1602.  
  1603.         and bx,[di]            ; clear new save others
  1604.  
  1605.         or bx,dx            ; add new pixels
  1606.  
  1607.         mov [di],bx            ; save pixels
  1608.  
  1609.         jmp ret_line        
  1610.  
  1611.         
  1612. Slope_gtr:
  1613.  
  1614. ;        As a reminder
  1615. ;
  1616. ; AH = pixel mask (which pixel within a byte)
  1617. ; AL = color mask
  1618. ; BX = 0
  1619. ; SI = dX
  1620. ; BP = dY
  1621. ; DI = points to the byte containing the first pixel
  1622. ;
  1623.  
  1624.  
  1625. ;   Slope > 0
  1626. ;
  1627. ;   From here we distinguish between slope < 1 and slope > 1
  1628. ;
  1629. ;
  1630.     cmp bp,si
  1631.     jg Slope_gtr_1
  1632.         jne Slope_less_1
  1633.         jmp Slope_1
  1634.  
  1635. Slope_less_1:
  1636.  
  1637. ;
  1638. ;   The slope is less than 1 and greater than 0.  On each iteration
  1639. ; of the loop we increment X.  Depending on the value of the decision
  1640. ; variable (DX) we may or may not increment Y.
  1641. ;
  1642.                                                             
  1643.     mov cx,si            ; # points = dX + 1
  1644.         inc cx   
  1645.  
  1646. ;
  1647. ;  Initialize the decision variables.
  1648. ;
  1649.     shl bp,1            ; BP = 2 * dY
  1650.     mov dx,bp            ; DX = 2 * dY       
  1651.     sub dx,si            ; DX = 2 * dY - dX
  1652.     neg si                ; SI = -dX
  1653.     shl si,1            ; SI = -2 * dX
  1654.     add si,bp            ; SI = 2 * (dY - dX)
  1655.  
  1656. pix1:    or bh,ah                        ; Add next pixel
  1657.  
  1658.         ror ah,1            ; shift mask to next pixel
  1659.         ror ah,1
  1660.  
  1661.         jc t1_6                         ; End of the byte ... write it
  1662.  
  1663.  
  1664.     cmp dh,bl                       ; Test the decision variable
  1665.                     ; Note BL = 0
  1666.     jge t1_5
  1667.  
  1668.     add dx,bp            ; Change decision variable
  1669.     loop pix1
  1670.  
  1671.     jmp final_dots
  1672.         
  1673. t1_5:   mov bl,bh                       ; write this byte
  1674.         not bl
  1675.         and bh,al
  1676.         
  1677.         and bl,[di]
  1678.         or bl,bh
  1679.         mov [di],bl
  1680.  
  1681.         xor bx,bx            ; BX = 0
  1682.  
  1683.  
  1684. t1_3:   xor di,2000h                    ; Switch banks ?
  1685.         cmp di,2000h
  1686.         jge t1_4
  1687.  
  1688.         add di,80            ; increment Y
  1689.         
  1690. t1_4:    add dx,si
  1691.     loop pix1
  1692.     jmp ret_line
  1693.  
  1694. t1_6:   mov bl,bh            ; write this byte
  1695.         not bl
  1696.         and bh,al
  1697.         
  1698.  
  1699.         and bl,[di]
  1700.         or bl,bh
  1701.         mov [di],bl
  1702.         inc di
  1703.         xor bx,bx            ; BX = 0
  1704.  
  1705.     cmp dh,bl                       ; Test the decision variable
  1706.                     ; Note BL = 0
  1707.         jge t1_3
  1708.  
  1709.         add dx,bp
  1710.         loop pix1                
  1711.         jmp ret_line
  1712.  
  1713.  
  1714. Slope_gtr_1:
  1715.  
  1716. ;        As a reminder
  1717. ;
  1718. ; AH = pixel mask (which pixel within a byte)
  1719. ; AL = color mask
  1720. ; BX = 0
  1721. ; SI = dX
  1722. ; BP = dY
  1723. ; DI = points to the byte containing the first pixel
  1724. ;
  1725.  
  1726. ;
  1727. ;     The slope is greater than 1.  On each iteration of the loop we 
  1728. ;   increment Y.  Depending on the value of the decision variable (DX) 
  1729. ;   we may or may not increment X.
  1730. ;
  1731.     mov cx,bp                    ; # points = dY + 1
  1732.     inc cx                                             
  1733.  
  1734.     shl si,1            ; SI = 2 * dX
  1735.     mov dx,si                       ; SI = 2 * dX
  1736.     sub dx,bp            ; DX = 2 * dX - dY
  1737.     neg bp                          ; BP = -dY
  1738.     shl bp,1            ; BP = -2 * dY
  1739.     add bp,si            ; BP = 2 * (dX - dY)
  1740.                                                             
  1741.         mov bh,ah            ; Set up the masks 
  1742.         and bh,al            ; (they do not change)
  1743.         mov al,ah
  1744.         not al
  1745.  
  1746. ;
  1747. ; AL = unchanged pixel mask
  1748. ; AH = pixel mask (used as a rotating counter here)
  1749. ; BH = color mask
  1750.  
  1751. pix2:    mov bl,al            ; write the pixel
  1752.  
  1753.         and bl,[di]
  1754.         or bl,bh
  1755.         mov [di],bl       
  1756.  
  1757.  
  1758.         xor di,2000h            ; Change banks
  1759.         cmp di,2000h
  1760.  
  1761.         jge t2_1
  1762.  
  1763.         add di,80            ; next Y
  1764.  
  1765. t2_1:   cmp dx,0            ; Check decision variable
  1766.         jge t2_2
  1767.         
  1768.         add dx,si
  1769.  
  1770.         loop pix2
  1771.         jmp ret_line
  1772.         
  1773. t2_2:   ror al,1            ; increment X and rotate masks
  1774.         ror bh,1
  1775.         ror ah,1
  1776.  
  1777.         ror al,1
  1778.         ror bh,1
  1779.         ror ah,1
  1780.  
  1781.         adc di,0            ; if masks wrap around go to next
  1782.                     ; byte
  1783.  
  1784.         add dx,bp
  1785.         loop pix2
  1786.         jmp ret_line
  1787.         
  1788.         
  1789.  
  1790. Slope_less:
  1791.  
  1792.     neg bp                ; make dY > 0
  1793.  
  1794.         cmp bp,si            ; (note: we know that dX > 0)
  1795.  
  1796.         jg case4                        ; slope < -1
  1797.  
  1798.         jne not_meqn1            ; slope > -1
  1799.  
  1800.         jmp Slope_neg_1            ; slope = -1
  1801.  
  1802.  
  1803. not_meqn1:
  1804.  
  1805. ;
  1806. ;  This section of the code is almost the same as for slope < 1 (above).
  1807. ;  The only difference is that here Y is decremented, instead of 
  1808. ;  incremented.
  1809. ;
  1810.  
  1811.         mov cx,si
  1812.         inc cx
  1813.         shl bp,1
  1814.         mov dx,bp
  1815.         sub dx,si
  1816.         neg si
  1817.         shl si,1
  1818.         add si,bp
  1819.         
  1820.  
  1821. pix3:   or bh,ah
  1822.         ror ah,1
  1823.         ror ah,1
  1824.         jc t3_6
  1825.  
  1826.     cmp dh,bl
  1827.     jge t3_5
  1828.  
  1829.     add dx,bp
  1830.     loop pix3
  1831.     jmp final_dots
  1832.         
  1833. t3_5:   mov bl,bh
  1834.         not bl
  1835.         and bh,al
  1836.         
  1837.         and bl,[di]
  1838.         or bl,bh
  1839.         mov [di],bl
  1840.         xor bx,bx
  1841.  
  1842.  
  1843. t3_3:   xor di,2000h            ; here's the difference !
  1844.         cmp di,2000h
  1845.  
  1846.         jl t3_4
  1847.  
  1848.         sub di,80
  1849.         
  1850. t3_4:    add dx,si
  1851.     loop pix3
  1852.     jmp ret_line
  1853.  
  1854.  
  1855. t3_6:   mov bl,bh
  1856.         not bl
  1857.         and bh,al
  1858.         
  1859.  
  1860.         and bl,[di]
  1861.         or bl,bh
  1862.         mov [di],bl
  1863.         inc di
  1864.         xor bx,bx
  1865.  
  1866.         cmp dh,bl
  1867.         jge t3_3
  1868.         add dx,bp
  1869.         loop pix3
  1870.         jmp ret_line
  1871.  
  1872.  
  1873. case4:
  1874.  
  1875. ;
  1876. ;  This section of the code is almost the same as for slope > 1 (above).
  1877. ;  The only difference is that here Y is decremented, instead of 
  1878. ;  incremented.
  1879. ;
  1880.  
  1881.     mov cx,bp
  1882.         inc cx
  1883.         shl si,1
  1884.         mov dx,si
  1885.         sub dx,bp
  1886.         neg bp
  1887.         shl bp,1
  1888.         add bp,si
  1889.  
  1890.         mov bh,ah
  1891.         and bh,al
  1892.         mov al,ah
  1893.         not al
  1894.  
  1895. pix4:    mov bl,al
  1896.         
  1897.         and bl,[di]
  1898.         or bl,bh
  1899.         mov [di],bl       
  1900.  
  1901.  
  1902.         xor di,2000h            ; here's the difference !
  1903.         cmp di,2000h
  1904.  
  1905.         jl t4_1
  1906.  
  1907.         sub di,80
  1908.  
  1909. t4_1:   cmp dx,0
  1910.         jge t4_2
  1911.         
  1912.         add dx,si
  1913.         loop pix4
  1914.         jmp ret_line
  1915.         
  1916. t4_2:   ror al,1
  1917.         ror bh,1
  1918.         ror ah,1
  1919.  
  1920.         ror al,1
  1921.         ror bh,1
  1922.         ror ah,1
  1923.  
  1924.         adc di,0
  1925.         add dx,bp
  1926.         loop pix4
  1927.         jmp ret_line
  1928.         
  1929.         
  1930. Slope_1 label near
  1931.  
  1932. ;
  1933. ;  The slope is 1.
  1934. ;
  1935.  
  1936.         mov cx,si            ; # points = dX + 1
  1937.         inc cx
  1938.  
  1939.         xor si,si            ; SI = 0
  1940.  
  1941.         mov dx,2000h            ; constants
  1942.         mov bp,80
  1943.  
  1944.         mov bh,ah            ; set up initial masks
  1945.         and bh,al
  1946.         mov al,ah
  1947.         not al
  1948.  
  1949.  
  1950. meq1_next:
  1951.     mov bl,al
  1952.         
  1953.         
  1954.         and bl,[di]
  1955.         or bl,bh
  1956.         mov [di],bl       
  1957.  
  1958.  
  1959.         xor di,dx            ; Bank testing
  1960.         test di,dx
  1961.  
  1962.         jne meq1_1
  1963.  
  1964.         add di,bp
  1965.  
  1966. meq1_1: ror al,1            ; similar to code above
  1967.         ror bh,1
  1968.         ror ah,1
  1969.  
  1970.         ror al,1
  1971.         ror bh,1
  1972.         ror ah,1
  1973.  
  1974.         adc di,si
  1975.  
  1976.         loop meq1_next
  1977.     jmp ret_line
  1978.         
  1979.  
  1980.  
  1981. Slope_neg_1 label near
  1982.  
  1983.  
  1984. ;
  1985. ;  This section of the code is almost the same as for slope = -1 (above).
  1986. ;  The only difference is that here Y is decremented, instead of 
  1987. ;  incremented.
  1988. ;
  1989.  
  1990.  
  1991.         mov cx,si
  1992.         inc cx
  1993.  
  1994.         xor si,si
  1995.  
  1996.         mov dx,2000h
  1997.         mov bp,80
  1998.         
  1999.         mov bh,ah
  2000.         and bh,al
  2001.         mov al,ah
  2002.         not al
  2003.  
  2004.  
  2005. meqn1_next:
  2006.     mov bl,al
  2007.         
  2008.         and bl,[di]
  2009.         or bl,bh
  2010.         mov [di],bl       
  2011.  
  2012.  
  2013.         xor di,dx            ; Here's the difference !
  2014.         test di,dx
  2015.         je meqn1_1
  2016.         sub di,bp
  2017.  
  2018. meqn1_1:
  2019.         ror al,1
  2020.         ror bh,1
  2021.         ror ah,1
  2022.  
  2023.         ror al,1
  2024.         ror bh,1
  2025.         ror ah,1
  2026.  
  2027.         adc di,si
  2028.  
  2029.         loop meqn1_next
  2030.     jmp ret_line        
  2031.  
  2032.  
  2033. final_dots label near
  2034.  
  2035. ;
  2036. ;  This code writes the pixels that remain in the BH register.
  2037. ;
  2038.  
  2039. ;
  2040. ;  BH = pixel buffer
  2041. ;  BL = 0
  2042. ;  AL = color mask
  2043. ;  DI = points to the byte containing the pixels
  2044. ;
  2045.         
  2046.         cmp bh,bl
  2047.         je ret_line
  2048.         mov bl,bh
  2049.         not bl
  2050.         and bh,al
  2051.         
  2052.         and bl,[di]
  2053.         or bl,bh
  2054.         mov [di],bl       
  2055.  
  2056. ret_line label near
  2057.  
  2058.         pop ds                ; Restore the registers
  2059.         pop bp
  2060.         ret 0AH                ; remove arguments from the stack
  2061.  
  2062.  
  2063. m_line endp
  2064. cseg ends
  2065.      end
  2066.