(* $R- $S- $V- *)

MODULE VSpriteDemo;

(* Einfaches VSprite-Demo ... by H.G. *)

FROM Arts      IMPORT Assert;
FROM SYSTEM    IMPORT ADR,ADDRESS,BITSET,INLINE;
FROM Intuition IMPORT NewWindow,WindowPtr,OpenWindow,WindowFlagSet,customScreen,
                      CloseWindow,IDCMPFlags,IDCMPFlagSet,ViewAddress,
                      NewScreen,ScreenPtr,OpenScreen,CloseScreen,WindowFlags;
FROM Graphics  IMPORT ViewModes,ViewModeSet,VSprite,ViewPortPtr,
                      AddVSprite,GelsInfo,RemVSprite,SortGList,InitGels,
                      MrgCop,LoadView,VSpriteFlags,VSpriteFlagSet,CollTable,
                      RastPortPtr,DrawGList,MakeVPort;
FROM Exec      IMPORT AllocMem,MemReqs,MemReqSet,FreeMem,GetMsg,ReplyMsg,
                      WaitPort;
FROM Dos       IMPORT Delay;

TYPE CardPtr = POINTER TO CARDINAL;

VAR VSprites      : ARRAY[0..11] OF VSprite;
    vsFirst,vsLast: VSprite;
    Window        : WindowPtr;
    Screen        : ScreenPtr;
    WindowDaten   : NewWindow;
    ScreenDaten   : NewScreen;
    TheGelsInfo   : GelsInfo;
    ViewPort      : ViewPortPtr;
    RastPort      : RastPortPtr;
    ChipSprite    : ARRAY[0..11] OF CardPtr;
    i,j           : INTEGER;
    SprColors     : ARRAY[0..11],[0..2] OF CARDINAL;

(* Dies ist eine Prozedur, um Daten aus dem FAST- ins CHIP-Memory
   zu kopieren. Folgende Parameter werden benötigt:

   source: Zeiger auf die eigentlichen (FAST-Memory)-Daten, z.B.
           die INLINE-Datenprozedur.
   dest  : Zeiger auf den (CHIP-)Speicherbereich, in den die Daten
           kopiert werden sollen.
   size  : Anzahl der zu kopierenden Bytes. *)

PROCEDURE ChipCopy(source: CardPtr; VAR dest: CardPtr; size: LONGCARD);

VAR ChipPtr: CardPtr;
    copied : LONGCARD;

  BEGIN
    ChipPtr:=AllocMem(size,MemReqSet{chip});
    dest:=ChipPtr;
    copied:=0;
    REPEAT
      ChipPtr^:=source^;
      INC(ChipPtr,2); INC(source,2); INC(copied,2);
    UNTIL copied=size;
  END ChipCopy;

(* Hier steht die INLINE-Datenprozedur mit den Spritedaten.
   Jedes Sprite hat das Aussehen eines bunten Quadrats.     *)

PROCEDURE SpriteDaten; (* $E- *)
  BEGIN
    INLINE(0FFFFH,00000H);
    INLINE(0FF81H,03F80H);
    INLINE(0FFC1H,01FC0H);
    INLINE(0FFE1H,00FE0H);
    INLINE(0FFF1H,007F0H);
    INLINE(0FFF9H,003F8H);
    INLINE(0FFFDH,001FCH);
    INLINE(0FFFFH,000FEH);
    INLINE(0BFFFH,0407EH);
    INLINE(09FFFH,0603EH);
    INLINE(08FFFH,0701EH);
    INLINE(087FFH,0780EH);
    INLINE(083FFH,07C06H);
    INLINE(081FFH,07E02H);
    INLINE(080FFH,07F00H);
    INLINE(0FFFFH,00000H);
  END SpriteDaten;

BEGIN

  (* Farben jedes Sprite initialisieren ... *)

  SprColors[0][0]:=000FH; SprColors[0][1]:=0F00H; SprColors[0][2]:=0FF0H;
  SprColors[1][0]:=0F00H; SprColors[1][1]:=000FH; SprColors[1][2]:=0FF0H;
  SprColors[2][0]:=0FF0H; SprColors[2][1]:=0F00H; SprColors[2][2]:=000FH;
  SprColors[3][0]:=0FF0H; SprColors[3][1]:=000FH; SprColors[3][2]:=0F00H;
  SprColors[4][0]:=0F00H; SprColors[4][1]:=0FF0H; SprColors[4][2]:=000FH;
  SprColors[5][0]:=000FH; SprColors[5][1]:=0FF0H; SprColors[5][2]:=0F00H;
  SprColors[6][0]:=0444H; SprColors[6][1]:=0888H; SprColors[6][2]:=0CCCH;
  SprColors[7][0]:=0444H; SprColors[7][1]:=0CCCH; SprColors[7][2]:=0888H;
  SprColors[8][0]:=0CCCH; SprColors[8][1]:=0444H; SprColors[8][2]:=0888H;
  SprColors[9][0]:=0CCCH; SprColors[9][1]:=0888H; SprColors[9][2]:=0444H;
  SprColors[10][0]:=0888H; SprColors[10][1]:=0CCCH; SprColors[10][2]:=0444H;
  SprColors[11][0]:=0444H; SprColors[11][1]:=0CCCH; SprColors[11][2]:=0888H;

  (* Alle 12 VSprites initialisieren und ins CHIP-Memory kopieren.
     Die Felder für Kollisionen werden noch nicht initialisiert, da hier
     keine Kollisionen benutzt werden. *)

  FOR i:=0 TO 11 DO

    ChipSprite[i]:=NIL;
    ChipCopy(ADR(SpriteDaten),ChipSprite[i],64);

    WITH VSprites[i] DO
      flags:=VSpriteFlagSet{vsprite}; y:=20*i; x:=20*i; height:=16; width:=1;
      depth:=2; meMask:=BITSET{}; hitMask:=BITSET{}; imageData:=ChipSprite[i];
      sprColors:=ADR(SprColors[i]); nextVSprite:=NIL; prevVSprite:=NIL;
      drawPath:=NIL; clearPath:=NIL; oldX:=0; oldY:=0; borderLine:=NIL;
      collMask:=NIL; vsBob:=NIL; planePick:=0; planeOnOff:=0;
    END;

  END;

  (* Die GelsInfo-Struktur initialisieren *)
  (* und benötigten Speicher holen.       *)

  WITH TheGelsInfo DO
    sprRsrvd:=0FFH; collHandler:=NIL; flags:=0; gelHead:=NIL;
    gelTail:=NIL; firstBlissObj:=NIL; lastBlissObj:=NIL;
    nextLine:=AllocMem(16,MemReqSet{public,memClear});
    lastColor:=AllocMem(32,MemReqSet{public,memClear});
    leftmost:=0; rightmost:=320; topmost:=0; bottommost:=256;
  END;

  (* Screen und Window öffnen. Ziemlich uninteressant! *)

  WITH ScreenDaten DO
    leftEdge:=0; topEdge:=0; width:=320; height:=256; depth:=5;
    detailPen:=0; blockPen:=1; viewModes:=ViewModeSet{sprites};
    type:=customScreen; font:=NIL; defaultTitle:=NIL; gadgets:=NIL;
    customBitMap:=NIL;
  END;

  WITH WindowDaten DO
    leftEdge:=0; topEdge:=0; width:=320; height:=256; detailPen:=1;
    blockPen:=0; idcmpFlags:=IDCMPFlagSet{mouseMove,closeWindow};
    flags:=WindowFlagSet{borderless}; firstGadget:=NIL; title:=NIL;
    screen:=NIL; bitMap:=NIL; checkMark:=NIL; type:=customScreen;
  END;

  Screen:=OpenScreen(ScreenDaten);
  Assert(Screen#NIL,ADR("Konnte Screen nicht öffnen!"));

  WindowDaten.screen:=Screen;
  Window:=OpenWindow(WindowDaten);
  Assert(Window#NIL,ADR("Konnte Window nicht öffnen!"));

  (* View- und RastPort schnappen: *)

  ViewPort:=ADR(Screen^.viewPort);
  RastPort:=Window^.rPort;

  (* GelsInfo einbinden und initialisieren ... *)

  RastPort^.gelsInfo:=ADR(TheGelsInfo);
  InitGels(ADR(vsFirst),ADR(vsLast),ADR(TheGelsInfo));

  (* 12 VSprites einbinden ... *)

  FOR i:=0 TO 11 DO
    AddVSprite(ADR(VSprites[i]),RastPort);
  END;

  (* Hier beginnt die Darstellung der VSprites durch Neuberechnen der
     GEL-Liste sowie deren Zeichnen und anschließende Neuberechnung der
     ViewPort-Zwischen-Copperlisten ... *)

  FOR i:=1 TO 50 DO

    FOR j:=0 TO 11 DO
      VSprites[j].x:=VSprites[j].x+1;           (* x-Koordinate verändern *)
    END;

    SortGList(RastPort);                        (* GEL-Liste sortieren *)
    DrawGList(RastPort,ViewPort);               (* GEL-Liste zeichnen *)
    MakeVPort(ViewAddress(),ViewPort);          (* Copperlists berechnen *)
    MrgCop(ViewAddress());                      (* Hardware-Copperlist
                                                   erstellen und ...  *)
    LoadView(ViewAddress());                    (* ... ausführen! *)

  END;

  (* s.o. *)

  FOR i:=50 TO 1 BY -1 DO

    FOR j:=0 TO 11 DO
      VSprites[j].x:=VSprites[j].x-1;
    END;

    SortGList(RastPort);
    DrawGList(RastPort,ViewPort);
    MakeVPort(ViewAddress(),ViewPort);
    MrgCop(ViewAddress());
    LoadView(ViewAddress());

  END;

  Delay(500);

  FOR i:=0 TO 11 DO
    RemVSprite(ADR(VSprites[i]));               (* VSprites entfernen *)
    FreeMem(ChipSprite[i],64);                  (* CHIP-Memory freigeben *)
  END;

  FreeMem(TheGelsInfo.nextLine,16);             (* nextLine freigeben *)
  FreeMem(TheGelsInfo.lastColor,32);            (* lastColor freigeben *)

  CloseWindow(Window);                          (* Window schließen *)
  CloseScreen(Screen);                          (* Screen schließen *)

END VSpriteDemo.
