[Back to EGAVGA SWAG index]  [Back to Main SWAG index]  [Original]

{
> 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;



[Back to EGAVGA SWAG index]  [Back to Main SWAG index]  [Original]