home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapterc / lc-4.asm < prev    next >
Assembly Source File  |  1997-06-18  |  17KB  |  354 lines

  1. ; *** Listing 18.4 ***
  2. ;
  3. ; Contains 3 C-callable routines: GenerateOctant, DrawVOctant, and
  4. ;       DrawHOctant. See individual routines for comments.
  5. ;
  6. ; Assembled with TASM 4.0.  Link with L18-2.C and L18-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 circle, 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 GenerateOctant(unsigned char *PixList, int MajorAxis,
  20. ;       int MinorAxis, unsigned long RadiusSqMinusMajorAxisSq,
  21. ;       unsigned long MinorAxisSquaredThreshold);
  22. ;
  23. ; Return value = MajorAxis
  24. ;
  25. GenerateOctantParms     struc
  26.         dw      ?       ;pushed BP
  27.         dw      ?       ;return address
  28. PixList dw      ?       ;pointer to list to store draw control data in
  29. MajorAxis dw    ?       ;initial major/minor axis coords relative to
  30. MinorAxis dw    ?       ; to the center of the circle
  31. RadiusSqMinusMajorAxisSq dd ?  ;initial Radius**2 - MajorAxis**2
  32. MinorAxisSquaredThreshold dd ? ;initial threshhold for minor axis
  33. GenerateOctantParms     ends   ; movement is MinorAxis**2 - MinorAxis
  34. ;
  35.         public _GenerateOctant
  36. _GenerateOctant proc    near
  37.         push    bp              ;preserve caller's stack frame
  38.         mov     bp,sp           ;point to our stack frame
  39.         push    si              ;preserve C register variables
  40.         push    di
  41. ;                                       ;get all parms into registers
  42.         mov     di,[PixList+bp]         ;point DI to PixList
  43.         mov     ax,[MajorAxis+bp]       ;AX=MajorAxis
  44.         mov     bx,[MinorAxis+bp]       ;BX=MinorAxis
  45.         mov     cx,word ptr [RadiusSqMinusMajorAxisSq+bp]
  46.         mov     dx,word ptr [RadiusSqMinusMajorAxisSq+bp+2]
  47.                                         ;DX:CX=RadiusSqMinusMajorAxisSq
  48.         mov     si,word ptr [MinorAxisSquaredThreshold+bp]
  49.         mov     bp,word ptr [MinorAxisSquaredThreshold+bp+2]
  50.                                         ;BP:SI=MinorAxisSquaredThreshold
  51. GenLoop:
  52.         sub     cx,1            ;subtract MajorAxis + MajorAxis + 1 from
  53.         sbb     dx,0            ; RadiusSqMinusMajorAxisSq
  54.         sub     cx,ax
  55.         sbb     dx,0
  56.         sub     cx,ax
  57.         sbb     dx,0
  58.         cmp     dx,bp           ;if RadiusSqMinusMajorAxisSq <=
  59.         jb      IsMinorMove     ; MinorAxisSquaredThreshold, move along
  60.         ja      NoMinorMove     ; minor as well as major, otherwise move
  61.         cmp     cx,si           ; only along major
  62.         ja      NoMinorMove
  63. IsMinorMove:                    ;move along minor as well as major
  64.         dec     bx              ;decrement MinorAxis
  65.         sub     si,bx           ;subtract MinorAxis + MinorAxis from
  66.         sbb     bp,0            ; MinorAxisSquaredThreshold
  67.         sub     si,bx
  68.         sbb     bp,0
  69.         mov     byte ptr [di],1 ;enter 1 (move both axes) in PixList
  70.         inc     di              ;advance PixList pointer
  71.         inc     ax              ;increment MajorAxis
  72.         cmp     ax,bx           ;done if MajorAxis > MinorAxis, else
  73.         jbe     GenLoop         ; continue generating PixList entries
  74.         jmp     short Done
  75. NoMinorMove:
  76.         mov     byte ptr [di],0 ;enter 0 (move only major) in PixList
  77.         inc     di              ;advance PixList pointer
  78.         inc     ax              ;increment MajorAxis
  79.         cmp     ax,bx           ;done if MajorAxis > MinorAxis, else
  80.         jbe     GenLoop         ; continue generating PixList entries
  81. Done:
  82.         pop     di              ;restore C register variables
  83.         pop     si
  84.         pop     bp
  85.         ret
  86. _GenerateOctant endp
  87. ;********************************************************************
  88. ; Draws the arc for an octant in which Y is the major axis. (X,Y) is the
  89. ; starting point of the arc. HorizontalMoveDirection selects whether the
  90. ; arc advances to the left or right horizontally (0=left, 1=right).
  91. ; RowOffset contains the offset in bytes from one scan line to the next,
  92. ; controlling whether the arc is drawn up or down. DrawLength is the
  93. ; vertical length in pixels of the arc, and DrawList is a list
  94. ; containing 0 for each point if the next point is vertically aligned,
  95. ; and 1 if the next point is 1 pixel diagonally to the left or right.
  96. ;
  97. ; The Graphics Controller Index register must already point to the Bit
  98. ; Mask register.
  99. ;
  100. ; C near-callable as:
  101. ;  void DrawVOctant(int X, int Y, int DrawLength, int RowOffset,
  102. ;       int HorizontalMoveDirection, unsigned char *DrawList);
  103. ;
  104. DrawParms       struc
  105.         dw      ?       ;pushed BP
  106.         dw      ?       ;return address
  107. X       dw      ?       ;initial coordinates
  108. Y       dw      ?
  109. DrawLength dw   ?       ;vertical length
  110. RowOffset dw    ?       ;distance from one scan line to the next
  111. HorizontalMoveDirection dw ? ;1 to move right, 0 to move left
  112. DrawList dw     ?       ;pointer to list containing 1 to draw
  113. DrawParms       ends    ; diagonally, 0 to draw vertically for
  114.                                 ; each point
  115. SCREEN_SEGMENT  equ     0a000h  ;display memory segment in mode 12h
  116. SCREEN_WIDTH_IN_BYTES equ 80    ;distance from one scan line to next
  117. GC_INDEX        equ     3ceh    ;GC Index register address
  118. ;
  119.         public _DrawVOctant
  120. _DrawVOctant    proc    near
  121.         push    bp              ;preserve caller's stack frame
  122.         mov     bp,sp           ;point to our stack frame
  123.         push    si              ;preserve C register variables
  124.         push    di
  125. ;Point ES:DI to the byte the initial pixel is in.
  126.         mov     ax,SCREEN_SEGMENT
  127.         mov     es,ax
  128.         mov     ax,SCREEN_WIDTH_IN_BYTES
  129.         mul     [bp+Y]  ;Y*SCREEN_WIDTH_IN_BYTES
  130.         mov     di,[bp+X] ;X
  131.         mov     cx,di   ;set X aside in CX
  132.         shr     di,1
  133.         shr     di,1
  134.         shr     di,1    ;X/8
  135.         add     di,ax   ;screen offset = Y*SCREEN_WIDTH_IN_BYTES+X/8
  136.         and     cl,07h  ;X modulo 8
  137. if ISVGA                ;---VGA---
  138.         mov     ah,80h  ;keep VGA bit mask in AH
  139.         shr     ah,cl   ;initial bit mask = 80h shr (X modulo 8);
  140.         cld             ;for LODSB, used below
  141. else                    ;---EGA---
  142.         mov     al,80h  ;keep EGA bit mask in AL
  143.         shr     al,cl   ;initial bit mask = 80h shr (X modulo 8);
  144.         mov     dx,GC_INDEX+1 ;point DX to GC Data reg/bit mask
  145. endif                   ;---------
  146.         mov     si,[bp+DrawList] ;SI points to list to draw from
  147.         sub     bx,bx           ;so we have the constant 0 in a reg
  148.         mov     cx,[bp+DrawLength] ;CX=# of pixels to draw
  149.         jcxz    VDrawDone       ;skip this if no pixels to draw
  150.         cmp     [bp+HorizontalMoveDirection],0 ;draw right or left
  151.         mov     bp,[bp+RowOffset] ;BP=offset to next row
  152.         jz      VGoLeft         ;draw from right to left
  153. VDrawRightLoop:                 ;draw from left to right
  154. if ISVGA                        ;---VGA---
  155.         and     es:[di],ah      ;AH becomes bit mask in write mode 3,
  156.                                 ; set/reset provides color
  157.         lodsb                   ;get next draw control byte
  158.         and     al,al           ;move right?
  159.         jz      VAdvanceOneLineRight ;no move right
  160.         ror     ah,1            ;move right
  161. else                            ;---EGA---
  162.         out     dx,al           ;set the desired bit mask
  163.         and     es:[di],al      ;data doesn't matter (set/reset provides
  164.                                 ; color); just force read then write
  165.         cmp     [si],bl         ;check draw control byte; move right?
  166.         jz      VAdvanceOneLineRight ;no move right
  167.         ror     al,1            ;move right
  168. endif                           ;---------
  169.         adc     di,bx   ;move one byte to the right if mask wrapped
  170. VAdvanceOneLineRight:
  171. ife ISVGA                       ;---EGA---
  172.         inc     si              ;advance draw control list pointer
  173. endif                           ;---------
  174.         add     di,bp           ;move to the next scan line up or down
  175.         loop    VDrawRightLoop  ;do next pixel, if any
  176.         jmp     short VDrawDone ;done
  177. VGoLeft:                        ;draw from right to left
  178. VDrawLeftLoop:
  179. if ISVGA                        ;---VGA---
  180.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  181.         lodsb                   ;get next draw control byte
  182.         and     al,al           ;move left?
  183.         jz      VAdvanceOneLineLeft ;no move left
  184.         rol     ah,1            ;move left
  185. else                            ;---EGA---
  186.         out     dx,al           ;set the desired bit mask
  187.         and     es:[di],al      ;data doesn't matter; force read/write
  188.         cmp     [si],bl         ;check draw control byte; move left?
  189.         jz      VAdvanceOneLineLeft ;no move left
  190.         rol     al,1            ;move left
  191. endif                           ;---------
  192.         sbb     di,bx           ;move one byte to the left if mask wrapped
  193. VAdvanceOneLineLeft:
  194. ife ISVGA                       ;---EGA---
  195.         inc     si              ;advance draw control list pointer
  196. endif                           ;---------
  197.         add     di,bp           ;move to the next scan line up or down
  198.         loop    VDrawLeftLoop   ;do next pixel, if any
  199. VDrawDone:
  200.         pop     di              ;restore C register variables
  201.         pop     si
  202.         pop     bp
  203.         ret
  204. _DrawVOctant    endp
  205. ;********************************************************************
  206. ; Draws the arc for an octant in which X is the major axis. (X,Y) is the
  207. ; starting point of the arc. HorizontalMoveDirection selects whether the
  208. ; arc advances to the left or right horizontally (0=left, 1=right).
  209. ; RowOffset contains the offset in bytes from one scan line to the next,
  210. ; controlling whether the arc is drawn up or down. DrawLength is the
  211. ; horizontal length in pixels of the arc, and DrawList is a list
  212. ; containing 0 for each point if the next point is horizontally aligned,
  213. ; and 1 if the next point is 1 pixel above or below diagonally.
  214. ;
  215. ; Graphics Controller Index register must already point to the Bit Mask
  216. ; register.
  217. ;
  218. ; C near-callable as:
  219. ;  void DrawHOctant(int X, int Y, int DrawLength, int RowOffset,
  220. ;       int HorizontalMoveDirection, unsigned char *DrawList)
  221. ;
  222. ; Uses same parameter structure as DrawVOctant().
  223. ;
  224.         public _DrawHOctant
  225. _DrawHOctant    proc    near
  226.         push    bp              ;preserve caller's stack frame
  227.         mov     bp,sp           ;point to our stack frame
  228.         push    si              ;preserve C register variables
  229.         push    di
  230. ;Point ES:DI to the byte the initial pixel is in.
  231.         mov     ax,SCREEN_SEGMENT
  232.         mov     es,ax
  233.         mov     ax,SCREEN_WIDTH_IN_BYTES
  234.         mul     [bp+Y]  ;Y*SCREEN_WIDTH_IN_BYTES
  235.         mov     di,[bp+X] ;X
  236.         mov     cx,di   ;set X aside in CX
  237.         shr     di,1
  238.         shr     di,1
  239.         shr     di,1    ;X/8
  240.         add     di,ax   ;screen offset = Y*SCREEN_WIDTH_IN_BYTES+X/8
  241.         and     cl,07h  ;X modulo 8
  242.         mov     bh,80h
  243.         shr     bh,cl   ;initial bit mask = 80h shr (X modulo 8);
  244. if ISVGA                ;---VGA---
  245.         cld             ;for LODSB, used below
  246. else                    ;---EGA---
  247.         mov     dx,GC_INDEX+1 ;point DX to GC Data reg/bit mask
  248. endif                    ;---------
  249.         mov     si,[bp+DrawList] ;SI points to list to draw from
  250.         sub     bl,bl           ;so we have the constant 0 in a reg
  251.         mov     cx,[bp+DrawLength] ;CX=# of pixels to draw
  252.         jcxz    HDrawDone       ;skip this if no pixels to draw
  253. if ISVGA                        ;---VGA---
  254.         sub     ah,ah           ;clear bit mask accumulator
  255. else                            ;---EGA---
  256.         sub     al,al           ;clear bit mask accumulator
  257. endif                           ;---------
  258.         cmp     [bp+HorizontalMoveDirection],0 ;draw right or left
  259.         mov     bp,[bp+RowOffset] ;BP=offset to next row
  260.         jz      HGoLeft         ;draw from right to left
  261. HDrawRightLoop:                 ;draw from left to right
  262. if ISVGA                        ;---VGA---
  263.         or      ah,bh           ;put this pixel in bit mask accumulator
  264.         lodsb                   ;get next draw control byte
  265.         and     al,al           ;move up/down?
  266. else                            ;---EGA---
  267.         or      al,bh           ;put this pixel in bit mask accumulator
  268.         cmp     [si],bl         ;check draw control byte; move up/down?
  269. endif                           ;---------
  270.         jz      HAdvanceOneLineRight ;no move up/down
  271.                         ;move up/down; first draw accumulated pixels
  272. if ISVGA                        ;---VGA---
  273.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  274.         sub     ah,ah           ;clear bit mask accumulator
  275. else                            ;---EGA---
  276.         out     dx,al           ;set the desired bit mask
  277.         and     es:[di],al      ;data doesn't matter; force read/write
  278.         sub     al,al           ;clear bit mask accumulator
  279. endif                           ;---------
  280.         add     di,bp           ;move to the next scan line up or down
  281. HAdvanceOneLineRight:
  282. ife ISVGA                       ;---EGA---
  283.         inc     si              ;advance draw control list pointer
  284. endif                           ;---------
  285.         ror     bh,1            ;move to right; shift mask
  286.         jnc     HDrawLoopRightBottom ;didn't wrap to the next byte
  287.                         ;move to next byte; 1st draw accumulated pixels
  288. if ISVGA                        ;---VGA---
  289.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  290.         sub     ah,ah           ;clear bit mask accumulator
  291. else
  292.         out     dx,al           ;set the desired bit mask
  293.         and     es:[di],al      ;data doesn't matter; force read/write
  294.         sub     al,al           ;clear bit mask accumulator
  295. endif                           ;---------
  296.         inc     di              ;move 1 byte to the right
  297. HDrawLoopRightBottom:
  298.         loop    HDrawRightLoop  ;draw next pixel, if any
  299.         jmp     short HDrawDone ;done
  300. HGoLeft:                        ;draw from right to left
  301. HDrawLeftLoop:
  302. if ISVGA                        ;---VGA---
  303.         or      ah,bh           ;put this pixel in bit mask accumulator
  304.         lodsb                   ;get next draw control byte
  305.         and     al,al           ;move up/down?
  306. else                            ;---EGA---
  307.         or      al,bh           ;put this pixel in bit mask accumulator
  308.         cmp     [si],bl         ;check draw control byte; move up/down?
  309. endif                           ;---------
  310.         jz      HAdvanceOneLineLeft ;no move up/down
  311.                         ;move up/down; first draw accumulated pixels
  312. if ISVGA                        ;---VGA---
  313.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  314.         sub     ah,ah           ;clear bit mask accumulator
  315. else                            ;---EGA---
  316.         out     dx,al           ;set the desired bit mask
  317.         and     es:[di],al      ;data doesn't matter; force read/write
  318.         sub     al,al           ;clear bit mask accumulator
  319. endif                           ;---------
  320.         add     di,bp           ;move to the next scan line up or down
  321. HAdvanceOneLineLeft:
  322. ife ISVGA                       ;---EGA---
  323.         inc     si              ;advance draw control list pointer
  324. endif                           ;---------
  325.         rol     bh,1            ;move to left; shift mask
  326.         jnc     HDrawLoopLeftBottom ;didn't wrap to next byte
  327.                         ;move to next byte; 1st draw accumulated pixels
  328. if ISVGA                        ;---VGA---
  329.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  330.         sub     ah,ah           ;clear bit mask accumulator
  331. else                            ;---EGA---
  332.         out     dx,al           ;set the desired bit mask
  333.         and     es:[di],al      ;data doesn't matter; force read/write
  334.         sub     al,al           ;clear bit mask accumulator
  335. endif                           ;---------
  336.         dec     di              ;move 1 byte to the left
  337. HDrawLoopLeftBottom:
  338.         loop    HDrawLeftLoop   ;draw next pixel, if any
  339. HDrawDone:
  340.                                 ;draw any remaining accumulated pixels
  341. if ISVGA                        ;---VGA---
  342.         and     es:[di],ah      ;AH becomes bit mask in write mode 3
  343. else                            ;---EGA---
  344.         out     dx,al           ;set the desired bit mask
  345.         and     es:[di],al      ;data doesn't matter; force read/write
  346. endif                           ;---------
  347.         pop     di              ;restore C register variables
  348.         pop     si
  349.         pop     bp
  350.         ret
  351. _DrawHOctant    endp
  352.         end
  353.  
  354.