@C9Sourcecode - Das Intro von Coder`s Revenge

@CE
Der Schneeffekt!!! :)
@C7
Ja, es weihnachtet so schn, und da gehrt auch Schnee dazu. Wenn er schon nicht
drauen rumliegt - Coder`s Revenge bringt ihn, exclusiv fr unsere Leser.

Der Schneeffekt ist nichts anderes als eine aus Punkten bestehende, dreidimen-
sional um eine Achse rotierende, perspektivisch verzerrte, in x-Richtung
schlengelnde, depth-shaded und nach unten fallende Sule.

@C6Bewegung der Schneeflocken
@C7                                                        @G"schneef1"
Jede Schneeflocke hat eine Hhe, einen Abstand zur Mit-
telachse und einen Winkel. Diese 3 Daten beschreiben die
Position der Schneeflocke in der imaginren Sule. Die
Hhe der Schneeflocke wird stndig verringert. Somit
fllt der Schnee. Wenn die Schneeflocke am Boden der
Sule angekommen ist, wird sie wieder nach oben gesetzt.
Der Winkel der Schneeflocke wird ebenfalls stndig ver-
ringert, wodurch sie sich immer um die Mittelachse
dreht. Der Abstand zum Mittelpunkt, also der Radius,
bleibt logischerweise konstant. Damit gestalten die
Schneeflocken in ihrer Gesamtheit einen nach unten
fallenden Zylinder.
                                                        @G"schneef2"
Damit die fallenden Schneeflocken nicht allzu langweilig
wirken, verpassen wir ihnen noch etwas windhosenartiges.
Dazu wird die Sule bei der Darstellung in x-Richtung
entlang einer Sinuskurve verschoben.




@C6Darstellung auf dem 2-dimensionalen Screen
@C7
Wie gesagt, hat eine Schneeflocke eine Hhe, einen
Abstand zum Mittelpunkt und einen Drehwinkel. Somit ist
also ihre Position im 3-dimensionalen Raum beschrieben. Um die Schneeflocken nun
auf dem Bildschirm darzustellen, mu man diese Koordinaten in 2-dimensionale
Koordinaten umrechnen. Wir definieren den Bildschirmmittelpunkt als Koordinaten-
ursprung P(0|0).

Die Umrechnung wird in zwei Schritten getan: Zunchst werden die Winkel-Radius-
Hhe-Koordinaten einer Schneeflocke in x-y-z-Koordinaten umgerechnet. Diese Form
der Koordinaten ist einfacher zu handhaben, wenn wir den zweiten Schritt machen,
die x-y-z-Koordinaten in xy-Koordinaten fr die Bildschirmdarstellung umzurech-
nen.

1. Winkel-Radius-Hhe -> x-y-z

Die Hhe der Schneeflocke in der Sule braucht nicht umgerechnet werden, sie
kann direkt als y-Koordinate bernommen werden. Um den x-Wert zu bestimmen,
bilden wir den Sinus des aktuellen Drehwinkels und multiplizieren ihn mit dem
Radius. hnlich wird verfahren, um den z-Wert, also die Tiefe im Raum, zu
bilden. Hier mu der Cosinus des Winkels gebildet und mit dem Radius multipli-
ziert werden.
Da es sehr viel Rechenzeit kostet, den Sinus bzw. Cosinus eines Winkels zu
bilden, speichern wir uns die Sinus- bzw. Cosinuswerte fr alle Winkel, die die
Schneeflocke annehmen kann, in Tabellen ab. Fr unsere Zwecke definieren wir die
Sinus- und Cosinusfunktion so, da sie bei 512 periodisch ist. Das heit, da
eine Schneeflocke in 512 Schritten einmal um die Mittelachse der Sule gedreht
werden kann. Da die Sinus- bzw. Cosinusfunktion Funktionswerte liefert, die
zwischen 0 und 1 liegen und wir in ARM-Assembler nur Integer-Zahlen verwenden
knnen, multiplizieren wir beim Erstellen der Tabellen die Funktionswerte mit
256. Somit bestehen die Eintrge der Tabellen aus Integerzahlen, die zwischen 0
und 256 liegen.

2. xyz -> xy

Hier knnen x- und y-Wert direkt bernommen werden. Der z-Wert, die Tiefe im
Raum, mu mit in die 2-dimensionalen x-y-Koordinaten eingerechnet werden. Dabei
soll unsere Schneesule nach hinten perspektivisch verzerrt werden, damit eine
dreidimensionale Wirkung zustande kommt. Die Bildschirmmitte soll ja unser
Koordinatenursprung sein, hier liegt auch der Fluchtpunkt der perspektivischen
Verzerrung. Im Klartext, h, -code heit das, da bei z-Werten, die tiefer im
3D-Raum liegen, unsere gesuchten 2D-x-y-Werte mehr zum Bildschirmmittelpunkt
"verbogen" werden mssen als bei z-Werten, die nher zum Betrachter liegen.
Objekte, die tiefer im Raum liegen, erscheinen dem zweidimensional abbildenden
Auge ja auch kleiner und zum Fluchtpunkt hin verschoben. Fr unsere Schneesule
knnen wir die Verzerrung in x-Richtung vernachlssigen, die dreidimensionale
Wirkung kommt auch zustande, wenn wir die z-Werte nur bei den y-Koordinaten mit
einrechnen. Um nun die y-Werte zu "korrigieren", verwenden wir folgende Formel:
@C2
  y = y + y*z/scale
@C7
y*z/scale ist also der Summand, um den der y-Wert korrigiert wird. Das "y*z"
bewirkt, da der Einflu der perspektivischen Verschiebung zum Fluchtpunkt hin
geringer wird, wenn sich die y-Koordinate der 0, also dem Fluchtpunkt, nhert.
Mit "scale" wird die Intensitt beschrieben, in der der z-Wert den y-Wert beein-
flut. Je grer scale ist, desto geringer ist auch die Beeinflussung. In
unserem Fall realisieren wir diese Division mit "scale" durch einen Shift (ASR).

3. Plotten auf den Screen

Letztendlich mssen die Schneeflocken noch in den Bildschirmspeicher geschrieben
werden. Die x-y-Koordinaten werden dazu in absolute Bildschirmadressen umge-
wandelt. Da die x-y-Werte der Schneeflocken relativ zum Bildschirmmittelpunkt
sind, erhlt man die absolute Plot-Adresse nach der Formel:
@C2
  Adr = Screenbaseadresse + Offset_zur_Bildmitte + x + y*320
@C7
Wir nutzen eine Auflsung von 320*256 Pixeln, also hat "Offset_zur_Bildmitte"
den Wert 320*128+160.
Da die Schneeflocken in grerer Raumtiefe dunkler sein sollen, laden wir vor
dem Plotten noch den entsprechenden Farbwert aus einer Helligkeitstabelle. Dafr
brauchen wir nochmal den z-Wert der 3D-Koordinaten, der ja die Raumtiefe angibt.

@C3
Anz%=1024                               :REM Anzahl der Schneeflocken

DIM CODE 4000
DIM SCHNEE Anz%*16
DIM XSIN 512*4
DIM ZCOS 512*4
DIM MOVTAB 4*(360+512)

FOR I%=0 TO Anz%-1                      :REM Daten der Schneeflocken initial.
SCHNEE!(I%*16)=RND(511)                 :REM Winkel
SCHNEE!(I%*16+4)=RND(256)               :REM Radius
SCHNEE!(I%*16+8)=RND(256)-128           :REM Hoehe
SCHNEE!(I%*16+12)=CODE                  :REM alte Position
NEXT

FOR I%=0 TO 511                         :REM Sinus und Cosinustabelle erstellen
XSIN!(I%*4)=SINRAD(I%*0.703125)*256     :REM - periodisch bei 512
ZCOS!(I%*4)=COSRAD(I%*0.703125)*256
NEXT

FOR I%=0 TO 360+512-1                   :REM Schneebahn-Tabelle erstellen
MOVTAB!(I%*4)=SINRADI%*100
NEXT


FOR durchl=0 TO 2 STEP 2
P%=CODE
[ OPT durchl

SWI &100+22:SWI &100+15
SWI &100+22:SWI &100+13

SWI "OS_RemoveCursors"
ADR R0,scrbase:MOV R1,R0
SWI "OS_ReadVduVariables"

.mainloop
MOV R0,#19:SWI "OS_Byte"                ; auf VSync warten
B schnee
.back
SWI "OS_ReadEscapeState":BCC mainloop
SWI "OS_Exit"

.scrbase EQUD 149:EQUD -1

; ----- lustiges Schneetreiben -----
; R0 - Screenadresse
; R1 - Adresse der Schneetabelle
; R2 - Adresse der Sinustabelle
; R3 - Adresse der Cosinustabelle
; R4 - Winkel der Schneeflocke zum Mittelpunkt
; R5 - Radius (Entfernung vom Mittelpunkt)
; R6 - Hoehe auf dem Bildschirm (y-Position)
; R7 - x-Pos. / absolute Position der Schneeflocke relativ zum Screenmittelpunkt
; R8 - Temp / Farbe
; R9 - Adresse der Farbtabelle
; R10 - Tiefe im Raum (z-Position)
; R13 - Adresse der Schneebahn (Schneewirbel)
; R14 - Schneeflockenzaehler

.schneetab EQUD SCHNEE                  ; Adresse der Schneedaten
.schneesin EQUD XSIN                    ; Adresse der Sinustabelle fuer x-Pos.
.schneecos EQUD ZCOS                    ; Adresse der Cosinustabelle fuer z-Pos.
.schneebahn EQUD MOVTAB+256*4           ; Adresse der Bahndaten d. Schneewirbels
.schneectr EQUD 0                       ; Zaehler fuer Schneebahn
.schneecol EQUB 0:EQUB 1:EQUB 2:EQUB 3:EQUB 44:EQUB 45:EQUB 46:EQUB 47
EQUB 208:EQUB 209:EQUB 210:EQUB 211:EQUB 252:EQUB 253:EQUB 254:EQUB 255

.schnee
LDR R0,scrbase                          ; Screenbaseadresse laden
ADD R0,R0,#160:ADD R0,R0,#320*128       ; alle Adressen releativ zur Screenmitte

LDR R1,schneetab                        ; Adresse der Schneedaten
LDR R2,schneesin                        ; Adresse der Sinustabelle fuer x-Pos.
LDR R3,schneecos                        ; Adresse der Cosinustabelle fuer z-Pos.
ADR R9,schneecol+8                      ; Zeiger auf Mitte der Farbtabelle

LDR R14,schneectr                       ; Zaehler fuer Schneebahn laden
SUBS R14,R14,#2                         ; - verringern
ADDLT R14,R14,#360                      ; - wenn kleiner 0 wieder 359
STR R14,schneectr                       ; - speichern
LDR R13,schneebahn                      ; Adresse der Schneebahndaten
ADD R13,R13,R14,ASL #2                  ; Position in Schneebahn-Tabelle setzen

MOV R14,#Anz%                           ; Zaehler fuer Schneeflocken

.schneeloop
LDMIA R1,{R4,R5,R6,R7}                  ; Winkel, Radius, Hoehe, alte Pos. laden

MOV R8,#0:STRB R8,[R7]                  ; Pixel an alter Position loeschen

LDR R7,[R2,R4,ASL #2]                   ; Sinus des Winkels laden
MUL R7,R5,R7:MOV R7,R7,ASR #8           ; Radius mit Sinus multiplizieren
LDR R8,[R13,R6,ASL #2]                  ; Eintrag aus Schneebahn laden
ADD R7,R7,R8                            ; und mit x-Position addieren
CMN R7,#160:RSBGTS R8,R7,#160:BLE notplot; x-Clipping (-160 bis 160 ist erlaubt)

LDR R10,[R3,R4,ASL #2]                  ; Cosinus des Winkels laden -> 3D-Tiefe
MUL R10,R5,R10                          ; Radius mit Cosinus multiplizieren

MUL R8,R10,R6                           ; z-Koordinate in y-Offset umrechnen
ADD R8,R6,R8,ASR #16                    ; zu y-Koordinate addieren->Perspektive

ADD R7,R7,R8,ASL #8                     ; absoluten Offset zur Screenmitt bilden
ADD R7,R7,R8,ASL #6                     ; -> (x + y*320)
CMN R7,#320*128:RSBGTS R8,R7,#320*128   ; y-Clipping
LDRGTB R8,[R9,R10,ASR #13]              ; je nach 3D-Tiefe die Farbe laden
STRGTB R8,[R7,R0]!                      ; Pixel an fertige Position plotten
.notplot
MOVLE R7,R0                             ; bei out-of-screen alte Position = 0

SUBS R4,R4,#2:ADDLT R4,R4,#512          ; Winkel verringern (Drehung)
ADD R6,R6,#2:CMP R6,#128:SUBGE R6,R6,#256; Hoehe verringern

STMIA R1!,{R4,R5,R6,R7}                 ; veraenderte Werte speichern
SUBS R14,R14,#1:BNE schneeloop          ; naechste Schneeflocke

B back
]
NEXT durchl
CALL CODE

@C7
Nachtrgliche Revision des Artikels: Bei Redaktionsschlu lag doch Schnee.

                                                                        @G"^.red"

