home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / asm / PJGRAPH.ZIP / CHAP12.3 < prev    next >
Encoding:
Text File  |  1989-09-26  |  13.0 KB  |  387 lines

  1. ; Fast assembler implementation of Bresenham's line-drawing algorithm
  2. ; for the EGA and VGA. Works in modes 0Dh, 0Eh, 0Fh, 10h, and 12h.
  3. ; Turbo C version 2.0 near-callable.
  4. ; Bit mask accumulation technique when |DeltaX| >= |DeltaY|
  5. ;  suggested by Jim Mackraz.
  6. ;
  7. ; Assemble and link with the program of Listing 12.2 with a command
  8. ; line like:
  9. ;
  10. ;       tcc lst12-2 lst12-3.asm
  11. ;
  12. ; (requires Turbo C and either TASM or MASM).
  13. ;
  14. ; Assembled with TASM 1.0.
  15. ;
  16. ; By Michael Abrash.  2/4/89.
  17. ; Updated 6/29/89.
  18. ;
  19. ;****************************************************************
  20. ; C-compatible line-drawing entry point at _EVGALine.           *
  21. ; Called from Turbo C with:                                     *
  22. ;       EVGALine(X0, Y0, X1, Y1, Color);                        *
  23. ;****************************************************************
  24. ;
  25.  
  26. _TEXT   segment byte public 'CODE'
  27.         assume cs: _TEXT
  28.  
  29. ;
  30. ; Equates.
  31. ;
  32. EVGA_SCREEN_WIDTH_IN_BYTES equ  80      ;memory offset from start of
  33.                                         ; one row to start of next
  34.                                         ; in display memory
  35. EVGA_SCREEN_SEGMENT     equ     0a000h  ;display-memory segment
  36. GC_INDEX                equ     3ceh    ;Graphics Controller
  37.                                         ; Index register port
  38. SET_RESET_INDEX         equ     0       ;indexes of needed
  39. ENABLE_SET_RESET_INDEX  equ     1       ; Graphics Controller
  40. BIT_MASK_INDEX          equ     8       ; registers
  41.  
  42. ;
  43. ; Stack frame.
  44. ;
  45. EVGALineParms   struc
  46.         dw      ?               ;pushed BP
  47.         dw      ?               ;pushed return address (make double
  48.                                 ; word for far call)
  49. X0      dw      ?               ;starting X coordinate of line
  50. Y0      dw      ?               ;starting Y coordinate of line
  51. X1      dw      ?               ;ending X coordinate of line
  52. Y1      dw      ?               ;ending Y coordinate of line
  53. Color   db      ?               ;color of line
  54.         db      ?               ;dummy to pad to word size
  55. EVGALineParms   ends
  56.  
  57. ;****************************************************************
  58. ; Line-drawing macros.                                          *
  59. ;****************************************************************
  60.  
  61. ;
  62. ; Macro to loop through length of line, drawing each pixel in turn.
  63. ; Used for case of |DeltaX| >= |DeltaY|.
  64. ; |DeltaX|+1 points are drawn.
  65. ;
  66. ; Input:                                
  67. ;       MOVE_LEFT: 1 if DeltaX < 0, 0 else
  68. ;       AL: pixel mask for initial pixel
  69. ;       BX: |DeltaX| (X distance between start and end points)
  70. ;       DX: address of GC data register, with index register set to
  71. ;               index of Bit Mask register
  72. ;       SI: DeltaY (Y distance between start and end points)
  73. ;       ES:DI: display-memory address of byte containing initial
  74. ;               pixel
  75. ;
  76. ; Output: none
  77. ;
  78. LINE1   macro   MOVE_LEFT
  79.         local   LineLoop, MoveXCoord, NextPixel, Line1End
  80.         local   MoveToNextByte, ResetBitMaskAccumulator
  81.         mov     cx,bx   ;# of pixels in line
  82.         jcxz    Line1End ;done if there are no more pixels
  83.                         ; (there's always at least the one pixel
  84.                         ; at the start location)
  85.         shl     si,1    ;DeltaY * 2
  86.         mov     bp,si   ;error term
  87.         sub     bp,bx   ;error term starts at DeltaY * 2 - DeltaX
  88.         shl     bx,1    ;DeltaX * 2
  89.         sub     si,bx   ;DeltaY * 2 - DeltaX * 2 (used in loop)
  90.         add     bx,si   ;DeltaY * 2 (used in loop)
  91.         mov     ah,al   ;set aside pixel mask for initial pixel
  92.                         ; with AL (the pixel mask accumulator) set
  93.                         ; for the initial pixel
  94. LineLoop:
  95. ;
  96. ; See if it's time to advance the Y coordinate yet.
  97. ;
  98.         and     bp,bp           ;see if error term is negative
  99.         js      MoveXCoord      ;yes, stay at the same Y coordinate
  100. ;
  101. ; Advance the Y coordinate, first writing all pixels in the current
  102. ; byte, then move the pixel mask either left or right, depending
  103. ; on MOVE_LEFT.
  104. ;
  105.         out     dx,al   ;set up bit mask for pixels in this byte
  106.         xchg    byte ptr [di],al
  107.                         ;load latches and write pixels, with bit mask
  108.                         ; preserving other latched bits. Because
  109.                         ; set/reset is enabled for all planes, the
  110.                         ; value written actually doesn't matter
  111.         add     di,EVGA_SCREEN_WIDTH_IN_BYTES   ;increment Y coordinate
  112.         add     bp,si   ;adjust error term back down
  113. ;
  114. ; Move pixel mask one pixel (either right or left, depending
  115. ; on MOVE_LEFT), adjusting display-memory address when pixel mask wraps.
  116. ;
  117. if MOVE_LEFT
  118.         rol     ah,1    ;move pixel mask 1 pixel to the left
  119. else
  120.         ror     ah,1    ;move pixel mask 1 pixel to the right
  121. endif
  122.         jnc     ResetBitMaskAccumulator ;didn't wrap to next byte
  123.         jmp     short MoveToNextByte    ;did wrap to next byte
  124. ;
  125. ; Move pixel mask one pixel (either right or left, depending
  126. ; on MOVE_LEFT), adjusting display-memory address and writing pixels
  127. ; in this byte when pixel mask wraps.
  128. ;
  129. MoveXCoord:
  130.         add     bp,bx   ;increment error term & keep same Y coordinate
  131. if MOVE_LEFT
  132.         rol     ah,1    ;move pixel mask 1 pixel to the left
  133. else
  134.         ror     ah,1    ;move pixel mask 1 pixel to the right
  135. endif
  136.         jnc     NextPixel ;if still in same byte, no need to
  137.                         ; modify display memory yet
  138.         out     dx,al   ;set up bit mask for pixels in this byte.
  139.         xchg    byte ptr [di],al
  140.                         ;load latches and write pixels, with bit mask
  141.                         ; preserving other latched bits. Because
  142.                         ; set/reset is enabled for all planes, the
  143.                         ; value written actually doesn't matter
  144. MoveToNextByte:
  145. if MOVE_LEFT
  146.         dec     di      ;next pixel is in byte to left
  147. else
  148.         inc     di      ;next pixel is in byte to right
  149. endif
  150. ResetBitMaskAccumulator:
  151.         sub     al,al   ;reset pixel mask accumulator   
  152. NextPixel:
  153.         or      al,ah   ;add the next pixel to the pixel mask
  154.                         ; accumulator
  155.         loop    LineLoop
  156. ;
  157. ; Write the pixels in the final byte.
  158. ;
  159. Line1End:
  160.         out     dx,al   ;set up bit mask for pixels in this byte.
  161.         xchg    byte ptr [di],al
  162.                         ;load latches and write pixels, with bit mask
  163.                         ; preserving other latched bits. Because
  164.                         ; set/reset is enabled for all planes, the
  165.                         ; value written actually doesn't matter
  166.         endm
  167.  
  168. ;
  169. ; Macro to loop through length of line, drawing each pixel in turn.
  170. ; Used for case of DeltaX < DeltaY.
  171. ; |DeltaY|+1 points are drawn.
  172. ;
  173. ; Input:                                
  174. ;       MOVE_LEFT: 1 if DeltaX < 0, 0 else
  175. ;       AL: pixel mask for initial pixel
  176. ;       BX: |DeltaX| (X distance between start and end points)
  177. ;       DX: address of GC data register, with index register set to
  178. ;               index of Bit Mask register
  179. ;       SI: DeltaY (Y distance between start and end points)
  180. ;       ES:DI: display-memory address of byte containing initial
  181. ;               pixel
  182. ;
  183. ; Output: none
  184. ;
  185. LINE2   macro   MOVE_LEFT
  186.         local   LineLoop, MoveYCoord, ETermAction, Line2End
  187.         mov     cx,si   ;# of pixels in line
  188.         shl     bx,1    ;DeltaX * 2
  189.         mov     bp,bx   ;error term
  190.         sub     bp,si   ;error term starts at DeltaX * 2 - DeltaY
  191.         shl     si,1    ;DeltaY * 2
  192.         sub     bx,si   ;DeltaX * 2 - DeltaY * 2 (used in loop)
  193.         add     si,bx   ;DeltaX * 2 (used in loop)
  194. ;
  195. ; Set up initial bit mask & draw initial pixel.
  196. ;
  197.         out     dx,al
  198.         xchg    byte ptr [di],ah
  199.                         ;load latches and write pixel, with bit mask
  200.                         ; preserving other latched bits. Because
  201.                         ; set/reset is enabled for all planes, the
  202.                         ; value written actually doesn't matter
  203.         jcxz    Line2End ;done if there are no more pixels
  204.                         ; (there's always at least the one pixel
  205.                         ; at the start location)
  206. LineLoop:
  207. ;
  208. ; See if it's time to advance the X coordinate yet.
  209. ;
  210.         and     bp,bp           ;see if error term is negative
  211.         jns     ETermAction     ;no, advance X coordinate
  212.         add     bp,si           ;increment error term & keep same
  213.         jmp     short MoveYCoord ; X coordinate
  214. ETermAction:
  215. ;
  216. ; Move pixel mask one pixel (either right or left, depending
  217. ; on MOVE_LEFT), adjusting display-memory address when pixel mask wraps.
  218. ;
  219. if MOVE_LEFT
  220.         rol     al,1
  221.         sbb     di,0
  222. else
  223.         ror     al,1
  224.         adc     di,0
  225. endif
  226.         out     dx,al   ;set new bit mask
  227.         add     bp,bx   ;adjust error term back down
  228. ;
  229. ; Advance Y coordinate.
  230. ;
  231. MoveYCoord:
  232.         add     di,EVGA_SCREEN_WIDTH_IN_BYTES
  233. ;
  234. ; Write the next pixel.
  235. ;
  236.         xchg    byte ptr [di],ah
  237.                         ;load latches and write pixel, with bit mask
  238.                         ; preserving other latched bits. Because
  239.                         ; set/reset is enabled for all planes, the
  240.                         ; value written actually doesn't matter
  241. ;
  242.         loop    LineLoop
  243. Line2End:
  244.         endm
  245.  
  246. ;****************************************************************
  247. ; Line-drawing routine.                                         *
  248. ;****************************************************************
  249.  
  250.         public  _EVGALine
  251. _EVGALine       proc    near
  252.         push    bp
  253.         mov     bp,sp
  254.         push    si      ;preserve register variables
  255.         push    di
  256.         push    ds
  257. ;
  258. ; Point DS to display memory.
  259. ;
  260.         mov     ax,EVGA_SCREEN_SEGMENT
  261.         mov     ds,ax
  262. ;
  263. ; Set the Set/Reset and Set/Reset Enable registers for
  264. ; the selected color.
  265. ;
  266.         mov     dx,GC_INDEX
  267.         mov     al,SET_RESET_INDEX
  268.         out     dx,al
  269.         inc     dx
  270.         mov     al,[bp+Color]
  271.         out     dx,al
  272.         dec     dx
  273.         mov     al,ENABLE_SET_RESET_INDEX
  274.         out     dx,al
  275.         inc     dx
  276.         mov     al,0ffh
  277.         out     dx,al
  278. ;
  279. ; Get DeltaY.
  280. ;
  281.         mov     si,[bp+Y1]      ;line Y start
  282.         mov     ax,[bp+Y0]      ;line Y end, used later in
  283.                                 ;calculating the start address
  284.         sub     si,ax           ;calculate DeltaY
  285.         jns     CalcStartAddress ;if positive, we're set
  286. ;
  287. ; DeltaY is negative -- swap coordinates so we're always working
  288. ; with a positive DeltaY.
  289. ;
  290.         mov     ax,[bp+Y1]      ;set line start to Y1, for use
  291.                                 ; in calculating the start address
  292.         mov     dx,[bp+X0]
  293.         xchg    dx,[bp+X1]
  294.         mov     [bp+X0],dx      ;swap X coordinates
  295.         neg     si              ;convert to positive DeltaY
  296. ;
  297. ; Calculate the starting address in display memory of the line.
  298. ; Hardwired for a screen width of 80 bytes.
  299. ;
  300. CalcStartAddress:
  301.         shl     ax,1    ;Y0 * 2 ;Y0 is already in AX
  302.         shl     ax,1    ;Y0 * 4
  303.         shl     ax,1    ;Y0 * 8
  304.         shl     ax,1    ;Y0 * 16
  305.         mov     di,ax
  306.         shl     ax,1    ;Y0 * 32
  307.         shl     ax,1    ;Y0 * 64
  308.         add     di,ax   ;Y0 * 80
  309.         mov     dx,[bp+X0]
  310.         mov     cl,dl   ;set aside lower 3 bits of column for
  311.         and     cl,7    ; pixel masking
  312.         shr     dx,1
  313.         shr     dx,1
  314.         shr     dx,1    ;get byte address of column (X0/8)
  315.         add     di,dx   ;offset of line start in display segment
  316. ;
  317. ; Set up GC Index register to point to the Bit Mask register.
  318. ;
  319.         mov     dx,GC_INDEX
  320.         mov     al,BIT_MASK_INDEX
  321.         out     dx,al
  322.         inc     dx      ;leave DX pointing to the GC Data register
  323. ;
  324. ; Set up pixel mask (in-byte pixel address).
  325. ;
  326.         mov     al,80h
  327.         shr     al,cl
  328. ;
  329. ; Calculate DeltaX.
  330. ;
  331.         mov     bx,[bp+X1]
  332.         sub     bx,[bp+X0]
  333. ;
  334. ; Handle correct one of four octants.
  335. ;
  336.         js      NegDeltaX
  337.         cmp     bx,si
  338.         jb      Octant1
  339. ;
  340. ; DeltaX >= DeltaY >= 0.
  341. ;
  342.         LINE1   0
  343.         jmp     EVGALineDone
  344. ;
  345. ; DeltaY > DeltaX >= 0.
  346. ;
  347. Octant1:
  348.         LINE2   0
  349.         jmp     short EVGALineDone
  350. ;
  351. NegDeltaX:
  352.         neg     bx      ;|DeltaX|
  353.         cmp     bx,si
  354.         jb      Octant2
  355. ;
  356. ; |DeltaX| >= DeltaY and DeltaX < 0.
  357. ;
  358.         LINE1   1
  359.         jmp     short EVGALineDone
  360. ;
  361. ; |DeltaX| < DeltaY and DeltaX < 0.
  362. ;
  363. Octant2:
  364.         LINE2   1
  365. ;
  366. EVGALineDone:
  367. ;
  368. ; Restore EVGA state.
  369. ;
  370.         mov     al,0ffh
  371.         out     dx,al   ;set Bit Mask register to 0ffh
  372.         dec     dx
  373.         mov     al,ENABLE_SET_RESET_INDEX
  374.         out     dx,al
  375.         inc     dx
  376.         sub     al,al
  377.         out     dx,al   ;set Enable Set/Reset register to 0
  378. ;
  379.         pop     ds
  380.         pop     di
  381.         pop     si
  382.         pop     bp
  383.         ret
  384. _EVGALine       endp
  385.  
  386. _TEXT   ends
  387.         end