Option Strict Off
Option Explicit On
Module EngineShell
	
	'This module is a simplifying syntax shell for David Piuva's graphics engine.
	'By only using simple datatypes in the ActiveX interface, more languages are supported.
	
	'Whenever a new method in the engine have complicated ways to get called, make
	'  your own method in you own shell module for easy upgrading.
	'Remember to replace frmMain.DGE with whatever your window and engine instance is called.
	
	'Break and show error messages from the graphics engine
	'This should be placed after every call to the engine that can give error messages so that the application will break in debug mode when an error has occured.
	'It will continue to break on each point until the error message is deleted by reading it.
	'   String buffer methods don't give error messages because they are used to show the message.
	'   Matrix buffer methods don't have any preconditions.
	Friend Sub RE()
		Static Messages As String
		If frmMain.DGE.Message_GetCount > 0 Then
			frmMain.DGE.Message_GetContent_OutSB()
			Messages = GetStringFromEngine
			Do While frmMain.DGE.Message_GetCount > 0
				frmMain.DGE.Message_GetContent_OutSB()
				Messages = Messages & vbNewLine & vbNewLine & GetStringFromEngine
			Loop 
			MsgBox(Messages, MsgBoxStyle.Critical, "Messages from the graphics engine!")
			System.Diagnostics.Debug.Assert(False, "") 'Stop debug execution to see where the error occured using the call stack.
		End If
	End Sub
	
	'Ignore error messages
	Friend Sub IE()
		Do While frmMain.DGE.Message_GetCount > 0
			frmMain.DGE.Message_GetContent_OutSB()
		Loop
	End Sub
	
	Friend Sub SetRelativeWorkingDirectory(ByRef RelativePath As String)
		InsertStringToEngine(My.Application.Info.DirectoryPath & "\" & RelativePath) : frmMain.DGE.Engine_SetCurrentDirectory_InSB() : RE()
	End Sub
	
	Friend Sub InsertStringToEngine(ByRef T As String)
		Static I As Integer
		frmMain.DGE.SetLengthOfStringBuffer(Len(T))
		For I = 1 To Len(T)
			frmMain.DGE.WriteToStringBuffer(I, Asc(Mid(T, I, 1)))
		Next I
	End Sub
	
	Friend Function GetStringFromEngine() As String
		Static I As Integer
		GetStringFromEngine = ""
		For I = 1 To frmMain.DGE.GetLengthOfStringBuffer
			GetStringFromEngine = GetStringFromEngine & Chr(frmMain.DGE.ReadFromStringBuffer(I))
		Next I
	End Function
	
	Friend Function GetVector2FromMatrixBuffer() As Vector2
		GetVector2FromMatrixBuffer = MakeVector2(frmMain.DGE.GetX1, frmMain.DGE.GetY1)
	End Function
	
	Friend Function GetVector3FromMatrixBuffer() As Vector3
		GetVector3FromMatrixBuffer = MakeVector3(frmMain.DGE.GetX1, frmMain.DGE.GetY1, frmMain.DGE.GetZ1)
	End Function
	
	Friend Function GetSecondVector3FromMatrixBuffer() As Vector3
		GetSecondVector3FromMatrixBuffer = MakeVector3(frmMain.DGE.GetX2, frmMain.DGE.GetY2, frmMain.DGE.GetZ2)
	End Function
	
	Friend Function GetVector4FromMatrixBuffer() As Vector4
		GetVector4FromMatrixBuffer = MakeVector4(frmMain.DGE.GetX1, frmMain.DGE.GetY1, frmMain.DGE.GetZ1, frmMain.DGE.GetW1)
	End Function
	
	Friend Function GetMatrix3FromMatrixBuffer() As Matrix3
		GetMatrix3FromMatrixBuffer = MakeMatrix3(MakeVector3(frmMain.DGE.GetX1, frmMain.DGE.GetY1, frmMain.DGE.GetZ1), MakeVector3(frmMain.DGE.GetX2, frmMain.DGE.GetY2, frmMain.DGE.GetZ2), MakeVector3(frmMain.DGE.GetX3, frmMain.DGE.GetY3, frmMain.DGE.GetZ3))
	End Function
	
	Friend Function GetMatrix4FromMatrixBuffer() As Matrix4
		GetMatrix4FromMatrixBuffer = MakeMatrix4(MakeVector4(frmMain.DGE.GetX1, frmMain.DGE.GetY1, frmMain.DGE.GetZ1, frmMain.DGE.GetW1), MakeVector4(frmMain.DGE.GetX2, frmMain.DGE.GetY2, frmMain.DGE.GetZ2, frmMain.DGE.GetW2), MakeVector4(frmMain.DGE.GetX3, frmMain.DGE.GetY3, frmMain.DGE.GetZ3, frmMain.DGE.GetW3), MakeVector4(frmMain.DGE.GetX4, frmMain.DGE.GetY4, frmMain.DGE.GetZ4, frmMain.DGE.GetW4))
	End Function
	
	Friend Sub SetInstanceAxisSystem(Instance As Integer, System As Matrix3)
		frmMain.DGE.Instance_SetXAxis(Instance, System.XAxis.X, System.XAxis.Y, System.XAxis.Z)
		frmMain.DGE.Instance_SetYAxis(Instance, System.YAxis.X, System.YAxis.Y, System.YAxis.Z)
		frmMain.DGE.Instance_SetZAxis(Instance, System.ZAxis.X, System.ZAxis.Y, System.ZAxis.Z)
		RE
	End Sub
	
	'The result is normalized and orthogonal so that it's transpose equals it's inverse.
	Friend Function MakeAxisSystem_Polar(Longitude As Single, Lattitude As Single) As Matrix3
		'Right
		MakeAxisSystem_Polar.XAxis.X = System.Math.Cos(Longitude)
		MakeAxisSystem_Polar.XAxis.Y = 0
		MakeAxisSystem_Polar.XAxis.Z = -System.Math.Sin(Longitude)
		'Up
		MakeAxisSystem_Polar.YAxis.X = System.Math.Sin(Longitude) * -System.Math.Sin(Lattitude)
		MakeAxisSystem_Polar.YAxis.Y = System.Math.Cos(Lattitude)
		MakeAxisSystem_Polar.YAxis.Z = System.Math.Cos(Longitude) * -System.Math.Sin(Lattitude)
		'Forward
		MakeAxisSystem_Polar.ZAxis.X = System.Math.Sin(Longitude) * System.Math.Cos(Lattitude)
		MakeAxisSystem_Polar.ZAxis.Y = System.Math.Sin(Lattitude)
		MakeAxisSystem_Polar.ZAxis.Z = System.Math.Cos(Longitude) * System.Math.Cos(Lattitude)
	End Function
	
	'The result is normalized and orthogonal so that it's transpose equals it's inverse.
	Friend Function MakeAxisSystem_Orthogonalized(Forward As Vector3, Up As Vector3) As Matrix3
		Dim Forward_Normalized As Vector3
		Forward_Normalized = NormalVector3(Forward)
		MakeAxisSystem_Orthogonalized.ZAxis = Forward_Normalized
		MakeAxisSystem_Orthogonalized.XAxis = NormalVector3(CrosProduct(NormalVector3(Up), Forward_Normalized))
		MakeAxisSystem_Orthogonalized.YAxis = NormalVector3(CrosProduct(Forward_Normalized, MakeAxisSystem_Orthogonalized.XAxis))
	End Function
	
	Friend Function MakeAxisSystem_DirectedUp(Direction As Vector3, CameraDirection As Vector3) As Matrix3
		Dim NormalizedDirection As Vector3
		Dim M As Matrix3
		NormalizedDirection = NormalVector3(Direction)
		If NormalizedDirection.Y < -0.8 or NormalizedDirection.Y > 0.8 Then
			M = MakeAxisSystem_Orthogonalized(NormalizedDirection, NormalVector3(MakeVector3(CameraDirection.X, 0, CameraDirection.Z)))
		Else
			M = MakeAxisSystem_Orthogonalized(NormalizedDirection, MakeVector3(0, 1, 0))
		End If
		MakeAxisSystem_DirectedUp.XAxis = NegVector3(M.XAxis)
		MakeAxisSystem_DirectedUp.YAxis = M.ZAxis
		MakeAxisSystem_DirectedUp.ZAxis = M.YAxis
	End Function
	
	Friend Function GetVelocityAtPointFromRigidBody(RigidBody As Integer, WorldSpacePoint As Vector3) As Vector3
		frmMain.DGE.RigidBody_GetVelocityAtPoint_OutV3(RigidBody, WorldSpacePoint.X, WorldSpacePoint.Y, WorldSpacePoint.Z): GetVelocityAtPointFromRigidBody = GetVector3FromMatrixBuffer: RE
	End Function
	
	Friend Sub ApplyForce_Linear(RigidBody As Integer, Acc As Vector3)
		frmMain.DGE.RigidBody_Dynamic_ApplyForce_Linear(RigidBody, Acc.X, Acc.Y, Acc.Z): RE
	End Sub
	
	Friend Sub ApplyForce_Angular(RigidBody As Integer, Acc As Vector3)
		frmMain.DGE.RigidBody_Dynamic_ApplyForce_Angular(RigidBody, Acc.X, Acc.Y, Acc.Z): RE
	End Sub
	
	Friend Function GetDimensionsFromModel(Model As Integer) As Vector3
		Dim Min As Vector3
		Dim Max As Vector3
		frmMain.DGE.Model_GetBoundingBoxMinimum_OutV3(Model): Min = GetVector3FromMatrixBuffer: RE
		frmMain.DGE.Model_GetBoundingBoxMaximum_OutV3(Model): Max = GetVector3FromMatrixBuffer: RE
		GetDimensionsFromModel = SubVector3(Max, Min)
	End Function
	
	Friend Function LoadModel(Filename As String) As Integer
		InsertStringToEngine(Filename)
		LoadModel = frmMain.DGE.Model_LoadFromFile_InSB() : IE()
		If LoadModel <= 0 Then
			LoadModel = Model_NotFound
		End If
	End Function
	
	Friend Sub SafeDeleteInstance(ByRef InstanceRef As Integer)
		If InstanceRef > 0 Then
			frmMain.DGE.Instance_Delete(InstanceRef) : RE()
			InstanceRef = 0
		End If
	End Sub
	
	Friend Sub SafeDeleteModel(ByRef ModelRef As Integer)
		If ModelRef > 0 and ModelRef <> Model_NotFound Then
			frmMain.DGE.Model_Delete(ModelRef) : RE()
		End If
		ModelRef = 0
	End Sub
	
	Friend Sub PlaceCameraUsingDirection(ByVal Camera As Integer, Position As Vector3, Direction As Vector3, Up As Vector3)
		frmMain.DGE.Camera_Place(Camera, Position.x, Position.y, Position.z, Position.x + Direction.x, Position.y + Direction.y, Position.z + Direction.z, Up.x, Up.y, Up.z) : RE()
	End Sub
	
	Friend Function CameraHasVerticalFOV(ByVal CameraRef As Integer) As Boolean
		CameraHasVerticalFOV = (frmMain.DGE.Camera_IsFieldOfViewVertical(CameraRef) <> 0) : RE()
	End Function
	
	Friend Sub SetVisibility(ByVal Instance As Integer, ByVal Visible As Boolean)
		frmMain.DGE.Instance_SetVisibility(Instance, 0, Visible) : RE() 'Visible light
		frmMain.DGE.Instance_SetVisibility(Instance, 1, Visible) : RE() 'Shadow casting
	End Sub
	
	Friend Function StartEngine() As Boolean
		StartEngine = frmMain.DGE.Engine_Initiate : RE()
	End Function
End Module