From 3b1439ceddcbfe83cdea575c3eaf0296c355b27b Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Tue, 15 Oct 2024 21:59:53 +0300 Subject: [PATCH] Refactoring code for better readability --- .../3D/Galaxy explorer/galaxyexplorer.bas | 689 +++++++++--------- 1 file changed, 345 insertions(+), 344 deletions(-) diff --git a/Graphics/3D/Galaxy explorer/galaxyexplorer.bas b/Graphics/3D/Galaxy explorer/galaxyexplorer.bas index 0a58d6d..6074a44 100755 --- a/Graphics/3D/Galaxy explorer/galaxyexplorer.bas +++ b/Graphics/3D/Galaxy explorer/galaxyexplorer.bas @@ -1,344 +1,345 @@ -' Program to render 3D pointcloud galaxy. -' By Svjatoslav Agejenko. -' Email: svjatoslav@svjatoslav.eu -' Homepage: http://www.svjatoslav.eu -' -' Changelog: -' 2003, Initial version. -' 2024, Improved program readability using AI. -' -' User can navigate through the galaxy using mouse or keyboard controls. -' To use mouse controls, program requires special TSR (terminate and stay resident) -' program to be loaded. The TSR makes mouse input available to the QBasic program. -' -' Navigation controls: -' - Press left and right mouse buttons simultaneously to move in X and Z axis. -' - Press right mouse button to move in Y axis. -' - Use keyboard keys 'a', 'd', 'w', 's' to move in X and Z axis. -' - Press 'q' to quit the program. - -DECLARE SUB temp () -DECLARE SUB mkGalaxy (x!, y!, z!) -DECLARE SUB rndInit () -DECLARE FUNCTION rn! () -DECLARE SUB disp () -DECLARE SUB starText () -DECLARE SUB control () -DECLARE SUB putByte (addr!, dat!) -DECLARE SUB putWord (addr!, dat!) -DECLARE FUNCTION getWord! (addr!) -DECLARE FUNCTION getByte! (addr!) -DECLARE SUB start () -DECLARE SUB animate () - -DIM SHARED angle1, angle2, angle3 - -DIM SHARED time - -DIM SHARED externalSegment, externalAddress - -DIM SHARED myX, myY, myZ -DIM SHARED speedX, speedY, speedZ -DIM SHARED buttonLeft, buttonRight -DIM SHARED maxMove - -DIM SHARED zoom -DIM SHARED randomValue(0 TO 10000) -DIM SHARED randomPointer - -DIM SHARED pointX(1 TO 12000) -DIM SHARED pointY(1 TO 12000) -DIM SHARED pointZ(1 TO 12000) -DIM SHARED pointColor(1 TO 12000) -DIM SHARED numPoints - -DIM SHARED temporaryRegister(0 TO 10) - -newLine = 0 -newPage = 0 - -start - -currentX = 0 -currentY = 0 -currentZ = 0 - -numPoints = 0 -mkGalaxy 0, 0, 0 -1 - -variableAngle = INT(RND * 3) - -SELECT CASE variableAngle -CASE 0 - currentX = RND * 500 - 250 -CASE 1 - currentY = RND * 100 - 50 -CASE 2 - currentZ = RND * 500 - 250 -END SELECT - -control -disp - -PCOPY 0, 1 -CLS -GOTO 1 - -SUB control - -IF getByte(8) <> 0 THEN - putByte 8, 0 - xPosition = getWord(2) - putWord 2, 0 - yPosition = getWord(4) - putWord 4, 0 - button = getWord(6) - putWord 6, 0 - buttonLeft = 0 - buttonRight = 0 - IF button = 1 THEN buttonLeft = 1 - IF button = 2 THEN buttonRight = 1 - IF button = 3 THEN buttonLeft = 1: buttonRight = 1 - - ' Handle mouse movements - IF buttonRight = 1 THEN - IF buttonLeft = 1 THEN - speedX = speedX + SIN(angle1) * yPosition / 4 - speedZ = speedZ - COS(angle1) * yPosition / 4 - GOTO 3 - END IF - speedY = speedY + yPosition / 4 - 3 - yPosition = 0 - END IF - -END IF - -' Limit the position values to prevent overflow -IF xPosition < -maxMove THEN xPosition = -maxMove -IF xPosition > maxMove THEN xPosition = maxMove -angle1 = angle1 - xPosition / 150 - -IF yPosition < -maxMove THEN yPosition = -maxMove -IF yPosition > maxMove THEN yPosition = maxMove -angle2 = angle2 - yPosition / 150 - -' Check for keyboard input -keyInput$ = INKEY$ - -IF keyInput$ = "a" THEN speedX = speedX - COS(angle1): speedZ = speedZ - SIN(angle1) -IF keyInput$ = "d" THEN speedX = speedX + COS(angle1): speedZ = speedZ + SIN(angle1) -IF keyInput$ = "w" THEN speedX = speedX - SIN(angle1): speedZ = speedZ + COS(angle1) -IF keyInput$ = "s" THEN speedX = speedX + SIN(angle1): speedZ = speedZ - COS(angle1) -IF keyInput$ = "q" THEN SYSTEM - -' Decelerate the movement -speedX = speedX / 1.1 -speedY = speedY / 1.1 -speedZ = speedZ / 1.1 - -myX = myX + speedX -myZ = myZ + speedZ -myY = myY + speedY - -END SUB - -SUB disp - -sinAngle1 = SIN(angle1) -cosAngle1 = COS(angle1) -sinAngle2 = SIN(angle2) -cosAngle2 = COS(angle2) - -' Loop through all points to calculate and display their positions -FOR pointIndex = 1 TO numPoints - - xCoordinate = pointX(pointIndex) - myX - yCoordinate = pointY(pointIndex) - myY - zCoordinate = pointZ(pointIndex) - myZ - - ' Rotate the points - rotatedX = xCoordinate * cosAngle1 + zCoordinate * sinAngle1 - rotatedZ = zCoordinate * cosAngle1 - xCoordinate * sinAngle1 - - rotatedY = yCoordinate * cosAngle2 + rotatedZ * sinAngle2 - finalZ = rotatedZ * cosAngle2 - yCoordinate * sinAngle2 - - ' Draw points that are sufficiently close - IF finalZ > 3 THEN - screenX = rotatedX / finalZ * 130 + 160 - screenY = rotatedY / finalZ * 130 + 100 - PSET (screenX, screenY), pointColor(pointIndex) - END IF - -NEXT pointIndex -END SUB - -FUNCTION getByte (address) -getByte = PEEK(externalAddress + address) -END FUNCTION - -FUNCTION getWord (address) -firstByte = PEEK(externalAddress + address) -secondByte = PEEK(externalAddress + address + 1) - -combinedHex$ = HEX$(firstByte) -IF LEN(combinedHex$) = 1 THEN combinedHex$ = "0" + combinedHex$ -IF LEN(combinedHex$) = 0 THEN combinedHex$ = "00" - -combinedValue = VAL("&H" + HEX$(secondByte) + combinedHex$) - -getWord = combinedValue -END FUNCTION - -SUB mkGalaxy (localX, localY, localZ) - -randomAngle1 = rn * 10 -randomAngle2 = rn * 10 - -galaxySin1 = SIN(randomAngle1) -galaxyCos1 = COS(randomAngle1) -galaxySin2 = SIN(randomAngle2) -galaxyCos2 = COS(randomAngle2) - -randomPointer = 0 -size = 100 -piValue = 3.14 -spiralBarsMultiplier = 3 - -FOR pointIndex = 1 TO 10000 - - randomVariable = rn * 10 - distanceFromCenter = randomVariable * randomVariable / 30 - - spiralOffset = rn * (11.5 - randomVariable) / 3 - halfSpiralOffset = spiralOffset / 2 - - angleExponent = rn * (distanceFromCenter / 2) / spiralBarsMultiplier * 2 - spiralBarAngle = 2 * piValue / spiralBarsMultiplier * INT(rn * spiralBarsMultiplier) - - xCoordinate = (SIN(randomVariable - spiralBarAngle + angleExponent) * distanceFromCenter + rn * spiralOffset - halfSpiralOffset) * size - zCoordinate = (COS(randomVariable - spiralBarAngle + angleExponent) * distanceFromCenter + rn * spiralOffset - halfSpiralOffset) * size - yCoordinate = (rn * spiralOffset - halfSpiralOffset) * size - - rotatedX = xCoordinate * galaxyCos1 + zCoordinate * galaxySin1 - rotatedZ = zCoordinate * galaxyCos1 - xCoordinate * galaxySin1 - - rotatedY = yCoordinate * galaxyCos2 + rotatedZ * galaxySin2 - finalZ = rotatedZ * galaxyCos2 - yCoordinate * galaxySin2 - - numPoints = numPoints + 1 - - pointX(numPoints) = rotatedX + localX - pointY(numPoints) = rotatedY + localY - pointZ(numPoints) = finalZ + localZ - pointColor(numPoints) = INT(RND * 15) + 1 -NEXT pointIndex - -END SUB - -SUB mouseDemo - -currentX = 150 -currentY = 100 -maxMove = 50 -100 -frameCounter = frameCounter + 1 - -LOCATE 1, 1 -PRINT currentX, currentY -PRINT frameCounter - -CIRCLE (currentX, currentY), 10, 0 -xPosition = getWord(2) -putWord 2, 0 -yPosition = getWord(4) -putWord 4, 0 - -IF xPosition < -maxMove THEN xPosition = -maxMove -IF xPosition > maxMove THEN xPosition = maxMove -currentX = currentX + xPosition - -IF yPosition < -maxMove THEN yPosition = -maxMove -IF yPosition > maxMove THEN yPosition = maxMove -currentY = currentY + yPosition - -CIRCLE (currentX, currentY), 10, 10 - -SOUND 0, .05 -GOTO 100 - -END SUB - -SUB putByte (address, dataByte) - -POKE (externalAddress + address), dataByte -END SUB - -SUB putWord (address, dataWord) - -hexValue$ = HEX$(dataWord) - -2 -IF LEN(hexValue$) < 4 THEN hexValue$ = "0" + hexValue$: GOTO 2 - -firstByteValue = VAL("&H" + LEFT$(hexValue$, 2)) -secondByteValue = VAL("&H" + RIGHT$(hexValue$, 2)) - -POKE (externalAddress + address), secondByteValue -POKE (externalAddress + address + 1), firstByteValue - -END SUB - -FUNCTION rn - -randomPointer = randomPointer + 1 -IF randomPointer > 10000 THEN randomPointer = 0 -rn = randomValue(randomPointer) - -END FUNCTION - -SUB rndInit - -FOR index = 0 TO 10000 - randomValue(index) = RND -NEXT index - -randomPointer = 0 -END SUB - -SUB start - -starText - -SCREEN 7, , , 1 - -maxMove = 50 -rndInit - -END SUB - -SUB starText - -DEF SEG = 0 ' read first from interrupt table - -externalSegment = PEEK(&H79 * 4 + 3) * 256 -externalSegment = externalSegment + PEEK(&H79 * 4 + 2) - -PRINT "Segment is: " + HEX$(externalSegment) - -externalAddress = PEEK(&H79 * 4 + 1) * 256 -externalAddress = externalAddress + PEEK(&H79 * 4 + 0) - -PRINT "relative address is:"; externalAddress - -DEF SEG = externalSegment - -IF getWord(0) <> 1983 THEN - PRINT "FATAL ERROR: you must load" - PRINT "QBasic extension TSR first!" - SYSTEM -END IF - -END SUB \ No newline at end of file +' Program to render a 3D point cloud galaxy. +' By Svjatoslav Agejenko. +' Email: svjatoslav@svjatoslav.eu +' Homepage: http://www.svjatoslav.eu + +' Changelog: +' 2003, Initial version. +' 2024, Improved program readability using AI. + +' User can navigate through the galaxy using mouse or keyboard controls. +' To use mouse controls, program requires a special TSR (terminate and stay resident) +' program to be loaded. The TSR makes mouse input available to the QBasic program. + +' Navigation controls: +' - Press left and right mouse buttons simultaneously to move in X and Z axis. +' - Press right mouse button to move in Y axis. +' - Use keyboard keys 'a', 'd', 'w', 's' to move in X and Z axis. +' - Press 'q' to quit the program. + +DECLARE SUB temp () +DECLARE SUB mkGalaxy (x!, y!, z!) +DECLARE SUB rndInit () +DECLARE FUNCTION rn! () +DECLARE SUB disp () +DECLARE SUB control () +DECLARE SUB putByte (addr!, dat!) +DECLARE SUB putWord (addr!, dat!) +DECLARE FUNCTION getWord! (addr!) +DECLARE FUNCTION getByte! (addr!) +DECLARE SUB start () +DECLARE SUB animate () + +DIM SHARED angle1, angle2, angle3 + +DIM SHARED time + +DIM SHARED externalSegment, externalAddress + +' Variables for the camera position and movement +DIM SHARED myX, myY, myZ +DIM SHARED speedX, speedY, speedZ +DIM SHARED buttonLeft, buttonRight +DIM SHARED maxMove + +' Variable for zoom level +DIM SHARED zoom + +' Array to store random values +DIM SHARED randomValue(0 TO 10000) +DIM SHARED randomPointer + +' Arrays to store point coordinates and colors. These points make up galaxy. +DIM SHARED pointX(1 TO 12000) +DIM SHARED pointY(1 TO 12000) +DIM SHARED pointZ(1 TO 12000) +DIM SHARED pointColor(1 TO 12000) +DIM SHARED numPoints + +' Temporary register array +DIM SHARED temporaryRegister(0 TO 10) + +newLine = 0 +newPage = 0 + +start + +currentX = 0 +currentY = 0 +currentZ = 0 + +numPoints = 0 +mkGalaxy 0, 0, 0 +1 + +' Generate a random angle for initial camera position +variableAngle = INT(RND * 3) + +SELECT CASE variableAngle +CASE 0 + currentX = RND * 500 - 250 +CASE 1 + currentY = RND * 100 - 50 +CASE 2 + currentZ = RND * 500 - 250 +END SELECT + +control +disp + +PCOPY 0, 1 +CLS +GOTO 1 + +SUB control + +' Check for mouse input +IF getByte(8) <> 0 THEN + putByte 8, 0 + xPosition = getWord(2) + putWord 2, 0 + yPosition = getWord(4) + putWord 4, 0 + button = getWord(6) + putWord 6, 0 + + ' Reset mouse buttons + buttonLeft = 0 + buttonRight = 0 + + ' Handle mouse button states + IF button = 1 THEN buttonLeft = 1 + IF button = 2 THEN buttonRight = 1 + IF button = 3 THEN buttonLeft = 1: buttonRight = 1 + + ' Handle mouse movements + IF buttonRight = 1 THEN + IF buttonLeft = 1 THEN + speedX = speedX + SIN(angle1) * yPosition / 4 + speedZ = speedZ - COS(angle1) * yPosition / 4 + GOTO 3 + END IF + speedY = speedY + yPosition / 4 + 3 + yPosition = 0 + END IF + +END IF + +' Limit the position values to prevent overflow +IF xPosition < -maxMove THEN xPosition = -maxMove +IF xPosition > maxMove THEN xPosition = maxMove +angle1 = angle1 - xPosition / 150 + +IF yPosition < -maxMove THEN yPosition = -maxMove +IF yPosition > maxMove THEN yPosition = maxMove +angle2 = angle2 - yPosition / 150 + +' Check for keyboard input +keyInput$ = INKEY$ + +' Handle keyboard controls +IF keyInput$ = "a" THEN speedX = speedX - COS(angle1): speedZ = speedZ - SIN(angle1) +IF keyInput$ = "d" THEN speedX = speedX + COS(angle1): speedZ = speedZ + SIN(angle1) +IF keyInput$ = "w" THEN speedX = speedX - SIN(angle1): speedZ = speedZ + COS(angle1) +IF keyInput$ = "s" THEN speedX = speedX + SIN(angle1): speedZ = speedZ - COS(angle1) +IF keyInput$ = "q" THEN SYSTEM + +' Decelerate the movement +speedX = speedX / 1.1 +speedY = speedY / 1.1 +speedZ = speedZ / 1.1 + +myX = myX + speedX +myZ = myZ + speedZ +myY = myY + speedY + +END SUB + +SUB disp + +' Calculate sine and cosine values for rotation angles +sinAngle1 = SIN(angle1) +cosAngle1 = COS(angle1) +sinAngle2 = SIN(angle2) +cosAngle2 = COS(angle2) + +' Loop through all points to calculate and display their positions +FOR pointIndex = 1 TO numPoints + + ' Calculate the distance from the camera + xCoordinate = pointX(pointIndex) - myX + yCoordinate = pointY(pointIndex) - myY + zCoordinate = pointZ(pointIndex) - myZ + + ' Rotate the points + rotatedX = xCoordinate * cosAngle1 + zCoordinate * sinAngle1 + rotatedZ = zCoordinate * cosAngle1 - xCoordinate * sinAngle1 + + rotatedY = yCoordinate * cosAngle2 + rotatedZ * sinAngle2 + finalZ = rotatedZ * cosAngle2 - yCoordinate * sinAngle2 + + ' Draw points that are sufficiently close + IF finalZ > 3 THEN + screenX = rotatedX / finalZ * 130 + 160 + screenY = rotatedY / finalZ * 130 + 100 + PSET (screenX, screenY), pointColor(pointIndex) + END IF + +NEXT pointIndex +END SUB + +FUNCTION getByte (address) +getByte = PEEK(externalAddress + address) +END FUNCTION + +FUNCTION getWord (address) +firstByte = PEEK(externalAddress + address) +secondByte = PEEK(externalAddress + address + 1) + +' Combine the two bytes into a single value +combinedHex$ = HEX$(firstByte) +IF LEN(combinedHex$) = 1 THEN combinedHex$ = "0" + combinedHex$ +IF LEN(combinedHex$) = 0 THEN combinedHex$ = "00" + +combinedValue = VAL("&H" + HEX$(secondByte) + combinedHex$) + +getWord = combinedValue +END FUNCTION + +SUB mkGalaxy (localX, localY, localZ) + +' Generate random angles for stars within galaxy +randomAngle1 = rn * 10 +randomAngle2 = rn * 10 + +galaxySin1 = SIN(randomAngle1) +galaxyCos1 = COS(randomAngle1) +galaxySin2 = SIN(randomAngle2) +galaxyCos2 = COS(randomAngle2) + +randomPointer = 0 +size = 100 +piValue = 3.14 +spiralBarsMultiplier = 3 + +FOR pointIndex = 1 TO 10000 + + ' Generate a random star distance from the center + randomVariable = rn * 10 + distanceFromCenter = randomVariable * randomVariable / 30 + + ' Calculate spiral offset and half of it + spiralOffset = rn * (11.5 - randomVariable) / 3 + halfSpiralOffset = spiralOffset / 2 + + ' Generate angle exponent and spiral bar angle + angleExponent = rn * (distanceFromCenter / 2) / spiralBarsMultiplier * 2 + spiralBarAngle = 2 * piValue / spiralBarsMultiplier * INT(rn * spiralBarsMultiplier) + + ' Calculate x, z, and y coordinates + xCoordinate = (SIN(randomVariable - spiralBarAngle + angleExponent) * distanceFromCenter + rn * spiralOffset - halfSpiralOffset) * size + zCoordinate = (COS(randomVariable - spiralBarAngle + angleExponent) * distanceFromCenter + rn * spiralOffset - halfSpiralOffset) * size + yCoordinate = (rn * spiralOffset - halfSpiralOffset) * size + + ' Rotate the coordinates + rotatedX = xCoordinate * galaxyCos1 + zCoordinate * galaxySin1 + rotatedZ = zCoordinate * galaxyCos1 - xCoordinate * galaxySin1 + + rotatedY = yCoordinate * galaxyCos2 + rotatedZ * galaxySin2 + finalZ = rotatedZ * galaxyCos2 - yCoordinate * galaxySin2 + + ' Store the point in arrays + numPoints = numPoints + 1 + + pointX(numPoints) = rotatedX + localX + pointY(numPoints) = rotatedY + localY + pointZ(numPoints) = finalZ + localZ + pointColor(numPoints) = INT(RND * 15) + 1 +NEXT pointIndex + +END SUB + +SUB putByte (address, dataByte) + +POKE (externalAddress + address), dataByte +END SUB + +SUB putWord (address, dataWord) + +' Convert the word to a hexadecimal string +hexValue$ = HEX$(dataWord) + +' Ensure the string has at least 4 characters +2 +IF LEN(hexValue$) < 4 THEN + hexValue$ = "0" + hexValue$: GOTO 2 +END IF + +' Extract the first and second bytes +firstByteValue = VAL("&H" + LEFT$(hexValue$, 2)) +secondByteValue = VAL("&H" + RIGHT$(hexValue$, 2)) + +' Store the bytes in memory +POKE (externalAddress + address), secondByteValue +POKE (externalAddress + address + 1), firstByteValue + +END SUB + +FUNCTION rn + +' Increment the random pointer and get a new random value +randomPointer = randomPointer + 1 +IF randomPointer > 10000 THEN randomPointer = 0 +rn = randomValue(randomPointer) + +END FUNCTION + +SUB rndInit + +' Initialize the array of random values +FOR index = 0 TO 10000 + randomValue(index) = RND +NEXT index + +randomPointer = 0 +END SUB + +SUB start + +starText + +' Set up graphics mode +SCREEN 7, , , 1 + +' Initialize maximum movement and random values +maxMove = 50 +rndInit + +END SUB + +SUB starText + +' Read the segment and address from the interrupt table +DEF SEG = 0 ' read first from interrupt table + +externalSegment = PEEK(&H79 * 4 + 3) * 256 +externalSegment = externalSegment + PEEK(&H79 * 4 + 2) + +PRINT "Segment is: " + HEX$(externalSegment) + +externalAddress = PEEK(&H79 * 4 + 1) * 256 +externalAddress = externalAddress + PEEK(&H79 * 4 + 0) + +PRINT "relative address is:"; externalAddress + +' Read the word at the specified address +DEF SEG = externalSegment + +IF getWord(0) <> 1983 THEN + PRINT "FATAL ERROR: you must load" + PRINT "QBasic extension TSR first!" + SYSTEM +END IF + +END SUB -- 2.20.1