home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 07 / graph_pr.asc < prev    next >
Text File  |  1991-06-11  |  23KB  |  580 lines

  1. _GRAPHICS PROGRAMMING COLUMN_
  2. by Michael Abrash
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. ; Mode X (320x240, 256 colors) mode set routine. Works on all VGAs.
  8. ; C near-callable as:
  9. ;       void Set320x240Mode(void);
  10. ; Tested with TASM 2.0.
  11. ; Modified from public-domain mode set code by John Bridges.
  12.  
  13. SC_INDEX equ    03c4h   ;Sequence Controller Index
  14. CRTC_INDEX equ  03d4h   ;CRT Controller Index
  15. MISC_OUTPUT equ 03c2h   ;Miscellaneous Output register
  16. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  17.  
  18.         .model  small
  19.         .data
  20. ; Index/data pairs for CRT Controller registers that differ between
  21. ; mode 13h and mode X.
  22. CRTParms label  word
  23.         dw      00d06h  ;vertical total
  24.         dw      03e07h  ;overflow (bit 8 of vertical counts)
  25.         dw      04109h  ;cell height (2 to double-scan)
  26.         dw      0ea10h  ;v sync start
  27.         dw      0ac11h  ;v sync end and protect cr0-cr7
  28.         dw      0df12h  ;vertical displayed
  29.         dw      00014h  ;turn off dword mode
  30.         dw      0e715h  ;v blank start
  31.         dw      00616h  ;v blank end
  32.         dw      0e317h  ;turn on byte mode
  33. CRT_PARM_LENGTH equ     (($-CRTParms)/2)
  34.  
  35.         .code
  36.         public  _Set320x240Mode
  37. _Set320x240Mode proc    near
  38.         push    bp      ;preserve caller's stack frame
  39.         push    si      ;preserve C register vars
  40.         push    di      ; (don't count on BIOS preserving anything)
  41.  
  42.         mov     ax,13h  ;let the BIOS set standard 256-color
  43.         int     10h     ; mode (320x200 linear)
  44.  
  45.         mov     dx,SC_INDEX
  46.         mov     ax,0604h
  47.         out     dx,ax   ;disable chain4 mode
  48.         mov     ax,0100h
  49.         out     dx,ax   ;synchronous reset while switching clocks
  50.  
  51.         mov     dx,MISC_OUTPUT
  52.         mov     al,0e7h
  53.         out     dx,al   ;select 28 MHz dot clock & 60 Hz scanning rate
  54.  
  55.         mov     dx,SC_INDEX
  56.         mov     ax,0300h
  57.         out     dx,ax   ;undo reset (restart sequencer)
  58.  
  59.         mov     dx,CRTC_INDEX ;reprogram the CRT Controller
  60.         mov     al,11h  ;VSync End reg contains register write
  61.         out     dx,al   ; protect bit
  62.         inc     dx      ;CRT Controller Data register
  63.         in      al,dx   ;get current VSync End register setting
  64.         and     al,7fh  ;remove write protect on various
  65.         out     dx,al   ; CRTC registers
  66.         dec     dx      ;CRT Controller Index
  67.         cld
  68.         mov     si,offset CRTParms ;point to CRT parameter table
  69.         mov     cx,CRT_PARM_LENGTH ;# of table entries
  70. SetCRTParmsLoop:
  71.         lodsw           ;get the next CRT Index/Data pair
  72.         out     dx,ax   ;set the next CRT Index/Data pair
  73.         loop    SetCRTParmsLoop
  74.  
  75.         mov     dx,SC_INDEX
  76.         mov     ax,0f02h
  77.         out     dx,ax   ;enable writes to all four planes
  78.         mov     ax,SCREEN_SEG ;now clear all display memory, 8 pixels
  79.         mov     es,ax         ; at a time
  80.         sub     di,di   ;point ES:DI to display memory
  81.         sub     ax,ax   ;clear to zero-value pixels
  82.         mov     cx,8000h ;# of words in display memory
  83.         rep     stosw   ;clear all of display memory
  84.  
  85.         pop     di      ;restore C register vars
  86.         pop     si
  87.         pop     bp      ;restore caller's stack frame
  88.         ret
  89. _Set320x240Mode endp
  90.         end
  91.  
  92.  
  93.  
  94. [LISTING TWO]
  95.  
  96. ; Mode X (320x240, 256 colors) write pixel routine. Works on all VGAs.
  97. ; No clipping is performed.
  98. ; C near-callable as:
  99. ;    void WritePixelX(int X, int Y, unsigned int PageBase, int Color);
  100.  
  101. SC_INDEX equ    03c4h   ;Sequence Controller Index
  102. MAP_MASK equ    02h     ;index in SC of Map Mask register
  103. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  104. SCREEN_WIDTH equ 80     ;width of screen in bytes from one scan line
  105.                         ; to the next
  106.  
  107. parms   struc
  108.         dw      2 dup (?) ;pushed BP and return address
  109. X       dw      ?       ;X coordinate of pixel to draw
  110. Y       dw      ?       ;Y coordinate of pixel to draw
  111. PageBase dw     ?       ;base offset in display memory of page in
  112.                         ; which to draw pixel
  113. Color   dw      ?       ;color in which to draw pixel
  114. parms   ends
  115.  
  116.         .model  small
  117.         .code
  118.         public  _WritePixelX
  119. _WritePixelX    proc    near
  120.         push    bp      ;preserve caller's stack frame
  121.         mov     bp,sp   ;point to local stack frame
  122.  
  123.         mov     ax,SCREEN_WIDTH
  124.         mul     [bp+Y]  ;offset of pixel's scan line in page
  125.         mov     bx,[bp+X]
  126.         shr     bx,1
  127.         shr     bx,1    ;X/4 = offset of pixel in scan line
  128.         add     bx,ax   ;offset of pixel in page
  129.         add     bx,[bp+PageBase] ;offset of pixel in display memory
  130.         mov     ax,SCREEN_SEG
  131.         mov     es,ax   ;point ES:BX to the pixel's address
  132.  
  133.         mov     cl,byte ptr [bp+X]
  134.         and     cl,011b ;CL = pixel's plane
  135.         mov     ax,0100h + MAP_MASK ;AL = index in SC of Map Mask reg
  136.         shl     ah,cl   ;set only the bit for the pixel's plane to 1
  137.         mov     dx,SC_INDEX ;set the Map Mask to enable only the
  138.         out     dx,ax       ; pixel's plane
  139.  
  140.         mov     al,byte ptr [bp+Color]
  141.         mov     es:[bx],al ;draw the pixel in the desired color
  142.  
  143.         pop     bp      ;restore caller's stack frame
  144.         ret
  145. _WritePixelX    endp
  146.         end
  147.  
  148.  
  149.  
  150.  
  151. [LISTING THREE]
  152.  
  153. ; Mode X (320x240, 256 colors) read pixel routine. Works on all VGAs.
  154. ; No clipping is performed.
  155. ; C near-callable as:
  156. ;    unsigned int ReadPixelX(int X, int Y, unsigned int PageBase);
  157.  
  158. GC_INDEX equ    03ceh   ;Graphics Controller Index
  159. READ_MAP equ    04h     ;index in GC of the Read Map register
  160. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  161. SCREEN_WIDTH equ 80     ;width of screen in bytes from one scan line
  162.                         ; to the next
  163. parms   struc
  164.         dw      2 dup (?) ;pushed BP and return address
  165. X       dw      ?       ;X coordinate of pixel to read
  166. Y       dw      ?       ;Y coordinate of pixel to read
  167. PageBase dw     ?       ;base offset in display memory of page from
  168.                         ; which to read pixel
  169. parms   ends
  170.  
  171.         .model  small
  172.         .code
  173.         public  _ReadPixelX
  174. _ReadPixelX     proc    near
  175.         push    bp      ;preserve caller's stack frame
  176.         mov     bp,sp   ;point to local stack frame
  177.  
  178.         mov     ax,SCREEN_WIDTH
  179.         mul     [bp+Y]  ;offset of pixel's scan line in page
  180.         mov     bx,[bp+X]
  181.         shr     bx,1
  182.         shr     bx,1    ;X/4 = offset of pixel in scan line
  183.         add     bx,ax   ;offset of pixel in page
  184.         add     bx,[bp+PageBase] ;offset of pixel in display memory
  185.         mov     ax,SCREEN_SEG
  186.         mov     es,ax   ;point ES:BX to the pixel's address
  187.  
  188.         mov     ah,byte ptr [bp+X]
  189.         and     ah,011b ;AH = pixel's plane
  190.         mov     al,READ_MAP ;AL = index in GC of the Read Map reg
  191.         mov     dx,GC_INDEX ;set the Read Map to read the pixel's
  192.         out     dx,ax       ; plane
  193.  
  194.         mov     al,es:[bx] ;read the pixel's color
  195.         sub     ah,ah   ;convert it to an unsigned int
  196.  
  197.         pop     bp      ;restore caller's stack frame
  198.         ret
  199. _ReadPixelX     endp
  200.         end
  201.  
  202.  
  203.  
  204. [LISTING FOUR]
  205.  
  206. ; Mode X (320x240, 256 colors) rectangle fill routine. Works on all
  207. ; VGAs. Uses slow approach that selects the plane explicitly for each
  208. ; pixel. Fills up to but not including the column at EndX and the row
  209. ; at EndY. No clipping is performed.
  210. ; C near-callable as:
  211. ;    void FillRectangleX(int StartX, int StartY, int EndX, int EndY,
  212. ;       unsigned int PageBase, int Color);
  213.  
  214. SC_INDEX equ    03c4h   ;Sequence Controller Index
  215. MAP_MASK equ    02h     ;index in SC of Map Mask register
  216. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  217. SCREEN_WIDTH equ 80     ;width of screen in bytes from one scan line
  218.                         ; to the next
  219. parms   struc
  220.         dw      2 dup (?) ;pushed BP and return address
  221. StartX  dw      ?       ;X coordinate of upper left corner of rect
  222. StartY  dw      ?       ;Y coordinate of upper left corner of rect
  223. EndX    dw      ?       ;X coordinate of lower right corner of rect
  224.                         ; (the row at EndX is not filled)
  225. EndY    dw      ?       ;Y coordinate of lower right corner of rect
  226.                         ; (the column at EndY is not filled)
  227. PageBase dw     ?       ;base offset in display memory of page in
  228.                         ; which to fill rectangle
  229. Color   dw      ?       ;color in which to draw pixel
  230. parms   ends
  231.  
  232.         .model  small
  233.         .code
  234.         public  _FillRectangleX
  235. _FillRectangleX proc    near
  236.         push    bp      ;preserve caller's stack frame
  237.         mov     bp,sp   ;point to local stack frame
  238.         push    si      ;preserve caller's register variables
  239.         push    di
  240.  
  241.         mov     ax,SCREEN_WIDTH
  242.         mul     [bp+StartY] ;offset in page of top rectangle scan line
  243.         mov     di,[bp+StartX]
  244.         shr     di,1
  245.         shr     di,1    ;X/4 = offset of first rectangle pixel in scan
  246.                         ; line
  247.         add     di,ax   ;offset of first rectangle pixel in page
  248.         add     di,[bp+PageBase] ;offset of first rectangle pixel in
  249.                         ; display memory
  250.         mov     ax,SCREEN_SEG
  251.         mov     es,ax   ;point ES:DI to the first rectangle pixel's
  252.                         ; address
  253.         mov     dx,SC_INDEX ;set the Sequence Controller Index to
  254.         mov     al,MAP_MASK ; point to the Map Mask register
  255.         out     dx,al
  256.         inc     dx      ;point DX to the SC Data register
  257.         mov     cl,byte ptr [bp+StartX]
  258.         and     cl,011b ;CL = first rectangle pixel's plane
  259.         mov     al,01h
  260.         shl     al,cl   ;set only the bit for the pixel's plane to 1
  261.         mov     ah,byte ptr [bp+Color] ;color with which to fill
  262.         mov     bx,[bp+EndY]
  263.         sub     bx,[bp+StartY]  ;BX = height of rectangle
  264.         jle     FillDone        ;skip if 0 or negative height
  265.         mov     si,[bp+EndX]
  266.         sub     si,[bp+StartX]  ;CX = width of rectangle
  267.         jle     FillDone        ;skip if 0 or negative width
  268. FillRowsLoop:
  269.         push    ax      ;remember the plane mask for the left edge
  270.         push    di      ;remember the start offset of the scan line
  271.         mov     cx,si   ;set count of pixels in this scan line
  272. FillScanLineLoop:
  273.         out     dx,al   ;set the plane for this pixel
  274.         mov     es:[di],ah ;draw the pixel
  275.         shl     al,1    ;adjust the plane mask for the next pixel's
  276.         and     al,01111b ; bit, modulo 4
  277.         jnz     AddressSet ;advance address if we turned over from
  278.         inc     di      ; plane 3 to plane 0
  279.         mov     al,00001b ;set plane mask bit for plane 0
  280. AddressSet:
  281.         loop    FillScanLineLoop
  282.         pop     di      ;retrieve the start offset of the scan line
  283.         add     di,SCREEN_WIDTH ;point to the start of the next scan
  284.                         ; line of the rectangle
  285.         pop     ax      ;retrieve the plane mask for the left edge
  286.         dec     bx      ;count down scan lines
  287.         jnz     FillRowsLoop
  288. FillDone:
  289.         pop     di      ;restore caller's register variables
  290.         pop     si
  291.         pop     bp      ;restore caller's stack frame
  292.         ret
  293. _FillRectangleX endp
  294.         end
  295.  
  296.  
  297.  
  298.  
  299. [LISTING FIVE]
  300.  
  301. ; Mode X (320x240, 256 colors) rectangle fill routine. Works on all
  302. ; VGAs. Uses medium-speed approach that selects each plane only once
  303. ; per rectangle; this results in a fade-in effect for large
  304. ; rectangles. Fills up to but not including the column at EndX and the
  305. ; row at EndY. No clipping is performed.
  306. ; C near-callable as:
  307. ;    void FillRectangleX(int StartX, int StartY, int EndX, int EndY,
  308. ;       unsigned int PageBase, int Color);
  309.  
  310. SC_INDEX equ    03c4h   ;Sequence Controller Index
  311. MAP_MASK equ    02h     ;index in SC of Map Mask register
  312. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  313. SCREEN_WIDTH equ 80     ;width of screen in bytes from one scan line
  314.                         ; to the next
  315. parms struc
  316.         dw      2 dup (?) ;pushed BP and return address
  317. StartX  dw      ?       ;X coordinate of upper left corner of rect
  318. StartY  dw      ?       ;Y coordinate of upper left corner of rect
  319. EndX    dw      ?       ;X coordinate of lower right corner of rect
  320.                         ; (the row at EndX is not filled)
  321. EndY    dw      ?       ;Y coordinate of lower right corner of rect
  322.                         ; (the column at EndY is not filled)
  323. PageBase dw     ?       ;base offset in display memory of page in
  324.                         ; which to fill rectangle
  325. Color   dw      ?       ;color in which to draw pixel
  326. parms ends
  327.  
  328. StartOffset equ  -2     ;local storage for start offset of rectangle
  329. Width    equ     -4     ;local storage for address width of rectangle
  330. Height   equ     -6     ;local storage for height of rectangle
  331. PlaneInfo equ    -8     ;local storage for plane # and plane mask
  332. STACK_FRAME_SIZE equ 8
  333.  
  334.         .model  small
  335.         .code
  336.         public  _FillRectangleX
  337. _FillRectangleX proc    near
  338.         push    bp      ;preserve caller's stack frame
  339.         mov     bp,sp   ;point to local stack frame
  340.         sub     sp,STACK_FRAME_SIZE ;allocate space for local vars
  341.         push    si      ;preserve caller's register variables
  342.         push    di
  343.  
  344.         cld
  345.         mov     ax,SCREEN_WIDTH
  346.         mul     [bp+StartY] ;offset in page of top rectangle scan line
  347.         mov     di,[bp+StartX]
  348.         shr     di,1
  349.         shr     di,1    ;X/4 = offset of first rectangle pixel in scan
  350.                         ; line
  351.         add     di,ax   ;offset of first rectangle pixel in page
  352.         add     di,[bp+PageBase] ;offset of first rectangle pixel in
  353.                         ; display memory
  354.         mov     ax,SCREEN_SEG
  355.         mov     es,ax   ;point ES:DI to the first rectangle pixel's
  356.         mov     [bp+StartOffset],di ; address
  357.         mov     dx,SC_INDEX ;set the Sequence Controller Index to
  358.         mov     al,MAP_MASK ; point to the Map Mask register
  359.         out     dx,al
  360.         mov     bx,[bp+EndY]
  361.         sub     bx,[bp+StartY]  ;BX = height of rectangle
  362.         jle     FillDone        ;skip if 0 or negative height
  363.         mov     [bp+Height],bx
  364.         mov     dx,[bp+EndX]
  365.         mov     cx,[bp+StartX]
  366.         cmp     dx,cx
  367.         jle     FillDone        ;skip if 0 or negative width
  368.         dec     dx
  369.         and     cx,not 011b
  370.         sub     dx,cx
  371.         shr     dx,1
  372.         shr     dx,1
  373.         inc     dx      ;# of addresses across rectangle to fill
  374.         mov     [bp+Width],dx
  375.         mov     word ptr [bp+PlaneInfo],0001h
  376.                            ;lower byte = plane mask for plane 0,
  377.                            ; upper byte = plane # for plane 0
  378. FillPlanesLoop:
  379.         mov     ax,word ptr [bp+PlaneInfo]
  380.         mov     dx,SC_INDEX+1 ;point DX to the SC Data register
  381.         out     dx,al   ;set the plane for this pixel
  382.         mov     di,[bp+StartOffset] ;point ES:DI to rectangle start
  383.         mov     dx,[bp+Width]
  384.         mov     cl,byte ptr [bp+StartX]
  385.         and     cl,011b ;plane # of first pixel in initial byte
  386.         cmp     ah,cl   ;do we draw this plane in the initial byte?
  387.         jae     InitAddrSet ;yes
  388.         dec     dx      ;no, so skip the initial byte
  389.         jz      FillLoopBottom ;skip this plane if no pixels in it
  390.         inc     di
  391. InitAddrSet:
  392.         mov     cl,byte ptr [bp+EndX]
  393.         dec     cl
  394.         and     cl,011b ;plane # of last pixel in final byte
  395.         cmp     ah,cl   ;do we draw this plane in the final byte?
  396.         jbe     WidthSet ;yes
  397.         dec     dx      ;no, so skip the final byte
  398.         jz      FillLoopBottom ;skip this planes if no pixels in it
  399. WidthSet:
  400.         mov     si,SCREEN_WIDTH
  401.         sub     si,dx   ;distance from end of one scan line to start
  402.                         ; of next
  403.         mov     bx,[bp+Height] ;# of lines to fill
  404.         mov     al,byte ptr [bp+Color] ;color with which to fill
  405. FillRowsLoop:
  406.         mov     cx,dx   ;# of bytes across scan line
  407.         rep     stosb   ;fill the scan line in this plane
  408.         add     di,si   ;point to the start of the next scan
  409.                         ; line of the rectangle
  410.         dec     bx      ;count down scan lines
  411.         jnz     FillRowsLoop
  412. FillLoopBottom:
  413.         mov     ax,word ptr [bp+PlaneInfo]
  414.         shl     al,1    ;set the plane bit to the next plane
  415.         inc     ah      ;increment the plane #
  416.         mov     word ptr [bp+PlaneInfo],ax
  417.         cmp     ah,4    ;have we done all planes?
  418.         jnz     FillPlanesLoop ;continue if any more planes
  419. FillDone:
  420.         pop     di      ;restore caller's register variables
  421.         pop     si
  422.         mov     sp,bp   ;discard storage for local variables
  423.         pop     bp      ;restore caller's stack frame
  424.         ret
  425. _FillRectangleX endp
  426.         end
  427.  
  428.  
  429.  
  430.  
  431.  
  432. [LISTING SIX]
  433.  
  434. ; Mode X (320x240, 256 colors) rectangle fill routine. Works on all
  435. ; VGAs. Uses fast approach that fans data out to up to four planes at
  436. ; once to draw up to four pixels at once. Fills up to but not
  437. ; including the column at EndX and the row at EndY. No clipping is
  438. ; performed.
  439. ; C near-callable as:
  440. ;    void FillRectangleX(int StartX, int StartY, int EndX, int EndY,
  441. ;       unsigned int PageBase, int Color);
  442.  
  443. SC_INDEX equ    03c4h   ;Sequence Controller Index
  444. MAP_MASK equ    02h     ;index in SC of Map Mask register
  445. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  446. SCREEN_WIDTH equ 80     ;width of screen in bytes from one scan line
  447.                         ; to the next
  448. parms   struc
  449.         dw      2 dup (?) ;pushed BP and return address
  450. StartX  dw      ?       ;X coordinate of upper left corner of rect
  451. StartY  dw      ?       ;Y coordinate of upper left corner of rect
  452. EndX    dw      ?       ;X coordinate of lower right corner of rect
  453.                         ; (the row at EndX is not filled)
  454. EndY    dw      ?       ;Y coordinate of lower right corner of rect
  455.                         ; (the column at EndY is not filled)
  456. PageBase dw     ?       ;base offset in display memory of page in
  457.                         ; which to fill rectangle
  458. Color   dw      ?       ;color in which to draw pixel
  459. parms   ends
  460.  
  461.         .model  small
  462.         .data
  463. ; Plane masks for clipping left and right edges of rectangle.
  464. LeftClipPlaneMask       db      00fh,00eh,00ch,008h
  465. RightClipPlaneMask      db      00fh,001h,003h,007h
  466.         .code
  467.         public  _FillRectangleX
  468. _FillRectangleX proc    near
  469.         push    bp      ;preserve caller's stack frame
  470.         mov     bp,sp   ;point to local stack frame
  471.         push    si      ;preserve caller's register variables
  472.         push    di
  473.  
  474.         cld
  475.         mov     ax,SCREEN_WIDTH
  476.         mul     [bp+StartY] ;offset in page of top rectangle scan line
  477.         mov     di,[bp+StartX]
  478.         shr     di,1    ;X/4 = offset of first rectangle pixel in scan
  479.         shr     di,1    ; line
  480.         add     di,ax   ;offset of first rectangle pixel in page
  481.         add     di,[bp+PageBase] ;offset of first rectangle pixel in
  482.                         ; display memory
  483.         mov     ax,SCREEN_SEG   ;point ES:DI to the first rectangle
  484.         mov     es,ax           ; pixel's address
  485.         mov     dx,SC_INDEX ;set the Sequence Controller Index to
  486.         mov     al,MAP_MASK ; point to the Map Mask register
  487.         out     dx,al
  488.         inc     dx      ;point DX to the SC Data register
  489.         mov     si,[bp+StartX]
  490.         and     si,0003h                 ;look up left edge plane mask
  491.         mov     bh,LeftClipPlaneMask[si] ; to clip & put in BH
  492.         mov     si,[bp+EndX]
  493.         and     si,0003h                  ;look up right edge plane
  494.         mov     bl,RightClipPlaneMask[si] ; mask to clip & put in BL
  495.         
  496.         mov     cx,[bp+EndX]    ;calculate # of addresses across rect
  497.         mov     si,[bp+StartX]
  498.         cmp     cx,si
  499.         jle     FillDone        ;skip if 0 or negative width
  500.         dec     cx
  501.         and     si,not 011b
  502.         sub     cx,si
  503.         shr     cx,1
  504.         shr     cx,1    ;# of addresses across rectangle to fill - 1
  505.         jnz     MasksSet ;there's more than one byte to draw
  506.         and     bh,bl   ;there's only one byte, so combine the left
  507.                         ; and right edge clip masks
  508. MasksSet:
  509.         mov     si,[bp+EndY]
  510.         sub     si,[bp+StartY]  ;BX = height of rectangle
  511.         jle     FillDone        ;skip if 0 or negative height
  512.         mov     ah,byte ptr [bp+Color] ;color with which to fill
  513.         mov     bp,SCREEN_WIDTH ;stack frame isn't needed any more
  514.         sub     bp,cx   ;distance from end of one scan line to start
  515.         dec     bp      ; of next
  516. FillRowsLoop:
  517.         push    cx      ;remember width in addresses - 1
  518.         mov     al,bh   ;put left-edge clip mask in AL
  519.         out     dx,al   ;set the left-edge plane (clip) mask
  520.         mov     al,ah   ;put color in AL
  521.         stosb           ;draw the left edge
  522.         dec     cx      ;count off left edge byte
  523.         js      FillLoopBottom ;that's the only byte
  524.         jz      DoRightEdge ;there are only two bytes
  525.         mov     al,00fh ;middle addresses are drawn 4 pixels at a pop
  526.         out     dx,al   ;set the middle pixel mask to no clip
  527.         mov     al,ah   ;put color in AL
  528.         rep     stosb   ;draw the middle addresses four pixels apiece
  529. DoRightEdge:
  530.         mov     al,bl   ;put right-edge clip mask in AL
  531.         out     dx,al   ;set the right-edge plane (clip) mask
  532.         mov     al,ah   ;put color in AL
  533.         stosb           ;draw the right edge
  534. FillLoopBottom:
  535.         add     di,bp   ;point to the start of the next scan line of
  536.                         ; the rectangle
  537.         pop     cx      ;retrieve width in addresses - 1
  538.         dec     si      ;count down scan lines
  539.         jnz     FillRowsLoop
  540. FillDone:
  541.         pop     di      ;restore caller's register variables
  542.         pop     si
  543.         pop     bp      ;restore caller's stack frame
  544.         ret
  545. _FillRectangleX endp
  546.         end
  547.  
  548.  
  549.  
  550.  
  551. [LISTING SEVEN]
  552.  
  553. /* Program to demonstrate mode X (320x240, 256-colors) rectangle
  554.    fill by drawing adjacent 20x20 rectangles in successive colors from
  555.    0 on up across and down the screen */
  556. #include <conio.h>
  557. #include <dos.h>
  558.  
  559. void Set320x240Mode(void);
  560. void FillRectangleX(int, int, int, int, unsigned int, int);
  561.  
  562. void main() {
  563.    int i,j;
  564.    union REGS regset;
  565.  
  566.    Set320x240Mode();
  567.    FillRectangleX(0,0,320,240,0,0); /* clear the screen to black */
  568.    for (j = 1; j < 220; j += 21) {
  569.       for (i = 1; i < 300; i += 21) {
  570.          FillRectangleX(i, j, i+20, j+20, 0, ((j/21*15)+i/21) & 0xFF);
  571.       }
  572.    }
  573.    getch();
  574.    regset.x.ax = 0x0003;   /* switch back to text mode and done */
  575.    int86(0x10, ®set, ®set);
  576. }
  577.  
  578.  
  579.  
  580.