Magic Disk 64

home to index to html: MD9411-KURSE-IRQ-KURS_13.1.html
                IRQ-KURS                
     "Die Hardware ausgetrickst..."     
                (Teil 13)               
----------------------------------------
Herzlich Willkommen zum dreizehnten Teil
unseres  IRQ-Kurses.  Auch  diesen Monat
soll es um das trickreiche  manipulieren
von Sprites gehen. Wir werden uns einige
Routinen  zum  Dehnen  von  Sprites  an-
schauen, und dabei lernen, daß  es  auch
Sprites gibt, die mehr als 21 Rasterzei-
len hoch sind...                        
1) DAS PRINZIP                          
Wie immer kommen wir zu Beginn zum Funk-
tionsprinzip  des  Rastereffektes dieses
Kursteils: Wie Sie vielleicht wissen, so
ist die Größe eines Sprites  prinzipiell
auf  24x21  Pixel  begrenzt. Diese Größe
ist starr und eigentlich nicht veränder-
bar. Es existieren jedoch 3 Sonderfälle,
in  denen  das  Sprite  auch größer sein
kann, nämlich dann, wenn wir  mit  Hilfe
der  Register $D017 und $D01D die X- und
Y-Expansion eines  Sprites  einschalten.
In  diesem  Fall  kann sowohl die X- als
auch die Y-Ausdehnung verdoppelt werden,
so daß wir ein Sprite mit einer  maxima-
len  Größe von 48x42 Pixeln erhalten, in
dem die  normalen  24x21  Pixel  einfach
doppelt dargestellt werden. Wie Sie also
sehen  ist der VIC rein theoretisch doch
in der  Lage  größere  Sprites  auf  den
Bildschirm  zu zaubern. Jedoch auch dies
nur in höchst beschränkter Form, da  wir
nun  ebenfalls  an  eine  fixe Auflösung
gebunden  sind.  Wir  werden  allerdings
gleich  ein  Verfahren kennenlernen, mit
dem es uns möglich sein wird,  zumindest
die  Y-Auflösung  eines Sprites variabel
festzulegen.                            
Dreh-  und  Angelpunkt  dieses  Effektes
wird das eben schon angesprochene  Regi-
ster zur Y-Expansion der Sprites ($D017)
sein. Wollen wir zunächst einmal klären,
wie  der  VIC die Sprites überhaupt dar-
stellt: Nehmen wir also an, daß wir  ein
Sprite  auf  dem  Bildschirm  darstellen
möchten. Zunächst  einmal  nicht  expan-
diert.  Der  VIC vergleicht nun jede Ra-
sterzeilennummer mit der Y-Position  des
Sprites. Sind beide Werte gleich, so hat
er  die Rasterzeile erreicht, in der die
oberste Linie des Sprites zu sehen  sein
soll. Es wird nun eine interne Schaltlo-
gik aktiviert, die  dem  VIC  zu  Beginn
einer  jeden Rasterzeile die Adresse der
nächsten drei Datenbytes an den Datenbus
legt und ihn somit jedesmal mit  den  in
dieser  Zeile für dieses Sprite relevan-
ten  Daten  füttert.   Die   Schaltlogik
verfügt  nun  für  jedes Sprite über ein
1-Bit-Zähl-,  sowie   ein   1-Bit-Latch-
Register, die beide bei einem Schreibzu-
griff auf das Register  $D017,  mit  dem
Zustand  des Bits zum zugehörigen Sprite
neu  initialisiert  werden.  Das  Latch-
Register dient dabei als "Merkhilfe" für
den Zustand der Y-Expansion des Sprites.
Enthält  es  den  Bitwert 1, so soll das
Sprite in Y-Richtung verdoppelt  werden,
enthält es den Wert 0, so soll es normal
dargestellt  werden. Ab der Rasterzeile,
ab der das Sprite nun gezeichnet  werden
soll  legt  die Schaltlogik nun zunächst
die aktuelle Spritedatenadresse  an  den
Bus und füttert den VIC so mit den Spri-
tedaten  für  die   erste   Rasterzeile.
Gleichzeitig   wird  bei  Erreichen  der
nächsten Rasterzeile der 1-Bit-Zähler um
eins erniedrigt. Tritt dabei ein  Unter-
lauf auf, so reinitialisiert die Schalt-
logik den Zähler wieder mit  dem  Inhalt
des Latch-Registers und erhöht die Quel-
ladresse für die Speitedaten um 3 Bytes,
so daß Sie anschließend dem VIC die  Da-
ten   der  nächsten  Spritezeile  zukom-
menlässt. Tritt kein Unterlauf auf, weil
der Zähler auf 1 stand und  beim  Herun-
terzählen  auf  0  sprang, so bleibt die
Quelladresse  der  Spritedaten  unverän-
dert,  so daß der VIC auch in dieser Ra-
sterzeile dieselben  Spritedaten  liest,
die  er  auch  eine  Rasterzeile  vorher
schon darstellte. Ist  die  Spriteexpan-
sion  nun  abgeschaltet, so wurden Latch
und Zähler zu  Beginn  mit  dem  Wert  0
gefüttert.  In dem Fall läuft der Zähler
in jeder  Rasterzeile  unter  und  somit
bekommt  der  VIC  in  jeder Rasterzeile
neue  Spritedaten  zugewiesen.  Ist  die
Y-Expansion  eingeschaltet, so enthalten
Zähler und Latch den Wert 1 und es  wird
fortlaufend nur in jeder zweiten Raster-
zeile eine neue Adresse an den  Datenbus
angelegt,  womit  der  VIC das Sprite in
der  Vertikalen  doppelt  so  hoch  dar-
stellt.                                 
Wie nun eingangs schon erwähnt so werden
sowohl Latch als auch Zähler neu initia-
lisiert,  sobald  ein Schreibzugriff auf
Register $D017  erfolgt.  Dadurch  haben
wir  also  auch direkten Einfluß auf den
Y-Expansions-Zähler. Was sollte uns  nun
also  davon  abhalten,  diesen Zähler in
JEDER Rasterzeile durch  Setzen  des  Y-
Expansionsbits  des  gewünschten Sprites
wieder auf 1 zurückzusetzen, so daß  die
Schaltlogik nie einen Unterlauf erzeugen
kann,  und  somit immer wieder dieselben
Spritedaten angezeigt werden?  Und  ganz
genau  so  können  wir ein Sprite länger
strecken als es eigentlich ist und  z.B.
3-, 4-, oder 5-fache Expansion des Spri-
tes bewirken (indem jede Spritezeile 3-,
4- oder 5-mal hintereinander dargestellt
wird)! Wir haben sogar  die  Möglichkeit
jede Spritezeile beliebig, und voneinan-
der unabhängig oft, zu  wiederholen,  so
daß  man  z.B. auch eine Sinuswelle über
das Sprite laufen  lassen  kann!  Hierzu
muß  lediglich exakt zu Beginn einer Ra-
sterzeile  entweder  das   Expansionsbit
gesetzt  werden,  wenn  die  Rasterzeile
dieselben Spritedaten enthalten soll wie
die letzte Rasterzeile, oder wir Löschen
das Expansionsbit des gewünschten  Spri-
tes,  um  die Daten der nächsten Sprite-
zeile in den VIC zu holen!              
2) PROGRAMMBEISPIELE 1 UND 2            
Um einen Eindruck von den  Möglichkeiten
zu  bekommen, die uns dieser Effekt bie-
tet, sollten Sie sich  einmal  die  Bei-
spielprogramme "STRETCHER.1" bis "STRET-
CHER.4" auf  dieser  MD  anschauen.  Sie
werden alle wie immer mit LOAD"Name",8,1
geladen  und durch ein "SYS4096" gestar-
tet. Die ersten beiden Beispiele stellen
ein Sprite dar,  das  normalerweise  nur
eine  diagonale Line von der linken obe-
ren Ecke zur rechten  unteren  Ecke  des
Sprites  enthält. Im ersten Beispiel ha-
ben wir lediglich einige  dieser  Zeilen
mehrfach  dargestellt.  Das  zweite Bei-
spiel  enthält  eine  Streckungstabelle,
mit  der  wir  jede Rasterzeile in Folge
1-, 2-, 3-, 4-, 5-, und  6-Mal  darstel-
len, womit die Linie in etwa die Rundun-
gen einer Sinuskurve bekommt!           
Wollen  wir uns nun einmal den Programm-
code anschauen, den  wir  zur  Erzeugung
der Verzerrung in Beispiel "STRETCHER.1"
verwenden.  Die  Initialisierung und den
Beginn der IRQ-Routine  möchte  ich  wie
immer aussparen, da beides absolut iden-
tisch mit unseren anderen IRQ-Beispielen
ist. Wir legen hier den  Raster-IRQ  auf
Rasterzeile  $82  fest  und schalten Be-
triebssystem-ROM ab, um direkt über  den
IRQ-Vektor  bei $FFFE/$FFFF zu springen.
Die IRQ-Routine selbst  beginnt  nun  ab
Adresse  $1100, wo zunächst unser altbe-
kannter Trick zum Glätten des IRQs  auf-
geführt  ist.  Der  für  uns wesentliche
Teil beginnt wie  immer  ab   dem  Label
"ONECYCLE",  ab  den  der  IRQ geglättet
wurde, und die für uns relevanten Routi-
nenteile stehen. Zusätzlich sei erwähnt,
daß  wir gleichzeitig, um Timingprobleme
zu vermeiden, eine FLD-Routine  benutzen
um  die Charakterzeilen wegzudrücken und
gleichzeitig  den  linken  und   rechten
Bildschirmrand öffnen, damit wir in spä-
teren Beispielen auch Sprites in  diesen
Bereichen  darstellen  und sehen können.
Hier nun  jedoch  zunächst  der  Source-
Code:                                   
onecycle:                               
  lda #$18   ;1. Wert für FLD           
  sta $d011  ; in $D011 schreiben       
  lda #$f8   ;Nächsten IRQ bei Raster-  
  sta $d012  ; zeile $f8 auslösen       
  dec $d019  ;VIC-ICR löschen           
  lda #21*5  ;Zähler f. FLD init. (21*5=
  sta $02    ; 5-fache Spritehöhe)      
  nop        ;Verzögern..               
  ldx #$00   ;Tabellenindex init.       
fldloop:                                
  lda ad017,x;Wert aus Stretch-Tab lesen
  sta $d017  ; und in Y-Exp. eintragen  
  lda ad011,x;Wert aus FLD-Tab lesen    
  sta $d011  ; und in $D011 eintragen   
  dec $d016  ;38 Spalten   (Rand        
  inc $d016  ;40 Spalten    öffnen)     
  nop        ;Bis zum Anfang der        
  nop        ; nächsten Rasterzeile     
  nop        ; verzögern...             
  nop                                   
  nop                                   
  nop                                   
  nop                                   
  nop                                   
  nop                                   
  lda #$00   ;Y-Exp. auf 0              
  sta $d017  ; zurücksetzen             
  inx        ;Tab-Index+1               
  cpx $02    ;Mit FLD-Zähler vgl.       
  bcc fldloop;Kleiner, also weiter      
  lda #$82   ;Nächster IRQ bei Rasterz. 
  sta $d012  ; $82                      
  ldx #$00   ;IRQ-Vektoren              
  ldy #$11   ; auf eigene               
  stx $fffe  ; Routine                  
  sty $ffff  ; umstellen                
  lda #$0e   ;Farben auf hellblau/      
  sta $d020  ; schwarz setzen           
  lda #$00                              
  sta $d021                             
  pla        ;Prozessorregs. zurück-    
  tay        ; holen                    
  pla                                   
  tax                                   
  pla                                   
  rti        ;IRQ beenden               
Ab   dem   Label   ONECYCLE  setzen  wir
zunächst einige Basiswerte für die Spri-
te-Stretch, FLD- und Sideborderroutinen.
Hierzu  schreiben  wir  erst  einmal die
Anzahl der Rasterzeilen, in denen  diese
drei  Effekte aktiv sein sollen als Ver-
gleichszähler in Adresse $02 und löschen
das X-Register, das als  Index  auf  die
FLD-  und Sprite-Stretch-Tabellen dienen
soll (dazu später mehr). Das Setzen  des
nächsten  IRQ-Auslösers  auf Rasterzeile
$F8 ist lediglich ein Relikt aus älteren
IRQ-Routinen, in denen wir  den  unteren
und  oberen  Rand des Bildschirms öffne-
ten. Da wir später jedoch wieder Raster-
zeile  $82  als  IRQ-Auslöser festlegen,
ist diese Befehlsfolge eigentlich  unnö-
tig.  Dennoch haben wir sie beibehalten,
da das Entfernen der beiden Befehle  zum
Einen  das  Timing, das zum exakten syn-
chronisieren zwischen Programm  und  Ra-
sterstrahl  notwendig  ist,  durcheinan-
derbrächte und wir dadurch andere Befeh-
le  zum  Verzögern einfügen müssten, und
zum Anderen um die Flexibilität der Rou-
tine  dadurch  nicht einzuschränken. Auf
diese Weise wird es z.B.  für  Sie  sehr
einfach,  die Routine mit einer Top- und
Bottom-Border-Funktion   "nachzurüsten",
indem  Sie  lediglich  die  IRQ-Vektoren
weiter unten  auf  eine  solche  Routine
verbiegen und das Festlegen des nächsten
IRQs  bei Rasterzeile $82 auf diese Rou-
tine verlagern. Dies ist  übrigens  eine
saubere   Möglichkeit   timing-kritische
IRQ-Routinen  zu  schreiben,   und   sie
zusätzlich  zu  anderen  Raster-Effekten
erweiterbar zu halten.  Da  wir  sowieso
die meiste Zeit verzögern müssen tun uns
die  beiden  Befehle  auch  nicht weiter
weh.                                    
Es folgt nun der  eigentliche  Kern  der
IRQ-Routine;  eine Schleife namens "FLD-
LOOP". Hier lesen  wir  zunächst  einmal
einen  Wert  aus der Tabelle "AD017" aus
und  tragen  ihn  in  das  Y-Expansions-
Register ein. Die besagte Tabelle befin-
det sich im Code ab  Adresse  $1600  und
enthält  die  Werte,  die nötig sind, um
das Sprite wie gewünscht zu  dehnen.  Da
wir  uns  in  den Beispielen 1 und 2 nur
auf ein  Sprite  beschränken  (Sprite  0
nämlich),  enthält die Tabelle natürlich
nur $00- und  $01-Werte.  Bei  $00  wird
ganz  normal die nächste Spritezeile ge-
lesen und angezeigt, bei $01 wird  immer
wieder  die zuletzt dargestellte Sprite-
zeile auf den Bildschirm gebracht.  Fol-
gen  mehrere  $01-Werte  aufeinander, so
wird eine  einzige  Spritezeile  so  oft
wiederholt, wie $01-Werte in der Tabelle
stehen.  Um die nächste Spritezeile dar-
zustellen muß  jetzt  mindestens  einmal
ein  $00-Wert  folgen.  Diese Zeile kann
nun ebenfalls  beliebig  oft  wiederholt
werden, usw. Zur besseren Öbersicht hier
ein  Auszug  aus  der  Tabelle mit Ihren
Werten für das Beispiel "STRETCHER.1":  
ad017:                                  
  .byte $01,$01,$01,$00,$01,$00,$00,$00 
  .byte $00,$00,$00,$00,$00,$00,$00,$00 
  .byte $01,$01,$01,$00,$01,$00,$00,$00 
  .byte $00,$00,$00,$00,$00,$00,$00,$00 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$01,$01,$01,$01 
  .byte $01,$01,$01,$01,$00,$00,$00,$00 
Wie  Sie  sehen   verzerren   wir   hier
zunächst  die  ersten  Spritezeilen ver-
schieden oft. Hiernach wird  die  letzte
Spritezeile  so  oft wiederholt, bis das
Ende unseres, durch FLD- und  Sideborder
behandelten, Bildschirmbereichs erreicht
wurde.                                  
Kommen wir jedoch wieder zu unserer FLD-
LOOP  zurück.  Nach  dem  Setzen  des Y-
Expansions-Registers wird  abermals  ein
Tabellenwert  gelesen und diesmal in Re-
gister $D011 übertragen. Diese  Befehls-
folge  ist für den FLD-Effekt notwendig,
mit dem wir den Beginn der nächsten Cha-
rakterzeile  vor  dem  Rasterstrahl her-
schieben. Die Tabelle enthält immer wie-
der  die  Werte $19, $1A, $1B, $1C, $1D,
$1E, $1F, $18, usw., womit wir in  jeder
Rasterzeile  die  Horizontalverschiebung
um eine  Rasterzeile  versetzt  vor  dem
Rasterstrahl herdrücken.                
Als Nächstes folgt das Üffnen des linken
und rechten Bildschirmrandes  durch  die
altbekannte  Befehlsfolge  zum schnellen
Runter- und wieder Hochschalten zwischen
38- und 40-Spalten-Darstellung.         
Durch  die  nun  folgenden 9 NOP-Befehle
verzögern wir solange, bis  der  Raster-
strahl  eine  Position  erreicht hat, zu
der  die   VIC-Schaltlogik   schon   die
gewünschte  Spritezeilenadresse  an  den
Datenbus angelegt hat, und somit der VIC
mit den gewünschten Spritedaten für die-
se Zeile gefüttert wurde. Jetzt schalten
wir die Y-Expansion wiederum ganz ab, um
das  Register für den nächsten Wert vor-
zubereiten.  Gleichzeitig  stellen   wir
damit  sicher, daß der Rest des Sprites,
der ggf. über  unseren,  vom  Raster-IRQ
behandelten,  Bereich  hinausragt  (z.B.
wenn wir das Sprite zu lang gedehnt  ha-
ben),  in  normaler  Darstellung auf den
Bildschirm gelangt. Es wird nun nur noch
der Index-Zähler im X-Register  für  den
nächsten  Schleifendurchlauf um 1 erhöht
und mit der  Anzahl  der  Raster-Effekt-
Zeilen  in  Register $02 verglichen. Ist
er noch kleiner als dieser Wert, so kön-
nen wir die Schleife wiederholen, um die
nächste  Rasterzeile  zu  bearbeiten. Im
anderen Fall sind wir am Ende angelangt,
wo  der  nächste  Interrupt  vorbereitet
wird,  bevor wir die IRQ-Routine wie ge-
wohnt beenden.                          
Damit  hätten  wir  auch  schon den Kern
unserer Routine  besprochen.  Experimen-
tieren  Sie  doch ein wenig mit der Ver-
zerrung, indem Sie die  Tabelle  "AD017"
ab  Adresse  $1600 mit Hilfe eines Spei-
chermoditors abändern. Sie werden  sehen
welch  lustige Deformierungen dabei ent-
stehen können! Beachten Sie  dabei,  daß
Sie  die  Form  des  Sprites im Speicher
niemals ändern, sonder daß die  Änderung
hardwaremäßig eintritt!                 
(Anm.d.Red.: Bitte wählen Sie nun den 2.
   Teil des IRQ-Kurs aus dem Textmenu)  
Valid HTML 4.0 Transitional Valid CSS!