mxUserInputDriverGUI

mxUserInputDriverGUI

refs gh-17

Rem
	bbdoc: User Input interface
End Rem
Type mxUserInput

	Rem
		bbdoc:Command Line Interface
	End Rem
	Const c_cli:Byte = 0

	Rem
		bbdoc:Graphical User Interface
	End Rem
	Const c_gui:Byte = 1

	Field m_driver:mxUserInputDriver

	Rem
		bbdoc: Factory for initializing mxUserInput object
		about: interface can be either c_cli of c_gui
	End Rem
	Function factory:mxUserInput(interface:Byte)
		Local ui:mxUserInput = New mxUserInput
		Select interface
			Case c_cli
				ui.m_driver = New mxUserInputDriverCLI
			Case c_gui
				ui.m_driver = New mxUserInputDriverGUI
		End Select
		Return ui
	End Function

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Return Self.m_driver.Confirm(question)
	End Method

End Type

Rem
	bbdoc: User Input Driver interface
End Rem
Type mxUserInputDriver Abstract

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String) Abstract

End Type

Rem
	bbdoc: UserInpitDriver for Command Line Interface
End Rem
Type mxUserInputDriverCLI Extends mxUserInputDriver

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Local resp:String = Input(question + " ").ToLower()
		If resp = "y" Or resp = "yes"
			Return True
		Else
			Return False
		End If
	End Method

End Type

Type mxUserInputDriverGUI Extends mxUserInputDriver
	Rem
		bbdoc:Ask user to confirm an action
	End Rem
	Method Confirm:Byte(question:String)
		Return Confirm(question)
	End Method

End Type

Rem
	bbdoc: User Input interface
End Rem
Type mxUserInput

	Rem
		bbdoc:Command Line Interface
	End Rem
	Const c_cli:Byte = 0

	Rem
		bbdoc:Graphical User Interface
	End Rem
	Const c_gui:Byte = 1

	Field m_driver:mxUserInputDriver

	Rem
		bbdoc: Factory for initializing mxUserInput object
		about: interface can be either c_cli of c_gui
	End Rem
	Function factory:mxUserInput(interface:Byte)
		Local ui:mxUserInput = New mxUserInput
		Select interface
			Case c_cli
				ui.m_driver = New mxUserInputDriverCLI
			Case c_gui
				RuntimeError("GUI driver not yet supported!")
		End Select
		Return ui
	End Function

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Return Self.m_driver.Confirm(question)
	End Method

End Type

Rem
	bbdoc: User Input Driver interface
End Rem
Type mxUserInputDriver Abstract

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String) Abstract

End Type

Rem
	bbdoc: UserInpitDriver for Command Line Interface
End Rem
Type mxUserInputDriverCLI Extends mxUserInputDriver

	Rem
		bbdoc: Ask user to confirm an action
		returns: True or False
	End Rem
	Method Confirm:Byte(question:String)
		Local resp:String = Input(question + " ").ToLower()
		If resp = "y" Or resp = "yes"
			Return True
		Else
			Return False
		End If
	End Method

End Type


Maximus now identifies itself to servers as: Maximus/<version> (<os>;<language>)

Rem
Copyright (c) 2010 Tim Howard

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
End Rem

Rem
	bbdoc: Maximus module base.
	about: An abstract type for the similarities between module scopes and modules.
End Rem
Type mxModuleBase Abstract

	Field m_name:String, m_description:String

'#region Field accessors

	Rem
		bbdoc: Set the base's name.
		returns: Nothing.
	End Rem
	Method SetName(name:String)
		Assert name, "(mxModuleBase.SetName) name cannot be Null!"
		m_name = name
	End Method

	Rem
		bbdoc: Get the base's name.
		returns: The base's name.
	End Rem
	Method GetName:String()
		Return m_name
	End Method

	Rem
		bbdoc: Set the base's description.
		returns: Nothing.
	End Rem
	Method SetDescription(description:String)
		Assert description, "(mxModuleBase.SetDescription) description cannot be Null!"
		m_description = description
	End Method

	Rem
		bbdoc: Get the base's description.
		returns: The base's description.
	End Rem
	Method GetDescription:String()
		Return m_description
	End Method

'#end region Field accessors

	Rem
		bbdoc: Set a common field from the given variable.
		returns: True if the given variable was handled, or False if it was not.
	End Rem
	Method SetCommonFromVariable:Int(variable:dVariable)
		Select variable.GetName().ToLower()
			Case "desc"
				SetDescription(variable.ValueAsString())
				Return True
		End Select
		Return False
	End Method

End Type

Rem
	bbdoc: Maximus module scope.
End Rem
Type mxModuleScope Extends mxModuleBase

	Field m_modules:dObjectMap

	Method New()
		m_modules = New dObjectMap
	End Method

	Rem
		bbdoc: Add the given module to the scope.
		returns: True if the module was added, or False if it was not (the module is Null).
	End Rem
	Method AddModule:Int(modul:mxModule)
		If modul <> Null
			m_modules._Insert(modul.GetName(), modul)
			modul.SetParent(Self)
			Return True
		End If
		Return False
	End Method

	Rem
		bbdoc: Check if the given module name is found in the scope.
		returns: True if the given module was found in the scope, or False if it was not.
	End Rem
	Method HasModule:Int(modname:String)
		Return m_modules._Contains(modname)
	End Method

	Rem
		bbdoc: Get a module with the given name.
		returns: The module with the given name, or Null if there is no module with the given name.
	End Rem
	Method GetModuleWithName:mxModule(modname:String)
		Return mxModule(m_modules._ValueByKey(modname))
	End Method

	Rem
		bbdoc: Load the given dJObject into the scope.
		returns: Itself, or Null if @root is Null.
	End Rem
	Method FromJSON:mxModuleScope(root:dJObject)
		If root <> Null
			SetName(root.GetName())
			For Local variable:dVariable = EachIn root.GetValues()
				If dJObject(variable)
					AddModule(New mxModule.FromJSON(dJObject(variable)))
				Else
					SetCommonFromVariable(variable)
				End If
			Next
			Return Self
		End If
		Return Null
	End Method

	Rem
		bbdoc: Get the module enumerator for the scope.
		returns: The module enumerator for the scope.
	End Rem
	Method ModuleEnumerator:TMapEnumerator()
		Return m_modules.ValueEnumerator()
	End Method

End Type

Rem
	bbdoc: Maximus module.
End Rem
Type mxModule Extends mxModuleBase

	Field m_parent:mxModuleScope
	Field m_versions:dObjectMap

	Method New()
		m_versions = New dObjectMap
	End Method

'#region Field accessors

	Rem
		bbdoc: Set the module's parent.
		returns: Nothing.
	End Rem
	Method SetParent(parent:mxModuleScope)
		m_parent = parent
	End Method

	Rem
		bbdoc: Get the module's parent.
		returns: The module's parent.
	End Rem
	Method GetParent:mxModuleScope()
		Return m_parent
	End Method

'#end region Field accessors

	Rem
		bbdoc: Add the given version to the module.
		returns: True if the version was added, or False if it was not (the version is Null).
	End Rem
	Method AddVersion:Int(version:mxModuleVersion)
		If version <> Null
			m_versions._Insert(version.GetName(), version)
			version.SetParent(Self)
			Return True
		End If
		Return False
	End Method

	Rem
		bbdoc: Check if there is a version with the given name.
		returns: True if the version was found, or False if it was not.
	End Rem
	Method HasVersion:Int(name:String)
		Return m_versions._Contains(name)
	End Method

	Rem
		bbdoc: Get a version with the given name.
		returns: The version with the given name, or Null if there is no version with the given name.
	End Rem
	Method GetVersionWithName:mxModuleVersion(name:String)
		Return mxModuleVersion(m_versions._ValueByKey(name))
	End Method

	Rem
		bbdoc: Get the latest (non-dev) version for this module.
		returns: The latest version for this module.
	End Rem
	Method GetLatestVersion:mxModuleVersion()
		Local hver:mxModuleVersion
		For Local ver:mxModuleVersion = EachIn VersionEnumerator()
			If ver.GetName() <> "dev"
				If hver = Null Or hver.Compare(ver) = 1
					hver = ver
				End If
			End If
		Next
		Return hver
	End Method

	Rem
		bbdoc: Set a common field from the given variable.
		returns: True if the given variable was handled, or False if it was not.
	End Rem
	Method SetCommonFromVariable:Int(variable:dVariable)
		If Super.SetCommonFromVariable(variable) = True
			Return True
		Else
			Select variable.GetName().ToLower()
				Case "versions"
					For Local jobj:dJObject = EachIn dJObject(variable).GetValues()
						AddVersion(New mxModuleVersion.FromJSON(jobj))
					Next
			End Select
			Return False
		End If
	End Method

	Rem
		bbdoc: Load the given dJObject into the module.
		returns: Itself, or Null if @root is Null.
	End Rem
	Method FromJSON:mxModule(root:dJObject)
		If root <> Null
			SetName(root.GetName())
			For Local variable:dVariable = EachIn root.GetValues()
				SetCommonFromVariable(variable)
			Next
			Return Self
		End If
		Return Null
	End Method

	Rem
		bbdoc: Get the version enumerator for the module.
		returns: The version enumerator for the module.
	End Rem
	Method VersionEnumerator:TMapEnumerator()
		Return m_versions.ValueEnumerator()
	End Method

End Type

Rem
	bbdoc: Maximus module version.
End Rem
Type mxModuleVersion

	Field m_parent:mxModule
	Field m_name:String, m_url:String
	Field m_dependencies:mxModuleDependencies

	Method New()
		m_dependencies = New mxModuleDependencies
	End Method

'#region Field accessors

	Rem
		bbdoc: Set the version's parent.
		returns: Nothing.
	End Rem
	Method SetParent(parent:mxModule)
		m_parent = parent
	End Method

	Rem
		bbdoc: Get the version's parent.
		returns: The version's parent.
	End Rem
	Method GetParent:mxModule()
		Return m_parent
	End Method

	Rem
		bbdoc: Set the version's name.
		returns: Nothing.
	End Rem
	Method SetName(name:String)
		Assert name, "(mxModuleVersion.SetName) name cannot be Null!"
		m_name = name
	End Method

	Rem
		bbdoc: Get the version's name.
		returns: The version's name.
	End Rem
	Method GetName:String()
		Return m_name
	End Method

	Rem
		bbdoc: Set the version's url.
		returns: Nothing.
	End Rem
	Method SetUrl(url:String)
		Assert url, "(mxModuleVersion.SetUrl) url cannot be Null!"
		m_url = url
	End Method

	Rem
		bbdoc: Get the version's url.
		returns: The version's url.
	End Rem
	Method GetUrl:String()
		Return m_url
	End Method

	Rem
		bbdoc: Get the temporary fetch path for the version's source archive.
		returns: The temporary file path for the version's source archive.
	End Rem
	Method GetTemporaryFilePath:String()
		Return "tmp/" + StripDir(GetUrl())
	End Method

	Rem
		bbdoc: Set the version's dependencies.
		returns: Nothing.
	End Rem
	Method SetDependencies(dependencies:mxModuleDependencies)
		m_dependencies = dependencies
	End Method

	Rem
		bbdoc: Get the version's dependencies.
		returns: The version's dependencies.
	End Rem
	Method GetDependencies:mxModuleDependencies()
		Return m_dependencies
	End Method

	Rem
		bbdoc: Get the version parts for the version.
		returns: True if the version is development, in which case the parameters are both 0; or False, in which case the parameters are set accordingly.
	End Rem
	Method GetVersionParts:Int(vmajor:String Var, vminor:String Var)
		If m_name <> "dev"
			Local i:Int = m_name.Find(".")
			If i > -1
				vmajor = m_name[..i]
				vminor = m_name[i + 1..]
			Else
				vmajor = m_name ' I'm not sure what other version formats would be used, so I'm just playing a random card here
			End If
			Return False
		End If
		Return True
	End Method

'#end region Field accessors

	Rem
		bbdoc: Set a common field from the given variable.
		returns: True if the given variable was handled, or False if it was not.
	End Rem
	Method SetCommonFromVariable:Int(variable:dVariable)
		Select variable.GetName().ToLower()
			Case "url"
				SetUrl(variable.ValueAsString())
			Case "deps"
				m_dependencies.FromJSON(dJArray(variable))
				Return True
		End Select
		Return False
	End Method

	Rem
		bbdoc: Load the given dJObject into the version.
		returns: Itself, or Null if @root is Null.
	End Rem
	Method FromJSON:mxModuleVersion(root:dJObject)
		If root <> Null
			SetName(root.GetName())
			For Local variable:dVariable = EachIn root.GetValues()
				SetCommonFromVariable(variable)
			Next
			Return Self
		End If
		Return Null
	End Method

	Rem
		bbdoc: Get the dependency enumerator for the version.
		returns: The dependency enumerator for the version.
	End Rem
	Method DependencyEnumerator:TMapEnumerator()
		Return m_dependencies.DependencyEnumerator()
	End Method

	Rem
		bbdoc: Compare the version with the given version.
		returns: 0 if the two versions are the same (same in version number alone), 1 if this version is greater than the given, or -1 if the given version is greater than this version.
	End Rem
	Method Compare:Int(with:Object)
		Local ver:mxModuleVersion = mxModuleVersion(with)
		If ver <> Null
			If m_name = ver.m_name
				Return 0
			Else
				Local smajor:String, sminor:String, wmajor:String, wminor:String
				Local sdev:Int = GetVersionParts(smajor, sminor), wdev:Int = ver.GetVersionParts(wmajor, wminor)
				If (sdev = True And wdev = True) Or (smajor = wmajor And sminor = wminor)
					Return 0
				Else If smajor > wmajor
					Return 1
				Else If smajor = wmajor
					If sminor > wminor
						Return 1
					Else
						Return -1
					End If
				Else
					Return -1
				End If
			End If
		End If
		Return 0
	End Method

	Rem
		bbdoc: Fetch the version's source archive.
		returns: Nothing.
	End Rem
	Method FetchSourceArchive()
		Local file:String = GetTemporaryFilePath()
		logger.LogMessage("fetching: " + GetUrl() + " -> " + file + "~t", False)
		If FileType(file) = FILETYPE_NONE
			Local stream:TStream = WriteFileExplicitly(file)
			If stream <> Null
				Local request:TRESTRequest = New TRESTRequest, response:TRESTResponse
				request.SetProgressCallback(_ProgressCallback, New _mxProgressStore)
				request.SetStream(stream)
				Try
					Local os:String
					?Win32
						os = "Windows"
					?Linux
						os = "Linux"
					?MacOS
						os = "MacOS"
					?

					Local language:String
					If mainapp.m_locale Then language = mainapp.m_locale.GetName()

					response = request.Call(GetUrl(), ["User-Agent: Maximus/" + mxApp.c_version + " (" + os + "; " + language + ")"], "GET")
				Catch e:Object
					stream.Close()
					DeleteFile(file)
					logger.LogMessage("")
					ThrowError(_s("error.fetch.error", [e.ToString()]))
				End Try
				stream.Close()
				If response.responseCode = 200
					logger.LogMessage(_s("message.fetch.done", [String(response.responseCode)]))
				Else
					DeleteFile(file)
					logger.LogMessage("")
					ThrowError(_s("error.fetch.error", ["Bad response code: " + String(response.responseCode)]))
				End If
			Else
				ThrowError(_s("error.writeperms", [file]))
			End If
		Else
			logger.LogMessage(_s("message.fetch.alreadyfetched"))
		End If
	End Method

	Rem
		bbdoc: Progress callback for source archive fetching.
		returns: Zero (no error).
	End Rem
	Function _ProgressCallback:Int(data:Object, dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
		Local store:_mxProgressStore = _mxProgressStore(data)
		Local prog:Int = (dlnow / dltotal) * 100
		If prog > store.m_progress + 5
			store.m_progress = prog
			WriteStdOut(".")
		End If
		Return 0
	End Function

End Type

Rem
	bbdoc: Maximus temporary progress storage for archive fetching.
End Rem
Type _mxProgressStore

	Field m_progress:Int = 0

End Type

Rem
Copyright (c) 2010 Tim Howard

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
End Rem

Rem
	bbdoc: Maximus module base.
	about: An abstract type for the similarities between module scopes and modules.
End Rem
Type mxModuleBase Abstract

	Field m_name:String, m_description:String

'#region Field accessors

	Rem
		bbdoc: Set the base's name.
		returns: Nothing.
	End Rem
	Method SetName(name:String)
		Assert name, "(mxModuleBase.SetName) name cannot be Null!"
		m_name = name
	End Method

	Rem
		bbdoc: Get the base's name.
		returns: The base's name.
	End Rem
	Method GetName:String()
		Return m_name
	End Method

	Rem
		bbdoc: Set the base's description.
		returns: Nothing.
	End Rem
	Method SetDescription(description:String)
		Assert description, "(mxModuleBase.SetDescription) description cannot be Null!"
		m_description = description
	End Method

	Rem
		bbdoc: Get the base's description.
		returns: The base's description.
	End Rem
	Method GetDescription:String()
		Return m_description
	End Method

'#end region Field accessors

	Rem
		bbdoc: Set a common field from the given variable.
		returns: True if the given variable was handled, or False if it was not.
	End Rem
	Method SetCommonFromVariable:Int(variable:dVariable)
		Select variable.GetName().ToLower()
			Case "desc"
				SetDescription(variable.ValueAsString())
				Return True
		End Select
		Return False
	End Method

End Type

Rem
	bbdoc: Maximus module scope.
End Rem
Type mxModuleScope Extends mxModuleBase

	Field m_modules:dObjectMap

	Method New()
		m_modules = New dObjectMap
	End Method

	Rem
		bbdoc: Add the given module to the scope.
		returns: True if the module was added, or False if it was not (the module is Null).
	End Rem
	Method AddModule:Int(modul:mxModule)
		If modul <> Null
			m_modules._Insert(modul.GetName(), modul)
			modul.SetParent(Self)
			Return True
		End If
		Return False
	End Method

	Rem
		bbdoc: Check if the given module name is found in the scope.
		returns: True if the given module was found in the scope, or False if it was not.
	End Rem
	Method HasModule:Int(modname:String)
		Return m_modules._Contains(modname)
	End Method

	Rem
		bbdoc: Get a module with the given name.
		returns: The module with the given name, or Null if there is no module with the given name.
	End Rem
	Method GetModuleWithName:mxModule(modname:String)
		Return mxModule(m_modules._ValueByKey(modname))
	End Method

	Rem
		bbdoc: Load the given dJObject into the scope.
		returns: Itself, or Null if @root is Null.
	End Rem
	Method FromJSON:mxModuleScope(root:dJObject)
		If root <> Null
			SetName(root.GetName())
			For Local variable:dVariable = EachIn root.GetValues()
				If dJObject(variable)
					AddModule(New mxModule.FromJSON(dJObject(variable)))
				Else
					SetCommonFromVariable(variable)
				End If
			Next
			Return Self
		End If
		Return Null
	End Method

	Rem
		bbdoc: Get the module enumerator for the scope.
		returns: The module enumerator for the scope.
	End Rem
	Method ModuleEnumerator:TMapEnumerator()
		Return m_modules.ValueEnumerator()
	End Method

End Type

Rem
	bbdoc: Maximus module.
End Rem
Type mxModule Extends mxModuleBase

	Field m_parent:mxModuleScope
	Field m_versions:dObjectMap

	Method New()
		m_versions = New dObjectMap
	End Method

'#region Field accessors

	Rem
		bbdoc: Set the module's parent.
		returns: Nothing.
	End Rem
	Method SetParent(parent:mxModuleScope)
		m_parent = parent
	End Method

	Rem
		bbdoc: Get the module's parent.
		returns: The module's parent.
	End Rem
	Method GetParent:mxModuleScope()
		Return m_parent
	End Method

'#end region Field accessors

	Rem
		bbdoc: Add the given version to the module.
		returns: True if the version was added, or False if it was not (the version is Null).
	End Rem
	Method AddVersion:Int(version:mxModuleVersion)
		If version <> Null
			m_versions._Insert(version.GetName(), version)
			version.SetParent(Self)
			Return True
		End If
		Return False
	End Method

	Rem
		bbdoc: Check if there is a version with the given name.
		returns: True if the version was found, or False if it was not.
	End Rem
	Method HasVersion:Int(name:String)
		Return m_versions._Contains(name)
	End Method

	Rem
		bbdoc: Get a version with the given name.
		returns: The version with the given name, or Null if there is no version with the given name.
	End Rem
	Method GetVersionWithName:mxModuleVersion(name:String)
		Return mxModuleVersion(m_versions._ValueByKey(name))
	End Method

	Rem
		bbdoc: Get the latest (non-dev) version for this module.
		returns: The latest version for this module.
	End Rem
	Method GetLatestVersion:mxModuleVersion()
		Local hver:mxModuleVersion
		For Local ver:mxModuleVersion = EachIn VersionEnumerator()
			If ver.GetName() <> "dev"
				If hver = Null Or hver.Compare(ver) = 1
					hver = ver
				End If
			End If
		Next
		Return hver
	End Method

	Rem
		bbdoc: Set a common field from the given variable.
		returns: True if the given variable was handled, or False if it was not.
	End Rem
	Method SetCommonFromVariable:Int(variable:dVariable)
		If Super.SetCommonFromVariable(variable) = True
			Return True
		Else
			Select variable.GetName().ToLower()
				Case "versions"
					For Local jobj:dJObject = EachIn dJObject(variable).GetValues()
						AddVersion(New mxModuleVersion.FromJSON(jobj))
					Next
			End Select
			Return False
		End If
	End Method

	Rem
		bbdoc: Load the given dJObject into the module.
		returns: Itself, or Null if @root is Null.
	End Rem
	Method FromJSON:mxModule(root:dJObject)
		If root <> Null
			SetName(root.GetName())
			For Local variable:dVariable = EachIn root.GetValues()
				SetCommonFromVariable(variable)
			Next
			Return Self
		End If
		Return Null
	End Method

	Rem
		bbdoc: Get the version enumerator for the module.
		returns: The version enumerator for the module.
	End Rem
	Method VersionEnumerator:TMapEnumerator()
		Return m_versions.ValueEnumerator()
	End Method

End Type

Rem
	bbdoc: Maximus module version.
End Rem
Type mxModuleVersion

	Field m_parent:mxModule
	Field m_name:String, m_url:String
	Field m_dependencies:mxModuleDependencies

	Method New()
		m_dependencies = New mxModuleDependencies
	End Method

'#region Field accessors

	Rem
		bbdoc: Set the version's parent.
		returns: Nothing.
	End Rem
	Method SetParent(parent:mxModule)
		m_parent = parent
	End Method

	Rem
		bbdoc: Get the version's parent.
		returns: The version's parent.
	End Rem
	Method GetParent:mxModule()
		Return m_parent
	End Method

	Rem
		bbdoc: Set the version's name.
		returns: Nothing.
	End Rem
	Method SetName(name:String)
		Assert name, "(mxModuleVersion.SetName) name cannot be Null!"
		m_name = name
	End Method

	Rem
		bbdoc: Get the version's name.
		returns: The version's name.
	End Rem
	Method GetName:String()
		Return m_name
	End Method

	Rem
		bbdoc: Set the version's url.
		returns: Nothing.
	End Rem
	Method SetUrl(url:String)
		Assert url, "(mxModuleVersion.SetUrl) url cannot be Null!"
		m_url = url
	End Method

	Rem
		bbdoc: Get the version's url.
		returns: The version's url.
	End Rem
	Method GetUrl:String()
		Return m_url
	End Method

	Rem
		bbdoc: Get the temporary fetch path for the version's source archive.
		returns: The temporary file path for the version's source archive.
	End Rem
	Method GetTemporaryFilePath:String()
		Return "tmp/" + StripDir(GetUrl())
	End Method

	Rem
		bbdoc: Set the version's dependencies.
		returns: Nothing.
	End Rem
	Method SetDependencies(dependencies:mxModuleDependencies)
		m_dependencies = dependencies
	End Method

	Rem
		bbdoc: Get the version's dependencies.
		returns: The version's dependencies.
	End Rem
	Method GetDependencies:mxModuleDependencies()
		Return m_dependencies
	End Method

	Rem
		bbdoc: Get the version parts for the version.
		returns: True if the version is development, in which case the parameters are both 0; or False, in which case the parameters are set accordingly.
	End Rem
	Method GetVersionParts:Int(vmajor:String Var, vminor:String Var)
		If m_name <> "dev"
			Local i:Int = m_name.Find(".")
			If i > -1
				vmajor = m_name[..i]
				vminor = m_name[i + 1..]
			Else
				vmajor = m_name ' I'm not sure what other version formats would be used, so I'm just playing a random card here
			End If
			Return False
		End If
		Return True
	End Method

'#end region Field accessors

	Rem
		bbdoc: Set a common field from the given variable.
		returns: True if the given variable was handled, or False if it was not.
	End Rem
	Method SetCommonFromVariable:Int(variable:dVariable)
		Select variable.GetName().ToLower()
			Case "url"
				SetUrl(variable.ValueAsString())
			Case "deps"
				m_dependencies.FromJSON(dJArray(variable))
				Return True
		End Select
		Return False
	End Method

	Rem
		bbdoc: Load the given dJObject into the version.
		returns: Itself, or Null if @root is Null.
	End Rem
	Method FromJSON:mxModuleVersion(root:dJObject)
		If root <> Null
			SetName(root.GetName())
			For Local variable:dVariable = EachIn root.GetValues()
				SetCommonFromVariable(variable)
			Next
			Return Self
		End If
		Return Null
	End Method

	Rem
		bbdoc: Get the dependency enumerator for the version.
		returns: The dependency enumerator for the version.
	End Rem
	Method DependencyEnumerator:TMapEnumerator()
		Return m_dependencies.DependencyEnumerator()
	End Method

	Rem
		bbdoc: Compare the version with the given version.
		returns: 0 if the two versions are the same (same in version number alone), 1 if this version is greater than the given, or -1 if the given version is greater than this version.
	End Rem
	Method Compare:Int(with:Object)
		Local ver:mxModuleVersion = mxModuleVersion(with)
		If ver <> Null
			If m_name = ver.m_name
				Return 0
			Else
				Local smajor:String, sminor:String, wmajor:String, wminor:String
				Local sdev:Int = GetVersionParts(smajor, sminor), wdev:Int = ver.GetVersionParts(wmajor, wminor)
				If (sdev = True And wdev = True) Or (smajor = wmajor And sminor = wminor)
					Return 0
				Else If smajor > wmajor
					Return 1
				Else If smajor = wmajor
					If sminor > wminor
						Return 1
					Else
						Return -1
					End If
				Else
					Return -1
				End If
			End If
		End If
		Return 0
	End Method

	Rem
		bbdoc: Fetch the version's source archive.
		returns: Nothing.
	End Rem
	Method FetchSourceArchive()
		Local file:String = GetTemporaryFilePath()
		logger.LogMessage("fetching: " + GetUrl() + " -> " + file + "~t", False)
		If FileType(file) = FILETYPE_NONE
			Local stream:TStream = WriteFileExplicitly(file)
			If stream <> Null
				Local request:TRESTRequest = New TRESTRequest, response:TRESTResponse
				request.SetProgressCallback(_ProgressCallback, New _mxProgressStore)
				request.SetStream(stream)
				Try
					response = request.Call(GetUrl(), Null, "GET")
				Catch e:Object
					stream.Close()
					DeleteFile(file)
					logger.LogMessage("")
					ThrowError(_s("error.fetch.error", [e.ToString()]))
				End Try
				stream.Close()
				If response.responseCode = 200
					logger.LogMessage(_s("message.fetch.done", [String(response.responseCode)]))
				Else
					DeleteFile(file)
					logger.LogMessage("")
					ThrowError(_s("error.fetch.error", ["Bad response code: " + String(response.responseCode)]))
				End If
			Else
				ThrowError(_s("error.writeperms", [file]))
			End If
		Else
			logger.LogMessage(_s("message.fetch.alreadyfetched"))
		End If
	End Method

	Rem
		bbdoc: Progress callback for source archive fetching.
		returns: Zero (no error).
	End Rem
	Function _ProgressCallback:Int(data:Object, dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
		Local store:_mxProgressStore = _mxProgressStore(data)
		Local prog:Int = (dlnow / dltotal) * 100
		If prog > store.m_progress + 5
			store.m_progress = prog
			WriteStdOut(".")
		End If
		Return 0
	End Function

End Type

Rem
	bbdoc: Maximus temporary progress storage for archive fetching.
End Rem
Type _mxProgressStore

	Field m_progress:Int = 0

End Type


Fixed camera range issues approaching zero.

Strict

Rem
	bbdoc: Direct3D 9 renderer for MaxB3D
End Rem
Module MaxB3D.D3D9Driver
ModuleInfo "Author: Kevin Primm"
ModuleInfo "License: MIT"

Import MaxB3D.Core
Import Prime.D3D9Max2DEx
Import Prime.DirectXEx

?Win32

Import "d3d9.cpp"

Private

Extern "C"
	Function maxb3dD3D9VertexElements:Byte Ptr()'="_maxb3dD3D9VertexElements@0"
End Extern

Function GetD3D9MaxB3DVertexDecl:IDirect3DVertexDeclaration9(d3ddev:IDirect3DDevice9)
	Global decl:IDirect3DVertexDeclaration9,dev:IDirect3DDevice9
	If decl=Null Or dev<>d3ddev
		Assert d3ddev.CreateVertexDeclaration(maxb3dD3D9VertexElements(),decl)=D3D_OK,"Failed to create vertex declaration."
		dev=d3ddev
	EndIf
	Return decl
End Function

Function Pow2Size( n )
	Local t=1
	While t<n
		t:*2
	Wend
	Return t
End Function

Public

Type TD3D9MaxB3DDriver Extends TMaxB3DDriver
	Field _d3ddev:IDirect3DDevice9
	Field _viewporton

	Method SetGraphics( g:TGraphics )
		Super.SetGraphics g
		_d3ddev=Null
		If g<>Null
			_d3ddev=TD3D9Graphics(TMax2DGraphics(g)._graphics).GetDirect3DDevice()
			EndMax2D
		EndIf
	End Method

	Method MakeBuffer:TBuffer(src:Object,width,height,flags)
		Return TMax2DExDriver(_parent).MakeBuffer(src,width,height,flags)
	End Method

	Method GetCaps:TCaps()
		Local caps:TCaps=New TCaps
		Return caps
	End Method

	Method Abbr$()
		Return "d3d9"
	End Method

	Method SetMax2D(enable)
		If enable
			Global identity:TMatrix=TMatrix.Identity()
			Local width=GraphicsWidth(),height=GraphicsHeight()
			Local matrix#[]=[..
			2.0/width,0.0,0.0,0.0,..
			 0.0,-2.0/height,0.0,0.0,..
			 0.0,0.0,1.0,0.0,..
			 -1-(1.0/width),1+(1.0/height),1.0,1.0]

			SetBlend -1
			SetBlend SOLIDBLEND

			_d3ddev.SetTransform D3DTS_PROJECTION,matrix
			_d3ddev.SetTransform D3DTS_WORLD,identity.ToPtr()
			_d3ddev.SetTransform D3DTS_VIEW,identity.ToPtr()
			_d3ddev.SetTransform D3DTS_TEXTURE0,identity.ToPtr()

			_d3ddev.SetVertexDeclaration Null
			_d3ddev.SetIndices Null
			_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1

			_d3ddev.SetRenderState D3DRS_LIGHTING,False
			_d3ddev.SetRenderState D3DRS_ZENABLE,False
			_d3ddev.SetRenderState D3DRS_SCISSORTESTENABLE,_viewporton

			_d3ddev.SetRenderState D3DRS_ALPHATESTENABLE,True

			For Local i=1 To 7
				_d3ddev.SetTexture i,Null
			Next

			_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1

			_d3ddev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_MODULATE
			_d3ddev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_MODULATE

			_d3ddev.SetTextureStageState 0,D3DTSS_ADDRESS,D3DTADDRESS_CLAMP

			_d3ddev.SetTextureStageState 0,D3DTSS_MAGFILTER,D3DTFG_POINT
			_d3ddev.SetTextureStageState 0,D3DTSS_MINFILTER,D3DTFN_POINT
			_d3ddev.SetTextureStageState 0,D3DTSS_MIPFILTER,D3DTFP_POINT

			_d3ddev.SetRenderState D3DRS_FOGENABLE,False

			_d3ddev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE
			_d3ddev.SetRenderState D3DRS_FILLMODE,D3DFILL_SOLID
		Else
			_d3ddev.SetRenderState D3DRS_ZENABLE,True
			_d3ddev.SetRenderState D3DRS_ZWRITEENABLE,True

			_d3ddev.GetRenderState D3DRS_SCISSORTESTENABLE,_viewporton
			_d3ddev.SetRenderState D3DRS_SCISSORTESTENABLE,True

			_d3ddev.SetRenderState D3DRS_LIGHTING,True
			_d3ddev.SetRenderState D3DRS_NORMALIZENORMALS,True

			_d3ddev.SetRenderState D3DRS_COLORVERTEX, True

			'_d3ddev.SetRenderState D3DRS_ALPHAREF, 1
			'_d3ddev.SetRenderState D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL
		EndIf
	End Method

	Method SetCamera(camera:TCamera,config:TWorldConfig)
		_d3ddev.SetRenderState D3DRS_DITHERENABLE, config.Dither

		Local clearflags
		If camera._clsmode&CLSMODE_COLOR clearflags:|D3DCLEAR_TARGET
		If camera._clsmode&CLSMODE_DEPTH clearflags:|D3DCLEAR_ZBUFFER

		Local viewport[]=[camera._viewx,camera._viewy,camera._viewwidth-camera._viewx,camera._viewheight-camera._viewy]
		_d3ddev.SetScissorRect viewport
		_d3ddev.Clear(1,viewport,clearflags,D3DCOLOR_XRGB(camera._brush._r*255,camera._brush._g*255,camera._brush._b*255),1.0,0)

		Select camera._fogmode
		Case FOGMODE_LINEAR
			_d3ddev.SetRenderState D3DRS_FOGENABLE,True
			_d3ddev.SetRenderState D3DRS_FOGSTART,Int(Varptr camera._fognear)
			_d3ddev.SetRenderState D3DRS_FOGEND,Int(Varptr camera._fogfar)
		Default
			_d3ddev.SetRenderState D3DRS_FOGENABLE,False
		End Select

		Local oldnear# = camera._near ' Ugh, hack. Need to investigate cause.
		camera._near = Max(camera._near - 0.396250010, .01)
		camera.UpdateMatrices()
		camera._near = oldnear

		_d3ddev.SetTransform D3DTS_PROJECTION,camera._projection.ToPtr()
		_d3ddev.SetTransform D3DTS_VIEW,camera._modelview.ToPtr()
	End Method

	Method SetLight(light:TLight,index)
		If light=Null
			_d3ddev.LightEnable index,False
			Return
		EndIf

		Local brush:TBrush=light._brush

		Global d3dlight:D3DLIGHT9=New D3DLIGHT9
		d3dlight.Type_=D3DLIGHT_DIRECTIONAL
		d3dlight.Diffuse_r=brush._r;d3dlight.Diffuse_g=brush._g;d3dlight.Diffuse_b=brush._b;d3dlight.Diffuse_a=brush._a
		'd3dlight.Ambient_r=WorldConfig.AmbientRed/255.0;d3dlight.Ambient_g=WorldConfig.AmbientGreen/255.0;d3dlight.Ambient_b=WorldConfig.AmbientBlue/255.0;d3dlight.Ambient_a=1.0

		d3dlight.Direction_x=0.0;d3dlight.Direction_y=0.0;d3dlight.Direction_z=1.0

		Local matrix:TMatrix=light._matrix
		matrix.TransformVec3 d3dlight.Direction_x,d3dlight.Direction_y,d3dlight.Direction_z
		matrix.GetPosition d3dlight.Position_x,d3dlight.Position_y,d3dlight.Position_z

		d3dlight.Range=light._range

		_d3ddev.SetLight index,d3dlight
		_d3ddev.LightEnable index,True
	End Method

	Method SetBrush(brush:TBrush,hasalpha,config:TWorldConfig)
		_d3ddev.SetRenderState D3DRS_ALPHABLENDENABLE,hasalpha
		_d3ddev.SetRenderState D3DRS_ZWRITEENABLE,Not hasalpha

		Select brush._blend
		Case BLEND_NONE, BLEND_ALPHA
			_d3ddev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
			_d3ddev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA
		Case BLEND_MULTIPLY
			_d3ddev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR
			_d3ddev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ZERO
		Case BLEND_ADD
			_d3ddev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
			_d3ddev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ONE
		End Select

		If brush._fx&FX_FULLBRIGHT
			_d3ddev.SetRenderState D3DRS_AMBIENT,D3DCOLOR_RGB(255,255,255)
		Else
			_d3ddev.SetRenderState D3DRS_AMBIENT,D3DCOLOR_RGB(config.AmbientRed,config.AmbientGreen,config.AmbientBlue)
		EndIf

		If brush._fx&FX_VERTEXCOLOR
			_d3ddev.SetRenderState D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_COLOR1
			_d3ddev.SetRenderState D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_COLOR1
		Else
			_d3ddev.SetRenderState D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_MATERIAL
			_d3ddev.SetRenderState D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_MATERIAL
		EndIf

		If brush._fx&FX_FLATSHADED
			_d3ddev.SetRenderState D3DRS_SHADEMODE, D3DSHADE_FLAT
		Else
			_d3ddev.SetRenderState D3DRS_SHADEMODE, D3DSHADE_GOURAUD
		EndIf

		If brush._fx&FX_NOCULLING
			_d3ddev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE
		Else
			_d3ddev.SetRenderState D3DRS_CULLMODE,D3DCULL_CCW
		EndIf

		If brush._fx&FX_WIREFRAME Or config.Wireframe
			_d3ddev.SetRenderState D3DRS_FILLMODE,D3DFILL_WIREFRAME
		Else
			_d3ddev.SetRenderState D3DRS_FILLMODE,D3DFILL_SOLID
		EndIf

		Local material:D3DMATERIAL9 = New D3DMATERIAL9
		material.Diffuse_r=brush._r;material.Diffuse_g=brush._g;material.Diffuse_b=brush._b;material.Diffuse_a=brush._a
		material.Ambient_r=brush._r;material.Ambient_g=brush._g;material.Ambient_b=brush._b;material.Ambient_a=brush._a

		_d3ddev.SetMaterial material

		Local alpha_test
		For Local i=0 To 7
			Local texture:TTexture=brush._texture[i]
			If texture=Null Or texture._blend=BLEND_NONE
				_d3ddev.SetTexture i,Null
				Continue
			EndIf

			_d3ddev.SetTexture i,UpdateTextureRes(texture._frame[brush._textureframe[i]],texture._flags)._tex

			Local matrix:TMatrix=TMatrix.Identity()
			'matrix._m[0,0]=-texture._sx
			'matrix._m[1,1]=texture._sy
			matrix=TMatrix.YawPitchRoll(0,0,-texture._r).Multiply(matrix)
			matrix=TMatrix.Scale(-texture._sx,texture._sy,1).Multiply(matrix)
			matrix._m[2,0]=-texture._px
			matrix._m[2,1]=-texture._py

			_d3ddev.SetTransform D3DTS_TEXTURE0+i,matrix.ToPtr()

			_d3ddev.SetTextureStageState i,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2
			_d3ddev.SetTextureStageState i,D3DTSS_ADDRESS,0

			_d3ddev.SetSamplerState i,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR
			_d3ddev.SetSamplerState i,D3DSAMP_MINFILTER,D3DTEXF_LINEAR

			'_d3ddev.SetRenderState D3DRS_WRAP0+i, D3DWRAP_U|D3DWRAP_V
			alpha_test :| (texture._flags&TEXTURE_ALPHA Or texture._flags&TEXTURE_MASKED)

			If texture._flags&TEXTURE_MIPMAP
				_d3ddev.SetSamplerState i,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR
				_d3ddev.SetTextureStageState i,D3DTSS_MAGFILTER,D3DTEXF_LINEAR
				_d3ddev.SetTextureStageState i,D3DTSS_MINFILTER,D3DTEXF_LINEAR
			Else
				_d3ddev.SetSamplerState i,D3DSAMP_MIPFILTER,D3DTEXF_NONE
				_d3ddev.SetTextureStageState i,D3DTSS_MAGFILTER,D3DTEXF_POINT
				_d3ddev.SetTextureStageState i,D3DTSS_MINFILTER,D3DTEXF_POINT
			EndIf

			If texture._flags&TEXTURE_CLAMPU
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP
			Else
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSU,D3DTADDRESS_WRAP
			EndIf

			If texture._flags&TEXTURE_CLAMPV
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP
			Else
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSV,D3DTADDRESS_WRAP
			EndIf

			If texture._flags&TEXTURE_SPHEREMAP
				_d3ddev.SetTextureStageState i,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_SPHEREMAP
			Else
				_d3ddev.SetTextureStageState i,D3DTSS_TEXCOORDINDEX,texture._coords
			EndIf

			Select texture._blend
			Case BLEND_ALPHA
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_MODULATE
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_MODULATE
			Case BLEND_MULTIPLY
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_MODULATE
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_MODULATE
			Case BLEND_ADD
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_ADD
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_ADD
			Case BLEND_DOT3
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_DOTPRODUCT3
			Case BLEND_MULTIPLY2
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_MODULATE2X
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_MODULATE2X
			Default
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_SELECTARG2
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2
			End Select
		Next
		_d3ddev.SetRenderState D3DRS_ALPHATESTENABLE, alpha_test
	End Method

	Method RenderSurface(resource:TSurfaceRes,brush:TBrush)
		Local res:TD3D9SurfaceRes=TD3D9SurfaceRes(resource)

		_d3ddev.SetFVF 0
		_d3ddev.SetVertexDeclaration GetD3D9MaxB3DVertexDecl(_d3ddev)
		_d3ddev.SetStreamSource 0,res._pos,0,12
		_d3ddev.SetStreamSource 1,res._nml,0,12
		_d3ddev.SetStreamSource 2,res._clr,0,16
		_d3ddev.SetStreamSource 3,res._tex[0],0,8
		_d3ddev.SetStreamSource 4,res._tex[1],0,8
		_d3ddev.SetStreamSource 5,res._tex[2],0,8
		_d3ddev.SetStreamSource 6,res._tex[3],0,8
		_d3ddev.SetStreamSource 7,res._tex[4],0,8
		_d3ddev.SetStreamSource 8,res._tex[5],0,8
		_d3ddev.SetStreamSource 9,res._tex[6],0,8
		_d3ddev.SetStreamSource 10,res._tex[7],0,8
		_d3ddev.SetIndices res._tri
		_d3ddev.DrawIndexedPrimitive D3DPT_TRIANGLELIST,0,0,res._vertexcnt,0,res._trianglecnt

		Return res._trianglecnt
	End Method

	Method RenderSprite(sprite:TSprite)
		Global _data#[]=[ -1.0, 1.0,0.0, 0.0,0.0,1.0, 0.0,0.0, ..
											-1.0,-1.0,0.0, 0.0,0.0,1.0, 0.0,1.0, ..
		                   1.0, 1.0,0.0, 0.0,0.0,1.0, 1.0,0.0, ..
		                   1.0,-1.0,0.0, 0.0,0.0,1.0, 1.0,1.0     ]

		_d3ddev.SetVertexDeclaration Null
		_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1
		_d3ddev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_data,8*4
	End Method

	Method BeginEntityRender(entity:TEntity)
		_d3ddev.SetTransform D3DTS_WORLD,entity.GetMatrix(True).ToPtr()
	End Method

	Method EndEntityRender(entity:TEntity)
	End Method

	Method RenderFlat(flat:TFlat)
		Local x#,y#,z#
		flat.GetScale x,y,z,True

		Global _data#[]=[ -1.0,0.0, 1.0, 0.0,1.0,0.0, 0.0,0.0, ..
		                   1.0,0.0, 1.0, 0.0,1.0,0.0,   x,0.0, ..
		                  -1.0,0.0,-1.0, 0.0,1.0,0.0, 0.0,  z, ..
		                   1.0,0.0,-1.0, 0.0,1.0,0.0,   x,  z     ]

		_d3ddev.SetVertexDeclaration Null
		_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1
		_d3ddev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_data,8*4
	End Method

	Method RenderTerrain(terrain:TTerrain)
	End Method

	Method RenderBSPTree(tree:TBSPTree)
		Local node:TBSPNode=tree.Node
		If node=Null Return
		Local triangles
		triangles:+RenderBSPTree(node.In)

		_d3ddev.SetVertexDeclaration Null
		_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1

		For Local poly:TBSPPolygon=EachIn node.On
			Local ptA:TVector=poly.Point[0],v0
			Local trianglecnt=poly.Count()-2
			Local data#[trianglecnt*24],dataptr:Float Ptr=data
			For Local i=0 To trianglecnt-1
				Local ptB:TVector=poly.Point[i+1],ptC:TVector=poly.Point[i+2]
				data[i*24+00]=ptA.x;data[i*24+01]=ptA.y;data[i*24+02]=ptA.z;data[i*24+03]=poly.Plane.x;data[i*24+04]=poly.Plane.y;	data[i*24+05]=poly.Plane.z;data[i*24+06]=0.0;data[i*24+07]=0.0
				data[i*24+08]=ptB.x;data[i*24+09]=ptB.y;data[i*24+10]=ptB.z;data[i*24+11]=poly.Plane.x;data[i*24+12]=poly.Plane.y;	data[i*24+13]=poly.Plane.z;data[i*24+14]=0.0;data[i*24+15]=0.0
				data[i*24+16]=ptC.x;data[i*24+17]=ptC.y;data[i*24+18]=ptC.z;data[i*24+19]=poly.Plane.x;data[i*24+20]=poly.Plane.y;data[i*24+21]=poly.Plane.z;data[i*24+22]=0.0;data[i*24+23]=0.0
			Next
			_d3ddev.DrawPrimitiveUP D3DPT_TRIANGLELIST,trianglecnt,data,8*4
			triangles:+trianglecnt
		Next

		triangles:+RenderBSPTree(node.Out)
		Return triangles
	End Method

	Method UpdateTextureRes:TD3D9TextureRes(frame:TTextureFrame,flags)
		Local res:TD3D9TextureRes=TD3D9TextureRes(frame._res)
		If res And frame._updateres=False Return res

		If res=Null res=New TD3D9TextureRes
		frame._res=res

		Local pixmap:TPixmap=frame._pixmap
		Local tex_width=Pow2Size(pixmap.width),tex_height=Pow2Size(pixmap.height)
		pixmap=ConvertPixmap(ResizePixmap(pixmap,tex_width,tex_height),PF_BGRA8888)
		If res._tex=Null Assert _d3ddev.CreateTexture(tex_width,tex_height,(flags & TEXTURE_MIPMAP)=0,D3DUSAGE_AUTOGENMIPMAP,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,res._tex,Null)=D3D_OK

		Local rect:D3DLOCKED_RECT=New D3DLOCKED_RECT
		res._tex.LockRect 0,rect,Null,0
		MemCopy rect.pBits,pixmap.pixels,pixmap.width*pixmap.height*4
		res._tex.UnlockRect 0

		frame._updateres=False

		Return res
	End Method

	Method UpdateSurfaceRes:TD3D9SurfaceRes(surface:TSurface)
		Local res:TD3D9SurfaceRes=TD3D9SurfaceRes(surface._res)
		If res=Null res=New TD3D9SurfaceRes;surface._reset=-1

		If surface._reset=0 Return res
		If surface._reset=-1 surface._reset=1|2|4|8|16|32|64|128|256

		If surface._reset&1 And surface._vertexpos UploadVertexData res._pos,surface._vertexpos
		If surface._reset&2 And surface._vertexnml UploadVertexData res._nml,surface._vertexnml
		If surface._reset&4 And surface._vertexclr UploadVertexData res._clr,surface._vertexclr
		If surface._reset&8 And surface._triangle
			If res._tri=Null _d3ddev.CreateIndexBuffer(surface._triangle.length*4,0,D3DFMT_INDEX32,D3DPOOL_MANAGED,res._tri,Null)
			Local dataptr:Byte Ptr
			Assert res._tri.Lock(0,0,dataptr,0)=D3D_OK,"Failed to lock index buffer."
			MemCopy dataptr,surface._triangle,surface._triangle.length*4
			res._tri.Unlock()
		EndIf

		For Local i=0 To surface._vertextex.length-1
			If surface._reset&Int(2^(4+i)) UploadVertexData res._tex[i],surface._vertextex[i]
		Next

		res._trianglecnt=surface._trianglecnt
		res._vertexcnt=surface._vertexcnt

		surface._reset=0
		surface._res=res

		Return res
	End Method

	Method MergeSurfaceRes:TSurfaceRes(base:TSurface,animation:TSurface,data)
		If animation=Null Return UpdateSurfaceRes(base)
		Local base_res:TD3D9SurfaceRes=UpdateSurfaceRes(base)
		Local anim_res:TD3D9SurfaceRes=UpdateSurfaceRes(animation)
		Local res:TD3D9SurfaceRes=base_res.Copy()
		res._pos=anim_res._pos
		Return res
	End Method

	Method UploadVertexData(buffer:IDirect3DVertexBuffer9 Var,data#[])
		If buffer=Null _d3ddev.CreateVertexBuffer(data.length*4,0,0,D3DPOOL_MANAGED,buffer,Null)
		Local dataptr:Byte Ptr
		Assert buffer.Lock(0,0,dataptr,0)=D3D_OK,"Failed to lock vertex buffer."
		MemCopy dataptr,data,data.length*4
		buffer.Unlock()
	End Method

End Type

Type TD3D9TextureRes Extends TTextureRes
	Field _tex:IDirect3DTexture9
End Type

Type TD3D9SurfaceRes Extends TSurfaceRes
	Field _pos:IDirect3DVertexBuffer9
	Field _nml:IDirect3DVertexBuffer9
	Field _clr:IDirect3DVertexBuffer9
	Field _tri:IDirect3DIndexBuffer9
	Field _tex:IDirect3DVertexBuffer9[8]

	Method Copy:TD3D9SurfaceRes()
		Local res:TD3D9SurfaceRes=New TD3D9SurfaceRes
		res._vertexcnt=_vertexcnt;res._trianglecnt=_trianglecnt
		res._pos=_pos;res._nml=_nml;res._clr=_clr;res._tri=_tri;
		For Local i=0 To 7
			res._tex[i]=_tex[i]
		Next
		Return res
	End Method
End Type

Rem
	bbdoc: Needs documentation. #TODO
End Rem
Function D3D9MaxB3DDriver:TD3D9MaxB3DDriver()
	If D3D9Max2DExDriver()
		Global driver:TD3D9MaxB3DDriver=New TD3D9MaxB3DDriver
		driver._parent=D3D9Max2DExDriver()
		Return driver
	End If
End Function

Rem
	bbdoc: Utility function that sets the MaxB3D D3D9 driver and calls Graphics.
End Rem
Function D3D9Graphics3D:TGraphics(width,height,depth=0,hertz=0,flags=0)
	SetGraphicsDriver D3D9MaxB3DDriver(),GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER
	Return Graphics(width,height,depth,hertz,flags)
End Function

Local driver:TD3D9MaxB3DDriver=D3D9MaxB3DDriver()
If driver SetGraphicsDriver driver,GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER

?

Strict

Rem
	bbdoc: Direct3D 9 renderer for MaxB3D
End Rem
Module MaxB3D.D3D9Driver
ModuleInfo "Author: Kevin Primm"
ModuleInfo "License: MIT"

Import MaxB3D.Core
Import Prime.D3D9Max2DEx
Import Prime.DirectXEx

?Win32

Import "d3d9.cpp"

Private

Extern "C"
	Function maxb3dD3D9VertexElements:Byte Ptr()'="_maxb3dD3D9VertexElements@0"
End Extern

Function GetD3D9MaxB3DVertexDecl:IDirect3DVertexDeclaration9(d3ddev:IDirect3DDevice9)
	Global decl:IDirect3DVertexDeclaration9,dev:IDirect3DDevice9
	If decl=Null Or dev<>d3ddev
		Assert d3ddev.CreateVertexDeclaration(maxb3dD3D9VertexElements(),decl)=D3D_OK,"Failed to create vertex declaration."
		dev=d3ddev
	EndIf
	Return decl
End Function

Function Pow2Size( n )
	Local t=1
	While t<n
		t:*2
	Wend
	Return t
End Function

Public

Type TD3D9MaxB3DDriver Extends TMaxB3DDriver
	Field _d3ddev:IDirect3DDevice9
	Field _viewporton

	Method SetGraphics( g:TGraphics )
		Super.SetGraphics g
		_d3ddev=Null
		If g<>Null
			_d3ddev=TD3D9Graphics(TMax2DGraphics(g)._graphics).GetDirect3DDevice()
			EndMax2D
		EndIf
	End Method

	Method MakeBuffer:TBuffer(src:Object,width,height,flags)
		Return TMax2DExDriver(_parent).MakeBuffer(src,width,height,flags)
	End Method

	Method GetCaps:TCaps()
		Local caps:TCaps=New TCaps
		Return caps
	End Method

	Method Abbr$()
		Return "d3d9"
	End Method

	Method SetMax2D(enable)
		If enable
			Global identity:TMatrix=TMatrix.Identity()
			Local width=GraphicsWidth(),height=GraphicsHeight()
			Local matrix#[]=[..
			2.0/width,0.0,0.0,0.0,..
			 0.0,-2.0/height,0.0,0.0,..
			 0.0,0.0,1.0,0.0,..
			 -1-(1.0/width),1+(1.0/height),1.0,1.0]

			SetBlend -1
			SetBlend SOLIDBLEND

			_d3ddev.SetTransform D3DTS_PROJECTION,matrix
			_d3ddev.SetTransform D3DTS_WORLD,identity.ToPtr()
			_d3ddev.SetTransform D3DTS_VIEW,identity.ToPtr()
			_d3ddev.SetTransform D3DTS_TEXTURE0,identity.ToPtr()

			_d3ddev.SetVertexDeclaration Null
			_d3ddev.SetIndices Null
			_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1

			_d3ddev.SetRenderState D3DRS_LIGHTING,False
			_d3ddev.SetRenderState D3DRS_ZENABLE,False
			_d3ddev.SetRenderState D3DRS_SCISSORTESTENABLE,_viewporton

			_d3ddev.SetRenderState D3DRS_ALPHATESTENABLE,True

			For Local i=1 To 7
				_d3ddev.SetTexture i,Null
			Next

			_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1

			_d3ddev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_MODULATE
			_d3ddev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_MODULATE

			_d3ddev.SetTextureStageState 0,D3DTSS_ADDRESS,D3DTADDRESS_CLAMP

			_d3ddev.SetTextureStageState 0,D3DTSS_MAGFILTER,D3DTFG_POINT
			_d3ddev.SetTextureStageState 0,D3DTSS_MINFILTER,D3DTFN_POINT
			_d3ddev.SetTextureStageState 0,D3DTSS_MIPFILTER,D3DTFP_POINT

			_d3ddev.SetRenderState D3DRS_FOGENABLE,False

			_d3ddev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE
			_d3ddev.SetRenderState D3DRS_FILLMODE,D3DFILL_SOLID
		Else
			_d3ddev.SetRenderState D3DRS_ZENABLE,True
			_d3ddev.SetRenderState D3DRS_ZWRITEENABLE,True

			_d3ddev.GetRenderState D3DRS_SCISSORTESTENABLE,_viewporton
			_d3ddev.SetRenderState D3DRS_SCISSORTESTENABLE,True

			_d3ddev.SetRenderState D3DRS_LIGHTING,True
			_d3ddev.SetRenderState D3DRS_NORMALIZENORMALS,True

			_d3ddev.SetRenderState D3DRS_COLORVERTEX, True

			'_d3ddev.SetRenderState D3DRS_ALPHAREF, 1
			'_d3ddev.SetRenderState D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL
		EndIf
	End Method

	Method SetCamera(camera:TCamera,config:TWorldConfig)
		_d3ddev.SetRenderState D3DRS_DITHERENABLE, config.Dither

		Local clearflags
		If camera._clsmode&CLSMODE_COLOR clearflags:|D3DCLEAR_TARGET
		If camera._clsmode&CLSMODE_DEPTH clearflags:|D3DCLEAR_ZBUFFER

		Local viewport[]=[camera._viewx,camera._viewy,camera._viewwidth-camera._viewx,camera._viewheight-camera._viewy]
		_d3ddev.SetScissorRect viewport
		_d3ddev.Clear(1,viewport,clearflags,D3DCOLOR_XRGB(camera._brush._r*255,camera._brush._g*255,camera._brush._b*255),1.0,0)

		Select camera._fogmode
		Case FOGMODE_LINEAR
			_d3ddev.SetRenderState D3DRS_FOGENABLE,True
			_d3ddev.SetRenderState D3DRS_FOGSTART,Int(Varptr camera._fognear)
			_d3ddev.SetRenderState D3DRS_FOGEND,Int(Varptr camera._fogfar)
		Default
			_d3ddev.SetRenderState D3DRS_FOGENABLE,False
		End Select

		Local oldnear# = camera._near ' Ugh, hack. Need to investigate cause.
		camera._near :- 0.396250010
		camera.UpdateMatrices()
		camera._near = oldnear

		_d3ddev.SetTransform D3DTS_PROJECTION,camera._projection.ToPtr()
		_d3ddev.SetTransform D3DTS_VIEW,camera._modelview.ToPtr()
	End Method

	Method SetLight(light:TLight,index)
		If light=Null
			_d3ddev.LightEnable index,False
			Return
		EndIf

		Local brush:TBrush=light._brush

		Global d3dlight:D3DLIGHT9=New D3DLIGHT9
		d3dlight.Type_=D3DLIGHT_DIRECTIONAL
		d3dlight.Diffuse_r=brush._r;d3dlight.Diffuse_g=brush._g;d3dlight.Diffuse_b=brush._b;d3dlight.Diffuse_a=brush._a
		'd3dlight.Ambient_r=WorldConfig.AmbientRed/255.0;d3dlight.Ambient_g=WorldConfig.AmbientGreen/255.0;d3dlight.Ambient_b=WorldConfig.AmbientBlue/255.0;d3dlight.Ambient_a=1.0

		d3dlight.Direction_x=0.0;d3dlight.Direction_y=0.0;d3dlight.Direction_z=1.0

		Local matrix:TMatrix=light._matrix
		matrix.TransformVec3 d3dlight.Direction_x,d3dlight.Direction_y,d3dlight.Direction_z
		matrix.GetPosition d3dlight.Position_x,d3dlight.Position_y,d3dlight.Position_z

		d3dlight.Range=light._range

		_d3ddev.SetLight index,d3dlight
		_d3ddev.LightEnable index,True
	End Method

	Method SetBrush(brush:TBrush,hasalpha,config:TWorldConfig)
		_d3ddev.SetRenderState D3DRS_ALPHABLENDENABLE,hasalpha
		_d3ddev.SetRenderState D3DRS_ZWRITEENABLE,Not hasalpha

		Select brush._blend
		Case BLEND_NONE, BLEND_ALPHA
			_d3ddev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
			_d3ddev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA
		Case BLEND_MULTIPLY
			_d3ddev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_DESTCOLOR
			_d3ddev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ZERO
		Case BLEND_ADD
			_d3ddev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
			_d3ddev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ONE
		End Select

		If brush._fx&FX_FULLBRIGHT
			_d3ddev.SetRenderState D3DRS_AMBIENT,D3DCOLOR_RGB(255,255,255)
		Else
			_d3ddev.SetRenderState D3DRS_AMBIENT,D3DCOLOR_RGB(config.AmbientRed,config.AmbientGreen,config.AmbientBlue)
		EndIf

		If brush._fx&FX_VERTEXCOLOR
			_d3ddev.SetRenderState D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_COLOR1
			_d3ddev.SetRenderState D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_COLOR1
		Else
			_d3ddev.SetRenderState D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_MATERIAL
			_d3ddev.SetRenderState D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_MATERIAL
		EndIf

		If brush._fx&FX_FLATSHADED
			_d3ddev.SetRenderState D3DRS_SHADEMODE, D3DSHADE_FLAT
		Else
			_d3ddev.SetRenderState D3DRS_SHADEMODE, D3DSHADE_GOURAUD
		EndIf

		If brush._fx&FX_NOCULLING
			_d3ddev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE
		Else
			_d3ddev.SetRenderState D3DRS_CULLMODE,D3DCULL_CCW
		EndIf

		If brush._fx&FX_WIREFRAME Or config.Wireframe
			_d3ddev.SetRenderState D3DRS_FILLMODE,D3DFILL_WIREFRAME
		Else
			_d3ddev.SetRenderState D3DRS_FILLMODE,D3DFILL_SOLID
		EndIf

		Local material:D3DMATERIAL9 = New D3DMATERIAL9
		material.Diffuse_r=brush._r;material.Diffuse_g=brush._g;material.Diffuse_b=brush._b;material.Diffuse_a=brush._a
		material.Ambient_r=brush._r;material.Ambient_g=brush._g;material.Ambient_b=brush._b;material.Ambient_a=brush._a

		_d3ddev.SetMaterial material

		Local alpha_test
		For Local i=0 To 7
			Local texture:TTexture=brush._texture[i]
			If texture=Null Or texture._blend=BLEND_NONE
				_d3ddev.SetTexture i,Null
				Continue
			EndIf

			_d3ddev.SetTexture i,UpdateTextureRes(texture._frame[brush._textureframe[i]],texture._flags)._tex

			Local matrix:TMatrix=TMatrix.Identity()
			'matrix._m[0,0]=-texture._sx
			'matrix._m[1,1]=texture._sy
			matrix=TMatrix.YawPitchRoll(0,0,-texture._r).Multiply(matrix)
			matrix=TMatrix.Scale(-texture._sx,texture._sy,1).Multiply(matrix)
			matrix._m[2,0]=-texture._px
			matrix._m[2,1]=-texture._py

			_d3ddev.SetTransform D3DTS_TEXTURE0+i,matrix.ToPtr()

			_d3ddev.SetTextureStageState i,D3DTSS_TEXTURETRANSFORMFLAGS,D3DTTFF_COUNT2
			_d3ddev.SetTextureStageState i,D3DTSS_ADDRESS,0

			_d3ddev.SetSamplerState i,D3DSAMP_MAGFILTER,D3DTEXF_LINEAR
			_d3ddev.SetSamplerState i,D3DSAMP_MINFILTER,D3DTEXF_LINEAR

			'_d3ddev.SetRenderState D3DRS_WRAP0+i, D3DWRAP_U|D3DWRAP_V
			alpha_test :| (texture._flags&TEXTURE_ALPHA Or texture._flags&TEXTURE_MASKED)

			If texture._flags&TEXTURE_MIPMAP
				_d3ddev.SetSamplerState i,D3DSAMP_MIPFILTER,D3DTEXF_LINEAR
				_d3ddev.SetTextureStageState i,D3DTSS_MAGFILTER,D3DTEXF_LINEAR
				_d3ddev.SetTextureStageState i,D3DTSS_MINFILTER,D3DTEXF_LINEAR
			Else
				_d3ddev.SetSamplerState i,D3DSAMP_MIPFILTER,D3DTEXF_NONE
				_d3ddev.SetTextureStageState i,D3DTSS_MAGFILTER,D3DTEXF_POINT
				_d3ddev.SetTextureStageState i,D3DTSS_MINFILTER,D3DTEXF_POINT
			EndIf

			If texture._flags&TEXTURE_CLAMPU
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP
			Else
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSU,D3DTADDRESS_WRAP
			EndIf

			If texture._flags&TEXTURE_CLAMPV
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP
			Else
				_d3ddev.SetSamplerState i,D3DSAMP_ADDRESSV,D3DTADDRESS_WRAP
			EndIf

			If texture._flags&TEXTURE_SPHEREMAP
				_d3ddev.SetTextureStageState i,D3DTSS_TEXCOORDINDEX,D3DTSS_TCI_SPHEREMAP
			Else
				_d3ddev.SetTextureStageState i,D3DTSS_TEXCOORDINDEX,texture._coords
			EndIf

			Select texture._blend
			Case BLEND_ALPHA
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_MODULATE
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_MODULATE
			Case BLEND_MULTIPLY
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_MODULATE
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_MODULATE
			Case BLEND_ADD
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_ADD
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_ADD
			Case BLEND_DOT3
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_DOTPRODUCT3
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_DOTPRODUCT3
			Case BLEND_MULTIPLY2
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_MODULATE2X
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_MODULATE2X
			Default
				_d3ddev.SetTextureStageState i,D3DTSS_COLOROP,D3DTOP_SELECTARG2
				_d3ddev.SetTextureStageState i,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2
			End Select
		Next
		_d3ddev.SetRenderState D3DRS_ALPHATESTENABLE, alpha_test
	End Method

	Method RenderSurface(resource:TSurfaceRes,brush:TBrush)
		Local res:TD3D9SurfaceRes=TD3D9SurfaceRes(resource)

		_d3ddev.SetFVF 0
		_d3ddev.SetVertexDeclaration GetD3D9MaxB3DVertexDecl(_d3ddev)
		_d3ddev.SetStreamSource 0,res._pos,0,12
		_d3ddev.SetStreamSource 1,res._nml,0,12
		_d3ddev.SetStreamSource 2,res._clr,0,16
		_d3ddev.SetStreamSource 3,res._tex[0],0,8
		_d3ddev.SetStreamSource 4,res._tex[1],0,8
		_d3ddev.SetStreamSource 5,res._tex[2],0,8
		_d3ddev.SetStreamSource 6,res._tex[3],0,8
		_d3ddev.SetStreamSource 7,res._tex[4],0,8
		_d3ddev.SetStreamSource 8,res._tex[5],0,8
		_d3ddev.SetStreamSource 9,res._tex[6],0,8
		_d3ddev.SetStreamSource 10,res._tex[7],0,8
		_d3ddev.SetIndices res._tri
		_d3ddev.DrawIndexedPrimitive D3DPT_TRIANGLELIST,0,0,res._vertexcnt,0,res._trianglecnt

		Return res._trianglecnt
	End Method

	Method RenderSprite(sprite:TSprite)
		Global _data#[]=[ -1.0, 1.0,0.0, 0.0,0.0,1.0, 0.0,0.0, ..
											-1.0,-1.0,0.0, 0.0,0.0,1.0, 0.0,1.0, ..
		                   1.0, 1.0,0.0, 0.0,0.0,1.0, 1.0,0.0, ..
		                   1.0,-1.0,0.0, 0.0,0.0,1.0, 1.0,1.0     ]

		_d3ddev.SetVertexDeclaration Null
		_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1
		_d3ddev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_data,8*4
	End Method

	Method BeginEntityRender(entity:TEntity)
		_d3ddev.SetTransform D3DTS_WORLD,entity.GetMatrix(True).ToPtr()
	End Method

	Method EndEntityRender(entity:TEntity)
	End Method

	Method RenderFlat(flat:TFlat)
		Local x#,y#,z#
		flat.GetScale x,y,z,True

		Global _data#[]=[ -1.0,0.0, 1.0, 0.0,1.0,0.0, 0.0,0.0, ..
		                   1.0,0.0, 1.0, 0.0,1.0,0.0,   x,0.0, ..
		                  -1.0,0.0,-1.0, 0.0,1.0,0.0, 0.0,  z, ..
		                   1.0,0.0,-1.0, 0.0,1.0,0.0,   x,  z     ]

		_d3ddev.SetVertexDeclaration Null
		_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1
		_d3ddev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_data,8*4
	End Method

	Method RenderTerrain(terrain:TTerrain)
	End Method

	Method RenderBSPTree(tree:TBSPTree)
		Local node:TBSPNode=tree.Node
		If node=Null Return
		Local triangles
		triangles:+RenderBSPTree(node.In)

		_d3ddev.SetVertexDeclaration Null
		_d3ddev.SetFVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1

		For Local poly:TBSPPolygon=EachIn node.On
			Local ptA:TVector=poly.Point[0],v0
			Local trianglecnt=poly.Count()-2
			Local data#[trianglecnt*24],dataptr:Float Ptr=data
			For Local i=0 To trianglecnt-1
				Local ptB:TVector=poly.Point[i+1],ptC:TVector=poly.Point[i+2]
				data[i*24+00]=ptA.x;data[i*24+01]=ptA.y;data[i*24+02]=ptA.z;data[i*24+03]=poly.Plane.x;data[i*24+04]=poly.Plane.y;	data[i*24+05]=poly.Plane.z;data[i*24+06]=0.0;data[i*24+07]=0.0
				data[i*24+08]=ptB.x;data[i*24+09]=ptB.y;data[i*24+10]=ptB.z;data[i*24+11]=poly.Plane.x;data[i*24+12]=poly.Plane.y;	data[i*24+13]=poly.Plane.z;data[i*24+14]=0.0;data[i*24+15]=0.0
				data[i*24+16]=ptC.x;data[i*24+17]=ptC.y;data[i*24+18]=ptC.z;data[i*24+19]=poly.Plane.x;data[i*24+20]=poly.Plane.y;data[i*24+21]=poly.Plane.z;data[i*24+22]=0.0;data[i*24+23]=0.0
			Next
			_d3ddev.DrawPrimitiveUP D3DPT_TRIANGLELIST,trianglecnt,data,8*4
			triangles:+trianglecnt
		Next

		triangles:+RenderBSPTree(node.Out)
		Return triangles
	End Method

	Method UpdateTextureRes:TD3D9TextureRes(frame:TTextureFrame,flags)
		Local res:TD3D9TextureRes=TD3D9TextureRes(frame._res)
		If res And frame._updateres=False Return res

		If res=Null res=New TD3D9TextureRes
		frame._res=res

		Local pixmap:TPixmap=frame._pixmap
		Local tex_width=Pow2Size(pixmap.width),tex_height=Pow2Size(pixmap.height)
		pixmap=ConvertPixmap(ResizePixmap(pixmap,tex_width,tex_height),PF_BGRA8888)
		If res._tex=Null Assert _d3ddev.CreateTexture(tex_width,tex_height,(flags & TEXTURE_MIPMAP)=0,D3DUSAGE_AUTOGENMIPMAP,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,res._tex,Null)=D3D_OK

		Local rect:D3DLOCKED_RECT=New D3DLOCKED_RECT
		res._tex.LockRect 0,rect,Null,0
		MemCopy rect.pBits,pixmap.pixels,pixmap.width*pixmap.height*4
		res._tex.UnlockRect 0

		frame._updateres=False

		Return res
	End Method

	Method UpdateSurfaceRes:TD3D9SurfaceRes(surface:TSurface)
		Local res:TD3D9SurfaceRes=TD3D9SurfaceRes(surface._res)
		If res=Null res=New TD3D9SurfaceRes;surface._reset=-1

		If surface._reset=0 Return res
		If surface._reset=-1 surface._reset=1|2|4|8|16|32|64|128|256

		If surface._reset&1 And surface._vertexpos UploadVertexData res._pos,surface._vertexpos
		If surface._reset&2 And surface._vertexnml UploadVertexData res._nml,surface._vertexnml
		If surface._reset&4 And surface._vertexclr UploadVertexData res._clr,surface._vertexclr
		If surface._reset&8 And surface._triangle
			If res._tri=Null _d3ddev.CreateIndexBuffer(surface._triangle.length*4,0,D3DFMT_INDEX32,D3DPOOL_MANAGED,res._tri,Null)
			Local dataptr:Byte Ptr
			Assert res._tri.Lock(0,0,dataptr,0)=D3D_OK,"Failed to lock index buffer."
			MemCopy dataptr,surface._triangle,surface._triangle.length*4
			res._tri.Unlock()
		EndIf

		For Local i=0 To surface._vertextex.length-1
			If surface._reset&Int(2^(4+i)) UploadVertexData res._tex[i],surface._vertextex[i]
		Next

		res._trianglecnt=surface._trianglecnt
		res._vertexcnt=surface._vertexcnt

		surface._reset=0
		surface._res=res

		Return res
	End Method

	Method MergeSurfaceRes:TSurfaceRes(base:TSurface,animation:TSurface,data)
		If animation=Null Return UpdateSurfaceRes(base)
		Local base_res:TD3D9SurfaceRes=UpdateSurfaceRes(base)
		Local anim_res:TD3D9SurfaceRes=UpdateSurfaceRes(animation)
		Local res:TD3D9SurfaceRes=base_res.Copy()
		res._pos=anim_res._pos
		Return res
	End Method

	Method UploadVertexData(buffer:IDirect3DVertexBuffer9 Var,data#[])
		If buffer=Null _d3ddev.CreateVertexBuffer(data.length*4,0,0,D3DPOOL_MANAGED,buffer,Null)
		Local dataptr:Byte Ptr
		Assert buffer.Lock(0,0,dataptr,0)=D3D_OK,"Failed to lock vertex buffer."
		MemCopy dataptr,data,data.length*4
		buffer.Unlock()
	End Method

End Type

Type TD3D9TextureRes Extends TTextureRes
	Field _tex:IDirect3DTexture9
End Type

Type TD3D9SurfaceRes Extends TSurfaceRes
	Field _pos:IDirect3DVertexBuffer9
	Field _nml:IDirect3DVertexBuffer9
	Field _clr:IDirect3DVertexBuffer9
	Field _tri:IDirect3DIndexBuffer9
	Field _tex:IDirect3DVertexBuffer9[8]

	Method Copy:TD3D9SurfaceRes()
		Local res:TD3D9SurfaceRes=New TD3D9SurfaceRes
		res._vertexcnt=_vertexcnt;res._trianglecnt=_trianglecnt
		res._pos=_pos;res._nml=_nml;res._clr=_clr;res._tri=_tri;
		For Local i=0 To 7
			res._tex[i]=_tex[i]
		Next
		Return res
	End Method
End Type

Rem
	bbdoc: Needs documentation. #TODO
End Rem
Function D3D9MaxB3DDriver:TD3D9MaxB3DDriver()
	If D3D9Max2DExDriver()
		Global driver:TD3D9MaxB3DDriver=New TD3D9MaxB3DDriver
		driver._parent=D3D9Max2DExDriver()
		Return driver
	End If
End Function

Rem
	bbdoc: Utility function that sets the MaxB3D D3D9 driver and calls Graphics.
End Rem
Function D3D9Graphics3D:TGraphics(width,height,depth=0,hertz=0,flags=0)
	SetGraphicsDriver D3D9MaxB3DDriver(),GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER
	Return Graphics(width,height,depth,hertz,flags)
End Function

Local driver:TD3D9MaxB3DDriver=D3D9MaxB3DDriver()
If driver SetGraphicsDriver driver,GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER

?


CreateMonkeyHead fix

CreateMonkeyHead fix

Strict

Rem
	bbdoc: Blender's 'Suzanne' model loader.
End Rem
Module MaxB3D.MonkeyHeadLoader

Import MaxB3D.Core
Import "data.c"

Extern
	Function get_monkeyhead(verts:Float Ptr Var,normals:Float Ptr Var,tris:Short Ptr Var,vert_count Var,tri_count Var)
End Extern

Type TMeshLoaderMONKEYHEAD Extends TMeshLoader
	Method Run(config:TWorldConfig,mesh:TMesh,stream:TStream,url:Object)
		If String(url)<>"//monkeyhead" Return False
		Global surface:TSurface
		If Not surface
			surface=New TSurface
			Local v:Float Ptr,n:Float Ptr,t:Short Ptr,vc,tc
			get_monkeyhead v,n,t,vc,tc
			surface.Resize vc,tc

			For Local i=0 To vc-1
				surface.SetCoords i,v[i*3+0],v[i*3+1],v[i*3+2]
				surface.SetNormal i,-n[i*3+0],-n[i*3+1],-n[i*3+2]
			Next

			For Local i=0 To tc-1
				surface.SetTriangle i,t[i*3+0],t[i*3+1],t[i*3+2]
			Next
		EndIf
		mesh.AppendSurface surface.Copy()
		Return True
	End Method

	Method Info$()
		Return "Suzanne"
	End Method
	Method ModuleName$()
		Return "monkeyheadloader"
	End Method
End Type
New TMeshLoaderMONKEYHEAD

Rem
	bbdoc: Needs documentation. #TODO
End Rem
Function CreateMonkeyHead:TMesh(parent:TEntity=Null)
	Return _currentworld.AddMesh("//monkeyhead",parent)
End Function

Strict

Rem
	bbdoc: Blender's 'Suzanne' model loader.
End Rem
Module MaxB3D.MonkeyHeadLoader

Import MaxB3D.Core
Import "data.c"

Extern
	Function get_monkeyhead(verts:Float Ptr Var,normals:Float Ptr Var,tris:Short Ptr Var,vert_count Var,tri_count Var)
End Extern

Type TMeshLoaderMONKEYHEAD Extends TMeshLoader
	Method Run(config:TWorldConfig,mesh:TMesh,stream:TStream,url:Object)
		If String(url)<>"//monkeyhead" Return False
		Global surface:TSurface
		If Not surface
			surface=New TSurface
			Local v:Float Ptr,n:Float Ptr,t:Short Ptr,vc,tc
			get_monkeyhead v,n,t,vc,tc
			surface.Resize vc,tc

			For Local i=0 To vc-1
				surface.SetCoords i,v[i*3+0],v[i*3+1],v[i*3+2]
				surface.SetNormal i,-n[i*3+0],-n[i*3+1],-n[i*3+2]
			Next

			For Local i=0 To tc-1
				surface.SetTriangle i,t[i*3+0],t[i*3+1],t[i*3+2]
			Next
		EndIf
		mesh.AppendSurface surface.Copy()
		Return True
	End Method

	Method Info$()
		Return "Suzanne"
	End Method
	Method ModuleName$()
		Return "monkeyheadloader"
	End Method
End Type
New TMeshLoaderMONKEYHEAD

Rem
	bbdoc: Needs documentation. #TODO
End Rem
Function CreateMonkeyHead:TMesh(parent:TEntity=Null)
	Return _currentworld.AddMesh("*monkeyhead*",parent)
End Function


[json] (v0.3) 	Corrected rootliness in dJEventHandler.

Rem
Copyright (c) 2010 Tim Howard

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
End Rem

SuperStrict

Rem
bbdoc: JSON handler for cower.jonk
End Rem
Module duct.json

ModuleInfo "Version: 0.3"
ModuleInfo "Copyright: Tim Howard"
ModuleInfo "License: MIT"

ModuleInfo "History: Version 0.3"
ModuleInfo "History: Corrected rootliness in dJEventHandler"
ModuleInfo "History: Version 0.2"
ModuleInfo "History: dJNullVariable.ValueAsString now returns Null (instead of ~qnull~q); documentation correction"
ModuleInfo "History: Version 0.1"
ModuleInfo "History: Initial version."

Import duct.variables
Import cower.jonk

Rem
	bbdoc: duct JSON object.
End Rem
Type dJObject Extends TIdentifier

	Rem
		bbdoc: Create a new dJObject.
		returns: The new dJObject (itself).
	End Rem
	Method Create:dJObject()
		Super.Create()
		Return Self
	End Method

	Rem
		bbdoc: Get the object's parent.
		returns: The object's parent.
	End Rem
	Method GetParent:dJObject()
		Return dJObject(m_parent)
	End Method

End Type

Rem
	bbdoc: duct JSON array.
End Rem
Type dJArray Extends dJObject

	Rem
		bbdoc: Create a new dJArray.
		returns: The new dJArray (itself).
	End Rem
	Method Create:dJArray()
		Super.Create()
		Return Self
	End Method

End Type

Const TV_NULL:Int = 100

Rem
	bbdoc: duct JSON null variable.
End Rem
Type dJNullVariable Extends TVariable

	Rem
		bbdoc: Create a New dJNullVariable.
		returns: The New dJNullVariable (itself).
	End Rem
	Method Create:dJNullVariable(name:String = Null)
		SetName(name)
		Return Self
	End Method

'#region Field accessors

	Rem
		bbdoc: Set the value of the variable To the given String (ambiguous).
		returns: Nothing.
		about: This does nothing for dJNullVariable.
	End Rem
	Method SetAmbiguous(value:String)
	End Method

	Rem
		bbdoc: Convert the variable to a String.
		returns: A string representation of the variable.
		about: This function is for script output, for in-code use see #ValueAsString.
	End Rem
	Method ConvToString:String()
		Return "null"
	End Method

	Rem
		bbdoc: Get the variable as a String.
		returns: The variable's value converted to a String.
	End Rem
	Method ValueAsString:String()
		Return Null
	End Method

'#end region (Field accessors)

'#region Data handling

	Rem
		bbdoc: Create a copy of the variable
		returns: A clone of the variable.
	End Rem
	Method Copy:dJNullVariable()
		Return New dJNullVariable.Create(m_name)
	End Method

	Rem
		bbdoc: Serialize the variable to a stream.
		returns: Nothing.
		about: @tv tells the method whether it should serialize the TV type for the variable, or to not.
	End Rem
	Method Serialize(stream:TStream, tv:Int = True, name:Int = False)
		If tv = True
			stream.WriteByte(TV_INTEGER)
		End If
		If name = True
			WriteLString(stream, m_name)
		End If
	End Method

	Rem
		bbdoc: Deserialize the variable from a stream.
		returns: The deserialized variable.
		about: @tv tells the method whether it should deserialize the TV type for the variable, or to not.
	End Rem
	Method DeSerialize:dJNullVariable(stream:TStream, tv:Int = True, name:Int = False)
		If tv = True
			stream.ReadByte()
		End If
		If name = True
			m_name = ReadLString(stream)
		End If
		Return Self
	End Method

'#end region (Data handling)

	Rem
		bbdoc: Get the type of this variable.
		returns: The type of this variable ("null").
	End Rem
	Function ReportType:String()
		Return "null"
	End Function

	Rem
		bbdoc: Get the TV type of this variable.
		returns: The TV_* type of this variable (TV_NULL).
	End Rem
	Function GetTVType:Int()
		Return TV_NULL
	End Function

End Type

Rem
	bbdoc: duct event handler for JONK.
End Rem
Type dJEventHandler Extends JEventHandler

	Field m_objname:String
	Field m_root:dJObject
	Field m_object:dJObject

	Field tmpvar:TVariable

	Method BeginParsing()
		'm_root = New dJObject.Create()
		'm_object = m_root
	End Method

	Method EndParsing()
		'Assert m_object = m_root, "(dJEventHandler.EndParsing) m_object != m_root!"
		m_objname = Null
		m_object = Null
	End Method

	Method ObjectBegin()
		tmpvar = New dJObject.Create()
		DoBegin()
	End Method

	Method ObjectKey(name:String)
		m_objname = name
	End Method

	Method ObjectEnd()
		m_object = dJObject(m_object.GetParent())
	End Method

	Method ArrayBegin()
		tmpvar = New dJArray.Create()
		DoBegin()
	End Method

	Method ArrayEnd()
		m_object = dJObject(m_object.GetParent())
	End Method

	Method NumberValue(number:String, isdecimal:Int)
		If isdecimal = True
			tmpvar = New TFloatVariable.Create(Null, Float(number))
		Else
			tmpvar = New TIntVariable.Create(Null, Int(number))
		End If
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method StringValue(value:String)
		tmpvar = New TStringVariable.Create(Null, value)
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method BooleanValue(value:Int)
		tmpvar = New TBoolVariable.Create(Null, value)
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method NullValue()
		tmpvar = New dJNullVariable.Create(Null)
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method Error:Int(err:JParserException)
		Return False
	End Method

	Method SetAndClearName(variable:TVariable)
		variable.SetName(m_objname)
		m_objname = Null
	End Method

	Method DoBegin()
		SetAndClearName(tmpvar)
		If m_object <> Null m_object.AddValue(tmpvar)
		m_object = dJObject(tmpvar)
		If Not m_root Then m_root = m_object
	End Method

End Type

Rem
	bbdoc: duct JSON reader.
End Rem
Type dJReader

	Field m_evthandler:dJEventHandler
	Field m_parser:JParser
	Field m_root:dJObject

	Method New()
		m_evthandler = New dJEventHandler
	End Method

	Rem
		bbdoc: Initiate the reader with the given url/stream.
		returns: Itself, or Null if the stream could not be opened.
	End Rem
	Method InitWithStream:dJReader(url:Object, encoding:Int = JSONEncodingUTF8, bufferLength:Int = JParser.JPARSERBUFFER_INITIAL_SIZE)
		Try
			m_parser = New JParser.InitWithStream(url, m_evthandler, encoding, bufferLength)
			Return Self
		Catch e:JException
			Return Null
		End Try
	End Method

	Rem
		bbdoc: Initiate the reader with the given string.
		returns: Itself.
	End Rem
	Method InitWithString:dJReader(str:String)
		m_parser = New JParser.InitWithString(str, m_evthandler)
		Return Self
	End Method

	Rem
		bbdoc: Parse the reader's data.
		returns: The root object for the json data.
		about: A #JParserException will be thrown if there is an error during parsing.
	End Rem
	Method Parse:dJObject()
		m_parser.Parse()
		Return m_evthandler.m_root
	End Method

End Type

Rem
	Copyright (c) 2009 Tim Howard

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
End Rem

SuperStrict

Rem
bbdoc: JSON handler for cower.jonk
End Rem
Module duct.json

ModuleInfo "Version: 0.2"
ModuleInfo "Copyright: Tim Howard"
ModuleInfo "License: MIT"

ModuleInfo "History: Version 0.2"
ModuleInfo "History: dJNullVariable.ValueAsString now returns Null (instead of ~qnull~q); documentation correction"
ModuleInfo "History: Version 0.1"
ModuleInfo "History: Initial version."

Import duct.variables
Import cower.jonk

Rem
	bbdoc: duct JSON object.
End Rem
Type dJObject Extends TIdentifier

	Rem
		bbdoc: Create a new dJObject.
		returns: The new dJObject (itself).
	End Rem
	Method Create:dJObject()
		Super.Create()
		Return Self
	End Method

	Rem
		bbdoc: Get the object's parent.
		returns: The object's parent.
	End Rem
	Method GetParent:dJObject()
		Return dJObject(m_parent)
	End Method

End Type

Rem
	bbdoc: duct JSON array.
End Rem
Type dJArray Extends dJObject

	Rem
		bbdoc: Create a new dJArray.
		returns: The new dJArray (itself).
	End Rem
	Method Create:dJArray()
		Super.Create()
		Return Self
	End Method

End Type

Const TV_NULL:Int = 100

Rem
	bbdoc: duct JSON null variable.
End Rem
Type dJNullVariable Extends TVariable

	Rem
		bbdoc: Create a New dJNullVariable.
		returns: The New dJNullVariable (itself).
	End Rem
	Method Create:dJNullVariable(name:String = Null)
		SetName(name)
		Return Self
	End Method

'#region Field accessors

	Rem
		bbdoc: Set the value of the variable To the given String (ambiguous).
		returns: Nothing.
		about: This does nothing for dJNullVariable.
	End Rem
	Method SetAmbiguous(value:String)
	End Method

	Rem
		bbdoc: Convert the variable to a String.
		returns: A string representation of the variable.
		about: This function is for script output, for in-code use see #ValueAsString.
	End Rem
	Method ConvToString:String()
		Return "null"
	End Method

	Rem
		bbdoc: Get the variable as a String.
		returns: The variable's value converted to a String.
	End Rem
	Method ValueAsString:String()
		Return Null
	End Method

'#end region (Field accessors)

'#region Data handling

	Rem
		bbdoc: Create a copy of the variable
		returns: A clone of the variable.
	End Rem
	Method Copy:dJNullVariable()
		Return New dJNullVariable.Create(m_name)
	End Method

	Rem
		bbdoc: Serialize the variable to a stream.
		returns: Nothing.
		about: @tv tells the method whether it should serialize the TV type for the variable, or to not.
	End Rem
	Method Serialize(stream:TStream, tv:Int = True, name:Int = False)
		If tv = True
			stream.WriteByte(TV_INTEGER)
		End If
		If name = True
			WriteLString(stream, m_name)
		End If
	End Method

	Rem
		bbdoc: Deserialize the variable from a stream.
		returns: The deserialized variable.
		about: @tv tells the method whether it should deserialize the TV type for the variable, or to not.
	End Rem
	Method DeSerialize:dJNullVariable(stream:TStream, tv:Int = True, name:Int = False)
		If tv = True
			stream.ReadByte()
		End If
		If name = True
			m_name = ReadLString(stream)
		End If
		Return Self
	End Method

'#end region (Data handling)

	Rem
		bbdoc: Get the type of this variable.
		returns: The type of this variable ("null").
	End Rem
	Function ReportType:String()
		Return "null"
	End Function

	Rem
		bbdoc: Get the TV type of this variable.
		returns: The TV_* type of this variable (TV_NULL).
	End Rem
	Function GetTVType:Int()
		Return TV_NULL
	End Function

End Type

Rem
	bbdoc: duct event handler for JONK.
End Rem
Type dJEventHandler Extends JEventHandler

	Field m_objname:String
	Field m_root:dJObject
	Field m_object:dJObject

	Field tmpvar:TVariable

	Method BeginParsing()
		m_root = New dJObject.Create()
		m_object = m_root
	End Method

	Method EndParsing()
		Assert m_object = m_root, "(dJEventHandler.EndParsing) m_object != m_root!"
		m_objname = Null
		m_object = Null
	End Method

	Method ObjectBegin()
		tmpvar = New dJObject.Create()
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
		m_object = dJObject(tmpvar)
	End Method

	Method ObjectKey(name:String)
		m_objname = name
	End Method

	Method ObjectEnd()
		m_object = dJObject(m_object.GetParent())
	End Method

	Method ArrayBegin()
		tmpvar = New dJArray.Create()
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
		m_object = dJObject(tmpvar)
	End Method

	Method ArrayEnd()
		m_object = dJObject(m_object.GetParent())
	End Method

	Method NumberValue(number:String, isdecimal:Int)
		If isdecimal = True
			tmpvar = New TFloatVariable.Create(Null, Float(number))
		Else
			tmpvar = New TIntVariable.Create(Null, Int(number))
		End If
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method StringValue(value:String)
		tmpvar = New TStringVariable.Create(Null, value)
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method BooleanValue(value:Int)
		tmpvar = New TBoolVariable.Create(Null, value)
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method NullValue()
		tmpvar = New dJNullVariable.Create(Null)
		SetAndClearName(tmpvar)
		m_object.AddValue(tmpvar)
	End Method

	Method Error:Int(err:JParserException)
		Return False
	End Method

	Method SetAndClearName(variable:TVariable)
		variable.SetName(m_objname)
		m_objname = Null
	End Method

End Type

Rem
	bbdoc: duct JSON reader.
End Rem
Type dJReader

	Field m_evthandler:dJEventHandler
	Field m_parser:JParser
	Field m_root:dJObject

	Method New()
		m_evthandler = New dJEventHandler
	End Method

	Rem
		bbdoc: Initiate the reader with the given url/stream.
		returns: Itself, or Null if the stream could not be opened.
	End Rem
	Method InitWithStream:dJReader(url:Object, encoding:Int = JSONEncodingUTF8, bufferLength:Int = JParser.JPARSERBUFFER_INITIAL_SIZE)
		Try
			m_parser = New JParser.InitWithStream(url, m_evthandler, encoding, bufferLength)
			Return Self
		Catch e:JException
			Return Null
		End Try
	End Method

	Rem
		bbdoc: Initiate the reader with the given string.
		returns: Itself.
	End Rem
	Method InitWithString:dJReader(str:String)
		m_parser = New JParser.InitWithString(str, m_evthandler)
		Return Self
	End Method

	Rem
		bbdoc: Parse the reader's data.
		returns: The root object for the json data.
		about: A #JParserException will be thrown if there is an error during parsing.
	End Rem
	Method Parse:dJObject()
		m_parser.Parse()
		Return m_evthandler.m_root
	End Method

End Type


Added Karja's SetMatrix code for MonkeyMax.

--HG--
extra : convert_revision : svn%3Ae934d3cd-0d57-f34a-94d0-9e8d31ae1c29/trunk%40345

' ***** Start mojo.bmax.bmx ******

Global app:gxtkApp;

Type gxtkApp
	Field ginput:gxtkInput;
	Field gaudio:gxtkAudio;
	Field ggraphics:gxtkGraphics;

	Field dead:int=0;
	Field suspended:int=0;
	Field vloading:int=0;
	Field maxloading:int=0;
	Field updateRate:int=0;
	Field nextUpdate:Float=0;
	Field updatePeriod:Float=0;
	Field startMillis:Float=0;

	Method New()' gxtkApp()
		app=self;
		ggraphics=new gxtkGraphics;
	EndMethod

	Method Setup()

		ginput=new gxtkInput;
		gaudio=new gxtkAudio;

		bb_input_SetInputDevice(ginput);
		bb_audio_SetAudioDevice(gaudio);

		startMillis=BlitzMaxMillisecs()

		'game.stage.addEventListener( Event.ENTER_FRAME,OnEnterFrame );

		SetFrameRate( 0 );

		InvokeOnCreate();
		InvokeOnRender();
		Update()
	EndMethod

	Method Update()
		While Not AppTerminate()
			local updates:Int = 0

			local cont:int = 1
			While (cont)
				nextUpdate:+updatePeriod
				InvokeOnUpdate()
				if not updatePeriod then cont = 0
				if nextUpdate>BlitzMaxMillisecs() then cont = 0
				updates:+1
				if updates = 7 then
					nextUpdate = BlitzMaxMillisecs()
					cont = 0
				endif
			Wend
			InvokeOnRender()
		Wend
	EndMethod

	Method InvokeOnCreate()
		if dead return
		dead = 1
		OnCreate()
		dead = 0
	EndMethod

	Method InvokeOnUpdate()
		if dead or suspended or not updateRate or vloading return
		OnUpdate()
	EndMethod

	Method InvokeOnRender()
		if dead or suspended return
		ggraphics.BeginRender()
		if vloading
			OnLoading()
		else
			OnRender()
		Endif
		ggraphics.EndRender()
	EndMethod

	Method SetFrameRate( fps:int )
		if fps
			updatePeriod=1000.0/fps;
			nextUpdate=BlitzMaxMillisecs() +updatePeriod;
		else
			updatePeriod=0
		endif
	EndMethod

	Method LoadString:String( path:String )
		path = "data/" + path;
		Return LoadText( path )
	EndMethod

	' ***** GXTK API *****

	Method GraphicsDevice:gxtkGraphics()
		Return ggraphics
	EndMethod

	Method InputDevice:gxtkInput()
		Return ginput
	EndMethod

	Method AudioDevice:gxtkAudio()
		Return gaudio
	EndMethod

	Method SetUpdateRate:int(hertz:int)
		updateRate = hertz
		if not vloading then SetFrameRate(updateRate)
		Return 0
	EndMethod

	Method MilliSecs:Int()
		return BlitzMaxMillisecs() - startMillis
	EndMethod

	Method Loading:int()
		return vloading;
	EndMethod

	Method OnCreate:int()
		return 0;
	EndMethod

	Method OnUpdate:int()
		return 0;
	EndMethod

	Method OnSuspend:int()
		return 0;
	EndMethod

	Method OnResume:int()
		return 0;
	EndMethod

	Method OnRender:int()
		return 0;
	EndMethod

	Method OnLoading:int()
		return 0;
	EndMethod
EndType

Type gxtkGraphics
	Field gmode:Int = 1

	Method Mode:Int()
		return gmode
	EndMethod

	Method Cls:Int(r:int = 0, g:int = 0, b:int = 0)
		BlitzMaxCls(r, g, b)
		Return 0
	EndMethod

	Method LoadSurface:gxtkSurface(path:String)
		local image:TImage = LoadImage("data/"+path)
		if image then
			local gs:gxtkSurface = new gxtkSurface
			gs.setImage(image)
			return gs
		endif
		return null
	EndMethod

	Method BeginRender()
	EndMethod

	Method EndRender()
		Flip
	EndMethod

	Method SetColor:Int(r:Int, g:Int, b:Int)
		BlitzMaxSetColor(r, g, b)
		return 0
	EndMethod

	Method SetAlpha:Int(a:Float)
		BlitzMaxSetAlpha(a)
		return 0
	EndMethod

	Method SetBlend:Int(blend:Int)
		BlitzMaxSetBlend(blend)
		return 0
	EndMethod

	Method Width:Int()
		'TO-DO
		Return 800
	EndMethod

	Method Height:Int()
		'TO-DO
		Return 600
	EndMethod

	Method SetScissor:Int(x:int, y:int, w:int, h:int)
    'TO-DO
		Return 0
	EndMethod

	Method SetMatrix:Int(ix:float,iy:float,jx:float,jy:float,tx:float,ty:float)
		Local sx:Float = Sqr( (ix*ix) + (jx*jx) )
		Local sy:Float = Sqr( (iy*iy) + (jy*jy) )
		Local rot:Float = Atan2( jx, ix )
		SetTransform( rot, sx, sy )
		SetOrigin( tx, ty )
		Return 0
	EndMethod

	Method DrawSurface:Int(surface:gxtkSurface,x:Float,y:Float)
		DrawImage(surface.image, x, y, 0)
		Return 0
	EndMethod

	Method DrawSurface2:Int(surface:gxtkSurface,x:Float,y:Float, srcx:int, srcy:int, srcw:int, srch:int )

	'	Print "x = "+x
	'	Print "y = "+y
	'	Print "srcx = "+srcx
	'	Print "srcy = "+srcy
	'	Print "srcw = "+srcw
	'	Print "srch = "+srch
		DrawSubImageRect(surface.image, x, y, srcw, srch, srcx, srcy, srcw, srch)

		Return 0
	EndMethod

	Method DrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
		BlitzMaxDrawLine(x1, y1, x2, y2)
		Return 0
	EndMethod

	Method DrawOval:Int( x:Float, y:Float, w:Float, h:Float )
		BlitzMaxDrawOval(x, y, w, h)
		Return 0
	EndMethod

	Method DrawPoly:Int(vertices:Float[])
		BlitzMaxDrawPoly( vertices )
		Return 0
	EndMethod

	Method DrawRect:Int( x:Float, y:Float, w:Float, h:Float )
		BlitzMaxDrawRect(x, y, w, h)
		Return 0
	EndMethod
EndType

Type gxtkInput
	Method MouseX:Float()
		return 0
	EndMethod

	Method MouseY:Float()
		return 0
	EndMethod

	Method KeyDown:Int( key:Int )
		return BRL.PolledInput.KeyDown( key )
	EndMethod

	Method KeyHit:Int( key:Int )
		return BRL.PolledInput.KeyHit( key )
	EndMethod

	Method GetChar:Int()
		return BRL.PolledInput.GetChar()
	EndMethod

	Method JoyX:Int( index:Int )
		return Pub.FreeJoy.JoyX( index )
	EndMethod

	Method JoyY:Int( index:Int )
		return Pub.FreeJoy.JoyY( index )
	EndMethod

	Method JoyZ:Int( index:Int )
		return Pub.FreeJoy.JoyZ( index )
	EndMethod

	Method TouchX:Float( index:Int )
		return 0
	EndMethod

	Method TouchY:Float( index:Int )
		return 0
	EndMethod
EndType

Type gxtkAudio
	Field amusicState:Int = 0;

	Method MusicState:Int()
'		If( musicState = 1 And music.isPlaying() = False )
'			musicState = 0;
'		Endif
		return amusicState;
	EndMethod

	Method PlayMusic:Int( path:String, flags:int )
		return 0
	EndMethod

	Method StopMusic()
	EndMethod

	Method StopChannel( channel:Int )
	EndMethod

	Method PlaySample( sound:gxtkSample, channel:Int, flags:Int )
	EndMethod

	Method SetPan( channel:Int, pan:Float )
	EndMethod

	Method SetRate( channel:Int, rate:Float )
	EndMethod

	Method SetMusicVolume:Int( volume:Float )
		Return 0
	EndMethod

	Method SetVolume:Int( channel:Int, volume:Float )
		Return 0
	EndMethod

	Method LoadSample:gxtkSample( path:String )
		Return Null
	EndMethod
EndType

Type gxtkSample
	Method Discard()
	EndMethod
EndType

Function BlitzMaxDrawPoly:Int(vertices:Float[])
	DrawPoly vertices
	Return 0
EndFunction

Function BlitzMaxDrawRect:Int( x:Float, y:Float, w:Float, h:Float )
	DrawRect x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawOval:Int( x:Float, y:Float, w:Float, h:Float )
	DrawOval x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
	DrawLine x1, y1, x2, y2
	Return 0
EndFunction

Function BlitzMaxMillisecs:Int()
	return MilliSecs()
EndFunction

Function BlitzMaxSetColor(r:Int, g:Int, b:Int)
	SetColor(r, g, b)
EndFunction

Function BlitzMaxSetBlend(blend:Int)
	SetBlend(blend)
EndFunction

Function BlitzMaxSetAlpha(a:Float)
	SetAlpha(a)
EndFunction

Function BlitzMaxCls(r:Int = 0, g:Int = 0, b:Int = 0)
	SetClsColor(r, g, b)
	Cls
EndFunction

Type gxtkSurface
	Field w:Int, h:Int
	Field image:TImage

	Method setImage(image:TImage)
		self.image = image
	EndMethod

	Method Width:Int()
		return image.Width
	EndMethod

	Method Height:Int()
		return image.Height
	EndMethod

	Method Discard()
	EndMethod
EndType

' ***** End mojo.bmax.bmx ******

' ***** Start mojo.bmax.bmx ******

Global app:gxtkApp;

Type gxtkApp
	Field ginput:gxtkInput;
	Field gaudio:gxtkAudio;
	Field ggraphics:gxtkGraphics;

	Field dead:int=0;
	Field suspended:int=0;
	Field vloading:int=0;
	Field maxloading:int=0;
	Field updateRate:int=0;
	Field nextUpdate:Float=0;
	Field updatePeriod:Float=0;
	Field startMillis:Float=0;

	Method New()' gxtkApp()
		app=self;
		ggraphics=new gxtkGraphics;
	EndMethod

	Method Setup()

		ginput=new gxtkInput;
		gaudio=new gxtkAudio;

		bb_input_SetInputDevice(ginput);
		bb_audio_SetAudioDevice(gaudio);

		startMillis=BlitzMaxMillisecs()

		'game.stage.addEventListener( Event.ENTER_FRAME,OnEnterFrame );

		SetFrameRate( 0 );

		InvokeOnCreate();
		InvokeOnRender();
		Update()
	EndMethod

	Method Update()
		While Not AppTerminate()
			local updates:Int = 0

			local cont:int = 1
			While (cont)
				nextUpdate:+updatePeriod
				InvokeOnUpdate()
				if not updatePeriod then cont = 0
				if nextUpdate>BlitzMaxMillisecs() then cont = 0
				updates:+1
				if updates = 7 then
					nextUpdate = BlitzMaxMillisecs()
					cont = 0
				endif
			Wend
			InvokeOnRender()
		Wend
	EndMethod

	Method InvokeOnCreate()
		if dead return
		dead = 1
		OnCreate()
		dead = 0
	EndMethod

	Method InvokeOnUpdate()
		if dead or suspended or not updateRate or vloading return
		OnUpdate()
	EndMethod

	Method InvokeOnRender()
		if dead or suspended return
		ggraphics.BeginRender()
		if vloading
			OnLoading()
		else
			OnRender()
		Endif
		ggraphics.EndRender()
	EndMethod

	Method SetFrameRate( fps:int )
		if fps
			updatePeriod=1000.0/fps;
			nextUpdate=BlitzMaxMillisecs() +updatePeriod;
		else
			updatePeriod=0
		endif
	EndMethod

	Method LoadString:String( path:String )
		path = "data/" + path;
		Return LoadText( path )
	EndMethod

	' ***** GXTK API *****

	Method GraphicsDevice:gxtkGraphics()
		Return ggraphics
	EndMethod

	Method InputDevice:gxtkInput()
		Return ginput
	EndMethod

	Method AudioDevice:gxtkAudio()
		Return gaudio
	EndMethod

	Method SetUpdateRate:int(hertz:int)
		updateRate = hertz
		if not vloading then SetFrameRate(updateRate)
		Return 0
	EndMethod

	Method MilliSecs:Int()
		return BlitzMaxMillisecs() - startMillis
	EndMethod

	Method Loading:int()
		return vloading;
	EndMethod

	Method OnCreate:int()
		return 0;
	EndMethod

	Method OnUpdate:int()
		return 0;
	EndMethod

	Method OnSuspend:int()
		return 0;
	EndMethod

	Method OnResume:int()
		return 0;
	EndMethod

	Method OnRender:int()
		return 0;
	EndMethod

	Method OnLoading:int()
		return 0;
	EndMethod
EndType

Type gxtkGraphics
	Field gmode:Int = 1

	Method Mode:Int()
		return gmode
	EndMethod

	Method Cls:Int(r:int = 0, g:int = 0, b:int = 0)
		BlitzMaxCls(r, g, b)
		Return 0
	EndMethod

	Method LoadSurface:gxtkSurface(path:String)
		local image:TImage = LoadImage("data/"+path)
		if image then
			local gs:gxtkSurface = new gxtkSurface
			gs.setImage(image)
			return gs
		endif
		return null
	EndMethod

	Method BeginRender()
	EndMethod

	Method EndRender()
		Flip
	EndMethod

	Method SetColor:Int(r:Int, g:Int, b:Int)
		BlitzMaxSetColor(r, g, b)
		return 0
	EndMethod

	Method SetAlpha:Int(a:Float)
		BlitzMaxSetAlpha(a)
		return 0
	EndMethod

	Method SetBlend:Int(blend:Int)
		BlitzMaxSetBlend(blend)
		return 0
	EndMethod

	Method Width:Int()
		'TO-DO
		Return 800
	EndMethod

	Method Height:Int()
		'TO-DO
		Return 600
	EndMethod

	Method SetScissor:Int(x:int, y:int, w:int, h:int)
		Return 0
	EndMethod

	Method SetMatrix:Int(x:float,iy:float,jx:float,jy:float,tx:float,ty:float)
		Return 0
	EndMethod

	Method DrawSurface:Int(surface:gxtkSurface,x:Float,y:Float)
		DrawImage(surface.image, x, y, 0)
		Return 0
	EndMethod

	Method DrawSurface2:Int(surface:gxtkSurface,x:Float,y:Float, srcx:int, srcy:int, srcw:int, srch:int )

	'	Print "x = "+x
	'	Print "y = "+y
	'	Print "srcx = "+srcx
	'	Print "srcy = "+srcy
	'	Print "srcw = "+srcw
	'	Print "srch = "+srch
		DrawSubImageRect(surface.image, x, y, srcw, srch, srcx, srcy, srcw, srch)

		Return 0
	EndMethod

	Method DrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
		BlitzMaxDrawLine(x1, y1, x2, y2)
		Return 0
	EndMethod

	Method DrawOval:Int( x:Float, y:Float, w:Float, h:Float )
		BlitzMaxDrawOval(x, y, w, h)
		Return 0
	EndMethod

	Method DrawPoly:Int(vertices:Float[])
		BlitzMaxDrawPoly( vertices )
		Return 0
	EndMethod

	Method DrawRect:Int( x:Float, y:Float, w:Float, h:Float )
		BlitzMaxDrawRect(x, y, w, h)
		Return 0
	EndMethod
EndType

Type gxtkInput
	Method MouseX:Float()
		return 0
	EndMethod

	Method MouseY:Float()
		return 0
	EndMethod

	Method KeyDown:Int( key:Int )
		return BRL.PolledInput.KeyDown( key )
	EndMethod

	Method KeyHit:Int( key:Int )
		return BRL.PolledInput.KeyHit( key )
	EndMethod

	Method GetChar:Int()
		return BRL.PolledInput.GetChar()
	EndMethod

	Method JoyX:Int( index:Int )
		return Pub.FreeJoy.JoyX( index )
	EndMethod

	Method JoyY:Int( index:Int )
		return Pub.FreeJoy.JoyY( index )
	EndMethod

	Method JoyZ:Int( index:Int )
		return Pub.FreeJoy.JoyZ( index )
	EndMethod

	Method TouchX:Float( index:Int )
		return 0
	EndMethod

	Method TouchY:Float( index:Int )
		return 0
	EndMethod
EndType

Type gxtkAudio
	Field amusicState:Int = 0;

	Method MusicState:Int()
'		If( musicState = 1 And music.isPlaying() = False )
'			musicState = 0;
'		Endif
		return amusicState;
	EndMethod

	Method PlayMusic:Int( path:String, flags:int )
		return 0
	EndMethod

	Method StopMusic()
	EndMethod

	Method StopChannel( channel:Int )
	EndMethod

	Method PlaySample( sound:gxtkSample, channel:Int, flags:Int )
	EndMethod

	Method SetPan( channel:Int, pan:Float )
	EndMethod

	Method SetRate( channel:Int, rate:Float )
	EndMethod

	Method SetMusicVolume:Int( volume:Float )
		Return 0
	EndMethod

	Method SetVolume:Int( channel:Int, volume:Float )
		Return 0
	EndMethod

	Method LoadSample:gxtkSample( path:String )
		Return Null
	EndMethod
EndType

Type gxtkSample
	Method Discard()
	EndMethod
EndType

Function BlitzMaxDrawPoly:Int(vertices:Float[])
	DrawPoly vertices
	Return 0
EndFunction

Function BlitzMaxDrawRect:Int( x:Float, y:Float, w:Float, h:Float )
	DrawRect x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawOval:Int( x:Float, y:Float, w:Float, h:Float )
	DrawOval x, y, w, h
	Return 0
EndFunction

Function BlitzMaxDrawLine:Int( x1:Float,y1:Float,x2:Float,y2:Float )
	DrawLine x1, y1, x2, y2
	Return 0
EndFunction

Function BlitzMaxMillisecs:Int()
	return MilliSecs()
EndFunction

Function BlitzMaxSetColor(r:Int, g:Int, b:Int)
	SetColor(r, g, b)
EndFunction

Function BlitzMaxSetBlend(blend:Int)
	SetBlend(blend)
EndFunction

Function BlitzMaxSetAlpha(a:Float)
	SetAlpha(a)
EndFunction

Function BlitzMaxCls(r:Int = 0, g:Int = 0, b:Int = 0)
	SetClsColor(r, g, b)
	Cls
EndFunction

Type gxtkSurface
	Field w:Int, h:Int
	Field image:TImage

	Method setImage(image:TImage)
		self.image = image
	EndMethod

	Method Width:Int()
		return image.Width
	EndMethod

	Method Height:Int()
		return image.Height
	EndMethod

	Method Discard()
	EndMethod
EndType

' ***** End mojo.bmax.bmx ******


XYZRecord array resize #51

XYZRecord array resize #51

Type flixel

	Function systemMillisecs:Int()
		Return Millisecs()
	End Function

	Function hideMouse()
		bmxHideMouse()
	End Function

	Function showMouse()
		bmxShowMouse()
	End Function

	Function isMobile:Int()
		Return False
	End Function

	Function openURL(url:String)
		bmxOpenURL(url)
	End Function

End Type

Function bmxHideMouse()
	HideMouse()
EndFunction

Function bmxShowMouse()
	ShowMouse()
EndFunction

Function bmxOpenURL(url:String)
	OpenURL(url)
End Function

Function resize_array_array_XYZRecord:bb_xyzrecord__1X_1Y_1Z_1Record[][] (arr:bb_xyzrecord__1X_1Y_1Z_1Record[][], leng:Int)
	Local i:Int = arr.length
	arr = arr[..leng]

	If( leng<=i ) Return arr

	For Local l:Int = 0 Until Len(arr)
		arr[l] = arr[l][..leng]
	Next

	While( i<leng )
		arr[0][i]= Null
		i:+1
	Wend

	Return arr
EndFunction