--- /dev/null
+;-----------------------------------------------------------------------\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