Dot tunnels gave me fits trying to figure out. So here's one for the lulz, maybe it will help (or hinder) someone else!

`'''''''''''''''''''''''''''''''''''''''''''''''''''''''`

' DOT TUNNEL

' by boogop

' The c# logic from my entry for the Amiga

' demo a year or so ago

' - now in glorious lo-res!

'

' For me, dot tunnels were the hardest effect

' to figure out. There didn't seem to be many

' examples (before I found dbfinteractive, on

' which there are several) and the ones I could

' find on the intarnets or hornet archive were

' frequently not very good. Some of them

' weren't tunnels at all, they were tubes with the

' rings fixed in place. The best one I ever saw

' was Crystal2 BBS addy by Xography but they never

' released the source, and I haven't been able to

' figure out how they were handling the movement path

'''''''''''''''''''''''''''''''''''''''''''''''''''''''

#include "tinyptc_ext.bi"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' screen dimensions & put_pixel routine

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

const screenWidth = 320

const screenHeight = 200

const SCR_SIZE as integer = screenWidth*screenHeight

dim shared buffer( 0 to SCR_SIZE-1 ) as integer

dim shared as uinteger ptr pntr

dim shared as integer ptr p

declare sub put_pixel(buffer() as integer, byval x as integer, byval y as integer, byval col as integer)

' this may be Shockwave's routine!

sub put_pixel(buffer() as integer, byval x as integer, byval y as integer, byval col as integer)

if(y < screenHeight -1 and y > 1) then

if( x < screenWidth-1 and x > 1 ) then

PNTR = @buffer(y * screenWidth + x)

asm

mov eax, dword ptr[col]

mov edi, [pntr]

stosd

end asm

end if

end if

end sub

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' declare variables

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

type colors

dim as integer r,g,b

end type

dim shared as colors colArray(256)

const _pointsPerCircle = 20

const _numCircles = 35

dim shared as double zDistance = 8

' named star because I lifted it from my 3d starfield code :)

type star

dim as double xpos, ypos, speed, zpos

dim as double origX, origY, origZ

dim as integer oldx,oldy

end type

dim shared as star circles(_numCircles, _pointsPerCircle)

dim shared as double maxZ = 0

dim shared as double diam = 50

dim shared as double xp,yp,zp,increment, px, py, skew, skewCount

dim shared as integer angle = 0

dim shared as double zPos = 1

dim shared as integer angleAdder = int(360 / _pointsPerCircle)

dim shared as double zPosAdder

dim shared as double midWidth = screenWidth / 2

dim shared as double midHeight = screenHeight / 2

dim as integer i,j, xpathcount

dim as double rad = 3.1416 / 180.0

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' set initial values

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

skewCount = .0001

zPosAdder = zDistance / _numCircles

for j = 0 to _numCircles

for i = 0 to _pointsPerCircle

dim as double Y = diam * Sin(angle * rad)

dim as double X = 2 * diam * Cos(angle * rad) ' make it oval shaped for the lulz

circles(j, i).xpos = X

circles(j, i).ypos = Y

circles(j, i).speed = .0025

circles(j, i).zpos = zPos

circles(j, i).origX = X

circles(j, i).origY = Y

circles(j, i).oldx = 0

circles(j, i).oldy = 0

angle += angleAdder

next i

zPos += zPosAdder

next j

maxZ = 0

' figure out the largest z value

for j = 0 to _numCircles

for i = 0 to _pointsPerCircle

if circles(j, i).zpos > maxZ then

maxZ = circles(j, i).zpos

end if

next i

next j

increment = 0

' fill color array

i = 0

while i < 256

dim as single red = 1 + Cos(i * 3.14 / 128)

dim as single grn = 1 + Cos((i - 85) * 3.14 / 128)

dim as single blu = 1 + Cos((i + 85) * 3.14 / 128)

colArray(i).r = int(red * 127) mod 256

colArray(i).g = int(grn * 127) mod 256

colArray(i).b = int(blu * 127) mod 256

i = i+1

wend

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' run the thing

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'ptc_setdialog(1,"FullScreen?",0,0)

if( ptc_open( "freeBASIC - tinyPTC Dot Tunnel", screenWidth, screenHeight ) = 0 ) then

end -1

end if

while inkey() <> chr(27)

if skew <= 1 then

skew = skew + skewcount

end if

for i = 0 to _numCircles

for j = 0 to _pointsPerCircle

' erase the last point

put_pixel Buffer(),circles(i, j).oldx,circles(i, j).oldy,0

put_pixel Buffer(),circles(i, j).oldx+1,circles(i, j).oldy,0

' bring each circle towards the viewer

circles(i, j).zpos -= circles(i, j).speed

' if a circle is close enough to the viewer, send it to the back

' using the maximum z value

if circles(i, j).zpos < 2 then

circles(i, j).xpos = circles(i, j).origX

circles(i, j).ypos = circles(i, j).origY

circles(i, j).zpos = maxZ

end if

' most compilers will perform some kind of bounds checks, and those

' will really bog an app down. Cast the array to vars so any bounds

' checking only has to happen once

xp = circles(i, j).xpos

yp = circles(i, j).ypos

zp = circles(i, j).zpos

' kludgey color fader lol

dim as double cc = 1 - Abs(zp / (maxZ * .8))

if (cc < 0) then

cc = 0

end if

if (cc > 1) then

cc = 1

end if

dim as integer c = int(300 * cc)

if c > 255 then

c = 255

end if

dim as integer co = rgb(colArray(c).b,colArray(c).r,colArray(c).g)

if zp > int(maxZ * .6) then

co = rgb(colArray(c).b/2,c,c)

end if

' zpos isn't quite right and doesn't bring the circles as close

' as it should but I don't feel like fixing it!

dim as double z = zp - 1.5

' path of the tunnel

px = 50 * Sin(z * skew * sin(increment))

py = 40 * Cos(z * skew * cos(increment))

' calculate perspective, add path, align to center screen

dim as double sx = (xp / z) + px + midWidth

dim as double sy = (yp / z) - py + midHeight

dim as integer ix = int(sx)

dim as integer iy = int(sy)

put_pixel Buffer(),ix,iy,co

put_pixel Buffer(),ix+1,iy,co

' save the current pos so we can erase it in the next iteration

circles(i, j).oldx = ix

circles(i, j).oldy = iy

next j

next i

increment +=.0005

ptc_update @buffer(0)

wend