QB64.org Forum

Active Forums => Programs => Topic started by: FellippeHeitor on February 05, 2019, 06:41:06 pm

Title: Reddit's mobile app loading animation
Post by: FellippeHeitor on February 05, 2019, 06:41:06 pm
I am a bit obsessed with loading animations (one may have noticed at this point), be them fading dots, bouncing circles, or, in this case, little orbs orbiting a bigger orb.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(400, 400, 32)
  2.  
  3. _TITLE "Reddit's mobile app loading animation"
  4.  
  5. COLOR _RGB32(39, 78, 177)
  6.     'LINE (0, 0)-(_WIDTH - 1, _HEIGHT - 1), _RGBA32(0, 0, 0, 30), BF
  7.     CLS
  8.  
  9.     CircleFill _WIDTH / 2, _HEIGHT / 2, 35, _DEFAULTCOLOR
  10.  
  11.     a = a + .05
  12.     b = b + .025
  13.     IF a > _PI(2) THEN a = _PI(2) - a
  14.     IF b > _PI(2) THEN b = _PI(2) - b
  15.  
  16.     c = 90
  17.     FOR i = a TO a - _PI(.85) STEP -.001
  18.         PSET (_WIDTH / 2 + COS(i - _PI) * c, _HEIGHT / 2 + SIN(i - _PI) * c)
  19.         PSET (_WIDTH / 2 + COS(i) * c, _HEIGHT / 2 + SIN(i) * c)
  20.     NEXT
  21.     CircleFill _WIDTH / 2 + COS(a - _PI) * c, _HEIGHT / 2 + SIN(a - _PI) * c, 10, _DEFAULTCOLOR
  22.     CircleFill _WIDTH / 2 + COS(a) * c, _HEIGHT / 2 + SIN(a) * c, 10, _DEFAULTCOLOR
  23.  
  24.     d = 180
  25.     FOR i = b TO b - _PI(.85) STEP -.001
  26.         PSET (_WIDTH / 2 + COS(i - _PI) * d, _HEIGHT / 2 + SIN(i - _PI) * d)
  27.         PSET (_WIDTH / 2 + COS(i) * d, _HEIGHT / 2 + SIN(i) * d)
  28.     NEXT
  29.     CircleFill _WIDTH / 2 + COS(b - _PI) * d, _HEIGHT / 2 + SIN(b - _PI) * d, 20, _DEFAULTCOLOR
  30.     CircleFill _WIDTH / 2 + COS(b) * d, _HEIGHT / 2 + SIN(b) * d, 20, _DEFAULTCOLOR
  31.  
  32.     _DISPLAY
  33.     _LIMIT 30
  34.  
  35. SUB CircleFill (x AS LONG, y AS LONG, R AS LONG, C AS _UNSIGNED LONG)
  36.     DIM x0 AS SINGLE, y0 AS SINGLE
  37.     DIM e AS SINGLE
  38.  
  39.     x0 = R
  40.     y0 = 0
  41.     e = -R
  42.     DO WHILE y0 < x0
  43.         IF e <= 0 THEN
  44.             y0 = y0 + 1
  45.             LINE (x - x0, y + y0)-(x + x0, y + y0), C, BF
  46.             LINE (x - x0, y - y0)-(x + x0, y - y0), C, BF
  47.             e = e + 2 * y0
  48.         ELSE
  49.             LINE (x - y0, y - x0)-(x + y0, y - x0), C, BF
  50.             LINE (x - y0, y + x0)-(x + y0, y + x0), C, BF
  51.             x0 = x0 - 1
  52.             e = e - 2 * x0
  53.         END IF
  54.     LOOP
  55.     LINE (x - R, y)-(x + R, y), C, BF

I like to watch them align from time to time.

Title: Re: Reddit's mobile app loading animation
Post by: Pete on February 05, 2019, 07:02:13 pm
Look Mark, more balls. Go get 'em boy!

Pete :D
Title: Re: Reddit's mobile app loading animation
Post by: STxAxTIC on February 05, 2019, 07:21:16 pm
That CircleFill routine looks familiar - on the other hand I suppose it *should*, because like the irreducible mousetrap, there really are one, maybe two, correct ways to fill a circle in this language. The thing that interests me right now is the choice of of variable types:

Code: QB64: [Select]
  1. SUB CircleFill (x AS LONG, y AS LONG, R AS LONG, C AS _UNSIGNED LONG)
  2.     DIM x0 AS SINGLE, y0 AS SINGLE
  3.     DIM e AS SINGLE

So the sub takes LONGs for coordinates, but then cooks up helper variables that are SINGLE. Shoudn't these types agree? When you go to compute x-x0 for instance, doesn't the result lose any LONGness that may have been intended? (Not to mention, as a pure numbers thing, LONG has way more precision than is necessary to put color on a screen only few thousand pixels wide at best.)

Not a critique, just wanna make a little smoke.
Title: Re: Reddit's mobile app loading animation
Post by: FellippeHeitor on February 05, 2019, 07:54:58 pm
I'll refer you to Vince on that one. He provided me with that code for our (mine and Ashish's) p5js.bas library (https://github.com/FellippeHeitor/p5js.bas), so I have no idea what goes there, except it works :-)
Title: Re: Reddit's mobile app loading animation
Post by: _vince on February 05, 2019, 08:40:16 pm
vince's circle fill

Code: QB64: [Select]
  1. defint a-z
  2. sub circlef (x, y, r, c as long)
  3.         x0 = r
  4.         y0 = 0
  5.         e = -r
  6.         do while y0 < x0
  7.                 if e <= 0 then
  8.                         y0 = y0 + 1
  9.                         line (x-x0, y+y0)-(x+x0, y+y0), c, bf
  10.                         line (x-x0, y-y0)-(x+x0, y-y0), c, bf
  11.                         e = e + 2*y0
  12.                 else
  13.                         line (x-y0, y-x0)-(x+y0, y-x0), c, bf
  14.                         line (x-y0, y+x0)-(x+y0, y+x0), c, bf
  15.                         x0 = x0 - 1
  16.                         e = e - 2*x0
  17.                 end if
  18.         loop
  19.         line (x-r,y)-(x+r,y),c,bf
  20.  
Title: Re: Reddit's mobile app loading animation
Post by: bplus on February 06, 2019, 10:11:22 am
That CircleFill routine looks familiar - on the other hand I suppose it *should*, because like the irreducible mousetrap, there really are one, maybe two, correct ways to fill a circle in this language. The thing that interests me right now is the choice of of variable types:

Code: QB64: [Select]
  1. SUB CircleFill (x AS LONG, y AS LONG, R AS LONG, C AS _UNSIGNED LONG)
  2.     DIM x0 AS SINGLE, y0 AS SINGLE
  3.     DIM e AS SINGLE

So the sub takes LONGs for coordinates, but then cooks up helper variables that are SINGLE. Shoudn't these types agree? When you go to compute x-x0 for instance, doesn't the result lose any LONGness that may have been intended? (Not to mention, as a pure numbers thing, LONG has way more precision than is necessary to put color on a screen only few thousand pixels wide at best.)

Not a critique, just wanna make a little smoke.


Smoke this:
IMO State of the art with Circle Fill is this:
Code: QB64: [Select]
  1. ' with Steve's EllipseFill, who needs CircleFill?
  2. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  3. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  4. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  5.     DIM a AS LONG, b AS LONG
  6.     DIM x AS LONG, y AS LONG
  7.     DIM xx AS LONG, yy AS LONG
  8.     DIM sx AS LONG, sy AS LONG
  9.     DIM e AS LONG
  10.  
  11.     a = 2 * rx * rx
  12.     b = 2 * ry * ry
  13.     x = rx
  14.     xx = ry * ry * (1 - rx - rx)
  15.     yy = rx * rx
  16.     sx = b * rx
  17.  
  18.     DO WHILE sx >= sy
  19.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  20.         IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  21.  
  22.         y = y + 1
  23.         sy = sy + a
  24.         e = e + yy
  25.         yy = yy + a
  26.  
  27.         IF (e + e + xx) > 0 THEN
  28.             x = x - 1
  29.             sx = sx - b
  30.             e = e + xx
  31.             xx = xx + b
  32.         END IF
  33.     LOOP
  34.  
  35.     x = 0
  36.     y = ry
  37.     xx = rx * ry
  38.     yy = rx * rx * (1 - ry - ry)
  39.     e = 0
  40.     sx = 0
  41.     sy = a * ry
  42.  
  43.     DO WHILE sx <= sy
  44.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  45.         LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  46.  
  47.         DO
  48.             x = x + 1
  49.             sx = sx + b
  50.             e = e + xx
  51.             xx = xx + b
  52.         LOOP UNTIL (e + e + yy) > 0
  53.  
  54.         y = y - 1
  55.         sy = sy - a
  56.         e = e + yy
  57.         yy = yy + a
  58.  
  59.     LOOP
  60.  

We had a conversation and tests for Circle Fill in June 2018 but then Steve comes up with an Ellipse Fill in November 2018 that turns out to be at least as fast and a more general solution to filled ellipse (including circles), see ref links in code above.

About typing, the parameters are integer but the working variables need to be long (at least) for mult and squaring integers.

Being a ball enthusiast I guess I am the only one that noticed?
Title: Re: Reddit's mobile app loading animation
Post by: STxAxTIC on February 06, 2019, 10:41:02 am
Sure, ellipsefill is better than circlefill for ellipses that aren't tilted, if I read that code correctly. The circlefill codes are by that standard, more general by symmetry argument. Can that handle a rotated filled ellipse? I stand corrected if it can.
Title: Re: Reddit's mobile app loading animation
Post by: _vince on February 06, 2019, 11:20:49 am
but then Steve comes up with an Ellipse Fill in November 2018 that turns out to be at least as fast and a more general solution to filled ellipse (including circles),

That Steve!!!

Some funny stuff:
Code: QB64: [Select]
  1. xx = ry * ry * (1 - rx - rx)
  2. IF (e + e + xx) > 0 THEN
  3.  
That's on a Steve level of ultraoptimization
Title: Re: Reddit's mobile app loading animation
Post by: bplus on February 06, 2019, 11:28:33 am
Sure, ellipsefill is better than circlefill for ellipses that aren't tilted, if I read that code correctly. The circlefill codes are by that standard, more general by symmetry argument. Can that handle a rotated filled ellipse? I stand corrected if it can.

? A circle is a special kind of ellipse, thus I say the ellipse is more general than a circle, like a square is a special case of rectangles which are special cases of quads. (EDIT: I guess I should have said a more general solution to filled circles, not filled ellipses.)

And yes, so far ellipses can't be tilted. Good challenge though!
Title: Re: Reddit's mobile app loading animation
Post by: bplus on February 06, 2019, 11:36:05 am
Code: QB64: [Select]
  1.  
  2. SCREEN _NEWIMAGE(400, 400, 32)
  3.  
  4. _TITLE "Loading Animation Ellipse mod" 'B+ mod 2019-02-06
  5. ' Fellipe's original: https://www.qb64.org/forum/index.php?topic=1042.0
  6.  
  7. COLOR _RGBA32(39, 78, 177, 10)
  8. c = 100: c1 = 35
  9. d = 140: d1 = 180
  10. b = _PI(.25)
  11. cx = 200: cy = 200
  12.     CLS
  13.     FOR r = 20 TO 1 STEP -1
  14.         EllipseFill cx, cy, r, r, _RGB32(12 * (25 - r), 12 * (25 - r), 12 * (25 - r))
  15.     NEXT
  16.  
  17.     a = a + .05
  18.     b = b + .025
  19.     IF a > _PI(2) THEN a = _PI(2) - a
  20.     IF b > _PI(2) THEN b = _PI(2) - b
  21.  
  22.     FOR i = a TO a - _PI(.85) STEP -.001
  23.         PSET (cx + COS(i - _PI) * c, cy + SIN(i - _PI) * c1)
  24.         PSET (cx + COS(i) * c, cy + SIN(i) * c1)
  25.     NEXT
  26.     FOR r = 10 TO 1 STEP -1
  27.         k = (10 - r) * 25
  28.         EllipseFill cx + COS(a - _PI) * c, cy + SIN(a - _PI) * c1, r, r, _RGB32(k, k, 0)
  29.         EllipseFill cx + COS(a) * c, cy + SIN(a) * c1, r, r, _RGB32(k, 0, k)
  30.     NEXT
  31.     FOR i = b TO b - _PI(.85) STEP -.001
  32.         PSET (cx + COS(i - _PI) * d, cy + SIN(i - _PI) * d1)
  33.         PSET (cx + COS(i) * d, cy + SIN(i) * d1)
  34.     NEXT
  35.     FOR r = 20 TO 1 STEP -1
  36.         k = (20 - r) * 6
  37.         EllipseFill cx + COS(b - _PI) * d, cy + SIN(b - _PI) * d1, r, r, _RGB32(0, k, 0)
  38.         EllipseFill cx + COS(b) * d, cy + SIN(b) * d1, r, r, _RGB32(k, 0, 0)
  39.     NEXT
  40.     _DISPLAY
  41.     _LIMIT 30
  42.  
  43.  
  44. ' with Steve's EllipseFill, who needs CircleFill?
  45. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  46. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  47. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  48.     DIM a AS LONG, b AS LONG
  49.     DIM x AS LONG, y AS LONG
  50.     DIM xx AS LONG, yy AS LONG
  51.     DIM sx AS LONG, sy AS LONG
  52.     DIM e AS LONG
  53.  
  54.     a = 2 * rx * rx
  55.     b = 2 * ry * ry
  56.     x = rx
  57.     xx = ry * ry * (1 - rx - rx)
  58.     yy = rx * rx
  59.     sx = b * rx
  60.  
  61.     DO WHILE sx >= sy
  62.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  63.         IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  64.  
  65.         y = y + 1
  66.         sy = sy + a
  67.         e = e + yy
  68.         yy = yy + a
  69.  
  70.         IF (e + e + xx) > 0 THEN
  71.             x = x - 1
  72.             sx = sx - b
  73.             e = e + xx
  74.             xx = xx + b
  75.         END IF
  76.     LOOP
  77.  
  78.     x = 0
  79.     y = ry
  80.     xx = rx * ry
  81.     yy = rx * rx * (1 - ry - ry)
  82.     e = 0
  83.     sx = 0
  84.     sy = a * ry
  85.  
  86.     DO WHILE sx <= sy
  87.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  88.         LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  89.  
  90.         DO
  91.             x = x + 1
  92.             sx = sx + b
  93.             e = e + xx
  94.             xx = xx + b
  95.         LOOP UNTIL (e + e + yy) > 0
  96.  
  97.         y = y - 1
  98.         sy = sy - a
  99.         e = e + yy
  100.         yy = yy + a
  101.  
  102.     LOOP
  103.  
  104.  
  105.  

 


Append: Oh! I should report: While creating this mod, I learned that EllipseFill can't take a radius of 0, the routine needs a fix.
Title: Re: Reddit's mobile app loading animation
Post by: FellippeHeitor on February 06, 2019, 11:52:05 am
Cool mod, bplus!
Title: Re: Reddit's mobile app loading animation
Post by: STxAxTIC on February 06, 2019, 12:18:22 pm
... and if you want to blow your balls up, run this thing. Download both attachments, and load data-reddit.txt as an argument. (Drop onto Sanctum.exe). While running, press (and hold if you wish) n to witness some destruction. Things don't just blow up and disappear when you do that. They dismantle, particle-by-particle, into a puddle at z=0. If you've got the pilot skills, go blow up the moon and the UFO afterward.

Code: QB64: [Select]
  1. $EXEICON:'sanctum.ico'
  2. REM $include:'Color32.BI'
  3.  
  4. ' Video.
  5. SCREEN _NEWIMAGE(640, 480, 32)
  6. 'SCREEN _NEWIMAGE(800, 600, 32)
  7. 'SCREEN _NEWIMAGE(1024, 768, 32)
  8. screenwidth = _WIDTH
  9. screenheight = _HEIGHT
  10. plotmode = 1
  11.  
  12. ' Memory.
  13. DIM bignumber AS LONG
  14. bignumber = 3000000
  15. DIM numparticleorig AS LONG
  16. numparticleorig = bignumber
  17. numparticlevisible = bignumber
  18. numgroupvisible = 0
  19.  
  20. ' Structure to store groups of particles.
  21. TYPE GroupElement
  22.     Identity AS LONG
  23.     Pointer AS LONG
  24.     Lagger AS LONG
  25.     ContentName AS STRING * 25
  26.     FirstParticle AS LONG
  27.     LastParticle AS LONG
  28.     EventTimer AS LONG
  29.     COMx AS SINGLE
  30.     COMy AS SINGLE
  31.     COMz AS SINGLE
  32.     CORx AS SINGLE
  33.     CORy AS SINGLE
  34.     CORz AS SINGLE
  35. DIM VectorGroup(bignumber / 10) AS GroupElement
  36.  
  37. ' Constant(s).
  38. pi = 3.1415926536
  39. ee = 2.7182818285
  40.  
  41. ' Camera orientation vectors.
  42. DIM uhat(1 TO 3), vhat(1 TO 3), nhat(1 TO 3)
  43.  
  44. ' Clipping planes.
  45. DIM nearplane(1 TO 4), farplane(1 TO 4), rightplane(1 TO 4), leftplane(1 TO 4), topplane(1 TO 4), bottomplane(1 TO 4)
  46.  
  47. ' Basis vectors defined in xyz three-space.
  48. DIM xhat(1 TO 3), yhat(1 TO 3), zhat(1 TO 3)
  49. xhat(1) = 1: xhat(2) = 0: xhat(3) = 0
  50. yhat(1) = 0: yhat(2) = 1: yhat(3) = 0
  51. zhat(1) = 0: zhat(2) = 0: zhat(3) = 1
  52.  
  53. ' Basis vectors projected in uv two-space.
  54. DIM xhatp(1 TO 2), yhatp(1 TO 2), zhatp(1 TO 2)
  55.  
  56. ' Particle vectors defined in xyz three-space.
  57. DIM vecgroupname(bignumber / 10) AS STRING
  58. DIM vecorig(numparticleorig, 3)
  59. DIM vecorigvel(numparticleorig, 3)
  60. DIM vecorigrot(numparticleorig, 3)
  61. DIM vecorigacc(numparticleorig, 3)
  62. DIM veccolor(numparticleorig) AS LONG
  63. DIM vec(numparticleorig, 3)
  64. DIM vecvisible(numparticlevisible, 3)
  65. DIM vecvisiblecolor(numparticlevisible) AS LONG
  66.  
  67. ' Particle vectors projected in uv two-space.
  68. DIM vecpuv(numparticleorig, 1 TO 2)
  69. DIM vecvisiblepuv(numparticlevisible, 1 TO 2)
  70.  
  71. ' Particle projections adjusted for screen uv two-space.
  72. DIM vecpuvs(numparticleorig, 1 TO 2)
  73. DIM vecvisiblepuvs(numparticlevisible, 1 TO 2)
  74.  
  75. ' State.
  76. nearplane(4) = 1
  77. farplane(4) = -100
  78. rightplane(4) = 0 '*' fovd * (nhat(1) * rightplane(1) + nhat(2) * rightplane(2) + nhat(3) * rightplane(3))
  79. leftplane(4) = 0
  80. topplane(4) = 0
  81. bottomplane(4) = 0
  82. centerx = screenwidth / 2
  83. centery = screenheight / 2
  84. fovd = -256
  85. numparticleorig = 0
  86. numparticlevisible = 0
  87. particleindex = 0
  88. vecgroupcounter = 0
  89. vecgroupindex = 0
  90. speeddamp = 1 / 66 ' Rotation damper.
  91. speedboost = 1.5 ' Linear boost.
  92. timevar = 0
  93. 'camx = -42
  94. 'camy = 28
  95. 'camz = 40
  96. camx = 18.69336: camy = 24.12129: camz = 20.24639
  97. uhat(1) = -1: uhat(2) = 0: uhat(3) = 0
  98. vhat(1) = 0: vhat(2) = 0: vhat(3) = 1
  99. 'uhat(1) = -.2078192: uhat(2) = -.9781672: uhat(3) = 0
  100. 'vhat(1) = 0: vhat(2) = 0: vhat(3) = 1
  101. toggleanimatestandard = 1
  102. toggleanimateforced = 1
  103. toggleinvertmouse = -1
  104. togglehud = -1
  105.  
  106. ' Prime main loop.
  107. GOSUB initialize.objects
  108. GOSUB redraw
  109.  
  110. ' Begin main loop.
  111.     IF toggleanimatestandard = 1 THEN flagredraw = 1
  112.     IF flagredraw = 1 THEN
  113.         GOSUB redraw
  114.         flagredraw = -1
  115.     END IF
  116.     GOSUB mouseprocess
  117.     GOSUB keyprocess
  118.  
  119.     _DISPLAY
  120.     _KEYCLEAR
  121.     _LIMIT 60
  122.  
  123.  
  124. ' Gosubs.
  125.  
  126. mouseprocess:
  127. mx = 0
  128. my = 0
  129.     mx = mx + _MOUSEMOVEMENTX
  130.     my = my + _MOUSEMOVEMENTY
  131.  
  132.     IF _MOUSEWHEEL > 0 THEN GOSUB rotate.clockwise
  133.     IF _MOUSEWHEEL < 0 THEN GOSUB rotate.counterclockwise
  134.     IF mx > 0 THEN
  135.         GOSUB rotate.uhat.plus: GOSUB normalize.screen.vectors
  136.     END IF
  137.     IF mx < 0 THEN
  138.         GOSUB rotate.uhat.minus: GOSUB normalize.screen.vectors
  139.     END IF
  140.     IF my > 0 THEN
  141.         IF toggleinvertmouse = -1 THEN
  142.             GOSUB rotate.vhat.plus: GOSUB normalize.screen.vectors
  143.         ELSE
  144.             GOSUB rotate.vhat.minus: GOSUB normalize.screen.vectors
  145.         END IF
  146.     END IF
  147.     IF my < 0 THEN
  148.         IF toggleinvertmouse = -1 THEN
  149.             GOSUB rotate.vhat.minus: GOSUB normalize.screen.vectors
  150.         ELSE
  151.             GOSUB rotate.vhat.plus: GOSUB normalize.screen.vectors
  152.         END IF
  153.     END IF
  154.     mx = 0
  155.     my = 0
  156.  
  157. 'MouseLB = _MOUSEBUTTON(1)
  158. 'MouseRB = _MOUSEBUTTON(2)
  159. flagredraw = 1
  160.  
  161. keyprocess:
  162. IF key$ <> "" THEN flagredraw = 1
  163.     CASE "8", CHR$(0) + CHR$(73)
  164.         GOSUB rotate.vhat.plus
  165.     CASE "2", CHR$(0) + CHR$(81)
  166.         GOSUB rotate.vhat.minus
  167.     CASE "4", CHR$(0) + CHR$(75)
  168.         GOSUB rotate.uhat.minus
  169.     CASE "6", CHR$(0) + CHR$(77)
  170.         GOSUB rotate.uhat.plus
  171.     CASE "7"
  172.         GOSUB rotate.clockwise
  173.     CASE "9"
  174.         GOSUB rotate.counterclockwise
  175.     CASE "1"
  176.         GOSUB rotate.uhat.minus: GOSUB normalize.screen.vectors: GOSUB rotate.clockwise
  177.     CASE "3"
  178.         GOSUB rotate.uhat.plus: GOSUB normalize.screen.vectors: GOSUB rotate.counterclockwise
  179.     CASE "s", CHR$(0) + CHR$(80)
  180.         GOSUB strafe.camera.nhat.plus
  181.     CASE "w", CHR$(0) + CHR$(72)
  182.         GOSUB strafe.camera.nhat.minus
  183.     CASE "d"
  184.         GOSUB strafe.camera.uhat.plus
  185.     CASE "a"
  186.         GOSUB strafe.camera.uhat.minus
  187.     CASE "e"
  188.         GOSUB strafe.camera.vhat.plus
  189.     CASE "q"
  190.         GOSUB strafe.camera.vhat.minus
  191.     CASE "x"
  192.         uhat(1) = 0: uhat(2) = 1: uhat(3) = 0
  193.         vhat(1) = 0: vhat(2) = 0: vhat(3) = 1
  194.     CASE "X"
  195.         uhat(1) = 0: uhat(2) = -1: uhat(3) = 0
  196.         vhat(1) = 0: vhat(2) = 0: vhat(3) = 1
  197.     CASE "y"
  198.         uhat(1) = -1: uhat(2) = 0: uhat(3) = 0
  199.         vhat(1) = 0: vhat(2) = 0: vhat(3) = 1
  200.     CASE "Y"
  201.         uhat(1) = 1: uhat(2) = 0: uhat(3) = 0
  202.         vhat(1) = 0: vhat(2) = 0: vhat(3) = 1
  203.     CASE "z"
  204.         uhat(1) = 1: uhat(2) = 0: uhat(3) = 0
  205.         vhat(1) = 0: vhat(2) = 1: vhat(3) = 0
  206.         GOSUB normalize.screen.vectors
  207.     CASE "Z"
  208.         uhat(1) = 0: uhat(2) = 1: uhat(3) = 0
  209.         vhat(1) = 1: vhat(2) = 0: vhat(3) = 0
  210.     CASE "]"
  211.         farplane(4) = farplane(4) - 1
  212.     CASE "["
  213.         farplane(4) = farplane(4) + 1
  214.     CASE " "
  215.         togglehud = -togglehud
  216.     CASE "t"
  217.         toggleanimatestandard = -toggleanimatestandard
  218.     CASE "i"
  219.         toggleinvertmouse = -toggleinvertmouse
  220.     CASE "p"
  221.         plotmode = -plotmode
  222.     CASE "v"
  223.         OPEN "snapshot-camera.txt" FOR OUTPUT AS #1
  224.         PRINT #1, camx, camy, camz
  225.         PRINT #1, uhat(1), uhat(2), uhat(3)
  226.         PRINT #1, vhat(1), vhat(2), vhat(3)
  227.         CLOSE #1
  228.     CASE CHR$(27)
  229.         SYSTEM
  230.     CASE "f"
  231.         explodex = camx - nhat(1) * (1 - .1 * RND) * 60
  232.         explodey = camy - nhat(2) * (1 - .1 * RND) * 60
  233.         explodez = camz - nhat(3) * (1 - .1 * RND) * 60
  234.         GOSUB explode
  235.     CASE "n"
  236.         VectorGroup(closestgroup).ContentName = "Newtonian"
  237.         FOR particleindex = VectorGroup(closestgroup).FirstParticle TO VectorGroup(closestgroup).LastParticle
  238.             vecorigvel(particleindex, 1) = (RND - .5) * 20
  239.             vecorigvel(particleindex, 2) = (RND - .5) * 20
  240.             vecorigvel(particleindex, 3) = (RND - .5) * 20
  241.             vecorigacc(particleindex, 3) = -30
  242.         NEXT
  243.         VectorGroup(closestgroup).EventTimer = INT(TIMER)
  244.     CASE "k"
  245.         'IF LTRIM$(RTRIM$(VectorGroup(closestgroup).ContentName)) <> "Sparks" THEN
  246.         explodex = VectorGroup(closestgroup).COMx
  247.         explodey = VectorGroup(closestgroup).COMy
  248.         explodez = VectorGroup(closestgroup).COMz
  249.         GOSUB explode
  250.         p = VectorGroup(closestgroup).Pointer
  251.         l = VectorGroup(closestgroup).Lagger
  252.         VectorGroup(l).Pointer = p
  253.         IF p <> -999 THEN
  254.             VectorGroup(p).Lagger = l
  255.         ELSE
  256.             'determine last object id
  257.             p = 1
  258.             DO
  259.                 k = VectorGroup(p).Identity
  260.                 p = VectorGroup(k).Pointer
  261.                 IF p = -999 THEN EXIT DO
  262.             LOOP
  263.             lastobjectid = k
  264.             VectorGroup(lastobjectid).Pointer = -999
  265.         END IF
  266.         'END IF
  267.     CASE "b"
  268.         'determine last object id
  269.         p = 1
  270.         DO
  271.             k = VectorGroup(p).Identity
  272.             p = VectorGroup(k).Pointer
  273.             IF p = -999 THEN EXIT DO
  274.         LOOP
  275.         lastobjectid = k
  276.         particleindex = VectorGroup(lastobjectid).LastParticle
  277.         'create new group
  278.         vecgroupcounter = vecgroupcounter + 1
  279.         vecgroupindex = vecgroupcounter
  280.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  281.         VectorGroup(vecgroupindex).Pointer = -999
  282.         VectorGroup(vecgroupindex).Lagger = lastobjectid
  283.         VectorGroup(vecgroupindex).ContentName = "Block"
  284.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  285.         FOR r = 1 TO 400
  286.             particleindex = particleindex + 1
  287.             vecorig(particleindex, 1) = camx + -40 * nhat(1) + RND * tilesize / 2
  288.             vecorig(particleindex, 2) = camy + -40 * nhat(2) + RND * tilesize / 2
  289.             vecorig(particleindex, 3) = camz + -40 * nhat(3) + RND * tilesize / 2
  290.             IF RND > .5 THEN
  291.                 veccolor(particleindex) = Lime
  292.             ELSE
  293.                 veccolor(particleindex) = Purple
  294.             END IF
  295.             GOSUB calccom
  296.         NEXT
  297.         VectorGroup(vecgroupindex).LastParticle = particleindex
  298.         GOSUB adjustcom
  299.         'connect new group to last group
  300.         VectorGroup(lastobjectid).Pointer = vecgroupindex
  301.  
  302. convert:
  303. ' Convert graphics from uv-cartesian coordinates to monitor coordinates.
  304. x0 = x: y0 = y
  305. x = x0 + centerx
  306. y = -y0 + centery
  307.  
  308. rotate.uhat.plus:
  309. uhat(1) = uhat(1) + nhat(1) * speeddamp
  310. uhat(2) = uhat(2) + nhat(2) * speeddamp
  311. uhat(3) = uhat(3) + nhat(3) * speeddamp
  312.  
  313. rotate.uhat.minus:
  314. uhat(1) = uhat(1) - nhat(1) * speeddamp
  315. uhat(2) = uhat(2) - nhat(2) * speeddamp
  316. uhat(3) = uhat(3) - nhat(3) * speeddamp
  317.  
  318. rotate.vhat.plus:
  319. vhat(1) = vhat(1) + nhat(1) * speeddamp
  320. vhat(2) = vhat(2) + nhat(2) * speeddamp
  321. vhat(3) = vhat(3) + nhat(3) * speeddamp
  322.  
  323. rotate.vhat.minus:
  324. vhat(1) = vhat(1) - nhat(1) * speeddamp
  325. vhat(2) = vhat(2) - nhat(2) * speeddamp
  326. vhat(3) = vhat(3) - nhat(3) * speeddamp
  327.  
  328. rotate.counterclockwise:
  329. v1 = vhat(1)
  330. v2 = vhat(2)
  331. v3 = vhat(3)
  332. vhat(1) = vhat(1) + uhat(1) * speeddamp
  333. vhat(2) = vhat(2) + uhat(2) * speeddamp
  334. vhat(3) = vhat(3) + uhat(3) * speeddamp
  335. uhat(1) = uhat(1) - v1 * speeddamp
  336. uhat(2) = uhat(2) - v2 * speeddamp
  337. uhat(3) = uhat(3) - v3 * speeddamp
  338.  
  339. rotate.clockwise:
  340. v1 = vhat(1)
  341. v2 = vhat(2)
  342. v3 = vhat(3)
  343. vhat(1) = vhat(1) - uhat(1) * speeddamp
  344. vhat(2) = vhat(2) - uhat(2) * speeddamp
  345. vhat(3) = vhat(3) - uhat(3) * speeddamp
  346. uhat(1) = uhat(1) + v1 * speeddamp
  347. uhat(2) = uhat(2) + v2 * speeddamp
  348. uhat(3) = uhat(3) + v3 * speeddamp
  349.  
  350. strafe.camera.uhat.plus:
  351. camx = camx + uhat(1) * speedboost
  352. camy = camy + uhat(2) * speedboost
  353. camz = camz + uhat(3) * speedboost
  354.  
  355. strafe.camera.uhat.minus:
  356. camx = camx - uhat(1) * speedboost
  357. camy = camy - uhat(2) * speedboost
  358. camz = camz - uhat(3) * speedboost
  359.  
  360. strafe.camera.vhat.plus:
  361. camx = camx + vhat(1) * speedboost
  362. camy = camy + vhat(2) * speedboost
  363. camz = camz + vhat(3) * speedboost
  364.  
  365. strafe.camera.vhat.minus:
  366. camx = camx - vhat(1) * speedboost
  367. camy = camy - vhat(2) * speedboost
  368. camz = camz - vhat(3) * speedboost
  369.  
  370. strafe.camera.nhat.plus:
  371. camx = camx + nhat(1) * speedboost
  372. camy = camy + nhat(2) * speedboost
  373. camz = camz + nhat(3) * speedboost
  374.  
  375. strafe.camera.nhat.minus:
  376. camx = camx - nhat(1) * speedboost
  377. camy = camy - nhat(2) * speedboost
  378. camz = camz - nhat(3) * speedboost
  379.  
  380. normalize.screen.vectors:
  381. uhatmag = SQR(uhat(1) ^ 2 + uhat(2) ^ 2 + uhat(3) ^ 2)
  382. uhat(1) = uhat(1) / uhatmag: uhat(2) = uhat(2) / uhatmag: uhat(3) = uhat(3) / uhatmag
  383. vhatmag = SQR(vhat(1) ^ 2 + vhat(2) ^ 2 + vhat(3) ^ 2)
  384. vhat(1) = vhat(1) / vhatmag: vhat(2) = vhat(2) / vhatmag: vhat(3) = vhat(3) / vhatmag
  385. uhatdotvhat = uhat(1) * vhat(1) + uhat(2) * vhat(2) + uhat(3) * vhat(3)
  386. IF SQR(uhatdotvhat ^ 2) > .0005 THEN
  387.     BEEP ' ... if vectors are somenow not normalized. This has never happened.
  388.     uhat(1) = 0.8251367: uhat(2) = -0.564903: uhat(3) = -0.005829525
  389.     vhat(1) = 0.065519: vhat(2) = 0.08544215: vhat(3) = 0.9941866
  390. ' The normal vector points toward the eye.
  391. nhat(1) = uhat(2) * vhat(3) - uhat(3) * vhat(2)
  392. nhat(2) = uhat(3) * vhat(1) - uhat(1) * vhat(3)
  393. nhat(3) = uhat(1) * vhat(2) - uhat(2) * vhat(1)
  394. nhatmag = SQR(nhat(1) ^ 2 + nhat(2) ^ 2 + nhat(3) ^ 2)
  395. nhat(1) = nhat(1) / nhatmag: nhat(2) = nhat(2) / nhatmag: nhat(3) = nhat(3) / nhatmag
  396.  
  397. redraw:
  398. GOSUB normalize.screen.vectors
  399. GOSUB calculate.clippingplanes
  400. ' Project the three-space basis vectors onto the screen plane.
  401. xhatp(1) = xhat(1) * uhat(1) + xhat(2) * uhat(2) + xhat(3) * uhat(3)
  402. xhatp(2) = xhat(1) * vhat(1) + xhat(2) * vhat(2) + xhat(3) * vhat(3)
  403. yhatp(1) = yhat(1) * uhat(1) + yhat(2) * uhat(2) + yhat(3) * uhat(3)
  404. yhatp(2) = yhat(1) * vhat(1) + yhat(2) * vhat(2) + yhat(3) * vhat(3)
  405. zhatp(1) = zhat(1) * uhat(1) + zhat(2) * uhat(2) + zhat(3) * uhat(3)
  406. zhatp(2) = zhat(1) * vhat(1) + zhat(2) * vhat(2) + zhat(3) * vhat(3)
  407. GOSUB compute.visible.groups
  408. GOSUB project.particles
  409. GOSUB draw.all.objects
  410.  
  411. compute.visible.groups:
  412. numparticlevisible = 0
  413. numgroupvisible = 0
  414. closestdist2 = 10000 ^ 2
  415. closestgroup = 1
  416. ci = -1
  417. cf = -1
  418.  
  419. k = 1
  420. k = VectorGroup(k).Identity
  421.  
  422.     xcom = VectorGroup(k).COMx
  423.     ycom = VectorGroup(k).COMy
  424.     zcom = VectorGroup(k).COMz
  425.     thename$ = LTRIM$(RTRIM$(VectorGroup(k).ContentName))
  426.  
  427.     ' Force animation regardless of distance from camera.
  428.     IF thename$ = "Rotor" THEN
  429.         vecgroupindex = k
  430.         GOSUB animateforced
  431.     END IF
  432.  
  433.     dist2 = (camx - xcom) ^ 2 + (camy - ycom) ^ 2 + (camz - zcom) ^ 2
  434.  
  435.     IF dist2 < farplane(4) ^ 2 THEN
  436.  
  437.         groupinview = 1 ' Disable near plane group clipping to make things more interesting at zero distance.
  438.         'IF (xcom - camx) * nearplane(1) + (ycom - camy) * nearplane(2) + (zcom - camz) * nearplane(3) - nearplane(4) < 0 THEN groupinview = 0
  439.         'IF (xcom - camx) * farplane(1) + (ycom - camy) * farplane(2) + (zcom - camz) * farplane(3) - farplane(4) < 0 THEN groupinview = 0
  440.         IF (xcom - camx) * rightplane(1) + (ycom - camy) * rightplane(2) + (zcom - camz) * rightplane(3) - rightplane(4) < 0 THEN groupinview = 0
  441.         IF (xcom - camx) * leftplane(1) + (ycom - camy) * leftplane(2) + (zcom - camz) * leftplane(3) - leftplane(4) < 0 THEN groupinview = 0
  442.         IF (xcom - camx) * topplane(1) + (ycom - camy) * topplane(2) + (zcom - camz) * topplane(3) - topplane(4) < 0 THEN groupinview = 0
  443.         IF (xcom - camx) * bottomplane(1) + (ycom - camy) * bottomplane(2) + (zcom - camz) * bottomplane(3) - bottomplane(4) < 0 THEN groupinview = 0
  444.         IF groupinview = 1 THEN
  445.  
  446.             numgroupvisible = numgroupvisible + 1
  447.  
  448.             IF toggleanimatestandard = 1 THEN
  449.                 vecgroupindex = k
  450.                 GOSUB animatestandard
  451.             END IF
  452.  
  453.             IF dist2 < closestdist2 AND thename$ <> "Sparks" AND thename$ <> "Newtonian" THEN
  454.                 closestdist2 = dist2
  455.                 closestgroup = k
  456.             END IF
  457.  
  458.             IF k = closestgroup THEN ci = numparticlevisible
  459.  
  460.             FOR i = VectorGroup(k).FirstParticle TO VectorGroup(k).LastParticle
  461.                 vec(i, 1) = vecorig(i, 1) - camx
  462.                 vec(i, 2) = vecorig(i, 2) - camy
  463.                 vec(i, 3) = vecorig(i, 3) - camz
  464.                 GOSUB clip.particle.viewplanes
  465.             NEXT
  466.  
  467.             IF k = closestgroup THEN cf = numparticlevisible
  468.  
  469.         END IF
  470.  
  471.     END IF
  472.  
  473.     k = VectorGroup(k).Pointer
  474.     IF k = -999 THEN EXIT DO
  475.     k = VectorGroup(k).Identity
  476.  
  477.  
  478. IF ci <> -1 AND cf <> -1 THEN
  479.     FOR i = ci TO cf
  480.         vecvisiblecolor(i) = Yellow
  481.     NEXT
  482.  
  483.  
  484. clip.particle.viewplanes:
  485. ' requires i
  486. particleinview = 1
  487. fogswitch = -1
  488. ' Perform standard view plane clipping and implement fog effect.
  489. IF vec(i, 1) * nearplane(1) + vec(i, 2) * nearplane(2) + vec(i, 3) * nearplane(3) - nearplane(4) < 0 THEN particleinview = 0
  490. IF vec(i, 1) * farplane(1) + vec(i, 2) * farplane(2) + vec(i, 3) * farplane(3) - farplane(4) < 0 THEN particleinview = 0
  491. IF vec(i, 1) * farplane(1) + vec(i, 2) * farplane(2) + vec(i, 3) * farplane(3) - farplane(4) * .9 < 0 THEN fogswitch = 1
  492. IF vec(i, 1) * rightplane(1) + vec(i, 2) * rightplane(2) + vec(i, 3) * rightplane(3) - rightplane(4) < 0 THEN particleinview = 0
  493. IF vec(i, 1) * leftplane(1) + vec(i, 2) * leftplane(2) + vec(i, 3) * leftplane(3) - leftplane(4) < 0 THEN particleinview = 0
  494. IF vec(i, 1) * topplane(1) + vec(i, 2) * topplane(2) + vec(i, 3) * topplane(3) - topplane(4) < 0 THEN particleinview = 0
  495. IF vec(i, 1) * bottomplane(1) + vec(i, 2) * bottomplane(2) + vec(i, 3) * bottomplane(3) - bottomplane(4) < 0 THEN particleinview = 0
  496. IF particleinview = 1 THEN
  497.     numparticlevisible = numparticlevisible + 1
  498.     vecvisible(numparticlevisible, 1) = vec(i, 1)
  499.     vecvisible(numparticlevisible, 2) = vec(i, 2)
  500.     vecvisible(numparticlevisible, 3) = vec(i, 3)
  501.     'IF closestgroup = k THEN
  502.     'vecvisiblecolor(numparticlevisible) = Yellow
  503.     'ELSE
  504.     vecvisiblecolor(numparticlevisible) = veccolor(i)
  505.     'END IF
  506.     IF fogswitch = 1 THEN vecvisiblecolor(numparticlevisible) = Gray
  507.  
  508. project.particles:
  509. ' Project vectors onto the screen plane.
  510. FOR i = 1 TO numparticlevisible
  511.     vecvisibledotnhat = vecvisible(i, 1) * nhat(1) + vecvisible(i, 2) * nhat(2) + vecvisible(i, 3) * nhat(3)
  512.     vecvisiblepuv(i, 1) = vecvisible(i, 1) * uhat(1) + vecvisible(i, 2) * uhat(2) + vecvisible(i, 3) * uhat(3)
  513.     vecvisiblepuv(i, 2) = vecvisible(i, 1) * vhat(1) + vecvisible(i, 2) * vhat(2) + vecvisible(i, 3) * vhat(3)
  514.     vecvisiblepuvs(i, 1) = vecvisiblepuv(i, 1) * fovd / vecvisibledotnhat
  515.     vecvisiblepuvs(i, 2) = vecvisiblepuv(i, 2) * fovd / vecvisibledotnhat
  516.  
  517. draw.all.objects:
  518. GOSUB plot.particles
  519. ' Redraw compass.
  520. x = 30 * xhatp(1): y = 30 * xhatp(2): GOSUB convert
  521. LINE (centerx, centery)-(x, y), Red
  522. x = 30 * yhatp(1): y = 30 * yhatp(2): GOSUB convert
  523. LINE (centerx, centery)-(x, y), Green
  524. x = 30 * zhatp(1): y = 30 * zhatp(2): GOSUB convert
  525. LINE (centerx, centery)-(x, y), Blue
  526. IF togglehud = 1 THEN
  527.  
  528.     COLOR LimeGreen
  529.     LOCATE 2, 2: PRINT "- View Info -"
  530.     COLOR DarkKhaki
  531.     LOCATE 3, 2: PRINT "Particles:"; numparticlevisible
  532.     LOCATE 4, 2: PRINT "Groups:"; numgroupvisible
  533.     LOCATE 5, 2: PRINT "Depth:"; -farplane(4)
  534.     LOCATE 6, 2: PRINT "Adjust via [ ]"
  535.     COLOR LimeGreen
  536.     LOCATE 8, 2: PRINT "- Camera -"
  537.     COLOR DarkKhaki
  538.     LOCATE 9, 2: PRINT INT(camx); INT(camy); INT(camz)
  539.     COLOR LimeGreen
  540.     LOCATE 11, 2: PRINT "- Closest: -"
  541.     COLOR DarkKhaki
  542.     dist = INT(SQR((camx - VectorGroup(closestgroup).COMx) ^ 2 + (camy - VectorGroup(closestgroup).COMy) ^ 2 + (camz - VectorGroup(closestgroup).COMz) ^ 2))
  543.     LOCATE 12, 2: PRINT LTRIM$(RTRIM$(VectorGroup(closestgroup).ContentName)) + " (" + LTRIM$(RTRIM$(STR$(dist))) + ")"
  544.     COLOR LimeGreen
  545.     a$ = "MOVE - ALIGN": LOCATE 2, screenwidth / 8 - LEN(a$): PRINT a$
  546.     COLOR DarkKhaki
  547.     a$ = "q w e - x y z": LOCATE 3, screenwidth / 8 - LEN(a$): PRINT a$
  548.     a$ = "a s d - X Y Z": LOCATE 4, screenwidth / 8 - LEN(a$): PRINT a$
  549.     a$ = "i = invert ms": LOCATE 5, screenwidth / 8 - LEN(a$): PRINT a$
  550.     COLOR LimeGreen
  551.     a$ = "- ROTATE -": LOCATE 7, screenwidth / 8 - LEN(a$): PRINT a$
  552.     COLOR DarkKhaki
  553.     a$ = "7 8 9 Mouse": LOCATE 8, screenwidth / 8 - LEN(a$): PRINT a$
  554.     a$ = "4 5 6   +  ": LOCATE 9, screenwidth / 8 - LEN(a$): PRINT a$
  555.     a$ = "1 2 3 Wheel": LOCATE 10, screenwidth / 8 - LEN(a$): PRINT a$
  556.     COLOR LimeGreen
  557.     a$ = "- CONTROL -": LOCATE 12, screenwidth / 8 - LEN(a$): PRINT a$
  558.     COLOR DarkKhaki
  559.     a$ = "b = Create": LOCATE 13, screenwidth / 8 - LEN(a$): PRINT a$
  560.     a$ = "k = Destroy": LOCATE 14, screenwidth / 8 - LEN(a$): PRINT a$
  561.     a$ = "f = Fireworks": LOCATE 15, screenwidth / 8 - LEN(a$): PRINT a$
  562.     a$ = "t = Stop time": LOCATE 16, screenwidth / 8 - LEN(a$): PRINT a$
  563.     COLOR LimeGreen
  564.     a$ = "SPACE = Hide Info": LOCATE (screenheight / 16) - 3, (screenwidth / 8) / 2 - LEN(a$) / 2: PRINT a$
  565.     COLOR LimeGreen
  566.     a$ = "You See: " + LTRIM$(RTRIM$(VectorGroup(closestgroup).ContentName)): LOCATE (screenheight / 16) - 3, (screenwidth / 8) / 2 - LEN(a$) / 2: PRINT a$
  567.  
  568. calculate.clippingplanes:
  569. ' Calculate normal vectors to all clipping planes.
  570. nearplane(1) = -nhat(1)
  571. nearplane(2) = -nhat(2)
  572. nearplane(3) = -nhat(3)
  573. farplane(1) = nhat(1)
  574. farplane(2) = nhat(2)
  575. farplane(3) = nhat(3)
  576. rightplane(1) = (screenheight / 2) * fovd * uhat(1) - (screenheight / 2) * (screenwidth / 2) * nhat(1)
  577. rightplane(2) = (screenheight / 2) * fovd * uhat(2) - (screenheight / 2) * (screenwidth / 2) * nhat(2)
  578. rightplane(3) = (screenheight / 2) * fovd * uhat(3) - (screenheight / 2) * (screenwidth / 2) * nhat(3)
  579. mag = SQR((rightplane(1)) ^ 2 + (rightplane(2)) ^ 2 + (rightplane(3)) ^ 2)
  580. rightplane(1) = rightplane(1) / mag
  581. rightplane(2) = rightplane(2) / mag
  582. rightplane(3) = rightplane(3) / mag
  583. leftplane(1) = -(screenheight / 2) * fovd * uhat(1) - (screenheight / 2) * (screenwidth / 2) * nhat(1)
  584. leftplane(2) = -(screenheight / 2) * fovd * uhat(2) - (screenheight / 2) * (screenwidth / 2) * nhat(2)
  585. leftplane(3) = -(screenheight / 2) * fovd * uhat(3) - (screenheight / 2) * (screenwidth / 2) * nhat(3)
  586. mag = SQR((leftplane(1)) ^ 2 + (leftplane(2)) ^ 2 + (leftplane(3)) ^ 2)
  587. leftplane(1) = leftplane(1) / mag
  588. leftplane(2) = leftplane(2) / mag
  589. leftplane(3) = leftplane(3) / mag
  590. topplane(1) = (screenwidth / 2) * fovd * vhat(1) - (screenheight / 2) * (screenwidth / 2) * nhat(1)
  591. topplane(2) = (screenwidth / 2) * fovd * vhat(2) - (screenheight / 2) * (screenwidth / 2) * nhat(2)
  592. topplane(3) = (screenwidth / 2) * fovd * vhat(3) - (screenheight / 2) * (screenwidth / 2) * nhat(3)
  593. mag = SQR((topplane(1)) ^ 2 + (topplane(2)) ^ 2 + (topplane(3)) ^ 2)
  594. topplane(1) = topplane(1) / mag
  595. topplane(2) = topplane(2) / mag
  596. topplane(3) = topplane(3) / mag
  597. bottomplane(1) = -(screenwidth / 2) * fovd * vhat(1) - (screenheight / 2) * (screenwidth / 2) * nhat(1)
  598. bottomplane(2) = -(screenwidth / 2) * fovd * vhat(2) - (screenheight / 2) * (screenwidth / 2) * nhat(2)
  599. bottomplane(3) = -(screenwidth / 2) * fovd * vhat(3) - (screenheight / 2) * (screenwidth / 2) * nhat(3)
  600. mag = SQR((bottomplane(1)) ^ 2 + (bottomplane(2)) ^ 2 + (bottomplane(3)) ^ 2)
  601. bottomplane(1) = bottomplane(1) / mag
  602. bottomplane(2) = bottomplane(2) / mag
  603. bottomplane(3) = bottomplane(3) / mag
  604.  
  605. plot.particles:
  606. FOR i = 1 TO numparticlevisible - 1
  607.     x = vecvisiblepuvs(i, 1): y = vecvisiblepuvs(i, 2): GOSUB convert: x1 = x: y1 = y
  608.     x = vecvisiblepuvs(i + 1, 1): y = vecvisiblepuvs(i + 1, 2): GOSUB convert: x2 = x: y2 = y
  609.     IF ((x2 - x1) ^ 2 + (y2 - y1) ^ 2) < 15 ^ 2 THEN
  610.         IF plotmode = 1 THEN
  611.             LINE (x1, y1)-(x2, y2), vecvisiblecolor(i)
  612.         ELSE
  613.             LINE (x1, y1)-(x2, y2), vecvisiblecolor(i), B
  614.         END IF
  615.     ELSE
  616.         CIRCLE (x1, y1), 1, vecvisiblecolor(i)
  617.     END IF
  618.  
  619. ' Data.
  620.  
  621. initialize.objects:
  622. particleindex = 0
  623. vecgroupcounter = 0
  624. gridsize = 550
  625. tilesize = 15
  626.  
  627. '__AAA
  628. vecgroupcounter = vecgroupcounter + 1
  629. vecgroupindex = vecgroupcounter
  630. VectorGroup(vecgroupindex).Identity = vecgroupindex
  631. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  632. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  633. VectorGroup(vecgroupindex).ContentName = "__AAA"
  634. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  635. FOR r = 1 TO 5
  636.     particleindex = particleindex + 1
  637.     vecorig(particleindex, 1) = -1000
  638.     vecorig(particleindex, 2) = -1000
  639.     vecorig(particleindex, 3) = -1000
  640.     veccolor(particleindex) = White
  641.     GOSUB calccom
  642. VectorGroup(vecgroupindex).LastParticle = particleindex
  643. GOSUB adjustcom
  644.  
  645. 'Banner
  646. vecgroupcounter = vecgroupcounter + 1
  647. vecgroupindex = vecgroupcounter
  648. VectorGroup(vecgroupindex).Identity = vecgroupindex
  649. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  650. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  651. VectorGroup(vecgroupindex).ContentName = "Banner"
  652. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  653. xl = -1.9: xr = 1.9: dx = .32
  654. yl = -1: yr = 1: dy = .32
  655. xl = xl * 4: xr = xr * 4: yl = yl * 4: yr = yr * 4
  656. xrange = 1 + INT((-xl + xr) / dx)
  657. yrange = 1 + INT((-yl + yr) / dy)
  658. t = 0
  659. FOR i = xl TO xr STEP dx
  660.     FOR j = yl TO yr STEP dy
  661.         particleindex = particleindex + 1
  662.         vecorig(particleindex, 1) = 70 + 1.25 * COS(i - 2 * t) ^ 2 - 1.25 * SIN(j - t) ^ 2
  663.         vecorig(particleindex, 2) = 30 + i
  664.         vecorig(particleindex, 3) = 40 + j
  665.         IF vecorig(particleindex, 1) < 70 THEN
  666.             veccolor(particleindex) = Red
  667.         ELSE
  668.             veccolor(particleindex) = DarkOrange
  669.         END IF
  670.         GOSUB calccom
  671.     NEXT
  672. VectorGroup(vecgroupindex).LastParticle = particleindex
  673. GOSUB adjustcom
  674.  
  675. 'Clock Face (Rolex)
  676. vecgroupcounter = vecgroupcounter + 1
  677. vecgroupindex = vecgroupcounter
  678. VectorGroup(vecgroupindex).Identity = vecgroupindex
  679. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  680. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  681. VectorGroup(vecgroupindex).ContentName = "Clock Face (Rolex)"
  682. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  683. FOR q = 0 TO 2 * pi STEP (2 * pi / 12) / 25
  684.     FOR r = 10 TO 12 STEP .5
  685.         particleindex = particleindex + 1
  686.         vecorig(particleindex, 1) = 40 + r * COS(q)
  687.         vecorig(particleindex, 2) = -20 + r
  688.         vecorig(particleindex, 3) = 40 + r * SIN(q)
  689.         veccolor(particleindex) = DarkSlateGray
  690.         GOSUB calccom
  691.     NEXT
  692. VectorGroup(vecgroupindex).LastParticle = particleindex
  693. GOSUB adjustcom
  694.  
  695. 'Clock Hands
  696. vecgroupcounter = vecgroupcounter + 1
  697. vecgroupindex = vecgroupcounter
  698. VectorGroup(vecgroupindex).Identity = vecgroupindex
  699. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  700. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  701. VectorGroup(vecgroupindex).ContentName = "Clock Hands"
  702. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  703. DIM hand(3)
  704. DIM hcol(3) AS LONG
  705. hand(1) = VAL(LEFT$(TIME$, 2)) * (2 * pi / 12)
  706. hand(2) = VAL(MID$(TIME$, 4, 2)) * (2 * pi / 60)
  707. hand(3) = VAL(RIGHT$(TIME$, 2)) * (2 * pi / 60)
  708. phase = pi / 2
  709. hcol(1) = Gold
  710. hcol(2) = Lime
  711. hcol(3) = OrangeRed
  712. FOR q = 1 TO 3
  713.     FOR r = 0 TO 5 + q STEP .1
  714.         particleindex = particleindex + 1
  715.         vecorig(particleindex, 1) = 40 + r * COS(hand(q) + phase)
  716.         vecorig(particleindex, 2) = -10
  717.         vecorig(particleindex, 3) = 40 + r * SIN(hand(q) + phase)
  718.         veccolor(particleindex) = hcol(q)
  719.         GOSUB calccom
  720.     NEXT
  721. VectorGroup(vecgroupindex).LastParticle = particleindex
  722. GOSUB adjustcom
  723.  
  724. 'Dirt
  725. h = 5
  726. FOR w = 1 TO 5
  727.     FOR u = -gridsize TO gridsize STEP tilesize
  728.         FOR v = -gridsize TO gridsize STEP tilesize
  729.             vecgroupcounter = vecgroupcounter + 1
  730.             vecgroupindex = vecgroupcounter
  731.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  732.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  733.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  734.             VectorGroup(vecgroupindex).ContentName = "Dirt"
  735.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  736.             FOR i = u TO u + tilesize STEP h
  737.                 FOR j = v TO v + tilesize STEP h
  738.                     IF RND > 1 - w / 5 THEN
  739.                         particleindex = particleindex + 1
  740.                         vecorig(particleindex, 1) = i + RND * h - RND * h
  741.                         vecorig(particleindex, 2) = j + RND * h - RND * h
  742.                         vecorig(particleindex, 3) = -(w - 1) * 70 - RND * 70
  743.                         IF RND > .5 THEN
  744.                             veccolor(particleindex) = DarkGoldenRod
  745.                         ELSE
  746.                             IF RND > .5 THEN
  747.                                 veccolor(particleindex) = SaddleBrown
  748.                             ELSE
  749.                                 veccolor(particleindex) = Sienna
  750.                             END IF
  751.                         END IF
  752.                         GOSUB calccom
  753.                     END IF
  754.                 NEXT
  755.             NEXT
  756.             VectorGroup(vecgroupindex).LastParticle = particleindex
  757.             GOSUB adjustcom
  758.         NEXT
  759.     NEXT
  760.  
  761. 'Grass and Puddles
  762. h = 2
  763. FOR u = -gridsize TO gridsize STEP tilesize
  764.     FOR v = -gridsize TO gridsize STEP tilesize
  765.         vecgroupcounter = vecgroupcounter + 1
  766.         vecgroupindex = vecgroupcounter
  767.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  768.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  769.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  770.         VectorGroup(vecgroupindex).ContentName = "Grass and Puddles"
  771.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  772.         FOR i = u TO u + tilesize STEP h
  773.             FOR j = v TO v + tilesize STEP h
  774.                 particleindex = particleindex + 1
  775.                 vecorig(particleindex, 1) = i + RND * h - RND * h
  776.                 vecorig(particleindex, 2) = j + RND * h - RND * h
  777.                 vecorig(particleindex, 3) = .5 + 1 * COS((i - 15) * .08) - 1 * COS((j - 6) * .12)
  778.                 IF vecorig(particleindex, 3) > 0 THEN
  779.                     IF RND > .5 THEN
  780.                         veccolor(particleindex) = Green
  781.                     ELSE
  782.                         veccolor(particleindex) = ForestGreen
  783.                     END IF
  784.                 ELSE
  785.                     IF RND > .2 THEN
  786.                         veccolor(particleindex) = LightSeaGreen
  787.                     ELSE
  788.                         veccolor(particleindex) = Blue
  789.                     END IF
  790.                 END IF
  791.                 GOSUB calccom
  792.             NEXT
  793.         NEXT
  794.         VectorGroup(vecgroupindex).LastParticle = particleindex
  795.         GOSUB adjustcom
  796.     NEXT
  797.  
  798. 'Grave
  799. 'xloc = -90
  800. 'yloc = 0
  801. thickness = 2.5
  802. span = 20
  803. height = 30
  804. crux = 22
  805. FOR xloc = -90 TO -290 STEP -60
  806.     FOR yloc = 0 TO 180 STEP 45
  807.         FOR k = 0 TO height
  808.             vecgroupcounter = vecgroupcounter + 1
  809.             vecgroupindex = vecgroupcounter
  810.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  811.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  812.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  813.             VectorGroup(vecgroupindex).ContentName = "Grave"
  814.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  815.             FOR i = -thickness TO thickness STEP thickness / 2
  816.                 FOR j = -thickness TO thickness STEP thickness / 2
  817.                     particleindex = particleindex + 1
  818.                     vecorig(particleindex, 1) = xloc + i + (RND - .5) * 2
  819.                     vecorig(particleindex, 2) = yloc + j + (RND - .5) * 2
  820.                     vecorig(particleindex, 3) = k + (RND - .5) * 2
  821.                     IF RND > .5 THEN
  822.                         veccolor(particleindex) = SlateGray
  823.                     ELSE
  824.                         veccolor(particleindex) = DarkGray
  825.                     END IF
  826.                     GOSUB calccom
  827.                 NEXT
  828.             NEXT
  829.             VectorGroup(vecgroupindex).LastParticle = particleindex
  830.             GOSUB adjustcom
  831.         NEXT
  832.         FOR j = -span / 2 TO -thickness
  833.             vecgroupcounter = vecgroupcounter + 1
  834.             vecgroupindex = vecgroupcounter
  835.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  836.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  837.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  838.             VectorGroup(vecgroupindex).ContentName = "Grave"
  839.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  840.             FOR k = -thickness TO thickness STEP thickness / 2
  841.                 FOR i = -thickness TO thickness STEP thickness / 2
  842.                     particleindex = particleindex + 1
  843.                     vecorig(particleindex, 1) = xloc + i + (RND - .5) * 2
  844.                     vecorig(particleindex, 2) = yloc + j + (RND - .5) * 2
  845.                     vecorig(particleindex, 3) = crux + k + (RND - .5) * 2
  846.                     IF RND > .5 THEN
  847.                         veccolor(particleindex) = SlateGray
  848.                     ELSE
  849.                         veccolor(particleindex) = DarkGray
  850.                     END IF
  851.                     GOSUB calccom
  852.                 NEXT
  853.             NEXT
  854.             VectorGroup(vecgroupindex).LastParticle = particleindex
  855.             GOSUB adjustcom
  856.         NEXT
  857.         FOR j = thickness TO span / 2
  858.             vecgroupcounter = vecgroupcounter + 1
  859.             vecgroupindex = vecgroupcounter
  860.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  861.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  862.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  863.             VectorGroup(vecgroupindex).ContentName = "Grave"
  864.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  865.             FOR k = -thickness TO thickness STEP thickness / 2
  866.                 FOR i = -thickness TO thickness STEP thickness / 2
  867.                     particleindex = particleindex + 1
  868.                     vecorig(particleindex, 1) = xloc + i + (RND - .5) * 2
  869.                     vecorig(particleindex, 2) = yloc + j + (RND - .5) * 2
  870.                     vecorig(particleindex, 3) = crux + k + (RND - .5) * 2
  871.                     IF RND > .5 THEN
  872.                         veccolor(particleindex) = SlateGray
  873.                     ELSE
  874.                         veccolor(particleindex) = DarkGray
  875.                     END IF
  876.                     GOSUB calccom
  877.                 NEXT
  878.             NEXT
  879.             VectorGroup(vecgroupindex).LastParticle = particleindex
  880.             GOSUB adjustcom
  881.         NEXT
  882.     NEXT
  883.  
  884. 'Heaven's Bottom Layer
  885. h = 2
  886. FOR u = -gridsize TO gridsize STEP tilesize
  887.     FOR v = -gridsize TO gridsize STEP tilesize
  888.         vecgroupcounter = vecgroupcounter + 1
  889.         vecgroupindex = vecgroupcounter
  890.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  891.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  892.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  893.         VectorGroup(vecgroupindex).ContentName = "Heaven's Bottom Layer"
  894.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  895.         FOR i = u TO u + tilesize STEP h
  896.             FOR j = v TO v + tilesize STEP h
  897.                 particleindex = particleindex + 1
  898.                 vecorig(particleindex, 1) = i + RND * h - RND * h
  899.                 vecorig(particleindex, 2) = j + RND * h - RND * h
  900.                 vecorig(particleindex, 3) = 420 - RND
  901.                 IF RND > .5 THEN
  902.                     veccolor(particleindex) = BlueViolet
  903.                 ELSE
  904.                     veccolor(particleindex) = Cyan
  905.                 END IF
  906.                 GOSUB calccom
  907.             NEXT
  908.         NEXT
  909.         VectorGroup(vecgroupindex).LastParticle = particleindex
  910.         GOSUB adjustcom
  911.     NEXT
  912.  
  913. 'Hell Spawn
  914. FOR u = -gridsize TO gridsize STEP tilesize
  915.     FOR v = -gridsize TO gridsize STEP tilesize
  916.         vecgroupcounter = vecgroupcounter + 1
  917.         vecgroupindex = vecgroupcounter
  918.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  919.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  920.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  921.         VectorGroup(vecgroupindex).ContentName = "Hell Spawn"
  922.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  923.         FOR i = u TO u + tilesize STEP tilesize / 5
  924.             FOR j = v TO v + tilesize STEP tilesize / 5
  925.                 particleindex = particleindex + 1
  926.                 vecorig(particleindex, 1) = i + RND * tilesize / 5
  927.                 vecorig(particleindex, 2) = j + RND * tilesize / 5
  928.                 vecorig(particleindex, 3) = -350 - RND * 70
  929.                 IF RND > .2 THEN
  930.                     veccolor(particleindex) = Red
  931.                 ELSE
  932.                     veccolor(particleindex) = DarkGoldenRod
  933.                 END IF
  934.                 GOSUB calccom
  935.             NEXT
  936.         NEXT
  937.         VectorGroup(vecgroupindex).LastParticle = particleindex
  938.         GOSUB adjustcom
  939.     NEXT
  940.  
  941. 'Icewall East
  942. h = 2
  943. FOR u = -gridsize TO gridsize STEP tilesize
  944.     FOR v = 0 TO 70 STEP tilesize
  945.         vecgroupcounter = vecgroupcounter + 1
  946.         vecgroupindex = vecgroupcounter
  947.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  948.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  949.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  950.         VectorGroup(vecgroupindex).ContentName = "Icewall East"
  951.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  952.         FOR i = u TO u + tilesize STEP h
  953.             FOR j = v TO v + tilesize STEP h
  954.                 particleindex = particleindex + 1
  955.                 vecorig(particleindex, 1) = gridsize
  956.                 vecorig(particleindex, 2) = i + RND * h - RND * h
  957.                 vecorig(particleindex, 3) = j + RND * h - RND * h
  958.                 IF RND > .5 THEN
  959.                     veccolor(particleindex) = White
  960.                 ELSE
  961.                     veccolor(particleindex) = Ivory
  962.                 END IF
  963.                 GOSUB calccom
  964.             NEXT
  965.         NEXT
  966.         VectorGroup(vecgroupindex).LastParticle = particleindex
  967.         GOSUB adjustcom
  968.     NEXT
  969.  
  970. 'Icewall South
  971. h = 2
  972. FOR u = -gridsize TO gridsize STEP tilesize
  973.     FOR v = 0 TO 70 STEP tilesize
  974.         vecgroupcounter = vecgroupcounter + 1
  975.         vecgroupindex = vecgroupcounter
  976.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  977.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  978.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  979.         VectorGroup(vecgroupindex).ContentName = "Icewall South"
  980.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  981.         FOR i = u TO u + tilesize STEP h
  982.             FOR j = v TO v + tilesize STEP h
  983.                 particleindex = particleindex + 1
  984.                 vecorig(particleindex, 1) = -gridsize
  985.                 vecorig(particleindex, 2) = i + RND * h - RND * h
  986.                 vecorig(particleindex, 3) = j + RND * h - RND * h
  987.                 IF RND > .5 THEN
  988.                     veccolor(particleindex) = White
  989.                 ELSE
  990.                     veccolor(particleindex) = Ivory
  991.                 END IF
  992.                 GOSUB calccom
  993.             NEXT
  994.         NEXT
  995.         VectorGroup(vecgroupindex).LastParticle = particleindex
  996.         GOSUB adjustcom
  997.     NEXT
  998.  
  999. 'Icewall North
  1000. h = 2
  1001. FOR u = -gridsize TO gridsize STEP tilesize
  1002.     FOR v = 0 TO 70 STEP tilesize
  1003.         vecgroupcounter = vecgroupcounter + 1
  1004.         vecgroupindex = vecgroupcounter
  1005.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1006.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1007.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1008.         VectorGroup(vecgroupindex).ContentName = "Icewall North"
  1009.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1010.         FOR i = u TO u + tilesize STEP h
  1011.             FOR j = v TO v + tilesize STEP h
  1012.                 particleindex = particleindex + 1
  1013.                 vecorig(particleindex, 1) = i + RND * h - RND * h
  1014.                 vecorig(particleindex, 2) = gridsize
  1015.                 vecorig(particleindex, 3) = j + RND * h - RND * h
  1016.                 IF RND > .5 THEN
  1017.                     veccolor(particleindex) = White
  1018.                 ELSE
  1019.                     veccolor(particleindex) = Ivory
  1020.                 END IF
  1021.                 GOSUB calccom
  1022.             NEXT
  1023.         NEXT
  1024.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1025.         GOSUB adjustcom
  1026.     NEXT
  1027.  
  1028. 'Icewall West
  1029. h = 2
  1030. FOR u = -gridsize TO gridsize STEP tilesize
  1031.     FOR v = 0 TO 70 STEP tilesize
  1032.         vecgroupcounter = vecgroupcounter + 1
  1033.         vecgroupindex = vecgroupcounter
  1034.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1035.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1036.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1037.         VectorGroup(vecgroupindex).ContentName = "Icewall West"
  1038.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1039.         FOR i = u TO u + tilesize STEP h
  1040.             FOR j = v TO v + tilesize STEP h
  1041.                 particleindex = particleindex + 1
  1042.                 vecorig(particleindex, 1) = i + RND * h - RND * h
  1043.                 vecorig(particleindex, 2) = -gridsize
  1044.                 vecorig(particleindex, 3) = j + RND * h - RND * h
  1045.                 IF RND > .5 THEN
  1046.                     veccolor(particleindex) = White
  1047.                 ELSE
  1048.                     veccolor(particleindex) = Ivory
  1049.                 END IF
  1050.                 GOSUB calccom
  1051.             NEXT
  1052.         NEXT
  1053.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1054.         GOSUB adjustcom
  1055.     NEXT
  1056.  
  1057. 'Lake of Fire
  1058. h = 2
  1059. FOR u = -gridsize TO gridsize STEP tilesize
  1060.     FOR v = -gridsize TO gridsize STEP tilesize
  1061.         vecgroupcounter = vecgroupcounter + 1
  1062.         vecgroupindex = vecgroupcounter
  1063.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1064.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1065.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1066.         VectorGroup(vecgroupindex).ContentName = "Lake of Fire"
  1067.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1068.         FOR i = u TO u + tilesize STEP h
  1069.             FOR j = v TO v + tilesize STEP h
  1070.                 particleindex = particleindex + 1
  1071.                 vecorig(particleindex, 1) = i + RND * h - RND * h
  1072.                 vecorig(particleindex, 2) = j + RND * h - RND * h
  1073.                 vecorig(particleindex, 3) = -350 - 70 - RND
  1074.                 IF RND > .2 THEN
  1075.                     veccolor(particleindex) = Red
  1076.                 ELSE
  1077.                     veccolor(particleindex) = Indigo
  1078.                 END IF
  1079.                 GOSUB calccom
  1080.             NEXT
  1081.         NEXT
  1082.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1083.         GOSUB adjustcom
  1084.     NEXT
  1085.  
  1086. 'Megalith
  1087. ctrx = -90
  1088. ctry = -320
  1089. ctrz = 4
  1090. w = 8
  1091. h = 256
  1092. dens = 100
  1093. FOR k = 1 TO h STEP w
  1094.     FOR i = -h / 20 + k / 20 TO h / 20 - k / 20 STEP w
  1095.         FOR j = -h / 20 + k / 20 TO h / 20 - k / 20 STEP w
  1096.             vecgroupcounter = vecgroupcounter + 1
  1097.             vecgroupindex = vecgroupcounter
  1098.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  1099.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1100.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1101.             VectorGroup(vecgroupindex).ContentName = "Megalith"
  1102.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1103.             FOR q = 1 TO dens
  1104.                 particleindex = particleindex + 1
  1105.                 vecorig(particleindex, 1) = ctrx + i + (RND - .5) * w
  1106.                 vecorig(particleindex, 2) = ctry + j + (RND - .5) * w
  1107.                 vecorig(particleindex, 3) = ctrz + k + (RND - .5) * w
  1108.                 IF RND > .5 THEN
  1109.                     veccolor(particleindex) = Cyan
  1110.                 ELSE
  1111.                     veccolor(particleindex) = Teal
  1112.                 END IF
  1113.                 GOSUB calccom
  1114.             NEXT
  1115.             VectorGroup(vecgroupindex).LastParticle = particleindex
  1116.             GOSUB adjustcom
  1117.         NEXT
  1118.     NEXT
  1119.  
  1120. 'Moon
  1121. vecgroupcounter = vecgroupcounter + 1
  1122. vecgroupindex = vecgroupcounter
  1123. VectorGroup(vecgroupindex).Identity = vecgroupindex
  1124. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1125. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1126. VectorGroup(vecgroupindex).ContentName = "Moon"
  1127. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1128. radius = 4
  1129. au = 60
  1130. dx = (2 * pi / radius) * .05
  1131. dy = (2 * pi / radius) * .05
  1132. xl = 0: xr = 2 * pi
  1133. yl = 0: yr = pi
  1134. xrange = 1 + INT((-xl + xr) / dx)
  1135. yrange = 1 + INT((-yl + yr) / dy)
  1136. FOR i = 1 TO xrange
  1137.     FOR j = 1 TO yrange
  1138.         particleindex = particleindex + 1
  1139.         theta = i * dx - dx
  1140.         phi = j * dy - dy
  1141.         vecorig(particleindex, 1) = au + radius * SIN(phi) * COS(theta)
  1142.         vecorig(particleindex, 2) = radius * SIN(phi) * SIN(theta)
  1143.         vecorig(particleindex, 3) = 90 + radius * COS(phi)
  1144.         IF RND > .5 THEN
  1145.             veccolor(particleindex) = Gray
  1146.         ELSE
  1147.             veccolor(particleindex) = PaleGoldenRod
  1148.         END IF
  1149.         GOSUB calccom
  1150.     NEXT
  1151. VectorGroup(vecgroupindex).LastParticle = particleindex
  1152. GOSUB adjustcom
  1153.  
  1154. 'Pyramid
  1155. ctrx = -90
  1156. ctry = -120
  1157. ctrz = 4
  1158. w = 8
  1159. h = 56
  1160. dens = 50
  1161. FOR k = 1 TO h STEP w
  1162.     FOR i = -h / 2 + k / 2 TO h / 2 - k / 2 STEP w
  1163.         FOR j = -h / 2 + k / 2 TO h / 2 - k / 2 STEP w
  1164.             vecgroupcounter = vecgroupcounter + 1
  1165.             vecgroupindex = vecgroupcounter
  1166.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  1167.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1168.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1169.             VectorGroup(vecgroupindex).ContentName = "Pyramid"
  1170.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1171.             FOR q = 1 TO dens
  1172.                 particleindex = particleindex + 1
  1173.                 vecorig(particleindex, 1) = ctrx + i + (RND - .5) * w
  1174.                 vecorig(particleindex, 2) = ctry + j + (RND - .5) * w
  1175.                 vecorig(particleindex, 3) = ctrz + k + (RND - .5) * w
  1176.                 IF RND > .5 THEN
  1177.                     veccolor(particleindex) = DarkGoldenRod
  1178.                 ELSE
  1179.                     veccolor(particleindex) = GoldenRod
  1180.                 END IF
  1181.                 GOSUB calccom
  1182.             NEXT
  1183.             VectorGroup(vecgroupindex).LastParticle = particleindex
  1184.             GOSUB adjustcom
  1185.         NEXT
  1186.     NEXT
  1187.  
  1188. 'Rain
  1189. FOR u = -gridsize TO gridsize STEP tilesize
  1190.     FOR v = -gridsize TO gridsize STEP tilesize
  1191.         vecgroupcounter = vecgroupcounter + 1
  1192.         vecgroupindex = vecgroupcounter
  1193.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1194.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1195.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1196.         VectorGroup(vecgroupindex).ContentName = "Rain"
  1197.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1198.         FOR i = u TO u + tilesize STEP tilesize '/ 3
  1199.             FOR j = v TO v + tilesize STEP tilesize '/ 3
  1200.                 particleindex = particleindex + 1
  1201.                 vecorig(particleindex, 1) = i + RND * tilesize
  1202.                 vecorig(particleindex, 2) = j + RND * tilesize
  1203.                 vecorig(particleindex, 3) = RND * 70
  1204.                 IF RND > 5 THEN
  1205.                     veccolor(particleindex) = Aquamarine
  1206.                 ELSE
  1207.                     veccolor(particleindex) = DodgerBlue
  1208.                 END IF
  1209.                 GOSUB calccom
  1210.             NEXT
  1211.         NEXT
  1212.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1213.         GOSUB adjustcom
  1214.     NEXT
  1215.  
  1216. ''Rotor
  1217. 'vecgroupcounter = vecgroupcounter + 1
  1218. 'vecgroupindex = vecgroupcounter
  1219. 'VectorGroup(vecgroupindex).Identity = vecgroupindex
  1220. 'VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1221. 'VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1222. 'VectorGroup(vecgroupindex).ContentName = "Rotor"
  1223. 'VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1224. 'xc = 5
  1225. 'yc = 5
  1226. 'zc = 40
  1227. 'rad = 20
  1228. 'FOR k = 1 TO 600
  1229. '    xx = RND * 2 * rad - rad
  1230. '    yy = 0
  1231. '    zz = RND * 2 * rad - rad
  1232. '    IF xx ^ 2 + yy ^ 2 + zz ^ 2 < rad ^ 2 THEN
  1233. '        particleindex = particleindex + 1
  1234. '        vecorig(particleindex, 1) = xc + xx
  1235. '        vecorig(particleindex, 2) = yc + yy
  1236. '        vecorig(particleindex, 3) = zc + zz
  1237. '        vecorigrot(particleindex, 1) = 50
  1238. '        vecorigrot(particleindex, 2) = 50
  1239. '        vecorigrot(particleindex, 3) = 50
  1240. '        GOSUB calccom
  1241. '        veccolor(particleindex) = _RGB(INT(RND * 255), INT(RND * 255), INT(RND * 255))
  1242. '    END IF
  1243. 'NEXT
  1244. 'VectorGroup(vecgroupindex).LastParticle = particleindex
  1245. 'GOSUB adjustcom
  1246. 'VectorGroup(vecgroupindex).CORx = VectorGroup(vecgroupindex).COMx
  1247. 'VectorGroup(vecgroupindex).CORy = VectorGroup(vecgroupindex).COMy
  1248. 'VectorGroup(vecgroupindex).CORz = VectorGroup(vecgroupindex).COMz
  1249.  
  1250. 'Sky
  1251. h = 2
  1252. FOR u = -gridsize TO gridsize STEP tilesize
  1253.     FOR v = -gridsize TO gridsize STEP tilesize
  1254.         vecgroupcounter = vecgroupcounter + 1
  1255.         vecgroupindex = vecgroupcounter
  1256.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1257.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1258.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1259.         VectorGroup(vecgroupindex).ContentName = "Sky"
  1260.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1261.         FOR i = u TO u + tilesize STEP h
  1262.             FOR j = v TO v + tilesize STEP h
  1263.                 particleindex = particleindex + 1
  1264.                 vecorig(particleindex, 1) = i + RND * h - RND * h
  1265.                 vecorig(particleindex, 2) = j + RND * h - RND * h
  1266.                 vecorig(particleindex, 3) = 70 + RND * h - RND * h
  1267.                 IF RND > .5 THEN
  1268.                     veccolor(particleindex) = Snow
  1269.                 ELSE
  1270.                     veccolor(particleindex) = RoyalBlue
  1271.                 END IF
  1272.                 GOSUB calccom
  1273.             NEXT
  1274.         NEXT
  1275.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1276.         GOSUB adjustcom
  1277.     NEXT
  1278.  
  1279. 'Snake?
  1280. vecgroupcounter = vecgroupcounter + 1
  1281. vecgroupindex = vecgroupcounter
  1282. VectorGroup(vecgroupindex).Identity = vecgroupindex
  1283. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1284. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1285. VectorGroup(vecgroupindex).ContentName = "Snake?"
  1286. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1287. FOR i = -pi TO pi STEP .005
  1288.     particleindex = particleindex + 1
  1289.     vecorig(particleindex, 1) = -10 + 5 * COS(i)
  1290.     vecorig(particleindex, 2) = -20 + 5 * SIN(i)
  1291.     vecorig(particleindex, 3) = 25 - 3 * COS(6 * i) * SIN(3 * i)
  1292.     veccolor(particleindex) = Coral
  1293.     GOSUB calccom
  1294. VectorGroup(vecgroupindex).LastParticle = particleindex
  1295. GOSUB adjustcom
  1296.  
  1297. 'Sparks
  1298. vecgroupcounter = vecgroupcounter + 1
  1299. vecgroupindex = vecgroupcounter
  1300. VectorGroup(vecgroupindex).Identity = vecgroupindex
  1301. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1302. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1303. VectorGroup(vecgroupindex).ContentName = "Sparks"
  1304. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1305. u = 0
  1306. v = 0
  1307. FOR i = 1 TO 300
  1308.     particleindex = particleindex + 1
  1309.     vecorig(particleindex, 1) = RND - .5
  1310.     vecorig(particleindex, 2) = RND - .5
  1311.     vecorig(particleindex, 3) = 20 + RND - .5
  1312.     vecorigvel(particleindex, 1) = 8 * (RND - .5)
  1313.     vecorigvel(particleindex, 2) = 8 * (RND - .5)
  1314.     vecorigvel(particleindex, 3) = 20 * RND
  1315.     vecorigacc(particleindex, 1) = 0
  1316.     vecorigacc(particleindex, 2) = 0
  1317.     vecorigacc(particleindex, 3) = -40
  1318.     veccolor(particleindex) = _RGB(INT(RND * 255), INT(RND * 255), INT(RND * 255))
  1319.     GOSUB calccom
  1320. VectorGroup(vecgroupindex).LastParticle = particleindex
  1321. GOSUB adjustcom
  1322.  
  1323. 'Stars
  1324. h = 5
  1325. FOR w = 1 TO 5
  1326.     FOR u = -gridsize TO gridsize STEP tilesize
  1327.         FOR v = -gridsize TO gridsize STEP tilesize
  1328.             vecgroupcounter = vecgroupcounter + 1
  1329.             vecgroupindex = vecgroupcounter
  1330.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  1331.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1332.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1333.             VectorGroup(vecgroupindex).ContentName = "Stars"
  1334.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1335.             FOR i = u TO u + tilesize STEP h
  1336.                 FOR j = v TO v + tilesize STEP h
  1337.                     IF RND > 1 - w / 5 THEN
  1338.                         particleindex = particleindex + 1
  1339.                         vecorig(particleindex, 1) = i + RND * h - RND * h
  1340.                         vecorig(particleindex, 2) = j + RND * h - RND * h
  1341.                         vecorig(particleindex, 3) = w * 70 + RND * 70
  1342.                         IF RND > .5 THEN
  1343.                             veccolor(particleindex) = GhostWhite
  1344.                         ELSE
  1345.                             IF RND > .5 THEN
  1346.                                 veccolor(particleindex) = White
  1347.                             ELSE
  1348.                                 veccolor(particleindex) = DarkGray
  1349.                             END IF
  1350.                         END IF
  1351.                         GOSUB calccom
  1352.                     END IF
  1353.                 NEXT
  1354.             NEXT
  1355.             VectorGroup(vecgroupindex).LastParticle = particleindex
  1356.             GOSUB adjustcom
  1357.         NEXT
  1358.     NEXT
  1359.  
  1360. 'Sun
  1361. radius = 10
  1362. dx = .0628
  1363. dy = .0628
  1364. xl = 0: xr = 2 * pi
  1365. yl = 0: yr = pi
  1366. xrange = 1 + INT((-xl + xr) / dx)
  1367. yrange = 1 + INT((-yl + yr) / dy)
  1368. FOR i = 1 TO xrange STEP 10
  1369.     FOR j = 1 TO yrange STEP 10
  1370.         vecgroupcounter = vecgroupcounter + 1
  1371.         vecgroupindex = vecgroupcounter
  1372.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1373.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1374.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1375.         VectorGroup(vecgroupindex).ContentName = "Sun"
  1376.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1377.         FOR u = i TO i + 10 STEP 1
  1378.             FOR v = j TO j + 10 STEP 1
  1379.                 particleindex = particleindex + 1
  1380.                 theta = u * dx - dx
  1381.                 phi = v * dy - dy
  1382.                 vecorig(particleindex, 1) = radius * SIN(phi) * COS(theta)
  1383.                 vecorig(particleindex, 2) = radius * SIN(phi) * SIN(theta)
  1384.                 vecorig(particleindex, 3) = 90 + radius * COS(phi)
  1385.                 IF RND > .5 THEN
  1386.                     veccolor(particleindex) = Sunglow
  1387.                 ELSE
  1388.                     veccolor(particleindex) = SunsetOrange
  1389.                 END IF
  1390.                 GOSUB calccom
  1391.             NEXT
  1392.         NEXT
  1393.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1394.         GOSUB adjustcom
  1395.     NEXT
  1396.  
  1397. 'UFO!!!
  1398. vecgroupcounter = vecgroupcounter + 1
  1399. vecgroupindex = vecgroupcounter
  1400. VectorGroup(vecgroupindex).Identity = vecgroupindex
  1401. VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1402. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1403. VectorGroup(vecgroupindex).ContentName = "UFO!!!"
  1404. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1405. FOR q = 0 TO 2 * pi STEP (2 * pi / 12) / 25
  1406.     FOR r = 10 TO 12 STEP .5
  1407.         particleindex = particleindex + 1
  1408.         vecorig(particleindex, 1) = -90 + r * COS(q)
  1409.         vecorig(particleindex, 2) = -120 + r * SIN(q)
  1410.         vecorig(particleindex, 3) = 100 + r - 12
  1411.         veccolor(particleindex) = HotPink
  1412.         GOSUB calccom
  1413.     NEXT
  1414.     FOR r = 12 TO 10 STEP -.5
  1415.         particleindex = particleindex + 1
  1416.         vecorig(particleindex, 1) = -90 + r * COS(q)
  1417.         vecorig(particleindex, 2) = -120 + r * SIN(q)
  1418.         vecorig(particleindex, 3) = 100 - r + 12
  1419.         veccolor(particleindex) = Red
  1420.         GOSUB calccom
  1421.     NEXT
  1422. r = 5
  1423. h = 30
  1424. FOR w = 1 TO 400
  1425.     xx = (RND - .5) * 2 * r
  1426.     yy = (RND - .5) * 2 * r
  1427.     IF xx ^ 2 + yy ^ 2 < r ^ 2 THEN
  1428.         particleindex = particleindex + 1
  1429.         vecorig(particleindex, 1) = -90 + xx
  1430.         vecorig(particleindex, 2) = -120 + yy
  1431.         vecorig(particleindex, 3) = 100 - RND * h
  1432.         IF RND > .5 THEN
  1433.             veccolor(particleindex) = Aquamarine
  1434.         ELSE
  1435.             veccolor(particleindex) = Lime
  1436.         END IF
  1437.         GOSUB calccom
  1438.     END IF
  1439. VectorGroup(vecgroupindex).LastParticle = particleindex
  1440. GOSUB adjustcom
  1441.  
  1442. 'Waves or Particles? (1)
  1443. FOR i = 1 TO 5 STEP 1
  1444.     FOR k = 1 TO 5 STEP 1
  1445.         vecgroupcounter = vecgroupcounter + 1
  1446.         vecgroupindex = vecgroupcounter
  1447.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1448.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1449.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1450.         VectorGroup(vecgroupindex).ContentName = "Waves or Particles?"
  1451.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1452.         FOR u = i TO i + 1 STEP .05
  1453.             FOR v = k TO k + 1 STEP .05
  1454.                 particleindex = particleindex + 1
  1455.                 vecorig(particleindex, 1) = 70 + 7 * u
  1456.                 vecorig(particleindex, 2) = 80 + 1 * COS((u ^ 2 - v ^ 2))
  1457.                 vecorig(particleindex, 3) = 10 + 7 * v
  1458.                 IF vecorig(particleindex, 2) < 80 THEN
  1459.                     veccolor(particleindex) = DarkBlue
  1460.                 ELSE
  1461.                     veccolor(particleindex) = DeepPink
  1462.                 END IF
  1463.                 GOSUB calccom
  1464.             NEXT
  1465.         NEXT
  1466.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1467.         GOSUB adjustcom
  1468.     NEXT
  1469.  
  1470. 'Waves or Particles? (2)
  1471. FOR i = 1 TO 5 STEP 1
  1472.     FOR k = 1 TO 5 STEP 1
  1473.         vecgroupcounter = vecgroupcounter + 1
  1474.         vecgroupindex = vecgroupcounter
  1475.         VectorGroup(vecgroupindex).Identity = vecgroupindex
  1476.         VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1477.         VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1478.         VectorGroup(vecgroupindex).ContentName = "Waves or Particles?"
  1479.         VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1480.         FOR u = i TO i + 1 STEP .05
  1481.             FOR v = k TO k + 1 STEP .05
  1482.                 particleindex = particleindex + 1
  1483.                 vecorig(particleindex, 1) = -7 * u
  1484.                 vecorig(particleindex, 2) = 80 + 1 * COS(2 * ((u - 7) ^ 2 - (v - 5) ^ 2))
  1485.                 vecorig(particleindex, 3) = 10 + 7 * v
  1486.                 IF vecorig(particleindex, 2) < 80 THEN
  1487.                     veccolor(particleindex) = Magenta
  1488.                 ELSE
  1489.                     veccolor(particleindex) = Chocolate
  1490.                 END IF
  1491.                 GOSUB calccom
  1492.             NEXT
  1493.         NEXT
  1494.         VectorGroup(vecgroupindex).LastParticle = particleindex
  1495.         GOSUB adjustcom
  1496.     NEXT
  1497.  
  1498. 'File
  1499.     DO WHILE NOT EOF(1)
  1500.         INPUT #1, xx, yy, zz, co
  1501.         recordtype = 0
  1502.         IF xx = -111111 AND yy = -111111 AND zz = -111111 AND co = -111111 THEN ' Next record begins a group.
  1503.             recordtype = 111111
  1504.             INPUT #1, n$
  1505.             vecgroupcounter = vecgroupcounter + 1
  1506.             vecgroupindex = vecgroupcounter
  1507.             VectorGroup(vecgroupindex).Identity = vecgroupindex
  1508.             VectorGroup(vecgroupindex).Pointer = vecgroupindex + 1
  1509.             VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1510.             VectorGroup(vecgroupindex).ContentName = n$
  1511.             VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1512.         END IF
  1513.         IF xx = -222222 AND yy = -222222 AND zz = -222222 AND co = -222222 THEN ' Next record is position offset for entire group.
  1514.             recordtype = 222222
  1515.             INPUT #1, xx, yy, zz
  1516.             vecorigvel(particleindex, 1) = 0 'xx
  1517.             vecorigvel(particleindex, 2) = 0 'yy
  1518.             vecorigvel(particleindex, 3) = 0 'zz
  1519.         END IF
  1520.  
  1521.         IF xx = -333333 AND yy = -333333 AND zz = -333333 AND co = -333333 THEN ' Next record is previous particle's linear velocity vector.
  1522.             recordtype = 333333
  1523.             INPUT #1, xx, yy, zz
  1524.             vecorigvel(particleindex, 1) = xx
  1525.             vecorigvel(particleindex, 2) = yy
  1526.             vecorigvel(particleindex, 3) = zz
  1527.         END IF
  1528.         IF xx = -444444 AND yy = -444444 AND zz = -444444 AND co = -444444 THEN ' Next record is previous particle's linear acceleration vector.
  1529.             recordtype = 444444
  1530.             INPUT #1, xx, yy, zz
  1531.             vecorigacc(particleindex, 1) = xx
  1532.             vecorigacc(particleindex, 2) = yy
  1533.             vecorigacc(particleindex, 3) = zz
  1534.         END IF
  1535.         IF xx = -555555 AND yy = -555555 AND zz = -555555 AND co = -555555 THEN ' Next record is rotation point for entire group.
  1536.             recordtype = 555555
  1537.             INPUT #1, xx, yy, zz
  1538.             VectorGroup(vecgroupindex).CORx = xx
  1539.             VectorGroup(vecgroupindex).CORy = yy
  1540.             VectorGroup(vecgroupindex).CORz = zz
  1541.         END IF
  1542.         IF xx = -666666 AND yy = -666666 AND zz = -666666 AND co = -666666 THEN ' Next record is previous particle's angular velocity vector.
  1543.             recordtype = 666666
  1544.             INPUT #1, xx, yy, zz
  1545.             vecorigrot(particleindex, 1) = xx
  1546.             vecorigrot(particleindex, 2) = yy
  1547.             vecorigrot(particleindex, 3) = zz
  1548.         END IF
  1549.  
  1550.         IF xx = -999999 AND yy = -999999 AND zz = -999999 AND co = -999999 THEN ' Previous record was last in group.
  1551.             recordtype = 999999
  1552.             VectorGroup(vecgroupindex).LastParticle = particleindex
  1553.             GOSUB adjustcom
  1554.         END IF
  1555.         IF recordtype = 0 THEN ' Not a special record. Store position and color.
  1556.             particleindex = particleindex + 1
  1557.             vecorig(particleindex, 1) = xx
  1558.             vecorig(particleindex, 2) = yy
  1559.             vecorig(particleindex, 3) = zz
  1560.             SELECT CASE co
  1561.                 CASE 0
  1562.                     veccolor(particleindex) = Black
  1563.                 CASE 1
  1564.                     veccolor(particleindex) = Blue
  1565.                 CASE 2
  1566.                     veccolor(particleindex) = Green
  1567.                 CASE 3
  1568.                     veccolor(particleindex) = Cyan
  1569.                 CASE 4
  1570.                     veccolor(particleindex) = Red
  1571.                 CASE 5
  1572.                     veccolor(particleindex) = Purple
  1573.                 CASE 6
  1574.                     veccolor(particleindex) = Orange
  1575.                 CASE 7
  1576.                     veccolor(particleindex) = LightGray
  1577.                 CASE 8
  1578.                     veccolor(particleindex) = DarkGray
  1579.                 CASE 9
  1580.                     veccolor(particleindex) = LightBlue
  1581.                 CASE 10
  1582.                     veccolor(particleindex) = LightGreen
  1583.                 CASE 11
  1584.                     veccolor(particleindex) = LightCyan
  1585.                 CASE 12
  1586.                     veccolor(particleindex) = OrangeRed 'lightred
  1587.                 CASE 13
  1588.                     veccolor(particleindex) = Violet 'lightpurple
  1589.                 CASE 14
  1590.                     veccolor(particleindex) = Yellow
  1591.                 CASE 15
  1592.                     veccolor(particleindex) = White
  1593.                 CASE ELSE
  1594.                     veccolor(particleindex) = White
  1595.             END SELECT
  1596.             GOSUB calccom
  1597.         END IF
  1598.     LOOP
  1599.     CLOSE #1
  1600.  
  1601. '__ZZZ
  1602. vecgroupcounter = vecgroupcounter + 1
  1603. vecgroupindex = vecgroupcounter
  1604. VectorGroup(vecgroupindex).Identity = vecgroupindex
  1605. VectorGroup(vecgroupindex).Pointer = -999
  1606. VectorGroup(vecgroupindex).Lagger = vecgroupindex - 1
  1607. VectorGroup(vecgroupindex).ContentName = "__ZZZ"
  1608. VectorGroup(vecgroupindex).FirstParticle = particleindex + 1
  1609. FOR r = 1 TO 5
  1610.     particleindex = particleindex + 1
  1611.     vecorig(particleindex, 1) = -1000
  1612.     vecorig(particleindex, 2) = -1000
  1613.     vecorig(particleindex, 3) = -1000
  1614.     veccolor(particleindex) = White
  1615.     GOSUB calccom
  1616. VectorGroup(vecgroupindex).LastParticle = particleindex
  1617. GOSUB adjustcom
  1618.  
  1619. numparticleorig = particleindex
  1620.  
  1621. animateforced:
  1622. ' requires vecgroupindex
  1623. ' protects timevar
  1624. IF thename$ = "Rotor" THEN
  1625.     GOSUB resetcom
  1626.     FOR particleindex = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1627.         x = vecorig(particleindex, 1) - VectorGroup(vecgroupindex).CORx
  1628.         y = vecorig(particleindex, 2) - VectorGroup(vecgroupindex).CORy
  1629.         z = vecorig(particleindex, 3) - VectorGroup(vecgroupindex).CORz
  1630.         ax = vecorigrot(particleindex, 1)
  1631.         ay = vecorigrot(particleindex, 2)
  1632.         az = vecorigrot(particleindex, 3)
  1633.         IF az <> 0 THEN
  1634.             da = timestep * az
  1635.             xx = x
  1636.             yy = y
  1637.             x = xx * COS(da) - yy * SIN(da)
  1638.             y = xx * SIN(da) + yy * COS(da)
  1639.         END IF
  1640.         IF ay <> 0 THEN
  1641.             da = timestep * ay
  1642.             xx = x
  1643.             zz = z
  1644.             x = xx * COS(da) + zz * SIN(da)
  1645.             z = -xx * SIN(da) + zz * COS(da)
  1646.         END IF
  1647.         IF ax <> 0 THEN
  1648.             da = timestep * ax
  1649.             yy = y
  1650.             zz = z
  1651.             y = yy * COS(da) - zz * SIN(da)
  1652.             z = yy * SIN(da) + zz * COS(da)
  1653.         END IF
  1654.         vecorig(particleindex, 1) = x + VectorGroup(vecgroupindex).CORx
  1655.         vecorig(particleindex, 2) = y + VectorGroup(vecgroupindex).CORy
  1656.         vecorig(particleindex, 3) = z + VectorGroup(vecgroupindex).CORz
  1657.         GOSUB calccom
  1658.     NEXT
  1659.     GOSUB adjustcom
  1660.  
  1661.  
  1662. animatestandard:
  1663. ' requires vecgroupindex
  1664. ' protects timevar
  1665. timestep = .001
  1666. timevar = timevar + timestep
  1667. IF timevar > 10 ^ 6 THEN timevar = 0
  1668. thename$ = LTRIM$(RTRIM$(VectorGroup(vecgroupindex).ContentName))
  1669. IF thename$ = "Clock Hands" THEN
  1670.     pin = VectorGroup(vecgroupindex).FirstParticle
  1671.     hands(1, 1) = VAL(LEFT$(TIME$, 2)) * (2 * pi / 12)
  1672.     hands(2, 1) = VAL(MID$(TIME$, 4, 2)) * (2 * pi / 60)
  1673.     hands(3, 1) = VAL(RIGHT$(TIME$, 2)) * (2 * pi / 60)
  1674.     FOR q = 1 TO 3
  1675.         FOR r = 0 TO 5 + q STEP .1
  1676.             pin = pin + 1
  1677.             vecorig(pin, 1) = 40 + r * COS(hands(q, 1) + pi / 2)
  1678.             vecorig(pin, 2) = -10
  1679.             vecorig(pin, 3) = 40 + r * SIN(hands(q, 1) + pi / 2)
  1680.         NEXT
  1681.     NEXT
  1682. IF thename$ = "Banner" THEN
  1683.     pin = VectorGroup(vecgroupindex).FirstParticle
  1684.     t = timevar / 50
  1685.     xl = -1.9: xr = 1.9: dx = .32
  1686.     yl = -1: yr = 1: dy = .32
  1687.     xl = xl * 4: xr = xr * 4: yl = yl * 4: yr = yr * 4
  1688.     FOR i = xl TO xr STEP dx
  1689.         FOR j = yl TO yr STEP dy
  1690.             pin = pin + 1
  1691.             vecorig(pin, 1) = 70 + 1.25 * COS(i - 2 * t) ^ 2 - 1.25 * SIN(j - t) ^ 2
  1692.             vecorig(pin, 2) = 30 + i
  1693.             vecorig(pin, 3) = 40 + j
  1694.             IF vecorig(pin, 1) < 70 THEN
  1695.                 veccolor(pin) = Red
  1696.             ELSE
  1697.                 veccolor(pin) = DarkOrange
  1698.             END IF
  1699.         NEXT
  1700.     NEXT
  1701. IF thename$ = "Hell Spawn" THEN
  1702.     FOR i = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1703.         vecorig(i, 3) = vecorig(i, 3) + .3
  1704.         IF vecorig(i, 3) > -350 THEN vecorig(i, 3) = -350 - 70
  1705.     NEXT
  1706. IF thename$ = "Moon" THEN
  1707.     t = timevar * .00001
  1708.     GOSUB resetcom
  1709.     FOR particleindex = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1710.         xx = vecorig(particleindex, 1)
  1711.         yy = vecorig(particleindex, 2)
  1712.         vecorig(particleindex, 1) = xx * COS(t) - yy * SIN(t)
  1713.         vecorig(particleindex, 2) = xx * SIN(t) + yy * COS(t)
  1714.         GOSUB calccom
  1715.     NEXT
  1716.     GOSUB adjustcom
  1717. IF thename$ = "Rain" THEN
  1718.     FOR i = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1719.         vecorig(i, 3) = vecorig(i, 3) - .3
  1720.         IF vecorig(i, 3) < 0 THEN vecorig(i, 3) = 70
  1721.     NEXT
  1722. IF thename$ = "Snake?" THEN
  1723.     pin = VectorGroup(vecgroupindex).FirstParticle
  1724.     t = timevar * .1
  1725.     FOR i = -pi TO pi STEP .005
  1726.         vecorig(pin, 1) = -10 + 5 * COS(i + t)
  1727.         vecorig(pin, 2) = -20 + 5 * SIN(i + t)
  1728.         vecorig(pin, 3) = 25 - 3 * COS(6 * i + t) * SIN(3 * i + t)
  1729.         pin = pin + 1
  1730.     NEXT
  1731. IF thename$ = "Sparks" THEN
  1732.     GOSUB resetcom
  1733.     dt = timestep * 100
  1734.     FOR particleindex = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1735.         vecorigvel(particleindex, 1) = vecorigvel(particleindex, 1) + vecorigacc(particleindex, 1) * dt
  1736.         vecorigvel(particleindex, 2) = vecorigvel(particleindex, 2) + vecorigacc(particleindex, 2) * dt
  1737.         vecorigvel(particleindex, 3) = vecorigvel(particleindex, 3) + vecorigacc(particleindex, 3) * dt
  1738.         vecorig(particleindex, 1) = vecorig(particleindex, 1) + vecorigvel(particleindex, 1) * dt
  1739.         vecorig(particleindex, 2) = vecorig(particleindex, 2) + vecorigvel(particleindex, 2) * dt
  1740.         vecorig(particleindex, 3) = vecorig(particleindex, 3) + vecorigvel(particleindex, 3) * dt
  1741.         IF vecorig(particleindex, 3) < 0 THEN
  1742.             vecorig(particleindex, 3) = 0
  1743.             vecorigvel(particleindex, 1) = vecorigvel(particleindex, 1) * .75
  1744.             vecorigvel(particleindex, 2) = vecorigvel(particleindex, 2) * .75
  1745.             vecorigvel(particleindex, 3) = -vecorigvel(particleindex, 3) * .5
  1746.         END IF
  1747.         GOSUB calccom
  1748.     NEXT
  1749.     GOSUB adjustcom
  1750. IF thename$ = "Newtonian" THEN
  1751.     GOSUB resetcom
  1752.     dt = timestep * 100
  1753.     FOR particleindex = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1754.         vecorigvel(particleindex, 1) = vecorigvel(particleindex, 1) + vecorigacc(particleindex, 1) * dt
  1755.         vecorigvel(particleindex, 2) = vecorigvel(particleindex, 2) + vecorigacc(particleindex, 2) * dt
  1756.         vecorigvel(particleindex, 3) = vecorigvel(particleindex, 3) + vecorigacc(particleindex, 3) * dt
  1757.         vecorig(particleindex, 1) = vecorig(particleindex, 1) + vecorigvel(particleindex, 1) * dt
  1758.         vecorig(particleindex, 2) = vecorig(particleindex, 2) + vecorigvel(particleindex, 2) * dt
  1759.         vecorig(particleindex, 3) = vecorig(particleindex, 3) + vecorigvel(particleindex, 3) * dt
  1760.         IF vecorig(particleindex, 3) < 0 THEN
  1761.             vecorig(particleindex, 3) = 0
  1762.             vecorigvel(particleindex, 1) = vecorigvel(particleindex, 1) * .75
  1763.             vecorigvel(particleindex, 2) = vecorigvel(particleindex, 2) * .75
  1764.             vecorigvel(particleindex, 3) = -vecorigvel(particleindex, 3) * .5
  1765.         END IF
  1766.         GOSUB calccom
  1767.     NEXT
  1768.     GOSUB adjustcom
  1769.     IF INT(TIMER) - VectorGroup(vecgroupindex).EventTimer > 20000 THEN
  1770.         PRINT VectorGroup(vecgroupindex).EventTimer
  1771.         END
  1772.  
  1773.         VectorGroup(vecgroupindex).ContentName = "Destroyed"
  1774.     END IF
  1775. IF thename$ = "UFO!!!" THEN
  1776.     GOSUB resetcom
  1777.     dt = timestep
  1778.     FOR particleindex = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1779.         xx = vecorig(particleindex, 1) - 150
  1780.         yy = vecorig(particleindex, 2) - 150
  1781.         vecorig(particleindex, 1) = xx * COS(dt) - yy * SIN(dt) + 150
  1782.         vecorig(particleindex, 2) = xx * SIN(dt) + yy * COS(dt) + 150
  1783.         GOSUB calccom
  1784.     NEXT
  1785.     GOSUB adjustcom
  1786.  
  1787.  
  1788. explode:
  1789. GOSUB resetcom
  1790. vecgroupindex = VectorGroup(1).Identity
  1791.     IF LTRIM$(RTRIM$(VectorGroup(vecgroupindex).ContentName)) = "Sparks" THEN
  1792.         FOR particleindex = VectorGroup(vecgroupindex).FirstParticle TO VectorGroup(vecgroupindex).LastParticle
  1793.             vecorig(particleindex, 1) = explodex
  1794.             vecorig(particleindex, 2) = explodey
  1795.             vecorig(particleindex, 3) = explodez
  1796.             vecorigvel(particleindex, 1) = (RND - .5) * 20
  1797.             vecorigvel(particleindex, 2) = (RND - .5) * 20
  1798.             vecorigvel(particleindex, 3) = (RND - .2) * 40
  1799.             vecorigacc(particleindex, 3) = -30
  1800.             GOSUB calccom
  1801.         NEXT
  1802.         GOSUB adjustcom
  1803.         EXIT DO
  1804.     END IF
  1805.     vecgroupindex = VectorGroup(vecgroupindex).Pointer
  1806.     IF vecgroupindex = -999 THEN EXIT DO
  1807.     vecgroupindex = VectorGroup(vecgroupindex).Identity
  1808.  
  1809. calccom:
  1810. VectorGroup(vecgroupindex).COMx = vecorig(particleindex, 1) + VectorGroup(vecgroupindex).COMx
  1811. VectorGroup(vecgroupindex).COMy = vecorig(particleindex, 2) + VectorGroup(vecgroupindex).COMy
  1812. VectorGroup(vecgroupindex).COMz = vecorig(particleindex, 3) + VectorGroup(vecgroupindex).COMz
  1813.  
  1814. adjustcom:
  1815. f = 1 + VectorGroup(vecgroupindex).LastParticle - VectorGroup(vecgroupindex).FirstParticle
  1816. VectorGroup(vecgroupindex).COMx = VectorGroup(vecgroupindex).COMx / f
  1817. VectorGroup(vecgroupindex).COMy = VectorGroup(vecgroupindex).COMy / f
  1818. VectorGroup(vecgroupindex).COMz = VectorGroup(vecgroupindex).COMz / f
  1819.  
  1820. resetcom:
  1821. VectorGroup(vecgroupindex).COMx = 0
  1822. VectorGroup(vecgroupindex).COMy = 0
  1823. VectorGroup(vecgroupindex).COMz = 0
Title: Re: Reddit's mobile app loading animation
Post by: FellippeHeitor on February 06, 2019, 01:36:39 pm
This is very satisfying to watch, STx! Destroying the rotor piece by piece was even more satisfying, I must say!
Title: Re: Reddit's mobile app loading animation
Post by: _vince on February 12, 2019, 03:53:51 pm
another variant, might be faster might be slower, needs a test.  Should be much faster for larger circles and possibly slower for smaller circles.  It draws the majority of the circle as a single LINE BF using Steve's algorithm

Code: QB64: [Select]
  1. 'vince's implementation of bresenham circles using steve-like optimizations
  2. sub circlef(x, y, r, c as long)
  3.         x0 = r
  4.         y0 = 0
  5.         e = -r
  6.     rr = r/sqr(2)
  7.         do while y0 < x0
  8.                 if e <= 0 then
  9.                         y0 = y0 + 1
  10.             line (x-x0, y+y0)-(x-rr, y+y0), c, bf
  11.             line (x+x0, y+y0)-(x+rr, y+y0), c, bf
  12.                         line (x-x0, y-y0)-(x-rr, y-y0), c, bf
  13.             line (x+x0, y-y0)-(x+rr, y-y0), c, bf
  14.                         e = e + 2*y0
  15.                 else
  16.                         line (x-y0, y-x0)-(x+y0, y-x0), c, bf
  17.                         line (x-y0, y+x0)-(x+y0, y+x0), c, bf
  18.                         x0 = x0 - 1
  19.                         e = e - 2*x0
  20.                 end if
  21.         loop
  22.         line (x-r,y)-(x-rr,y),c,bf
  23.     line (x+r,y)-(x+rr,y),c,bf
  24.     line (x-rr+1, y-rr)-(x+rr-1,y+rr),c,bf
  25.