home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chaptere / le-4.asm < prev    next >
Encoding:
Assembly Source File  |  1997-06-18  |  18.4 KB  |  396 lines

  1. ; *** Listing 20.4 ***
  2. ;
  3. ; Contains 3 C-callable routines: GenerateEOctant, DrawVOctant, and
  4. ;       DrawHOctant. See individual routines for comments.
  5. ;
  6. ; Assembled with TASM 4.0.  Link with L20-2.C and L20-3.C.
  7. ; Checked by Jim Mischel  11/30/94.
  8. ;
  9. ISVGA   equ     0       ;set to 1 to use VGA write mode 3
  10.                         ; keep synchronized with Listing 3
  11.         .model small
  12.         .code
  13. ;********************************************************************
  14. ; Generates an octant of the specified ellipse, placing the results in
  15. ; PixList, with a 0 in PixList meaning draw pixel & move only along
  16. ; major axis, and a 1 in PixList meaning draw pixel & move along both
  17. ; axes.
  18. ; C near-callable as:
  19. ;  int GenerateEOctant(unsigned char *PixList, long MinorAdjust,
  20. ;       long Threshold, long MajorSquared, long MinorSquared);
  21. ;
  22. ; Return value = PixelCount (# of points)
  23. ;
  24. ; Passed parameters:
  25. ;
  26. GenerateOctantParms     struc
  27.         dw      ?       ;pushed BP
  28.         dw      ?       ;return address pushed by call
  29. PixList dw      ?       ;pointer to list to store draw control data in
  30. MinorAdjust dd  ?       ;initially MajorAxis**2 * 2 * MinorAxis, used
  31.                         ; to adjust threshold after minor axis move
  32. Threshold dd    ?       ;initially MajorAxis**2 / 4 + MajorAxis**2 *
  33.                         ; MinorAxis, used to determine when to advance
  34.                         ; along the minor axis
  35. MajorSquared dd ?       ;MajorAxis**2
  36. MinorSquared dd ?       ;MinorAxis**2
  37. GenerateOctantParms     ends
  38. ;
  39. ; Local variables (offsets relative to BP in stack frame):
  40. ;
  41. PixelCount      equ     -2      ;running major axis coordinate
  42.                                 ; relative to center
  43. MajorAdjust     equ     -6      ;used to adjust threshold after major
  44.                                 ; axis move
  45. MajorSquaredTimes2 equ  -10     ;MajorSquared * 2
  46. MinorSquaredTimes2 equ  -14     ;MinorSquared * 2
  47. ;
  48.         public _GenerateEOctant
  49. _GenerateEOctant proc    near
  50.         push    bp              ;preserve caller's stack frame
  51.         mov     bp,sp           ;point to our stack frame
  52.         add     sp,MinorSquaredTimes2
  53.                                 ;allocate room for local vars
  54.         push    si              ;preserve C register variables
  55.         push    di
  56. ;Initialize local variables.
  57.         mov     word ptr [bp+PixelCount],0 ;initialize count of pixels
  58.                                         ; to zero
  59.         mov     ax,word ptr [bp+MajorSquared] ;set MajorSquaredTimes2
  60.         shl     ax,1                    ;lower word times 2
  61.         mov     word ptr [bp+MajorSquaredTimes2],ax
  62.         mov     ax,word ptr [bp+MajorSquared+2]
  63.         rcl     ax,1                    ;upper word times 2
  64.         mov     word ptr [bp+MajorSquaredTimes2+2],ax
  65.         
  66.         mov     ax,word ptr [bp+MinorSquared] ;set MinorSquaredTimes2
  67.         shl     ax,1                    ;lower word times 2
  68.         mov     word ptr [bp+MinorSquaredTimes2],ax
  69.         mov     ax,word ptr [bp+MinorSquared+2]
  70.         rcl     ax,1                    ;upper word times 2
  71.         mov     word ptr [bp+MinorSquaredTimes2+2],ax
  72. ;Set up registers for loop.     
  73.         mov     di,[PixList+bp]         ;point DI to PixList
  74. ; Set MajorAdjust to 0.
  75.         sub     cx,cx
  76.         mov     si,cx                   ;SI:CX = MajorAdjust
  77.  
  78.         mov     bx,word ptr [bp+Threshold]      ;DX:BX = threshold
  79.         mov     dx,word ptr [bp+Threshold+2]
  80. ; At this point:
  81. ;  DX:BX = threshold
  82. ;  SI:CX = MajorAdjust
  83. ;  DI = PixList pointer
  84. GenLoop:
  85. ; Advance the threshold by MajorAdjust + MinorAxis**2.
  86.         add     bx,cx
  87.         adc     dx,si
  88.         add     bx,word ptr [bp+MinorSquared]
  89.         adc     dx,word ptr [bp+MinorSquared+2]
  90. ; If the threshold has passed 0, then the minor coordinate has
  91. ; advanced more than halfway to the next pixel and it's time to
  92. ; advance the minor coordinate by 1 and set the next threshold
  93. ; accordingly.
  94.         mov     byte ptr [di],0 ;assume we won't move along the
  95.                                 ; minor axis
  96.         js      MoveMajor       ;and, in fact, we won't move minor
  97. ; Minor coordinate has advanced.
  98. ; Adjust the minor axis adjust value.
  99.         mov     ax,word ptr [bp+MajorSquaredTimes2]
  100.         sub     word ptr [bp+MinorAdjust],ax
  101.         mov     ax,word ptr [bp+MajorSquaredTimes2+2]
  102.         sbb     word ptr [bp+MinorAdjust+2],ax
  103. ; Adjust the threshold for the minor axis move
  104.         sub     bx,word ptr [bp+MinorAdjust]
  105.         sbb     dx,word ptr [bp+MinorAdjust+2]
  106.         mov     byte ptr [di],1
  107. MoveMajor:
  108.         inc     di
  109. ; Count this point.
  110.         inc     word ptr [bp+PixelCount]
  111. ; Adjust the major adjust for the new point.
  112.         add     cx,word ptr [bp+MinorSquaredTimes2]
  113.         adc     si,word ptr [bp+MinorSquaredTimes2+2]
  114. ; Stop if the major axis has switched (the arc has passed the
  115. ; 45-degree point).
  116.         cmp     si,word ptr [bp+MinorAdjust+2]
  117.         ja      Done
  118.         jb      GenLoop
  119.         cmp     cx,word ptr [bp+MinorAdjust]
  120.         jb      GenLoop
  121. Done:
  122.         mov     ax,[bp+PixelCount]      ;return # of points
  123.         pop     di              ;restore C register variables
  124.         pop     si
  125.         mov     sp,bp           ;deallocate local vars
  126.         pop     bp              ;restore caller's stack frame
  127.         ret
  128. _GenerateEOctant endp
  129. ;********************************************************************
  130. ; Draws the arc for an octant in which Y is the major axis. (X,Y) is the
  131. ; starting point of the arc. HorizontalMoveDirection selects whether the
  132. ; arc advances to the left or right horizontally (0=left, 1=right).
  133. ; RowOffset contains the offset in bytes from one scan line to the next,
  134. ; controlling whether the arc is drawn up or down. DrawLength is the
  135. ; vertical length in pixels of the arc, and DrawList is a list
  136. ; containing 0 for each point if the next point is vertically aligned,
  137. ; and 1 if the next point is 1 pixel diagonally to the left or right.
  138. ;
  139. ; The Graphics Controller Index register must already point to the Bit
  140. ; Mask register.
  141. ;
  142. ; C near-callable as:
  143. ;  void DrawVOctant(int X, int Y, int DrawLength, int RowOffset,
  144. ;       int HorizontalMoveDirection, unsigned char *DrawList);
  145. ;
  146. DrawParms       struc
  147.         dw      ?       ;pushed BP
  148.         dw      ?       ;return address
  149. X       dw      ?       ;initial coordinates
  150. Y       dw      ?
  151. DrawLength dw   ?       ;vertical length
  152. RowOffset dw    ?       ;distance from one scan line to the next
  153. HorizontalMoveDirection dw ? ;1 to move right, 0 to move left
  154. DrawList dw     ?       ;pointer to list containing 1 to draw
  155. DrawParms       ends    ; diagonally, 0 to draw vertically for
  156.                                 ; each point
  157. SCREEN_SEGMENT  equ     0a000h  ;display memory segment in mode 12h
  158. SCREEN_WIDTH_IN_BYTES equ 80    ;distance from one scan line to next
  159. GC_INDEX        equ     3ceh    ;GC Index register address
  160. ;
  161.         public _DrawVOctant
  162. _DrawVOctant    proc    near
  163.         push    bp              ;preserve caller's stack frame
  164.         mov     bp,sp           ;point to our stack frame
  165.         push    si              ;preserve C register variables
  166.         push    di
  167. ;Point ES:DI to the byte the initial pixel is in.
  168.         mov     ax,SCREEN_SEGMENT
  169.         mov     es,ax
  170.         mov     ax,SCREEN_WIDTH_IN_BYTES
  171.         mul     [bp+Y]  ;Y*SCREEN_WIDTH_IN_BYTES
  172.         mov     di,[bp+X] ;X
  173.         mov     cx,di   ;set X aside in CX
  174.         shr     di,1
  175.         shr     di,1
  176.         shr     di,1    ;X/8
  177.         add     di,ax   ;screen offset = Y*SCREEN_WIDTH_IN_BYTES+X/8
  178.         and     cl,07h  ;X modulo 8
  179. if ISVGA                ;---VGA---
  180.         mov     ah,80h  ;keep VGA bit mask in AH
  181.         shr     ah,cl   ;initial bit mask = 80h shr (X modulo 8);
  182.         cld             ;for LODSB, used below
  183. else                    ;---EGA---
  184.         mov     al,80h  ;keep EGA bit mask in AL
  185.         shr     al,cl   ;initial bit mask = 80h shr (X modulo 8);
  186.         mov     dx,GC_INDEX+1 ;point DX to GC Data reg/bit mask
  187. endif                   ;---------
  188.         mov     si,[bp+DrawList] ;SI points to list to draw from
  189.         sub     bx,bx           ;so we have the constant 0 in a reg
  190.         mov     cx,[bp+DrawLength] ;CX=# of pixels to draw
  191.         jcxz    VDrawDone       ;skip this if no pixels to draw
  192.         cmp     [bp+HorizontalMoveDirection],0 ;draw right or left
  193.         mov     bp,[bp+RowOffset] ;BP=offset to next row
  194.         jz      VGoLeft         ;draw from right to left
  195. VDrawRightLoop:                 ;draw from left to right
  196. if ISVGA                        ;---VGA---
  197.         and     es:[di],ah      ;AH becomes bit mask in write mode 3,
  198.                                 ; set/reset provides color
  199.         lodsb                   ;get next draw control byte
  200.         and     al,al           ;move right?
  201.         jz      VAdvanceOneLineRight ;no move right
  202.         ror     ah,1            ;move right
  203. else                            ;---EGA---
  204.         out     dx,al           ;set the desired bit mask
  205.         and     es:[di],al      ;data doesn't matter (set/reset provides
  206.                                 ; color); just force read then write
  207.         cmp     [si],bl         ;check draw control byte; move right?
  208.         jz      VAdvanceOneLineRight ;no move right
  209.         ror     al,1            ;move right
  210. endif                           ;---------
  211.         adc     di,bx   ;move one byte to the right if mask wrapped
  212. VAdvanceOneLineRight:
  213. ife ISVGA                       ;---EGA---
  214.         inc     si              ;advance draw control list pointer
  215. endif                           ;---------
  216.         add     di,bp           ;move to the next scan line up or down
  217.         loop    VDrawRightLoop  ;do next pixel, if any
  218.         jmp     short VDrawDone ;done
  219. VGoLeft:                        ;draw from right to left
  220. VDrawLeftLoop:
  221. if ISVGA                        ;---VGA---
  222.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  223.         lodsb                   ;get next draw control byte
  224.         and     al,al           ;move left?
  225.         jz      VAdvanceOneLineLeft ;no move left
  226.         rol     ah,1            ;move left
  227. else                            ;---EGA---
  228.         out     dx,al           ;set the desired bit mask
  229.         and     es:[di],al      ;data doesn't matter; force read/write
  230.         cmp     [si],bl         ;check draw control byte; move left?
  231.         jz      VAdvanceOneLineLeft ;no move left
  232.         rol     al,1            ;move left
  233. endif                           ;---------
  234.         sbb     di,bx           ;move one byte to the left if mask wrapped
  235. VAdvanceOneLineLeft:
  236. ife ISVGA                       ;---EGA---
  237.         inc     si              ;advance draw control list pointer
  238. endif                           ;---------
  239.         add     di,bp           ;move to the next scan line up or down
  240.         loop    VDrawLeftLoop   ;do next pixel, if any
  241. VDrawDone:
  242.         pop     di              ;restore C register variables
  243.         pop     si
  244.         pop     bp
  245.         ret
  246. _DrawVOctant    endp
  247. ;********************************************************************
  248. ; Draws the arc for an octant in which X is the major axis. (X,Y) is the
  249. ; starting point of the arc. HorizontalMoveDirection selects whether the
  250. ; arc advances to the left or right horizontally (0=left, 1=right).
  251. ; RowOffset contains the offset in bytes from one scan line to the next,
  252. ; controlling whether the arc is drawn up or down. DrawLength is the
  253. ; horizontal length in pixels of the arc, and DrawList is a list
  254. ; containing 0 for each point if the next point is horizontally aligned,
  255. ; and 1 if the next point is 1 pixel above or below diagonally.
  256. ;
  257. ; Graphics Controller Index register must already point to the Bit Mask
  258. ; register.
  259. ;
  260. ; C near-callable as:
  261. ;  void DrawHOctant(int X, int Y, int DrawLength, int RowOffset,
  262. ;       int HorizontalMoveDirection, unsigned char *DrawList)
  263. ;
  264. ; Uses same parameter structure as DrawVOctant().
  265. ;
  266.         public _DrawHOctant
  267. _DrawHOctant    proc    near
  268.         push    bp              ;preserve caller's stack frame
  269.         mov     bp,sp           ;point to our stack frame
  270.         push    si              ;preserve C register variables
  271.         push    di
  272. ;Point ES:DI to the byte the initial pixel is in.
  273.         mov     ax,SCREEN_SEGMENT
  274.         mov     es,ax
  275.         mov     ax,SCREEN_WIDTH_IN_BYTES
  276.         mul     [bp+Y]  ;Y*SCREEN_WIDTH_IN_BYTES
  277.         mov     di,[bp+X] ;X
  278.         mov     cx,di   ;set X aside in CX
  279.         shr     di,1
  280.         shr     di,1
  281.         shr     di,1    ;X/8
  282.         add     di,ax   ;screen offset = Y*SCREEN_WIDTH_IN_BYTES+X/8
  283.         and     cl,07h  ;X modulo 8
  284.         mov     bh,80h
  285.         shr     bh,cl   ;initial bit mask = 80h shr (X modulo 8);
  286. if ISVGA                ;---VGA---
  287.         cld             ;for LODSB, used below
  288. else                    ;---EGA---
  289.         mov     dx,GC_INDEX+1 ;point DX to GC Data reg/bit mask
  290. endif                    ;---------
  291.         mov     si,[bp+DrawList] ;SI points to list to draw from
  292.         sub     bl,bl           ;so we have the constant 0 in a reg
  293.         mov     cx,[bp+DrawLength] ;CX=# of pixels to draw
  294.         jcxz    HDrawDone       ;skip this if no pixels to draw
  295. if ISVGA                        ;---VGA---
  296.         sub     ah,ah           ;clear bit mask accumulator
  297. else                            ;---EGA---
  298.         sub     al,al           ;clear bit mask accumulator
  299. endif                           ;---------
  300.         cmp     [bp+HorizontalMoveDirection],0 ;draw right or left
  301.         mov     bp,[bp+RowOffset] ;BP=offset to next row
  302.         jz      HGoLeft         ;draw from right to left
  303. HDrawRightLoop:                 ;draw from left to right
  304. if ISVGA                        ;---VGA---
  305.         or      ah,bh           ;put this pixel in bit mask accumulator
  306.         lodsb                   ;get next draw control byte
  307.         and     al,al           ;move up/down?
  308. else                            ;---EGA---
  309.         or      al,bh           ;put this pixel in bit mask accumulator
  310.         cmp     [si],bl         ;check draw control byte; move up/down?
  311. endif                           ;---------
  312.         jz      HAdvanceOneLineRight ;no move up/down
  313.                                 ;move up/down; first draw accumulated pixels
  314. if ISVGA                        ;---VGA---
  315.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  316.         sub     ah,ah           ;clear bit mask accumulator
  317. else                            ;---EGA---
  318.         out     dx,al           ;set the desired bit mask
  319.         and     es:[di],al      ;data doesn't matter; force read/write
  320.         sub     al,al           ;clear bit mask accumulator
  321. endif                           ;---------
  322.         add     di,bp           ;move to the next scan line up or down
  323. HAdvanceOneLineRight:
  324. ife ISVGA                       ;---EGA---
  325.         inc     si              ;advance draw control list pointer
  326. endif                           ;---------
  327.         ror     bh,1            ;move to right; shift mask
  328.         jnc     HDrawLoopRightBottom ;didn't wrap to the next byte
  329.                                 ;move to next byte; 1st draw accumulated pixels
  330. if ISVGA                        ;---VGA---
  331.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  332.         sub     ah,ah           ;clear bit mask accumulator
  333. else
  334.         out     dx,al           ;set the desired bit mask
  335.         and     es:[di],al      ;data doesn't matter; force read/write
  336.         sub     al,al           ;clear bit mask accumulator
  337. endif                           ;---------
  338.         inc     di              ;move 1 byte to the right
  339. HDrawLoopRightBottom:
  340.         loop    HDrawRightLoop  ;draw next pixel, if any
  341.         jmp     short HDrawDone ;done
  342. HGoLeft:                        ;draw from right to left
  343. HDrawLeftLoop:
  344. if ISVGA                        ;---VGA---
  345.         or      ah,bh           ;put this pixel in bit mask accumulator
  346.         lodsb                   ;get next draw control byte
  347.         and     al,al           ;move up/down?
  348. else                            ;---EGA---
  349.         or      al,bh           ;put this pixel in bit mask accumulator
  350.         cmp     [si],bl         ;check draw control byte; move up/down?
  351. endif                           ;---------
  352.         jz      HAdvanceOneLineLeft ;no move up/down
  353.                                 ;move up/down; first draw accumulated pixels
  354. if ISVGA                        ;---VGA---
  355.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  356.         sub     ah,ah           ;clear bit mask accumulator
  357. else                            ;---EGA---
  358.         out     dx,al           ;set the desired bit mask
  359.         and     es:[di],al      ;data doesn't matter; force read/write
  360.         sub     al,al           ;clear bit mask accumulator
  361. endif                           ;---------
  362.         add     di,bp           ;move to the next scan line up or down
  363. HAdvanceOneLineLeft:
  364. ife ISVGA                       ;---EGA---
  365.         inc     si              ;advance draw control list pointer
  366. endif                           ;---------
  367.         rol     bh,1            ;move to left; shift mask
  368.         jnc     HDrawLoopLeftBottom ;didn't wrap to next byte
  369.                                 ;move to next byte; 1st draw accumulated pixels
  370. if ISVGA                        ;---VGA---
  371.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  372.         sub     ah,ah           ;clear bit mask accumulator
  373. else                            ;---EGA---
  374.         out     dx,al           ;set the desired bit mask
  375.         and     es:[di],al      ;data doesn't matter; force read/write
  376.         sub     al,al           ;clear bit mask accumulator
  377. endif                           ;---------
  378.         dec     di              ;move 1 byte to the left
  379. HDrawLoopLeftBottom:
  380.         loop    HDrawLeftLoop   ;draw next pixel, if any
  381. HDrawDone:
  382.                                 ;draw any remaining accumulated pixels
  383. if ISVGA                        ;---VGA---
  384.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  385. else                            ;---EGA---
  386.         out     dx,al           ;set the desired bit mask
  387.         and     es:[di],al      ;data doesn't matter; force read/write
  388. endif                           ;---------
  389.         pop     di              ;restore C register variables
  390.         pop     si
  391.         pop     bp
  392.         ret
  393. _DrawHOctant    endp
  394.         end
  395.  
  396.