home *** CD-ROM | disk | FTP | other *** search
/ Falcon 030 Power 2 / F030_POWER2.iso / ST_STE / MAGS / UCM9.ARJ / ucm9 / SOURCES.LZH / VOXEL / VOXEL.TXT < prev   
Text File  |  1997-06-25  |  33KB  |  733 lines

  1. Lamers Heaven
  2.  
  3. Ausgabe 1:     Voxel Space ST
  4. Autor:         Mike of STAX
  5.  
  6. Willkommen zur ersten Ausgabe von Lamers Heaven !
  7.  
  8. EINLEITUNG:
  9.  
  10. Da diese Serie erst neu ab dieser Undercover Edition er÷ffnet wurde, m÷chte ich Euch erst kurz was ⁿber Sinn und Zweck der ganzen Vorstellung erzΣhlen.
  11. Ich bin Mike of STAX und wurde von Moondog/TNB dazu ⁿberredet, ihn beim Aufbau einer
  12. ST Coding Corner zu unterstⁿtzen. 
  13. Vielleicht hat der ein oder andere schon mal was von der Gruppe STAX geh÷rt, in der letzten
  14. Zeit aber bestimmt nicht viel, da es doch sehr ruhig um uns geworden ist. Neben Matt war/bin
  15. ich fⁿr Coding/Design und in alten Tagen auch mal fⁿr die ein oder andere Grafik zustΣndig
  16. gewesen - doch das ist ehrlich gesagt schon eine Weile her. So war ich den TrΣnen der Rⁿhrung nahe, als ich die alten Quellen hervorholte und analysierte (wie war das noch anno
  17. 94 ...???). Soviel mu∞ gleich vorweg gesagt werden: sΣmtliche Codes haben schon ein
  18. ehrfurchtsvolles Alter (Copyright 1994 und frⁿhes 1995), auch wurde nichts mehr daran ver-
  19. Σndert oder gar optimiert. Fast alle Effekte sind mit der Intention entstanden, m÷glichst viele
  20. verschiedene FX m÷glichst bald zu haben (Grundlagenforschung !).
  21. Moondog/TNB zufolge gibt es noch ein paar hartgesottene ST Coder (auch die Polen sind ja 
  22. schwer im kommen ...), so da∞ ich mich fⁿr die Idee einer Coding Ecke begeistern lie∞. Ich
  23. selbst habe meine lehrreichen Lektionen noch aus der ehrwⁿrdigen "Hexer" - Serie in der 
  24. 68000er/ST-Magazin um die Jahre 88/89. In jenen Tagen drehte sich noch alles um das שffnen
  25. der RΣnder, Raster Interrupts und Plane FX. Wer hierzu mehr wissen und das Gefⁿhl der ST-
  26. Hochzeiten spⁿren will, dem seien diese Ausgaben empfohlen (bei Interesse gebe ich gerne 
  27. die genauen Heftnummer an - im Kopf habe ich die nicht mehr ...).
  28. Genauer betrachtet hat sich auf dem ST seit diesen Zeiten doch viel getan. Dominierten am
  29. Anfang noch Raster/Randeffekte, wurde im Anschlu∞ daran die Copy-Leistung des ST's 
  30. hinsichtlich Scrolling (Screen, Laufschriften) und Bl÷cken aller Art (Shapes, Sprites) ausgelotet.
  31. Heutzutage dreht sich fast alles um Pixel Effekte - also VerΣnderung von einzelnen Pixeln, 
  32. natⁿrlich m÷glichst viele (freilich gab es auch viele Sternenfeld Routinen, aber die aktuellen
  33. FX fordern viel mehr PunktverΣnderungen). In diese Gruppe geh÷ren sicherlich die Zoomer,
  34. Rotierer, Texturemapper, Gouraudshader oder sogar Bumpmapper ... (die Liste kann beliebig
  35. fortgesetzt werden - siehe PC - aber fⁿr uns ST-Jⁿnger ist bei der Rechenzeit irgendwo auch
  36. mal Schlu∞, in der Fantasie nicht ...).
  37. Lamers Heaven als Coding Ecke soll eine feste Instanz des beliebten Undercover Mags werden, ob ich immer dabei bin, ist allerdings fraglich. Auf jeden Fall schon mal viel Spa∞ 
  38. mit dieser und den folgenden Ausgaben.
  39.  
  40. THEMA
  41.  
  42. Ich m÷chte hier hauptsΣchlich Effekte der Pixelgruppe vorstellen, aktuelles Thema in dieser, der ersten Ausgabe, ist:
  43.  
  44.                 VOXELSPACE
  45.  
  46. Einige Anmerkungen zur Vorgehensweise. Ich werde keine kompletten Quellen mitliefern,
  47. sondern neben allegemeinen ErklΣrungen und detailierten Hinweisen nur Schlⁿsselteile 
  48. des Codings vorstellen. Wer sich etwas damit beschΣftigt, kommt damit sicherlich zurecht.
  49. Ausfⁿhrbare PRG Files schon eher (leider hat die Zeit diesmal nicht mehr gereicht, sowas
  50. auf die Beine zu stellen - folgt noch) - schlⁿsselfertige Quellen, wie gesagt nicht.
  51. Manche der vorgestellten Methoden oder Tricks sind nicht auf meinem Mist gewachsen. So ist diesmal ein Trick beim Ablegen der Raydaten (folgt noch ...) und deren  Berechnungs-routine nicht 100% original von mir. Manchmal bringt einen ein GesprΣch mit anderern ST    
  52. Leidensgenossen auf neue Ideen ...
  53.  
  54. Motivation
  55.  
  56. "Hallo Mike, hast Du schon Commanche gesehen, kuck doch mal her !". Tja, und da habe ich dann mal auf den PC Monitor geschaut - und  gestaunt. Das ist ja echt ⁿbel gewesen.
  57. Ich habe dann spontan auf dem ST rumprobiert, aber da kam nix raus. Erst spΣter wollte es
  58. dann klappen - und diesmal haben die PCler auch etwas bl÷d geschaut. Soviel vorweg:
  59. natⁿrlich kann man das Vorbild nicht total erreichen, aber ein bi∞chen was geht immer ...
  60.  
  61. Wer noch keine Voxelspace Routine gesehen hat, hier kurz ein ץberblick:
  62. Voxelspace ist eine Technik mit der man 2D Aufnahmen mit einfachen Mitteln als 3D Modelle
  63. bzw. Volumenk÷rper anzeigen kann (Voxel = Volume Pixel), indem man diesen Aufnahmen 
  64. mit den Voxeln rΣumliche Tiefe verleiht.Gern benutzt um ⁿber Landschaften zu gleiten, deren
  65. Ursprung oftmals Satellitenaufnahmen sind; wird auch in der Medizin - IT vielfach eingesetzt.
  66. In unserem Fall soll es um die Darstellung von Landschaften gehen, ⁿber die man mit einem
  67. FluggerΣt gleiten kann.
  68.  
  69. Ausgehend vom PC Commanche ergeben sich folgende Anforderungen:
  70.  
  71. 1)  M÷glichst gro∞e Landkarte
  72. 2)  Nuancenreich sowohl bei der Aufl÷sung der Voxel als auch bei der naturgetreuen Farb-gebung
  73. 3)  Hohe Geschwindigkeit der Animation
  74. 4)  Freie Bewegbarkeit des Gleiters in alle Richtungen mit Drehung
  75. 5)  VerΣnderbarkeit der Flugh÷he des Gleiters
  76.  
  77. Grundlagen
  78.  
  79. ץble Geschichte, oder ? Ok, gehen wir mal durch, was wir alles brauchen und warum.
  80.  
  81. 1)  Landkarte
  82.  
  83. Ausganspunkt ist eine 2D Landkarte, die wir dreidimensional darstellen wollen. Die einzelnen
  84. Pixel haben eine bestimmte Farbe. Den Pixeln wird nun noch eine H÷he zugewiesen.
  85. Damit steht schonmal die grundlegende Datenstruktur. 
  86. Wenn wir so ⁿber die Landschaft dⁿsen, sehen wir immer einen Ausschnitt aus unserer Karte.
  87. Um es erstmal einfach zu machen, stellen wir uns diesen Ausschnitt als Rechteck dar, der
  88. ausgelesen und auf dem Screen dargestellt wird.
  89.  
  90. Unser Landkartenausschnitt k÷nnte so aussehen (hier mal nur 4x4 Pixel, von oben betrachtet):
  91.  
  92.     M N O P
  93.     I J K L
  94.     E F G H
  95.     A B C D
  96.     
  97.           /\
  98.           ||
  99.  
  100.       Betrachter
  101.  
  102. Stellt man sich nun jeden Pixel als einen kleinen Turm vor mit einer bestimmten H÷he, so
  103. sieht man vorne die erste Zeile mit den Tⁿrmen A,B,C,D. Sind diese etwas niedriger, sieht 
  104. man auch die Tⁿrme dahinter, vielleicht sogar die MNOP Turmreihe. Die Tⁿrme werden zusΣtzlich in ihrer H÷he entsprechend ihrer Entfernung vom Betrachter perspektivisch angepa∞t. Ein Turm weiter hinten ist zwar kleiner in seiner eigenen H÷he, aber beginnt am Boden auch etwas weiter oben. Am besten selbst mal in die Ferne sehen, um diese Perspektive in der Praxis zu sehen.
  105.  
  106. Ok, unsere Pixel werden also zu Tⁿrmchen mit einer bestimmten Farbe und H÷he (diese beiden Informationen bilden zusammen unsere erste Voxel Datenstruktur). Wie man die Tⁿrmchen zeichnet, werden wir gleich kennenlernen.
  107.  
  108. Man baut den Screen in Spalten auf. Jede X Spalte wird einzeln aufgebaut, bis der Screen-
  109. inhalt steht. Ausgehend von unserem Beispiel betreffen die Pixel A, E, I, M (Pixel + H÷he,
  110. ab jetzt Voxel = Turm genannt) unsere erste Scanspalte. Wir beginnen in jeder Screenspalte unten mit dem Zeichnen, die Landkarte gehen wir von vorne nach hinten durch. 
  111. In unserem Fall also Turm A. Dieser habe die H÷he 2 , also werden zwei Pixel mit der
  112. Farbe A von unten nach oben gezeichnet (Schritt 1).
  113.  
  114. Spalte 1 (Spalte ganz links zeigt die Zeile (H÷he) an):
  115.  
  116.     Schritt 1    Schritt 2    Schritt 3    Schritt 4
  117. 6
  118. 5
  119. 4                            M
  120. 3            E        E        E
  121. 2    A        A        A        A
  122. 1    A        A        A        A
  123.  
  124.  
  125. Turm E habe die H÷he 3, da wir uns weiter vom Betrachter wegbewegen, wird die H÷he auf
  126. 2 angepa∞t, das Grundoffset sei 1, 2+1 = 3 (immer von unten gerechnet !). Jetzt m÷chten
  127. wir aber den Turm A nicht ⁿbermalen, da der ja eigentlich vor uns steht und somit ja als erstes sichtbar sein mⁿ∞te. Man merkt sich nach jeder Zeichenoperation die H÷he des VorgΣngers und vergleicht sie mit der neu zu zeichnenden H÷he. Ist die neue H÷he kleiner als die alte, mu∞ ja nichts gezeichnet werden, da der neue Turm hinter dem Vordermann und somit un-sichtbar fⁿr den Betrachter ist. Liegt sie ⁿber dem VorgΣngerturm, zeichnet man nur die H÷hendifferenz darⁿber (Schritt 2).
  128.  
  129. Voxel I hat die H÷he 2, nach Perspektivenanpassung nur noch 1, Grundoffset sei 2, macht 3.
  130. Da der VorgΣngerturm schon die Zeichenh÷he von 3 hatte ist der neue Turm nicht sichtbar
  131. (Schritt 3).
  132.  
  133. Turm M sei wieder sichtbar (Schritt 4). Somit ist eine Bildschirmspalte gefⁿllt. Das gleiche Ver-
  134. fahren wird nun auf alle Spalten angewendet (Spaltenberechnung mit Voxeln B, F, J, N, usw.)
  135. bis der Landschaftscreen steht (siehe auch Grafik TURM.IFF).
  136.  
  137. Noch ein Satz zur Voxeldatenstruktur. Da pro Voxel H÷he + Farbe anfallen (angenommen, wie
  138. auf dem PC 256 Farben = 1 Byte + 256 H÷hen = 1 Byte -> 2 Byte pro Voxel) kommt da fⁿr eine
  139. ordentliche Landschaft schon was zusammen:
  140. 512 X 512 in der Ausdehnung macht 512x512x2 = 524 KB und das ist noch keine gro∞e Landschaft ! Bei Commanche waren die Maps gr÷∞er (ca. 1024x1024 = 2MB), fⁿr den ST ist das indiskutabel, noch dazu weil noch anderes Zeugs mit in den Speicher mu∞ (siehe 
  141. IMPLEMENTIERUNG).
  142.  
  143.  
  144. 2) Nuancenreich sowohl bei der Aufl÷sung der Voxel als auch bei der naturgetreuen Farb-gebung
  145.  
  146. Die Breite unserer Voxeltⁿrme ist natⁿrlich entscheidend fⁿr die Aufl÷sung insgesamt. Eine
  147. angestrebte ScreenzeichenflΣche von 256x160 (wer will, kann auch noch mehr machen ...)
  148. bedeutet bei einer 1 Pixel Turmbreite fⁿr den ST Overkill. Man mu∞ es hier etwas grober an-gehen. Hier gibt es die Varianten von 4 (mein Vorschlag) oder 8 Pixeln. Das ist machbar.
  149. Bei den Farben ist bei 16 Schlu∞. Leider. Diese sollten daher gut aufeinander abgestimmt sein.
  150. Ich habe mal probiert mit Rasterungen Zwischenfarben zu erzeugen. Das Ergebnis war
  151. scheu∞lich ...
  152.  
  153. 3)  Hohe Geschwindigkeit der Animation
  154.  
  155. Mit einer 4er Aufl÷sung und einem kleinerem Fenster (wie unter 2) beschrieben) sind Frame-
  156. raten um die 17 Bilder drin. Das geht in Ordnung.
  157.  
  158. 4)  Freie Bewegbarkeit des Gleiters in alle Richtungen mit Drehung
  159.  
  160. Das kommt gut, macht aber die Landkartenauswertung etwas schwieriger. Wer darauf  ver-
  161. zichten kann, wertet die Landschaft wie oben beschrieben mit einem rechteckigen Fenster
  162. aus, welches er in X und Y Richtungen verschieben kann (aber eben nicht drehen ...).
  163. Wer es sich und dem ST so richtig geben m÷chte, macht es mit Drehung. 
  164. Man kann hier nicht einfach ⁿber- bzw. nebeneinander liegende Voxel auslesen. 
  165. Auslesen in AbhΣngigkeit von der Richtung kann man wie folgt:
  166. Man stelle sich einen Kreis vor mit Mittelpunkt B. B ist der Betrachter. man schickt nun Strahlen von diesem Mittelpunkt in die Welt hinaus; diese stellen die Sehstrahlen des Betrachters dar.
  167. Eine volle Umdrehung hat 360 Grad, also nehmen wir mal 360 Strahlen (Abstand 1 Grad).
  168. Wenn der Betrachter jetzt genau nach Norden schaut (Grad 0) und wir annehmen, da∞ sein
  169. Sichtkegel noch ein wenig nach links und rechts geht, werten wir z.B. die Strahlen 330 - 30 Grad aus (angenommen  60 Grad Sichtkegel). Wenn wir uns etwas nach rechts drehen (30 Grad), dann werten wir die Strahlen 0 - 60 aus (man stelle sich den Kreis mit den Strahlen vor;
  170. siehe auch Grafik STRAHL.IFF !).
  171. Viel mehr ist es gar nicht. Die Strahlen werden vorher berechnet (genauer: x + y Offsets - siehe IMPLEMENTIERUNG !) und auf die Landkarte angewendet (in AbhΣngigkeit von der Betrachterposition).
  172.  
  173. Als weiters Goodie kann man auch noch das Kippen des Horizontes einbauen. Hierfⁿr werden
  174. die Startscreenoffsets fⁿr die einzelnen Spalten = Tⁿrmchen nach oben/unten modifiziert. 
  175.  
  176.  
  177. 5)  VerΣnderbarkeit der Flugh÷he des Gleiters
  178.  
  179. Wenn sich die Flugh÷he verΣndert, verΣndert sich auch die Perspektive auf die Landschaft.
  180. In AbhΣngigkeit davon mu∞ die Perspektivenanpassung bei der H÷henberechnung wΣhrend des Spaltenzeichnens durchgefⁿhrt werden. Dies beeinflu∞t die Perspektivenanpassung der
  181. Voxelgrundh÷he (wie in der Landkarte abgespeichert) und das H÷hengrundoffset. Das 
  182. lΣuft das auf mehrere Perspektiventabellen hinaus - das erklΣre ich nicht weiter. Mit einem
  183. einfachen Strahlensatz kommt man da weiter - probierts mal.
  184.  
  185. Neben der Drehbarkeit ist diese FunktionalitΣt sicherlich auch optional.
  186.  
  187.  
  188. Implementierung
  189.  
  190. 0)  Landschaftsdaten
  191.  
  192. Unsere Landschaft soll die Gr÷∞e 256x256 haben. Fⁿr jeden Voxel speichern wir ein Byte fⁿr die
  193. H÷he und ein Byte fⁿr die Farbe ab. Man k÷nnte es auch so angehen, da∞ man aus der H÷he
  194. die Farbe ableiten kann. Ich habe mich fⁿr die erste Methode entschieden. Eine Zeile der 
  195. Landschaftsmatrix wird folgenderma∞en im Speicher abgelegt:
  196.  
  197. 256 H÷henbytes     -> erste Landschaftszeile
  198. 256 Farbbytes        -> erste Landschaftszeile
  199. 256 H÷henbytes     -> zweite Landschaftszeile
  200. 256 Farbbytes        -> zweite Landschaftszeile
  201. ...
  202.  
  203. Wichtig: die H÷henwerte sind mit 4 multipliziert - damit man bei der Spaltenzeichenroutine
  204. direkt in den Code einspringen kann. Somit bleiben nur noch 64 H÷hen (=256/4) ⁿbrig.
  205.  
  206. Eine Landschaftsvoxelzeile hat also 512 Bytes. Insgesamt braucht die Landschaft: 
  207. 512 Byte * 256 Zeilen = 128kb
  208.  
  209. Wie man sich eine solche Landschaft generiert, ist eine andere Frage. Ich habe mir mit einem
  210. Fraktalprogramm 2D Ansichten berechnen lassen und diese in mein Format konvertiert (nach
  211. dem Schema: H÷he->Farbe). Eine Auswertung einer Sinuskurve ist natⁿrlich auch m÷glich (und spart fⁿr das Programmfile Speicherplatz -> weniger Daten, wenn zur Laufzeit generiert).
  212.  
  213. 1)  Strahlenvorberechnung
  214.  
  215. Wie bereits angesprochen, berechnen wir die Strahlen vorher. Eine Umdrehung soll hier aber aus 512 Stufen = Strahlen bestehen - hieraus resultiert eine etwas feinere Drehung. Bitte beachtet ierzu die Grafik STRAHL.IFF.
  216. Ein Sichtstrahl ist spΣter zustΣndig fⁿr das Auslesen der Landschaftspunkte einer Spaltenbe-
  217. rechnung. Ein solcher Strahl besteht hier aus 64 Punktoffsets. Dies stellt die Sichtweite dar, mit der wir in die Landschaft Richtung Horizont kucken. Diese Offsets werden dann bei der 
  218. Spaltenberechnung auf die aktulle Position aufaddiert - also um von einem Strahlpunkt zum
  219. nΣchsten zu kommen, addiert man das x-y-Offset. Dadurch wird das alles relativ zu der 
  220. aktuellen Position in der Landkarte (absolute Punkte wⁿrden bei einer Bewegung nix bringen).
  221.  
  222. Ein Punktoffset besteht aus X+Y Offset, die wir in einem Longword ablegen, und zwar so:
  223.  
  224. Highword| Lowword
  225.   y offset        x offset
  226.  
  227. Man nimmt als Strahlausgangspunkt meist nicht den Mittelpuntk des Kreises, sondern bewegt
  228. sich etwas weiter weg. Diesem Umstand trΣgt die Angabe "radius1" Rechnung, indem hier
  229. der Abstand vom Mittelpunkt des Sichkreises (siehe Grafik, Grundlagenbesprechung) ange-geben wird.
  230.  
  231.  
  232. ******* Source: Vorberechnung der Strahlen mit x,y Positionen ******
  233.  
  234. map_groesse    equ    256        ; unsere Landschaft ist 256x256 gro∞
  235.  
  236. strahlen    equ    512        ; volle Umdrehung = 512 Strahlen = 360 Grad
  237. radius1        equ    40        ; Kreis innen
  238. radius2        equ     170        ; Kreis au∞en
  239. punkte        equ    64        ; wieviel Punkte nach vorne sehen - Richtung Horizont
  240.  
  241. bit_shift    equ    9        ; 2**9 = 512 -> eine Zeile in der Landkarte 
  242.                     ; siehe Landschaftsdaten
  243.  
  244. berechne_strahlen:
  245.  
  246.                 lea     strahlen_speicher(PC),A0    ; hier werden die Strahlen abgelegt
  247.                 lea     sin_tabelle(PC),A1        ; Sinustabelle mit 1024 Eintraegen
  248.                 lea     cos_tabelle(PC),A4        ; Kosinustabelle 
  249.  
  250.                 moveq   #0,D0               ; StrahlenzΣhler initialisieren
  251.  
  252. strahlen_loop:
  253.                 move.l  D0,-(SP)
  254.  
  255. ; pro Strahl durchlaufen ...
  256.  
  257.                 move.w  D0,D4            
  258.                 mulu    #1024,D4        ; 1024 Winkel in der Cos/Sin Tabelle ...
  259.                 divu    #strahlen,D4        ; ... auf ben÷tigte Strahlenwinkel umrechnen
  260.                 add.w   D4,D4            ; fuer Tabellenzugriff ( pro Winkel ein Word)
  261.                 and.w   #$07FE,D4        ; in der Tablle bleiben (sin+cos periodisch)
  262.                 move.w  0(A1,D4.w),D0    ; Sinuswert (multipliziert mit 2**15)
  263.                 move.w  0(A4,D4.w),D1    ; Kosinuswert (dito)
  264.                 move.w  D0,D2
  265.                 move.w  D1,D3
  266.                 muls    #radius1,D0        ; X Startpunkt auf dem inneren Kreis    (x1)
  267.                 muls    #radius1,D1        ; Y Startpunkt auf dem inneren Kreis    (y1)
  268.                 muls    #radius2,D2        ; X Startpunkt auf dem Σu∞eren Kreis    (x2)
  269.                 muls    #radius2,D3        ; Y Startpunkt auf dem Σu∞eren Kreis    (y2)
  270.                 add.l   D0,D0            ; 2**15 * 2 = 2**16 
  271.                 add.l   D1,D1            ; "
  272.                 add.l   D2,D2            ; "
  273.                 add.l   D3,D3            ; "
  274.                 swap    D0            ; Multiplikation mit 2**16 rⁿckgΣngigmachen
  275.                 swap    D1
  276.                 swap    D2
  277.                 swap    D3
  278.  
  279.                 sub.w   D0,D2            ; x2 - x1 = deltaX
  280.                 sub.w   D1,D3            ; y2 - y1 = deltaY
  281.                 ext.l   D2            ; fⁿr weitere Long Berechnungen erweitern
  282.                 ext.l   D3            ; "
  283.  
  284.                 suba.w  A2,A2            ; A2 l÷schen - ist letzter x Wert
  285.                 suba.w  A3,A3            ; A3 l÷schen - ist letzter y Wert
  286.  
  287.                 moveq   #0,D4            ; ist neuer x Wert
  288.                 moveq   #0,D5            ; ist neuer y Wert
  289.  
  290. ;--------------------------------------------------
  291. ; und jetzt die Positionsoffsets pro Strahl berechnen
  292.  
  293.                 move.w  #punkte-1,D6
  294.  
  295. punkt_loop:
  296.                 movea.l D4,A5        ; Aktuellen x Strahlwert sichern
  297.                 movea.l D5,A6        ; gleiches fⁿr y
  298.  
  299.                 divs    #punkte,D4    ; zwischen Radius1 und radius2 auf dem Strahl bewegen ...
  300.                 divs    #punkte,D5    ; Umrechnung, um die gewⁿnschte Punktanzahl auf die
  301.                 add.w   D0,D4        ; Distanz x1->x2, y1->y2 zu verteilen
  302.                 add.w   D1,D5
  303.                 ext.w   D4
  304.                 ext.w   D5
  305.  
  306.                 movem.w D4-D5,-(SP)    ; aktuelle x,y Position sichern
  307.                 sub.w   A2,D4        ; von alter Position abziehen, ergibt Delta x ...
  308.                 sub.w   A3,D5        ; Delta y fⁿr die Strahloffsets !
  309.                 movem.w (SP)+,A2-A3    ; aktuelle Werte werden alte Position !
  310.  
  311.                 and.l   #map_groesse-1,D4    ; innerhalb der Landschaft bleiben x
  312.                 and.l   #map_groesse-1,D5    ; innerhalb der Landschaft bleiben y
  313.  
  314.                 moveq   #bit_shift,D7    ; spezielles x+y Format erzeugen:
  315.                 lsl.l   D7,D5            ; y mit Zeilenbreite multiplizieren
  316.                         ; 256 fⁿr H÷hen + 256 Pixel fⁿr Farben 
  317. ; -> 512 = 2**9
  318.                 or.l    D4,D5            ; x ins Lowword
  319.  
  320.                 move.l  D5,(A0)+        ; x+y Wert fⁿr den berechneten Punkt ablegen
  321.  
  322. ;---------------------------------------
  323.  
  324.                 move.l  A5,D4            ; x+y Startwerte fⁿr Strahl wiederherstellen
  325.                 move.l  A6,D5
  326.  
  327.                 add.l   D2,D4            ; Weiter in x Richtung auf dem Strahl bewegen
  328.                 add.l   D3,D5            ; weiter in y Richtung auf dem Strahl bewegen
  329.                 dbra    D6,punkt_loop    ; Strahl abarbeiten
  330.  
  331.                 move.l  (SP)+,D0
  332.  
  333.                 addq.w  #1,D0            ; naechster Strahl
  334.  
  335.                 cmp.w   #strahlen,D0        ; Schon alle Strahlen ?
  336.                 bne     strahlen_loop
  337.                 rts
  338.  
  339. 2)  Vorberechnung der Junk-Konvertierungstabelle und Junk Format
  340.  
  341. Wie setzt man einzelne Punkt schnell auf dem ST (in 4 Planes natⁿrlich) ??? 
  342. Hierbei hilft der movep.l Befehl - aber der wird bestimmt in einer anderen Ausgabe be-sprochen. Fⁿr Voxel brauchen wir ihn gar nicht ...
  343. Allerdings kann die Aufl÷sung einige Probleme machen. WΣhlt man 8 Pixel Breite fⁿr einen Voxel, dann ist es doch ein Job fⁿr movep. 
  344. Wenn wir eine Voxelbreite von 4 Pixeln wollen, wird alles etwas komplizierter, aber sieht eben auch besser aus ! Aber wie setzte ich schnell 4 Pixel ? 
  345. Man schreibt in der Spaltenzeichenschleife ⁿberhaupt keine Pixel, sondern benutzt einen
  346. Zwischenpuffer mit einem dafⁿr gⁿnstigen Format - nennen wir ihn mal Junk Puffer. Hier schreiben wir dann unsere Voxeldaten rein. Im zweiten Schritt wird dann dieser Puffer aus-
  347. gewertet und in den ST Bildschirmspeicher geschrieben. Das mu∞ natⁿrlich flott gehen.
  348. In diesem Fall ist es schneller als Voxel gleich direkt zu zeichnen.
  349. So sieht das Format des Junk Puffers aus:
  350.  
  351. Wir haben 16 Farben, man kann also mit 4 Bit alle Farben codieren. Also soll ein Voxel durch
  352. diese Information seine Farbe codieren (da∞ die Breite spΣter 4 ist, interessiert uns hier noch
  353. nicht ! Eine Farbe pro Einheit = Voxel ). In ein Byte unseres Puffers passen somit 2 Voxelfarb-
  354. informationen. So sei es.
  355.  
  356. #----------- Byte 1 --------------# #----------- Byte 2 --------------# ...
  357. Voxel1 Farbe  Voxel2 Farbe Voxel3 Farbe Voxel 4 Farbe 
  358.  
  359. Beim Schreiben in unseren Puffer mⁿssen wir nur aufpassen, da∞ wir einmal Bits 4,5,6,7 und
  360. einmal Bits 0,1,2,3 beschreiben (Highnibble, Lownibble). Dies werden spΣter zwei ver-schiedene Spaltenzeichenroutinen ⁿbernehmen.
  361.  
  362. Die nΣchste Frage ist natⁿrlich, wie die Daten des Junk Puffers in den Bildschirmspeicher 
  363. kommen. Ganz einfach - eine gro∞e Tabelle hilft mal wieder !
  364.  
  365. Die Junk Puffer Konvertierungsroutine (siehe Punkt 4) geht so vor:
  366. Es wird immer ein Wort aus dem Junk Puffer ausgelesen. Dieses Wort codiert ja 4 Voxel (pro
  367. Byte 2). Bei einer angestrebten Voxelbreite von 4 macht entsprechen dieser Information
  368. 4 Voxel * 4 Pixel = 16 Pixel. H÷rte ich gerade 16 Pixel ??? Das ist doch schon was fⁿr unseren
  369. ST Bildschirmspeicher. Und so geht es weiter ... ץber die Tabelle werden die 4 Farb-informationen in die 4 Planew÷rter des STs umgesetzt und in den Bildschirmspeicher geschrieben. Mehr ist es nicht. Zur Tabelle selbst: sie mu∞ alle Kombinationen abdecken,
  370. also 16 Farben (Voxel 1) * 16 Farben(Voxel 2) * 16 Farben (Voxel 3) * 15 Farben (Voxel 4, ich
  371. benutze Farbe 16 fⁿr Rasterfarben, kann ich mir hier also sparen ...) * 4 Planew÷rter ST =
  372. 491520 Bytes ! Ist nicht gerade wenig .... ich wei∞.
  373.  
  374.  
  375. ********** Source: Vorberechnungen der Junk Tabelle ***********
  376.  
  377. precalculate_junk_tab:
  378.  
  379.                 lea     mammut_table,A0
  380.  
  381.                 lea     d0_tab(PC),A1
  382.                 lea     d1_tab(PC),A2
  383.                 lea     d2_tab(PC),A3
  384.                 lea     d3_tab(PC),A4
  385.  
  386.                 moveq   #0,D0
  387.                 moveq   #0,D1
  388.                 moveq   #0,D2
  389.                 moveq   #0,D3
  390.  
  391. loop:
  392.  
  393. ; Spalte 0
  394.  
  395.                 move.w  D0,D4
  396.                 lsl.w   #3,D4
  397.                 movem.l 0(A1,D4.w),D5-D6
  398.  
  399. ; Spalte 1
  400.                 move.w  D1,D4
  401.                 lsl.w   #3,D4
  402.                 or.l    0(A2,D4.w),D5
  403.                 or.l    4(A2,D4.w),D6
  404.  
  405. ; Spalte 2
  406.                 move.w  D2,D4
  407.                 lsl.w   #3,D4
  408.                 or.l    0(A3,D4.w),D5
  409.                 or.l    4(A3,D4.w),D6
  410.  
  411. ; Spalte 3
  412.  
  413.                 move.w  D3,D4
  414.                 lsl.w   #3,D4
  415.                 or.l    0(A4,D4.w),D5
  416.                 or.l    4(A4,D4.w),D6
  417.  
  418. ; In Tabelle schreiben
  419.  
  420.                 move.l  D5,(A0)+
  421.                 move.l  D6,(A0)+
  422.  
  423. ; NΣchste Kombination
  424.  
  425.                 addq.w  #1,D0
  426.                 cmp.w   #16,D0    ; 16 * ...
  427.                 blt.s   loop
  428.                 moveq   #0,D0
  429.  
  430.                 addq.w  #1,D1
  431.                 cmp.w   #16,D1    ; ... * 16 * ...
  432.                 blt.s   loop
  433.                 moveq   #0,D1
  434.  
  435.                 addq.w  #1,D2
  436.                 cmp.w   #16,D2    ; ... * 16 * ...
  437.                 blt.s   loop
  438.                 moveq   #0,D2
  439.  
  440.                 addq.w  #1,D3
  441.                 cmp.w   #15,D3    ; ... * 15
  442.                 blt.s   loop
  443.  
  444.                 rts
  445.  
  446. d0_tab:         DC.W $000F,$000F,$000F,$000F
  447.                 DC.W $000F,0,0,0
  448.                 DC.W 0,$000F,0,0
  449.                 DC.W $000F,$000F,0,0
  450.                 DC.W 0,0,$000F,0
  451.                 DC.W $000F,0,$000F,0
  452.                 DC.W 0,$000F,$000F,0
  453.                 DC.W $000F,$000F,$000F,0
  454.                 DC.W 0,0,0,$000F
  455.                 DC.W $000F,0,0,$000F
  456.                 DC.W 0,$000F,0,$000F
  457.                 DC.W $000F,$000F,0,$000F
  458.                 DC.W 0,0,$000F,$000F
  459.                 DC.W $000F,0,$000F,$000F
  460.                 DC.W 0,$000F,$000F,$000F
  461.                 DS.W 4
  462.  
  463. d1_tab:         DC.W $00F0,$00F0,$00F0,$00F0
  464.                 DC.W $00F0,0,0,0
  465.                 DC.W 0,$00F0,0,0
  466.                 DC.W $00F0,$00F0,0,0
  467.                 DC.W 0,0,$00F0,0
  468.                 DC.W $00F0,0,$00F0,0
  469.                 DC.W 0,$00F0,$00F0,0
  470.                 DC.W $00F0,$00F0,$00F0,0
  471.                 DC.W 0,0,0,$00F0
  472.                 DC.W $00F0,0,0,$00F0
  473.                 DC.W 0,$00F0,0,$00F0
  474.                 DC.W $00F0,$00F0,0,$00F0
  475.                 DC.W 0,0,$00F0,$00F0
  476.                 DC.W $00F0,0,$00F0,$00F0
  477.                 DC.W 0,$00F0,$00F0,$00F0
  478.                 DS.W 4
  479.  
  480. d2_tab:         DC.W $0F00,$0F00,$0F00,$0F00
  481.                 DC.W $0F00,0,0,0
  482.                 DC.W 0,$0F00,0,0
  483.                 DC.W $0F00,$0F00,0,0
  484.                 DC.W 0,0,$0F00,0
  485.                 DC.W $0F00,0,$0F00,0
  486.                 DC.W 0,$0F00,$0F00,0
  487.                 DC.W $0F00,$0F00,$0F00,0
  488.                 DC.W 0,0,0,$0F00
  489.                 DC.W $0F00,0,0,$0F00
  490.                 DC.W 0,$0F00,0,$0F00
  491.                 DC.W $0F00,$0F00,0,$0F00
  492.                 DC.W 0,0,$0F00,$0F00
  493.                 DC.W $0F00,0,$0F00,$0F00
  494.                 DC.W 0,$0F00,$0F00,$0F00
  495.                 DS.W 4
  496.  
  497. d3_tab:         DC.W $F000,$F000,$F000,$F000
  498.                 DC.W $F000,0,0,0
  499.                 DC.W 0,$F000,0,0
  500.                 DC.W $F000,$F000,0,0
  501.                 DC.W 0,0,$F000,0
  502.                 DC.W $F000,0,$F000,0
  503.                 DC.W 0,$F000,$F000,0
  504.                 DC.W $F000,$F000,$F000,0
  505.                 DC.W 0,0,0,$F000
  506.                 DC.W $F000,0,0,$F000
  507.                 DC.W 0,$F000,0,$F000
  508.                 DC.W $F000,$F000,0,$F000
  509.                 DC.W 0,0,$F000,$F000
  510.                 DC.W $F000,0,$F000,$F000
  511.                 DC.W 0,$F000,$F000,$F000
  512.                 DS.W 4
  513.  
  514.  
  515. 3)  Spaltenzeichnerroutine
  516.  
  517. Die Spaltenzeichenroutine geht nach dem bereits geschilderten Algorithmus vor (siehe 
  518. Grundlagen). Anzumerken ist noch, da∞ die Farbtabelle die 4 Bit Farbinformationen
  519. im oberen Nibble eines Bytes speichert. In der zweiten Routine mⁿssen die Farben dann noch 
  520. fⁿr das untere Nibble geshiftet werden.
  521.  
  522.  
  523. ********** Source: Zeichnen der Spalten ***********
  524.  
  525. mask        equ    %00000000000000011111111011111111
  526. spalten        equ    64    ; wir zeichnen 64 Spalten (256 Screenpixel / 4 Pixel pro Voxel)
  527.  
  528. scan_nibble_high:
  529.  
  530. ;**** Registerbelegung innerhalb der Schleifen ****
  531.  
  532. ; d0= x+y Position
  533. ; d1= Neue Hoehe
  534. ; d2= Alte Hoehe
  535. ; d3= Spaltenpunkte ZΣhler
  536. ; d4= pers adr + work byte
  537. ; d5= perts adder
  538. ; d6= Offset einer Zeile innerhalb des Junk Puffers
  539. ; d7= And Maske fⁿr Bleiben innerhalb der Landschaft 
  540.  
  541. * a0= Delta-xy-offset Tabelle eines Strahls
  542. * a1= Zugriff auf die H÷hendaten der Landschaft
  543. * a2= Zugriff auf die Farbdaten der Landschaft
  544. * a3= Fⁿr Direkteinsprung in die Turmzeichenbefehlsfolge
  545. * a4= Perspektiven Tabelle
  546. * a5= Aktuelle Screen Adresse
  547. * a6= Alte Screen Adresse
  548.  
  549.                 lea     byte_code_1(PC),A3    * Adresse fⁿr Code (Direkteinsprung)
  550.  
  551.                 moveq   #0,D1           * Neue H÷he init
  552.                 moveq   #0,D2           * Alte H÷he init
  553.                 move.w  #punkte-1,D3    * Anzahl der Voxel, die Richtung Horizont 
  554.                        * ausgewertet werden sollen
  555.                 moveq   #0,D4           * Perspektiventabelle Start ganz vorne beim Betrachter
  556.                 move.w  #perspektiven*punkte,D5    * Offset fⁿr Schritt Richtung Horizont
  557.          moveq   #spalten/2,D6            * Zeilenoffset einer Junk Puffer Zeile
  558.                 move.l  #mask,D7            * LandschaftsabhΣngig
  559.  
  560.  
  561. do_row_byte_1:
  562.                 add.w   D5,D4           * In der Perspektiventabelle einen Schritt
  563.    * Richtung Horizont machen ...
  564.  
  565.                 add.l   (A0)+,D0        * actual x-y-position
  566.                 and.l   D7,D0           * mask raender
  567.  
  568.                 move.b  0(A1,D0.l),D4   * H÷he auslesen
  569.                 move.b  0(A4,D4.l),D1   * H÷he perspektivisch anpassen ...
  570.    * Ergebnis: H÷he * 4 -> fⁿr Direkteinsprung
  571.  
  572.                 sub.w   D1,D2           * Alte H÷he - neue H÷he < 0 ?
  573. * damit ist der neue Punkt nicht sichtbar !
  574.    * also nichts zeichnen
  575.  
  576.                 bmi.s   scan_me_byte_1
  577.                 add.w   D1,D2           * Operation rⁿckgΣngig machen -> alte H÷he bleibt
  578.                        * der Ma∞stab !
  579.                 dbra    D3,do_row_byte_1     * NΣchster Punkt
  580.                 rts
  581.  
  582. scan_me_byte_1:
  583.                 move.b  0(A2,D0.l),D4   * Farbinformation holen (Byte)
  584.  
  585.                 jmp     0(A3,D2.w)       * Direkteinsprung (abh. von neu zu zeichnendem
  586.                        * Turmdelta -> die )
  587.  
  588. ********* Farbwerte eintragen ***********
  589.  
  590.                 REPT max_y
  591.                 move.b  D4,(A5)        * Farbe in Junk Puffer schreiben
  592.                 suba.w  D6,A5            * vorherige Zeile im Junk Puffer adressieren
  593.             ; beide Befehle zusammen 2 Words = 4 Byte
  594.                 ENDR
  595.  
  596. byte_code_1:    move.w  D1,D2            * neue H÷he wird zur alten H÷he
  597.                 dbra    D3,do_row_byte_1    * nΣchstes Voxel
  598.                 rts
  599.                 
  600.  
  601. Die selbe Prozedur fⁿr jede 2.Spalte - hier werden die niedrigen Nibbles des Junk
  602. Puffers gefⁿllt.
  603.  
  604. scan_nibble_low:
  605.  
  606.                 lea     byte_code_2(PC),A3
  607.  
  608.                 moveq   #0,D1           
  609.                 moveq   #0,D2           
  610.                 move.w  #punkte-1,D3    
  611.                 moveq   #0,D4
  612.                 move.w  #perspektiven*punkte,D5
  613.          moveq   #spalten/2,D6            * Zeilenoffset einer Junk Puffer Zeile
  614.                 move.l  #mask,D7            * LandschaftsabhΣngig
  615.  
  616. do_row_byte_2:
  617.                 add.w   D5,D4
  618.  
  619.                 add.l   (A0)+,D0        
  620.                 and.l   D7,D0           
  621.  
  622.                 move.b  0(A1,D0.l),D4   
  623.                 move.b  0(A4,D4.l),D1   
  624.  
  625.                 sub.w   D1,D2          
  626.                 bmi.s   scan_me_byte_2
  627.                 add.w   D1,D2
  628.                 dbra    D3,do_row_byte_2
  629.                 rts
  630.  
  631. scan_me_byte_2:
  632.                 move.b  0(A2,D0.l),D4   
  633.  
  634.                 lsr.b   #4,D4            ; Farbinformation ins untere Nibble
  635.  
  636.                 jmp     0(A3,D2.w)
  637.  
  638.                 REPT max_y
  639.                 or.b    D4,(A5)        ; unteres Nibble fⁿllen
  640.                 suba.w  D6,A5
  641.                 ENDR
  642.  
  643. byte_code_2:    move.w  D1,D2
  644.                 dbra    D3,do_row_byte_2
  645.                 rts
  646.  
  647.  
  648. 4)  Junk Puffer Konvertierungsroutine
  649.  
  650. Umsetzen der Voxel 4Bit Farbinformationen in den ST Bildschirmspeicher - siehe Abschnitt
  651. Junk Puffer Vorberechnung.
  652.  
  653.  
  654. ********** Source: Umsetzen des Junk Puffers in den ST Bildschirmspeicher ***********
  655.  
  656.  
  657. scanner:        
  658.  
  659.                 movea.l screen_adr(PC),A0        ; Bildschirmspeicheradresse
  660.  
  661.                 lea     mammut_table,A1        ; Konvertierungstabelle Adresse
  662.  
  663.                 lea     junk_puffer(PC),A2        ; Junk Puffer Adresse
  664.  
  665.                 move.w  #highs-1,D0            ; wieviele Zeilen im Junk Puffer
  666.  
  667. copy_lines:     movea.w D0,A3
  668.  
  669.                 moveq   #0,D0
  670.                 moveq   #0,D2
  671.                 moveq   #0,D4
  672.                 moveq   #0,D6
  673.                 move.w  (A2)+,D0            ; Wort mit 4 Voxel Farben holen
  674.                 move.w  (A2)+,D2
  675.                 move.w  (A2)+,D4
  676.                 move.w  (A2)+,D6
  677.                 lsl.l   #3,D0                ; 4 Plane W÷rter = 8 Byte
  678.                 lsl.l   #3,D2
  679.                 lsl.l   #3,D4
  680.                 lsl.l   #3,D6
  681.  
  682.                 movem.l 0(A1,D0.l),D0-D1        ; Konvertierte W÷rter holen
  683.                 movem.l 0(A1,D2.l),D2-D3
  684.                 movem.l 0(A1,D4.l),D4-D5
  685.                 movem.l 0(A1,D6.l),D6-D7
  686.                 movem.l D0-D7,(A0)              * 64 Pixel schreiben
  687.                 movem.l D0-D7,160(A0)        * Zeile verdoppeln (y double pix)
  688.  
  689. off             SET 16*4/2
  690.                 REPT 3
  691.  
  692.                 moveq   #0,D0
  693.                 moveq   #0,D2
  694.                 moveq   #0,D4
  695.                 moveq   #0,D6
  696.                 move.w  (A2)+,D0
  697.                 move.w  (A2)+,D2
  698.                 move.w  (A2)+,D4
  699.                 move.w  (A2)+,D6
  700.                 lsl.l   #3,D0
  701.                 lsl.l   #3,D2
  702.                 lsl.l   #3,D4
  703.                 lsl.l   #3,D6
  704.  
  705.                 movem.l 0(A1,D0.l),D0-D1
  706.                 movem.l 0(A1,D2.l),D2-D3
  707.                 movem.l 0(A1,D4.l),D4-D5
  708.                 movem.l 0(A1,D6.l),D6-D7
  709.                 movem.l D0-D7,off(A0)   * 64 pixel
  710.                 movem.l D0-D7,off+160(A0)
  711. off             SET off+16*4/2
  712.                 ENDR
  713.  
  714.                 lea     320(A0),A0
  715.                 move.w  A3,D0
  716.                 dbra    D0,copy_lines
  717.                 rts
  718.  
  719.  
  720. Zusammenfassung
  721.  
  722. So, das wars erstmal fⁿr heute. Ich hoffe, da∞ Ihr mit den Beschreibungen klarkommt. 
  723. Auf Diskette findet Ihr noch die beiden Grafiken TURM.IFF und STRAHL.IFF sowie alle
  724. Quellenausschnitte.
  725. Bitte gebt uns auch etwas Feedback - was war gut, was schlecht, k÷nnte man was anders 
  726. machen, oder habt Ihr spezielle Themenwⁿnsche ..... schreibt ans Undercover HQ !
  727. Ich wⁿnsche allen ATARI Freaks ein paar sch÷ne Sommermonate und noch viel Spa∞ mit 
  728. den anderen Artikeln .....
  729.  
  730.  
  731. Mike of STAX in 1997.
  732.  
  733.