From d5b33002056e57e53c4829e4f020228d0e346c6d Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Thu, 27 Feb 2025 22:29:14 +0200 Subject: [PATCH] Improve code readability --- Graphics/Presentations/AI/AI demo.bas | 1900 +++++++++++++------------ 1 file changed, 1001 insertions(+), 899 deletions(-) diff --git a/Graphics/Presentations/AI/AI demo.bas b/Graphics/Presentations/AI/AI demo.bas index 16aa99c..10b1216 100644 --- a/Graphics/Presentations/AI/AI demo.bas +++ b/Graphics/Presentations/AI/AI demo.bas @@ -6,38 +6,46 @@ DECLARE SUB Scene3 () DECLARE SUB Scene4 () DECLARE SUB Scene5 () DECLARE SUB Scene7 () -DECLARE SUB Initialize () ' Renamed from "start" for clarity -DECLARE SUB sc1 () -DECLARE SUB sc2 () -DECLARE SUB sc3 () -DECLARE SUB sc4 () -DECLARE SUB sc5 () -DECLARE SUB sc6 () -DECLARE SUB sc7 () -DECLARE SUB sc8 () -DECLARE SUB sc10 () -DECLARE SUB sc9 () -DECLARE SUB DrawRoundedBox (x1!, y1!, x2!, y2!) ' Renamed from "box" for clarity -DECLARE SUB ComputeShadeValue (tx1!, ty1!, tz1!, tx2!, ty2!, tz2!, tx3!, ty3!, tz3!, c!) ' Renamed from "calc" -DECLARE SUB GetAngle (x1!, y1!, x2!, y2!, N!) -DECLARE SUB RotatePoint (zx!, zy!, x1!, y1!, N!) -DECLARE SUB FillPolygon (xCoord1!, yCoord1!, xCoord2!, yCoord2!, xCoord3!, yCoord3!, colorVal!) +DECLARE SUB Initialize () +DECLARE SUB ShowScenePart1 () +DECLARE SUB ShowScenePart2 () +DECLARE SUB ShowScenePart3 () +DECLARE SUB ShowScenePart4 () +DECLARE SUB ShowScenePart5 () +DECLARE SUB ShowScenePart6 () +DECLARE SUB ShowScenePart7 () +DECLARE SUB ShowScenePart8 () +DECLARE SUB ShowScenePart10 () +DECLARE SUB ShowScenePart9 () +DECLARE SUB DrawRoundedBox (xOne!, yOne!, xTwo!, yTwo!) +DECLARE SUB ComputeShadeValue (txOne!, tyOne!, tzOne!, txTwo!, tyTwo!, tzTwo!, txThree!, tyThree!, tzThree!, colorResult!) +DECLARE SUB GetAngle (xOne!, yOne!, xTwo!, yTwo!, angleOutput!) +DECLARE SUB RotatePoint (centerX!, centerY!, pointX!, pointY!, angleRadians!) +DECLARE SUB FillPolygon (xCoordOne!, yCoordOne!, xCoordTwo!, yCoordTwo!, xCoordThree!, yCoordThree!, colorValue!) DECLARE SUB InitializeFont () DECLARE SUB WaitForInput () DECLARE SUB MakeBackground () -DECLARE SUB SetPalette (r!, g!, b!, c!) -DECLARE SUB PrintText (x!, y!, s!, c!, a$) +DECLARE SUB SetPalette (red!, green!, blue!, colorIndex!) +DECLARE SUB PrintText (posX!, posY!, scale!, colorValue!, textString$) -' AI presentation -' made by Svjatoslav Agejenko -' in 2002 -' homepage: svjatoslav.eu -' email: svjatoslav@svjatoslav.eu +' Presentation about artificial intelligence. +' +' By Svjatoslav Agejenko. +' Email: svjatoslav@svjatoslav.eu +' Homepage: http://www.svjatoslav.eu +' +' Changelog: +' 2002, Initial version +' 2025, Improved program readability using AI -DIM SHARED pii -DIM SHARED pi -DIM SHARED angl1, angl2 -DIM SHARED font(0 TO 7, 0 TO 7, 32 TO 150) + +DIM SHARED globalPiI +DIM SHARED globalPi +DIM SHARED globalAngleOne +DIM SHARED globalAngleTwo + +' Holds the captured font bitmap +DIM SHARED fontData(0 TO 7, 0 TO 7, 32 TO 150) Initialize @@ -50,204 +58,222 @@ Scene7 Scene8 Scene9 -SUB ComputeShadeValue (tx1, ty1, tz1, tx2, ty2, tz2, tx3, ty3, tz3, c) -' Computes a value (c) based on the positions of three 3D points. -' It rotates these points around multiple axes, then calculates -' an offset 'a' used to determine a final computed result in 'c'. - x1 = tx1 - y1 = ty1 - z1 = tz1 +SUB ComputeShadeValue (txOne, tyOne, tzOne, txTwo, tyTwo, tzTwo, txThree, tyThree, tzThree, colorResult) +' +' Computes a "shade" or brightness value stored in 'colorResult' by: +' 1) Assigning local copies of the point coordinates. +' 2) Rotating them around multiple axes via GetAngle and RotatePoint. +' 3) Computing a distance 'distCalc' to adjust brightness. +' + xLocalOne = txOne + yLocalOne = tyOne + zLocalOne = tzOne - x2 = tx2 - y2 = ty2 - z2 = tz2 + xLocalTwo = txTwo + yLocalTwo = tyTwo + zLocalTwo = tzTwo - x3 = tx3 - y3 = ty3 - z3 = tz3 + xLocalThree = txThree + yLocalThree = tyThree + zLocalThree = tzThree ' First rotation - GetAngle x1, y1, x2, y2, n1 - RotatePoint x1, y1, x2, y2, -n1 - RotatePoint x1, y1, x3, y3, -n1 + GetAngle xLocalOne, yLocalOne, xLocalTwo, yLocalTwo, angleTemp1 + RotatePoint xLocalOne, yLocalOne, xLocalTwo, yLocalTwo, -angleTemp1 + RotatePoint xLocalOne, yLocalOne, xLocalThree, yLocalThree, -angleTemp1 ' Second rotation - GetAngle y1, z1, y2, z2, n2 - n2 = n2 + pi / 2 - RotatePoint y1, z1, y2, z2, -n2 - RotatePoint y1, z1, y3, z3, -n2 + GetAngle yLocalOne, zLocalOne, yLocalTwo, zLocalTwo, angleTemp2 + angleTemp2 = angleTemp2 + globalPi / 2 + RotatePoint yLocalOne, zLocalOne, yLocalTwo, zLocalTwo, -angleTemp2 + RotatePoint yLocalOne, zLocalOne, yLocalThree, zLocalThree, -angleTemp2 ' Third rotation - GetAngle x1, z1, x3, z3, n3 - n3 = n3 + pi / 2 - RotatePoint x1, z1, x2, z2, -n3 - RotatePoint x1, z1, x3, z3, -n3 - - x4 = x1 - y4 = y1 - z4 = z1 + 30 - - RotatePoint x1, z1, x4, z4, n3 - RotatePoint y1, z1, y4, z4, n2 - RotatePoint x1, y1, x4, y4, n1 - - ' The distance 'a' is used to calculate 'c' - x1 = tx1 + 20 - y1 = ty1 + 10 - a = SQR((x1 - x4) ^ 2 + (y1 - y4) ^ 2) - c = 49 - a - IF c < 0 THEN c = 0 + GetAngle xLocalOne, zLocalOne, xLocalThree, zLocalThree, angleTemp3 + angleTemp3 = angleTemp3 + globalPi / 2 + RotatePoint xLocalOne, zLocalOne, xLocalTwo, zLocalTwo, -angleTemp3 + RotatePoint xLocalOne, zLocalOne, xLocalThree, zLocalThree, -angleTemp3 + + xOffset = xLocalOne + yOffset = yLocalOne + zOffset = zLocalOne + 30 + + RotatePoint xLocalOne, zLocalOne, xOffset, zOffset, angleTemp3 + RotatePoint yLocalOne, zLocalOne, yOffset, zOffset, angleTemp2 + RotatePoint xLocalOne, yLocalOne, xOffset, yOffset, angleTemp1 + + ' The distance 'distCalc' is used to compute 'colorResult' + xLocalOne = txOne + 20 + yLocalOne = tyOne + 10 + distCalc = SQR((xLocalOne - xOffset) ^ 2 + (yLocalOne - yOffset) ^ 2) + colorResult = 49 - distCalc + IF colorResult < 0 THEN colorResult = 0 END SUB -SUB DrawRoundedBox (x1, y1, x2, y2) -' Draws a soft-edged rectangular box by blending pixel colors around the edges. -' The edges fade gently to create a smoothed border. - FOR y = y1 TO y2 - s = 10 - IF y - y1 <= 10 THEN - s = (SQR((20 - (y - y1)) * (y - y1))) ' fade calculation +SUB DrawRoundedBox (xOne, yOne, xTwo, yTwo) +' +' Draws a soft-edged rectangular box by fading pixel colors around its edges. +' This creates a gentle "rounded" or "blurred" border appearance. +' + FOR yLoop = yOne TO yTwo + fadeSize = 10 + ' Fade in the upper boundary region + IF yLoop - yOne <= 10 THEN + fadeSize = (SQR((20 - (yLoop - yOne)) * (yLoop - yOne))) END IF - IF y2 - y <= 10 THEN - s = (SQR((20 - (y2 - y)) * (y2 - y))) ' Similar fade near the lower boundary + ' Fade in the lower boundary region + IF yTwo - yLoop <= 10 THEN + fadeSize = (SQR((20 - (yTwo - yLoop)) * (yTwo - yLoop))) END IF - FOR x = x1 - s TO x2 + s - c = POINT(x, y) - IF c <= 127 THEN - c = c + 127 - IF c > 245 THEN c = 245 - PSET (x, y), c + FOR xLoop = xOne - fadeSize TO xTwo + fadeSize + colorVal = POINT(xLoop, yLoop) + IF colorVal <= 127 THEN + colorVal = colorVal + 127 + IF colorVal > 245 THEN colorVal = 245 + PSET (xLoop, yLoop), colorVal END IF - NEXT x - NEXT y + NEXT xLoop + NEXT yLoop END SUB -'------------------------------------------------------------------------------- -SUB FillPolygon (xCoord1, yCoord1, xCoord2, yCoord2, xCoord3, yCoord3, colorVal) -' Fills a triangular area by connecting the edges. -' It uses a scanline approach, storing intersection points in yb() array, -' then drawing horizontal lines between those intersection points. - - DIM yb(-100 TO 300) - - ' The following variables (mx1, my1, etc.) track the endpoints of edges - mx1 = xCoord1 - my1 = yCoord1 - mx2 = xCoord2 - my2 = yCoord2 - GOSUB mkl - - mx1 = xCoord1 - my1 = yCoord1 - mx2 = xCoord3 - my2 = yCoord3 - GOSUB mkl - - mx1 = xCoord3 - my1 = yCoord3 - mx2 = xCoord2 - my2 = yCoord2 - GOSUB mkl - - GOTO 1 - -mkl: + +SUB FillPolygon (xCoordOne, yCoordOne, xCoordTwo, yCoordTwo, xCoordThree, yCoordThree, colorValue) +' +' Fills a triangular region using a simple scanline approach. +' 1) Draw lines between points to find intersections on each horizontal row. +' 2) Use the pairs of intersection points to draw horizontal lines in colorValue. +' + DIM scanIntersection(-100 TO 300) + + localX1 = xCoordOne + localY1 = yCoordOne + localX2 = xCoordTwo + localY2 = yCoordTwo + GOSUB fillLines + + localX1 = xCoordOne + localY1 = yCoordOne + localX2 = xCoordThree + localY2 = yCoordThree + GOSUB fillLines + + localX1 = xCoordThree + localY1 = yCoordThree + localX2 = xCoordTwo + localY2 = yCoordTwo + GOSUB fillLines + + GOTO polygonDone + +fillLines: ' If the second point is above the first, swap them - IF my2 < my1 THEN - SWAP my1, my2 - SWAP mx1, mx2 + IF localY2 < localY1 THEN + SWAP localY1, localY2 + SWAP localX1, localX2 END IF - ' Scan through each row (y) in the current edge segment - FOR y = my1 TO my2 - 1 - x = mx1 + (mx2 - mx1) * ((y - my1) / (my2 - my1)) - IF yb(y) = 0 THEN - ' First intersection on this scanline - yb(y) = x + ' Walk through rows from localY1 up to localY2 + FOR yFill = localY1 TO localY2 - 1 + xFill = localX1 + (localX2 - localX1) * ((yFill - localY1) / (localY2 - localY1)) + IF scanIntersection(yFill) = 0 THEN + ' This is the first intersection discovered on this row + scanIntersection(yFill) = xFill ELSE - ' Second intersection -> draw a horizontal line - LINE (x, y)-(yb(y), y), colorVal + ' Second intersection found -> draw horizontal line to the first intersection + LINE (xFill, yFill)-(scanIntersection(yFill), yFill), colorValue END IF - NEXT y + NEXT yFill RETURN -1 : +polygonDone: END SUB -'------------------------------------------------------------------------------- -SUB GetAngle (x1, y1, x2, y2, N) -' Determines the angle (N) between two points (x1,y1) and (x2,y2). -' Used for rotation operations in 2D or for adjusting orientation. - IF y1 = y2 THEN - IF x2 > x1 THEN N = pi / 2 ELSE N = pi * 1.5 - GOTO 2 +SUB GetAngle (xOne, yOne, xTwo, yTwo, angleOutput) +' +' Computes an angle in radians between two points (xOne,yOne) and (xTwo,yTwo). +' The result is stored in angleOutput. Used for 2D rotation or orientation logic. +' + IF yOne = yTwo THEN + IF xTwo > xOne THEN + angleOutput = globalPi / 2 + ELSE + angleOutput = globalPi * 1.5 + END IF + GOTO skipLogic END IF - IF y2 > y1 THEN - IF x2 = x1 THEN - N = pi - GOTO 2 + IF yTwo > yOne THEN + IF xTwo = xOne THEN + angleOutput = globalPi + GOTO skipLogic END IF - IF x2 > x1 THEN - N = (pi * 1) - ATN((x2 - x1) / (y2 - y1)) + IF xTwo > xOne THEN + angleOutput = (globalPi * 1) - ATN((xTwo - xOne) / (yTwo - yOne)) ELSE - N = pi + ATN((x1 - x2) / (y2 - y1)) + angleOutput = globalPi + ATN((xOne - xTwo) / (yTwo - yOne)) END IF ELSE - IF x2 = x1 THEN - N = 0 - GOTO 2 + IF xTwo = xOne THEN + angleOutput = 0 + GOTO skipLogic END IF - IF x2 > x1 THEN - N = ATN((x2 - x1) / (y1 - y2)) + IF xTwo > xOne THEN + angleOutput = ATN((xTwo - xOne) / (yOne - yTwo)) ELSE - N = pi * 2 - ATN((x1 - x2) / (y1 - y2)) + angleOutput = globalPi * 2 - ATN((xOne - xTwo) / (yOne - yTwo)) END IF END IF -2 : +skipLogic: END SUB -'------------------------------------------------------------------------------- -SUB Initialize -' Initializes screen mode, sets up global constants pi and pii, -' and captures system font data for later use in PrintText. +SUB Initialize +' +' Initializes the environment: +' 1) Switches to SCREEN 13 +' 2) Sets globalPi and globalPiI +' 3) Calculates a shared factor (fac) for angles +' 4) Calls InitializeFont to capture system font data +' SCREEN 13 - pi = 3.141592 - pii = pi - fac = 360 / (pi * 2) + globalPi = 3.141592 + globalPiI = globalPi + factorAngle = 360 / (globalPi * 2) InitializeFont END SUB -'------------------------------------------------------------------------------- -SUB InitializeFont -' Captures the current text font into an array for later use -' when drawing text with PrintText. +SUB InitializeFont +' +' Captures the current text font into fontData() for later use in PrintText. +' This is done by printing each ASCII character (32..150) and reading its bits. +' SetPalette 0, 0, 0, 70 COLOR 70 - FOR a = 32 TO 150 + FOR asciiCode = 32 TO 150 LOCATE 1, 1 - PRINT CHR$(a); - FOR y = 0 TO 7 - FOR x = 0 TO 7 - font(x, y, a) = POINT(x, y) - NEXT x - NEXT y - NEXT a + PRINT CHR$(asciiCode); + FOR yScan = 0 TO 7 + FOR xScan = 0 TO 7 + fontData(xScan, yScan, asciiCode) = POINT(xScan, yScan) + NEXT xScan + NEXT yScan + NEXT asciiCode END SUB + DEFINT A-Z -'------------------------------------------------------------------------------- SUB MakeBackground -' Creates a fractal-like background by iteratively sampling and -' perturbing pixel values, producing a terrain effect. - +' +' Creates a fractal-like landscape in the background by iteratively sampling +' and perturbing pixel values. The result is a random terrain effect. +' CLS SetPalette 0, 5, 5, 250 SetPalette 0, 5, 5, 251 @@ -256,139 +282,155 @@ SUB MakeBackground SetPalette 0, 5, 5, 254 SetPalette 0, 5, 5, 255 - FOR a = 0 TO 127 - OUT &H3C8, a - OUT &H3C9, SIN(a / 22) * 30 + 30 - OUT &H3C9, SIN(a / 18) * 5 + 5 - OUT &H3C9, COS(a / 12) * 10 + 10 - NEXT a - - FOR a = 128 TO 245 - OUT &H3C8, a - b = a - 128 - OUT &H3C9, SIN(b / 22) * 4 + 10 - OUT &H3C9, SIN(b / 18) * 4 + 10 - OUT &H3C9, COS(b / 12) * 4 + 10 - NEXT a - - DIM lm - lm = 127 - - s = 2 ^ 8 -5 : - s = s \ 2 - x2 = (319 \ s) - 1 - y2 = (199 \ s) - 1 - - FOR y = 0 TO y2 - FOR x = 0 TO x2 - x1 = x * s - y1 = y * s - c1 = POINT(x1, y1) - c2 = POINT(x1 + s, y1) - c3 = POINT(x1, y1 + s) - c4 = POINT(x1 + s, y1 + s) - - sp = s \ 2 - - cc2 = ((c1 + c2) / 2) + (RND * 6) - 3 - IF cc2 > lm THEN cc2 = lm - - cc3 = ((c1 + c3) / 2) + (RND * 6) - 3 - IF cc3 > lm THEN cc3 = lm - - cc4 = ((c2 + c4) / 2) + (RND * 6) - 3 - IF cc4 > lm THEN cc4 = lm - - cc5 = ((c3 + c4) / 2) + (RND * 6) - 3 - IF cc5 > lm THEN cc5 = lm - - cc1 = ((cc2 + cc3 + cc4 + cc5) / 4) + (RND * 6) - 3 - IF cc1 > lm THEN cc1 = lm - - PSET (x1 + sp, y1 + sp), cc1 - PSET (x1 + sp, y1), cc2 - PSET (x1, y1 + sp), cc3 - PSET (x1 + s, y1 + sp), cc4 - PSET (x1 + sp, y1 + s), cc5 - NEXT x - NEXT y - IF s > 2 THEN GOTO 5 - + ' Set custom RGB values for palette entries 0..127 + FOR loopIndex = 0 TO 127 + OUT &H3C8, loopIndex + OUT &H3C9, SIN(loopIndex / 22) * 30 + 30 + OUT &H3C9, SIN(loopIndex / 18) * 5 + 5 + OUT &H3C9, COS(loopIndex / 12) * 10 + 10 + NEXT loopIndex + + ' Palette entries 128..245 + FOR loopIndex = 128 TO 245 + OUT &H3C8, loopIndex + offsetIndex = loopIndex - 128 + OUT &H3C9, SIN(offsetIndex / 22) * 4 + 10 + OUT &H3C9, SIN(offsetIndex / 18) * 4 + 10 + OUT &H3C9, COS(offsetIndex / 12) * 4 + 10 + NEXT loopIndex + + DIM limitValue + limitValue = 127 + + dimensionSize = 2 ^ 8 +fractalLoop: + dimensionSize = dimensionSize \ 2 + xSteps = (319 \ dimensionSize) - 1 + ySteps = (199 \ dimensionSize) - 1 + + ' Subdivide squares in the image to add random variations + FOR loopY = 0 TO ySteps + FOR loopX = 0 TO xSteps + topLeftX = loopX * dimensionSize + topLeftY = loopY * dimensionSize + pixC1 = POINT(topLeftX, topLeftY) + pixC2 = POINT(topLeftX + dimensionSize, topLeftY) + pixC3 = POINT(topLeftX, topLeftY + dimensionSize) + pixC4 = POINT(topLeftX + dimensionSize, topLeftY + dimensionSize) + + halfBlock = dimensionSize \ 2 + + newC2 = ((pixC1 + pixC2) / 2) + (RND * 6) - 3 + IF newC2 > limitValue THEN newC2 = limitValue + + newC3 = ((pixC1 + pixC3) / 2) + (RND * 6) - 3 + IF newC3 > limitValue THEN newC3 = limitValue + + newC4 = ((pixC2 + pixC4) / 2) + (RND * 6) - 3 + IF newC4 > limitValue THEN newC4 = limitValue + + newC5 = ((pixC3 + pixC4) / 2) + (RND * 6) - 3 + IF newC5 > limitValue THEN newC5 = limitValue + + centerVal = ((newC2 + newC3 + newC4 + newC5) / 4) + (RND * 6) - 3 + IF centerVal > limitValue THEN centerVal = limitValue + + PSET (topLeftX + halfBlock, topLeftY + halfBlock), centerVal + PSET (topLeftX + halfBlock, topLeftY), newC2 + PSET (topLeftX, topLeftY + halfBlock), newC3 + PSET (topLeftX + dimensionSize, topLeftY + halfBlock), newC4 + PSET (topLeftX + halfBlock, topLeftY + dimensionSize), newC5 + NEXT loopX + NEXT loopY + + IF dimensionSize > 2 THEN GOTO fractalLoop END SUB + DEFSNG A-Z -'------------------------------------------------------------------------------- -SUB PrintText (x, y, s, c, a$) -' Prints text at a specified (x,y) position on the screen, by reading -' from the 'font' array captured in InitializeFont. Allows for scaling = 1. - - IF s = 1 THEN - x2 = x - FOR a = 1 TO LEN(a$) - b = ASC(RIGHT$(LEFT$(a$, a), 1)) - IF b > 150 OR b < 32 THEN GOTO 7 - FOR y1 = 0 TO 7 - FOR x1 = 0 TO 7 - c1 = font(x1, y1, b) - IF c1 > 0 THEN PSET (x1 + x2, y1 + y), c - NEXT x1 - NEXT y1 -7 : - x2 = x2 + 8 - NEXT a +SUB PrintText (posX, posY, scale, colorValue, textString$) +' +' Renders text at (posX, posY) using the captured fontData(). +' Currently supports scale=1 for normal size. If scale=1, each character +' is drawn 1:1 from the font data. +' + IF scale = 1 THEN + nextX = posX + FOR charPos = 1 TO LEN(textString$) + asciiVal = ASC(RIGHT$(LEFT$(textString$, charPos), 1)) + IF asciiVal > 150 OR asciiVal < 32 THEN GOTO skipChar + + FOR yScan = 0 TO 7 + FOR xScan = 0 TO 7 + pixVal = fontData(xScan, yScan, asciiVal) + IF pixVal > 0 THEN PSET (xScan + nextX, yScan + posY), colorValue + NEXT xScan + NEXT yScan + +skipChar: + nextX = nextX + 8 + NEXT charPos END IF END SUB -'------------------------------------------------------------------------------- -SUB RotatePoint (zx, zy, x1, y1, N) -' Rotates a point (x1,y1) around a center (zx,zy) by angle N (in radians). -' This is a standard 2D rotation transform. - - x2 = x1 - zx - y2 = y1 - zy - c1 = SIN(N) - s1 = COS(N) - x1 = x2 * s1 - y2 * c1 + zx - y1 = x2 * c1 + y2 * s1 + zy + +SUB RotatePoint (centerX, centerY, pointX, pointY, angleRadians) +' +' Rotates point (pointX, pointY) around (centerX, centerY) by angleRadians. +' Standard 2D rotation formula: +' X' = (X - CX)*cos - (Y - CY)*sin + CX +' Y' = (X - CX)*sin + (Y - CY)*cos + CY +' + deltaX = pointX - centerX + deltaY = pointY - centerY + sinAngle = SIN(angleRadians) + cosAngle = COS(angleRadians) + pointX = deltaX * cosAngle - deltaY * sinAngle + centerX + pointY = deltaX * sinAngle + deltaY * cosAngle + centerY END SUB + '------------------------------------------------------------------------------- SUB Scene1 -' Initializes palette and reads 3D data from "data.dat" for a rotating -' point/line demonstration. The code then renders lines in 2D projection -' while applying transformations over time to create animation-like motion. - +' +' Loads & processes 3D data from "data.dat" to demonstrate simple line rendering. +' The object is rotated in real-time, and lines are projected in 2D. +' Timers and angles cause a rotating, animated effect. +' SetPalette 0, 63, 20, 255 - DIM px(0 TO 1000) - DIM py(0 TO 1000) - DIM pz(0 TO 1000) - DIM px1(0 TO 1000) - DIM py1(0 TO 1000) - DIM lin1!(0 TO 1500) - DIM lin2!(0 TO 1500) - DIM lbx1(1 TO 1500) - DIM lby1(1 TO 1500) - DIM lbx2(1 TO 1500) - DIM lby2(1 TO 1500) - - DIM np, nl - DIM an1, an2, an3 - DIM an1s, an2s, an3s - DIM inco, inpo - DIM tim - DIM nlt - DIM ehi - - tim = 0 - ehi = 1 - an1 = 0 - an2 = 0 - np = -1 - nl = 0 - inco = 0 - inpo = 0 - nlt = 0 + + DIM pointX(0 TO 1000) + DIM pointY(0 TO 1000) + DIM pointZ(0 TO 1000) + + DIM projectedX(0 TO 1000) + DIM projectedY(0 TO 1000) + + DIM linePointOne!(0 TO 1500) + DIM linePointTwo!(0 TO 1500) + + DIM lineBufferXOne(1 TO 1500) + DIM lineBufferYOne(1 TO 1500) + DIM lineBufferXTwo(1 TO 1500) + DIM lineBufferYTwo(1 TO 1500) + + DIM numPoints, numLines + DIM angleOne, angleTwo, angleThree + DIM angleOneSpeed, angleTwoSpeed, angleThreeSpeed + DIM incPoints, incPolys + DIM timeCounter + DIM totalLines + DIM extraHelperIndex + + timeCounter = 0 + extraHelperIndex = 1 + angleOne = 0 + angleTwo = 0 + numPoints = -1 + numLines = 0 + incPoints = 0 + incPolys = 0 + totalLines = 0 SetPalette 40, 40, 40, 254 COLOR 254 @@ -396,453 +438,495 @@ SUB Scene1 PRINT "One moment" OPEN "data.dat" FOR INPUT AS #1 - INPUT #1, a - INPUT #1, inco - INPUT #1, inpo - - FOR a = 1 TO inco - INPUT #1, x, y, z - np = np + 1 - px(np) = x - 100 - py(np) = y - pz(np) = z - NEXT a - - INPUT #1, b, b, l1, l2, l3 - - FOR a = 1 TO inpo - 1 - INPUT #1, b, b, l1!, l2!, l3! - nlin1! = l1! - nlin2! = l2! - GOSUB addlin - nlin1! = l2! - nlin2! = l3! - GOSUB addlin - nlin1! = l1! - nlin2! = l3! - GOSUB addlin + INPUT #1, readTemp + INPUT #1, incPoints + INPUT #1, incPolys + + FOR loopIndex = 1 TO incPoints + INPUT #1, pxVal, pyVal, pzVal + numPoints = numPoints + 1 + pointX(numPoints) = pxVal - 100 + pointY(numPoints) = pyVal + pointZ(numPoints) = pzVal + NEXT loopIndex + + INPUT #1, dummyVar, dummyVar, lineVal1, lineVal2, lineVal3 + + FOR loopIndex = 1 TO incPolys - 1 + INPUT #1, dummyVar, dummyVar, lineVal1!, lineVal2!, lineVal3! + newLineOne! = lineVal1! + newLineTwo! = lineVal2! + GOSUB addLine + newLineOne! = lineVal2! + newLineTwo! = lineVal3! + GOSUB addLine + newLineOne! = lineVal1! + newLineTwo! = lineVal3! + GOSUB addLine LOCATE 4, 10 - PRINT STR$(INT(a / (inpo - 1) * 100)) + "% ready" - NEXT a + PRINT STR$(INT(loopIndex / (incPolys - 1) * 100)) + "% ready" + NEXT loopIndex CLOSE 1 CLS -3 : - tim = tim + 1 +rotateLoop: + timeCounter = timeCounter + 1 + quitKey$ = INKEY$ IF quitKey$ = "q" THEN END - a = COS(tim / 25) - an1 = COS(tim / 29) * a - an2 = (pii / 2) + SIN(tim / 42) * a + varA = COS(timeCounter / 25) + angleOne = COS(timeCounter / 29) * varA + angleTwo = (globalPiI / 2) + SIN(timeCounter / 42) * varA - s1 = SIN(an1) - c1 = COS(an1) - s2 = SIN(an2) - c2 = COS(an2) + sin1 = SIN(angleOne) + cos1 = COS(angleOne) + sin2 = SIN(angleTwo) + cos2 = COS(angleTwo) - IF ehi >= 1 THEN - nlt = nlt + ehi - ehi = ehi + .03 - IF nlt > nl THEN nlt = nl: ehi = 0 + IF extraHelperIndex >= 1 THEN + totalLines = totalLines + extraHelperIndex + extraHelperIndex = extraHelperIndex + .03 + IF totalLines > numLines THEN totalLines = numLines: extraHelperIndex = 0 END IF - FOR a = 0 TO np - x = px(a) - y = py(a) - z = pz(a) - - z2 = z * s1 + y * c1 - y1 = y * s1 - z * c1 - - z1 = z2 * s2 + x * c2 - x1 = x * s2 - z2 * c2 - - z1 = z1 + 100 - x1 = x1 / z1 * 74 * 2 - y1 = y1 / z1 * 65 * 2 - - px1(a) = x1 + 160 - py1(a) = y1 + 80 - NEXT a - - FOR a = 1 TO nlt - l1 = lin1!(a) - l2 = lin2!(a) - x1 = px1(l1) - y1 = py1(l1) - x2 = px1(l2) - y2 = py1(l2) - LINE (lbx1(a), lby1(a))-(lbx2(a), lby2(a)), 0 - LINE (x1, y1)-(x2, y2), 255 - lbx1(a) = x1 - lby1(a) = y1 - lbx2(a) = x2 - lby2(a) = y2 - NEXT a + ' Project each 3D point to 2D + FOR loopIndex = 0 TO numPoints + localX = pointX(loopIndex) + localY = pointY(loopIndex) + localZ = pointZ(loopIndex) + + zTemp = localZ * sin1 + localY * cos1 + yTemp = localY * sin1 - localZ * cos1 + + zFinal = zTemp * sin2 + localX * cos2 + xFinal = localX * sin2 - zTemp * cos2 + + zFinal = zFinal + 100 + xFinal = xFinal / zFinal * 74 * 2 + yFinal = yTemp / zFinal * 65 * 2 + + projectedX(loopIndex) = xFinal + 160 + projectedY(loopIndex) = yFinal + 80 + NEXT loopIndex + + ' Draw lines + FOR loopIndex = 1 TO totalLines + lineStart = linePointOne!(loopIndex) + lineEnd = linePointTwo!(loopIndex) + x1Temp = projectedX(lineStart) + y1Temp = projectedY(lineStart) + x2Temp = projectedX(lineEnd) + y2Temp = projectedY(lineEnd) + LINE (lineBufferXOne(loopIndex), lineBufferYOne(loopIndex))-(lineBufferXTwo(loopIndex), lineBufferYTwo(loopIndex)), 0 + LINE (x1Temp, y1Temp)-(x2Temp, y2Temp), 255 + lineBufferXOne(loopIndex) = x1Temp + lineBufferYOne(loopIndex) = y1Temp + lineBufferXTwo(loopIndex) = x2Temp + lineBufferYTwo(loopIndex) = y2Temp + NEXT loopIndex + SOUND 0, .5 - IF tim < 280 THEN GOTO 3 - GOTO 4 + IF timeCounter < 280 THEN GOTO rotateLoop + GOTO endScene -addlin: - FOR b = 1 TO nl - IF lin1!(b) = nlin1! THEN - IF lin2!(b) = nlin2! THEN RETURN +addLine: + FOR checkIndex = 1 TO numLines + IF linePointOne!(checkIndex) = newLineOne! THEN + IF linePointTwo!(checkIndex) = newLineTwo! THEN RETURN END IF - IF lin1!(b) = nlin2! THEN - IF lin2!(b) = nlin1! THEN RETURN + IF linePointOne!(checkIndex) = newLineTwo! THEN + IF linePointTwo!(checkIndex) = newLineOne! THEN RETURN END IF - NEXT b - nl = nl + 1 - lin1!(nl) = nlin1! - lin2!(nl) = nlin2! + NEXT checkIndex + numLines = numLines + 1 + linePointOne!(numLines) = newLineOne! + linePointTwo!(numLines) = newLineTwo! RETURN -4 : - angl1 = an1 - angl2 = an2 +endScene: + globalAngleOne = angleOne + globalAngleTwo = angleTwo END SUB -'------------------------------------------------------------------------------- -SUB Scene2 -' Loads 3D data from "data.dat" and projects triangular faces to 2D. -' The polygons are sorted by depth, then drawn from farthest to nearest -' using FillPolygon to produce simple hidden-surface-like rendering. +SUB Scene2 +' +' Loads 3D data from "data.dat" and projects triangular faces in 2D. +' Each triangle's average depth is computed, and polygons are drawn +' from back to front with FillPolygon. The shading is computed too. +' SetPalette 0, 63, 20, 255 CLS - angl1 = 0 - angl2 = 1.5 - DIM px(0 TO 2000) - DIM py(0 TO 2000) - DIM pz(0 TO 2000) + globalAngleOne = 0 + globalAngleTwo = 1.5 - DIM rpx(0 TO 2000) - DIM rpy(0 TO 2000) - DIM rpz(0 TO 2000) + DIM pointX(0 TO 2000) + DIM pointY(0 TO 2000) + DIM pointZ(0 TO 2000) - DIM pol1(1 TO 2000) - DIM pol2(1 TO 2000) - DIM pol3(1 TO 2000) + DIM rotatedX(0 TO 2000) + DIM rotatedY(0 TO 2000) + DIM rotatedZ(0 TO 2000) - np = 0 - nl = 0 + DIM polyOne(1 TO 2000) + DIM polyTwo(1 TO 2000) + DIM polyThree(1 TO 2000) + + numPoints = 0 + numTriangles = 0 OPEN "data.dat" FOR INPUT AS #1 - INPUT #1, a - INPUT #1, inco - INPUT #1, inpo - - FOR a = 1 TO inco - INPUT #1, x, y, z - px(np) = x - 100 - py(np) = y - pz(np) = z - np = np + 1 - NEXT a - - INPUT #1, b, b, l1, l2, l3 - - FOR a = 1 TO inpo - 1 - INPUT #1, b, b, l1, l2, l3 - nl = nl + 1 - pol1(nl) = l1 - pol2(nl) = l2 - pol3(nl) = l3 - NEXT a + INPUT #1, readTemp + INPUT #1, totalPoints + INPUT #1, totalPolys + + FOR loopIndex = 1 TO totalPoints + INPUT #1, posXVal, posYVal, posZVal + pointX(numPoints) = posXVal - 100 + pointY(numPoints) = posYVal + pointZ(numPoints) = posZVal + numPoints = numPoints + 1 + NEXT loopIndex + + INPUT #1, dummyVal, dummyVal, lineValA, lineValB, lineValC + + FOR loopIndex = 1 TO totalPolys - 1 + INPUT #1, dummyVal, dummyVal, lineValA, lineValB, lineValC + numTriangles = numTriangles + 1 + polyOne(numTriangles) = lineValA + polyTwo(numTriangles) = lineValB + polyThree(numTriangles) = lineValC + NEXT loopIndex CLOSE #1 - s1 = SIN(angl1) - c1 = COS(angl1) - s2 = SIN(angl2) - c2 = COS(angl2) - - FOR a = 0 TO np - x = px(a) - y = py(a) - z = pz(a) - z2 = z * s1 + y * c1 - y1 = y * s1 - z * c1 - z1 = z2 * s2 + x * c2 - x1 = x * s2 - z2 * c2 - z1 = z1 + 100 - x1 = x1 / z1 * 74 * 2 - y1 = y1 / z1 * 65 * 2 - rpx(a) = x1 + 160 - rpy(a) = y1 + 80 - rpz(a) = z1 - NEXT a - - FOR a = 1 TO 49 - SetPalette a * 1.1 + 20, a * 1.1 + 10, a * 1.1, a - NEXT a - - DIM polz(1 TO nl) - - FOR a = 1 TO nl - polz(a) = (rpz(pol1(a)) + rpz(pol2(a)) + rpz(pol3(a))) - NEXT a - - e = nl - FOR a = 1 TO nl - su = -10000 - sun = 1 - FOR b = 1 TO e - IF polz(b) > su THEN su = polz(b): sun = b - NEXT b - - p1 = pol1(sun) - p2 = pol2(sun) - p3 = pol3(sun) - - polz(sun) = polz(e) - pol1(sun) = pol1(e) - pol2(sun) = pol2(e) - pol3(sun) = pol3(e) - e = e - 1 - - ComputeShadeValue rpx(p1), rpy(p1), rpz(p1), rpx(p2), rpy(p2), rpz(p2), rpx(p3), rpy(p3), rpz(p3), d - FillPolygon INT(rpx(p1)), INT(rpy(p1)), INT(rpx(p2)), INT(rpy(p2)), INT(rpx(p3)), INT(rpy(p3)), INT(d) - NEXT a + sin1 = SIN(globalAngleOne) + cos1 = COS(globalAngleOne) + sin2 = SIN(globalAngleTwo) + cos2 = COS(globalAngleTwo) + + ' Project each 3D point + FOR loopIndex = 0 TO numPoints + localX = pointX(loopIndex) + localY = pointY(loopIndex) + localZ = pointZ(loopIndex) + + zTmp = localZ * sin1 + localY * cos1 + yTmp = localY * sin1 - localZ * cos1 + zFin = zTmp * sin2 + localX * cos2 + xFin = localX * sin2 - zTmp * cos2 + + zFin = zFin + 100 + xFin = xFin / zFin * 74 * 2 + yFin = yTmp / zFin * 65 * 2 + + rotatedX(loopIndex) = xFin + 160 + rotatedY(loopIndex) = yFin + 80 + rotatedZ(loopIndex) = zFin + NEXT loopIndex + + ' Adjust palette for shading + FOR loopIndex = 1 TO 49 + SetPalette loopIndex * 1.1 + 20, loopIndex * 1.1 + 10, loopIndex * 1.1, loopIndex + NEXT loopIndex + + DIM polyDepth(1 TO numTriangles) + + FOR loopIndex = 1 TO numTriangles + polyDepth(loopIndex) = (rotatedZ(polyOne(loopIndex)) + rotatedZ(polyTwo(loopIndex)) + rotatedZ(polyThree(loopIndex))) + NEXT loopIndex + + eIndex = numTriangles + + ' Sort by descending depth (z) + FOR loopIndex = 1 TO numTriangles + bigVal = -10000 + bigIndex = 1 + FOR checkIdx = 1 TO eIndex + IF polyDepth(checkIdx) > bigVal THEN + bigVal = polyDepth(checkIdx) + bigIndex = checkIdx + END IF + NEXT checkIdx + + pA = polyOne(bigIndex) + pB = polyTwo(bigIndex) + pC = polyThree(bigIndex) + + polyDepth(bigIndex) = polyDepth(eIndex) + polyOne(bigIndex) = polyOne(eIndex) + polyTwo(bigIndex) = polyTwo(eIndex) + polyThree(bigIndex) = polyThree(eIndex) + eIndex = eIndex - 1 + + ComputeShadeValue rotatedX(pA), rotatedY(pA), rotatedZ(pA), _ + rotatedX(pB), rotatedY(pB), rotatedZ(pB), _ + rotatedX(pC), rotatedY(pC), rotatedZ(pC), shadeVal + + FillPolygon INT(rotatedX(pA)), INT(rotatedY(pA)), _ + INT(rotatedX(pB)), INT(rotatedY(pB)), _ + INT(rotatedX(pC)), INT(rotatedY(pC)), INT(shadeVal) + NEXT loopIndex END SUB -'------------------------------------------------------------------------------- -SUB Scene3 -' Demonstrates some simple raster effects and wave patterns, -' finishing with basic text drawing and random shifts of the screen buffer. - - DIM buf(1 TO 10000) - DIM buf1(0 TO 35) - FOR a = 1 TO 20 +SUB Scene3 +' +' Demonstrates simple raster/wave effects by copying screen slices, +' does some random shifting, then shows text with circles around the bits. +' + DIM bufferArray(1 TO 10000) + DIM waveArray(0 TO 35) + + FOR loopIndex = 1 TO 20 SOUND 0, 1 - NEXT a - FOR a = 0 TO 30 - IF a <= 5 THEN buf1(a) = 120 + (SQR((20 - a) * a)) - IF (a > 5) AND (a < 25) THEN buf1(a) = 120 + 10 - IF a >= 25 THEN buf1(a) = 120 + (SQR((30 - a) * (a - 10))) - NEXT a - - FOR y = 0 TO 30 - FOR x = 10 TO 300 STEP 10 - GET (x, 0)-(x + 9, 198), buf(1) - PUT (x, 1), buf(1), PSET - NEXT x - FOR a = 1 TO 49 - SetPalette a * 1.1 + (20 - y), a * 1.1 + 10 + (y / 1.5), a * 1.1, a - NEXT a + NEXT loopIndex + + ' Build a wave-like boundary in waveArray() + FOR loopIndex = 0 TO 30 + IF loopIndex <= 5 THEN waveArray(loopIndex) = 120 + (SQR((20 - loopIndex) * loopIndex)) + IF (loopIndex > 5) AND (loopIndex < 25) THEN waveArray(loopIndex) = 120 + 10 + IF loopIndex >= 25 THEN waveArray(loopIndex) = 120 + (SQR((30 - loopIndex) * (loopIndex - 10))) + NEXT loopIndex + + ' Slide the screen upward in small blocks + FOR screenY = 0 TO 30 + FOR screenX = 10 TO 300 STEP 10 + GET (screenX, 0)-(screenX + 9, 198), bufferArray(1) + PUT (screenX, 1), bufferArray(1), PSET + NEXT screenX + + ' Slight color shift + FOR colorIx = 1 TO 49 + SetPalette colorIx * 1.1 + (20 - screenY), colorIx * 1.1 + 10 + (screenY / 1.5), colorIx * 1.1, colorIx + NEXT colorIx + SOUND 0, 1 - LINE (160 - buf1(y), 20)-(160 + buf1(y), 20), 255 - NEXT y + LINE (160 - waveArray(screenY), 20)-(160 + waveArray(screenY), 20), 255 + NEXT screenY LOCATE 1, 1 COLOR 254 SetPalette 0, 0, 0, 254 PRINT "Tehisintellekt" SetPalette 63, 0, 0, 253 - FOR y = 0 TO 8 - FOR x = 0 TO 120 - c = POINT(x, y) - IF c > 0 THEN CIRCLE (x * 2 + 50, y * 3 + 26), 2, 0 - NEXT x - FOR x = 0 TO 120 - c = POINT(x, y + 1) - IF c > 0 THEN CIRCLE (x * 2 + 50, (y + 1) * 3 + 26), 2, 253 - NEXT x + + ' Draw circles around the nonzero pixels of the printed text + FOR rowY = 0 TO 8 + FOR rowX = 0 TO 120 + pixelVal = POINT(rowX, rowY) + IF pixelVal > 0 THEN CIRCLE (rowX * 2 + 50, rowY * 3 + 26), 2, 0 + NEXT rowX + + FOR rowX = 0 TO 120 + pixelVal = POINT(rowX, rowY + 1) + IF pixelVal > 0 THEN CIRCLE (rowX * 2 + 50, (rowY + 1) * 3 + 26), 2, 253 + NEXT rowX SOUND 0, 2 - NEXT y + NEXT rowY RANDOMIZE 1 - FOR a = 1 TO 10 - y = RND * 100 + 50 - FOR x = 10 TO 300 STEP 10 - GET (x, y)-(x + 9, 198), buf(1) - PUT (x, y - 1), buf(1), PSET - NEXT x - NEXT a + ' Perform random screen shifts + FOR loopIndex = 1 TO 10 + randY = RND * 100 + 50 + FOR screenX = 10 TO 300 STEP 10 + GET (screenX, randY)-(screenX + 9, 198), bufferArray(1) + PUT (screenX, randY - 1), bufferArray(1), PSET + NEXT screenX + NEXT loopIndex COLOR 253 SetPalette 0, 0, 0, 253 LOCATE 1 PRINT " autor: Svjatoslav Agejenko 30.09.2001 " - GET (0, 0)-(319, 8), buf(1) + + GET (0, 0)-(319, 8), bufferArray(1) LOCATE 1 PRINT " " - PUT (0, 190), buf(1), PSET - FOR a = 1 TO 32 - SetPalette 0, a, a * 2, 253 + PUT (0, 190), bufferArray(1), PSET + + FOR loopIndex = 1 TO 32 + SetPalette 0, loopIndex, loopIndex * 2, 253 SOUND 0, 1 - NEXT a + NEXT loopIndex WaitForInput END SUB -'------------------------------------------------------------------------------- -SUB Scene4 -' Uses MakeBackground to generate a fractal backdrop, then draws a box -' and prints some brief text explaining a "Spatial vision" concept. +SUB Scene4 +' +' Builds a fractal backdrop, draws a "rounded box," and prints short text lines +' about "Spatial vision" and "Object recognition." +' RANDOMIZE 1 MakeBackground DrawRoundedBox 30, 50, 290, 150 SetPalette 32, 64, 32, 250 - y = 0 - PrintText 30, 70 + y, 1, 250, " Spatial vision" - y = y + 16 - PrintText 30, 70 + y, 1, 250, "Object recognition" - y = y + 20 - PrintText 30, 70 + y, 1, 250, "Goal: + interpriteerimine" - y = y + 16 - PrintText 30, 70 + y, 1, 250, " + automaatjuhtimine" + yOffset = 0 + PrintText 30, 70 + yOffset, 1, 250, " Spatial vision" + yOffset = yOffset + 16 + PrintText 30, 70 + yOffset, 1, 250, "Object recognition" + yOffset = yOffset + 20 + PrintText 30, 70 + yOffset, 1, 250, "Goal: + interpriteerimine" + yOffset = yOffset + 16 + PrintText 30, 70 + yOffset, 1, 250, " + automaatjuhtimine" WaitForInput END SUB + '------------------------------------------------------------------------------- SUB Scene5 -' Again uses MakeBackground, draws a box, and prints text describing -' a feature-extraction process in image processing or computer vision. - +' +' Again creates a fractal background, draws a box, and explains +' some feature-extraction (edges) approaches: Laplace-Gauss, wavelet, +' hypercolumn theory, etc. +' RANDOMIZE 4 MakeBackground - DrawRoundedBox 30, 50, 290, 150 ' Renamed call + DrawRoundedBox 30, 50, 290, 150 SetPalette 32, 64, 32, 250 - y = -8 - PrintText 30, 70 + y, 1, 250, "Tunnuste ekstraheerimise protsess" - y = y + 20 - PrintText 30, 70 + y, 1, 250, "a) Laplace - Gaussi operaator;" - y = y + 12 - PrintText 30, 70 + y, 1, 250, "b) lainekese teisenduse multi-" - y = y + 12 - PrintText 30, 70 + y, 1, 250, " skaalaline serva avastamine;" - y = y + 12 - PrintText 30, 70 + y, 1, 250, "c) h�perveeru teooria lihtsate" - y = y + 12 - PrintText 30, 70 + y, 1, 250, " rakkude p�him�tted." + yOffset = -8 + PrintText 30, 70 + yOffset, 1, 250, "Tunnuste ekstraheerimise protsess" + yOffset = yOffset + 20 + PrintText 30, 70 + yOffset, 1, 250, "a) Laplace - Gaussi operaator;" + yOffset = yOffset + 12 + PrintText 30, 70 + yOffset, 1, 250, "b) lainekese teisenduse multi-" + yOffset = yOffset + 12 + PrintText 30, 70 + yOffset, 1, 250, " skaalaline serva avastamine;" + yOffset = yOffset + 12 + PrintText 30, 70 + yOffset, 1, 250, "c) h�perveeru teooria lihtsate" + yOffset = yOffset + 12 + PrintText 30, 70 + yOffset, 1, 250, " rakkude p�him�tted." WaitForInput END SUB -'------------------------------------------------------------------------------- -SUB Scene7 -' Simple transition effect: horizontal lines are drawn across the screen -' from top to bottom, clearing or darkening each row. +SUB Scene7 +' +' Simple transitional effect: draws horizontal lines across the screen +' in steps, clearing or darkening each row to black. +' SetPalette 0, 0, 0, 0 - FOR a = 0 TO 19 - FOR y = a TO 199 STEP 20 - LINE (0, y)-(319, y), 0 - NEXT y + FOR outerIndex = 0 TO 19 + FOR drawY = outerIndex TO 199 STEP 20 + LINE (0, drawY)-(319, drawY), 0 + NEXT drawY SOUND 0, .5 - NEXT a + NEXT outerIndex END SUB -'------------------------------------------------------------------------------- + SUB Scene8 -' A more complex 3D-like demo. It generates fractal terrain in the background, -' then plots points in a grid and draws lines between them. A "player" or -' "robot" object (with lines making a cube-like shape) moves around, -' picking up items, until time or user input ends the loop. - - FOR a = 1 TO 50 - SetPalette 0, 0, 0, a - NEXT a - - DIM px(0 TO 800) - DIM py(0 TO 800) - DIM pz(0 TO 800) - DIM lin1(0 TO 1000) - DIM lin2(0 TO 1000) - DIM linc(0 TO 1000) - DIM lbx1(1 TO 1000) - DIM lby1(1 TO 1000) - DIM lbx2(1 TO 1000) - DIM lby2(1 TO 1000) - DIM px1(0 TO 800) - DIM py1(0 TO 800) - DIM hlkx(1 TO 50) - DIM hlky(1 TO 50) - DIM hlkz(1 TO 50) - DIM hlka - DIM hlkr - DIM hlknu - DIM hlkin - DIM hlax, hlay, hlaz - DIM mx, mz, my - DIM desx, desz - DIM desa - - DIM np, nl - DIM an1, an2 - DIM tim - DIM eta - DIM mil - DIM miin - - miin = 0 - mil = 25 - tim = 0 - eta = 1 - an1 = 0 - an2 = 0 - - np = 0 - nl = 0 +' +' A more complex 3D scene: fractal terrain plus a "player" or "robot" object +' that collects items scattered on the terrain. Movement, angles, and final +' transformations are computed until time or key-press ends the loop. +' + FOR fadeIndex = 1 TO 50 + SetPalette 0, 0, 0, fadeIndex + NEXT fadeIndex + + DIM mainX(0 TO 800) + DIM mainY(0 TO 800) + DIM mainZ(0 TO 800) + + DIM lineStart(0 TO 1000) + DIM lineEnd(0 TO 1000) + DIM lineColor(0 TO 1000) + DIM lineBufferXOne(1 TO 1000) + DIM lineBufferYOne(1 TO 1000) + DIM lineBufferXTwo(1 TO 1000) + DIM lineBufferYTwo(1 TO 1000) + + DIM projectedX(0 TO 800) + DIM projectedY(0 TO 800) + + DIM holdX(1 TO 50) + DIM holdY(1 TO 50) + DIM holdZ(1 TO 50) + + DIM holdAngle + DIM holdRot + DIM holdNumber + DIM holdIndex + DIM holdAx, holdAy, holdAz + DIM moveX, moveZ, moveY + DIM destinationX, destinationZ + DIM destinationAngle + + DIM totalPoints, totalLines + DIM angleOne, angleTwo + DIM timeCounter + DIM incVal + DIM miniCount + DIM minutesVal + + minutesVal = 0 + miniCount = 25 + timeCounter = 0 + incVal = 1 + angleOne = 0 + angleTwo = 0 + + totalPoints = 0 + totalLines = 0 RANDOMIZE 100 - s = 64 - -14 : - sp = s / 2 - FOR y = 0 TO 100 STEP s - FOR x = 0 TO 100 STEP s - c1 = POINT(x, y) - c2 = POINT(x + s, y) - c3 = POINT(x, y + s) - c4 = POINT(x + s, y + s) - c5 = (c1 + c2 + c3 + c4) / 4 + RND * s * 6 - sp * 7 - c6 = (c2 + c4) / 2 + RND * s * 6 - sp * 7 - c7 = (c3 + c4) / 2 + RND * s * 6 - sp * 7 - IF c5 > 50 THEN c5 = 50 - IF c5 < 0 THEN c5 = 0 - IF c6 > 50 THEN c6 = 50 - IF c6 < 0 THEN c6 = 0 - IF c7 > 50 THEN c7 = 50 - IF c7 < 0 THEN c7 = 0 - PSET (x + sp, y + sp), c5 - PSET (x + s, y + sp), c6 - PSET (x + sp, y + s), c7 - NEXT x - NEXT y - s = s / 2 - IF s > 1 THEN GOTO 14 - - 'a$ = INPUT$(1) - - FOR z = 1 TO 400 STEP 20 - FOR x = 1 TO 400 STEP 20 - np = np + 1 - px(np) = x - py(np) = POINT(z / 20 + 10, x / 20 + 10) * 2 - pz(np) = z - IF x > 1 THEN - nl = nl + 1 - lin1(nl) = np - lin2(nl) = np - 1 - linc(nl) = 1 + blockSize = 64 + +fractalSubLoop: + halfBlock = blockSize / 2 + FOR yLoop = 0 TO 100 STEP blockSize + FOR xLoop = 0 TO 100 STEP blockSize + color1 = POINT(xLoop, yLoop) + color2 = POINT(xLoop + blockSize, yLoop) + color3 = POINT(xLoop, yLoop + blockSize) + color4 = POINT(xLoop + blockSize, yLoop + blockSize) + color5 = (color1 + color2 + color3 + color4) / 4 + RND * blockSize * 6 - halfBlock * 7 + color6 = (color2 + color4) / 2 + RND * blockSize * 6 - halfBlock * 7 + color7 = (color3 + color4) / 2 + RND * blockSize * 6 - halfBlock * 7 + IF color5 > 50 THEN color5 = 50 + IF color5 < 0 THEN color5 = 0 + IF color6 > 50 THEN color6 = 50 + IF color6 < 0 THEN color6 = 0 + IF color7 > 50 THEN color7 = 50 + IF color7 < 0 THEN color7 = 0 + PSET (xLoop + halfBlock, yLoop + halfBlock), color5 + PSET (xLoop + blockSize, yLoop + halfBlock), color6 + PSET (xLoop + halfBlock, yLoop + blockSize), color7 + NEXT xLoop + NEXT yLoop + blockSize = blockSize / 2 + IF blockSize > 1 THEN GOTO fractalSubLoop + + ' Build mesh points in mainX(), mainY(), mainZ() + FOR zLoop = 1 TO 400 STEP 20 + FOR xLoop = 1 TO 400 STEP 20 + totalPoints = totalPoints + 1 + mainX(totalPoints) = xLoop + mainY(totalPoints) = POINT(zLoop / 20 + 10, xLoop / 20 + 10) * 2 + mainZ(totalPoints) = zLoop + IF xLoop > 1 THEN + totalLines = totalLines + 1 + lineStart(totalLines) = totalPoints + lineEnd(totalLines) = totalPoints - 1 + lineColor(totalLines) = 1 END IF - IF z > 1 THEN - nl = nl + 1 - lin1(nl) = np - lin2(nl) = np - 20 - linc(nl) = 1 + IF zLoop > 1 THEN + totalLines = totalLines + 1 + lineStart(totalLines) = totalPoints + lineEnd(totalLines) = totalPoints - 20 + lineColor(totalLines) = 1 END IF - NEXT x - NEXT z + NEXT xLoop + NEXT zLoop LINE (0, 0)-(319, 199), 0, BF @@ -852,277 +936,295 @@ SUB Scene8 SetPalette 50, 50, 0, 3 SetPalette 64, 20, 0, 4 - mx = 200 - mz = 200 - kau = 1000 - hlax = 200 - hlay = 0 - hlaz = 200 - desx = 200 - desz = 200 + moveX = 200 + moveZ = 200 + distanceScale = 1000 + holdAx = 200 + holdAy = 0 + holdAz = 200 + destinationX = 200 + destinationZ = 200 OPEN "data2.dat" FOR INPUT AS #1 - a = 0 - b = 0 - hlkin = np + 1 - -15 : - INPUT #1, x, y, z - IF x = 999 THEN GOTO 16 - a = a + 1 - hlkx(a) = x - hlky(a) = -y - hlkz(a) = z - GOTO 15 - -16 : - INPUT #1, x, y - IF x = 999 THEN GOTO 17 - nl = nl + 1 - lin1(nl) = x + np + 1 - lin2(nl) = y + np + 1 - linc(nl) = 2 - GOTO 16 - -17 : + indexA = 0 + indexB = 0 + holdIndex = totalPoints + 1 + +readLoop: + INPUT #1, fileX, fileY, fileZ + IF fileX = 999 THEN GOTO checkLines + indexA = indexA + 1 + holdX(indexA) = fileX + holdY(indexA) = -fileY + holdZ(indexA) = fileZ + GOTO readLoop + +checkLines: + INPUT #1, readA, readB + IF readA = 999 THEN GOTO closeData + totalLines = totalLines + 1 + lineStart(totalLines) = readA + totalPoints + 1 + lineEnd(totalLines) = readB + totalPoints + 1 + lineColor(totalLines) = 2 + GOTO checkLines + +closeData: CLOSE #1 - np = np + a - hlknu = a + totalPoints = totalPoints + indexA + holdNumber = indexA RANDOMIZE 10 - c = 3 - FOR a = 1 TO 25 - p = RND * 396 + 2 - x = px(p) - z = pz(p) - yy = py(p) - 4 - - px(np + 1) = x - 5 - py(np + 1) = yy - pz(np + 1) = z - 5 - - px(np + 2) = x + 5 - py(np + 2) = yy - pz(np + 2) = z - 5 - - px(np + 3) = x + 5 - py(np + 3) = yy - pz(np + 3) = z + 5 - - px(np + 4) = x - 5 - py(np + 4) = yy - pz(np + 4) = z + 5 - - px(np + 5) = x - py(np + 5) = yy - 5 - pz(np + 5) = z - - lin1(nl + 1) = np + 1 - lin2(nl + 1) = np + 2 - linc(nl + 1) = c - - lin1(nl + 2) = np + 2 - lin2(nl + 2) = np + 3 - linc(nl + 2) = c - - lin1(nl + 3) = np + 3 - lin2(nl + 3) = np + 4 - linc(nl + 3) = c - - lin1(nl + 4) = np + 4 - lin2(nl + 4) = np + 1 - linc(nl + 4) = c - - lin1(nl + 5) = np + 1 - lin2(nl + 5) = np + 5 - linc(nl + 5) = c - - lin1(nl + 6) = np + 2 - lin2(nl + 6) = np + 5 - linc(nl + 6) = c - - lin1(nl + 7) = np + 3 - lin2(nl + 7) = np + 5 - linc(nl + 7) = c - - lin1(nl + 8) = np + 4 - lin2(nl + 8) = np + 5 - linc(nl + 8) = c - - np = np + 5 - nl = nl + 8 - NEXT a - -10 : + colorVal = 3 + FOR indexA = 1 TO 25 + randPick = RND * 396 + 2 + xBox = mainX(randPick) + zBox = mainZ(randPick) + yBox = mainY(randPick) - 4 + + mainX(totalPoints + 1) = xBox - 5 + mainY(totalPoints + 1) = yBox + mainZ(totalPoints + 1) = zBox - 5 + + mainX(totalPoints + 2) = xBox + 5 + mainY(totalPoints + 2) = yBox + mainZ(totalPoints + 2) = zBox - 5 + + mainX(totalPoints + 3) = xBox + 5 + mainY(totalPoints + 3) = yBox + mainZ(totalPoints + 3) = zBox + 5 + + mainX(totalPoints + 4) = xBox - 5 + mainY(totalPoints + 4) = yBox + mainZ(totalPoints + 4) = zBox + 5 + + mainX(totalPoints + 5) = xBox + mainY(totalPoints + 5) = yBox - 5 + mainZ(totalPoints + 5) = zBox + + lineStart(totalLines + 1) = totalPoints + 1 + lineEnd(totalLines + 1) = totalPoints + 2 + lineColor(totalLines + 1) = colorVal + + lineStart(totalLines + 2) = totalPoints + 2 + lineEnd(totalLines + 2) = totalPoints + 3 + lineColor(totalLines + 2) = colorVal + + lineStart(totalLines + 3) = totalPoints + 3 + lineEnd(totalLines + 3) = totalPoints + 4 + lineColor(totalLines + 3) = colorVal + + lineStart(totalLines + 4) = totalPoints + 4 + lineEnd(totalLines + 4) = totalPoints + 1 + lineColor(totalLines + 4) = colorVal + + lineStart(totalLines + 5) = totalPoints + 1 + lineEnd(totalLines + 5) = totalPoints + 5 + lineColor(totalLines + 5) = colorVal + + lineStart(totalLines + 6) = totalPoints + 2 + lineEnd(totalLines + 6) = totalPoints + 5 + lineColor(totalLines + 6) = colorVal + + lineStart(totalLines + 7) = totalPoints + 3 + lineEnd(totalLines + 7) = totalPoints + 5 + lineColor(totalLines + 7) = colorVal + + lineStart(totalLines + 8) = totalPoints + 4 + lineEnd(totalLines + 8) = totalPoints + 5 + lineColor(totalLines + 8) = colorVal + + totalPoints = totalPoints + 5 + totalLines = totalLines + 8 + NEXT indexA + +mainLoop: SOUND 0, 1 - IF INKEY$ <> "" THEN miin = 1 - IF miin > 150 THEN GOTO 13 - IF miin <> 0 THEN miin = miin + 7 - mx = hlax - my = 50 - hlay - miin - mz = hlaz - - SELECT CASE eta - CASE 1 - desx = px(np) - desz = pz(np) - GetAngle desx, desz, hlax, hlaz, desa - IF desa - hlka > pi THEN desa = desa - (pi * 2) - IF hlka - desa > pi THEN desa = desa + (pi * 2) - eta = 2 - FOR a = nl - 7 TO nl - linc(a) = 4 - NEXT a - CASE 2 - a = desa - hlka - IF desa = hlka THEN eta = 3 - IF a > .05 THEN a = .05 - IF a < -.05 THEN a = -.05 - hlka = hlka + a - CASE 3 - x = desx - hlax - z = desz - hlaz - v = SQR(x * x + z * z) - IF v < 5 THEN eta = 4 - v = v / 2 - hlax = hlax + x / v - hlaz = hlaz + z / v - CASE 4 - FOR a = np - 4 TO np - py(a) = py(a) - 1 - NEXT a - IF py(np) < 3 - hlay THEN - FOR a = nl - 7 TO nl - LINE (lbx1(a), lby1(a))-(lbx2(a), lby2(a)), 0 - NEXT a - np = np - 5 - nl = nl - 8 - mil = mil - 1 - eta = 6 - IF mil <= 0 THEN eta = 7 - END IF - CASE 6 - eta = 5 - CASE 5 - eta = 1 + IF INKEY$ <> "" THEN minutesVal = 1 + IF minutesVal > 150 THEN GOTO finalArea + IF minutesVal <> 0 THEN minutesVal = minutesVal + 7 + + moveX = holdAx + moveY = 50 - holdAy - minutesVal + moveZ = holdAz + + SELECT CASE incVal + CASE 1 + destinationX = mainX(totalPoints) + destinationZ = mainZ(totalPoints) + GetAngle destinationX, destinationZ, holdAx, holdAz, destinationAngle + IF destinationAngle - holdAngle > globalPi THEN destinationAngle = destinationAngle - (globalPi * 2) + IF holdAngle - destinationAngle > globalPi THEN destinationAngle = destinationAngle + (globalPi * 2) + incVal = 2 + FOR indexA = totalLines - 7 TO totalLines + lineColor(indexA) = 4 + NEXT indexA + + CASE 2 + angleDiff = destinationAngle - holdAngle + IF destinationAngle = holdAngle THEN incVal = 3 + IF angleDiff > .05 THEN angleDiff = .05 + IF angleDiff < -.05 THEN angleDiff = -.05 + holdAngle = holdAngle + angleDiff + + CASE 3 + diffX = destinationX - holdAx + diffZ = destinationZ - holdAz + distVal = SQR(diffX * diffX + diffZ * diffZ) + IF distVal < 5 THEN incVal = 4 + distVal = distVal / 2 + holdAx = holdAx + diffX / distVal + holdAz = holdAz + diffZ / distVal + + CASE 4 + FOR indexA = totalPoints - 4 TO totalPoints + mainY(indexA) = mainY(indexA) - 1 + NEXT indexA + IF mainY(totalPoints) < 3 - holdAy THEN + FOR indexA = totalLines - 7 TO totalLines + LINE (lineBufferXOne(indexA), lineBufferYOne(indexA))-(lineBufferXTwo(indexA), lineBufferYTwo(indexA)), 0 + NEXT indexA + totalPoints = totalPoints - 5 + totalLines = totalLines - 8 + miniCount = miniCount - 1 + incVal = 6 + IF miniCount <= 0 THEN incVal = 7 + END IF + + CASE 6 + incVal = 5 + + CASE 5 + incVal = 1 END SELECT - y = 60 - py(INT((hlaz + 10) / 20) * 20 + INT((hlax + 10) / 20)) - IF hlay > y + 5 THEN hlay = hlay - 1 - IF hlay < y THEN hlay = hlay + 1 - IF hlay > y + 25 THEN hlay = hlay - 1 - IF hlay < y - 20 THEN hlay = hlay + 1 - - s1 = SIN(hlka) - c1 = COS(hlka) - FOR a = 0 TO hlknu - 5 - x = hlkx(a + 1) - z = hlkz(a + 1) - px(a + hlkin) = x * s1 + z * c1 + hlax - py(a + hlkin) = hlky(a + 1) - hlay - pz(a + hlkin) = z * s1 - x * c1 + hlaz - NEXT a - - hlkr = hlkr + .5 - s1 = SIN(hlkr) - c1 = COS(hlkr) - FOR a = hlknu - 4 TO hlknu - 1 - x = hlkx(a + 1) - z = hlkz(a + 1) - px(a + hlkin) = x * s1 + z * c1 + hlax - py(a + hlkin) = hlky(a + 1) - hlay - pz(a + hlkin) = z * s1 - x * c1 + hlaz - NEXT a - - tim = tim + 1 - - an1 = an1 + SIN(tim / 100) / 20 - an2 = SIN(tim / 42) * .3 + 1.15 - - s1 = SIN(an1) - c1 = COS(an1) - s2 = SIN(an2) - c2 = COS(an2) - - FOR a = 0 TO np - x = px(a) - mx - y = py(a) - my - z = pz(a) - mz - - z2 = z * s1 + x * c1 - x1 = x * s1 - z * c1 - - z1 = z2 * s2 + y * c2 - y1 = y * s2 - z2 * c2 - - z1 = z1 + kau - IF z1 < 1 THEN px1(a) = -1: GOTO 11 - x1 = x1 / z1 * 74 * 2 - y1 = y1 / z1 * 65 * 2 - - px1(a) = x1 + 160 - py1(a) = y1 + 80 -11 : - NEXT a - - FOR a = 1 TO nl - l1 = lin1(a) - l2 = lin2(a) - x1 = px1(l1) - x2 = px1(l2) - LINE (lbx1(a), lby1(a))-(lbx2(a), lby2(a)), 0 - IF (x1 = -1) OR (x2 = -1) THEN GOTO 12 - y1 = py1(l1) - y2 = py1(l2) - LINE (x1, y1)-(x2, y2), linc(a) - lbx1(a) = x1 - lby1(a) = y1 - lbx2(a) = x2 - lby2(a) = y2 -12 : - NEXT a - IF kau > 200 THEN kau = kau - 10 - IF tim < 28000 THEN GOTO 10 -13 : + localYVal = 60 - mainY(INT((holdAz + 10) / 20) * 20 + INT((holdAx + 10) / 20)) + IF holdAy > localYVal + 5 THEN holdAy = holdAy - 1 + IF holdAy < localYVal THEN holdAy = holdAy + 1 + IF holdAy > localYVal + 25 THEN holdAy = holdAy - 1 + IF holdAy < localYVal - 20 THEN holdAy = holdAy + 1 + + sinVal = SIN(holdAngle) + cosVal = COS(holdAngle) + FOR indexA = 0 TO holdNumber - 5 + tempX = holdX(indexA + 1) + tempZ = holdZ(indexA + 1) + mainX(indexA + holdIndex) = tempX * sinVal + tempZ * cosVal + holdAx + mainY(indexA + holdIndex) = holdY(indexA + 1) - holdAy + mainZ(indexA + holdIndex) = tempZ * sinVal - tempX * cosVal + holdAz + NEXT indexA + + holdRot = holdRot + .5 + sinVal = SIN(holdRot) + cosVal = COS(holdRot) + FOR indexA = holdNumber - 4 TO holdNumber - 1 + tempX = holdX(indexA + 1) + tempZ = holdZ(indexA + 1) + mainX(indexA + holdIndex) = tempX * sinVal + tempZ * cosVal + holdAx + mainY(indexA + holdIndex) = holdY(indexA + 1) - holdAy + mainZ(indexA + holdIndex) = tempZ * sinVal - tempX * cosVal + holdAz + NEXT indexA + + timeCounter = timeCounter + 1 + + angleOne = angleOne + SIN(timeCounter / 100) / 20 + angleTwo = SIN(timeCounter / 42) * .3 + 1.15 + + sin1 = SIN(angleOne) + cos1 = COS(angleOne) + sin2 = SIN(angleTwo) + cos2 = COS(angleTwo) + + ' Project all points to 2D + FOR indexA = 0 TO totalPoints + shiftX = mainX(indexA) - moveX + shiftY = mainY(indexA) - moveY + shiftZ = mainZ(indexA) - moveZ + + zIntermediate = shiftZ * sin1 + shiftX * cos1 + xIntermediate = shiftX * sin1 - shiftZ * cos1 + + zProject = zIntermediate * sin2 + shiftY * cos2 + yProject = shiftY * sin2 - zIntermediate * cos2 + + zProject = zProject + distanceScale + IF zProject < 1 THEN projectedX(indexA) = -1: GOTO skip2D + xProject = xIntermediate / zProject * 74 * 2 + yProject = yProject / zProject * 65 * 2 + + projectedX(indexA) = xProject + 160 + projectedY(indexA) = yProject + 80 + +skip2D: + NEXT indexA + + ' Erase old lines and draw new ones + FOR indexA = 1 TO totalLines + startIndex = lineStart(indexA) + endIndex = lineEnd(indexA) + x1Temp = projectedX(startIndex) + x2Temp = projectedX(endIndex) + LINE (lineBufferXOne(indexA), lineBufferYOne(indexA))-(lineBufferXTwo(indexA), lineBufferYTwo(indexA)), 0 + IF (x1Temp = -1) OR (x2Temp = -1) THEN GOTO skipDrawing + y1Temp = projectedY(startIndex) + y2Temp = projectedY(endIndex) + LINE (x1Temp, y1Temp)-(x2Temp, y2Temp), lineColor(indexA) + lineBufferXOne(indexA) = x1Temp + lineBufferYOne(indexA) = y1Temp + lineBufferXTwo(indexA) = x2Temp + lineBufferYTwo(indexA) = y2Temp + +skipDrawing: + NEXT indexA + + IF distanceScale > 200 THEN distanceScale = distanceScale - 10 + IF timeCounter < 28000 THEN GOTO mainLoop + +finalArea: END SUB + '------------------------------------------------------------------------------- SUB Scene9 -' Wrap-up scene that shows a background, draws a box, and prints -' a final "Thank you for attention!" message. - +' +' Final scene: fractal background, a rounded box, and a short "Thank you" +' note to wrap up the presentation. +' RANDOMIZE 45 MakeBackground DrawRoundedBox 30, 50, 290, 80 SetPalette 32, 64, 32, 250 - y = -8 - PrintText 30, 70 + y, 1, 250, " Thank you for attention!" + yOffset = -8 + PrintText 30, 70 + yOffset, 1, 250, " Thank you for attention!" WaitForInput END SUB -'------------------------------------------------------------------------------- -SUB SetPalette (r, g, b, c) -' Sets a palette entry (c) to the specified (r,g,b) values, each 0..63 range. - - IF r < 0 THEN r = 0 - IF g < 0 THEN g = 0 - IF b < 0 THEN b = 0 - IF r > 63 THEN r = 63 - IF g > 63 THEN g = 63 - IF b > 63 THEN b = 63 - - OUT &H3C8, c - OUT &H3C9, r - OUT &H3C9, g - OUT &H3C9, b +SUB SetPalette (red, green, blue, colorIndex) +' +' Sets palette entry 'colorIndex' to (red,green,blue). +' Each component 0..63. +' + IF red < 0 THEN red = 0 + IF green < 0 THEN green = 0 + IF blue < 0 THEN blue = 0 + IF red > 63 THEN red = 63 + IF green > 63 THEN green = 63 + IF blue > 63 THEN blue = 63 + + OUT &H3C8, colorIndex + OUT &H3C9, red + OUT &H3C9, green + OUT &H3C9, blue END SUB -'------------------------------------------------------------------------------- -SUB WaitForInput -' Reads exactly one character from the keyboard and stores it in inputKey$. +SUB WaitForInput +' +' Waits for exactly one keystroke and stores it into inputKey$. +' inputKey$ = INPUT$(1) END SUB + + -- 2.20.1