{$I386_INTEL}
USES GO32;
TYPE Sprite = record
dtx,dty : longint; { Breite, H”he des Sprites }
adr : pointer; { Speicher-Adresse an der das "Bild" beginnt }
end;
CONST ManBild : array[0..9,0..9]of byte= { Probe-Bild (soll ein Maennchen sein ;-) }
((0,0,0,0,1,1,0,0,0,0),
(0,0,0,1,9,9,1,0,0,0),
(8,8,0,0,1,1,0,0,8,8),
(0,1,1,0,1,1,0,1,1,0),
(0,0,1,1,1,1,1,1,0,0),
(0,0,0,0,1,1,0,0,0,0),
(0,0,0,0,1,1,0,0,0,0),
(0,0,0,1,1,1,1,0,0,0),
(0,0,1,1,0,0,1,1,0,0),
(0,8,8,0,0,0,0,8,8,0));
XRes : longint=320;
YRes : longint=200;
VAR VideoBuffer : pointer;
Man : sprite;
PROCEDURE InitVGAMode(mode : word);
Var regs : trealregs;
BEGIN
regs.ax:=mode;
realintr($10,regs);
END;
PROCEDURE TransSprite(dest : pointer; x,y : longint; spr : sprite);
Var clipl,clipr,clipo, destskip,sprskip, sprdtx,sprdty : longint; spradr : pointer;
BEGIN
with spr do begin
x-=dtx shr 1; { Wird ben”tigt, um das Sprite "mittig" zu setzen }
y-=dty shr 1; { -> Bsp. x=160/y=100 -> Mittelpunkt des Sprites ist bei 160/100 }
if (x+dtx<0) or (x>=xres) or (y+dty<0) or (y>=yres) then exit;
{ links auáerhalb, rechts auáerhalb, oben auáerhalb, unten auáerhalb ?? Wenn ja -> raus }
clipr:=0; { Alle Variablen 0 = kein Abschneiden (Clipping) }
clipl:=0;
clipo:=0;
if (y<0) then begin clipo:=-y*dtx; dty+=y; y:=0; end;
if (y+dty>=yres) then dty:=yres-y;
if (x<0) then begin clipl:=-x; dtx+=x; x:=0; end;
if (x+dtx>=xres) then begin clipr:=(x+dtx)-xres; dtx:=xres-x; end;
{ Wenn am Rand, dann Spritel„nge/h”he, x/y und Clipping-Variablen ver„ndern }
if (dtx<=0) or (dty<=0) then exit;
{ Zur Sicherheit berprfen, ob durch Clipping gar nichts mehr darzustellen ist }
dest+=x+y*xres; { Im Videospeicher an Anfangs-Zeichen-Position des Sprites rcken }
adr+=clipo+clipl; { Im "Spritespeicher" an erstes Pixel rcken, das dargestellt wird }
destskip:=xres-dtx; { Um diesen Wert mssen wir pro gezeichneter (waagrechter) Linie im Videospeicher weiter }
sprskip:=clipl+clipr; { Das gleiche fr den Spritespeicher (Bei Clipping !!) }
spradr:=adr; { HilfsVariablen (FPC kann leider nicht auf den Sprite-Record ber ASM zugreifen :-( }
sprdtx:=dtx;
sprdty:=dty;
ASM
cld
mov edi,dest
mov esi,spradr
mov edx,sprdty
@@yloop:
mov ecx,sprdtx
@@xloop:
lodsb { Pixel laden }
or al,al { Pixel = 0 ? }
jz @@go
mov [edi],al { Nein, also setzen }
@@go: { Sonst normal im Speicher weiter }
inc edi
dec ecx { Noch mehr Pixel in X-Richtung ? }
jnz @@xloop
add esi,sprskip
add edi,destskip
dec edx { Noch mehr Zeilen in Y-Richtung ? }
jnz @@yloop
END ['EDI', 'ESI', 'EDX', 'ECX', 'EAX'];
end;
END;
PROCEDURE SolidSprite(dest : pointer; x,y : longint; spr : sprite);
Var clipl,clipr,clipo, destskip,sprskip, sprdtx,sprdty : longint; spradr : pointer;
BEGIN
with spr do begin
x-=dtx shr 1; { Wird ben”tigt, um das Sprite "mittig" zu setzen }
y-=dty shr 1; { -> Bsp. x=160/y=100 -> Mittelpunkt des Sprites ist bei 160/100 }
if (x+dtx<0) or (x>=xres) or (y+dty<0) or (y>=yres) then exit;
{ links auáerhalb, rechts auáerhalb, oben auáerhalb, unten auáerhalb ?? Wenn ja -> raus }
clipr:=0; { Alle Variablen 0 = kein Abschneiden (Clipping) }
clipl:=0;
clipo:=0;
if (y<0) then begin clipo:=-y*dtx; dty+=y; y:=0; end;
if (y+dty>=yres) then dty:=yres-y;
if (x<0) then begin clipl:=-x; dtx+=x; x:=0; end;
if (x+dtx>=xres) then begin clipr:=(x+dtx)-xres; dtx:=xres-x; end;
{ Wenn am Rand, dann Spritel„nge/h”he, x/y und Clipping-Variablen ver„ndern }
if (dtx<=0) or (dty<=0) then exit;
{ Zur Sicherheit berprfen, ob durch Clipping gar nichts mehr darzustellen ist }
dest+=x+y*xres; { Im Videospeicher an Anfangs-Zeichen-Position des Sprites rcken }
adr+=clipo+clipl; { Im "Spritespeicher" an erstes Pixel rcken, das dargestellt wird }
destskip:=xres-dtx; { Um diesen Wert mssen wir pro gezeichneter (waagrechter) Linie im Videospeicher weiter }
sprskip:=clipl+clipr; { Das gleiche fr den Spritespeicher (Bei Clipping !!) }
spradr:=adr; { HilfsVariablen (FPC kann leider nicht auf den Sprite-Record ber ASM zugreifen :-( }
sprdtx:=dtx;
sprdty:=dty;
ASM
cld
mov edi,dest
mov esi,spradr
mov edx,sprdty
@@yloop:
mov ecx,sprdtx
rep movsb { Alle Pixel in X-Richtung am Stck setzen }
add esi,sprskip
add edi,destskip
dec edx { Noch mehr Zeilen in Y-Richtung ? }
jnz @@yloop
END ['EDI', 'ESI', 'EDX', 'ECX'];
end;
END;
BEGIN
getmem(videobuffer,64000);
initvgamode($13); { 320x200,256 }
man.adr:=@manbild; { Adresse des Sprites gleich Adresse unseres "Bildes" }
man.dtx:=10; { Breite=10 }
man.dty:=10; { H”he=10 }
fillchar(videobuffer^,64000,10); { "Hintergrund" = Farbe 10 }
transsprite(videobuffer,80,100,man); { Transparentes Sprite }
solidsprite(videobuffer,240,100,man); { Undurchsichtiges Sprite }
dosmemput($a000,0,videobuffer^,64000); { BUFFER AN $a000:0 KOPIEREN }
readln;
initvgamode($3); { TEXTMODUS }
freemem(videobuffer,64000);
END.
{ P.S. Natrlich k”nnen die Routinen noch etwas ;-) optimiert werden... }
{ P.P.S. Alle bisherigen Lektionen arbeiten auch mit dem PMODE/DJ-Extender
und selbstverst„ndlich auch Win9x zusammen... }