home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_PAS
/
XLIB_TP5.ZIP
/
UNITS
/
X_RECT.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-12-19
|
37KB
|
789 lines
unit X_Rect;
interface
(* rectangle solid colour fill routine. *)
procedure x_rect_fill(X1,Y1,X2,Y2,Color:Word);
procedure x_rect_fill_clipped(X1,Y1,X2,Y2,Color:Word);
procedure Box(x1,y1,x2,y2,Color:Word);
procedure Shadow_Box(x1,y1,x2,y2,C1,C2,C3:Word);
(* rectangle 4x4 pattern fill routine. *)
procedure x_rect_pattern(X1,Y1,X2,Y2:Word;Var Pattern);
procedure x_rect_pattern_clipped(X1,Y1,X2,Y2:Word;Var Pattern);
(* Display memory to display memory copy routine. Left edge of source *)
(* rectangle modulo 4 must equal left edge of destination rectangle modulo 4*)
(* Works on all VGAs. Ignoring activ_screen->absolute Pos. *)
procedure x_cp_vid_rect(SrcX1,SrcY1,SrcX2,ScrY2,DestX1,DestY1:Word);
(* Copy a rectangular region of a VGA screen, with x coordinates *)
(* rounded to the nearest byte -- source and destination may overlap. *)
procedure x_shift_rect(ScrX1,ScrY1,ScrX2,ScrY2,DestX1,DestY1:Word);
implementation
uses X_Const,X_Main;
(* Plane masks for clipping left and right edges of rectangle. *)
const LeftClipPlaneMask :Array[0..3] of Byte = ($0f,$0e,$0c,$08);
RightClipPlaneMask:Array[0..3] of Byte = ($0f,$01,$03,$07);
(* Mode X (320x240, 256 colors) rectangle solid colour fill routine. *)
procedure x_rect_fill(X1,Y1,X2,Y2,Color:Word); assembler;
asm
cld
mov ax,ScrnLogicalByteWidth
mul Y1 (* offset in page of top rectangle scan line *)
mov di,X1
shr di,1 (*X/4 = offset of first rectangle pixel in scan *)
shr di,1 (* line *)
add di,ax (*offset of first rectangle pixel in page *)
add di,ScreenOfs (*offset of first rectangle pixel in *)
(* display memory *)
mov ax,SCREEN_SEG (*point ES:DI to the first rectangle *)
mov es,ax (* pixel's address *)
mov dx,SC_INDEX (*set the Sequence Controller Index to *)
mov al,MAP_MASK (* point to the Map Mask register *)
out dx,al
inc dx (*point DX to the SC Data register *)
mov si,X1
and si,0003h (*look up left edge plane mask *)
mov bh,[offset LeftClipPlaneMask+si] (* to clip & put in BH *)
mov si,X2
and si,0003h (*look up right edge plane *)
mov bl,[offset RightClipPlaneMask+si] (* mask to clip & put in BL *)
mov cx,X2 (*calculate # of addresses across rect *)
mov si,X1
cmp cx,si
jle @@FillDone (*skip if 0 or negative width *)
dec cx
and si,not 011b
sub cx,si
shr cx,1
shr cx,1 (*# of addresses across rectangle to fill - 1 *)
jnz @@MasksSet (*there's more than one byte to draw *)
and bh,bl (*there's only one byte, so combine the left *)
(* and right edge clip masks *)
@@MasksSet:
mov si,Y2
sub si,Y1 (* BX = height of rectangle *)
jle @@FillDone (*skip if 0 or negative height *)
mov ah,byte ptr [Color] (*color with which to fill *)
mov bp,ScrnLogicalByteWidth(*stack frame isn't needed any more *)
sub bp,cx (*distance from end of one scan line to start *)
dec bp (* of next *)
@@FillRowsLoop:
push cx (*remember width in addresses - 1 *)
mov al,bh (*put left-edge clip mask in AL *)
out dx,al (*set the left-edge plane (clip) mask *)
mov al,ah (*put color in AL *)
stosb (*draw the left edge *)
dec cx (*count off left edge byte *)
js @@FillLoopBottom (*that's the only byte *)
jz @@DoRightEdge (*there are only two bytes *)
mov al,00fh (*middle addresses drawn 4 pixels at a pop *)
out dx,al (*set the middle pixel mask to no clip *)
mov al,ah (*put color in AL *)
rep stosb (*draw middle addresses four pixels apiece *)
@@DoRightEdge:
mov al,bl (*put right-edge clip mask in AL *)
out dx,al (*set the right-edge plane (clip) mask *)
mov al,ah (*put color in AL *)
stosb (*draw the right edge *)
@@FillLoopBottom:
add di,bp (*point to start of the next scan line of *)
(* the rectangle *)
pop cx (*retrieve width in addresses - 1 *)
dec si (*count down scan lines *)
jnz @@FillRowsLoop
@@FillDone:
end;
procedure Box(x1,y1,x2,y2,Color:Word);
begin;
x_rect_fill(X1,Y1,X2,Y2,Color);
end;
procedure Shadow_Box(x1,y1,x2,y2,C1,C2,C3:Word);
var L_X:Word;
begin;
Box(x1,y1,x2,y2,C2);
Line(x1, y1, x2,y1,C1);
Line(x1, y1, x1,y2,C1);
Line(x1+1,y2, x2,y2,C3);
Line(x2, y1+1,x2,y2,C3);
end;
(*------------------------------------------------------------------------- *)
(* Mode X rectangle solid colour fill routine. *)
(* *)
(* Based on code originally published in DDJ Mag by M. Abrash *)
(* *)
procedure x_rect_fill_clipped(X1,Y1,X2,Y2,Color:Word); assembler;
(* StartX:word,StartY:word,EndX:word,EndY:word,ScreenOfs:word,Color:word *)
asm
push si (*preserve caller's register variables *)
push di
mov dx,[TopClip] (* Compare u.l. Y coord with Top *)
mov cx,[BottomClip]
mov ax,[Y1]
mov bx,[Y2]
cmp dx,ax
jle @@CheckBottomClip
cmp dx,bx
jg @@NotVisible
mov [Y1],dx
@@CheckBottomClip:
cmp cx,bx
jg @@CheckLeftClip
cmp cx,ax
jl @@NotVisible
mov [Y2],cx
@@CheckLeftClip:
mov dx,[LeftClip] (* Compare u.l. Y coord with Top *)
mov cx,[RightClip]
mov ax,[X1]
mov bx,[X2]
sal dx,1
sal dx,1
sal cx,1
sal cx,1
cmp dx,ax
jle @@CheckRightClip
cmp dx,bx
jg @@NotVisible
mov [X1],dx
@@CheckRightClip:
cmp cx,bx
jg @RFClipDone
cmp cx,ax
jl @@NotVisible
mov [X2],cx
@RFClipDone:
cld
mov ax,[ScrnLogicalByteWidth]
mul [Y1] (*offset in page of top rectangle scan line*)
mov di,[X1]
sar di,1 (*X/4 = offset of first rectangle pixel in scan *)
sar di,1
add di,ax (*offset of first rectangle pixel in page *)
add di,[ScreenOfs] (*offset of first rectangle pixel in *)
(* display memory *)
mov ax,SCREEN_SEG (*point ES:DI to the first rectangle *)
mov es,ax (* pixel's address *)
mov dx,SC_INDEX (*set the Sequence Controller Index to *)
mov al,MAP_MASK (* point to the Map Mask register *)
out dx,al
inc dx (*point DX to the SC Data register *)
mov si,[X1]
and si,0003h (*look up left edge plane mask *)
mov bh,[offset LeftClipPlaneMask+si] (* to clip & put in BH *)
mov si,[X1]
and si,0003h (*look up right edge plane *)
mov bl,[offset RightClipPlaneMask+si] (* mask to clip & put in BL *)
mov cx,[X1] (*calculate # of addresses across rect *)
mov si,[X1]
cmp cx,si
jle @@FillDone (*skip if 0 or negative width *)
dec cx
and si,not 011b
sub cx,si
sar cx,1 (*# of addresses across rectangle to fill - 1 *)
sar cx,1
jnz @@MasksSet (*there's more than one byte to draw *)
and bh,bl (*there's only one byte, so combine the left *)
(* and right edge clip masks *)
@@MasksSet:
mov si,[Y2]
sub si,[Y1] (*BX = height of rectangle *)
jle @@FillDone (*skip if 0 or negative height *)
mov ah,byte ptr [Color] (*color with which to fill *)
mov bp,[ScrnLogicalByteWidth] (*stack frame isn't needed any more *)
sub bp,cx (*distance from end of one scan line to start *)
dec bp (* of next *)
@@FillRowsLoop:
push cx (*remember width in addresses - 1 *)
mov al,bh (*put left-edge clip mask in AL *)
out dx,al (*set the left-edge plane (clip) mask *)
mov al,ah (*put color in AL *)
stosb (*draw the left edge *)
dec cx (*count off left edge byte *)
js @@FillLoopBottom (*that's the only byte *)
jz @@DoRightEdge (*there are only two bytes *)
mov al,00fh (*middle addresses drawn 4 pixels at a pop *)
out dx,al (*set the middle pixel mask to no clip *)
mov al,ah (*put color in AL *)
rep stosb (*draw middle addresses four pixels apiece *)
@@DoRightEdge:
mov al,bl (*put right-edge clip mask in AL *)
out dx,al (*set the right-edge plane (clip) mask *)
mov al,ah (*put color in AL *)
stosb (*draw the right edge *)
@@FillLoopBottom:
add di,bp (*point to start of the next scan line of *)
(* the rectangle *)
pop cx (*retrieve width in addresses - 1 *)
dec si (*count down scan lines *)
jnz @@FillRowsLoop
@@FillDone:
@@NotVisible:
mov ax,1
pop di (* restore registers *)
pop si
end;
(* ------------------------------------------------------------------------ *)
(* Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine. *)
(* Upper left corner of pattern is always aligned to a multiple-of-4 *)
(* row and column. Works on all VGAs. Uses approach of copying the *)
(* pattern to off-screen display memory, then loading the latches with *)
(* the pattern for each scan line and filling each scan line four *)
(* pixels at a time. Fills up to but not including the column at X2 *)
(* and the row at Y2. No clipping is performed. All ASM code tested *)
(* *)
procedure x_rect_pattern(X1,Y1,X2,Y2:Word;Var Pattern); assembler;
var NextScanOffset,RectAddrWidth,Height:Word;
asm
push ds
cld
mov ax,SCREEN_SEG (*point ES to display memory *)
mov es,ax
(*copy pattern to display memory buffer*)
lds si,dword ptr [Pattern] (*point to pattern to fill with *)
mov di,PATTERN_BUFFER (*point ES:DI to pattern buffer *)
mov dx,SC_INDEX (*point Sequence Controller Index to *)
mov al,MAP_MASK (* Map Mask *)
out dx,al
inc dx (*point to SC Data register *)
mov cx,4 (*4 pixel quadruplets in pattern *)
@@DownloadPatternLoop:
mov al,1 (* *)
out dx,al (*select plane 0 for writes *)
movsb (*copy over next plane 0 pattern pixel*)
dec di (*stay at same address for next plane *)
mov al,2 (* *)
out dx,al (*select plane 1 for writes *)
movsb (*copy over next plane 1 pattern pixel*)
dec di (*stay at same address for next plane *)
mov al,4 (* *)
out dx,al (*select plane 2 for writes *)
movsb (*copy over next plane 2 pattern pixel*)
dec di (*stay at same address for next plane *)
mov al,8 (* *)
out dx,al (*select plane 3 for writes *)
movsb (*copy over next plane 3 pattern pixel*)
(* and advance address *)
loop @@DownloadPatternLoop
pop ds
mov dx,GC_INDEX (*set the bit mask to select all bits *)
mov ax,00000h+BIT_MASK (* from the latches and none from *)
out dx,ax (* the CPU, so that we can write the *)
(* latch contents directly to memory *)
mov ax,Y1 (*top rectangle scan line *)
mov si,ax
and si,011b (*top rect scan line modulo 4 *)
add si,PATTERN_BUFFER (*point to pattern scan line that *)
(* maps to top line of rect to draw *)
mov dx,ScrnLogicalByteWidth
mul dx (*offset in page of top rect scan line*)
mov di,X1
mov bx,di
shr di,1 (*X/4 = offset of first rectangle pixel in scan*)
shr di,1 (* line *)
add di,ax (*offset of first rectangle pixel in page *)
add di,ScreenOfs (*offset of first rectangle pixel in *)
(* display memory *)
and bx,0003h (*look up left edge plane mask *)
mov ah,[offset LeftClipPlaneMask+bx] (* to clip *)
mov bx,[X2]
and bx,0003h (*look up right edge plane *)
mov al,[offset RightClipPlaneMask+bx] (* mask to clip *)
mov bx,ax (*put the masks in BX *)
mov cx,X2 (*calculate # of addresses across rect *)
mov ax,X1
cmp cx,ax
jle @@FillDone (*skip if 0 or negative width *)
dec cx
and ax,not 011b
sub cx,ax
shr cx,1
shr cx,1 (*# of addresses across rectangle to fill - 1*)
jnz @@MasksSet (*there's more than one pixel to draw *)
and bh,bl (*there's only one pixel, so combine the left*)
(* and right edge clip masks *)
@@MasksSet:
mov ax,Y2
sub ax,Y1 (*AX = height of rectangle *)
jle @@FillDone (*skip if 0 or negative height *)
mov Height,ax
mov ax,ScrnLogicalByteWidth
sub ax,cx (*distance from end of one scan line to start*)
dec ax (* of next *)
mov NextScanOffset,ax
mov RectAddrWidth,cx (*remember width in addresses - 1 *)
mov dx,SC_INDEX+1 (*point to Sequence Controller Data reg *)
(* (SC Index still points to Map Mask) *)
@@FillRowsLoop:
mov cx,RectAddrWidth (*width across - 1 *)
mov al,es:[si] (*read display memory to latch this scan *)
(* line's pattern *)
inc si (*point to the next pattern scan line, wrapping*)
jnz @@NoWrap (* back to the start of the pattern if *)
sub si,4 (* we've run off the end *)
@@NoWrap:
mov al,bh (*put left-edge clip mask in AL *)
out dx,al (*set the left-edge plane (clip) mask *)
stosb (*draw the left edge (pixels come from latches *)
(* value written by CPU doesn't matter) *)
dec cx (*count off left edge address *)
js @@FillLoopBottom (*that's the only address *)
jz @@DoRightEdge (*there are only two addresses *)
mov al,00fh (*middle addresses drawn 4 pixels at a pop*)
out dx,al (*set middle pixel mask to no clip *)
rep stosb (*draw middle addresses four pixels apiece*)
(* (from latches(* value written doesn't matter)*)
@@DoRightEdge:
mov al,bl (*put right-edge clip mask in AL *)
out dx,al (*set the right-edge plane (clip) mask *)
stosb (*draw the right edge (from latches(* value*)
(* written doesn't matter) *)
@@FillLoopBottom:
add di,NextScanOffset (*point to the start of the next scan *)
(* line of the rectangle *)
dec word ptr Height (*count down scan lines *)
jnz @@FillRowsLoop
@@FillDone:
mov dx,GC_INDEX+1 (*restore the bit mask to its default, *)
mov al,0ffh (* which selects all bits from the CPU *)
out dx,al (* and none from the latches (the GC *)
end;
procedure x_rect_pattern_clipped(X1,Y1,X2,Y2:Word;Var Pattern); assembler;
var NextScanOffset,RectAddrWidth,Height:Word;
asm
{ARG StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword}
push si (*preserve caller's register variables *)
push di
push ds
mov dx,[TopClip] (* Compare u.l. Y coord with Top *)
mov cx,[BottomClip]
mov ax,[Y1]
mov bx,[Y2]
cmp dx,ax
jle @@CheckBottomClip
cmp dx,bx
jg @@NotVisible
mov [Y1],dx
@@CheckBottomClip:
cmp cx,bx
jg @@CheckLeftClip
cmp cx,ax
jl @@NotVisible
mov [Y2],cx
@@CheckLeftClip:
mov dx,[LeftClip] (* Compare u.l. Y coord with Top *)
mov cx,[RightClip]
mov ax,[X2]
mov bx,[X2]
sal dx,1
sal dx,1
sal cx,1
sal cx,1
cmp dx,ax
jle @@CheckRightClip
cmp dx,bx
jg @@NotVisible
mov [X1],dx
@@CheckRightClip:
cmp cx,bx
jg @RPClipDone
cmp cx,ax
jl @@NotVisible
mov [X2],cx
jmp @RPClipDone
@RPClipDone:
cld
mov ax,SCREEN_SEG (*point ES to display memory *)
mov es,ax
(*copy pattern to display memory buffer *)
lds si,dword ptr [Pattern] (*point to pattern to fill with *)
mov di,PATTERN_BUFFER (*point ES:DI to pattern buffer *)
mov dx,SC_INDEX (*point Sequence Controller Index to *)
mov al,MAP_MASK (* Map Mask *)
out dx,al
inc dx (*point to SC Data register *)
mov cx,4 (*4 pixel quadruplets in pattern *)
@@DownloadPatternLoop:
mov al,1 (* *)
out dx,al (*select plane 0 for writes *)
movsb (*copy over next plane 0 pattern pixel*)
dec di (*stay at same address for next plane *)
mov al,2 (* *)
out dx,al (*select plane 1 for writes *)
movsb (*copy over next plane 1 pattern pixel*)
dec di (*stay at same address for next plane *)
mov al,4 (* *)
out dx,al (*select plane 2 for writes *)
movsb (*copy over next plane 2 pattern pixel*)
dec di (*stay at same address for next plane *)
mov al,8 (* *)
out dx,al (*select plane 3 for writes *)
movsb (*copy over next plane 3 pattern pixel*)
(* and advance address *)
loop @@DownloadPatternLoop
pop ds
mov dx,GC_INDEX (*set the bit mask to select all bits *)
mov ax,00000h+BIT_MASK (* from the latches and none from *)
out dx,ax (* the CPU, so that we can write the *)
(* latch contents directly to memory *)
mov ax,[Y1] (*top rectangle scan line *)
mov si,ax
and si,011b (*top rect scan line modulo 4 *)
add si,PATTERN_BUFFER (*point to pattern scan line that *)
(* maps to top line of rect to draw *)
mov dx,[ScrnLogicalByteWidth]
mul dx (*offset in page of top rect scan line*)
mov di,[X1]
mov bx,di
sar di,1 (*X/4 = offset of first rectangle pixel in scan *)
sar di,1
add di,ax (*offset of first rectangle pixel in page *)
add di,[ScreenOfs] (*offset of first rectangle pixel in *)
(* display memory *)
and bx,0003h (*look up left edge plane mask *)
mov ah,[offset LeftClipPlaneMask+bx] (* to clip *)
mov bx,[X2]
and bx,0003h (*look up right edge plane *)
mov al,[offset RightClipPlaneMask+bx] (* mask to clip *)
mov bx,ax (*put the masks in BX *)
mov cx,[X2] (*calculate # of addresses across rect *)
mov ax,[X1]
cmp cx,ax
jle @@FillDone (*skip if 0 or negative width *)
dec cx
and ax,not 011b
sub cx,ax
sar cx,1 (*# of addresses across rectangle to fill - 1 *)
sar cx,1
jnz @@MasksSet (*there's more than one pixel to draw *)
and bh,bl (*there's only one pixel, so combine the left *)
(* and right edge clip masks *)
@@MasksSet:
mov ax,[Y2]
sub ax,[Y1] (*AX = height of rectangle *)
jle @@FillDone (*skip if 0 or negative height *)
mov [Height],ax
mov ax,[ScrnLogicalByteWidth]
sub ax,cx (*distance from end of one scan line to start *)
dec ax (* of next *)
mov [NextScanOffset],ax
mov [RectAddrWidth],cx (*remember width in addresses - 1 *)
mov dx,SC_INDEX+1 (*point to Sequence Controller Data reg *)
(* (SC Index still points to Map Mask) *)
@@FillRowsLoop:
mov cx,[RectAddrWidth] (*width across - 1 *)
mov al,es:[si] (*read display memory to latch this scan *)
(* line's pattern *)
inc si (*point to the next pattern scan line, wrapping *)
jnz @@NoWrap (* back to the start of the pattern if *)
sub si,4 (* we've run off the end *)
@@NoWrap:
mov al,bh (*put left-edge clip mask in AL *)
out dx,al (*set the left-edge plane (clip) mask *)
stosb (*draw the left edge (pixels come from latches; *)
(* value written by CPU doesn't matter) *)
dec cx (*count off left edge address *)
js @@FillLoopBottom (*that's the only address *)
jz @@DoRightEdge (*there are only two addresses *)
mov al,00fh (*middle addresses drawn 4 pixels at a pop*)
out dx,al (*set middle pixel mask to no clip *)
rep stosb (*draw middle addresses four pixels apiece*)
(* (from latches; value written doesn't matter) *)
@@DoRightEdge:
mov al,bl (*put right-edge clip mask in AL *)
out dx,al (*set the right-edge plane (clip) mask *)
stosb (*draw the right edge (from latches(* value *)
(* written doesn't matter) *)
@@FillLoopBottom:
add di,[NextScanOffset] (*point to the start of the next scan *)
(* line of the rectangle *)
dec word ptr [Height] (*count down scan lines *)
jnz @@FillRowsLoop
@@FillDone:
mov dx,GC_INDEX+1 (*restore the bit mask to its default, *)
mov al,0ffh (* which selects all bits from the CPU *)
out dx,al (* and none from the latches (the GC *)
(* Index still points to Bit Mask) *)
@@NotVisible:
mov ax,1
pop ds
pop di (* restore registers *)
pop si
end;
(* ----------------------------------------------------------------------- *)
(* Mode X (320x240, 256 colors) display memory to display memory copy *)
(* routine. Left edge of source rectangle modulo 4 must equal left edge *)
(* of destination rectangle modulo 4. Works on all VGAs. Uses approach *)
(* of reading 4 pixels at a time from the source into the latches, then *)
(* writing the latches to the destination. Copies up to but not *)
(* including the column at SrcX2 and the row at SrcY2. No clipping is *)
(* performed. Results are not guaranteed if the source and destination *)
(* overlap. *)
(* *)
(* ! All X,Y-Values are not at active_screen, they are absolut ! *)
{
(*C near-callable as:
(* void x_cp_vid_rect(int SrcStartX, int SrcStartY,
(* int SrcEndX, int SrcEndY, int DestStartX,
(* int DestStartY, unsigned int SrcPageBase,
(* unsigned int DestPageBase, int SrcBitmapWidth,
(* int DestBitmapWidth);
}
procedure x_cp_vid_rect(SrcX1,SrcY1,SrcX2,ScrY2,DestX1,DestY1:Word);
{ SrcBitmapW,DestBitmapW:word);} assembler;
{ARG SrcStartX:word,SrcStartY:word,SrcEndX:word,SrcEndY:word,DestStartX:word,DestStartY:word,SrcPageBase:word,DestPageBase:word
,SrcBitmapW:word,DestBitmapW:word}
var SrcNextOffs,DestNextOffs,RectAddrW,Height:Word;
asm
push ds
cld
mov dx,GC_INDEX (*set the bit mask to select all bits *)
mov ax,00000h+BIT_MASK (* from the latches and none from *)
out dx,ax (* the CPU, so that we can write the *)
(* latch contents directly to memory *)
mov ax,SCREEN_SEG (*point ES to display memory *)
mov es,ax
mov ax,ScrnLogicalPixelWidth
shr ax,1;shr ax,1 (*convert to width in addresses *)
mul DestY1 (*top dest rect scan line *)
mov di,DestX1
shr di,1;shr di,1 (*X/4 = offset of first dest rect pixel in *)
(* scan line *)
add di,ax (*offset of first dest rect pixel *)
(* in display memory *)
mov ax,ScrnLogicalPixelWidth
shr ax,1;shr ax,1 (*convert to width in addresses *)
mul SrcY1 (*top source rect scan line *)
mov si,SrcX1
mov bx,si
shr si,1;shr si,1 (*X/4 = offset of first source rect pixel in *)
(* scan line *)
add si,ax (*offset of first source rect *)
(* pixel in display memory *)
and bx,0003h (*look up left edge plane mask *)
mov ah,[offset LeftClipPlaneMask+bx] (* to clip *)
mov bx,[SrcX2]
and bx,0003h (*look up right edge plane *)
mov al,[offset RightClipPlaneMask+bx] (* mask to clip *)
mov bx,ax (*put the masks in BX *)
mov cx,SrcX2 (*calculate # of addresses across *)
mov ax,SrcX1 (* rect *)
cmp cx,ax
jle @@CopyDone (*skip if 0 or negative width *)
dec cx
and ax,not 011b
sub cx,ax
shr cx,1;shr cx,1 (*# of addresses across rectangle to copy - 1*)
jnz @@MasksSet (*there's more than one address to draw *)
and bh,bl (*there's only one address, so combine the left*)
(* and right edge clip masks *)
@@MasksSet:
mov ax,ScrY2
sub ax,SrcY1 (* AX = height of rectangle *)
jle @@CopyDone (*skip if 0 or negative height *)
mov Height,ax
mov ax,ScrnLogicalPixelWidth
shr ax,1;shr ax,1 (*convert to width in addresses *)
sub ax,cx (*distance from end of one dest scan line *)
dec ax (* to start of next *)
mov DestNextOffs,ax
mov ax,ScrnLogicalPixelWidth
shr ax,1;shr ax,1 (*convert to width in addresses *)
sub ax,cx (*distance from end of one source scan line*)
dec ax (* to start of next *)
mov SrcNextOffs,ax
mov RectAddrW,cx (*remember width in addresses - 1 *)
mov dx,SC_INDEX+1 (*point to Sequence Controller Data reg *)
(* (SC Index still points to Map Mask) *)
mov ax,es (*DS=ES=screen segment for MOVS *)
mov ds,ax
@@CopyRowsLoop:
mov cx,RectAddrW (*width across - 1 *)
mov al,bh (*put left-edge clip mask in AL *)
out dx,al (*set the left-edge plane (clip) mask *)
movsb (*copy the left edge (pixels go through *)
(* latches) *)
dec cx (*count off left edge address *)
js @@CopyLoopBottom (*that's the only address *)
jz @@DoRightEdge (*there are only two addresses *)
mov al,00fh (*middle addresses are drawn 4 pix per go*)
out dx,al (*set the middle pixel mask to no clip *)
rep movsb (*draw the middle addresses four pix per go *)
(* (pixels copied through latches) *)
@@DoRightEdge:
mov al,bl (*put right-edge clip mask in AL *)
out dx,al (*set the right-edge plane (clip) mask *)
movsb (*draw the right edge (pixels copied through *)
(* latches) *)
@@CopyLoopBottom:
add si,SrcNextOffs (*point to the start of *)
add di,DestNextOffs (* next source & dest lines *)
dec word ptr Height (*count down scan lines *)
jnz @@CopyRowsLoop
@@CopyDone:
mov dx,GC_INDEX+1 (*restore the bit mask to its default, *)
mov al,0ffh (* which selects all bits from the CPU *)
out dx,al (* and none from the latches (the GC *)
(* Index still points to Bit Mask) *)
pop ds
end;
(* *)
(* Copy a rectangular region of a VGA screen, with x coordinates *)
(* rounded to the nearest byte -- source and destination may overlap. *)
(* *)
(* *)
(* SrcRight is rounded up, and the left edges are rounded down, to ensure *)
(* that the pixels pointed to by the arguments are inside the rectangle. *)
(* *)
(* The width of the rectangle in bytes (width in pixels / 4) *)
(* cannot exceed 255. *)
(* *)
procedure x_shift_rect(ScrX1,ScrY1,ScrX2,ScrY2,DestX1,DestY1:Word);assembler;
{ARG SrcLeft,SrcTop,SrcRight,SrcBottom,DestLeft,DestTop,ScreenOffs:word}
var width_temp:Word;
asm
push ds
(* find values for width & x motion *)
mov si, ScrX1 (* source x in bytes *)
shr si, 1
shr si, 1
mov di, DestX1 (* destination x in bytes *)
shr di, 1
shr di, 1
mov bx, ScrX2 (* right edge of source in bytes, rounded up *)
add bx, 3
shr bx, 1
shr bx, 1
sub bx, si
mov ax, bx (* width - 1 *)
inc bx (* we'll use this as an offset for moving up or down *)
mov width_temp, bx
cld (* by default, strings increment *)
cmp si, di
jge @@MovingLeft
(* we're moving our rectangle right, so we copy it from right to left *)
add si, ax (* source & destination will start on the right edge *)
add di, ax
neg bx
std (* strings decrement *)
@@MovingLeft:
(* find values for height & y motion *)
mov cx, ScrnLogicalByteWidth (* bytes to move to advance one line *)
mov ax, ScrY1
mov dx, DestY1 (* default destination y *)
cmp ax, dx
jge @@MovingUp
(* we're moving our rectangle down, so we copy it from bottom to top *)
mov ax, ScrY2 (* source starts at bottom *)
add dx, ax (* add (height - 1) to destination y *)
sub dx, ScrY1
neg cx (* advance up screen rather than down *)
@@MovingUp:
push dx (* save destination y during multiply *)
mul ScrnLogicalByteWidth
add si, ax (* add y in bytes to source *)
pop ax (* restore destination y *)
mul ScrnLogicalByteWidth
add di, ax (* add y in bytes to destination *)
sub cx, bx (* final value for moving up or down *)
add si, ScreenOfs (* source & destination are on the same screen *)
add di, ScreenOfs
mov dx, SC_INDEX (* set map mask to all four planes *)
mov ax, 00f02h
out dx, ax
mov dx, GC_INDEX (* set bit mask to take data from latches *)
mov ax, BIT_MASK (* rather than CPU *)
out dx, ax
mov ax, SCREEN_SEG (* source and destination are VGA memory *)
mov es, ax
mov ds, ax
mov ah, byte ptr width_temp (* width in bytes should fit in 8 bits *)
mov bx, ScrY2 (* height - 1 *)
sub bx, ScrY1
mov dx, cx (* bytes to add to advance one line *)
xor ch, ch (* ready to rock *)
@@LineLoop:
mov cl, ah (* load width in bytes *)
rep movsb (* move 4 pixels at a time using latches (YOW!) *)
add si, dx (* advance source by one line *)
add di, dx (* advance destination by one line *)
dec bx (* line counter *)
jge @@LineLoop (* 0 still means one more to go *)
mov dx, GC_INDEX + 1(* set bit mask to take data from CPU (normal setting) *)
mov al, 0ffh
out dx, al
(* kick *)
pop ds
end;
end.