]> 4ch.mooo.com Git - 16.git/blobdiff - 16/xlib/xrect.asm
added xlib to the project and i gotta convert the damn makefile -.-
[16.git] / 16 / xlib / xrect.asm
diff --git a/16/xlib/xrect.asm b/16/xlib/xrect.asm
new file mode 100755 (executable)
index 0000000..9b00356
--- /dev/null
@@ -0,0 +1,684 @@
+;-----------------------------------------------------------------------\r
+; MODULE XRECT\r
+;\r
+; Rectangle functions all MODE X 256 Color resolutions\r
+;\r
+; Compile with Tasm.\r
+; C callable.\r
+;\r
+;\r
+; ****** XLIB - Mode X graphics library                ****************\r
+; ******                                               ****************\r
+; ****** Written By Themie Gouthas                     ****************\r
+;\r
+; egg@dstos3.dsto.gov.au\r
+; teg@bart.dsto.gov.au\r
+;-----------------------------------------------------------------------\r
+\r
+\r
+include xlib.inc\r
+include xrect.inc\r
+\r
+\r
+       .data\r
+; Plane masks for clipping left and right edges of rectangle.\r
+        LeftClipPlaneMask       db      00fh,00eh,00ch,008h\r
+       RightClipPlaneMask      db      00fh,001h,003h,007h\r
+       .code\r
+\r
+;---------------------------------------------------------------------------\r
+; Mode X (320x240, 256 colors) rectangle solid colour fill routine.\r
+;\r
+; Based on code originally published in DDJ Mag by M. Abrash\r
+;\r
+; with TASM 2. C near-callable as:\r
+;\r
+;    void x_rect_fill_clipped(int StartX, int StartY, int EndX, int EndY,\r
+;       unsigned int PageBase, unsigne int color);\r
+;\r
+;\r
+\r
+\r
+_x_rect_fill_clipped proc\r
+ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word\r
+       push bp              ;preserve caller's stack frame\r
+       mov  bp,sp           ;point to local stack frame\r
+       push si              ;preserve caller's register variables\r
+       push di\r
+\r
+       mov   dx,[_TopClip]           ; Compare u.l. Y coord with Top\r
+       mov   cx,[_BottomClip]\r
+       mov   ax,[StartY]\r
+       mov   bx,[EndY]\r
+        cmp   dx,ax\r
+        jle   @@CheckBottomClip\r
+       cmp   dx,bx\r
+       jg    @@NotVisible\r
+       mov   [StartY],dx\r
+\r
+@@CheckBottomClip:\r
+       cmp   cx,bx\r
+       jg    @@CheckLeftClip\r
+       cmp   cx,ax\r
+       jl    @@NotVisible\r
+       mov   [EndY],cx\r
+\r
+@@CheckLeftClip:\r
+       mov   dx,[_LeftClip]           ; Compare u.l. Y coord with Top\r
+       mov   cx,[_RightClip]\r
+       mov   ax,[StartX]\r
+       mov   bx,[EndX]\r
+       sal   dx,2\r
+       sal   cx,2\r
+       cmp   dx,ax\r
+       jle   @@CheckRightClip\r
+       cmp   dx,bx\r
+       jg    @@NotVisible\r
+       mov   [StartX],dx\r
+\r
+@@CheckRightClip:\r
+       cmp   cx,bx\r
+       jg    RFClipDone\r
+       cmp   cx,ax\r
+       jl    @@NotVisible\r
+       mov   [EndX],cx\r
+       jmp   RFClipDone\r
+\r
+@@NotVisible:\r
+       mov   ax,1\r
+       pop   di                          ; restore registers\r
+       pop   si\r
+       pop   bp\r
+       ret\r
+_x_rect_fill_clipped endp\r
+\r
+\r
+\r
+;---------------------------------------------------------------------------\r
+; Mode X (320x240, 256 colors) rectangle solid colour fill routine.\r
+;\r
+; Based on code originally published in DDJ Mag by M. Abrash\r
+;\r
+; with TASM 2. C near-callable as:\r
+;\r
+;    void x_rect_fill(int StartX, int StartY, int EndX, int EndY,\r
+;       unsigned int PageBase, unsigne int color);\r
+;\r
+;\r
+\r
+\r
+_x_rect_fill proc\r
+ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word\r
+       push bp              ;preserve caller's stack frame\r
+       mov  bp,sp           ;point to local stack frame\r
+       push si              ;preserve caller's register variables\r
+       push di\r
+\r
+RFClipDone:\r
+       cld\r
+       mov  ax,[_ScrnLogicalByteWidth]\r
+       mul  [StartY]            ;offset in page of top rectangle scan line\r
+       mov  di,[StartX]\r
+       sar  di,2                ;X/4 = offset of first rectangle pixel in scan\r
+       add  di,ax               ;offset of first rectangle pixel in page\r
+       add  di,[PageBase]       ;offset of first rectangle pixel in\r
+                                ; display memory\r
+       mov  ax,SCREEN_SEG       ;point ES:DI to the first rectangle\r
+       mov  es,ax               ; pixel's address\r
+       mov  dx,SC_INDEX         ;set the Sequence Controller Index to\r
+       mov  al,MAP_MASK         ; point to the Map Mask register\r
+       out  dx,al\r
+       inc  dx                  ;point DX to the SC Data register\r
+       mov  si,[StartX]\r
+       and  si,0003h                    ;look up left edge plane mask\r
+       mov  bh,LeftClipPlaneMask[si]    ; to clip & put in BH\r
+       mov  si,[EndX]\r
+       and  si,0003h                    ;look up right edge plane\r
+       mov  bl,RightClipPlaneMask[si]   ; mask to clip & put in BL\r
+\r
+       mov  cx,[EndX]                   ;calculate # of addresses across rect\r
+       mov  si,[StartX]\r
+       cmp  cx,si\r
+       jle  @@FillDone                  ;skip if 0 or negative width\r
+       dec  cx\r
+       and  si,not 011b\r
+       sub  cx,si\r
+       sar  cx,2                 ;# of addresses across rectangle to fill - 1\r
+       jnz  @@MasksSet           ;there's more than one byte to draw\r
+       and  bh,bl                ;there's only one byte, so combine the left\r
+                                  ; and right edge clip masks\r
+@@MasksSet:\r
+       mov  si,[EndY]\r
+       sub  si,[StartY]            ;BX = height of rectangle\r
+       jle  @@FillDone             ;skip if 0 or negative height\r
+       mov  ah,byte ptr [Color]    ;color with which to fill\r
+       mov  bp,[_ScrnLogicalByteWidth]  ;stack frame isn't needed any more\r
+       sub  bp,cx                  ;distance from end of one scan line to start\r
+       dec  bp                     ; of next\r
+@@FillRowsLoop:\r
+       push cx                     ;remember width in addresses - 1\r
+       mov  al,bh                  ;put left-edge clip mask in AL\r
+       out  dx,al                  ;set the left-edge plane (clip) mask\r
+       mov  al,ah                  ;put color in AL\r
+       stosb                       ;draw the left edge\r
+       dec  cx                     ;count off left edge byte\r
+       js   @@FillLoopBottom       ;that's the only byte\r
+       jz   @@DoRightEdge          ;there are only two bytes\r
+       mov  al,00fh                ;middle addresses drawn 4 pixels at a pop\r
+       out  dx,al                  ;set the middle pixel mask to no clip\r
+       mov  al,ah                  ;put color in AL\r
+       rep  stosb                  ;draw middle addresses four pixels apiece\r
+@@DoRightEdge:\r
+       mov  al,bl                  ;put right-edge clip mask in AL\r
+       out  dx,al                  ;set the right-edge plane (clip) mask\r
+       mov  al,ah                  ;put color in AL\r
+        stosb                       ;draw the right edge\r
+@@FillLoopBottom:\r
+       add  di,bp                  ;point to start of the next scan line of\r
+                                    ; the rectangle\r
+       pop  cx                     ;retrieve width in addresses - 1\r
+       dec  si                     ;count down scan lines\r
+       jnz  @@FillRowsLoop\r
+@@FillDone:\r
+       pop  di                     ;restore caller's register variables\r
+       pop  si\r
+       pop  bp                     ;restore caller's stack frame\r
+        ret\r
+_x_rect_fill endp\r
+\r
+\r
+\r
+;---------------------------------------------------------------------------\r
+; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.\r
+; Upper left corner of pattern is always aligned to a multiple-of-4\r
+; row and column. Works on all VGAs. Uses approach of copying the\r
+; pattern to off-screen display memory, then loading the latches with\r
+; the pattern for each scan line and filling each scan line four\r
+; pixels at a time. Fills up to but not including the column at EndX\r
+; and the row at EndY. No clipping is performed. All ASM code tested\r
+;\r
+;\r
+; Based on code originally published in DDJ Mag by M. Abrash\r
+;\r
+;\r
+;  C near-callable as:\r
+;\r
+;    void x_rect_pattern_clipped(int StartX, int StartY, int EndX, int EndY,\r
+;       unsigned int PageBase, char far * Pattern);\r
+;\r
+;\r
+\r
+_x_rect_pattern_clipped proc\r
+ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword\r
+LOCAL   NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk\r
+       push bp                       ;preserve caller's stack frame\r
+       mov  bp,sp                    ;point to local stack frame\r
+       sub  sp,LocalStk              ;allocate space for local vars\r
+       push si                       ;preserve caller's register variables\r
+       push di\r
+       push ds\r
+\r
+       mov   dx,[_TopClip]           ; Compare u.l. Y coord with Top\r
+       mov   cx,[_BottomClip]\r
+       mov   ax,[StartY]\r
+       mov   bx,[EndY]\r
+       cmp   dx,ax\r
+       jle   @@CheckBottomClip\r
+       cmp   dx,bx\r
+       jg    @@NotVisible\r
+       mov   [StartY],dx\r
+\r
+@@CheckBottomClip:\r
+       cmp   cx,bx\r
+       jg    @@CheckLeftClip\r
+       cmp   cx,ax\r
+       jl    @@NotVisible\r
+       mov   [EndY],cx\r
+\r
+@@CheckLeftClip:\r
+       mov   dx,[_LeftClip]           ; Compare u.l. Y coord with Top\r
+       mov   cx,[_RightClip]\r
+       mov   ax,[StartX]\r
+       mov   bx,[EndX]\r
+       sal   dx,2\r
+       sal   cx,2\r
+       cmp   dx,ax\r
+       jle   @@CheckRightClip\r
+       cmp   dx,bx\r
+       jg    @@NotVisible\r
+       mov   [StartX],dx\r
+\r
+@@CheckRightClip:\r
+       cmp   cx,bx\r
+       jg    RPClipDone\r
+       cmp   cx,ax\r
+       jl    @@NotVisible\r
+       mov   [EndX],cx\r
+       jmp   RPClipDone\r
+\r
+@@NotVisible:\r
+       mov   ax,1\r
+       pop   ds\r
+       pop   di                          ; restore registers\r
+       pop   si\r
+       mov   sp,bp\r
+       pop   bp\r
+       ret\r
+\r
+_x_rect_pattern_clipped endp\r
+\r
+;---------------------------------------------------------------------------\r
+; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.\r
+; Upper left corner of pattern is always aligned to a multiple-of-4\r
+; row and column. Works on all VGAs. Uses approach of copying the\r
+; pattern to off-screen display memory, then loading the latches with\r
+; the pattern for each scan line and filling each scan line four\r
+; pixels at a time. Fills up to but not including the column at EndX\r
+; and the row at EndY. No clipping is performed. All ASM code tested\r
+;\r
+;\r
+; Based on code originally published in DDJ Mag by M. Abrash\r
+;\r
+;\r
+;  C near-callable as:\r
+;\r
+;    void x_rect_pattern(int StartX, int StartY, int EndX, int EndY,\r
+;       unsigned int PageBase, char far * Pattern);\r
+\r
+\r
+\r
+_x_rect_pattern proc\r
+ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword\r
+LOCAL   NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk\r
+       push bp                       ;preserve caller's stack frame\r
+       mov  bp,sp                    ;point to local stack frame\r
+       sub  sp,LocalStk              ;allocate space for local vars\r
+       push si                       ;preserve caller's register variables\r
+       push di\r
+       push ds\r
+\r
+RPClipDone:\r
+       cld\r
+       mov  ax,SCREEN_SEG            ;point ES to display memory\r
+       mov  es,ax\r
+                                     ;copy pattern to display memory buffer\r
+       lds  si,dword ptr [Pattern]   ;point to pattern to fill with\r
+       mov  di,PATTERN_BUFFER        ;point ES:DI to pattern buffer\r
+       mov  dx,SC_INDEX              ;point Sequence Controller Index to\r
+       mov  al,MAP_MASK              ; Map Mask\r
+       out  dx,al\r
+       inc  dx                       ;point to SC Data register\r
+       mov  cx,4                     ;4 pixel quadruplets in pattern\r
+@@DownloadPatternLoop:\r
+       mov  al,1                     ;\r
+       out  dx,al                    ;select plane 0 for writes\r
+        movsb                         ;copy over next plane 0 pattern pixel\r
+       dec  di                       ;stay at same address for next plane\r
+       mov  al,2                     ;\r
+       out  dx,al                    ;select plane 1 for writes\r
+       movsb                         ;copy over next plane 1 pattern pixel\r
+       dec  di                       ;stay at same address for next plane\r
+       mov  al,4                     ;\r
+       out  dx,al                    ;select plane 2 for writes\r
+        movsb                         ;copy over next plane 2 pattern pixel\r
+       dec  di                       ;stay at same address for next plane\r
+       mov  al,8                     ;\r
+       out  dx,al                    ;select plane 3 for writes\r
+        movsb                         ;copy over next plane 3 pattern pixel\r
+                                      ; and advance address\r
+        loop @@DownloadPatternLoop\r
+        pop  ds\r
+\r
+       mov  dx,GC_INDEX              ;set the bit mask to select all bits\r
+       mov  ax,00000h+BIT_MASK       ; from the latches and none from\r
+       out  dx,ax                    ; the CPU, so that we can write the\r
+                                      ; latch contents directly to memory\r
+       mov  ax,[StartY]              ;top rectangle scan line\r
+       mov  si,ax\r
+       and  si,011b                  ;top rect scan line modulo 4\r
+       add  si,PATTERN_BUFFER        ;point to pattern scan line that\r
+                                     ; maps to top line of rect to draw\r
+       mov  dx,[_ScrnLogicalByteWidth]\r
+       mul  dx                       ;offset in page of top rect scan line\r
+       mov  di,[StartX]\r
+       mov  bx,di\r
+       sar  di,2             ;X/4 = offset of first rectangle pixel in scan\r
+       add  di,ax                    ;offset of first rectangle pixel in page\r
+       add  di,[PageBase]            ;offset of first rectangle pixel in\r
+                                      ; display memory\r
+       and  bx,0003h                 ;look up left edge plane mask\r
+       mov  ah,LeftClipPlaneMask[bx] ; to clip\r
+       mov  bx,[EndX]\r
+       and  bx,0003h                  ;look up right edge plane\r
+       mov  al,RightClipPlaneMask[bx] ; mask to clip\r
+       mov  bx,ax                     ;put the masks in BX\r
+\r
+       mov  cx,[EndX]                 ;calculate # of addresses across rect\r
+       mov  ax,[StartX]\r
+       cmp  cx,ax\r
+       jle  @@FillDone                ;skip if 0 or negative width\r
+       dec  cx\r
+       and  ax,not 011b\r
+       sub  cx,ax\r
+       sar  cx,2                 ;# of addresses across rectangle to fill - 1\r
+       jnz  @@MasksSet           ;there's more than one pixel to draw\r
+       and  bh,bl                ;there's only one pixel, so combine the left\r
+                                  ; and right edge clip masks\r
+@@MasksSet:\r
+       mov  ax,[EndY]\r
+       sub  ax,[StartY]          ;AX = height of rectangle\r
+       jle  @@FillDone           ;skip if 0 or negative height\r
+       mov  [Height],ax\r
+       mov  ax,[_ScrnLogicalByteWidth]\r
+       sub  ax,cx                ;distance from end of one scan line to start\r
+       dec  ax                   ; of next\r
+       mov  [NextScanOffset],ax\r
+       mov  [RectAddrWidth],cx   ;remember width in addresses - 1\r
+       mov  dx,SC_INDEX+1        ;point to Sequence Controller Data reg\r
+                                  ; (SC Index still points to Map Mask)\r
+@@FillRowsLoop:\r
+       mov  cx,[RectAddrWidth]   ;width across - 1\r
+       mov  al,es:[si]           ;read display memory to latch this scan\r
+                                  ; line's pattern\r
+       inc  si                   ;point to the next pattern scan line, wrapping\r
+       jnz  short @@NoWrap       ; back to the start of the pattern if\r
+       sub  si,4                 ; we've run off the end\r
+@@NoWrap:\r
+       mov  al,bh                ;put left-edge clip mask in AL\r
+       out  dx,al                ;set the left-edge plane (clip) mask\r
+        stosb                     ;draw the left edge (pixels come from latches;\r
+                                  ; value written by CPU doesn't matter)\r
+       dec  cx                   ;count off left edge address\r
+       js   @@FillLoopBottom     ;that's the only address\r
+       jz   @@DoRightEdge        ;there are only two addresses\r
+       mov  al,00fh              ;middle addresses drawn 4 pixels at a pop\r
+       out  dx,al                ;set middle pixel mask to no clip\r
+       rep  stosb                ;draw middle addresses four pixels apiece\r
+                                  ; (from latches; value written doesn't matter)\r
+@@DoRightEdge:\r
+       mov  al,bl                ;put right-edge clip mask in AL\r
+       out  dx,al                ;set the right-edge plane (clip) mask\r
+        stosb                     ;draw the right edge (from latches; value\r
+                                  ; written doesn't matter)\r
+@@FillLoopBottom:\r
+       add  di,[NextScanOffset]  ;point to the start of the next scan\r
+                                 ; line of the rectangle\r
+       dec  word ptr [Height]    ;count down scan lines\r
+       jnz  @@FillRowsLoop\r
+@@FillDone:\r
+       mov  dx,GC_INDEX+1        ;restore the bit mask to its default,\r
+       mov  al,0ffh              ; which selects all bits from the CPU\r
+       out  dx,al                ; and none from the latches (the GC\r
+                                 ; Index still points to Bit Mask)\r
+\r
+       pop  di                   ;restore caller's register variables\r
+       pop  si\r
+       mov  sp,bp                ;discard storage for local variables\r
+       pop  bp                   ;restore caller's stack frame\r
+        ret\r
+_x_rect_pattern endp\r
+\r
+;-----------------------------------------------------------------------\r
+; Mode X (320x240, 256 colors) display memory to display memory copy\r
+; routine. Left edge of source rectangle modulo 4 must equal left edge\r
+; of destination rectangle modulo 4. Works on all VGAs. Uses approach\r
+; of reading 4 pixels at a time from the source into the latches, then\r
+; writing the latches to the destination. Copies up to but not\r
+; including the column at SrcEndX and the row at SrcEndY. No\r
+; clipping is performed. Results are not guaranteed if the source and\r
+; destination overlap.\r
+;\r
+;\r
+; Based on code originally published in DDJ Mag by M. Abrash\r
+;\r
+;C near-callable as:\r
+;    void x_cp_vid_rect(int SrcStartX, int SrcStartY,\r
+;       int SrcEndX, int SrcEndY, int DestStartX,\r
+;       int DestStartY, unsigned int SrcPageBase,\r
+;       unsigned int DestPageBase, int SrcBitmapWidth,\r
+;       int DestBitmapWidth);\r
+\r
+_x_cp_vid_rect proc\r
+       ARG SrcStartX:word,SrcStartY:word,SrcEndX:word,SrcEndY:word,DestStartX:word,DestStartY:word,SrcPageBase:word,DestPageBase:word,SrcBitmapW:word,DestBitmapW:word\r
+       LOCAL SrcNextOffs:word,DestNextOffs:word,RectAddrW:word,Height:word=LocalStk\r
+       push    bp                  ;preserve caller's stack frame\r
+       mov     bp,sp               ;point to local stack frame\r
+       sub     sp,LocalStk         ;allocate space for local vars\r
+       push    si                  ;preserve caller's register variables\r
+       push    di\r
+        push    ds\r
+\r
+        cld\r
+       mov     dx,GC_INDEX         ;set the bit mask to select all bits\r
+       mov     ax,00000h+BIT_MASK  ; from the latches and none from\r
+       out dx,ax                   ; the CPU, so that we can write the\r
+                                   ; latch contents directly to memory\r
+       mov     ax,SCREEN_SEG       ;point ES to display memory\r
+        mov     es,ax\r
+       mov     ax,[DestBitmapW]\r
+       shr     ax,2                ;convert to width in addresses\r
+       mul     [DestStartY]        ;top dest rect scan line\r
+       mov     di,[DestStartX]\r
+       sar     di,2                ;X/4 = offset of first dest rect pixel in\r
+                                   ; scan line\r
+       add     di,ax               ;offset of first dest rect pixel in page\r
+       add     di,[DestPageBase]   ;offset of first dest rect pixel\r
+                                   ; in display memory\r
+       mov     ax,[SrcBitmapW]\r
+       sar     ax,2                ;convert to width in addresses\r
+       mul     [SrcStartY]      ;top source rect scan line\r
+       mov     si,[SrcStartX]\r
+        mov     bx,si\r
+       sar     si,2              ;X/4 = offset of first source rect pixel in\r
+                                 ; scan line\r
+       add     si,ax             ;offset of first source rect pixel in page\r
+       add     si,[SrcPageBase]  ;offset of first source rect\r
+                                 ; pixel in display memory\r
+       and     bx,0003h                     ;look up left edge plane mask\r
+       mov     ah,LeftClipPlaneMask[bx]  ; to clip\r
+       mov     bx,[SrcEndX]\r
+       and     bx,0003h                     ;look up right edge plane\r
+       mov     al,RightClipPlaneMask[bx] ; mask to clip\r
+       mov     bx,ax                        ;put the masks in BX\r
+\r
+       mov     cx,[SrcEndX]              ;calculate # of addresses across\r
+       mov     ax,[SrcStartX]            ; rect\r
+        cmp     cx,ax\r
+       jle     @@CopyDone                   ;skip if 0 or negative width\r
+        dec     cx\r
+        and     ax,not 011b\r
+        sub     cx,ax\r
+       sar     cx,2             ;# of addresses across rectangle to copy - 1\r
+       jnz     @@MasksSet       ;there's more than one address to draw\r
+       and     bh,bl            ;there's only one address, so combine the left\r
+                                ; and right edge clip masks\r
+@@MasksSet:\r
+       mov     ax,[SrcEndY]\r
+       sub     ax,[SrcStartY]     ;AX = height of rectangle\r
+       jle     @@CopyDone         ;skip if 0 or negative height\r
+       mov     [Height],ax\r
+       mov     ax,[DestBitmapW]\r
+       sar     ax,2               ;convert to width in addresses\r
+       sub     ax,cx              ;distance from end of one dest scan line\r
+       dec     ax                 ; to start of next\r
+       mov     [DestNextOffs],ax\r
+       mov     ax,[SrcBitmapW]\r
+       sar     ax,2               ;convert to width in addresses\r
+       sub     ax,cx              ;distance from end of one source scan line\r
+       dec     ax                 ; to start of next\r
+       mov     [SrcNextOffs],ax\r
+       mov     [RectAddrW],cx     ;remember width in addresses - 1\r
+       mov     dx,SC_INDEX+1      ;point to Sequence Controller Data reg\r
+                                  ; (SC Index still points to Map Mask)\r
+       mov     ax,es              ;DS=ES=screen segment for MOVS\r
+        mov     ds,ax\r
+@@CopyRowsLoop:\r
+       mov     cx,[RectAddrW]     ;width across - 1\r
+       mov     al,bh              ;put left-edge clip mask in AL\r
+       out     dx,al              ;set the left-edge plane (clip) mask\r
+       movsb                      ;copy the left edge (pixels go through\r
+                                  ; latches)\r
+       dec     cx                 ;count off left edge address\r
+       js      @@CopyLoopBottom   ;that's the only address\r
+       jz      @@DoRightEdge      ;there are only two addresses\r
+       mov     al,00fh            ;middle addresses are drawn 4 pix per go\r
+       out     dx,al              ;set the middle pixel mask to no clip\r
+       rep     movsb              ;draw the middle addresses four pix per go\r
+                                  ; (pixels copied through latches)\r
+@@DoRightEdge:\r
+        mov     al,bl   ;put right-edge clip mask in AL\r
+        out     dx,al   ;set the right-edge plane (clip) mask\r
+        movsb           ;draw the right edge (pixels copied through\r
+                        ; latches)\r
+@@CopyLoopBottom:\r
+       add     si,[SrcNextOffs]   ;point to the start of\r
+       add     di,[DestNextOffs]  ; next source & dest lines\r
+       dec     word ptr [Height]  ;count down scan lines\r
+       jnz     @@CopyRowsLoop\r
+@@CopyDone:\r
+       mov     dx,GC_INDEX+1   ;restore the bit mask to its default,\r
+        mov     al,0ffh         ; which selects all bits from the CPU\r
+       out     dx,al           ; and none from the latches (the GC\r
+                                ; Index still points to Bit Mask)\r
+        pop     ds\r
+       pop     di              ;restore caller's register variables\r
+        pop     si\r
+       mov     sp,bp           ;discard storage for local variables\r
+       pop     bp              ;restore caller's stack frame\r
+        ret\r
+_x_cp_vid_rect  endp\r
+\r
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
+; Copy a rectangular region of a VGA screen, with x coordinates\r
+; rounded to the nearest byte -- source and destination may overlap.\r
+;\r
+; C near-callable as:\r
+;\r
+; void x_shift_rect (WORD SrcLeft, WORD SrcTop,\r
+;                    WORD SrcRight, WORD SrcBottom,\r
+;                    WORD DestLeft, WORD DestTop, WORD ScreenOffs);\r
+;\r
+; SrcRight is rounded up, and the left edges are rounded down, to ensure\r
+; that the pixels pointed to by the arguments are inside the rectangle.\r
+;\r
+; The width of the rectangle in bytes (width in pixels / 4)\r
+; cannot exceed 255.\r
+;\r
+; ax, bx, cx, dx, and es eat hot lead.\r
+;\r
+; This function was written by Matthew MacKenzie\r
+; matm@eng.umd.edu\r
+\r
+       align   2\r
+_x_shift_rect proc\r
+ARG     SrcLeft,SrcTop,SrcRight,SrcBottom,DestLeft,DestTop,ScreenOffs:word\r
+LOCAL   width_temp:word=LocalStk\r
+\r
+       push bp\r
+       mov bp, sp\r
+       sub sp, LocalStk\r
+       push si\r
+       push di\r
+       push ds\r
+\r
+       ; find values for width & x motion\r
+       mov si, SrcLeft     ; source x in bytes\r
+       sar si, 2\r
+\r
+       mov di, DestLeft    ; destination x in bytes\r
+       sar di, 2\r
+\r
+       mov bx, SrcRight    ; right edge of source in bytes, rounded up\r
+       add bx, 3\r
+       sar bx, 2\r
+       sub bx, si\r
+       mov ax, bx          ; width - 1\r
+       inc bx              ; we'll use this as an offset for moving up or down\r
+       mov width_temp, bx\r
+\r
+       cld                 ; by default, strings increment\r
+\r
+       cmp si, di\r
+       jge @@MovingLeft\r
+\r
+; we're moving our rectangle right, so we copy it from right to left\r
+       add si, ax          ; source & destination will start on the right edge\r
+       add di, ax\r
+       neg bx\r
+       std                 ; strings decrement\r
+\r
+@@MovingLeft:\r
+\r
+; find values for height & y motion\r
+       mov cx, _ScrnLogicalByteWidth ; bytes to move to advance one line\r
+       mov ax, SrcTop\r
+       mov dx, DestTop     ; default destination y\r
+       cmp ax, dx\r
+       jge @@MovingUp\r
+\r
+; we're moving our rectangle down, so we copy it from bottom to top\r
+       mov ax, SrcBottom   ; source starts at bottom\r
+       add dx, ax          ; add (height - 1) to destination y\r
+       sub dx, SrcTop\r
+       neg cx              ; advance up screen rather than down\r
+\r
+@@MovingUp:\r
+       push dx             ; save destination y during multiply\r
+       mul _ScrnLogicalByteWidth\r
+       add si, ax          ; add y in bytes to source\r
+       pop ax              ; restore destination y\r
+       mul _ScrnLogicalByteWidth\r
+       add di, ax          ; add y in bytes to destination\r
+\r
+       sub cx, bx          ; final value for moving up or down\r
+\r
+       add si, ScreenOffs  ; source & destination are on the same screen\r
+       add di, ScreenOffs\r
+\r
+       mov dx, SC_INDEX    ; set map mask to all four planes\r
+       mov ax, 00f02h\r
+       out dx, ax\r
+\r
+       mov dx, GC_INDEX    ; set bit mask to take data from latches\r
+       mov ax, BIT_MASK    ;  rather than CPU\r
+       out dx, ax\r
+\r
+       mov ax, SCREEN_SEG  ; source and destination are VGA memory\r
+       mov es, ax\r
+       mov ds, ax\r
+\r
+       mov ah, byte ptr width_temp ; width in bytes should fit in 8 bits\r
+\r
+       mov bx, SrcBottom   ; height - 1\r
+       sub bx, SrcTop\r
+\r
+       mov dx, cx          ; bytes to add to advance one line\r
+\r
+       xor ch, ch          ; ready to rock\r
+\r
+@@LineLoop:\r
+       mov cl, ah          ; load width in bytes\r
+       rep movsb           ; move 4 pixels at a time using latches (YOW!)\r
+\r
+       add si, dx          ; advance source by one line\r
+       add di, dx          ; advance destination by one line\r
+\r
+       dec bx              ; line counter\r
+       jge @@LineLoop      ; 0 still means one more to go\r
+\r
+       mov dx, GC_INDEX + 1; set bit mask to take data from CPU (normal setting)\r
+       mov al, 0ffh\r
+       out dx, al\r
+\r
+; kick\r
+       pop ds\r
+       pop di\r
+       pop si\r
+       mov sp, bp\r
+       pop bp\r
+\r
+       ret\r
+_x_shift_rect endp\r
+\r
+       end\r
+\r