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

  1. _GRAPHICS PROGRAMMING COLUMN_
  2. by Michael Abrash
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* Program to demonstrate mode X (320x240, 256 colors) patterned
  8.    rectangle fills by filling the screen with adjacent 80x60
  9.    rectangles in a variety of patterns. Tested with Borland C++
  10.    2.0 in C compilation mode and the small model */
  11. #include <conio.h>
  12. #include <dos.h>
  13.  
  14. void Set320x240Mode(void);
  15. void FillPatternX(int, int, int, int, unsigned int, char*);
  16.  
  17. /* 16 4x4 patterns */
  18. static char Patt0[]={10,0,10,0,0,10,0,10,10,0,10,0,0,10,0,10};
  19. static char Patt1[]={9,0,0,0,0,9,0,0,0,0,9,0,0,0,0,9};
  20. static char Patt2[]={5,0,0,0,0,0,5,0,5,0,0,0,0,0,5,0};
  21. static char Patt3[]={14,0,0,14,0,14,14,0,0,14,14,0,14,0,0,14};
  22. static char Patt4[]={15,15,15,1,15,15,1,1,15,1,1,1,1,1,1,1};
  23. static char Patt5[]={12,12,12,12,6,6,6,12,6,6,6,12,6,6,6,12};
  24. static char Patt6[]={80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,15};
  25. static char Patt7[]={78,78,78,78,80,80,80,80,82,82,82,82,84,84,84,84};
  26. static char Patt8[]={78,80,82,84,80,82,84,78,82,84,78,80,84,78,80,82};
  27. static char Patt9[]={78,80,82,84,78,80,82,84,78,80,82,84,78,80,82,84};
  28. static char Patt10[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
  29. static char Patt11[]={0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3};
  30. static char Patt12[]={14,14,9,9,14,9,9,14,9,9,14,14,9,14,14,9};
  31. static char Patt13[]={15,8,8,8,15,15,15,8,15,15,15,8,15,8,8,8};
  32. static char Patt14[]={3,3,3,3,3,7,7,3,3,7,7,3,3,3,3,3};
  33. static char Patt15[]={0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,89};
  34. /* Table of pointers to the 16 4x4 patterns with which to draw */
  35. static char* PattTable[] = {Patt0,Patt1,Patt2,Patt3,Patt4,Patt5,Patt6,
  36.       Patt7,Patt8,Patt9,Patt10,Patt11,Patt12,Patt13,Patt14,Patt15};
  37. void main() {
  38.    int i,j;
  39.    union REGS regset;
  40.  
  41.    Set320x240Mode();
  42.    for (j = 0; j < 4; j++) {
  43.       for (i = 0; i < 4; i++) {
  44.          FillPatternX(i*80,j*60,i*80+80,j*60+60,0,PattTable[j*4+i]);
  45.       }
  46.    }
  47.    getch();
  48.    regset.x.ax = 0x0003;   /* switch back to text mode and done */
  49.    int86(0x10, ®set, ®set);
  50. }
  51.  
  52.  
  53.  
  54.  
  55. [LISTING TWO]
  56.  
  57. ; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.
  58. ; Upper left corner of pattern is always aligned to a multiple-of-4
  59. ; row and column. Works on all VGAs. Uses approach of copying the
  60. ; pattern to off-screen display memory, then loading the latches with
  61. ; the pattern for each scan line and filling each scan line four
  62. ; pixels at a time. Fills up to but not including the column at EndX
  63. ; and the row at EndY. No clipping is performed. All ASM code tested
  64. ; with TASM 2. C near-callable as:
  65. ;    void FillPatternedX(int StartX, int StartY, int EndX, int EndY,
  66. ;       unsigned int PageBase, char* Pattern);
  67.  
  68. SC_INDEX equ    03c4h   ;Sequence Controller Index register port
  69. MAP_MASK equ    02h     ;index in SC of Map Mask register
  70. GC_INDEX equ    03ceh   ;Graphics Controller Index register port
  71. BIT_MASK equ    08h     ;index in GC of Bit Mask register
  72. PATTERN_BUFFER equ 0fffch ;offset in screen memory of the buffer used
  73.                         ; to store each pattern during drawing
  74. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  75. SCREEN_WIDTH equ 80     ;width of screen in addresses from one scan
  76.                         ; line to the next
  77. parms   struc
  78.         dw      2 dup (?) ;pushed BP and return address
  79. StartX  dw      ?       ;X coordinate of upper left corner of rect
  80. StartY  dw      ?       ;Y coordinate of upper left corner of rect
  81. EndX    dw      ?       ;X coordinate of lower right corner of rect
  82.                         ; (the row at EndX is not filled)
  83. EndY    dw      ?       ;Y coordinate of lower right corner of rect
  84.                         ; (the column at EndY is not filled)
  85. PageBase dw     ?       ;base offset in display memory of page in
  86.                         ; which to fill rectangle
  87. Pattern dw      ?       ;4x4 pattern with which to fill rectangle
  88. parms   ends
  89.  
  90. NextScanOffset equ -2   ;local storage for distance from end of one
  91.                         ; scan line to start of next
  92. RectAddrWidth equ -4    ;local storage for address width of rectangle
  93. Height   equ     -6     ;local storage for height of rectangle
  94. STACK_FRAME_SIZE equ 6
  95.  
  96.         .model  small
  97.         .data
  98. ; Plane masks for clipping left and right edges of rectangle.
  99. LeftClipPlaneMask       db      00fh,00eh,00ch,008h
  100. RightClipPlaneMask      db      00fh,001h,003h,007h
  101.         .code
  102.         public  _FillPatternX
  103. _FillPatternX proc    near
  104.         push    bp      ;preserve caller's stack frame
  105.         mov     bp,sp   ;point to local stack frame
  106.         sub     sp,STACK_FRAME_SIZE ;allocate space for local vars
  107.         push    si      ;preserve caller's register variables
  108.         push    di
  109.  
  110.         cld
  111.         mov     ax,SCREEN_SEG   ;point ES to display memory
  112.         mov     es,ax
  113.                                 ;copy pattern to display memory buffer
  114.         mov     si,[bp+Pattern] ;point to pattern to fill with
  115.         mov     di,PATTERN_BUFFER ;point ES:DI to pattern buffer
  116.         mov     dx,SC_INDEX     ;point Sequence Controller Index to
  117.         mov     al,MAP_MASK     ; Map Mask
  118.         out     dx,al
  119.         inc     dx              ;point to SC Data register
  120.         mov     cx,4            ;4 pixel quadruplets in pattern
  121. DownloadPatternLoop:
  122.         mov     al,1            ;
  123.         out     dx,al           ;select plane 0 for writes
  124.         movsb                   ;copy over next plane 0 pattern pixel
  125.         dec     di              ;stay at same address for next plane
  126.         mov     al,2            ;
  127.         out     dx,al           ;select plane 1 for writes
  128.         movsb                   ;copy over next plane 1 pattern pixel
  129.         dec     di              ;stay at same address for next plane
  130.         mov     al,4            ;
  131.         out     dx,al           ;select plane 2 for writes
  132.         movsb                   ;copy over next plane 2 pattern pixel
  133.         dec     di              ;stay at same address for next plane
  134.         mov     al,8            ;
  135.         out     dx,al           ;select plane 3 for writes
  136.         movsb                   ;copy over next plane 3 pattern pixel
  137.                                 ; and advance address
  138.         loop    DownloadPatternLoop
  139.  
  140.         mov     dx,GC_INDEX     ;set the bit mask to select all bits
  141.         mov     ax,00000h+BIT_MASK ; from the latches and none from
  142.         out     dx,ax           ; the CPU, so that we can write the
  143.                                 ; latch contents directly to memory
  144.         mov     ax,[bp+StartY]  ;top rectangle scan line
  145.         mov     si,ax
  146.         and     si,011b         ;top rect scan line modulo 4
  147.         add     si,PATTERN_BUFFER ;point to pattern scan line that
  148.                                 ; maps to top line of rect to draw
  149.         mov     dx,SCREEN_WIDTH
  150.         mul     dx      ;offset in page of top rectangle scan line
  151.         mov     di,[bp+StartX]
  152.         mov     bx,di
  153.         shr     di,1    ;X/4 = offset of first rectangle pixel in scan
  154.         shr     di,1    ; line
  155.         add     di,ax   ;offset of first rectangle pixel in page
  156.         add     di,[bp+PageBase] ;offset of first rectangle pixel in
  157.                         ; display memory
  158.         and     bx,0003h                 ;look up left edge plane mask
  159.         mov     ah,LeftClipPlaneMask[bx] ; to clip
  160.         mov     bx,[bp+EndX]
  161.         and     bx,0003h                  ;look up right edge plane
  162.         mov     al,RightClipPlaneMask[bx] ; mask to clip
  163.         mov     bx,ax                   ;put the masks in BX
  164.         
  165.         mov     cx,[bp+EndX]    ;calculate # of addresses across rect
  166.         mov     ax,[bp+StartX]
  167.         cmp     cx,ax
  168.         jle     FillDone        ;skip if 0 or negative width
  169.         dec     cx
  170.         and     ax,not 011b
  171.         sub     cx,ax
  172.         shr     cx,1
  173.         shr     cx,1    ;# of addresses across rectangle to fill - 1
  174.         jnz     MasksSet ;there's more than one pixel to draw
  175.         and     bh,bl   ;there's only one pixel, so combine the left
  176.                         ; and right edge clip masks
  177. MasksSet:
  178.         mov     ax,[bp+EndY]
  179.         sub     ax,[bp+StartY]  ;AX = height of rectangle
  180.         jle     FillDone        ;skip if 0 or negative height
  181.         mov     [bp+Height],ax
  182.         mov     ax,SCREEN_WIDTH
  183.         sub     ax,cx   ;distance from end of one scan line to start
  184.         dec     ax      ; of next
  185.         mov     [bp+NextScanOffset],ax
  186.         mov     [bp+RectAddrWidth],cx ;remember width in addresses - 1
  187.         mov     dx,SC_INDEX+1 ;point to Sequence Controller Data reg
  188.                                 ; (SC Index still points to Map Mask)
  189. FillRowsLoop:
  190.         mov     cx,[bp+RectAddrWidth] ;width across - 1
  191.         mov     al,es:[si] ;read display memory to latch this scan
  192.                         ; line's pattern
  193.         inc     si      ;point to the next pattern scan line, wrapping
  194.         jnz     short NoWrap ; back to the start of the pattern if
  195.         sub     si,4    ; we've run off the end
  196. NoWrap:
  197.         mov     al,bh   ;put left-edge clip mask in AL
  198.         out     dx,al   ;set the left-edge plane (clip) mask
  199.         stosb           ;draw the left edge (pixels come from latches;
  200.                         ; value written by CPU doesn't matter)
  201.         dec     cx      ;count off left edge address
  202.         js      FillLoopBottom ;that's the only address
  203.         jz      DoRightEdge ;there are only two addresses
  204.         mov     al,00fh ;middle addresses are drawn 4 pixels at a pop
  205.         out     dx,al   ;set the middle pixel mask to no clip
  206.         rep     stosb   ;draw the middle addresses four pixels apiece
  207.                         ; (from latches; value written doesn't matter)
  208. DoRightEdge:
  209.         mov     al,bl   ;put right-edge clip mask in AL
  210.         out     dx,al   ;set the right-edge plane (clip) mask
  211.         stosb           ;draw the right edge (from latches; value
  212.                         ; written doesn't matter)
  213. FillLoopBottom:
  214.         add     di,[bp+NextScanOffset] ;point to the start of the next scan
  215.                                         ; line of the rectangle
  216.         dec     word ptr [bp+Height] ;count down scan lines
  217.         jnz     FillRowsLoop
  218. FillDone:
  219.         mov     dx,GC_INDEX+1 ;restore the bit mask to its default,
  220.         mov     al,0ffh       ; which selects all bits from the CPU
  221.         out     dx,al         ; and none from the latches (the GC
  222.                               ; Index still points to Bit Mask)
  223.         pop     di      ;restore caller's register variables
  224.         pop     si
  225.         mov     sp,bp   ;discard storage for local variables
  226.         pop     bp      ;restore caller's stack frame
  227.         ret
  228. _FillPatternX endp
  229.         end
  230.  
  231.  
  232.  
  233.  
  234. [LISTING THREE]
  235.  
  236. ; Mode X (320x240, 256 colors) display memory to display memory copy
  237. ; routine. Left edge of source rectangle modulo 4 must equal left edge
  238. ; of destination rectangle modulo 4. Works on all VGAs. Uses approach
  239. ; of reading 4 pixels at a time from the source into the latches, then
  240. ; writing the latches to the destination. Copies up to but not
  241. ; including the column at SourceEndX and the row at SourceEndY. No
  242. ; clipping is performed. Results are not guaranteed if the source and
  243. ; destination overlap. C near-callable as:
  244. ;    void CopyScreenToScreenX(int SourceStartX, int SourceStartY,
  245. ;       int SourceEndX, int SourceEndY, int DestStartX,
  246. ;       int DestStartY, unsigned int SourcePageBase,
  247. ;       unsigned int DestPageBase, int SourceBitmapWidth,
  248. ;       int DestBitmapWidth);
  249.  
  250. SC_INDEX equ    03c4h   ;Sequence Controller Index register port
  251. MAP_MASK equ    02h     ;index in SC of Map Mask register
  252. GC_INDEX equ    03ceh   ;Graphics Controller Index register port
  253. BIT_MASK equ    08h     ;index in GC of Bit Mask register
  254. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  255.  
  256. parms   struc
  257.         dw      2 dup (?) ;pushed BP and return address
  258. SourceStartX dw ?       ;X coordinate of upper left corner of source
  259. SourceStartY dw ?       ;Y coordinate of upper left corner of source
  260. SourceEndX   dw ?       ;X coordinate of lower right corner of source
  261.                         ; (the row at SourceEndX is not copied)
  262. SourceEndY   dw ?       ;Y coordinate of lower right corner of source
  263.                         ; (the column at SourceEndY is not copied)
  264. DestStartX   dw ?       ;X coordinate of upper left corner of dest
  265. DestStartY   dw ?       ;Y coordinate of upper left corner of dest
  266. SourcePageBase dw ?     ;base offset in display memory of page in
  267.                         ; which source resides
  268. DestPageBase dw ?       ;base offset in display memory of page in
  269.                         ; which dest resides
  270. SourceBitmapWidth dw ?  ;# of pixels across source bitmap
  271.                         ; (must be a multiple of 4)
  272. DestBitmapWidth   dw ?  ;# of pixels across dest bitmap
  273.                         ; (must be a multiple of 4)
  274. parms   ends
  275.  
  276. SourceNextScanOffset equ -2   ;local storage for distance from end of
  277.                               ; one source scan line to start of next
  278. DestNextScanOffset equ -4    ;local storage for distance from end of
  279.                               ; one dest scan line to start of next
  280. RectAddrWidth equ -6    ;local storage for address width of rectangle
  281. Height   equ     -8     ;local storage for height of rectangle
  282. STACK_FRAME_SIZE equ 8
  283.  
  284.         .model  small
  285.         .data
  286. ; Plane masks for clipping left and right edges of rectangle.
  287. LeftClipPlaneMask       db      00fh,00eh,00ch,008h
  288. RightClipPlaneMask      db      00fh,001h,003h,007h
  289.         .code
  290.         public  _CopyScreenToScreenX
  291. _CopyScreenToScreenX proc    near
  292.         push    bp      ;preserve caller's stack frame
  293.         mov     bp,sp   ;point to local stack frame
  294.         sub     sp,STACK_FRAME_SIZE ;allocate space for local vars
  295.         push    si      ;preserve caller's register variables
  296.         push    di
  297.         push    ds
  298.  
  299.         cld
  300.         mov     dx,GC_INDEX     ;set the bit mask to select all bits
  301.         mov     ax,00000h+BIT_MASK ; from the latches and none from
  302.         out     dx,ax           ; the CPU, so that we can write the
  303.                                 ; latch contents directly to memory
  304.         mov     ax,SCREEN_SEG   ;point ES to display memory
  305.         mov     es,ax
  306.         mov     ax,[bp+DestBitmapWidth]
  307.         shr     ax,1            ;convert to width in addresses
  308.         shr     ax,1
  309.         mul     [bp+DestStartY] ;top dest rect scan line
  310.         mov     di,[bp+DestStartX]
  311.         shr     di,1    ;X/4 = offset of first dest rect pixel in
  312.         shr     di,1    ; scan line
  313.         add     di,ax   ;offset of first dest rect pixel in page
  314.         add     di,[bp+DestPageBase] ;offset of first dest rect pixel
  315.                         ; in display memory
  316.         mov     ax,[bp+SourceBitmapWidth]
  317.         shr     ax,1            ;convert to width in addresses
  318.         shr     ax,1
  319.         mul     [bp+SourceStartY] ;top source rect scan line
  320.         mov     si,[bp+SourceStartX]
  321.         mov     bx,si
  322.         shr     si,1    ;X/4 = offset of first source rect pixel in
  323.         shr     si,1    ; scan line
  324.         add     si,ax   ;offset of first source rect pixel in page
  325.         add     si,[bp+SourcePageBase] ;offset of first source rect
  326.                         ; pixel in display memory
  327.         and     bx,0003h                 ;look up left edge plane mask
  328.         mov     ah,LeftClipPlaneMask[bx] ; to clip
  329.         mov     bx,[bp+SourceEndX]
  330.         and     bx,0003h                  ;look up right edge plane
  331.         mov     al,RightClipPlaneMask[bx] ; mask to clip
  332.         mov     bx,ax                   ;put the masks in BX
  333.         
  334.         mov     cx,[bp+SourceEndX]   ;calculate # of addresses across
  335.         mov     ax,[bp+SourceStartX] ; rect
  336.         cmp     cx,ax
  337.         jle     CopyDone        ;skip if 0 or negative width
  338.         dec     cx
  339.         and     ax,not 011b
  340.         sub     cx,ax
  341.         shr     cx,1
  342.         shr     cx,1    ;# of addresses across rectangle to copy - 1
  343.         jnz     MasksSet ;there's more than one address to draw
  344.         and     bh,bl   ;there's only one address, so combine the left
  345.                         ; and right edge clip masks
  346. MasksSet:
  347.         mov     ax,[bp+SourceEndY]
  348.         sub     ax,[bp+SourceStartY]  ;AX = height of rectangle
  349.         jle     CopyDone        ;skip if 0 or negative height
  350.         mov     [bp+Height],ax
  351.         mov     ax,[bp+DestBitmapWidth]
  352.         shr     ax,1            ;convert to width in addresses
  353.         shr     ax,1
  354.         sub     ax,cx   ;distance from end of one dest scan line to
  355.         dec     ax      ; start of next
  356.         mov     [bp+DestNextScanOffset],ax
  357.         mov     ax,[bp+SourceBitmapWidth]
  358.         shr     ax,1            ;convert to width in addresses
  359.         shr     ax,1
  360.         sub     ax,cx   ;distance from end of one source scan line to
  361.         dec     ax      ; start of next
  362.         mov     [bp+SourceNextScanOffset],ax
  363.         mov     [bp+RectAddrWidth],cx ;remember width in addresses - 1
  364.         mov     dx,SC_INDEX+1 ;point to Sequence Controller Data reg
  365.                                 ; (SC Index still points to Map Mask)
  366.         mov     ax,es   ;DS=ES=screen segment for MOVS
  367.         mov     ds,ax
  368. CopyRowsLoop:
  369.         mov     cx,[bp+RectAddrWidth] ;width across - 1
  370.         mov     al,bh   ;put left-edge clip mask in AL
  371.         out     dx,al   ;set the left-edge plane (clip) mask
  372.         movsb           ;copy the left edge (pixels go through
  373.                         ; latches)
  374.         dec     cx      ;count off left edge address
  375.         js      CopyLoopBottom ;that's the only address
  376.         jz      DoRightEdge ;there are only two addresses
  377.         mov     al,00fh ;middle addresses are drawn 4 pixels at a pop
  378.         out     dx,al   ;set the middle pixel mask to no clip
  379.         rep     movsb   ;draw the middle addresses four pixels apiece
  380.                         ; (pixels copied through latches)
  381. DoRightEdge:
  382.         mov     al,bl   ;put right-edge clip mask in AL
  383.         out     dx,al   ;set the right-edge plane (clip) mask
  384.         movsb           ;draw the right edge (pixels copied through
  385.                         ; latches)
  386. CopyLoopBottom:
  387.         add     si,[bp+SourceNextScanOffset] ;point to the start of
  388.         add     di,[bp+DestNextScanOffset]  ; next source & dest lines
  389.         dec     word ptr [bp+Height] ;count down scan lines
  390.         jnz     CopyRowsLoop
  391. CopyDone:
  392.         mov     dx,GC_INDEX+1 ;restore the bit mask to its default,
  393.         mov     al,0ffh         ; which selects all bits from the CPU
  394.         out     dx,al           ; and none from the latches (the GC
  395.                                 ; Index still points to Bit Mask)
  396.         pop     ds
  397.         pop     di      ;restore caller's register variables
  398.         pop     si
  399.         mov     sp,bp   ;discard storage for local variables
  400.         pop     bp      ;restore caller's stack frame
  401.         ret
  402. _CopyScreenToScreenX endp
  403.         end
  404.  
  405.  
  406.  
  407.  
  408. [LISTING FOUR]
  409.  
  410. ; Mode X (320x240, 256 colors) system memory to display memory copy
  411. ; routine. Uses approach of changing the plane for each pixel copied;
  412. ; this is slower than copying all pixels in one plane, then all pixels
  413. ; in the next plane, and so on, but it is simpler; besides, images for
  414. ; which performance is critical should be stored in off-screen memory
  415. ; and copied to the screen via the latches. Copies up to but not
  416. ; including the column at SourceEndX and the row at SourceEndY. No
  417. ; clipping is performed. C near-callable as:
  418. ;    void CopySystemToScreenX(int SourceStartX, int SourceStartY,
  419. ;       int SourceEndX, int SourceEndY, int DestStartX,
  420. ;       int DestStartY, char* SourcePtr, unsigned int DestPageBase,
  421. ;       int SourceBitmapWidth, int DestBitmapWidth);
  422.  
  423. SC_INDEX equ    03c4h   ;Sequence Controller Index register port
  424. MAP_MASK equ    02h     ;index in SC of Map Mask register
  425. SCREEN_SEG equ  0a000h  ;segment of display memory in mode X
  426.  
  427. parms   struc
  428.         dw      2 dup (?) ;pushed BP and return address
  429. SourceStartX dw ?       ;X coordinate of upper left corner of source
  430. SourceStartY dw ?       ;Y coordinate of upper left corner of source
  431. SourceEndX   dw ?       ;X coordinate of lower right corner of source
  432.                         ; (the row at EndX is not copied)
  433. SourceEndY   dw ?       ;Y coordinate of lower right corner of source
  434.                         ; (the column at EndY is not copied)
  435. DestStartX   dw ?       ;X coordinate of upper left corner of dest
  436. DestStartY   dw ?       ;Y coordinate of upper left corner of dest
  437. SourcePtr    dw ?       ;pointer in DS to start of bitmap in which
  438.                         ; source resides
  439. DestPageBase dw ?       ;base offset in display memory of page in
  440.                         ; which dest resides
  441. SourceBitmapWidth dw ?  ;# of pixels across source bitmap
  442. DestBitmapWidth   dw ?  ;# of pixels across dest bitmap
  443.                         ; (must be a multiple of 4)
  444. parms   ends
  445.  
  446. RectWidth equ   -2      ;local storage for width of rectangle
  447. LeftMask equ    -4      ;local storage for left rect edge plane mask
  448. STACK_FRAME_SIZE equ 4
  449.  
  450.         .model  small
  451.         .code
  452.         public  _CopySystemToScreenX
  453. _CopySystemToScreenX proc    near
  454.         push    bp      ;preserve caller's stack frame
  455.         mov     bp,sp   ;point to local stack frame
  456.         sub     sp,STACK_FRAME_SIZE ;allocate space for local vars
  457.         push    si      ;preserve caller's register variables
  458.         push    di
  459.  
  460.         cld
  461.         mov     ax,SCREEN_SEG   ;point ES to display memory
  462.         mov     es,ax
  463.         mov     ax,[bp+SourceBitmapWidth]
  464.         mul     [bp+SourceStartY] ;top source rect scan line
  465.         add     ax,[bp+SourceStartX]
  466.         add     ax,[bp+SourcePtr] ;offset of first source rect pixel
  467.         mov     si,ax             ; in DS
  468.         
  469.         mov     ax,[bp+DestBitmapWidth]
  470.         shr     ax,1            ;convert to width in addresses
  471.         shr     ax,1
  472.         mov     [bp+DestBitmapWidth],ax ;remember address width
  473.         mul     [bp+DestStartY] ;top dest rect scan line
  474.         mov     di,[bp+DestStartX]
  475.         mov     cx,di
  476.         shr     di,1    ;X/4 = offset of first dest rect pixel in
  477.         shr     di,1    ; scan line
  478.         add     di,ax   ;offset of first dest rect pixel in page
  479.         add     di,[bp+DestPageBase] ;offset of first dest rect pixel
  480.                         ; in display memory
  481.         and     cl,011b ;CL = first dest pixel's plane
  482.         mov     al,11h  ;upper nibble comes into play when plane wraps
  483.                         ; from 3 back to 0
  484.         shl     al,cl   ;set the bit for the first dest pixel's plane
  485.         mov     [bp+LeftMask],al ; in each nibble to 1
  486.  
  487.         mov     cx,[bp+SourceEndX]   ;calculate # of pixels across
  488.         sub     cx,[bp+SourceStartX] ; rect
  489.         jle     CopyDone        ;skip if 0 or negative width
  490.         mov     [bp+RectWidth],cx
  491.         mov     bx,[bp+SourceEndY]
  492.         sub     bx,[bp+SourceStartY]  ;BX = height of rectangle
  493.         jle     CopyDone        ;skip if 0 or negative height
  494.         mov     dx,SC_INDEX     ;point to SC Index register
  495.         mov     al,MAP_MASK
  496.         out     dx,al           ;point SC Index reg to the Map Mask
  497.         inc     dx              ;point DX to SC Data reg
  498. CopyRowsLoop:
  499.         mov     ax,[bp+LeftMask]
  500.         mov     cx,[bp+RectWidth]
  501.         push    si      ;remember the start offset in the source
  502.         push    di      ;remember the start offset in the dest
  503. CopyScanLineLoop:
  504.         out     dx,al           ;set the plane for this pixel
  505.         movsb                   ;copy the pixel to the screen
  506.         rol     al,1            ;set mask for next pixel's plane
  507.         cmc                     ;advance destination address only when
  508.         sbb     di,0            ; wrapping from plane 3 to plane 0
  509.                                 ; (else undo INC DI done by MOVSB)
  510.         loop    CopyScanLineLoop
  511.         pop     di      ;retrieve the dest start offset
  512.         add     di,[bp+DestBitmapWidth] ;point to the start of the
  513.                                         ; next scan line of the dest
  514.         pop     si      ;retrieve the source start offset
  515.         add     si,[bp+SourceBitmapWidth] ;point to the start of the
  516.                                         ; next scan line of the source
  517.         dec     bx      ;count down scan lines
  518.         jnz     CopyRowsLoop
  519. CopyDone:
  520.         pop     di      ;restore caller's register variables
  521.         pop     si
  522.         mov     sp,bp   ;discard storage for local variables
  523.         pop     bp      ;restore caller's stack frame
  524.         ret
  525. _CopySystemToScreenX endp
  526.         end
  527.