# RayTrace Movie (Atari 8bit) by D. Scott Williamson

A downloadable tool

**Ray Trace Movie Mode 15 80 Column **

by D. Scott Williamson

SCHAU category entry (10 lines less than 80 characters)

Table of contents:

Description

Included files

Startup & Emulator Instructions

Proof of 10 lines less than 80 columns

Program overview

Detailed program description

Description

This program renders a sequence of real ray traced images of two spheres over a checkerboard under a gradient sky where the camera moves forward and up in each frame. Each frame takes hours to render on native hardware and several minutes in an accelerated emulator. It is amazing to me that 10 lines of Atari BASIC less than 80 characters each can achieve such a beautiful technological result on 1978 hardware given the time to render the frames.

The included GIF is composed of 198 images captured over 16 hours played forward and backwards looping.

Included Files

README RayTrace Movie Mode 15 80 Column.txt This file

Ray Tracing movie mode 15 80 column.atr Atari DOS floppy disk including RAYTR80M.LST and RAYTR80M.BAS

RayTrace Movie Mode 15 80 columns.gif Animated gif made from captured frames

RayTrace Movie Mode 15 80 columns.png Static screenshot

RayTrace80M.lst Program listing (included below too)

RayTrace80M line length (80).png PNG of line length proof

RayTrace80M line length (80).lst Listing of line length proof

The program will continually loop rendering ray traced frames of an animated sequence.

Proof of 10 lines less than 80 columns (also see included png)

00000000011111111112222222222333333333344444444445555555555666666666677777777778 12345678901234567890123456789012345678901234567890123456789012345678901234567890 1 GR.31:SE.0,7,2:SE.1,3,8:SE.2,13,15:DI.DI(16):F.I=0TO15:REA.R:DI(I)=R:N.I:A=2 2 F.N=0TO191:F.M=0TO159:POK.77,0:X=0:Y=-A/25:Z=A:I=SGN(M-80.5) 3 U=(M-80.5)/(40*1.3):V=(N-80.5)/(80*1.3):W=1/SQR(U*U+V*V+1):U=U*W:V=V*W:G=1 4 E=X-I:F=Y-I:P=U*E+V*F-W*Z:D=P*P-E*E-F*F-Z*Z+1:G.5+(D<=0)*3 5 T=-P-SQR(D):G.6+(T<=0)*2:D.0,24,6,30,36,12,42,18,9,33,3,27,45,21,39,15 6 X=X+T*U:Y=Y+T*V:Z=Z-T*W:E=X-I:F=Y-I:G=Z:P=2*(U*E+V*F-W*G) 7 U=U-P*E:V=V-P*F:W=W+P*G:I=-I:G.4 8 IF V<0THEN P=(Y+2)/V:S=INT(X-U*P)+INT(Z-W*P):S=S-INT(S/2)*2:V=-V*(S/2+.3)+.2 9 C.3-INT(((3*16)*SQR(V)+DI((M-INT(M/4)*4)+(N-INT(N/4)*4)*4)/3)/16):PL.M,191-N 10 N.M:N.N:A=10*(A=-1)+(A-.1)*(A>-1):G.2

Program Overview:

Line 1 sets up graphics mode 15 (4 color 160x192), colors, 4x4 dithering table, and initializes the animation parameter

Line 2 Loop over each screen pixel (M,N) and initialize view position (X,Y,Z)

Line 3 Calculate 2D unit viewport vector (U,V)

Lines 4-7 Handle reflections off the two spheres

Line 8 Handle the checkerboard pattern by a modulus 2 of a function combining X and Z in perspective to modulate the vertical V value that will be used as final intensity

Line 9 Set the color of the pixel based on curved intensity ramp and dithering and plot the pixel

line 10 Loop through pixels, update animation parameter to cycle between 10 and -1 by .1 increments

Detailed command by command program description:

1 GR.31: Graphics mode 15 full screen without text window 4 color 160x192

SE.0,7,2: Set color 1 to dark blue

SE.1,3,8: Set color 2 to purple

SE.2,13,15: Set color 3 to yellow

DI.DI(16): Dimension DI array for dithering constants

F.I=0TO15: Loop 0 to 15 to load DI array from data

REA.R: Read data into temporary variable R because can't read into array

DI(I)=R: Store data in R into array at index I

N.I: Next I

A=2 Set initial frame animation parameter A

A ranges from 10 to -1 and controls Z and Y coordinates of the camera

2 F.N=0TO191: Loop over scan lines

F.M=0TO159: Loop from left to right on each line

POK.77,0: Reset attract mode timer to prevent Atari color cycling CRT screen saver

X=0: Camera X coordinate is 0, centered

Y=-A/25: Camera Y coordinate ranges from -2.5 at A=10 to .25 at A=-1

Z=A: Camera Z coordinate

I=SGN(M-80.5) I is +1 on the left half of the screen and -1 on the right, the .5 guarantees never zero

3 U=(M-80.5)/(40*1.3): U is the viewport coordinate ranging from -1 to 1 horizontally

V=(N-80.5)/(80*1.3): V is the viewport coordinate ranging from -1 to 1 vertically

W=1/SQR(U*U+V*V+1): W is 1/(the length of the vector from the center of the screen to (U,V)

U=U*W: Scale U by the reciprocal length of offset vector to make unit vector (U,V)

V=V*W: Scale U by the reciprocal length of offset vector to make unit vector (U,V)

G=1 Initialize G to 1

4 E=X-I: E is X moved one pixel toward the horizontal center of the screen

F=Y-I: F is Y moved one pixel toward the vertical center of the screen

P=U*E+V*F-W*Z: P is the perspective adjusted point E,F in the viewport

D=P*P-E*E-F*F-Z*Z+1: Subtract the magnitude of (E,F,Z) from P and add 1 used to remove unwanted extra reflections on spheres

G.5+(D<=0)*3 These lines are too long for IF..THEN.. so use goto with conditional line number calculation: if D>0 goto 5 (next line) else 8

5 T=-P-SQR(D): Check to see if the next reflection will bounce off the other sphere

G.6+(T<=0)*2: If T<=0 then we're done bouncing the ray between spheres and UV have the final direction vector

D.0,24,6,30,36,12,42,18,9,33,3,27,45,21,39,15 Dither pattern constants

6 X=X+T*U: At this point there is a reflection, this handles bouncing ray between spheres (It cannot loop infinitely because the camera cannot see infinite reflection ray between spheres) Move the eyepoint Y to the surface of the sphere

Y=Y+T*V: Move the eyepoint Y to the surface of the sphere

Z=Z-T*W: Move the eyepoint Z to the surface of the sphere

E=X-I: Update E based on new X

F=Y-I: Update F based on new Y

G=Z: Update G based on new Z

P=2*(U*E+V*F-W*G) Update perspective parameter based on reflection

7 U=U-P*E: Update U parameter based on new P and E

V=V-P*F: Update V parameter based on new P and F

W=W+P*G: Update W parameter based on new P and G

I=-I: With each reflection negate I, bouncing in different direction

G.4 Loop unil one of the conditional gotos above goes to 8 (fails the if)

8 IF V<0THEN P=(Y+2)/V: Checkerboard calculation is only for pixels where V is negative below the virtical center of the screen

S=INT(X-U*P)+INT(Z-W*P): Calculate checkerboard parameter, X,Y is pixel in screen space, (U,W)*P is the perspective corerection

S=S-INT(S/2)*2: This a modulus 2 - subtract the integer portion of S/2 multiplied by 2

V=-V*(S/2+.3)+.2 Adjust the V (virtical screen space unit vector) value to be always positive and modulated by the checkerboard parameter S which is now 0 or 1 based on X and Z with perspective correction by P

9 C.3-INT(((3*16)*SQR(V)+DI((M-INT(M/4)*4)+(N-INT(N/4)*4)*4)/3)/16): Set color

V ranges from 0 to 1 where 0 at the horizon is bright and 1 toward the top and bottom of the screen are dark. V has been tweaked for the checkerboard.

Square root of V adds curvature to the gradient to represent a gradient on the inside of a sphere

Scaling by 3*16 is done because there are 3 is the maximum value and there are 16 dither parameters

The dithering is done in a 4x4 pixel square so the following calculation selects the dither parameter index based on the horizontal and vertical screen pixel position (M,N)

M-INT(M/4)*4 is the same as M mod 4

N-INT(N/4)*4 is the same as N mod 4

Note the N parameter is multiplied by 4 because dither parameters in DI are arranged in 4 rows of 4 VALUES

The dither parameter is looked up from DI and divided by 3 to get fractional values from integers for historical reasons

The scaled dithered parameter is added to the scaled value, divided by 16 and truncated by the INT instruction

The result is the fractional pixel value has fractional constants added to it at each pixel location such that when cast to an int some values move to neighboring integer values.

The result is subtracted from 3 to match the dark to light color gradient stored in the color registers

PL.M,191-N Plot point at M,191-N in the color set in line 9, the 191-N is to correct for the Atari graphics origin being in the upper left rather than lower left corner.

10 N.M: Next pixel on the LINE

N.N: Next line

A=10*(A=-1)+(A-.1)*(A>-1): Update animation parameter: If A=-1 then set A to 10, if A >-1 then subtract .1

G.2 Loop forever

## Download

## Install instructions

Startup & Emulator Instructions

1. Run Atari800Win PLus

2. Set Machine Type to XL/XE

3. Set Video System to NTSC (not strictly necessary)

4. Make sure BASIC is enabled ("Disable BASIC when booting" is disabled in settings)

4. Alt-D or drag and drop to attach "Ray Tracing movie mode 15 80 column.atr" to the emulator as D1:

5. Shift-F5 to reset the emulator which will now be in BASIC at the READY prompt with the disk loaded in D1:

6. Type "ENTER"D1:RAYTR80M.LST" and press enter to load the program

7. (optional) type "LIST" to see listing

8. type "RUN" to run the program

It is recommended to press F7 to toggle full speed of the emulator.

## Leave a comment

Log in with itch.io to leave a comment.