home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / assembler-kurs / listings3 / listing7m.s < prev    next >
Text File  |  1977-12-31  |  12KB  |  381 lines

  1.  
  2. ; Listing7m.s   Positionierung der Sprite mittels einer Universalroutine.
  3. ; Dieses Beispiel zeigt eine universelle Routine, die die Sprites bewegen
  4. ; kann, sie beachtet dabei alle Bits (horizontal und vertikal) des Sprites.
  5. ; Weiters zählt sie automatisch das Offset (128 für die X-Koordinaten,
  6. ; $2c für die Y-Koordinaten) dazu.
  7. ; Somit können die Koordinaten in der Tabelle die realen sein, also von
  8. ; 0 bis 320 für die horizontalen, und von 0 bis 256 für die vertikalen.
  9.  
  10.  
  11.     SECTION CipundCop,CODE
  12.  
  13. Anfang:
  14.     move.l    4.w,a6        ; Execbase
  15.     jsr    -$78(a6)    ; Disable
  16.     lea    GfxName(PC),a1    ; Libname
  17.     jsr    -$198(a6)    ; OpenLibrary
  18.     move.l    d0,GfxBase
  19.     move.l    d0,a6
  20.     move.l    $26(a6),OldCop    ; speichern die alte COP
  21.  
  22. ;    Pointen auf das "leere" PIC
  23.  
  24.     MOVE.L    #BITPLANE,d0    ; wohin pointen
  25.     LEA    BPLPOINTERS,A1    ; COP-Pointer
  26.     move.w    d0,6(a1)
  27.     swap    d0
  28.     move.w    d0,2(a1)
  29.  
  30. ;    Pointen auf den Sprite
  31.  
  32.     MOVE.L    #MEINSPRITE,d0        ; Adresse des Sprite in d0
  33.     LEA    SpritePointers,a1    ; Pointer in der Copperlist
  34.     move.w    d0,6(a1)
  35.     swap    d0
  36.     move.w    d0,2(a1)
  37.  
  38.     move.l    #COPPERLIST,$dff080    ; unsere COP
  39.     move.w    d0,$dff088        ; START COP
  40.     move.w    #0,$dff1fc        ; NO AGA!
  41.     move.w    #$c00,$dff106
  42.  
  43. mouse:
  44.     cmpi.b    #$ff,$dff006    ; Zeile 255?
  45.     bne.s    mouse
  46.  
  47.  
  48.     btst    #2,$dff016
  49.     beq.s    Warte
  50.     bsr.w    BewegeSprite    ; Bewege Sprite
  51.  
  52. Warte:
  53.     cmpi.b    #$ff,$dff006    ; Zeile 255?
  54.     beq.s    Warte
  55.  
  56.     btst    #6,$bfe001    ; Mouse gedrückt?
  57.     bne.s    mouse
  58.  
  59.  
  60.     move.l    OldCop(PC),$dff080    ; Pointen auf die SystemCOP
  61.     move.w    d0,$dff088        ; Starten die alte SystemCOP
  62.  
  63.     move.l    4.w,a6
  64.     jsr    -$7e(a6)    ; Enable
  65.     move.l    gfxbase(PC),a1
  66.     jsr    -$19e(a6)    ; Closelibrary
  67.     rts
  68.  
  69. ;    Daten
  70.  
  71. GfxName:
  72.     dc.b    "graphics.library",0,0
  73.  
  74. GfxBase:
  75.     dc.l    0
  76.  
  77. OldCop:
  78.     dc.l    0
  79.  
  80.  
  81. ; Um den Sprite richtig zu bewegen lesen wir zuerst die Tabelle, um zu
  82. ; wissen, welche Positionen er einnehmen muß, dann übergeben wir diese
  83. ; mitsamt der Adresse und der Höhe des Sprites an die Routine UniMoveSprite.
  84. ; Das geschieht durch die Register a1,d0,d1,d2
  85.  
  86. BewegeSprite:
  87.     bsr.s    LiesTabellen ; Liest die X-und Y-Koordinaten aus den Tabellen,
  88.                  ; gibt in das Register a1 die Adresse des
  89.                  ; Sprite, in d0 die Y-Pos, in d1 die X-Pos
  90.                  ; und in d2 die Höhe des Sprite.
  91.  
  92. ;
  93. ;    Eingangsparameter von UniMoveSprite:
  94. ;
  95. ;    a1 = Adresse des Sprite
  96. ;    d0 = Vertikale Position des Sprite auf dem Screen (0-255)
  97. ;    d1 = Horizontale Position des Sprite auf dem Screen (0-320)
  98. ;    d2 = Höhe des Sprite
  99.  
  100.     bsr.w    UniMoveSprite    ; führt die Universalroutine aus, die den
  101.                 ; Sprite bewegt
  102.     rts
  103.  
  104.  
  105. ; Diese Routine liest aus den zwei Tabellen die realen Koordinaten der Sprite.
  106. ; Also die X-Koordinate, die von 0 bis 320 geht, und die Y, von 0 bis 256
  107. ; (ohne Overscan). Da wir in diesem Beispiel kein Overscan verwenden ist die
  108. ; Koordinatentabelle für die Y-Positionen aus Byte erstellt. Die Tabelle für
  109. ; die X-Koordinaten hingegen besteht aus Word, da sie Werte größer als 256
  110. ; enthaltne muß.
  111. ; Diese Routine positioniert den Sprite aber nicht direkt. Sie limitiert sich
  112. ; darauf, es die Universalroutine tun zu lassen, sie übermittelt ihr nur
  113. ; die Koordinaten über die Register d0 und d1.
  114.  
  115.  
  116. LiesTabellen:
  117.     ADDQ.L    #1,TABYPOINT     ; Point auf das nächste Byte
  118.     MOVE.L    TABYPOINT(PC),A0 ; Adresse aus Long TABXPOINT
  119.                  ; wird in a0 kopiert
  120.     CMP.L    #ENDETABY-1,A0     ; Sind wir beim letzten Longword der TAB?
  121.     BNE.S    NOBSTARTY     ; noch nicht? dann weiter
  122.     MOVE.L    #TABY-1,TABYPOINT ; Starte wieder beim ersten Byte (-1)
  123. NOBSTARTY:
  124.     moveq    #0,d0        ; Lösche d0
  125.     MOVE.b    (A0),d0
  126.  
  127.     ADDQ.L    #2,TABXPOINT     ; Pointe auf das nächste Word
  128.     MOVE.L    TABXPOINT(PC),A0 ; Adresse aus Long TABXPOINT
  129.                  ; wird in a0 kopiert
  130.     CMP.L    #ENDETABX-2,A0     ; sind wir beim letzten Word der TAB?
  131.     BNE.S    NOBSTARTX     ; noch nicht? dann weiter
  132.     MOVE.L    #TABX-2,TABXPOINT ; beginne beim ersten Word-2
  133. NOBSTARTX:
  134.     moveq    #0,d1        ; löscht d1
  135.     MOVE.w    (A0),d1        ; setzen den Wert der Tabelle in d1
  136.  
  137.     lea    MEINSPRITE,a1    ; Adresse des Sprite in a1
  138.     moveq    #13,d2        ; Höhe des Sprite in d2
  139.     rts
  140.  
  141.  
  142. TABYPOINT:
  143.     dc.l    TABY-1        ; BEMERKE: Die Werte in der Tabelle sind hier
  144.                 ; Bytes, wir arbeiten also mit einem ADDQ.L #1,
  145.                 ; TABYPOINT, und nicht #2 wie bei den Words
  146.                 ; oder #4 bei den Longwords.
  147.  
  148. TABXPOINT:
  149.     dc.l    TABX-2    ; Bemerke: die Werte in der Tabelle sind hier Word
  150.  
  151.  
  152. ; Tabelle mit vorausberechneten Y-Koordinaten.
  153. ; Zu Bemerken, daß die Y-Position des Sprites zwischen $2c und $f2 liegen muß,
  154. ; wenn wir ihn in das Videofenster bekommen wollen. In der Tabelle sind alles
  155. ; Werte enthalten, die innerhalb dieses Limits liegen.
  156.  
  157. ; So macht man sich eine Tabelle:
  158.  
  159. ; BEG> 0
  160. ; END> 360
  161. ; AMOUNT> 200
  162. ; AMPLITUDE> $f0/2
  163. ; YOFFSET> $f0/2
  164. ; SIZE (B/W/L)> b
  165. ; MULTIPLIER> 1
  166.  
  167.  
  168. TABY:
  169.     incbin    "ycoordinatok.tab"    ; 200 .B Werte
  170. ENDETABY:
  171.  
  172.  
  173. ; Tabelle mit vorausberechneten X-Koordinaten.
  174. ; Diese Tabelle enthält die REALEN Koordinaten des Bildschirmes, und nicht
  175. ; die "halbierten" Werte wie für den Scroll, beidem jedesmal 2 Pixel auf einmal
  176. ; genommen wurden. In der Tabelle kommen keine Bytes vor, die größer als
  177. ; 304 (320-16, wegen des Sprites) oder kleiner als 0 sind.
  178.  
  179.  
  180.  
  181. TABX:
  182.     incbin    "xcoordinatok.tab"    ; 150 .W Werte
  183. ENDETABX:
  184.  
  185.  
  186.  
  187. ; Universelle Sprite-Positionierungs-Routine.
  188. ; Diese Routine verändert die Position des Sprites, dessen Adresse
  189. ; sich in a1 befindet und dessen Höhe im Register d2 steht.
  190. ; Seine Koordinaten für X und Y stehen jeweils in den Registers
  191. ; d0 und d1.
  192. ; Vor dem Aufruf dieser Routine muß die Adresse des Sprites in a1
  193. ; gegeben werden, seine Höhe in d2, und die Koordinaten, auf die
  194. ; er gesetzt werden soll in d0 (X) und d1 (Y).
  195.  
  196. ; Diese Prozedur wird "Parameterübergabe" genannt.
  197. ; Bemerke, diese Routine modifiziert die Register d0 und d1.
  198.  
  199.  
  200. ;    Eingangsparameter von UniMoveSprite:
  201. ;
  202. ;    a1 = Adresse des Sprite
  203. ;    d0 = Vertikale Position des Sprite auf dem Screen (0-255)
  204. ;    d1 = Horizontale Position des Sprite auf dem Screen (0-320)
  205. ;    d2 = Höhe des Sprite
  206. ;
  207. ;
  208.  
  209. UniMoveSprite:
  210. ; Vertikale Positionierung
  211.  
  212.     ADD.W    #$2c,d0         ; zähle den Offset vom Anfang des Screens dazu
  213.  
  214. ; a1 enthält die Adresse des Sprite
  215.  
  216.     MOVE.b    d0,(a1)        ; kopiert das Byte in VSTART
  217.     btst.l    #8,d0
  218.     beq.s    NichtVSTARTSET
  219.     bset.b    #2,3(a1)    ; Setzt das Bit 8 von VSTART (Zahl > $FF)
  220.     bra.s    ToVSTOP
  221. NichtVSTARTSET:
  222.     bclr.b    #2,3(a1)    ; Löscht das Bit 8 von VSTART (Zahl < $FF)
  223. ToVSTOP:
  224.     ADD.w    D2,D0        ; Zähle die Höhe des Sprite dazu, um
  225.                 ; die Endposition zu errechnen (VSTOP)
  226.     move.b    d0,2(a1)    ; Setze den richtigen Wert in VSTOP
  227.     btst.l    #8,d0
  228.     beq.s    NichtVSTOPSET
  229.     bset.b    #1,3(a1)    ; Setzt Bit 8 von VSTOP (Zahl > $FF)
  230.     bra.w    VVSTOPENDE
  231. NichtVSTOPSET:
  232.     bclr.b    #1,3(a1)    ; Löscht Bit 8 von VSTOP (Zahl < $FF)
  233. VVSTOPENDE:
  234.  
  235. ; horizontale Positionierung
  236.  
  237.     add.w    #128,D1     ; 128 - um den Sprite zu zentrieren
  238.     btst    #0,D1        ; niederwert. Bit der X-Koordinate auf 0?
  239.     beq.s    NiederBitNull
  240.     bset    #0,3(a1)    ; Setzen das niederw. Bit von HSTART
  241.     bra.s    PlaceCoords
  242.  
  243. NiederBitNull:
  244.     bclr    #0,3(a1)    ; Löschen das niederw. Bit von HSTART
  245. PlaceCoords:
  246.     lsr.w    #1,D1        ; SHIFTEN, verschieben den Wert von HSTART um
  247.                 ; 1 Bit nach Rechts, um es in den Wert zu
  248.                 ; "verwandeln", der dann in HSTART kommt, also
  249.                 ; ohne dem niederwertigen Bit.
  250.     move.b    D1,1(a1)    ; geben den Wert XX ins Byte HSTART
  251.     rts
  252.  
  253.     
  254.  
  255.     SECTION GRAPHIC,DATA_C
  256.  
  257. COPPERLIST:
  258. SpritePointers:
  259.     dc.w    $120,0,$122,0,$124,0,$126,0,$128,0 ; SPRITE
  260.     dc.w    $12a,0,$12c,0,$12e,0,$130,0,$132,0
  261.     dc.w    $134,0,$136,0,$138,0,$13a,0,$13c,0
  262.     dc.w    $13e,0
  263.  
  264.     dc.w    $8E,$2c81    ; DiwStrt
  265.     dc.w    $90,$2cc1    ; DiwStop
  266.     dc.w    $92,$38        ; DdfStart
  267.     dc.w    $94,$d0        ; DdfStop
  268.     dc.w    $102,0        ; BplCon1
  269.     dc.w    $104,0        ; BplCon2
  270.     dc.w    $108,0        ; Bpl1Mod
  271.     dc.w    $10a,0        ; Bpl2Mod
  272.  
  273.             ; 5432109876543210
  274.     dc.w    $100,%0001001000000000    ; Bit 12 an!! 1 Bitplane Lowres
  275.  
  276. BPLPOINTERS:
  277.     dc.w $e0,0,$e2,0    ;erstes    Bitplane
  278.  
  279.     dc.w    $180,$000    ; Color0    ; Hintergrund Schwarz
  280.     dc.w    $182,$123    ; Color1    ; Farbe 1 des Bitplane, die
  281.                         ; in diesem Fall leer ist,
  282.                         ; und deswegen nicht erscheint
  283.  
  284.     dc.w    $1A2,$F00    ; Color17, oder COLOR1 des Sprite0 - ROT
  285.     dc.w    $1A4,$0F0    ; Color18, oder COLOR2 des Sprite0 - GRÜN
  286.     dc.w    $1A6,$FF0    ; Color19, oder COLOR3 des Sprite0 - GELB
  287.  
  288.     dc.w    $FFFF,$FFFE    ; Ende der Copperlist
  289.  
  290.  
  291. ; ************ Hier ist der Sprite: NATÜRLICH muß er in CHIP RAM sein! ********
  292.  
  293. MEINSPRITE:      ; Länge 13 Zeilen
  294.     dc.b $50  ; Vertikale Anfangsposition des Sprite (von $2c bis $f2)
  295.     dc.b $90  ; Horizontale Anfangsposition des Sprite (von $40 bis $d8)
  296.     dc.b $5d  ; $50+13=$5d    ; Vertikale Endposition des Sprite
  297.     dc.b $00
  298.  dc.w    %0000000000000000,%0000110000110000 ; Binäres Format für ev. Änderungen
  299.  dc.w    %0000000000000000,%0000011001100000
  300.  dc.w    %0000000000000000,%0000001001000000
  301.  dc.w    %0000000110000000,%0011000110001100 ;BINÄR 00=COLOR 0 (DURCHSICHTIG)
  302.  dc.w    %0000011111100000,%0110011111100110 ;BINÄR 10=COLOR 1 (ROT)
  303.  dc.w    %0000011111100000,%1100100110010011 ;BINÄR 01=COLOR 2 (GRÜN)
  304.  dc.w    %0000110110110000,%1111100110011111 ;BINÄR 11=COLOR 3 (GELB)
  305.  dc.w    %0000011111100000,%0000011111100000
  306.  dc.w    %0000011111100000,%0001111001111000
  307.  dc.w    %0000001111000000,%0011101111011100
  308.  dc.w    %0000000110000000,%0011000110001100
  309.  dc.w    %0000000000000000,%1111000000001111
  310.  dc.w    %0000000000000000,%1111000000001111
  311.  dc.w    0,0    ; 2 word auf NULL definieren das Ende des Sprite.
  312.  
  313.  
  314.     SECTION LEERESPLANE,BSS_C ; Ein auf 0 gesetztes Bitplane, wir
  315.                   ; müssen es verwenden, denn ohne Bitplane
  316.                   ; ist es nicht möglich, die Sprites
  317.                   ; zu aktivieren
  318. BITPLANE:
  319.     ds.b    40*256        ; Bitplane auf 0 Lowres
  320.  
  321.     end
  322.  
  323. In  diesem  Listing präsentieren wir eine Universalroutine, um die Sprites
  324. zu verstellen, sie heißt "UniMoveSprite".  Diese  Routine  übernimmt  alle
  325. Aspekte  der  Positionierung der Sprite, es verwaltet alle Bit richtig und
  326. zählt den Offset dazu. Somit können die Werte  direkt  als  "reale"  Werte
  327. übergeben  werden, die Tabellen können also die Werte enthalten, auf denen
  328. der Sprite sich am Bildschirm im Endeffekt befinden soll.
  329. Diese Routine funktioniert mit jedem Sprite. Denn die Adresse  des  Sprite
  330. ist nicht fix, sie wird aus dem Register a1 ausgelesen. Das bedeutet daß:
  331.  
  332.   VSTART sich an der Adresse in a1 befindet
  333.  
  334.   HSTART sich im nachfolgenden Byte befindet, also an der Adresse a1 + 1
  335.  
  336.   VSTOP sich zwei Bytes danach befindet, oder a1 + 2
  337.  
  338.   das vierte Byte drei Byte danach liegt, oder a1 + 3
  339.  
  340. UniMoveSprite greift auf diese Byte mittels indirekter Adressierung über
  341. Register mit Offset zu:
  342.  
  343.  
  344.  um auf  VSTART zuzugreifen verwendet man (a1)
  345.  um auf  HSTART zuzugreifen verwendet man 1(a1)
  346.  um auf  VSTOP zuzugreifen verwendet man 2(a1)
  347.  um auf das vierte Byte verwendet man 3(a1)
  348.  
  349. Auch die Höhe des Sprites ist nicht fix, sondern im Register d2 enthalten.
  350. Damit  kann  die  Routine  dazu verwendet werden, um Sprites verschiedener
  351. Höhe zu bewegen. Weiters holt sich die Routine die Daten nicht direkt  aus
  352. der Tabelle, sondern bekommt sie über d0 und d1 mitgeteilt.
  353.  
  354. Und  wer  gibt  diese  Daten  in  die  Register?  Eine andere Routine, die
  355. "LiesTabellen" heißt, sie holt die Koordinaten aus den Tabellen, gibt  sie
  356. in  die Register d0 und d1 und führt dann die Routine "UniMoveSprite" aus.
  357. Praktisch haben wir die Aufgaben auf zwei Routinen aufgeteilt, so, als  ob
  358. es  zwei Angestellte wären. Die Routine "LiesTabellen" macht ihre Aufgabe,
  359. dann sagt sie: "Hey, Routine UniMoveSprite, hier kriegste ´nen  Sprite  zu
  360. bewegen,  ich schick´ dir die Adresse im Register a1. In d2 schick ich dir
  361. die Höhe. Dann noch die Koordinaten, die bekommst du über die Register  d0
  362. und d1. Du weißt ja, wie man damit umgeht!"
  363. Die Routine  "UniMoveSprite"  bekommt  die  Adresse  des  Sprite  und  die
  364. Koordinaten  und  setzt diese dann in die richtigen Bytes des Sprites. Die
  365. "Spedition" der Koordinaten über die Register heißt "Parameterübergabe".
  366.  
  367. Die Aufteilung der Arbeiten ist eine sehr bequeme Sache.  Nehmen  wir  an,
  368. wir  möchten  einen  Sprite  bewegen,  der  seine  Y-Koordinaten aus einer
  369. Tabelle  bekommt,  die  X-Koordinaten  hingegen  mit   ADDQ/SUBQ   separat
  370. berechnet werden, um praktisch einen Sprite zu schaffen, der dauernd links
  371. und rechts geht, dabei aber auf- und abschwingt. Da die Routine die  Daten
  372. aus  den  Registern  holt,  insteressiert  es  sie nicht, ob sie aus einer
  373. Tabelle kommen oder berechnet  werden.  Deshalb  können  wir  die  Routine
  374. wiederverwenden,  ohne  etwas ändern zu müssen. Und da sie die Adresse und
  375. die Höhe des Sprites auch über Register bekommt  ist  sie  somit  auch  an
  376. keinen bestimmten Sprite gebunden und universell einsetzbar.
  377. Von nun an werden wir also für jedes Beispiel mit  Sprites  diese  Routine
  378. "UniMoveSprite"  verwenden,  ohne  sie  nur  ein  einziges Mal abändern zu
  379. müssen.
  380.  
  381.