Here is a little example/pseudo 3D thing I wrote a while ago. There is not much explaining comment so you have to figure it out yourself ;)
SuperStrict
Global gBoxWidth# = 297
Global gBoxHeight# = 420
Global gBoxThickness# = 10
Graphics 800, 600, 32, 60
Global gWorld:TWorld = New TWorld
Local cube:TCube = TCube.Create(9,.9,9)
SetClsColor(255, 255, 255)
Local theta# = gWorld.pfTheta
Local phi# = gWorld.pfPhi
Local st# = 1.5
While Not KeyHit(KEY_ESCAPE)
Cls
cube.Update()
cube.Draw()
If MouseDown(1) Then
theta:+st
gWorld.SetTheta(theta)
End If
If MouseDown(2) Then
phi:+st
gWorld.SetPhi(phi)
End If
Flip
Wend
End
Type TPoint
Field pfX:Float, pfY:Float
Method New()
pfX = 0
pfY = 0
End Method
Method GetX#()
Return pfX
End Method
Method GetY#()
Return pfY
End Method
Method SetX(fX#)
pfX = fX
End Method
Method SetY(fY#)
pfY = fY
End Method
Method SetPoint(fx#, fy#)
pfX = fx
pfY = fy
End Method
Method AddX(dx#)
pfX:+dx
End Method
Method AddY(dy#)
pfY:+dy
End Method
Method Duplicate:TPoint()
Local p:TPoint = New TPoint
p.SetPoint(pfX, pfY)
Return p
End Method
Method DistanceTo#(pos:TPoint)
Return Sqr((pfX - pos.GetX()) ^ 2 + (pfY - pos.GetY()) ^ 2)
End Method
End Type
Type TWorld
Field pfD# = 50
Field pfVD# = 1400
Field pfTheta#
Field pfPhi#
Field pfSN1#
Field pfCN1#
Field pfSN2#
Field pfCN2#
Field pfTX# = GraphicsWidth() / 2
Field pfTY# = GraphicsHeight() / 2
Field pfScf# = 1.2
Field pfS# = 2
Field pfK1# = 7
Field pfK2# = 10
Field pfW#
Method New()
pfW = pfK2 / (pfK2 - pfK1)
SetTheta(90)
SetPhi(70)
End Method
Method SetTheta(fTheta#)
pfTheta = fTheta
pfSN1 = Sin(pfTheta)
pfCN1 = Cos(pfTheta)
End Method
Method SetPhi(fPhi#)
pfPhi = fPhi
pfSN2 = Sin(pfPhi)
pfCN2 = Cos(pfPhi)
End Method
Method GetEyeCoord:T3DVector(worldCoord:T3DVector)
Local eyeCoord:T3DVector = New T3DVector
eyeCoord.setX(-worldCoord.getX() * pfSN1 + worldCoord.getY() * pfCN1)
eyeCoord.setY(-worldCoord.getX() * pfCN1 * pfCN2 - worldCoord.getY() * pfSN1 * pfCN2 + worldCoord.getZ() * pfSN2)
eyeCoord.setZ(-worldCoord.getX() * pfSN2 * pfCN1 - worldCoord.getY() * pfSN1 * pfSN2 - worldCoord.getZ() * pfCN2 + pfD)
Return eyeCoord
End Method
Method GetScreenCoord:T3DVector(eyeCoord:T3DVector)
Local screenCoord:T3DVector = New T3DVector
screenCoord.setX((pfVD / pfS) * (eyeCoord.getX() / eyeCoord.getZ()) )
screenCoord.setY((pfVD / pfS) * (eyeCoord.getY() / eyeCoord.getZ()) )
screenCoord.setZ(pfW * (1 - pfK1 / eyeCoord.getZ()) )
Return screenCoord
End Method
Method Get2DPoint:TPoint(worldCoord:T3DVector)
Local x#, y#
Local screen:T3DVector = getScreenCoord(getEyeCoord(worldCoord))
Local p:TPoint = New TPoint
x = screen.getX() * pfScf + pfTX
y = pfTY - screen.getY()
p.SetPoint(x, y)
Return p
End Method
Method GetLineOfSight:T3DVector()
Local l:T3DVector = New T3DVector
l.setX(pfD * pfSN2 * pfCN1)
l.setY(pfD * pfSN2 * pfSN1)
l.setZ(pfD * pfCN2)
Return l
End Method
End Type
Type T3DVector
Field pfX#
Field pfY#
Field pfZ#
Method SetX(fx#)
pfX = fx
End Method
Method SetY(fy#)
pfY = fy
End Method
Method SetZ(fz#)
pfZ = fz
End Method
Method GetX#()
Return pfX
End Method
Method GetY#()
Return pfY
End Method
Method GetZ#()
Return pfZ
End Method
End Type
Type TCube
Field paV:T3DVector[8]
Field paSC:TPoint[8]
Field paSF%[6, 5]
Field paNPS%[6]
Field paN:T3DVector[6]
Field paVSF:Byte[6]
Field paE%[12, 4]
Field piNVE%
Function Create:TCube(fWidth#, fHeight#, fDepth#)
Local c:TCube = New TCube
Local i%, j%, n%, x#, y#, z#
RestoreData vertex
For i = 0 To 7
c.paV[i] = New T3DVector
c.paSc[i] = New TPoint
ReadData x
c.paV[i].setX(x * fWidth)
ReadData y
c.paV[i].setY(y * fHeight)
ReadData z
c.paV[i].setZ(z * fDepth)
Next
'surface array
RestoreData surface
For i = 0 To 5
ReadData n
c.paNPS[i] = n
Next
For i = 0 To 5
For j = 0 To (c.paNPS[i]-1)
ReadData n
c.paSF[i, j] = n-1
Next
Next
'normal array
Local u:T3DVector = New T3DVector
Local w:T3DVector = New T3DVector
For i = 0 To 5
c.paN[i] = New T3DVector
u.setX(c.paV[c.paSF[i, 1]].getX() - c.paV[c.paSF[i, 0]].getX())
u.setY(c.paV[c.paSF[i, 1]].getY() - c.paV[c.paSF[i, 0]].getY())
u.setZ(c.paV[c.paSF[i, 1]].getZ() - c.paV[c.paSF[i, 0]].getZ())
w.setX(c.paV[c.paSF[i, 2]].getX() - c.paV[c.paSF[i, 0]].getX())
w.setY(c.paV[c.paSF[i, 2]].getY() - c.paV[c.paSF[i, 0]].getY())
w.setZ(c.paV[c.paSF[i, 2]].getZ() - c.paV[c.paSF[i, 0]].getZ())
c.paN[i].setX(u.getY() * w.getZ() - w.getY() * u.getZ())
c.paN[i].setY(u.getZ() * w.getX() - w.getZ() * u.getX())
c.paN[i].setZ(u.getX() * w.getY() - w.getX() * u.getY())
Next
Return c
End Function
Method Update()
Local i%, j%, k%, lx#, ly#, lz#, ft#
'visiblity test
Local p:T3DVector = gWorld.GetLineOfSight()
For i = 0 To 5
lx = p.getX() - paV[paSF[i, 0]].getX()
ly = p.getY() - paV[paSF[i, 0]].getY()
lz = p.getZ() - paV[paSF[i, 0]].getZ()
ft = paN[i].getX() * lx + paN[i].getY() * ly + paN[i].getZ() * lz
paVSF[i] = (ft>0)
Next
'visible edge array
'clear edge array first
For i = 0 To 11
For j = 0 To 3
paE[i, j] = 0
Next
Next
Local m% = 0, e1%, e2%, skip:Byte
piNVE = 5
For i = 0 To 5
If paVSF[i] Then
e1 = paSF[i, 0]
For j = 1 To paNPS[i]-1
e2 = paSF[i, j]
skip = False
For k = 0 To m'(m-1)
If paE[k, 0] = e2 And paE[k, 1] = e1 Then
paE[k, 2] = 1
paE[k, 3] = i
skip = True
Exit
End If
Next
If Not skip Then
paE[m, 0] = e1
paE[m, 1] = e2
paE[m, 2] = 0
paE[m, 3] = i
m:+1
End If
e1 = e2
Next
piNVE = m - 1
End If
Next
For i = 0 To 7
paSc[i] = gWorld.Get2Dpoint(paV[i])
Next
End Method
Method Draw()
Local a#, b#, c#, d#, f1%, f2%
SetLineWidth(2)
For Local i% = 0 To piNVE
If paE[i, 2] <> 999 Then
f1 = paE[i, 0]
f2 = paE[i, 1]
a = paSC[f1].getX()
b = paSC[f1].getY()
c = paSC[f2].getX()
d = paSC[f2].getY()
SetColor(80, 60, 100)
DrawLine(a,b,c,d)
SetColor(100, 80, 60)
DrawOval(c-7, d-7, 13, 13)
End If
Next
End Method
End Type
#vertex
DefData 1, 1,-1
DefData 1, 1, 1
DefData 1,-1, 1
DefData 1,-1,-1
DefData -1, 1,-1
DefData -1,-1,-1
DefData -1,-1, 1
DefData -1, 1, 1
#surface
DefData 5,5,5,5,5,5
DefData 1,2,3,4,1
DefData 1,5,8,2,1
DefData 5,6,7,8,5
DefData 4,3,7,6,4
DefData 2,8,7,3,2
DefData 1,4,6,5,1