[Back to GRAPHICS SWAG index] [Back to Main SWAG index] [Original]
{Written By : Wesley Burns }
{Email : microcon@iafrica.com }
{Email: me if you have ANY questions about }
{ : 64k DMA Sound Blaster Programming using XMS }
{ : Fast Memory Management }
{ : PCX using XMS }
{ : XMS Units }
{ : Pascal in general }
{ : Or if you have some fast procedures that you don't mind parting with. }
PROGRAM FastClipMask;
{values: . x,y :coords of picture
. width,height:width and height of picture
. maskcolor :color to leave out
. Sprite :Souce of picture(Pointer)
. Dest :Pointer of destionation e.g Dest = ptr($a000:0000)}
var Pic,VScreen,BScreen:Pointer;
Counter:word;
time:real;
color:integer;
{General Timer}
Function timer:real;begin timer:=meml[$0040:$006c]/18.2; end;
{Wait for vertical retrace, to stop flicker}
Procedure WaitRetrace; Begin while ((Port[$3DA] AND 8) > 0) do; while
((Port[$3DA] AND 8) = 0) do; End;
{Much Faster that pascal Move Command}
procedure DMove (var source, dest; count: word); assembler;
asm
push ds
lds si,source {ds,si = source}
les di,dest {es,di = dest}
mov cx,count {cx = count}
mov ax,cx {ax = count}
cld
shr cx,2 {cx = count / 4}
db 66h
rep movsw {copy double words}
mov cl,al {get rest bytes}
and cl,3
rep movsb {copy rest}
pop ds
end;
{Mask Picture}
Procedure MaskPic(X,Y,Width,Height:integer; Maskcolor:byte; Sprite,
Dest:Pointer);
Begin
If (x <= -width) or (x >= 320) or (y <= -height) or (y >= 200) then exit;
{The above command checks to seek if the picture TOTAL runs of the scneen.}
{This is so, because if the below procedure is given a picture that falls}
{total past >= 320X200 then it screws up.}
Asm
PUSH DS { save DS. Turbo Pascal automatically }
{ saves other registers (ES SI DI) }
LDS SI,Sprite { Make DS:SI point to image data }
MOV AX,WIDTH { store width in variable }
MOV DX,AX
PUSH DX { Save width for use with the }
{ actual screen copying }
ADD AX,X { Add X to width, check for right side cut }
PUSH Width { save origonal width for possible top cutting }
CMP AX,320 { Check for right side clipping }
JG @RightCut
SUB AX,X { Check for left side clipping }
JC @LeftCut
JMP @CheckBottom { no clipping necessary on sides }
@RightCut:
SUB AX,Width
SUB AX,320
NEG AX { AX= -(new width), NEG to get + value }
MOV Width,AX { set new width according to rightclip }
JMP @CheckBottom
@LeftCut:
ADD AX,X
MOV Width,AX { set width according to left clip }
SUB DX,AX
ADD SI,DX
XOR BX,BX
MOV X,BX { recalculate X parameter }
@CheckBottom:
MOV AX,Height
ADD AX,Y
CMP AX,200 { Check for bottom cut }
JG @BottomCut
SUB AX,Y { Check for top cut }
JC @TopCut
POP BX { Saved Width is no longer necessary }
{ so remove it from the stack }
JMP @Display { no clipping on bottom necessary }
@BottomCut:
POP BX { remove saved width from stack }
{ no longer necessary }
SUB AX,Height
SUB AX,200
NEG AX
MOV Height,AX { adjust height according to clip}
JMP @Display
@TopCut:
ADD AX,Y
POP BX { retreive saved width value }
PUSH AX { save AX, which is new height value }
MOV AX,Y
NEG AX
IMUL BX
ADD SI,AX { adjust starting offset in sprite data }
{ according to the top cut }
POP AX { retrieve new height value }
MOV Height,AX { adjust height according to clip}
MOV BX,0
MOV Y,BX { Recalculate Y parameter }
@Display:
{ les AX,dest}
{ MOV di,AX}
LES di,dest
{ XOR DI,DI { Make ES:DI point to A000h:0000h}
MOV AX,320
IMUL [Y]
MOV DI,AX
ADD DI,X { Calculate screen offset }
POP DX { Retrieve origional width }
MOV BX,Width { Store values in registers }
MOV CX,Height { for optimal speed }
{ The actual sprite is copied here.
The Byte Ptr operations are used because they are faster
than LODSB and STOSB on 386+ CPUs! Change it and see
for yourself! The same is true with the DEC CX/JNZ
instead of the LOOP instruction }
@HeightLoop: { Loop for height }
PUSH SI
PUSH DI
PUSH CX
MOV CX,BX
@WidthLoop: { Loop for width }
MOV AL,Byte Ptr [DS:SI] { get 1 byte of sprite data }
CMP AL,Maskcolor { check for "transparent" color }
JZ @Skipped
MOV Byte Ptr [ES:DI],AL { Store sprite data onto screen }
@Skipped:
INC SI
INC DI
DEC CX
JNZ @WidthLoop
POP CX
POP DI
POP SI
ADD DI,320 { Increment video memory by 1 line }
ADD SI,DX { Increment Sprite data by 1 line (DX=Width)}
DEC CX
JNZ @HeightLoop
POP DS
{all done, whew!}
End;
End;
Begin
asm; mov ax,13h;int 10h;end;
Getmem(Pic,40000); {50x50 picture}
GetMem(VScreen,64000); {Virtual Screen, Scratch Pad}
GetMem(BScreen,64000); {Background, holds "game scenery"}
Fillchar(VScreen^,64000,0);
Fillchar(BScreen^,64000,4);
Color := 0;
{make picture}
for counter := 0 to 40000 do
begin color := not color;
IF COLOR = -1 THEN mem[seg(Pic^):counter] := 0;
IF COLOR = 0 THEN mem[seg(Pic^):counter] := random(2)+1;
end;
{Animate }
time:=timer;
for counter := 0 to 199 do
begin
{picture has black(0) and blue(1) stripes, masking only Black(0)}
{ | mask color, try changing it. }
MaskPic(counter,counter, 200, 200, 0, Pic, VScreen); {Draw Picture To
VIRTUAL SCREEN}
DMove(VScreen^, mem[$A000:0000], 64000); {Move VScreen to
Screen($a000:0000)}
DMove(BScreen^, VScreen^, 64000); {Restore Background screen}
WaitRetrace;
end;
{Shut Down}
asm; mov ax,03h;int 10h;end;
writeln;
writeln('With Background Updating, Copying to screen and Wait Retrace');
writeln(' Tested on 486-DX4-100MHz : 2.91 seconds for 100x200x200 frames');
writeln(' On This machine for 100x 200x200 frames : ', timer-time:3:2, 'seconds');
Freemem(Pic,40000);
FreeMem(VScreen,64000);
FreeMem(BScreen,64000);
End.
[Back to GRAPHICS SWAG index] [Back to Main SWAG index] [Original]