
;
; Set up FSMs - Create Entities, Apply Textures and Set Up Collision Parameters
;

Global g_planhigh = LoadSprite("plan_high.tga", 3)
Global g_coregrid = LoadTexture("gridSphe.tga", 3)

Function LoadPlanets()
	Restore planetData
	
	parent.Planet = Null
	id% = 0

	Repeat
		Read moon% : If moon = -1 Then Return
		Read name$, radius#, dist#, period#, incl#, tilt#, modelortexture$, skytex$, ringtex$
		
		p.Planet 	= New Planet
		p\parent	= Null
		p\name   	= name
		p\radius 	= radius/1000.0
		p\distance	= dist
		p\period 	= period
		p\tilt   	= tilt
		
		If moon <> 1 Then
			parent = p
			id = id + 1
			
			p\orbpivot 	= CreatePivot()	; at origin
		Else ; it's a moon
			p\parent   	= parent
			p\radius	= 2 * p\radius
			p\distance	= parent\radius * 4.0 + dist * 20
			
			p\orbpivot 	= CreatePivot(parent\moonpivot)
		EndIf
		p\moonpivot = CreatePivot(p\orbpivot)
		p\ringpivot = CreatePivot(p\orbpivot)
		p\campivot  = CreatePivot(p\orbpivot)
		
		p\id = id
		
		DebugLog name + " radius: " + p\radius + " dist: " + p\distance
		
		IntroText "Loading " + name + "..." ;+ "(" + id + ")..."
		
		If Right$(modelortexture, 2) = ".x" Then	; it's a .x file (assume a name.jpg texture)
			p\model = LoadMesh(modelortexture, p\orbpivot)
			FitMesh p\model, -1,-1,-1, 2,2,2, True		; make it diameter 2 (i.e. radius 1)
			modelortexture = Left(modelortexture, Len(modelortexture)-2) + ".jpg"
		Else										; it's a texture
			If moon = -2 Then	; special case, sun's always visible, use less polygons
				p\model = CreateSphere(8, p\orbpivot)
			Else
				p\model = CreateSphere(32, p\orbpivot)
			EndIf
		EndIf
		p\surfacetex = LoadTexture(modelortexture)
		EntityTexture p\model, p\surfacetex

		ScaleEntity p\model, p\radius, p\radius, p\radius
		
		If skytex <> "" Then
			p\sky = CreateSphere(32, p\model)
			If Right$(modelortexture, 4) = ".tga" Then
				p\skytex = LoadTexture(skytex, ALPHAMAP_FLAG)
			Else
				p\skytex = LoadTexture(skytex)
			EndIf
			EntityTexture p\sky, p\skytex
			ScaleEntity p\sky, 1.03, 1.03, 1.03
		EndIf
		
		If ringtex <> "" Then EntityParent RingSystem(ringtex, p\radius * 1.5, p\radius * 3.0, 0, 360, 80), p\ringpivot
		
		p\sprite = LoadSprite("sprites128px\sp_" + name + ".tga", ALPHAMAP_FLAG)
		If p\sprite Then EntityAlpha p\sprite,0.8
		
		PositionEntity p\model,		0, 0, p\distance		; space planet from sun
		PositionEntity p\moonpivot, 0, 0, p\distance		; place pivot in planet
		PositionEntity p\ringpivot, 0, 0, p\distance		; place pivot in planet
		PositionEntity p\campivot,  0, 0, p\distance		; place pivot in planet
		RotateEntity   p\orbpivot,  incl,	0, 0, True		; apply orbital incline (we're using Z axis for time too)
		RotateEntity   p\model,		tilt,	0, 0, True		; apply axial tilt
		
		RotateEntity   p\campivot,	0, 0, 0, True			; negate axial tilt
		
		TurnEntity p\orbpivot,	0, p\id * 20 + Rand(5,10), 0
		
		;;	p\orbit = Create3DCircle() ??
		;show_normals(p\model)
		
		p\flipped = False
		p\visited = False
		HidePlanet(p)

		If minimode = True And p\id > g_mini_id Then Return
	Forever
End Function

Function FindPlanet.Planet(name$)
	For p.Planet = Each Planet
		If p\name = name Then Return p
	Next
	Return Null
End Function

Function LookupPlanet.Planet(id%)
	For p.planet = Each planet
		If p\id = id Then Return p
	Next
	Return Null
End Function

Function MatchPlanet.Planet(model)
	For p.Planet = Each Planet
		If p\model = model Then	Return p
	Next
	Return Null
End Function

Function RandomPlanet.Planet()
	SeedRnd(MilliSecs())
	Repeat
		For p.Planet = Each Planet
			If p <> sol And Rand(1,1000) > 950 Then Return p
		Next
	Forever
End Function

Function SameSystem(p1.Planet, p2.planet)
	If p1 = Null Or p2 = Null Then						Return False	; if not given two planets to compare
	If p1 = p2 Then										Return True		; same place...
	If p1\parent = Null And p2\parent = Null Then 		Return False	; if neither has a parent (2 planets)
	If p1\parent = p2\parent Then						Return True		; if they have the same parent (2 moons)
	If p1\parent <> Null And p1\parent = p2 Then		Return True		; if one's parent is the other (planet & moon)
	If p2\parent <> Null And p2\parent = p1 Then		Return True		; if one's parent is the other (planet & moon)
	Return False														; any other case
End Function

Function ShowPlanet(p.Planet)
	ShowEntity p\model
	ShowEntity p\ringpivot
End Function

Function HidePlanet(p.Planet)
	HideEntity p\model
	HideEntity p\ringpivot
End Function

Function UpdatePlanet(p.Planet)
	If p <> sol Then
		; earth completes one orbit in g_orbspd sec
		degreesperframe# = (360.0 / (g_orbspd * c_gameRate)) * (365.0 / p\period)
		TurnEntity p\orbpivot,0,degreesperframe,0
		
		If p <> archer\loc Or archer\state = AT_ORBIT Then
			;TurnEntity p\model, 0, 0.1, 0						; axial rotation
		EndIf
		
		p\camdist# = Abs(EntityDistance(cam, p\model))
		
		If SameSystem(p, archer\loc) Then
			ShowPlanet(p)
		Else
			HidePlanet(p)
		EndIf
	EndIf
	
	If archer\state <> AT_CORE
		If p\flipped = True Then
			FlipMesh p\model : p\flipped = False
		EndIf
		EntityAlpha p\model,1		; remove transparency
		EntityFX p\model,0			; restore planet shading (normals work OK from the outside)
	EndIf
	
	If p\sprite <> 0 Then
		HideEntity p\sprite
		
		If archer\state = AT_SPACE Then	; draw helixes
			If p\visited = True Then p\ticks = p\ticks + 1
			If Float(p\ticks) > Sqr(p\distance) Then
				p\ticks = 0
				maxticks# = 10*p\id + 20*(p\id > 4)
				pt.Particle = MakeParticle.Particle(p\sprite, "helix", 0, maxticks, 0, -1, 0, p\model)
				
				;scale sprites according to actual radius
				size = 8 + 4 * p\id : ScaleSprite pt\entity,size,size
			EndIf
		ElseIf p <> archer\loc Then				; display other planets' target sprites
			ScaleSprite p\sprite,sprdist/10,sprdist/10
			ShowEntity p\sprite
			
			MoveToEntity(p\sprite, archer\arrow)
			
			PointEntity p\sprite,p\model
			MoveEntity p\sprite,0,0,sprdist
			EntityOrder p\sprite,50 + p\id		; increasing values -> draw behind
		EndIf
	ElseIf archer\state = AT_SPACE		; draw pixel helixes
		If p\visited = True Then
			;pt.Particle = MakePixel.Particle(100, 100, 200, "helix", 10, 0, -1, 0, p\model)
		EndIf
	EndIf
End Function

; Ring System Generator Ported From Celestia
Function RingSystem(texname$, innerRadius#, outerRadius#, beginAngle#, endAngle#, nSections%, doublesided=True)
	mesh = CreateMesh()
	surf = CreateSurface(mesh)
	texture = LoadTexture(texname, 1+2)
	
    angle# = endAngle - beginAngle

	; Establish starting vertices
	v0 = AddVertex(surf,  Cos(beginAngle) * innerRadius, 0, Sin(beginAngle) * innerRadius,  0, 0.5, 0)
	v1 = AddVertex(surf,  Cos(beginAngle) * outerRadius, 0, Sin(beginAngle) * outerRadius,  1, 0.5, 0)

	For i = 0 To nSections Step 1
		t# = Float(i) / nSections
		theta# = beginAngle + t * angle
        s# = Sin(theta) : c# = Cos(theta)

		; v1  v3  v5  ..   quad strip triangles would be (v0, v1, v3),
		; v0  v2  v4  ..   (v0, v3, v2), (v2, v3, v5), (v2, v3, v4)...

		v2 = AddVertex(surf,  c * innerRadius, 0, s * innerRadius,   0, 0.5, 0)
		v3 = AddVertex(surf,  c * outerRadius, 0, s * outerRadius,   1, 0.5, 0)

		; clockwise
		AddTriangle(surf, v0, v1, v3)
		AddTriangle(surf, v0, v3, v2)
		
		If doublesided = True Then
			; and counterclockwise
			AddTriangle(surf, v0, v3, v1)
			AddTriangle(surf, v0, v2, v3)
		EndIf
		
		v0 = v2 : v1 = v3
    Next

	EntityTexture mesh,texture
	EntityFX mesh,2
	LightMesh mesh,255,255,255,50,-20,-20,-20
	LightMesh mesh,255,255,255,50,20,20,20
	
	Return mesh
End Function