*
* Sprite-Demo
*
* written on 18/11/89  18:29:06  by Holger Gzella
*
* Dieses Programm erzeugt ein graues Gebilde (was das
* genau darstellen soll, bleibt Ihrer Fantasie über-
* lassen), das sich mit einem Joystick in Port 1
* horizontal(!) steuern läßt.
*
* ACHTUNG: Sobald die Sprites auf dem Bildschirm erscheinen,
*          flackern sie ca. 20 Sekunden lang, verhalten sich
*          danach aber völlig ruhig.
*          Wer weiß, woran das liegt oder sogar einen Ver-
*          besserungsvorschlag hat, möge mich benachrichtigen.
*

                incdir "asm:"
                include "exec/exec_lib.i"

MEMREQS         EQU     $10000|$2               * CHIP u. clear

StartIt:        lea     GfxName,a1              * Graphics öffnen
                moveq.l #0,d0
                CALLEXEC OpenLibrary
                move.l  d0,GfxBase

                move.l  #2000,d0                * 2000 Bytes
                move.l  #MEMREQS,d1             * CHIP-Memory
                CALLEXEC AllocMem               * allokieren
                tst.l   d0                      * alles klar?
                beq     Fault                   * nein - beenden!
                move.l  d0,CopperList           * Zeiger sichern

                move.l  #76*4,d0                * 76*4 Bytes für 4 Sprites
                move.l  #MEMREQS,d1             * CHIP-RAM
                CALLEXEC AllocMem               * allokieren
                tst.l   d0                      * alles klar?
                beq     Fault1.5                * nein - beenden!
                move.l  d0,Sprite0              * Zeiger sichern
                add.l   #76,d0
                move.l  d0,Sprite2
                add.l   #76,d0
                move.l  d0,Sprite4
                add.l   #76,d0
                move.l  d0,Sprite6

                move.l  #40*256,d0              * Speicher
                move.l  #MEMREQS,d1             * für Bitplane
                CALLEXEC AllocMem               * allokieren
                tst.l   d0                      * hat's geklappt?
                beq     Fault2                  * nein!
                move.l  d0,Bitplane             * Zeiger retten

*
* Jetzt wird die Maschine übernommen.
*

                CALLEXEC Forbid                 * kein Multitasking
                move.w  #$3e0,$DFF096           * Copper-, Sprite- und
                                                * andere DMAs sowie DMAEN
                                                * löschen
                move.w  #$4000,$DFF09A          * Interrupts lahmlegen

*
* Die Daten der Sprites müssen noch an die
* richtige Stelle kopiert werden.
*

                lea     Sprite0Data,a0
                move.l  Sprite0,a1
                moveq.w #37,d0

CopySprite0:    move.w  (a0)+,(a1)+
                dbra    d0,CopySprite0

                lea     Sprite2Data,a0
                move.l  Sprite2,a1
                moveq.w #37,d0

CopySprite2:    move.w  (a0)+,(a1)+
                dbra    d0,CopySprite2

                lea     Sprite4Data,a0
                move.l  Sprite4,a1
                moveq.w #37,d0

CopySprite4:    move.w  (a0)+,(a1)+
                dbra    d0,CopySprite4

                lea     Sprite6Data,a0
                move.l  Sprite6,a1
                moveq.w #37,d0

CopySprite6:    move.w  (a0)+,(a1)+
                dbra    d0,CopySprite6

*
* An dieser Stelle werden die Farben für unsere Sprites gesetzt ...
*

                lea     SprColors,a0
                lea     $DFF1A0,a1
                moveq.w #15,d0

CopyColors:     move.w  (a0)+,(a1)+
                dbra    d0,CopyColors

*
* Nun wird die Copperlist erstellt - ein Farbverlauf mit
* den Farben, die in der Tabelle im Datenteil stehen ...
*

                move.l  CopperList,a0           * Copperlist nach a0
                move.l  Bitplane,d2             * Bitplane nach d2
                move.l  Sprite0,d3              * Sprite0 nach d3
                move.l  Sprite2,d4              * Sprite2 nach d4
                move.l  Sprite4,d5              * Sprite4 nach d5
                move.l  Sprite6,d6              * Sprite6 nach d6

                swap    d2                      * auf oberes Word richten
                swap    d3
                swap    d4
                swap    d5
                swap    d6

*
* Hier werden erstmal die Plane- und Sprite-Zeiger zurückgesetzt.
*

                move.w  #$0E0,(a0)+             * Register: BPL1PTH
                move.w  d2,(a0)+                * oberes Word des Plane-
                                                * zeigers setzen
                move.w  #$0E2,(a0)+             * Register: BPL1PTL
                swap    d2                      * unteres Word holen
                move.w  d2,(a0)+                * und setzen

                move.w  #$120,(a0)+             * Register: SPR0PTH
                move.w  d3,(a0)+                * setzen
                move.w  #$122,(a0)+             * Register: SPR0PTL
                swap    d3                      * unteres Word holen
                move.w  d3,(a0)+                * und setzen

                move.w  #$128,(a0)+             * Register: SPR2PTH
                move.w  d4,(a0)+                * setzen
                move.w  #$12A,(a0)+             * Register: SPR2PTL
                swap    d4                      * unteres Word holen
                move.w  d4,(a0)+                * und setzen

                move.w  #$130,(a0)+             * Register: SPR4PTH
                move.w  d5,(a0)+                * setzen
                move.w  #$132,(a0)+             * Register: SPR4PTL
                swap    d5                      * unteres Word holen
                move.w  d5,(a0)+                * und setzen

                move.w  #$138,(a0)+             * Register: SPR6PTH
                move.w  d6,(a0)+                * setzen
                move.w  #$13A,(a0)+             * Register: SPR6PTL
                swap    d6                      * unteres Word holen
                move.w  d6,(a0)+                * und setzen

*
* Jetzt geht's recht normal weiter ...
*

                move.w  #$180,(a0)+             * bis zum Verlauf
                move.w  #$000,(a0)+             * schwarzer Hintergrund

                move.w  #$4601,d0               * Verlauf ab Zeile #66 ($46)
                lea     Colors,a1               * Hintergrundfarben 1 laden
                lea     Colors2,a2              * Hintergrundfarben 2 laden
                moveq.w #15,d1                  * 15+1=16 Abstufungen

SetEntry1:      move.w  d0,(a0)+                * Position in die Liste
                move.w  #$fffe,(a0)+            * Maske in die Liste
                move.w  #$180,(a0)+             * Hintergrund-Register
                move.w  (a1)+,(a0)+             * und Tabellen-Farbwert 1
                add.w   #$0100,d0               * y-Position erhöhen
                dbra    d1,SetEntry1            * bis zum bitteren Ende!

                move.w  #$180,(a0)+             * der Rest soll
                move.w  #$000,(a0)+             * schwarz sein!

                move.w  #$e001,d0               * Verlauf ab Zeile #224 ($e0)
                moveq.w #15,d1                  * 15+1=16 Abstufungen

SetEntry2:      move.w  d0,(a0)+
                move.w  #$fffe,(a0)+
                move.w  #$180,(a0)+
                move.w  (a2)+,(a0)+
                add.w   #$0100,d0
                dbra    d1,SetEntry2

                move.w  #$180,(a0)+             * der Rest soll
                move.w  #$000,(a0)+             * schwarz sein!

                move.l  #$fffffffe,(a0)         * Ende!

                move.w  #$2981,$DFF08E          * DIWSTRT setzen
                move.w  #$29C1,$DFF090          * DIWSTOP setzen
                move.w  #$0038,$DFF092          * DDFSTRT setzen
                move.w  #$00D0,$DFF094          * DDFSTOP setzen
                move.w  #$1000,$DFF100          * 1 Plane - BPLCON0 setzen
                move.w  #0,$DFF102              * kein Scrolling
                move.w  #0,$DFF108              * kein Modulo
                move.w  #0,$DFF10A              * soll benutzt werden

                move.l  CopperList,$DFF080      * List manipulieren
                move.w  #0,$DFF088              * COPJMP1 löschen

                move.w  #$83E0,$DFF096          * alle wichtigen DMAs und
                                                * und DMAEN aktivieren

*
* Nun kommt die Hauptschleife des Programms, eine Joystick-
* abfrage, die das Gebilde entsprechend bewegt.
*

DoJoystick:     move.l  $DFF004,d0              * Elektronenstrahl-Position
                and.l   #$1ff00,d0              * x-Koordinate ausmaskieren
                cmp.l   #4096,d0                * Zeile 16 erreicht?
                bne.s   DoJoystick              * scheint nicht so!

                move.w  $DFF00C,d0              * JOY1DAT holen
                btst    #1,d0                   * Bit 1 gesetzt?
                beq.s   NotRight                * Joystick nicht rechts

                bsr     JoyRight                * Joystick rechts
                bra.s   CheckMouse              * ... weiter!

NotRight:       btst    #9,d0                   * Bit 9 gesetzt?
                beq.s   CheckMouse              * Joystick nicht links

                bsr     JoyLeft                 * Joystick links

CheckMouse:     btst.b  #6,$bfe001              * Mausknopf?
                bne.s   DoJoystick              * nein!

*
* Hier wird der ursprüngliche Zustand wieder hergestellt.
*

                move.l  GfxBase,a1              * Graphics laden
                move.l  38(a1),$DFF080          * System-List wieder
                                                * aktivieren

                CALLEXEC CloseLibrary           * Graphics schließen

                move.l  #0,$DFF088              * COPJMP1 löschen

                move.w  #$c000,$DFF09A          * Interrupts aktivieren
                CALLEXEC Permit                 * Multitasking erlauben

                move.l  Sprite0,a1              * Sprites im
                move.l  #76*4,d0                * CHIP-Memory
                CALLEXEC FreeMem                * deallokieren

Fault1.5:       move.l  Bitplane,a1             * Bitplane im
                move.l  #40*256,d0              * CHIP-Speicher
                CALLEXEC FreeMem                * deallokieren

Fault2:         move.l  CopperList,a1           * Copperlist im
                move.l  #2000,d0                * CHIP-RAM wieder
                CALLEXEC FreeMem                * deallokieren

Fault:          moveq   #0,d0                   * Ende!
                rts

*
* Unterprogramme ...
*

*
* Diese Routine berechnet die Sprite-Positionen für die
* Kontrollwords und trägt diese dann anschließend ein.
* Sie benötigt folgende Parameter:
*
* D0 - x-Koordinate des Sprites.
* D1 - y-Koordinate des Sprites.
* D2 - Höhe des Sprites.
* D3 - Flag, das ein gesetztes (#1) oder
*      ungesetztes (#0) "attached"-Bit anzeigt.
* A0 - Zeiger auf die Sprite-Daten (inkl. Kontrollwords).
*
* Da Ihnen dieses Unterprogramm viel Rechnerei erspart,
* können Sie etwas Ähnliches gut in eigene Programme über-
* nehmen, wenn es nötig ist, Sprite-Positionen zu berechnen.
*

RePosition:     movem.l d0-d7,-(SP)             * Register retten

                moveq   #0,d4                   * d4 löschen
                moveq   #0,d5                   * d5 löschen

                move.w  d0,d4                   * x-Koordinate nach d4
                lsr.w   #1,d4                   * durch zwei dividieren:
                                                * x-Bits an die richtige
                                                * Stelle schieben
                move.w  d1,d5                   * y-Koordinate nach d5
                lsl.w   #8,d5                   * mit 256 multiplizieren:
                                                * y-Bits ans Ende des
                                                * Words schieben
                or.w    d5,d4                   * beide Words verknüpfen

*
* D4 enthält nun das korrekte, erste Kontrollword.
*

                move.w  d4,(a0)                 * 1. Kontrollword setzen

                move.w  d1,d6                   * y-Koordinate nach d6
                add.w   d2,d6                   * plus Höhe -> letzte Zeile
                move.w  d6,d7                   * d6 retten
                lsl.w   #8,d6                   * letzte Zeile ans Ende des
                                                * Words schieben
                and.w   #1,d0                   * HSTART0 isolieren
                or.w    d0,d6                   * und setzen

                and.w   #256,d7                 * VSTOP8 isolieren
                or.w    d7,d6                   * und setzen

                and.w   #256,d1                 * VSTART8 isolieren
                or.w    d1,d6                   * und setzen

                cmp.w   #1,d3                   * Sprite "attached"?
                bne.s   NotAttached             * auf keinen Fall!

                ori.w   #127,d6                 * ATTACHED setzen

*
* D6 enthält an dieser Stelle das zweite Kontrollword.
*

NotAttached:    move.w  d6,2(a0)                * 2. Kontrollword sichern.

                movem.l (SP)+,d0-d7             * Register holen
                rts

*
* Hier stehen die Routinen, die bei der Betätigung
* des Joysticks aufgerufen werden:
*

JoyRight:       move.w  Sprite0x,d0             * x-Koordinate laden
                cmp.w   #400,d0                 * schon 400?
                bge     TooMuch                 * weiter geht's nicht!

                addq.w  #1,d0
                move.w  d0,Sprite0x

                move.w  Sprite0y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite0,a0
                bsr     RePosition

                move.w  Sprite2x,d0
                addq.w  #1,d0
                move.w  d0,Sprite2x

                move.w  Sprite2y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite2,a0
                bsr     RePosition

                move.w  Sprite4x,d0
                addq.w  #1,d0
                move.w  d0,Sprite4x

                move.w  Sprite4y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite4,a0
                bsr     RePosition

                move.w  Sprite6x,d0
                addq.w  #1,d0
                move.w  d0,Sprite6x

                move.w  Sprite6y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite6,a0
                bsr     RePosition

TooMuch:        rts

JoyLeft:        move.w  Sprite0x,d0             * x-Koordinate laden
                cmp.w   #138,d0                 * schon 138?
                ble     TooFew                  * weniger geht nicht!

                subq.w  #1,d0
                move.w  d0,Sprite0x

                move.w  Sprite0y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite0,a0
                bsr     RePosition

                move.w  Sprite2x,d0
                subq.w  #1,d0
                move.w  d0,Sprite2x

                move.w  Sprite2y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite2,a0
                bsr     RePosition

                move.w  Sprite4x,d0
                subq.w  #1,d0
                move.w  d0,Sprite4x

                move.w  Sprite4y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite4,a0
                bsr     RePosition

                move.w  Sprite6x,d0
                subq.w  #1,d0
                move.w  d0,Sprite6x

                move.w  Sprite6y,d1
                moveq.w #16,d2
                moveq.w #0,d3
                move.l  Sprite6,a0
                bsr     RePosition

TooFew:         rts

*
* Auch hier wieder ein Datenteil ...
*

GfxName:        dc.b     "graphics.library",0
 even

GfxBase:        dc.l     0

CopperList:     dc.l     0                      * Zeiger auf die Copperlist
Bitplane:       dc.l     0                      * Zeiger auf die Plane

Sprite0:        dc.l     0                      * Zeiger auf Sprite 0
Sprite2:        dc.l     0                      * Zeiger auf Sprite 2
Sprite4:        dc.l     0                      * Zeiger auf Sprite 4
Sprite6:        dc.l     0                      * Zeiger auf Sprite 6

*
* Die Koordinaten der Sprites ... (Zwischenspeicher!)
*

Sprite0x:       dc.w     253
Sprite0y:       dc.w     138
Sprite2x:       dc.w     269
Sprite2y:       dc.w     138
Sprite4x:       dc.w     253
Sprite4y:       dc.w     154
Sprite6x:       dc.w     269
Sprite6y:       dc.w     154

*
* Hier sind ein paar Farbwerte für die beiden Farbbalken ...
*

Colors:         dc.w     $F00,$F10,$F20,$F30,$F40,$F50,$F60,$F70
                dc.w     $F80,$F90,$FA0,$FB0,$FC0,$FD0,$FE0,$FF0

Colors2:        dc.w     $0FF,$0EF,$0DF,$0CF,$0BF,$0AF,$09F,$08F
                dc.w     $07F,$06F,$05F,$04F,$03F,$02F,$01F,$00F

*
* Dies ist die Farbtabelle der Sprites ...
*

SprColors:      dc.w     $888,$999,$AAA,$BBB,$777,$666,$555,$444
                dc.w     $444,$555,$666,$777,$BBB,$AAA,$999,$888

*
* Und noch die Daten der Sprites ...
*

*
* Sprite 0 ...
*

Sprite0Data:

*
* Die Kontrollwords ... von Zeile #138 bis Zeile #155
*                       horizontal ab #253
*

                dc.w     %1000101001111110,%1001101100000001

*
* Die Daten ...
*

                dc.w     %0000000111111111,%0000000100000001
                dc.w     %0000001111111110,%0000001000000011
                dc.w     %0000011111111100,%0000010000000111
                dc.w     %0000111111111000,%0000100000001111
                dc.w     %0001111111110000,%0001000000011111
                dc.w     %0011111111100000,%0010000000111111
                dc.w     %0111111111000000,%0100000001111111
                dc.w     %1111111110000000,%1000000011111111
                dc.w     %1111111100000001,%0000000111111111
                dc.w     %1111111000000011,%0000001111111111
                dc.w     %1111110000000111,%0000011111111111
                dc.w     %1111100000001111,%0000111111111111
                dc.w     %1111000000011111,%0001111111111111
                dc.w     %1110000000111111,%0011111111111111
                dc.w     %1100000001111111,%0111111111111111
                dc.w     %1000000011111111,%1111111111111111

*
* Die Endmarkierung ...
*

                dc.w     %0000000000000000,%0000000000000000

*
* Sprite 2 ...
*

Sprite2Data:

*
* Die Kontrollwords ... von Zeile #138 bis Zeile #155;
*                       horizontal ab #269
*

                dc.w     %1000101010000110,%1001101100000001

*
* Die Daten ...
*

                dc.w     %1111111110000000,%1000000010000000
                dc.w     %0111111111000000,%1100000001000000
                dc.w     %0011111111100000,%1110000000100000
                dc.w     %0001111111110000,%1111000000010000
                dc.w     %0000111111111000,%1111100000001000
                dc.w     %0000011111111100,%1111110000000100
                dc.w     %0000001111111110,%1111111000000010
                dc.w     %0000000111111111,%1111111100000001
                dc.w     %1000000011111111,%1111111110000000
                dc.w     %1100000001111111,%1111111111000000
                dc.w     %1110000000111111,%1111111111100000
                dc.w     %1111000000011111,%1111111111110000
                dc.w     %1111100000001111,%1111111111111000
                dc.w     %1111110000000111,%1111111111111100
                dc.w     %1111111000000011,%1111111111111110
                dc.w     %1111111100000001,%1111111111111111

*
* Die Endmarkierung ...
*

                dc.w     %0000000000000000,%0000000000000000

*
* Sprite 4 ...
*

Sprite4Data:

*
* Die Kontrollwords ... von Zeile 154 bis Zeile 171
*                       horizontal ab #253
*

                dc.w     %1001101001111110,%1010101100000001

*
* Die Daten ...
*

                dc.w     %1000000011111111,%1111111111111111
                dc.w     %1100000001111111,%0111111111111111
                dc.w     %1110000000111111,%0011111111111111
                dc.w     %1111000000011111,%0001111111111111
                dc.w     %1111100000001111,%0000111111111111
                dc.w     %1111110000000111,%0000011111111111
                dc.w     %1111111000000011,%0000001111111111
                dc.w     %1111111100000001,%0000000111111111
                dc.w     %1111111110000000,%1000000011111111
                dc.w     %0111111111000000,%0100000001111111
                dc.w     %0011111111100000,%0010000000111111
                dc.w     %0001111111110000,%0001000000011111
                dc.w     %0000111111111000,%0000100000001111
                dc.w     %0000011111111100,%0000010000000111
                dc.w     %0000001111111110,%0000001000000011
                dc.w     %0000000111111111,%0000000100000001

*
* Die Endmarkierung ...
*

                dc.w     %0000000000000000,%0000000000000000

*
* Sprite 6 ...
*

Sprite6Data:

*
* Die Kontrollwords ... von Zeile #154 bis Zeile #171
*                       horizontal ab #269
*

                dc.w     %1001101010000110,%1010101100000001

*
* Die Daten ...
*

                dc.w     %1111111100000001,%1111111111111111
                dc.w     %1111111000000011,%1111111111111110
                dc.w     %1111110000000111,%1111111111111100
                dc.w     %1111100000001111,%1111111111111000
                dc.w     %1111000000011111,%1111111111110000
                dc.w     %1110000000111111,%1111111111100000
                dc.w     %1100000001111111,%1111111111000000
                dc.w     %1000000011111111,%1111111110000000
                dc.w     %0000000111111111,%1111111100000001
                dc.w     %0000001111111110,%1111111000000010
                dc.w     %0000011111111100,%1111110000000100
                dc.w     %0000111111111000,%1111100000001000
                dc.w     %0001111111110000,%1111000000010000
                dc.w     %0011111111100000,%1110000000100000
                dc.w     %0111111111000000,%1100000001000000
                dc.w     %1111111110000000,%1000000010000000

*
* Die Endmarkierung ...
*

                dc.w     %0000000000000000,%0000000000000000

                END

