Ray Tracer GTIA (Atari 8-bit) by D. Scott Williamson
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
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 !
Impressive! I was wondering when I saw the screen mode of your earlier entry, if you would attempt one in GTIA modes. Looks great!
very good