Magic Disk 64

home to index to text: MD9411-KURSE-IRQ-KURS_13.1.txt
                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 anschauen, und dabei lernen, daß es auch Sprites gibt, die mehr als 21 Rasterzeilen hoch sind. . .
1) DAS PRINZIP Wie immer kommen wir zu Beginn zum Funktionsprinzip des Rastereffektes dieses Kursteils: Wie Sie vielleicht wissen, so ist die Größe eines Sprites prinzipiell auf 24 x21 Pixel begrenzt. Diese Größe ist starr und eigentlich nicht veränderbar. 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 $ D01 D die Xund Y-Expansion eines Sprites einschalten.
In diesem Fall kann sowohl die Xals auch die Y-Ausdehnung verdoppelt werden, so daß wir ein Sprite mit einer maximalen Größe von 48 x42 Pixeln erhalten, in dem die normalen 24 x21 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.
Drehund Angelpunkt dieses Effektes wird das eben schon angesprochene Register 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 expandiert. Der VIC vergleicht nun jede Rasterzeilennummer 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 Schaltlogik 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 relevanten 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 Schreibzugriff 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 Spritedaten für die erste Rasterzeile.
Gleichzeitig wird bei Erreichen der nächsten Rasterzeile der 1- Bit-Zähler um eins erniedrigt. Tritt dabei ein Unterlauf auf, so reinitialisiert die Schaltlogik den Zähler wieder mit dem Inhalt des Latch-Registers und erhöht die Quelladresse für die Speitedaten um 3 Bytes, so daß Sie anschließend dem VIC die Daten der nächsten Spritezeile zukommenlässt. Tritt kein Unterlauf auf, weil der Zähler auf 1 stand und beim Herunterzählen auf 0 sprang, so bleibt die Quelladresse der Spritedaten unverändert, so daß der VIC auch in dieser Rasterzeile dieselben Spritedaten liest, die er auch eine Rasterzeile vorher schon darstellte. Ist die Spriteexpansion 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 Rasterzeile eine neue Adresse an den Datenbus angelegt, womit der VIC das Sprite in der Vertikalen doppelt so hoch darstellt.
Wie nun eingangs schon erwähnt so werden sowohl Latch als auch Zähler neu initialisiert, 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 Sprites bewirken ( indem jede Spritezeile 3-,4- oder 5- mal hintereinander dargestellt wird) ! Wir haben sogar die Möglichkeit jede Spritezeile beliebig, und voneinander 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 Rasterzeile 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 Sprites, um die Daten der nächsten Spritezeile in den VIC zu holen!

2) PROGRAMMBEISPIELE 1 UND 2            

Um einen Eindruck von den Möglichkeiten zu bekommen, die uns dieser Effekt bietet, sollten Sie sich einmal die Beispielprogramme " 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" gestartet. Die ersten beiden Beispiele stellen ein Sprite dar, das normalerweise nur eine diagonale Line von der linken oberen Ecke zur rechten unteren Ecke des Sprites enthält. Im ersten Beispiel haben wir lediglich einige dieser Zeilen mehrfach dargestellt. Das zweite Beispiel enthält eine Streckungstabelle, mit der wir jede Rasterzeile in Folge 1-,2-,3-,4-,5-, und 6- Mal darstellen, womit die Linie in etwa die Rundungen einer Sinuskurve bekommt!
Wollen wir uns nun einmal den Programmcode 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 identisch mit unseren anderen IRQ-Beispielen ist. Wir legen hier den Raster-IRQ auf Rasterzeile $82 fest und schalten Betriebssystem- 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 altbekannter Trick zum Glätten des IRQs aufgefü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 Routinenteile 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 Sprite- Stretch, FLDund Sideborderroutinen.
Hierzu schreiben wir erst einmal die Anzahl der Rasterzeilen, in denen diese drei Effekte aktiv sein sollen als Vergleichszähler in Adresse $02 und löschen das X-Register, das als Index auf die FLDund 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 öffneten. Da wir später jedoch wieder Rasterzeile $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 synchronisieren zwischen Programm und Ra- sterstrahl notwendig ist, durcheinanderbrächte und wir dadurch andere Befehle zum Verzögern einfügen müssten, und zum Anderen um die Flexibilität der Routine dadurch nicht einzuschränken. Auf diese Weise wird es z. B. für Sie sehr einfach, die Routine mit einer Topund 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 Routine verlagern. Dies ist übrigens eine saubere Möglichkeit timingkritische 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 befindet 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 gelesen und angezeigt, bei $01 wird immer wieder die zuletzt dargestellte Spritezeile auf den Bildschirm gebracht. Folgen mehrere $01- Werte aufeinander, so wird eine einzige Spritezeile so oft wiederholt, wie $01- Werte in der Tabelle stehen. Um die nächste Spritezeile darzustellen 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 verschieden oft. Hiernach wird die letzte Spritezeile so oft wiederholt, bis das Ende unseres, durch FLDund 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 Register $ D011 übertragen. Diese Befehlsfolge ist für den FLD-Effekt notwendig, mit dem wir den Beginn der nächsten Charakterzeile vor dem Rasterstrahl herschieben. Die Tabelle enthält immer wieder die Werte $19,$1 A,$1 B,$1 C,$1 D,$1 E,$1 F,$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 Runterund wieder Hochschalten zwischen 38- und 40- Spalten-Darstellung.
Durch die nun folgenden 9 NOP-Befehle verzögern wir solange, bis der Rasterstrahl 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 diese Zeile gefüttert wurde. Jetzt schalten wir die Y-Expansion wiederum ganz ab, um das Register für den nächsten Wert vorzubereiten. 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 haben), 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önnen 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 gewohnt beenden.
Damit hätten wir auch schon den Kern unserer Routine besprochen. Experimentieren Sie doch ein wenig mit der Verzerrung, indem Sie die Tabelle " AD017" ab Adresse $1600 mit Hilfe eines Speichermoditors abändern. Sie werden sehen welch lustige Deformierungen dabei entstehen 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!