home *** CD-ROM | disk | FTP | other *** search
/ ftp.uni-stuttgart.de/pub/systems/acorn/ / Acorn.tar / Acorn / acornet / fun / mags / hl-02-93.arc / !HL-02_93_Text_Text50 < prev    next >
Text File  |  1993-05-31  |  12KB  |  213 lines

  1.  
  2.  
  3.  
  4. ÿÿÿÿÿÿÿÿÿÿ Tips'n'Trix ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
  5.  
  6.  
  7. Diesmal haben wir in unserer Assemblerecke einen ganz besonderen Leckerbissen
  8. fⁿr Euch vorbereitet. Wie bereits in der letzten Ausgabe angekⁿndigt, geht's
  9. diesmal um Sprites.
  10. Sprites lassen - im Gegensatz zu ihren weniger beliebten Kollegen, den Shapes -
  11. an bestimmten Stellen den Grafikhintergrund durchscheinen. Besonders deutlich
  12. wird das bei Actiongames α la SWIV: Wⁿrde man dort die bewegten Objekte als
  13. Shapes erscheinen lassen, umgΣbe diese ein unsch÷ner, quadratischer und zumeist
  14. pechschwarzer Block. Ja richtig, Shapes entsprechen dem, was man sieht, wenn
  15. man beispielsweise mit !Paint eine kleine Grafik auf den Schirm pixeln wⁿrde.
  16. Nun, Shapes auf den Bildschirm zu plotten, erfordert kein besonders gro▀es
  17. programmiertechnisches Geschick: Man lΣdt einfach ein paar Register mit
  18. Grafikdaten und bringt diese dann ⁿber ein STM in den Bildschirmspeicher.
  19. Nach wenigen Taktzyklen gilt dann: Operation geglⁿckt, Patient tot. Hm, oder
  20. so Σhnlich. Zumindest wird ein eventueller Grafikhintergrund komplett
  21. ⁿberschrieben, das Shape erscheint viereckig.
  22. Bei Sprites sieht die Sache anders aus: Dort mu▀ erst Pixel fⁿr Pixel geprⁿft
  23. werden, ob der entsprechende Punkt transparent (=durchscheinend) oder gesetzt
  24. ist. Im ersten Fall darf der betreffende Pixel nicht geplottet werden,
  25. andernfalls schon. HΣufig wΣhlt man fⁿr diese durchscheinenden Spritepixel die
  26. Farbe schwarz.
  27.  
  28. Man sieht also, da▀ beim Plotten von Sprites ein ziemlich gro▀er Aufwand
  29. betrieben werden mu▀, um ein ansprechendes Ergebnis zu erzielen. Da die
  30. Jungs in den Entwicklungslaboratorien von Commodore anno dazumal wu▀ten, da▀
  31. ihre Kunden das niemals auf die Reihe bekommen wⁿrden, verpa▀ten sie ihren
  32. Computern (C64 & Amiga) kurzerhand jede Menge Hardwaresprites. Wie der Name es
  33. schon andeutet, ⁿbernimmt hier die Hardware die ⁿble Arbeit beim
  34. Spriteplotten. Der Programmierer spart hier also viel Rechenzeit ein. Leider
  35. hat die Sache auch einen Haken: Die Gr÷▀e der Sprites und die Anzahl der
  36. Farben ist begrenzt. Und weil die findigen Entwickler von Acorn den
  37. Programmierern einen m÷glichst gro▀en Freiraum lassen wollten, spendierten sie
  38. dem Archie auch nur ein einziges Hardwaresprite: den Mauspointer. Dieser ist
  39. maximal 32 Pixel breit, dafⁿr aber beliebig hoch, und enthΣlt zu allem
  40. ▄berflu▀ auch noch drei Farben (die vierte Farbe ist transparent) ! Diese
  41. au▀ergew÷hnlich reichliche Ausstattung an grafischen Grundlagen (ê Ironie) hat
  42. es bewirkt, da▀ das Hardwaresprite auf dem Archie noch nie "zweckentfremdet"
  43. wurde; mir ist kein Fall bekannt, in dem durch das Hardwaresprite
  44. beispielsweise ein Gegner in einem Actionspiel dargestellt wurde. Lieb und
  45. brav wie ein unbescholtener Bⁿrger verrichtet unser Hardwaresprite seine
  46. treuen Dienste als solider Mauspointer. Und das soll auch ruhig so bleiben.
  47.  
  48. Bevor wir nun in die Grundlagen der Spriteprogrammierung einsteigen, noch was
  49. wichtiges: Wenn im folgenden von Sprites die Rede ist, sind damit NICHT die
  50. herk÷mmlichen Sprites im Systemformat gemeint ! Gemeint sind die puren
  51. Spritegrafik-Daten, also ohne Name, Gr÷▀enangabe, usw. Wie man aus normalen
  52. Spritedateien reine Grafikdateien macht, erfahrt Ihr in einem der beigelegten
  53. Listings ("SpriteHack").
  54.  
  55. Wagen wir also den ersten Schritt in Richtung Spriteprogrammierung. Angenommen,
  56. R0 zeigt auf das Sprite, und R1 enthΣlt die Adresse, an die das Sprite
  57. geplottet werden soll. Nehmen wir weiter an, da▀ wir uns in Mode 13 befinden
  58. und da▀ das Sprite die Gr÷▀e 32x32 Pixel hat. Dann k÷nnte eine Spriteroutine
  59. folgenderma▀en aussehen:
  60.  
  61. ; R0-Sprite, R1-Plotadresse
  62. ; R2-SpaltenzΣhler, R3-ZeilenzΣhler
  63.  
  64.                  MOV R3,#32                ; 32 Zeilen
  65. .zeile_auslesen  MOV R2,#0                 ; R2 = 0..31
  66. .spalte_auslesen LDRB R4,[R0],#1           ; lese ein Byte
  67.                  CMP R4,#0                 ; Byte schwarz ?
  68.                  STRNEB R4,[R1,R2]         ; nein -> dann plotte
  69.                  ADD R2,R2,#1              ; erh÷he ZΣhler
  70.                  CMP R2,#31                ; Ende der Zeile ?
  71.                  BMI spalte_auslesen       ; nein, nΣchster Pixel
  72.                  ADD R1,R1,#320            ; nΣchste Bildschirmzeile
  73.                  SUBS R3,R3,#1             ; fertig ?
  74.                  BGT zeile_auslesen        ; nein, nΣchste Zeile auslesen
  75.  
  76. Eine wahrhaft sch÷ne Routine. Leider hat sie einen gro▀en Nachteil: Sie
  77. verbraucht pro Sprite durchschnittlich ganze 15000 Taktzyklen ! Das wⁿrde
  78. bedeuten, da▀ wir maximal 8 Sprites gleichzeitig darstellen k÷nnten (bei
  79. 50 Hertz)... Aber in Spielen, Demos, usw. schaffen's die Leute doch auch
  80. immer wieder, ein paar Sprites mehr auf dem Monitor herumspringen zu lassen !
  81.  
  82. Der Flaschenhals bei unserer Routine ist das lΣstige, byteweise Lesen und
  83. Schreiben eines jeden einzelnen Spritepixels. Zumindest das Lesen k÷nnen wir
  84. optimieren, indem wir nun jeweils 32 Pixel (=8 words) gleichzeitig lesen,
  85. die einzelnen Bytes ausmaskieren und dann wie oben verfahren. Zum Ausmaskieren
  86. ben÷tigen wir aber eine Maske (!), und fⁿr einen einzelnen Pixel hat diese
  87. den Wert %11111111 (binΣr), &FF (hexadezimal) oder 255 (dezimal).
  88. Also:
  89.  
  90. ; R0-Sprite, R1-Plotadresse
  91. ; R2-ZeilenzΣhler
  92.  
  93.                  MOV R3,#&FF               ; Bytemaske
  94.                  MOV R2,#32                ; ZeilenzΣhler
  95. .zeile_plotten   LDMIA R0!,{R4-R11}        ; hole 32 Spritebytes
  96.  
  97.                  ANDS R12,R3,R4            ; maskiere 1. Pixel aus (1. Wort)
  98.                  STRNEB R12,[R1,#0]        ; plotte, wenn Pixel gesetzt
  99.                  ANDS R12,R3,R4,LSR#8      ; maskiere 2. Pixel aus
  100.                  STRNEB R12,[R1,#1]        ; plotte, wenn Pixel gesetzt
  101.                  ANDS R12,R3,R4,LSR#16     ; maskiere 3. Pixel aus
  102.                  STRNEB R12,[R1,#2]        ; s.o.
  103.                  ANDS R12,R3,R4,LSR#24     ; maskiere 4. Pixel aus
  104.                  STRNEB R12,[R1,#3]        ; s.o.
  105.  
  106.                  ANDS R12,R3,R5            ; maskiere 5. Pixel aus (2. Wort)
  107.                  STRNEB R12,[R1,#4]        ; plotte, wenn Pixel gesetzt
  108.                  ANDS R12,R3,R5,LSR#8      ; maskiere 6. Pixel aus (2. Wort)
  109.                  STRNEB R12,[R1,#5]        ; ...
  110.                  ...
  111.                  usw. bis:
  112.                  ...
  113.                  ANDS R12,R3,R11,LSR#24    ; maskiere 32. Pixel aus (8. Wort)
  114.                  STRNEB R12,[R1,#31]       ; plotten, wenn Pixel gesetzt
  115.  
  116.                  ADD R1,R1,#320            ; eine Bildschirmzeile runter
  117.                  SUBS R2,R2,#1             ; fertig ?
  118.                  BNE zeile_plotten         ; nein, nΣchste Zeile
  119.  
  120. Diese Routine hat schon eine recht ansehliche Performance. Sie ist zwar
  121. ziemlich lang (ca. 260 Bytes) , verbraucht aber nur noch 4000-5000 Taktzyklen
  122. pro Sprite. Das entspricht etwa 20-30 Sprites pro VSync, was doch schon ganz
  123. beachtlich ist.
  124.  
  125. Trotzdem kann man auch hier noch krΣftig optimieren. Erreichen k÷nnen wir dies,
  126. indem wir auch fⁿr das Plotten der Spritedaten nicht das STRB-Kommando
  127. verwenden, sondern das zeitgⁿnstige STM. Wie das ?
  128. Der Trick bei der Sache ist, da▀ wir nun dem Sprite eine vordefinierte Maske
  129. beilegen. Auf ein Spritewort folgt ein entsprechendes Maskenwort, dann wieder
  130. ein Spritewort, ein Maskenwort, usw. Fⁿr jeden Spritepixel existiert in der
  131. Maske ein "Maskenpixel". Wie schon in der obigen Routine, enspricht auch hier
  132. ein Maskenwert von 255 dem Pixelzustand "gesetzt".
  133. Beim Plotten gehen wir nun wie folgt vor: ZunΣchst werden Spritegrafik und der
  134. entsprechende Hintergrund geladen. Nun werden ⁿber logische Operationen mit
  135. der Maske aus dem Hintergrund genau die Pixel gel÷scht, die im Sprite
  136. "gesetzt" sind. Wir erhalten also auf dem Hintergrund ein genaues Schattenbild
  137. des Sprites. Jetzt verknⁿpfen wir ⁿber logische Operationen erneut den
  138. Hintergrund, diesmal aber mit der Spritegrafik: Der Schatten wird mit Farbe
  139. gefⁿllt. Im Schlu▀akt bringen wir das Ergebnis mit einem STM-Kommando zurⁿck
  140. auf den Bildschirm und k÷nnen uns der nΣchsten Spritezeile zuwenden.
  141.  
  142. Programmtechnisch bedeutet das folgendes:
  143.  
  144. ; R0-Sprite, R1-Plotadresse
  145. ; R2-ZeilenzΣhler
  146.  
  147.                  MOV R2,#32
  148. .zeile_plotten   LDMIA R1,{R3-R6}          ; hole Hintergrund (4 Worte)
  149.                  LDMIA R0!,{R7-R14}        ; hole Sprite (7,9,11,13)
  150.                                                & Maske (8,10,12,14)
  151.  
  152.                  BIC R3,R3,R8              ; 1. Hintergrundwort masken
  153.                  BIC R4,R4,R10             ; 2. Hintergrundwort
  154.                  BIC R5,R5,R12             ; 3. Hintergrundwort 
  155.                  BIC R6,R6,R14             ; 4. Hintergrundwort
  156.  
  157.                  ORR R3,R3,R7              ; 1. Hintergrundwort mit Sprite
  158.                                                 verknⁿpfen
  159.                  ORR R4,R4,R9              ; 2. Hintergrundwort
  160.                  ORR R5,R5,R11             ; 3. Hintergrundwort
  161.                  ORR R6,R6,R13             ; 4. Hintergrundwort
  162.  
  163.                  STMIA R1!,{R3-R6}         ; Resultat plotten
  164.  
  165.  
  166.                  LDMIA R1,{R3-R6}          ; das Ganze nochmal
  167.                  LDMIA R0!,{R7-R14}
  168.                  BIC R3,R3,R8:BIC R4,R4,R10
  169.                  BIC R5,R5,R12:BIC R6,R6,R14
  170.                  ORR R3,R3,R7:ORR R4,R4,R9
  171.                  ORR R5,R5,R11:ORR R6,R6,R13
  172.                  STMIA R1!,{R3-R6}
  173.  
  174.                  ADD R1,R1,#288            ; eine Zeile runter
  175.                  SUBS R2,R2,#1             ; fertig ?
  176.                  BNE zeile_plotten         ; nein, nΣchste Zeile
  177.  
  178. Leider ist die Routine so noch nicht ganz vollstΣndig. Wie mancher von Euch
  179. bereits wissen wird, kann man mit den STM/STR/LDM/LDR-Kommandos nur ganze
  180. W÷rter (sogenannte ALIGNte Adressen = durch vier teilbar) sinnvoll ansprechen.
  181. Es kann aber durchaus passieren, da▀ ein Sprite an eine Adresse geplottet
  182. werden mu▀, die NICHT durch vier teilbar ist. Dieses Problem umgeht man
  183. dadurch, da▀ man im Speicher vier Sprites vorliegen hat, die jeweils um
  184. einen Pixel gegeneinander verschoben sind. Bevor man nun das Sprite plottet,
  185. ermittelt man, welche "inner word"-Position das Sprite hat (liegt zwischen
  186. null und drei), und wΣhlt dann dementsprechend das richtige Sprite zum Plotten
  187. aus. NΣheres dazu findet Ihr im beigelegten Demolisting im Directory
  188. "Examples". Ach ja, das Verschieben der vier Sprites geschieht im Demo mit
  189. einem Trick: Zu Beginn wird beim Laden der Spritedaten von Diskette das
  190. Spritefile einfach an verschiedene Adresse geladen ! Aber das Erstellen der
  191. Maske wird dann doch in Assembler vorgenommen. Schaut Euch alles in Ruhe an,
  192. der Durchblick kommt irgendwann von allein.
  193. Aber fⁿr Eure Arbeit werdet Ihr auch belohnt, denn Ihr besitzt dann eine
  194. Spriteroutine, die sich gewaschen hat. Pro Sprite ben÷tigt sie nur noch ca.
  195. 2000 Taktzyklen, was fⁿr ungefΣhr 50 Sprites pro VSync locker ausreicht. Die
  196. Nachteile der Mask&Plot-Methode will ich nicht verschweigen: Der Speicher-
  197. platzbedarf ist enorm, denn pro Sprite braucht man immerhin vier
  198. "geshiftete" Sprites und vier "geshiftete" Masken, was den ben÷tigten Speicher
  199. auf das Achtfache des Originals ansteigen lΣ▀t. Au▀erdem mⁿssen die drei
  200. linken Pixelspalten des Ur-Sprites leer (schwarz) sein, damit das Shiften
  201. richtig funktioniert. Aus einem 32x32-Sprite wird also effektiv ein 29x32-
  202. Sprite.
  203.  
  204.                                                                - Tim Juretzky -
  205.  
  206.  
  207. PS: Fⁿr Insider sei noch gesagt, da▀ sich sogar die Mask&Plot-Technik noch
  208. verfeinern lΣ▀t. Der Zeitgewinn liegt zwar "nur" bei 15 Prozent, aber bei
  209. kritischen Routinen ist sogar das schon eine Menge. Vielleicht gelingt es
  210. ja einem von Euch, bis zum nΣchsten Mal eine entsprechende Routine zu
  211. prΣsentieren... ?!?
  212.  
  213.