Lamers Heaven

Ausgabe 1: 	Voxel Space ST
Autor: 		Mike of STAX

Willkommen zur ersten Ausgabe von Lamers Heaven !

EINLEITUNG:

Da diese Serie erst neu ab dieser Undercover Edition erffnet wurde, mchte ich Euch erst kurz was ber Sinn und Zweck der ganzen Vorstellung erzhlen.
Ich bin Mike of STAX und wurde von Moondog/TNB dazu berredet, ihn beim Aufbau einer
ST Coding Corner zu untersttzen. 
Vielleicht hat der ein oder andere schon mal was von der Gruppe STAX gehrt, in der letzten
Zeit aber bestimmt nicht viel, da es doch sehr ruhig um uns geworden ist. Neben Matt war/bin
ich fr Coding/Design und in alten Tagen auch mal fr die ein oder andere Grafik zustndig
gewesen - doch das ist ehrlich gesagt schon eine Weile her. So war ich den Trnen der Rhrung nahe, als ich die alten Quellen hervorholte und analysierte (wie war das noch anno
94 ...???). Soviel mu gleich vorweg gesagt werden: smtliche Codes haben schon ein
ehrfurchtsvolles Alter (Copyright 1994 und frhes 1995), auch wurde nichts mehr daran ver-
ndert oder gar optimiert. Fast alle Effekte sind mit der Intention entstanden, mglichst viele
verschiedene FX mglichst bald zu haben (Grundlagenforschung !).
Moondog/TNB zufolge gibt es noch ein paar hartgesottene ST Coder (auch die Polen sind ja 
schwer im kommen ...), so da ich mich fr die Idee einer Coding Ecke begeistern lie. Ich
selbst habe meine lehrreichen Lektionen noch aus der ehrwrdigen "Hexer" - Serie in der 
68000er/ST-Magazin um die Jahre 88/89. In jenen Tagen drehte sich noch alles um das ffnen
der Rnder, Raster Interrupts und Plane FX. Wer hierzu mehr wissen und das Gefhl der ST-
Hochzeiten spren will, dem seien diese Ausgaben empfohlen (bei Interesse gebe ich gerne 
die genauen Heftnummer an - im Kopf habe ich die nicht mehr ...).
Genauer betrachtet hat sich auf dem ST seit diesen Zeiten doch viel getan. Dominierten am
Anfang noch Raster/Randeffekte, wurde im Anschlu daran die Copy-Leistung des ST's 
hinsichtlich Scrolling (Screen, Laufschriften) und Blcken aller Art (Shapes, Sprites) ausgelotet.
Heutzutage dreht sich fast alles um Pixel Effekte - also Vernderung von einzelnen Pixeln, 
natrlich mglichst viele (freilich gab es auch viele Sternenfeld Routinen, aber die aktuellen
FX fordern viel mehr Punktvernderungen). In diese Gruppe gehren sicherlich die Zoomer,
Rotierer, Texturemapper, Gouraudshader oder sogar Bumpmapper ... (die Liste kann beliebig
fortgesetzt werden - siehe PC - aber fr uns ST-Jnger ist bei der Rechenzeit irgendwo auch
mal Schlu, in der Fantasie nicht ...).
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 
mit dieser und den folgenden Ausgaben.

THEMA

Ich mchte hier hauptschlich Effekte der Pixelgruppe vorstellen, aktuelles Thema in dieser, der ersten Ausgabe, ist:

				VOXELSPACE

Einige Anmerkungen zur Vorgehensweise. Ich werde keine kompletten Quellen mitliefern,
sondern neben allegemeinen Erklrungen und detailierten Hinweisen nur Schlsselteile 
des Codings vorstellen. Wer sich etwas damit beschftigt, kommt damit sicherlich zurecht.
Ausfhrbare PRG Files schon eher (leider hat die Zeit diesmal nicht mehr gereicht, sowas
auf die Beine zu stellen - folgt noch) - schlsselfertige Quellen, wie gesagt nicht.
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 Gesprch mit anderern ST	
Leidensgenossen auf neue Ideen ...

Motivation

"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.
Ich habe dann spontan auf dem ST rumprobiert, aber da kam nix raus. Erst spter wollte es
dann klappen - und diesmal haben die PCler auch etwas bld geschaut. Soviel vorweg:
natrlich kann man das Vorbild nicht total erreichen, aber ein bichen was geht immer ...

Wer noch keine Voxelspace Routine gesehen hat, hier kurz ein berblick:
Voxelspace ist eine Technik mit der man 2D Aufnahmen mit einfachen Mitteln als 3D Modelle
bzw. Volumenkrper anzeigen kann (Voxel = Volume Pixel), indem man diesen Aufnahmen 
mit den Voxeln rumliche Tiefe verleiht.Gern benutzt um ber Landschaften zu gleiten, deren
Ursprung oftmals Satellitenaufnahmen sind; wird auch in der Medizin - IT vielfach eingesetzt.
In unserem Fall soll es um die Darstellung von Landschaften gehen, ber die man mit einem
Fluggert gleiten kann.

Ausgehend vom PC Commanche ergeben sich folgende Anforderungen:

1)  Mglichst groe Landkarte
2)  Nuancenreich sowohl bei der Auflsung der Voxel als auch bei der naturgetreuen Farb-gebung
3)  Hohe Geschwindigkeit der Animation
4)  Freie Bewegbarkeit des Gleiters in alle Richtungen mit Drehung
5)  Vernderbarkeit der Flughhe des Gleiters
 
Grundlagen

ble Geschichte, oder ? Ok, gehen wir mal durch, was wir alles brauchen und warum.

1)  Landkarte

Ausganspunkt ist eine 2D Landkarte, die wir dreidimensional darstellen wollen. Die einzelnen
Pixel haben eine bestimmte Farbe. Den Pixeln wird nun noch eine Hhe zugewiesen.
Damit steht schonmal die grundlegende Datenstruktur. 
Wenn wir so ber die Landschaft dsen, sehen wir immer einen Ausschnitt aus unserer Karte.
Um es erstmal einfach zu machen, stellen wir uns diesen Ausschnitt als Rechteck dar, der
ausgelesen und auf dem Screen dargestellt wird.

Unser Landkartenausschnitt knnte so aussehen (hier mal nur 4x4 Pixel, von oben betrachtet):

	M N O P
	I J K L
	E F G H
	A B C D
    
    	  /\
          ||

      Betrachter

Stellt man sich nun jeden Pixel als einen kleinen Turm vor mit einer bestimmten Hhe, so
sieht man vorne die erste Zeile mit den Trmen A,B,C,D. Sind diese etwas niedriger, sieht 
man auch die Trme dahinter, vielleicht sogar die MNOP Turmreihe. Die Trme werden zustzlich in ihrer Hhe entsprechend ihrer Entfernung vom Betrachter perspektivisch angepat. Ein Turm weiter hinten ist zwar kleiner in seiner eigenen Hhe, aber beginnt am Boden auch etwas weiter oben. Am besten selbst mal in die Ferne sehen, um diese Perspektive in der Praxis zu sehen.

Ok, unsere Pixel werden also zu Trmchen mit einer bestimmten Farbe und Hhe (diese beiden Informationen bilden zusammen unsere erste Voxel Datenstruktur). Wie man die Trmchen zeichnet, werden wir gleich kennenlernen.
 
Man baut den Screen in Spalten auf. Jede X Spalte wird einzeln aufgebaut, bis der Screen-
inhalt steht. Ausgehend von unserem Beispiel betreffen die Pixel A, E, I, M (Pixel + Hhe,
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. 
In unserem Fall also Turm A. Dieser habe die Hhe 2 , also werden zwei Pixel mit der
Farbe A von unten nach oben gezeichnet (Schritt 1).

Spalte 1 (Spalte ganz links zeigt die Zeile (Hhe) an):

	Schritt 1	Schritt 2	Schritt 3	Schritt 4
6
5
4							M
3			E		E		E
2	A		A		A		A
1	A		A		A		A


Turm E habe die Hhe 3, da wir uns weiter vom Betrachter wegbewegen, wird die Hhe auf
2 angepat, das Grundoffset sei 1, 2+1 = 3 (immer von unten gerechnet !). Jetzt mchten
wir aber den Turm A nicht bermalen, da der ja eigentlich vor uns steht und somit ja als erstes sichtbar sein mte. Man merkt sich nach jeder Zeichenoperation die Hhe des Vorgngers und vergleicht sie mit der neu zu zeichnenden Hhe. Ist die neue Hhe kleiner als die alte, mu ja nichts gezeichnet werden, da der neue Turm hinter dem Vordermann und somit un-sichtbar fr den Betrachter ist. Liegt sie ber dem Vorgngerturm, zeichnet man nur die Hhendifferenz darber (Schritt 2).

Voxel I hat die Hhe 2, nach Perspektivenanpassung nur noch 1, Grundoffset sei 2, macht 3.
Da der Vorgngerturm schon die Zeichenhhe von 3 hatte ist der neue Turm nicht sichtbar
(Schritt 3).

Turm M sei wieder sichtbar (Schritt 4). Somit ist eine Bildschirmspalte gefllt. Das gleiche Ver-
fahren wird nun auf alle Spalten angewendet (Spaltenberechnung mit Voxeln B, F, J, N, usw.)
bis der Landschaftscreen steht (siehe auch Grafik TURM.IFF).

Noch ein Satz zur Voxeldatenstruktur. Da pro Voxel Hhe + Farbe anfallen (angenommen, wie
auf dem PC 256 Farben = 1 Byte + 256 Hhen = 1 Byte -> 2 Byte pro Voxel) kommt da fr eine
ordentliche Landschaft schon was zusammen:
512 X 512 in der Ausdehnung macht 512x512x2 = 524 KB und das ist noch keine groe Landschaft ! Bei Commanche waren die Maps grer (ca. 1024x1024 = 2MB), fr den ST ist das indiskutabel, noch dazu weil noch anderes Zeugs mit in den Speicher mu (siehe 
IMPLEMENTIERUNG).


2) Nuancenreich sowohl bei der Auflsung der Voxel als auch bei der naturgetreuen Farb-gebung

Die Breite unserer Voxeltrme ist natrlich entscheidend fr die Auflsung insgesamt. Eine
angestrebte Screenzeichenflche von 256x160 (wer will, kann auch noch mehr machen ...)
bedeutet bei einer 1 Pixel Turmbreite fr 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.
Bei den Farben ist bei 16 Schlu. Leider. Diese sollten daher gut aufeinander abgestimmt sein.
Ich habe mal probiert mit Rasterungen Zwischenfarben zu erzeugen. Das Ergebnis war
scheulich ...

3)  Hohe Geschwindigkeit der Animation

Mit einer 4er Auflsung und einem kleinerem Fenster (wie unter 2) beschrieben) sind Frame-
raten um die 17 Bilder drin. Das geht in Ordnung.

4)  Freie Bewegbarkeit des Gleiters in alle Richtungen mit Drehung
 
Das kommt gut, macht aber die Landkartenauswertung etwas schwieriger. Wer darauf  ver-
zichten kann, wertet die Landschaft wie oben beschrieben mit einem rechteckigen Fenster
aus, welches er in X und Y Richtungen verschieben kann (aber eben nicht drehen ...).
Wer es sich und dem ST so richtig geben mchte, macht es mit Drehung. 
Man kann hier nicht einfach ber- bzw. nebeneinander liegende Voxel auslesen. 
Auslesen in Abhngigkeit von der Richtung kann man wie folgt:
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.
Eine volle Umdrehung hat 360 Grad, also nehmen wir mal 360 Strahlen (Abstand 1 Grad).
Wenn der Betrachter jetzt genau nach Norden schaut (Grad 0) und wir annehmen, da sein
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;
siehe auch Grafik STRAHL.IFF !).
Viel mehr ist es gar nicht. Die Strahlen werden vorher berechnet (genauer: x + y Offsets - siehe IMPLEMENTIERUNG !) und auf die Landkarte angewendet (in Abhngigkeit von der Betrachterposition).

Als weiters Goodie kann man auch noch das Kippen des Horizontes einbauen. Hierfr werden
die Startscreenoffsets fr die einzelnen Spalten = Trmchen nach oben/unten modifiziert. 


5)  Vernderbarkeit der Flughhe des Gleiters

Wenn sich die Flughhe verndert, verndert sich auch die Perspektive auf die Landschaft.
In Abhngigkeit davon mu die Perspektivenanpassung bei der Hhenberechnung whrend des Spaltenzeichnens durchgefhrt werden. Dies beeinflut die Perspektivenanpassung der
Voxelgrundhhe (wie in der Landkarte abgespeichert) und das Hhengrundoffset. Das 
luft das auf mehrere Perspektiventabellen hinaus - das erklre ich nicht weiter. Mit einem
einfachen Strahlensatz kommt man da weiter - probierts mal.

Neben der Drehbarkeit ist diese Funktionalitt sicherlich auch optional.
 

Implementierung

0)  Landschaftsdaten

Unsere Landschaft soll die Gre 256x256 haben. Fr jeden Voxel speichern wir ein Byte fr die
Hhe und ein Byte fr die Farbe ab. Man knnte es auch so angehen, da man aus der Hhe
die Farbe ableiten kann. Ich habe mich fr die erste Methode entschieden. Eine Zeile der 
Landschaftsmatrix wird folgendermaen im Speicher abgelegt:

256 Hhenbytes 	-> erste Landschaftszeile
256 Farbbytes		-> erste Landschaftszeile
256 Hhenbytes 	-> zweite Landschaftszeile
256 Farbbytes		-> zweite Landschaftszeile
...

Wichtig: die Hhenwerte sind mit 4 multipliziert - damit man bei der Spaltenzeichenroutine
direkt in den Code einspringen kann. Somit bleiben nur noch 64 Hhen (=256/4) brig.

Eine Landschaftsvoxelzeile hat also 512 Bytes. Insgesamt braucht die Landschaft: 
512 Byte * 256 Zeilen = 128kb

Wie man sich eine solche Landschaft generiert, ist eine andere Frage. Ich habe mir mit einem
Fraktalprogramm 2D Ansichten berechnen lassen und diese in mein Format konvertiert (nach
dem Schema: Hhe->Farbe). Eine Auswertung einer Sinuskurve ist natrlich auch mglich (und spart fr das Programmfile Speicherplatz -> weniger Daten, wenn zur Laufzeit generiert).

1)  Strahlenvorberechnung

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.
Ein Sichtstrahl ist spter zustndig fr das Auslesen der Landschaftspunkte einer Spaltenbe-
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 
Spaltenberechnung auf die aktulle Position aufaddiert - also um von einem Strahlpunkt zum
nchsten zu kommen, addiert man das x-y-Offset. Dadurch wird das alles relativ zu der 
aktuellen Position in der Landkarte (absolute Punkte wrden bei einer Bewegung nix bringen).

Ein Punktoffset besteht aus X+Y Offset, die wir in einem Longword ablegen, und zwar so:

Highword| Lowword
  y offset        x offset

Man nimmt als Strahlausgangspunkt meist nicht den Mittelpuntk des Kreises, sondern bewegt
sich etwas weiter weg. Diesem Umstand trgt die Angabe "radius1" Rechnung, indem hier
der Abstand vom Mittelpunkt des Sichkreises (siehe Grafik, Grundlagenbesprechung) ange-geben wird.


******* Source: Vorberechnung der Strahlen mit x,y Positionen ******

map_groesse	equ	256		; unsere Landschaft ist 256x256 gro

strahlen	equ	512		; volle Umdrehung = 512 Strahlen = 360 Grad
radius1		equ	40		; Kreis innen
radius2		equ 	170		; Kreis auen
punkte		equ	64		; wieviel Punkte nach vorne sehen - Richtung Horizont

bit_shift	equ	9		; 2**9 = 512 -> eine Zeile in der Landkarte 
					; siehe Landschaftsdaten

berechne_strahlen:

                lea     strahlen_speicher(PC),A0	; hier werden die Strahlen abgelegt
                lea     sin_tabelle(PC),A1		; Sinustabelle mit 1024 Eintraegen
                lea     cos_tabelle(PC),A4		; Kosinustabelle 

                moveq   #0,D0           	; Strahlenzhler initialisieren

strahlen_loop:
                move.l  D0,-(SP)

; pro Strahl durchlaufen ...

                move.w  D0,D4			
                mulu    #1024,D4		; 1024 Winkel in der Cos/Sin Tabelle ...
                divu    #strahlen,D4		; ... auf bentigte Strahlenwinkel umrechnen
                add.w   D4,D4			; fuer Tabellenzugriff ( pro Winkel ein Word)
                and.w   #$07FE,D4		; in der Tablle bleiben (sin+cos periodisch)
                move.w  0(A1,D4.w),D0	; Sinuswert (multipliziert mit 2**15)
                move.w  0(A4,D4.w),D1	; Kosinuswert (dito)
                move.w  D0,D2
                move.w  D1,D3
                muls    #radius1,D0		; X Startpunkt auf dem inneren Kreis	(x1)
                muls    #radius1,D1		; Y Startpunkt auf dem inneren Kreis	(y1)
                muls    #radius2,D2		; X Startpunkt auf dem ueren Kreis	(x2)
                muls    #radius2,D3		; Y Startpunkt auf dem ueren Kreis	(y2)
                add.l   D0,D0			; 2**15 * 2 = 2**16 
                add.l   D1,D1			; "
                add.l   D2,D2			; "
                add.l   D3,D3			; "
                swap    D0			; Multiplikation mit 2**16 rckgngigmachen
                swap    D1
                swap    D2
                swap    D3

                sub.w   D0,D2			; x2 - x1 = deltaX
                sub.w   D1,D3			; y2 - y1 = deltaY
                ext.l   D2			; fr weitere Long Berechnungen erweitern
                ext.l   D3			; "

                suba.w  A2,A2			; A2 lschen - ist letzter x Wert
                suba.w  A3,A3			; A3 lschen - ist letzter y Wert

                moveq   #0,D4			; ist neuer x Wert
                moveq   #0,D5			; ist neuer y Wert

;--------------------------------------------------
; und jetzt die Positionsoffsets pro Strahl berechnen

                move.w  #punkte-1,D6

punkt_loop:
                movea.l D4,A5		; Aktuellen x Strahlwert sichern
                movea.l D5,A6		; gleiches fr y

                divs    #punkte,D4	; zwischen Radius1 und radius2 auf dem Strahl bewegen ...
                divs    #punkte,D5	; Umrechnung, um die gewnschte Punktanzahl auf die
                add.w   D0,D4		; Distanz x1->x2, y1->y2 zu verteilen
                add.w   D1,D5
                ext.w   D4
                ext.w   D5

                movem.w D4-D5,-(SP)	; aktuelle x,y Position sichern
                sub.w   A2,D4		; von alter Position abziehen, ergibt Delta x ...
                sub.w   A3,D5		; Delta y fr die Strahloffsets !
                movem.w (SP)+,A2-A3	; aktuelle Werte werden alte Position !

                and.l   #map_groesse-1,D4	; innerhalb der Landschaft bleiben x
                and.l   #map_groesse-1,D5	; innerhalb der Landschaft bleiben y

                moveq   #bit_shift,D7	; spezielles x+y Format erzeugen:
                lsl.l   D7,D5			; y mit Zeilenbreite multiplizieren
						; 256 fr Hhen + 256 Pixel fr Farben 
; -> 512 = 2**9
                or.l    D4,D5			; x ins Lowword

                move.l  D5,(A0)+		; x+y Wert fr den berechneten Punkt ablegen

;---------------------------------------

                move.l  A5,D4			; x+y Startwerte fr Strahl wiederherstellen
                move.l  A6,D5

                add.l   D2,D4			; Weiter in x Richtung auf dem Strahl bewegen
                add.l   D3,D5			; weiter in y Richtung auf dem Strahl bewegen
                dbra    D6,punkt_loop	; Strahl abarbeiten

                move.l  (SP)+,D0

                addq.w  #1,D0			; naechster Strahl

                cmp.w   #strahlen,D0		; Schon alle Strahlen ?
                bne     strahlen_loop
                rts

2)  Vorberechnung der Junk-Konvertierungstabelle und Junk Format

Wie setzt man einzelne Punkt schnell auf dem ST (in 4 Planes natrlich) ??? 
Hierbei hilft der movep.l Befehl - aber der wird bestimmt in einer anderen Ausgabe be-sprochen. Fr Voxel brauchen wir ihn gar nicht ...
Allerdings kann die Auflsung einige Probleme machen. Whlt man 8 Pixel Breite fr einen Voxel, dann ist es doch ein Job fr movep. 
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 ? 
Man schreibt in der Spaltenzeichenschleife berhaupt keine Pixel, sondern benutzt einen
Zwischenpuffer mit einem dafr gnstigen Format - nennen wir ihn mal Junk Puffer. Hier schreiben wir dann unsere Voxeldaten rein. Im zweiten Schritt wird dann dieser Puffer aus-
gewertet und in den ST Bildschirmspeicher geschrieben. Das mu natrlich flott gehen.
In diesem Fall ist es schneller als Voxel gleich direkt zu zeichnen.
So sieht das Format des Junk Puffers aus:

Wir haben 16 Farben, man kann also mit 4 Bit alle Farben codieren. Also soll ein Voxel durch
diese Information seine Farbe codieren (da die Breite spter 4 ist, interessiert uns hier noch
nicht ! Eine Farbe pro Einheit = Voxel ). In ein Byte unseres Puffers passen somit 2 Voxelfarb-
informationen. So sei es.

#----------- Byte 1 --------------# #----------- Byte 2 --------------# ...
Voxel1 Farbe  Voxel2 Farbe Voxel3 Farbe Voxel 4 Farbe 

Beim Schreiben in unseren Puffer mssen wir nur aufpassen, da wir einmal Bits 4,5,6,7 und
einmal Bits 0,1,2,3 beschreiben (Highnibble, Lownibble). Dies werden spter zwei ver-schiedene Spaltenzeichenroutinen bernehmen.

Die nchste Frage ist natrlich, wie die Daten des Junk Puffers in den Bildschirmspeicher 
kommen. Ganz einfach - eine groe Tabelle hilft mal wieder !

Die Junk Puffer Konvertierungsroutine (siehe Punkt 4) geht so vor:
Es wird immer ein Wort aus dem Junk Puffer ausgelesen. Dieses Wort codiert ja 4 Voxel (pro
Byte 2). Bei einer angestrebten Voxelbreite von 4 macht entsprechen dieser Information
4 Voxel * 4 Pixel = 16 Pixel. Hrte ich gerade 16 Pixel ??? Das ist doch schon was fr unseren
ST Bildschirmspeicher. Und so geht es weiter ... ber die Tabelle werden die 4 Farb-informationen in die 4 Planewrter des STs umgesetzt und in den Bildschirmspeicher geschrieben. Mehr ist es nicht. Zur Tabelle selbst: sie mu alle Kombinationen abdecken,
also 16 Farben (Voxel 1) * 16 Farben(Voxel 2) * 16 Farben (Voxel 3) * 15 Farben (Voxel 4, ich
benutze Farbe 16 fr Rasterfarben, kann ich mir hier also sparen ...) * 4 Planewrter ST =
491520 Bytes ! Ist nicht gerade wenig .... ich wei.


********** Source: Vorberechnungen der Junk Tabelle ***********

precalculate_junk_tab:

                lea     mammut_table,A0

                lea     d0_tab(PC),A1
                lea     d1_tab(PC),A2
                lea     d2_tab(PC),A3
                lea     d3_tab(PC),A4

                moveq   #0,D0
                moveq   #0,D1
                moveq   #0,D2
                moveq   #0,D3

loop:

; Spalte 0

                move.w  D0,D4
                lsl.w   #3,D4
                movem.l 0(A1,D4.w),D5-D6

; Spalte 1
                move.w  D1,D4
                lsl.w   #3,D4
                or.l    0(A2,D4.w),D5
                or.l    4(A2,D4.w),D6

; Spalte 2
                move.w  D2,D4
                lsl.w   #3,D4
                or.l    0(A3,D4.w),D5
                or.l    4(A3,D4.w),D6

; Spalte 3

                move.w  D3,D4
                lsl.w   #3,D4
                or.l    0(A4,D4.w),D5
                or.l    4(A4,D4.w),D6

; In Tabelle schreiben

                move.l  D5,(A0)+
                move.l  D6,(A0)+

; Nchste Kombination

                addq.w  #1,D0
                cmp.w   #16,D0	; 16 * ...
                blt.s   loop
                moveq   #0,D0

                addq.w  #1,D1
                cmp.w   #16,D1	; ... * 16 * ...
                blt.s   loop
                moveq   #0,D1

                addq.w  #1,D2
                cmp.w   #16,D2	; ... * 16 * ...
                blt.s   loop
                moveq   #0,D2

                addq.w  #1,D3
                cmp.w   #15,D3	; ... * 15
                blt.s   loop

                rts

d0_tab:         DC.W $000F,$000F,$000F,$000F
                DC.W $000F,0,0,0
                DC.W 0,$000F,0,0
                DC.W $000F,$000F,0,0
                DC.W 0,0,$000F,0
                DC.W $000F,0,$000F,0
                DC.W 0,$000F,$000F,0
                DC.W $000F,$000F,$000F,0
                DC.W 0,0,0,$000F
                DC.W $000F,0,0,$000F
                DC.W 0,$000F,0,$000F
                DC.W $000F,$000F,0,$000F
                DC.W 0,0,$000F,$000F
                DC.W $000F,0,$000F,$000F
                DC.W 0,$000F,$000F,$000F
                DS.W 4

d1_tab:         DC.W $00F0,$00F0,$00F0,$00F0
                DC.W $00F0,0,0,0
                DC.W 0,$00F0,0,0
                DC.W $00F0,$00F0,0,0
                DC.W 0,0,$00F0,0
                DC.W $00F0,0,$00F0,0
                DC.W 0,$00F0,$00F0,0
                DC.W $00F0,$00F0,$00F0,0
                DC.W 0,0,0,$00F0
                DC.W $00F0,0,0,$00F0
                DC.W 0,$00F0,0,$00F0
                DC.W $00F0,$00F0,0,$00F0
                DC.W 0,0,$00F0,$00F0
                DC.W $00F0,0,$00F0,$00F0
                DC.W 0,$00F0,$00F0,$00F0
                DS.W 4

d2_tab:         DC.W $0F00,$0F00,$0F00,$0F00
                DC.W $0F00,0,0,0
                DC.W 0,$0F00,0,0
                DC.W $0F00,$0F00,0,0
                DC.W 0,0,$0F00,0
                DC.W $0F00,0,$0F00,0
                DC.W 0,$0F00,$0F00,0
                DC.W $0F00,$0F00,$0F00,0
                DC.W 0,0,0,$0F00
                DC.W $0F00,0,0,$0F00
                DC.W 0,$0F00,0,$0F00
                DC.W $0F00,$0F00,0,$0F00
                DC.W 0,0,$0F00,$0F00
                DC.W $0F00,0,$0F00,$0F00
                DC.W 0,$0F00,$0F00,$0F00
                DS.W 4

d3_tab:         DC.W $F000,$F000,$F000,$F000
                DC.W $F000,0,0,0
                DC.W 0,$F000,0,0
                DC.W $F000,$F000,0,0
                DC.W 0,0,$F000,0
                DC.W $F000,0,$F000,0
                DC.W 0,$F000,$F000,0
                DC.W $F000,$F000,$F000,0
                DC.W 0,0,0,$F000
                DC.W $F000,0,0,$F000
                DC.W 0,$F000,0,$F000
                DC.W $F000,$F000,0,$F000
                DC.W 0,0,$F000,$F000
                DC.W $F000,0,$F000,$F000
                DC.W 0,$F000,$F000,$F000
                DS.W 4


3)  Spaltenzeichnerroutine

Die Spaltenzeichenroutine geht nach dem bereits geschilderten Algorithmus vor (siehe 
Grundlagen). Anzumerken ist noch, da die Farbtabelle die 4 Bit Farbinformationen
im oberen Nibble eines Bytes speichert. In der zweiten Routine mssen die Farben dann noch 
fr das untere Nibble geshiftet werden.


********** Source: Zeichnen der Spalten ***********

mask		equ	%00000000000000011111111011111111
spalten		equ	64	; wir zeichnen 64 Spalten (256 Screenpixel / 4 Pixel pro Voxel)

scan_nibble_high:

;**** Registerbelegung innerhalb der Schleifen ****

; d0= x+y Position
; d1= Neue Hoehe
; d2= Alte Hoehe
; d3= Spaltenpunkte Zhler
; d4= pers adr + work byte
; d5= perts adder
; d6= Offset einer Zeile innerhalb des Junk Puffers
; d7= And Maske fr Bleiben innerhalb der Landschaft 

* a0= Delta-xy-offset Tabelle eines Strahls
* a1= Zugriff auf die Hhendaten der Landschaft
* a2= Zugriff auf die Farbdaten der Landschaft
* a3= Fr Direkteinsprung in die Turmzeichenbefehlsfolge
* a4= Perspektiven Tabelle
* a5= Aktuelle Screen Adresse
* a6= Alte Screen Adresse

                lea     byte_code_1(PC),A3	* Adresse fr Code (Direkteinsprung)

                moveq   #0,D1           * Neue Hhe init
                moveq   #0,D2           * Alte Hhe init
                move.w  #punkte-1,D3    * Anzahl der Voxel, die Richtung Horizont 
					   * ausgewertet werden sollen
                moveq   #0,D4		   * Perspektiventabelle Start ganz vorne beim Betrachter
                move.w  #perspektiven*punkte,D5	* Offset fr Schritt Richtung Horizont
		 moveq   #spalten/2,D6			* Zeilenoffset einer Junk Puffer Zeile
                move.l  #mask,D7			* Landschaftsabhngig


do_row_byte_1:
                add.w   D5,D4		   * In der Perspektiventabelle einen Schritt
   * Richtung Horizont machen ...

                add.l   (A0)+,D0        * actual x-y-position
                and.l   D7,D0           * mask raender

                move.b  0(A1,D0.l),D4   * Hhe auslesen
                move.b  0(A4,D4.l),D1   * Hhe perspektivisch anpassen ...
   * Ergebnis: Hhe * 4 -> fr Direkteinsprung

                sub.w   D1,D2           * Alte Hhe - neue Hhe < 0 ?
* damit ist der neue Punkt nicht sichtbar !
   * also nichts zeichnen

                bmi.s   scan_me_byte_1
                add.w   D1,D2		   * Operation rckgngig machen -> alte Hhe bleibt
					   * der Mastab !
                dbra    D3,do_row_byte_1 	* Nchster Punkt
                rts

scan_me_byte_1:
                move.b  0(A2,D0.l),D4   * Farbinformation holen (Byte)

                jmp     0(A3,D2.w)	   * Direkteinsprung (abh. von neu zu zeichnendem
					   * Turmdelta -> die )

********* Farbwerte eintragen ***********

                REPT max_y
                move.b  D4,(A5)		* Farbe in Junk Puffer schreiben
                suba.w  D6,A5			* vorherige Zeile im Junk Puffer adressieren
			; beide Befehle zusammen 2 Words = 4 Byte
                ENDR

byte_code_1:    move.w  D1,D2			* neue Hhe wird zur alten Hhe
                dbra    D3,do_row_byte_1	* nchstes Voxel
                rts
                

Die selbe Prozedur fr jede 2.Spalte - hier werden die niedrigen Nibbles des Junk
Puffers gefllt.

scan_nibble_low:

                lea     byte_code_2(PC),A3

                moveq   #0,D1           
                moveq   #0,D2           
                move.w  #punkte-1,D3    
                moveq   #0,D4
                move.w  #perspektiven*punkte,D5
		 moveq   #spalten/2,D6			* Zeilenoffset einer Junk Puffer Zeile
                move.l  #mask,D7			* Landschaftsabhngig

do_row_byte_2:
                add.w   D5,D4

                add.l   (A0)+,D0        
                and.l   D7,D0           

                move.b  0(A1,D0.l),D4   
                move.b  0(A4,D4.l),D1   

                sub.w   D1,D2          
                bmi.s   scan_me_byte_2
                add.w   D1,D2
                dbra    D3,do_row_byte_2
                rts

scan_me_byte_2:
                move.b  0(A2,D0.l),D4   

                lsr.b   #4,D4			; Farbinformation ins untere Nibble

                jmp     0(A3,D2.w)

                REPT max_y
                or.b    D4,(A5)		; unteres Nibble fllen
                suba.w  D6,A5
                ENDR

byte_code_2:    move.w  D1,D2
                dbra    D3,do_row_byte_2
                rts


4)  Junk Puffer Konvertierungsroutine

Umsetzen der Voxel 4Bit Farbinformationen in den ST Bildschirmspeicher - siehe Abschnitt
Junk Puffer Vorberechnung.


********** Source: Umsetzen des Junk Puffers in den ST Bildschirmspeicher ***********


scanner:        

                movea.l screen_adr(PC),A0		; Bildschirmspeicheradresse

                lea     mammut_table,A1		; Konvertierungstabelle Adresse

                lea     junk_puffer(PC),A2		; Junk Puffer Adresse

                move.w  #highs-1,D0			; wieviele Zeilen im Junk Puffer

copy_lines:     movea.w D0,A3

                moveq   #0,D0
                moveq   #0,D2
                moveq   #0,D4
                moveq   #0,D6
                move.w  (A2)+,D0			; Wort mit 4 Voxel Farben holen
                move.w  (A2)+,D2
                move.w  (A2)+,D4
                move.w  (A2)+,D6
                lsl.l   #3,D0				; 4 Plane Wrter = 8 Byte
                lsl.l   #3,D2
                lsl.l   #3,D4
                lsl.l   #3,D6

                movem.l 0(A1,D0.l),D0-D1		; Konvertierte Wrter holen
                movem.l 0(A1,D2.l),D2-D3
                movem.l 0(A1,D4.l),D4-D5
                movem.l 0(A1,D6.l),D6-D7
                movem.l D0-D7,(A0)      		* 64 Pixel schreiben
                movem.l D0-D7,160(A0)		* Zeile verdoppeln (y double pix)

off             SET 16*4/2
                REPT 3

                moveq   #0,D0
                moveq   #0,D2
                moveq   #0,D4
                moveq   #0,D6
                move.w  (A2)+,D0
                move.w  (A2)+,D2
                move.w  (A2)+,D4
                move.w  (A2)+,D6
                lsl.l   #3,D0
                lsl.l   #3,D2
                lsl.l   #3,D4
                lsl.l   #3,D6

                movem.l 0(A1,D0.l),D0-D1
                movem.l 0(A1,D2.l),D2-D3
                movem.l 0(A1,D4.l),D4-D5
                movem.l 0(A1,D6.l),D6-D7
                movem.l D0-D7,off(A0)   * 64 pixel
                movem.l D0-D7,off+160(A0)
off             SET off+16*4/2
                ENDR

                lea     320(A0),A0
                move.w  A3,D0
                dbra    D0,copy_lines
                rts


Zusammenfassung

So, das wars erstmal fr heute. Ich hoffe, da Ihr mit den Beschreibungen klarkommt. 
Auf Diskette findet Ihr noch die beiden Grafiken TURM.IFF und STRAHL.IFF sowie alle
Quellenausschnitte.
Bitte gebt uns auch etwas Feedback - was war gut, was schlecht, knnte man was anders 
machen, oder habt Ihr spezielle Themenwnsche ..... schreibt ans Undercover HQ !
Ich wnsche allen ATARI Freaks ein paar schne Sommermonate und noch viel Spa mit 
den anderen Artikeln .....


Mike of STAX in 1997.

