{$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... }