| WIP TEntity.bmx 
 
 
SuperStrict
Module engine.core
Import max2d.max2d
Import engine.Script
'Import brl.maxlua
Import BRL.Stream
Import BRL.PNGLoader
Import BRL.JPGLoader
Import BRL.TGALoader
Import BRL.BMPLoader
Import BRL.TextStream
Import DATA.THash
Import DATA.TData
Import BAH.ChipMunk
'Import BAH.BOX2D
Include "include/TAspect.bmx"
Include "include/TListData.bmx"
Include "include/etc.bmx"
 
Private
Global cpWorld:CPSpace = New CPSpace
Global world:TList = New TList, add@ = True
Global oldPick:TEntity, newPick:TEntity
Global post:TList = New TList
Function Linear#(a#, b#, m#)
	Return a + (b - a) * m
End Function
Public
Type TEntity Extends TLuaObject Final
	'id
	Field name$
	
	'active state
	Field _hide@
	
	'transform
	Field _pos:Vec2 = New Vec2
	Field _scl:Vec2 = Vec2.Create(1.0, 1.0)
	Field _ang#
	
	'tween
	'Field _tween# Ptr = MemAlloc(20)
	Field _oldx#			{no_save}
	Field _oldy#			{no_save}
	Field _oldsx# = 1.0		{no_save}
	Field _oldsy# = 1.0		{no_save}
	Field _oldang# = _ang	{no_save}
	
	'script
	Field _path$
	
	'hierarhy
	Field _parent:TEntity 			{ no_save no_copy hide }
	Field _link:TLink = New TLink { no_save no_copy }
	Field _childs:TList = New TList	{ no_copy }
	
	'aspects
	Field _aspects:THash = New THash
	
	Method SendMessage:Object(message:Object, context:Object)
		Local m$ = String(message)
		
		Select m.ToLower()
		Case "angle", "rotate"
		
		Case "turns"
			If context = "set"
				DebugLog "TURN?"
				Turn(Float(String(lua_result)))
			End If
			Return FloatTypeId
		Case "hide"
			If context = "get"
				lua_result = String(GetHide())
			Else
				DebugLog "SetHide = "+String(lua_result)
				_hide = String(lua_result).ToInt()
				DebugLog "Hide field: " + String(_hide)
			End If
			Return BoolTypeId
		Case "name"
			If context = "get"
			
			Else
			
			End If
		Case "path"
			If context = "get"
				lua_result = _path
			Else
				'DebugLog "setter!"
				_path = String(lua_result)
			End If
			Return StringTypeId
		End Select
		
		If context = "get"
			Local obj:Object = _aspects.ValueForKey(m)
			If obj
				lua_result = obj
				Return ObjectTypeId
			End If
		Else
		
		End If
		
	End Method
	
	Method New()
		name = "Entity_" + Super.ToString()
		If add = True Then _link = world.AddLast(Self)
	End Method
	
	Method Free()
		Invoke("Free")
		For Local a:TAspect = EachIn _aspects.Values()
			a.Free(Self)
		Next
		For Local child:TEntity = EachIn _childs
			child.Free()
		Next
		_link.Remove()
		_link = Null
		_parent = Null
		'MemFree(_tween)
		'If _parent
		'	_parent._childs.Remove(Self)
		'Else
		'	world.Remove(Self)
		'End If
	End Method
	
	Method SetHide(hide@)
		_hide = hide
	End Method
	
	Method GetHide@()
		If _hide Then Return True
		
		Local e:TEntity = _parent
		While e
			If e._hide Then Return True
			e = e._parent
		Wend
		
		Return False
	End Method
	
	Method Copy:TEntity(parent:TEntity = Null)
	
	End Method
	
	Method SetParent(parent:TEntity = Null, isGlobal@ = True)
		If _parent = parent Then Return
		
		Local gp:Vec2 = GetPosition(True)
		Local gr:Float = GetRotation(True)
		Local gs:Vec2 = GetScale(True)
		
		_link.Remove()
		_link = Null
		
		_parent = parent
		
		If _parent = Null
			_pos.Set(gp.x, gp.y)
			_ang = gr
			_scl.Set(gs.x, gs.y)
			_link = world.AddLast(Self)
			Return
		End If
		
		_link = _parent._childs.AddLast(Self)
		
		If isGlobal = True
			SetPosition(gp, True)
			SetRotation(gr, True)
			SetScale(gs, True)
		Else
			SetPosition(_pos, False)
			SetRotation(_ang, False)
			SetScale(_scl, False)
		End If
	End Method
	
	Method GetParent:TEntity()
		Return _parent
	End Method
	
	Method FindChild:TEntity(name$, isGlobal@ = False)
		For Local child:TEntity = EachIn _childs
			If child.name = name Then Return child
			If Not isGlobal Then Continue
			child = child.FindChild(name, True)
			If child Then Return child
		Next
	End Method
	
	Method CountChildren%()
		Return _childs.Count()
	End Method
	
	Method GetChild:TEntity(index%)
		Return TEntity(_childs.ValueAtIndex(index))
	End Method
	
	Method SetPosition(pos:Vec2, isGlobal@ = False)
		If isGlobal And _parent
			_pos.Sub(_parent.GetPosition(True))
			_pos.Div(_parent.GetScale(True))
			_pos.Rotate(Vec2.ForAngle(_parent.GetRotation(True)))
		Else
			_pos.Set(pos.x, pos.y)
		End If
		_oldx = _pos.x
		_oldy = _pos.y
	End Method
	
	Method GetPosition:Vec2(isGlobal@ = False)
		If isGlobal And _parent
			
			Local pos:Vec2 = New Vec2
			Local ent:TEntity = Self
			
			While ent
				pos.Add(ent._pos)
				If ent._parent
					pos.Mul(ent._parent._scl)
					pos.Rotate(Vec2.ForAngle(ent._parent._ang))
				End If
				ent = ent._parent
			Wend
			
			Return pos
		End If
		Return _pos.Copy()
	End Method
	
	Method SetRotation(angle#, isGlobal@ = False)
		If isGlobal And _parent
			_ang = (angle - _parent.GetRotation(True))' Mod 360
		Else
			_ang = angle' Mod 360
		End If
		_oldang = _ang
	End Method
	
	Method GetRotation#(isGlobal@ = False)
		If isGlobal And _parent
			
			Local ent:TEntity = _parent
			Local ang# = _ang
			
			While ent
				ang:+ent._ang
				ent = ent._parent
			Wend
			
			Return ang' Mod 360
		End If
		Return _ang' Mod 360
	End Method
	
	Method SetScale(scl:Vec2, isGlobal@ = False)
		If isGlobal And _parent
			_scl = _parent.GetScale(True) '.Div(scl)
			_scl.Div(scl)
		Else
			_scl.Set(scl.x, scl.y)
		End If
		_oldsx = _scl.x
		_oldsy = _scl.y
	End Method
	
	Method GetScale:Vec2(isGlobal@ = False)
		If isGlobal And _parent
			Local ent:TEntity = _parent
			Local scl:Vec2 = _scl.Copy()
			
			While ent
				scl.Mul(ent._scl)
				ent = ent._parent
			Wend
			
			Return scl
		End If
		Return _scl.Copy()
	End Method
	
	Method Distance#(target:TEntity)
		Local v:Vec2 = GetPosition(True)
		v.Sub(target.GetPosition(True))
		Return Abs(v.Length())
	End Method
	
	Method DeltaAngle#(target:TEntity)
	
	End Method
	
	Method Align(v:Vec2, m# = 1.0)
		
	End Method
	
	Method Compare%(with:Object)
		Local ent:TEntity = TEntity(with)
		
	End Method
	
	Method Move(v:Vec2)
		_oldx = _pos.x
		_oldy = _pos.y
		_pos.x:+v.x
		_pos.y:+v.y
	End Method
	
	Method Turn(angle#)
		_oldang = _ang
		_ang:+angle
	End Method
	
	Method Translate(v:Vec2)
		
	End Method
	
	Method Point(target:TEntity)
		
	End Method
	
	Method ObjectEnumerator:TListEnum()
		Return _childs.ObjectEnumerator()
	End Method
End Type
Function CreateEntity:TEntity(parent:TEntity = Null)
	Local entity:TEntity = New TEntity
	If parent Then entity.SetParent(parent)
	Return entity
End Function
Function LoadEntity:TEntity(url:Object, parent:TEntity = Null)
	add = False
	Local obj:Object = LoadObject(url)
	add = True
	
	'manager.Load(Null)
	
	Local entity:TEntity = TEntity(obj)
	
	If entity
		
		Load(entity)
		entity.SetParent(parent)
		
	Else
	
		Local list:TList = TList(obj)
		
		For entity:TEntity = EachIn list
			
			Load(entity)
			entity.SetParent(parent)
			
		Next
		
		entity = Null
		
	End If
	
	Return entity
	
	Function Load(entity:TEntity)
		If entity._path <> ""
			entity.SetClass(TLuaClass(Manager.Get(entity._path)))
		End If
		For Local a:TAspect = EachIn entity._aspects.Values()
			a.Load(entity)
		Next
		For Local child:TEntity = EachIn entity._childs
			Load(child)
		Next
		entity.Invoke("Load")
	End Function
End Function
Function SaveEntity(url:Object, entity:TEntity = Null)	
	If entity
		SaveObject(entity, url)
	Else
		SaveObject(world, url)
	End If
End Function
Function ClearWorld()
	For Local entity:TEntity = EachIn world
		entity.Free()
	Next
	world = New TList
End Function
Function UpdateWorld(capture@ = True)
	mouse.x = MouseX()
	mouse.y = MouseY()
	mouse.z = MouseZ()
	
	mouse.xspeed = MouseXSpeed()
	mouse.yspeed = MouseYSpeed()
	mouse.zspeed = MouseZSpeed()
	
	If newPick
		
		If newPick <> oldPick
			If oldPick Then oldPick.Invoke("Pick", ["-1"])
			newPick.Invoke("Pick", ["1"])
		Else
			newPick.Invoke("Pick", ["0"])
		End If
		
	End If
	oldPick = newPick
	
	cpWorld.DoStep(1.0 / 60.0)
	
	Local entity:TEntity
	
	post = New TList
	For entity = EachIn world
		UpdateEntity(entity, capture)
	Next
	
	For entity = EachIn post
		entity.Invoke("PostLoop", [String(capture)])
	Next
	
	Function UpdateEntity(entity:TEntity, capture@)
		If entity._hide Then Return
		
		If capture
			entity._oldx = entity._pos.x
			entity._oldy = entity._pos.y
			entity._oldsx = entity._scl.x
			entity._oldsy = entity._scl.y
			entity._oldang = entity._ang
		End If
		
		For Local aspect:TAspect = EachIn entity._aspects.Values()
			aspect.Loop(entity, capture)
		Next
		
		entity.Invoke("Loop", [String(capture)])
		
		For Local child:TEntity = EachIn entity._childs
			UpdateEntity(child, capture)
		Next
		
	End Function
End Function
Function RenderWorld(tween# = 1.0)
	
	Cls(black)
	
	TImage.picked = Null
	newPick = Null
	post = New TList
	
	Local entity:TEntity
	
	Matrix.Push()
	For entity = EachIn world
		Matrix.Load()
		RenderEntity(entity, tween)
	Next
	
	For entity = EachIn post
		For Local aspect:TPostDraw = EachIn entity._aspects.Values()
			Matrix.Load(aspect.Matrix)
			Exit
		Next
		entity.Invoke("PostDraw", [String(tween)])
	Next
	Matrix.Pop()
	
	Function RenderEntity(entity:TEntity, tween#)
		If entity._hide Then Return
		
		Matrix.Translate(Linear(entity._oldx, entity._pos.x, tween), ..
		Linear(entity._oldy, entity._pos.y, tween))
		Matrix.Scale(Linear(entity._oldsx, entity._scl.x, tween), ..
		Linear(entity._oldsy, entity._scl.y, tween))
		Matrix.Rotate(Linear(entity._oldang, entity._ang, tween))
		
		entity.Invoke("Draw", [String(tween)])
		
		For Local aspect:TAspect = EachIn entity._aspects.Values()
			aspect.Draw(entity, tween)
		Next
		
		For Local child:TEntity = EachIn entity._childs
			Matrix.Push()
			RenderEntity(child, tween)
			Matrix.Pop()
		Next
	End Function
End Function
Function CountChildren%(entity:TEntity = Null)
	If entity
		Return entity._childs.Count()
	Else
		Return world.Count()
	End If
End Function
Function GetChild:TEntity(index%, entity:TEntity = Null)
	If entity
		Return TEntity(entity._childs.ValueAtIndex(index))
	Else	
		Return TEntity(world.ValueAtIndex(index))
	End If
End Function
Function FindChild:TEntity(name$, entity:TEntity = Null, isGlobal@ = False)
	If entity
		Return entity.FindChild(name, isGlobal)
	Else
		For entity = EachIn world
			
		Next
	End If
End Function
 WIP Aspects.bmx:
 
 
Public
Type TAspect Abstract
	Method Load(entity:TEntity) 
	End Method
	Method Free(entity:TEntity) 
	End Method
	Method Loop(entity:TEntity, capture@) 
	End Method
	Method Draw(entity:TEntity, tween#) 
	End Method
End Type
Type TBody Extends TAspect
	'Field body:CPBody
	'Field shape:CPShape[]
	'Field shape:tlBox
	
	Method Loop(entity:TEntity, capture@)
		
	End Method
End Type
Type TMouseAspect Extends TAspect
	Method Loop(entity:TEntity, capture@)
		entity.SetPosition(Vec2.Create(MouseX(), MouseY()), True)
	End Method
End Type
Type TPostLoop Extends TAspect { single }
	Method Loop(entity:TEntity, capture@)
		post.AddLast(entity)
	End Method
End Type
Type TPostDraw Extends TAspect { single }
	Field Matrix#[6] { no_edit }
	
	Method Draw(entity:TEntity, tween#)
		MemCopy(Matrix, Varptr .Matrix.ix, 24)
		post.AddLast(entity)
	End Method
End Type
Type TLineCompare Extends TAspect
	Field xy#[]
End Type
Type TChildSorter Extends TAspect
	Method Loop(entity:TEntity, capture@)
		Local array:Object[] = entity._childs.ToArray()
		qsort(array)
		entity._childs = TList.FromArray(array)
	End Method
	
	Function qsort(array:Object[])
		
	End Function
End Type
Type TAnimator Extends TAspect
	Field keys#[]
	Field AnimSpeed#
	Field AnimTime#
	Field AnimMode@
	Field AnimFunc@
	
	Method Loop(entity:TEntity, c@)
		
	End Method
End Type
Type TSoundStreamed Extends TAspect
	Field path$
	
	
End Type
Type TSoundAspect Extends TAspect
	'Field sound:TSound 	{ no_save }
	Field path$			{ manager }
	Field flags%
	
	Method Play()
	'	PlaySound(sound)
	End Method
	
	Method Load(entity:TEntity)
	
	End Method
	
	
End Type
Type TImageAspect Extends TAspect
	Field image:TImage 	{ no_save }
	Field path$			{ manager }
	Field flags% = -1
	Field blend@ = ALPHABLEND
	Field Color#[] = white[..]
	Field pick@ = False
	
	Method Load(entity:TEntity)
		image = TImage.Load(path, flags)
		'image = TImage.Load(Manager.Get(path), flags)
	End Method
	
	Method Draw(entity:TEntity, tween#)
		SetBlend(blend)
		SetColor(Color)
		If pick Then image.pick = entity
		image.Draw()
		'newPick = TImage.picked
		If TImage.picked = entity
			'entity.Invoke("Pick")
			newPick = entity
		End If
		image.pick = Null
	End Method
End Type
Type TParticleAspect Extends TImageAspect
	
End Type
Type TTextAspect Extends TImageAspect
	Field Text$
	Field charKerning# = 0
	Field lineKerning# = 0
	
	Method Draw(entity:TEntity, tween#)
		SetBlend(blend)
		SetColor(Color)
		SetFont(image, charKerning, lineKerning)
		If pick Then image.pick = entity
		DrawText(Text)
		If TImage.picked = entity
			'entity.Invoke("Pick")
			newPick = entity
		End If
		image.pick = Null
	End Method
End Type
 
 |