{ > Would you please repost code of: > "the SpriteWidth, SpriteHeight, SpriteWidthExact, and flipping functions > you posted here quite a while ago" ? Scanning through my database resulted in the following 2 snippets of code for AniVGA V1.2 (again: it's only a quick-'n-dirty hack, use on your own risk, no support, no guarantees that the next version of AniVGA will have these routines!): } {for the INTERFACE-section:} FUNCTION SpriteHeight(Sp:WORD):WORD; FUNCTION SpriteWidth(Sp:WORD):WORD; FUNCTION SpriteWidthExact(Sp:WORD):WORD; PROCEDURE ExchangeColor(Sp:WORD; oldColor,newColor:BYTE); PROCEDURE MirrorSpriteVertical(Sp:WORD); {for the IMPLEMENTATION-section:} FUNCTION SpriteHeight(Sp:WORD):WORD; { in: Sp = SpriteLADEnummer, dessen Hoehe ermittelt werden soll} {out: Die Hoehe des Sprites in Zeilen oder 0, wenn gar kein Sprite geladen} VAR ad:WORD; BEGIN ad:=SPRITEAD[Sp]; IF (ad=0) THEN SpriteHeight:=0 {Sprite noch nicht geladen} ELSE SpriteHeight:=MEMW[ad:Hoehe] END; FUNCTION SpriteWidth(Sp:WORD):WORD; { in: Sp = SpriteLADEnummer, dessen Breite ermittelt werden soll} {out: Die Breite des Sprites in Zeilen oder 0, wenn gar kein Sprite geladen} {rem: Der ermittelte Wert kann um bis zu 3 Punkte zu gross sein} VAR ad:WORD; BEGIN ad:=SPRITEAD[Sp]; IF (ad=0) THEN SpriteWidth:=0 {Sprite noch nicht geladen} ELSE SpriteWidth:=MEMW[ad:Breite] SHL 2 END; FUNCTION SpriteWidthExact(Sp:WORD):WORD; { in: Sp = SpriteLADEnummer, dessen Breite ermittelt werden soll} {out: Die Breite des Sprites in Zeilen oder 0, wenn gar kein Sprite geladen} {rem: Der ermittelte Wert ist exakt, allerdings dauert die Routine etwas} { laenger als SpriteWidth() } VAR ad,i,temp,planeOFS:WORD; BEGIN ad:=SPRITEAD[Sp]; IF (ad=0) THEN SpriteWidthExact:=0 {Sprite noch nicht geladen} ELSE BEGIN temp:=0; planeOFS:=MEMW[ad:Right]; FOR i:=0 TO MEMW[ad:Hoehe]-1 DO BEGIN IF MEMW[ad:planeOFS]>temp THEN temp:=MEMW[ad:planeOFS]; INC(planeOFS,2) END; SpriteWidthExact:=temp+1 END; END; PROCEDURE ExchangeColor(Sp:WORD; oldColor,newColor:BYTE); { in: Sp = SpriteLADEnummer des Sprites} { oldColor = auszutauschende Farbe} { newColor = neue Farbe} {out: Alle oldColor Farbwerte des Sprites Sp wurden gegen newColor ersetzt} {rem: Evtl. neue Grenzen, die sich daraus ergeben koennten, wenn eine der} { Farben 0 ist, werden nicht neuberechnet} VAR ad,i,oneplanesize,planeOFS:WORD; BEGIN ad:=SPRITEAD[Sp]; IF (ad<>0) THEN BEGIN oneplanesize:=MEMW[ad:Breite]*MEMW[ad:Hoehe]; {Groesse einer Spriteplane} FOR i:=0 TO 3 DO BEGIN planeOFS:=MEMW[ad:i SHL 1]; ASM MOV ES,ad MOV DI,planeOFS CLD MOV AL,oldColor MOV DL,newColor MOV CX,oneplanesize @goon: REPNE SCASB JNZ @nomatch MOV ES:[DI-1],DL @nomatch: JCXZ @done JMP @goon @done: END; {of ASM} END; {of FOR} END; {of IF} END; PROCEDURE RevertWordArray(p:POINTER; len:WORD); ASSEMBLER; { in: p = Anfangsadresse eines Speicherbereichs,} { len = Laenge dieses Bereichs in Worten} {out: Die Reihenfolge der Worte p[0*2]..p[(len-1)*2] wurde gespiegelt} ASM MOV CX,len MOV BX,CX DEC BX SHL BX,1 SHR CX,1 JCXZ @fertig LDS SI,p MOV DI,DS MOV ES,DI MOV DI,SI ADD DI,BX {DS:SI = 1.Word des Arrays, ES:DI = letztes Word des Arrays} STD @oneword: MOV AX,ES:[DI] XCHG AX,[SI] STOSW INC SI INC SI LOOP @oneword CLD MOV AX,SEG @Data MOV DS,AX @fertig: END; PROCEDURE RevertByteGroups(p:POINTER; GroupsCount, GroupLen:WORD); ASSEMBLER; { in: p = Anfangsadresse eines Speicherbereichs,} { GroupsCount = Anzahl Gruppen innerhalb dieses Bereichs,} { GroupLen = Laenge einer einzelnen Gruppe in Bytes} {out: Die Reihenfolge der Gruppen wurde gespiegelt} {rem: Bsp.: 4 Gruppen a 3 Bytes: 01,02,03, 04,05,06, 07,08,09, 10,11,12} { nach dem Aufruf : 10,11,12, 07,08,09, 04,05,06, 01,02,03} ASM MOV CX,GroupsCount MOV AX,CX SHR CX,1 JCXZ @fertig DEC AX MOV BX,GroupLen MUL BX LDS SI,p MOV DI,DS MOV ES,DI MOV DI,SI ADD DI,AX {DS:SI = 1.Byte der 1.Gruppe, ES:DI = 1.Byte der letzten Gruppe,} {BX = Breite einer Gruppe, CX = Anzahl Gruppen} CLD @outer: MOV DX,BX @inner: MOV AL,ES:[DI] XCHG AL,[SI] STOSB INC SI DEC DX JNZ @inner SUB DI,BX SUB DI,BX LOOP @outer MOV AX,SEG @Data MOV DS,AX @fertig: END; PROCEDURE MirrorBoundaries(p:POINTER; len,m:WORD); ASSEMBLER; { in: p = Zeiger auf Anfang eines Wort-Bereiches,} { len = Anzahl zu bearbeitende Worte,} { m = Maximalwert, um den gespiegelt werden soll} {out: Die Werte des Bereichs wurden um (m-0)/2 gespiegelt;} { Bsp.: [....a...b.] mit m=9 sollte gespiegelt (bei (9-0)/2 = 4.5) so aus-} { 0123456789 { sehen:[.b...a....]} { Dadurch veraendern sich die Grenzen: Ist m der Maximalwert, so gilt fuer} { die neuen Grenzen: neu:=(m-0)-alt} {rem: Die Sentinelwerte *16000 werden nicht veraendert!} ASM MOV CX,len JCXZ @fertig CLD MOV DX,m LES DI,p LDS SI,p @oneword: LODSW CMP AX,+16000 JE @next CMP AX,-16000 JE @next NEG AX ADD AX,DX STOSW @next: LOOP @oneword MOV AX,SEG @Data MOV DS,AX @fertig: END; PROCEDURE MirrorSpriteVertical(Sp:WORD); { in: Sp = SpriteLADEnummer, das vertikal gespiegelt werden soll} {out: Das Sprites Sp wurde vertikal gespiegelt} VAR ad,i,zeilen,spalten:WORD; BEGIN ad:=SPRITEAD[Sp]; IF (ad<>0) THEN BEGIN zeilen :=MEMW[ad:Hoehe]; spalten:=MEMW[ad:Breite]; {Zeilendaten per "Butterfly" vertauschen, fuer alle 4 Ebenen:} FOR i:=0 TO 3 DO RevertByteGroups(PTR(ad,MEMW[ad:i SHL 1]),zeilen,spalten); {Grenzdaten des oberen und unteren Spriterandes korrigieren:} MirrorBoundaries(PTR(ad,MEMW[ad:Top]),spalten SHL 2,zeilen-1); MirrorBoundaries(PTR(ad,MEMW[ad:Bottom]),spalten SHL 2,zeilen-1); {nun obere gegen untere Grenzdaten austauschen:} i:=MEMW[ad:Top]; MEMW[ad:Top]:=MEMW[ad:Bottom]; MEMW[ad:Bottom]:=i; {Grenzdaten des linken und rechten Spriterandes mittauschen:} RevertWordArray(PTR(ad,MEMW[ad:Left]),zeilen); RevertWordArray(PTR(ad,MEMW[ad:Right]),zeilen); END; END; {___snippet two___} {The difference between the two routines is solely *where* the mirroring takes place: as default, the axis will be placed exactly in the midst of the sprite. However, as sprites are stored in multiples of 4 pixels in the X-direction, this "slack" of up to 3 pixels may be used to shift the mirror axes a bit to the right. --Don't think much about it: just use a sprite with a width of 5 pixels. (This will be rounded up to 2*4=8 pixels by MAKES automatically). Then run a small demo program and use Xshift values 0..3 to see what happens} {for the INTERFACE-section:} PROCEDURE MirrorSpriteHorizontalWithXShift(Sp,Xshift:WORD); PROCEDURE MirrorSpriteHorizontal(Sp:WORD); {for the IMPLEMENTATION-section:} PROCEDURE RevertByteArray(p:POINTER; len:WORD); ASSEMBLER; { in: p = Anfangsadresse eines Speicherbereichs,} { len = Laenge dieses Bereichs in Bytes} {out: Die Reihenfolge der Bytes p[0]..p[len-1] wurde gespiegelt} ASM MOV CX,len MOV BX,CX DEC BX SHR CX,1 JCXZ @fertig LDS SI,p MOV DI,DS MOV ES,DI MOV DI,SI ADD DI,BX {DS:SI = 1.Byte des Arrays, ES:DI = letztes Byte des Arrays} STD @onebyte: MOV AL,ES:[DI] XCHG AL,[SI] STOSB INC SI LOOP @onebyte CLD MOV AX,SEG @Data MOV DS,AX @fertig: END; PROCEDURE MirrorSpriteHorizontalWithXShift(Sp,Xshift:WORD); { in: Sp = SpriteLADEnummer, das horizontal gespiegelt werden soll} { Xshift = Offset, um die Spiegelachse zusaetzlich verschoben werden soll} {out: Das Sprite Sp wurde horizontal gespiegelt} {rem: Normalerweise wird das Sprite um seine _tatsaechliche_ Mitte gespiegelt} { (=per SpriteSpriteWidthExact() ermittelt). Da das Sprite jedoch in X- } { Richtung als Vielfaches von 4 gespeichert wird, kann das Zentrum der } { Spiegelung noch geringfuegig verschoben werden!} { Bsp.: Sprite ist 5 Punkte breit -> abgespeichert in 2 4er-Gruppen -> } { Spiegelung kann so erfolgen, als ob es 5,6,7 oder 8 Punkte breit} { waere; XShift kann somit die Werte 5-5=0 .. 8-5=3 annehmen!} TYPE ByteAt=ARRAY[0..65534] OF BYTE; VAR ad,i,j,index,zeilen,spalten,exBreite,plane0,plane1,plane2,plane3:WORD; p:POINTER; BEGIN ad:=SPRITEAD[Sp]; IF (ad<>0) THEN BEGIN zeilen :=MEMW[ad:Hoehe]; spalten:=MEMW[ad:Breite]; exBreite:=SpriteWidthExact(Sp)+Xshift; {Xshift-Addition darf nicht dazu fuehren, dass Sprite "aus dem } {Rahmen" faellt:} IF exBreite>spalten SHL 2 THEN exBreite:=spalten SHL 2; GetMem(p,spalten SHL 2); {Speicher fuer 1 Zeile} plane0:=MEMW[ad: 0 SHL 1]; plane1:=MEMW[ad: 1 SHL 1]; plane2:=MEMW[ad: 2 SHL 1]; plane3:=MEMW[ad: 3 SHL 1]; index:=0; {Invariante: index = i*spalten + j} FOR i:=0 TO zeilen-1 DO BEGIN {Zeile expandieren:} FOR j:=0 TO spalten-1 DO BEGIN ByteAt(p^)[j SHL 2 +0]:=MEM[ad:plane0 +index]; ByteAt(p^)[j SHL 2 +1]:=MEM[ad:plane1 +index]; ByteAt(p^)[j SHL 2 +2]:=MEM[ad:plane2 +index]; ByteAt(p^)[j SHL 2 +3]:=MEM[ad:plane3 +index]; INC(index) END; {Zeile spiegeln:} RevertByteArray(p,exBreite); {Zeile zurueckspeichern:} DEC(index,spalten); {auf Anfang der Zeile positionieren} FOR j:=0 TO spalten-1 DO BEGIN MEM[ad:plane0 +index]:=ByteAt(p^)[j SHL 2 +0]; MEM[ad:plane1 +index]:=ByteAt(p^)[j SHL 2 +1]; MEM[ad:plane2 +index]:=ByteAt(p^)[j SHL 2 +2]; MEM[ad:plane3 +index]:=ByteAt(p^)[j SHL 2 +3]; INC(index) END; END; FreeMem(p,spalten SHL 2); {Grenzdaten des linken und rechten Spriterandes korrigieren:} MirrorBoundaries(PTR(ad,MEMW[ad:Left]),zeilen,exBreite-1); MirrorBoundaries(PTR(ad,MEMW[ad:Right]),zeilen,exBreite-1); {nun linke gegen rechte Grenzdaten austauschen:} i:=MEMW[ad:Left]; MEMW[ad:Left]:=MEMW[ad:Right]; MEMW[ad:Right]:=i; {Grenzdaten des oberen und unteren Spriterandes mittauschen:} RevertWordArray(PTR(ad,MEMW[ad:Top]),exBreite); RevertWordArray(PTR(ad,MEMW[ad:Bottom]),exBreite); END; END; PROCEDURE MirrorSpriteHorizontal(Sp:WORD); { in: Sp = SpriteLADEnummer, das horizontal gespiegelt werden soll} {out: Das Sprites Sp wurde horizontal gespiegelt} BEGIN MirrorSpriteHorizontalWithXShift(Sp,0) END;