Hated Moron wrote: ↑Mon 09 Oct 2023, 00:05
As it turns out this is not what the OP actually wanted at all, but may still be of some interest. It's pretty much generic BBC BASIC code and will run without any modification in
BBC BASIC for Windows,
BBC BASIC for SDL 2.0 and
Matrix Brandy.
This has been brought up again over at the Discussion Group, and since it is such a good example of what can be achieved with 'generic' BBC BASIC code (not requiring BB4W or BBCSDL-specific extensions) I thought it might be helpful for me to annotate it:
Code: Select all
MODE 8
ORIGIN 640,512
GCOL 15
OFF
This is standard 'boilerplate' initialisation: setting a 640-pixel-wide window, moving the graphics origin to the centre, setting the draw colour to white and turning off the text caret (flashing cursor).
MODE 8 means different things in different systems: in BB4W and BBCSDL it's a 16-logical-colour mode and in Matrix Brandy (and Sophie's ARM BASIC) it's a 4-colour mode, but in both the highest colour index (15 or 3 respectively) is peak white. GCOL 15 has the desired effect in both cases (because the colour number is ANDed with the appropriate mask).
Code: Select all
NSTARS = 500
Radius = 300
Scale = 1000
Camera = 1000
Initialise the global variables. Note that the naming convention being followed here is that all-caps signifies a constant.
Code: Select all
DIM s(2, NSTARS-1), q(2, NSTARS-1)
DIM a(2,2), b(2,2), c(2,2), r(2,2)
Declare the global arrays. s() and q() both contain the Cartesian (x,y,z) coordinates of each of the 'stars' (before and after rotation), with the first subscript being 0 for x, 1 for y, 2 for z, and the second subscript being the star number (0 to NSTARS-1). a(), b(), c() and r() are 3x3 rotation matrices.
Code: Select all
FOR I% = 0 TO NSTARS-1
lon = 2 * PI * RND(1)
lat = ASN(2 * RND(1) - 1)
s(0, I%) = Radius * COS(lon) * COS(lat) : REM x
s(2, I%) = Radius * SIN(lon) * COS(lat) : REM z
s(1, I%) = Radius * SIN(lat) : REM y
NEXT
Initialise the stars to random positions over the surface of a sphere. I used Google to find the formula for a uniform distribution, which is expressed in polar coordinates (latitude and longitude); these are then converted to the required Cartesian coordinates.
This starts the main loop. The *REFRESH OFF is not strictly necessary (and isn't accepted by ARM BASIC) but makes the display less flickery in BB4W, BBCSDL and Matrix Brandy.
Code: Select all
CASE INKEY(0) OF
WHEN 138,142: Camera += 20
WHEN 139,143: Camera -= 20
ENDCASE
User controls. Pressing the up-arrow key, or rotating the mouse-wheel upwards, moves the 'camera' (viewpoint) in the negative Z-direction (into the screen); the down-arrow key, or rotating the mouse wheel downwards, moves the camera in the positive Z-direction (out of the screen). In Matrix Brandy and ARM BASIC 5 a
*FX 4,1 must be issued for the up and down arrow keys to generate these codes.
Code: Select all
a = 0 : REM pitch
b = TIME/500 : REM yaw
c = 0 : REM roll
Animate the sphere, in this case it simply rotates about the vertical axis at a fixed speed. Pitch is rotation around the x-axis, yaw is rotation around the y-axis and roll is rotation around the z-axis; in this case they take place in that order.
Code: Select all
a() = 1, 0, 0, 0, COS(a), -SIN(a), 0, SIN(a), COS(a)
b() = COS(b), 0, SIN(b), 0, 1, 0, -SIN(b), 0, COS(b)
c() = COS(c), -SIN(c), 0, SIN(c), COS(c), 0, 0, 0, 1
Initialise the rotation matrices, these correspond to the standard equations which can be found in any 3D geometry reference.
Code: Select all
r() = b() . a()
r() = c() . r()
q() = r() . s()
Combine the individual rotations (pitch, yaw, roll) into a single composite rotation matrix r() using matrix multiplication (dot product). Then rotate all the stars by multiplying their cartesian coordinates s() by this rotation matrix to give a new set of (rotated) coordinates q().
Start the display of the 'stars' by clearing the screen (CLS is faster than CLG if the text viewport and the graphics viewport are the same, which they are by default) and looping through all the indices.
Code: Select all
z = (Camera - q(2,I%)) / Scale
IF z>0 THEN
X% = q(0,I%) / z
Y% = q(1,I%) / z
Convert the stars' 3D coordinates (x,y,z) to their 2D screen coordinates (X%,Y%) using the standard
Perspective Projection. Check for the camera's z-coordinate and the star's z-coordinate being the same, because if they are a division-by-zero results; also check whether the star is 'behind' the camera and if so don't draw it.
Plot the stars as individual pixels, which is most easily achieved by drawing a zero-length line. Using PLOT 69,X%,Y% would result in them being drawn as 'points' which, depending on the screen mode, may consist of more than one pixel.
Complete the drawing loop and repeat forever (until ESCape is pressed). The WAIT 1 prevents excessive CPU usage in BB4W (otherwise it will loop as fast as possible using 100% CPU). In ARM BASIC 5 the *REFRESH should be omitted and WAIT 1 changed to WAIT.