Code archives/3D Graphics - Maths/3D math functions

This code has been declared by its author to be Public Domain code.

Download source code

3D math functions by Nilium
(Posted 22 years ago)
Various functions used in Vein R3; if you don't know what it does, chances are you don't need it.
;#Region DESCRIPTION
	;; Math functions, Vector class taken from the Anima engine (written by me)
;#End Region

;#Region CLASSES
	Type Vector
		Field X#
		Field Y#
		Field Z#
	End Type
	
	Type Size
		Field Width#
		Field Height#
		Field Depth#
	End Type
	
	Type Cube
		Field Position.Vector
		Field Size.Size
	End Type
	
	Type Rectangle
		Field X,Y,Width,Height
		Field Onscreen
	End Type
;#End Region

;#Region PROCEDURES
	Function Size.Size(Width#=0,Height#=0,Depth#=0)
		Local s.Size = New Size
		s\Width = Width
		s\Height = Height
		s\Depth = Depth
		Return s
	End Function
	
	Function Vector.Vector(X#=0,Y#=0,Z#=0)
		Local v.Vector = New Vector
		v\X = X
		v\Y = Y
		v\Z = Z
		Return v
	End Function
	
	Function VectorAdd(a.Vector,b.Vector)
		a\X =a\X + b\X
		a\Y =a\Y + b\Y
		a\Z =a\Z + b\Z
	End Function
	
	Function VectorSubtract(a.Vector,b.Vector)
		a\X =a\X - b\X
		a\Y =a\Y - b\Y
		a\Z =a\Z - b\Z
	End Function
	
	Function VectorSum.Vector(a.Vector,b.Vector)
		Return Vector(a\X+b\X,a\Y+b\Y,a\Z+b\Z)
	End Function
	
	Function VectorDifference.Vector(a.Vector,b.Vector)
		Return Vector(a\X-b\X,a\Y-b\Y,a\Z-b\Z)
	End Function
	
	Function VectorMultiply(a.Vector,b.Vector)
		a\X =a\X * b\X
		a\Y =a\Y * b\Y
		a\Z =a\Z * b\Z
	End Function
	
	Function VectorDivide(a.Vector,b.Vector)
		a\X =a\X / b\X
		a\Y =a\Y / b\Y
		a\Z =a\Z / b\Z
	End Function
	
	Function VectorProduct.Vector(a.Vector,b.Vector)
		Return Vector(a\X*b\X,a\Y*b\Y,a\Z*b\Z)
	End Function
	
	Function VectorQuotient.Vector(a.Vector,b.Vector)
		Return Vector(a\X/b\X,a\Y/b\Y,a\Z/b\Z)
	End Function
	
	Function VectorCross.Vector(a.Vector,b.Vector)
		Return Vector( (a\Y*b\Z)-(a\Z*b\Y), (a\Z*b\X)-(a\X*b\Z), (a\X*b\Y)-(a\Y*b\X) )
	End Function
	
	Function VectorDot#(a.Vector,b.Vector)
		Return (a\X*b\X) + (a\Y*b\Y) + (a\Z*b\Z)
	End Function
	
	Function VectorAngle#(a.Vector,b.Vector)
		Local d# = VectorDot(a,b)
		Local m# = VectorMagnitude(a)*VectorMagnitude(b)
		Return ACos(d#/m#)
	End Function
	
	Function VectorNormalize(a.Vector)
		Local m# = VectorMagnitude(a)
		a\X = a\X / m#
		a\Y = a\Y / m#
		a\Z = a\Z / m#
	End Function
	
	Function VectorMagnitude#(a.Vector)
		Return Sqr(a\X*a\X + a\Y*a\Y + a\Z*a\Z)
	End Function
	
	Function VectorScale(a.Vector,b#)
		a\X = a\X * b#
		a\Y = a\Y * b#
		a\Z = a\Z * b#
	End Function
	
	Function VectorSDivide(a.Vector,b#)
		a\X = a\X / b#
		a\Y = a\Y / b#
		a\Z = a\Z / b#
	End Function
	
	Function MinF#(A#,B#)
		If A < B Then Return B
		Return A
	End Function
	
	Function MinI%(A%,B%)
		If A < B Then Return B
		Return A
	End Function
	
	Function MaxF#(A#,B#)
		If A > B Then Return B
		Return A
	End Function
	
	Function MaxI%(A%,B%)
		If A > B Then Return B
		Return A
	End Function
	
	Function ConstrictF#(A#,B#,C#)
		If A > C Then
			While A > C
				A = A - (C-B)
			Wend
		ElseIf A < B Then
			While A < B
				A = A + (C-B)
			Wend
		EndIf
		Return A
	End Function
	
	Function ConstrictI#(A%,B%,C%)
		If A > C Then
			While A > C
				A = A - (C-B)
			Wend
		ElseIf A < B Then
			While A < B
				A = A + (C-B)
			Wend
		EndIf
		Return A
	End Function
	
	Function PointInRect(PX,PY,RX,RY,W,H)
		Return (PX >= RX) And (PY >= RY) And (PX <= RX+W) And (PY <= RY+H)
	End Function
	
	Function NearestPower(N#)
		v# = 1
		While N# > v#
			v# = v# * 2
		Wend
		k# = v# - N#
		Return v/(1 Or (k# > v/4))
	End Function
	
	Function GetCube.Cube(Camera,x#,y#,z#,sx#,sy#,sz#)
		Local MinX=9999,MinY=9999,MaxX=-9999,MaxY=-9999,MaxZ=-9999
		
		Local c = Camera
		
		CameraProject c,x,y,z
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,sx,y,z
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,sx,y,sz
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,x,y,sz
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,x,sy,z
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,sx,sy,z
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,sx,sy,sz
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		CameraProject c,x,sy,sz
		px = ProjectedX()
		py = ProjectedY()
		pz = ProjectedZ()
		
		If px < MinX Then MinX = px
		If py < MinY Then MinY = py
		If px > MaxX Then MaxX = px
		If py > MaxY Then MaxY = py
		If pz > MaxZ Then MaxZ = pz
		
		i.Cube = New Cube
		i\Position = Vector(MinX,MinY,-1)
		i\Size = Size(MaxX-MinX,MaxY-MinY,MaxZ)
		Return i
	End Function
	
	Function CubeInCamera(Camera,x#,y#,z#,sx#,sy#,sz#)
		Local c = Camera
		Local MinX=9999,MinY=9999,MaxX=-9999,MaxY=-9999
		
		CameraProject c,x,y,z
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,sx,y,z
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,sx,y,sz
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,x,y,sz
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,x,sy,z
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,sx,sy,z
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,sx,sy,sz
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		
		CameraProject c,x,sy,sz
		px = ProjectedX()
		py = ProjectedY()
		If ProjectedZ() >= 1 Then
			If px < MinX Then MinX = px
			If px > MaxX Then MaxX = px
			If py < MinY Then MinY = py
			If py > MaxY Then MaxY = py
		EndIf
		z = z + ProjectedZ()
		Stop
		If z <= 0 Then Return
		
		Return RectsOverlap(0,0,GraphicsWidth(),GraphicsHeight(),MinX,MinY,maxx-minx,maxy-miny)
	End Function
	
	Function GetMeshAABB.Cube(Mesh,glbl=1)
		c.Cube = New Cube
		c\Position = Vector()
		c\Size = Size()
		
		Local min#[3]
		Local max#[3]
		
		For x# = 0 To 3
			min[x] = 65536
			max[x] = -65536
		Next
		
		Local MX = 1
		Local MY = 2
		Local MZ = 3
		
		For surfaces = 1 To CountSurfaces(Mesh)
			s = GetSurface(Mesh,surfaces)
			For i = 0 To CountVertices(s)-1
				x# = VertexX(s,i)
				y# = VertexY(s,i)
				z# = VertexZ(s,i)
				
				If glbl Then
					TFormPoint x,y,z,Mesh,0
					x = TFormedX()
					y = TFormedY()
					z = TFormedZ()
				EndIf
				
				If x < min[MX] Then min[MX] = x
				If x > max[MX] Then max[MX] = x
				
				If y < min[MY] Then min[MY] = y
				If y > max[MY] Then max[MY] = y
				
				If z < min[MZ] Then min[MZ] = z
				If z > max[MZ] Then max[MZ] = z
			Next
		Next
		
		c\Position\x = min[MX]-.1
		c\Position\y = min[MY]-.1
		c\Position\z = min[MZ]-.1
		c\Size\Width = max[MX]-min[MX]+.2
		c\Size\height = max[MY]-min[MY]+.2
		c\Size\depth = max[MZ]-min[MZ]+.2
		Return c
	End Function
	
	Function AABBToScreen.Rectangle(Camera,x#,y#,z#,width#,height#,depth#)
		r.Rectangle = New Rectangle
		
		Local minx=16777215,miny=16777215,maxx=-16777215,maxy=-16777215
		
		CameraProject Camera,x,y,z
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x+width,y,z
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x+width,y,z+depth
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x,y,z+depth
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x,y+height,z
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x+width,y+height,z
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x+width,y+height,z+depth
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		CameraProject Camera,x,y+height,z+depth
		zs = zs + (ProjectedZ() > 0)
		px = ProjectedX()
		py = ProjectedY()
		
		If px > maxx Then maxx = px
		If px < minx Then minx = px
		
		If py > maxy Then maxy = py
		If py < miny Then miny = py
		
		r\Onscreen = 1
		r\x = minx
		r\y = miny
		r\width = maxx-minx
		r\height = maxy-miny
		
		Return r
	End Function
	
	Function FreeCube(c.Cube)
		If c = Null Then Return
		Delete c\Size
		Delete c\Position
		Delete c
	End Function
	
	Function PointInCube(x#,y#,z#,c.Cube)
		Return (x >= c\Position\X And x <= c\Position\X+c\Size\Width And y => c\Position\Y And y <= c\Position\Y+c\Size\Height And z => c\Position\Z And z <= c\Position\Z+c\Size\Depth)
	End Function
	
	Function CreateMeshBox(Entity)
		Local MinX#,MinY#,MinZ#
		Local MaxX#,MaxY#,MaxZ#
		For n = 1 To CountSurfaces(Entity)
			s = GetSurface(Entity,n)
			For i = 0 To CountVertices(s)-1
				x# = VertexX(s,i)
				y# = VertexY(s,i)
				z# = VertexZ(s,i)
				
				If x < MinX Then MinX = x
				If x > MaxX Then MaxX = x
				
				If y < MinY Then MinY = y
				If y > MaxY Then MaxY = y
				
				If z < MinZ Then MinZ = z
				If z > MaxZ Then MaxZ = z
			Next
		Next
		EntityBox Entity,MaxX,MaxY,MaxZ,MinX-MaxX,MinY-MaxY,MinZ-MaxZ
	End Function
;#End Region