[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]