A downloadable tool

Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing

Table of contents:

Description

Included files description

Startup & Emulator Instructions

Interactive instructions

Proof of 10 lines less than 256 columns

Program overview

Detailed program description


Description

This program generates a Ray Traced rendered 3D scene containing two offset mirrored spheres over a checkerboard under a twilight sky.  The pixel processing uses a multiresolution renderer to continuously refine an approximation of the image to full resolution.  A bright cursor shows exactly where the ray is being traced in real time.  While rendering, a soundscape inspired by the chorus of vibrations of the universe and quantum interference of photons as they travel through space is continuously rendered.  At any time, the user may use the joystick to view the scene in either 16 intensities of a single wavelength of light or one intensity of 16 frequencies of light.  When rendering is complete a cosmic melody is played in rounds of increasing frequency representing universal order yielding to entropy while the user may continue to interactively explore hues and intensities in the completed scene.

It is amazing to me that 10 lines of Atari BASIC can deliver such a beautiful multimedia technological result.

At any time the screen mode and color settings can be interactively adjusted by the joystick as follows:

Left will set GTIA mode 9 (16 luminosities of a single hue) and will cycle down through the 16 hues

Right will set GTIA mode 9 (16 luminosities of a single hue) and will cycle up through the 16 hues

Up will set GTIA mode 11 (16 hues of a single luminosity) and will cycle up through the 8 luminosities 

Down will set GTIA mode 11 (16 hues of a single luminosity) and will cycle down through the 8 luminosities 


Program features

What is Ray Tracing?  

Conventional 3D rendering typically draws shapes created from triangle meshes or curved surfaces that have bitmaps applied to represent color, reflectivity, roughness, surface normals, etc.  Light and shadow are approximated by calculations using the surface qualities and known light sources light fields in scenes.  Reflections and refractions are approximated using environment mapping techniques.  Ray Tracing actually casts a ray backwards from the eye through each pixel of the screen into the scene where they are reflected and refracted to retrace the path of photons back to light sources that emitted them.  Typically, a large number of rays are sent through each pixel and additional rays are scattered off surfaces.  All of these rays are integrated into the final color of each pixel.  In this way, Ray Tracing creates high detail photo-realistic images with accurate reflections, refractions, shadows, and radiance.

This program is a minimal Ray Tracing demonstration featuring an illuminated sky dome above two offset perfectly reflective spheres hovering over a checkerboard ground plane.  Light rays sent into the scene intersect the celestial dome directly or through a sequence of reflections off the spheres.  Note: There is only ray between the two spheres that would result in infinite reflections and it is not visible outside the spheres, so all rays that touch a sphere from the outside are guaranteed to reach the environment after a finite number of bounces between the spheres.

Adapted to Atari BASIC and enhanced from Coprolite9000's Mastodon post:https://mastodon.me.uk/@bbcmicrobot/111762132859648345 which itself is an adaptation from an unknown author, also seen here: https://www.riscosopen.org/forum/forums/5/topics/17679

GTIA modes 9 and 11

Atari GTIA graphics modes allow the bitmapped display of 16 hues or 16 intensities, a great improvement over the CTIA's 4 color graphics modes 

GTIA Mode 9: 16 intensities in 1 of 16 hues

GTIA Mode 11: 16 hues in 1 of 8 intensities 

Adding 32 to the graphics mode in line 80 allows interactively switching between compatible modes without clearing the frame buffer

Care had to be taken to render the scene correctly given the extremely wide (4:1) aspect ratio of the pixels


Multiresolution renderer

Rather than naively rasterizing the screen, the multiresolution renderer still renders each pixel exactly once but it is done in an order that successively covers the screen providing an observer an early and continuously refined view of the scene.  This is done by first rendering 3 rows that are 64 pixels tall, then 3 offset rows of 32 tall, then 6 rows of 16 tall, 12 rows of 8 tall, 24 rows of 4 tall, 48 rows of 2 tall, and finally 96 rows of 1 tall filling in every other remaining line on the screen.


Use of variables for constants

From the Atari BASIC Manual: "Each time a constant (4,5,16,3.14159, etc.) is used, it takes 7 bytes. Defining a new variable requires 8 bytes plus the length of the variable name (in characters). But each time it is used after being defined, it takes only I byte, regardless of its length."

Lines that contain too many constants overflow the internal tokenization buffer and cannot use the maximum 253 characters per line permitted by the input buffer length.  Using variables for constants is much more compact, furthermore deriving constants from other constants is even more compact during initialization.


The use of a single a single array to hold initialized data

BASIC provides DATA and READ statements but to use the data in the program it typically must be held in a variable.  This program has data structures for the dithering constants, three tables for input processing, and a 64 note table for the melody.  Using separate arrays would require separate DIM statements and initialization loops taking a lot of room.  Instead this program reads all the data into a single array called Q and subsections are indexed when needed by the program.


Modulus operator

Modulus operator is needed in this program for dither pattern tiling, the checkerboard, and to clamp graphics mode, intensity, and hue values changed by input.

Atari BASIC does not have a modulus operator (modulus(a,b) returns the remainder of a/b).  Instead A-INT(A/B)*B is used, let's look at it in parts.

INT(A/B) is the integer portion of A/B, aka truncated value of A/B, aka ceil(A/B)

INT(A/B)*B is the integer portion of A larger than B

A-INT(A/B)*B Subtracting the integer portion of A larger than B from A leaves the remainder or modulus.


Input

Useful joystick values from STICK(0) range from 5 to 15, subtracting 5 from the stick value allows the use of smaller 11 value tables in line 50.


Audio 

Sound hardware configuration

Atari computers audio is typically configured into the familiar four 8-bit channels but there is another rarely used two 16 bit channel configuration I've only seen in a few games like The Tale of Beta Lyrae.  In line 20, by combining audio channels 0 with 1 and 2 with 3, and clocking them from the 1.79MHz system clock you can get frequencies as low as 27.42Hz (close to note A2).  Playing two channels at frequencies different only by 1 creates a chorus or overtone effect, but when you can play square waves at such low frequencies with 16 bit frequency resolution the overtones resemble deep fat raspy filter effects.  


Resonant audio during rendering

The vibrations of the universe effect used during rendering sets a primary pitch based on the scan line, and a secondary pitch offset based on a sine function of the horizontal position on the scan line resulting in vibrations that go in and out of phase with chilling overtones.  Additionally the volume is modulated by which scan line is rendering with max volume at scan line 99.


Music

This was a little complicated...

1790000Hz divided by 65536 is 27.42 or A2.  This is the lowest note that can be played.

Ascending notes in scale can be calculated by multiplying each frequency by the twelfth root of 2 (1.059463094) 

Ascending notes in scale can also be calculated by dividing the reload value by the twelfth root of 2, or multiplying by the reciprocal (0.943874313)

Frequency values for notes were calculated in a spreadsheet

We created 32 note melodies in https://onlinesequencer.net, manually transcribed the notes into the spreadsheet, manually copied the frequency values for the notes into a column, then copied the column into the source code and adapted to the DATA statements in lines 90 and 100

The playback code loops through the 64 note melody then adjust a multiplier by 2 * 1/(the twelfth root of 2) to adjust the melody up by two semitones playing back at increasing pitch until it is reset

Each note is played for two loops with a decay volume to yield a slightly percussive instrument 


Included Files Description

README Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.txt This file

Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.atr Atari disk image containing program

Line Length Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.lst Line length <256 listing

Line Length Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.png Line length <256 image

AtariRayTraceRTG911M_1.gif Animated GIF

AtariRayTraceRTG911M_2.gif Animated GIF ping pong

RayTraceGTIA9ColorMusic_0.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA9ColorMusic_1.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA9ColorMusic_2.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA9ColorMusic_3.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA9ColorMusic_4.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA9ColorMusic_5.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA9ColorMusic_6.png Screenshot GTIA mode 9: 16 luminosities , single hue

RayTraceGTIA11ColorMusic_0.png Screenshot GTIA mode 11: 16 hues, single luminosity


Interactive instructions

The program runs in two phases:

The first phase is the multiresolution renderer where the sound is based on the ray being traced on the screen.  

The second phase after the screen is fully rendered plays music and is more responsive to input.

During both phases the screen mode and color settings can be interactively adjusted by the joystick as follows:

Left will set GTIA mode 9 (16 luminosities of a single hue) and will cycle down through the 16 hues

Right will set GTIA mode 9 (16 luminosities of a single hue) and will cycle up through the 16 hues

Up will set GTIA mode 11 (16 hues of a single luminosity) and will cycle up through the 8 luminosities 

Down will set GTIA mode 11 (16 hues of a single luminosity) and will cycle down through the 8 luminosities 


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

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222
0000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999000000000011111111112222222222333333333344444444445555555
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
10 GR.9:N191=191:DI.Q(N191):F0=53762:F1=53766:C0=53763:C1=53767:N0=0:N1=1:N2=N1+N1:N4=N2+N2:N8=N4+N4:N16=N4*N4:GM=N0:H=N0:L=N8:F.I=N0 TO 112:READ R:Q(I)=R:N.I:YT=N0:YD=64:YD2=YD*N2:YH=YD-N1:SO.N0,N0,N0,N0
20 N160=160:N99=99:N255=255:DEG:POK.53768,120:POK.53761,N160:POK.53760,N255:POK.53765,N160:POK.53764,N255:F.N=YT TO N191 STEP YD:PP=N255-N:SC=N160+(N99-ABS(N-N99))/10+N2:F.M=N0 TO 79:PS=PP-ABS(SIN(M*9))*20-1:GOS.80:C.15:PL.M,N191-N:DR.M,N191-(N+YH)
30 X=N0:Y=-0.1:Z=3:U=(M-40.5)/(20*1.7):V=(N-96.5)/(80*1.7):W=1/SQR(U*U+V*V+1):U=U*W:V=V*W:I=SGN(U):G=Z
40 E=X-I:F=Y-I:P=U*E+V*F-W*Z:D=P*P-E*E-F*F-Z*Z+1:IF D>0 THEN T=-P-SQR(D):IF T>0 THEN 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):U=U-P*E:V=V-P*F:W=W+P*G:I=-I:GOTO 40
50 IF V<0 THEN P=(Y+2)/V:SQ=INT(X-U*P)+INT(Z-W*P):SQ=SQ-INT(SQ/2)*2:V=-V*(SQ/2+0.3)+0.2:D. 0,24,6,30,36,12,42,18,9,33,3,27,45,21,39,15,0,0,0,9,0,0,0,9,-2,2,0,0,0,1,9,0,0,-1,9,0,0,0,8,8,0,9,8,8,0,9,1,1,8
60 C.15-INT(((14*N16)*SQR(V)+Q((M-INT(M/N4)*N4)+(N-INT(N/N4)*N4)*N4)/3)/N16):PL.M,N191-N:DR. M,N191-(N+YH):NEXT M:NEXT N:YD2=YD2/N2:YD=YD2:YT=YD/N2:YH=YT-N1:IF YD>N1 THEN GOTO 20
70 PN=.5:PP=N255:PS=PP-N1:SC=164:F.I=N0 TO 9:PN=(PN*.89)*(PN>.25)+(PN<=.25)*.5:F.N=0TO63:PP=Q(49+N)*PN:PS=PP-N1:F.J=9 TO N4 STEP -N4:SC=N160+J:GOS.80:N.J:N.N:I=N0:N.I
80 POK.77,N0:POK.F0,PP:POK.F1,PS:POK.C0,SC:POK.C1,SC:S=STICK(N0)-5:H=H+Q(27+S):H=H-INT(H/N16)*16:L=L+Q(N16+S):L=L-INT(L/N16)*N16:NM=Q(38+S):IF (NM<>N8) AND (NM<>GM) THEN GM=NM:GRAPHICS 9+32+GM*N2
90 SE.N4,(ABS(GM-N1))*H,GM*L:RET.:D.143,214,180,240,202,240,227,180,227,240,202,240,180,214,143,151,160,170,151,160,180,202,160,180,202,227,202,160,191,143,170,255
100 D.180,161,143,127,191,161,127,227,202,135,214,135,227,241,227,180,227,152,227,241,227,180,227,152,227,120,227,202,80,152,120,107,"The BASIC 10 Liner Contest is awesome! ;-)"


Program Overview:

Line 10 sets up graphics mode 9 (80x192 pixels, 16 luminosities of 1 hue), numerical constants, read the constants from data statements into Q data array, initialize multiresolution renderer and sound hardware

Line 20 Set degrees trig mode, customize sound configuration (two 16 bit channels clocked at 1.79MHz) Loop over each screen pixel (M,N), determine sound frequency and volume, call update subroutine {disable attract mode, update sounds, handle input to change graphics modes, adjust hue, adjust luminosity}, and draw cursor 

Line 30 Set X,Y,Z viewpoint, calculate 2D unit viewport vector U,V,W where W is the reciprocal length of vector U,V

Line 40 Handle reflections off the two spheres

Line 50 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, data statement containing dither constants and input delta tables for hue, luminosity, and graphics mode

Line 60 Set the color of the pixel based on curved intensity ramp and dithering and plot the pixel, draw the multiresolution pixel, loop through screen pixels, update multiresolution renderer pass and loop if needed

Line 70 Set sound parameters for music, loop forever, handle ascending song pitch, loop over notes in song, loop over attack volumes, set sound settings, call update subroutine, and set outer loop variable to 0 to loop forever

Line 80 Disable attract mode, update sounds, handle input to change graphics modes, adjust hue, adjust luminosity, set graphics mode only if change is needed

Line 90 Set hue or luminosity based on current graphics mode, return from subroutine, and data statement containing first 32 notes of music

Line 100 Data statement containing last 32 notes of music and an unused joke string


Detailed line by line program description:

10 GR.9: Graphics mode 9 

N191=191: Set a variable to frequently used constant 191 - in Atari Basic constants take up 6 bytes of BCD but variables only take 1 byte so tokenized BASIC lines can be longer

DI.Q(N191): Dimension Q constant array to max 99 elements (fewer are used), Q holds constant data read from data statements

F0=53762: Sound constant Frequency 0 address (audio channel 1)

F1=53766: Sound constant Frequency 1 address (audio channel 3)

C0=53763: Sound constant Control 0 address (audio channel 1)

C1=53767: Sound constant Control 1 address (audio channel 3)

N0=0: Initialize constant 0

N1=1: Initialize constant 1

N2=N1+N1: Initialize constant 2 (adding N1 to N1 is smaller than the constant 2)

N4=N2+N2: Initialize constant 4 (adding N2 to N2 is smaller than the constant 4)

N8=N4+N4: Initialize constant 8 (adding N4 to N4 is smaller than the constant 8)

N16=N4*N4: Initialize constant 16 (multiplying N4 and N4 is smaller than the constant 16)

GM=N0: Initialize Graphics Mode variable to 0

H=N0: Initialize Hue H to 0: Black and White in Graphics 9

L=N8: Initialize Luminosity to 8: Mid luminosity in Graphics 11

F.I=N0 TO 112: Loop I over 81 constants to read from data statements and store in Q array

READ R: Read R from data because in Atari BASIC you cannot read directly into an array element

Q(I)=R: Set Q(I) to the read data in R

N.I: next I

YT=N0: Initialize Y Top (YT) to zero for multiresolution renderer

YD=64: Initialize Y Delta (YD) to 64 for multiresolution renderer - this will start with rows 64 pixels tall

YD2=YD*N2: Initialize YD*2

YH=YD-N1: Initialize Y Height used to be 1 less than YD for drawing vertical lines

SO.N0,N0,N0,N0 Start SOUND 0,0,0,0 to initialize Atari BASIC sound system


20 N160=160: Initialize constant 0

N99=99: Initialize constant 99

N255=255: Initialize constant 255

DEG: Set to DEGrees mode instead of RADians

POK.53768,120: Set audio Control to 120 which combines channels 0 and 1 into a 16 bit channel, combines channels 2 and 3 into a 16 bit channel and clocks channel 0 and channel 2 with the 1.79MHz clock giving 2 channels with 16 bit frequency range allowing fantastic raspy square wave bass overtone sounds

POK.53761,N160: Set control of audio channel 0 to be silent tone

POK.53760,N255: Set frequency of audio channel 0 to be 255 

POK.53765,N160: Set control of audio channel 2 to be silent tone

POK.53764,N255: Set frequency of audio channel 2 to be 255 

F.N=YT TO N191 STEP YD: Loop N over 192 scan lines but in multiresolution order starting at Y Top (YT) and jumping Y Delta (YD) rows

PP=N255-N: Audio Primary Pitch (PP) while rendering will be determined by scan line

SC=N160+(N99-ABS(N-N99))/10+N2: Sound Control (SC) will be 160 (pure square wave tone, zero volume) plus a volume set by the scan lines that is no less than 2, no more than 12, and is softest at line 99

F.M=N0 TO 79: Loop M over 80 columns

PS=PP-ABS(SIN(M*9))*20-1: Calculate Pitch based on the Sine function of the horizontal scan line.  This sine function goes in and out of phase during a scan line to give a great interplay of overtones

GOS.80: GOSUB 80 - resets attract mode, updates sound, handles input, graphics mode changes and associated color changes

C.15: COLOR 15 - sets cursor color so user can track ray tracing drawing progress

PL.M,N191-N: PLOT cursor 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.

DR.M,N191-(N+YH) DRAWTO height specified by YH for the multiresolution rendering pass


30 X=N0: Begin ray tracing processing, set X, Y, and Z to (0,-.1,3)

Y=-0.1:

Z=3:

U=(M-40.5)/(20*1.7): Set UV to be normalized screen coordinates ranging from -1 to 1 horizontally and vertically.  Start by subtracting half the pixel width plus half a pixel (.5) to prevent divide by zero, then divide by approximately half the range to account for the Atari Pixel aspect ratio.  The *1.7 is a zoom (fudge) factor to tune the perspective to my liking

V=(N-96.5)/(80*1.7):

W=1/SQR(U*U+V*V+1): W is the reciprocal of the screen space vector, the +1 is to prevent divide by zero

U=U*W: Now scale vector U,V by reciprocal length to make UV a unit vector in the direction from the center of the screen to the pixel 

V=V*W:

I=SGN(U): I is the sign of the horizontal component of the screen space vector (I=-1 if U<0, I=0 if U=0, and I=1 if U>0, this is used to determine direction of ray bounce between spheres

G=Z Initialize G to Z


40 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

IF D>0 THEN T=-P-SQR(D): If D<=0 then exit reflection loop, this filters unwanted reflections on far sides of spheres.  If D<0 then calculate T used to reflect vector

IF T>0 THEN X=X+T*U: If T<=0 then exit reflection loop, vector does not strike spheres and can be used to calculate pixel intensity.  If T>0 then 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 X 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

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 between spheres negate I, bouncing in different direction

GOTO 40 Loop until one of the conditions D>0 or T>0 fails 


50 IF V<0 THEN P=(Y+2)/V: Checkerboard calculation is only for pixels where V is negative below the vertical center of the screen, P is a perspective parameter for the checkerboard

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

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

V=-V*(SQ/2+0.3)+0.2: Adjust the V (vertical 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  

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

0,0,0,9,0,0,0,9,-2,2,0, Intensity modification lookup indexed by STICK(0)-5: Down subtracts 2, up adds 2.  The 9's are unused values acting as delimiters to help humans read the table

0,0,1,9,0,0,-1,9,0,0,0, Hue modification lookup indexed by STICK(0)-5: Left subtracts 1, Right adds 1.  The 9's are unused values acting as delimiters to help humans read the table

8,8,0,9,8,8,0,9,1,1,8 Graphics mode modification lookup indexed by STICK(0)-5: Left and Right return 0, up and down return 1, diagonals return 8.  The 9's are unused values acting as delimiters to help humans read the table


60 C.15-INT(((14*N16)*SQR(V)+Q((M-INT(M/N4)*N4)+(N-INT(N/N4)*N4)*N4)/3)/N16): 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 14*16 is done because there are 15 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 15 to match the dark to light color gradient stored in the color registers

PL.M,N191-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.

DR. M,N191-(N+YH): DRAWTO height specified by YH for the multiresolution rendering pass

NEXT M: Next pixel on the line

NEXT N: Next line

YD2=YD2/N2: Divide Y Delta *2 by two

YD=YD2: Set YD to YD2 (Y Delta *2)

YT=YD/N2: Divide the Y Top (YT) by 2, each pass of the multiresolution renderer has twice as many rows half as tall

YH=YT-N1: Set the Y height (YH) to Y Top minus one, used to DRAWTO to fill the multiresolution pixels

IF YD>N1 THEN GOTO 20 Do passes until Y Delta (YD) is less than 1 (the last pass was 1 pixel tall)


70 PN=.5: At this point the rendering is done, and music is played.  Pitch Note (PN) is set to 1 - this parameter is scaled by (1/(2*(12th root of 2)) to play the notes 2 notes higher each loop for 1 octave

PP=N255: Set Primary Pitch (PP) to lowest note, a reload of 255 or roughly 27.42 Hz or note A2.

PS=PP-N1: Set Secondary Pitch (PS) to be one higher than PP to create awesome square wave chorus overtone sound

SC=164: Set control to 160+4 or square wave, volume 4

F.I=N0 TO 9: Loop I 10 times - this is an infinite loop withuot a GOTO due to resetting I to zero before the NEXT I within the loop

PN=(PN*.89)*(PN>.125)+(PN<=.125)*.5: If Pitch note is <=.125 then set it to .5, otherwise multiply it by .89 (1/(2*(12th root of 2))) 

F.N=0TO63: Loop through 32 note tune

PP=Q(49+N)*PN: Primary Pitch (PP) is looked up, indexed in Q at 49 (where the song starts) + N (note number), and the value is multiplied by Pitch Note that increases two semitones each loop

PS=PP-N1: Pitch Secondary (PS) is always PP-1 to generate the square wave chorus overtone

F.J=9 TO N4 STEP -N4: Volume decay on the instrument (effectively volume 9 followed by 5)

SC=N160+J: Sound Control (SC) is 160 (square wave) + volume J

GOS.80: resets attract mode, updates sound, handles input, graphics mode changes and associated color changes

N.J: Next volume in the instrument attack

N.N: Next note in the sequence

I=N0: Reset I to zero so this loops forever without a GOTO which would need a new line number

N.I Next I (loop forever)


80 POK.77,N0: Main subroutine - Reset Atari Attract mode to prevent color cycling in long running programs

POK.F0,PP: Poke frequency 0 with Pitch Primary PP

POK.F1,PS: Poke frequency 1 with Pitch Secondary PS

POK.C0,SC: Poke sound control 0 with Sound Control SC

POK.C1,SC: Poke sound control 1 with Sound Control SC

S=STICK(N0)-5: Read joystick value and subtract 5.  Subtracting 5 makes the lookup tables smaller

H=H+Q(27+S): Hue is adjusted by lookup table value indexed by S stick value

H=H-INT(H/N16)*16: Hue is clamped to mod 16

L=L+Q(N16+S): Luminosity is adjusted by lookup table value indexed by S stick value

L=L-INT(L/N16)*N16: Luminosity is clamped to mod 16

NM=Q(38+S): Look up new graphics mode NM based on stick value 

IF (NM<>N8) AND (NM<>GM) THEN GM=NM: If the New Mode NM is 8 from the table or the same as the old Graphics Mode GM then we don't need to change the value

GRAPHICS 9+32+GM*N2 Change the graphics value to 9 +GM*2 for 9 or 11 based on GM of 0 or 1 respectively.  The +32 preserves video memory (does not clear screen) when changing graphics modes


90 SE.N4,(ABS(GM-N1))*H,GM*L: SETCOLOR to set the hue or luminance based on Graphics Mode GM. 

RET.: Return from subroutine

D.143,214,180,240,202,240,227,180,227,240,202,240,180,214,143,151,160,170,151,160,180,202,160,180,202,227,202,160,191,143,170,255 The first 32 frequencies of the song


100 D.180,161,143,127,191,161,127,227,202,135,214,135,227,241,227,180,227,152,227,241,227,180,227,152,227,120,227,202,80,152,120,107, The second 32 frequencies of the song "The BASIC 10 Liner Contest is awesome! ;-)" An unused shameless appeal to the judges of the contest (a joke)

Download

Download
Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.atr 90 kB
Download
Line Length Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.lst 2 kB
Download
README Ray Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.txt 28 kB

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 Tracer in Atari BASIC GTIA modes 9 and 11 with multiresolution renderer, sound, music, and interactive color editing.atr" to the emulator

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 LOAD"D1:RTG911CM.BAS" and press enter to load the program

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

8. type "RUN" to run the program

You can optionally press F7 to toggle full speed of the emulator, useful to speed rendering.

Comments

Log in with itch.io to leave a comment.

Mind blowing

Fantastic !

(+1)

Impressive! I was wondering when I saw the screen mode of your earlier entry, if you would attempt one in GTIA modes. Looks great!

(+1)

very good