//============================================================
// Program:		CGFSolarSystem
// Description:	Solar System Class
// Author:		Benjamin Gottemoller
// Website:		http://www.particlefield.com
// Date:		who knows
// Legal:		Licensed under the gnu GPL (see gpl.txt for details)
//============================================================

#include "GameFrameSolarSystem.h"
#include "GameFrameSmartLoader.h"
#include "GameFrame.h"

CGFSolarSystem::CGFSolarSystem()
{
	GFParent = NULL;
	Camera = NULL;
	IsGravityActive = 0;
	IsLightingActive = 0;
	IsBackgroundActive = 0;
	memset(&Background, 0, sizeof(BACKGROUND));

	NumPlanets = 0;
	NumPlanetsUsed = 0;
	Planets = NULL;

	NumSuns = 0;
	NumSunsUsed = 0;
	Suns = NULL;
}

CGFSolarSystem::~CGFSolarSystem()
{
	Destroy();
}

void CGFSolarSystem::Initialize(GameFrame *gfparent, CGFCamera *camera)
{
	int i = 0;

	GFParent = gfparent;
	Camera = camera;
	IsGravityActive = 0;
	IsLightingActive = 0;
	IsBackgroundActive = 0;

	NumPlanets = 50;
	NumPlanetsUsed = 0;
	Planets = new PLANET[NumPlanets];

	NumSuns = 5;
	NumSunsUsed = 0;
	Suns = new SUN[NumSuns];

	for(i=0; i<NumPlanets; i++)
	{
		memset(&(Planets[i]), 0, sizeof(PLANET));
	}

	for(i=0; i<NumSuns; i++)
	{
		memset(&(Suns[i]), 0, sizeof(SUN));
	}
}

void CGFSolarSystem::SetBackgroundUniverse(BACKGROUND *background)
{
	IsBackgroundActive = 1;
	memcpy(&Background, background, sizeof(BACKGROUND));
}

int CGFSolarSystem::AddPlanet(PLANET *planet)
{
	int result = -1;
	if((NumPlanets <= 0) || (Planets == NULL) || (GFParent == NULL) || (planet == NULL)) return -1;

	if(NumPlanetsUsed >= NumPlanets)
	{
		int i = 0;
		PLANET *tmp = NULL;
		tmp = new PLANET[NumPlanets * 2];
		if(tmp == NULL) return -1;

		for(i=0; i<NumPlanets; i++)
		{
			memcpy(&(tmp[i]), &(Planets[i]), sizeof(PLANET));
		}

		for(i=NumPlanets; i<(NumPlanets * 2); i++)
		{
			memset(&(tmp[i]), 0, sizeof(PLANET));
		}

		delete[] Planets;
		Planets = tmp;
		tmp = NULL;
		NumPlanets *= 2;
	}

	memcpy(&(Planets[NumPlanetsUsed]), planet, sizeof(PLANET));
	Planets[NumPlanetsUsed].IsActive = 1;
	Planets[NumPlanetsUsed].PlanetRadius = GFParent->ObjectLib[Planets[NumPlanetsUsed].PlanetObjectIndex]->Radius;
	Planets[NumPlanetsUsed].AtmosphereRadius = GFParent->ObjectLib[Planets[NumPlanetsUsed].AtmosphereObjectIndex]->Radius;
	
	result = 1;
	NumPlanetsUsed++;

	return result;
}

int CGFSolarSystem::AddSun(SUN *sun)
{
	int result = -1;
	if((NumSuns <= 0) || (Suns == NULL) || (GFParent == NULL) || (sun == NULL)) return -1;

	if(NumSunsUsed >= NumSuns)
	{
		int i = 0;
		SUN *tmp = NULL;
		tmp = new SUN[NumSuns * 2];
		if(tmp == NULL) return -1;

		for(i=0; i<NumSuns; i++)
		{
			memcpy(&(tmp[i]), &(Suns[i]), sizeof(SUN));
		}

		for(i=NumSuns; i<(NumSuns * 2); i++)
		{
			memset(&(tmp[i]), 0, sizeof(SUN));
		}

		delete[] Suns;
		Suns = tmp;
		tmp = NULL;
		NumSuns *= 2;
	}

	memcpy(&(Suns[NumSunsUsed]), sun, sizeof(SUN));
	Suns[NumSunsUsed].IsActive = 1;
	Suns[NumSunsUsed].SunRadius = GFParent->ObjectLib[Suns[NumSunsUsed].SunObjectIndex]->Radius;

    Suns[NumSunsUsed].Light.Type		= D3DLIGHT_POINT;
	Suns[NumSunsUsed].Light.Range		= 1.8E18f;
	Suns[NumSunsUsed].Light.Position	= D3DXVECTOR3(Suns[NumSunsUsed].X, Suns[NumSunsUsed].Y, Suns[NumSunsUsed].Z);

	result = 1;
	NumSunsUsed++;

	return result;
}

int CGFSolarSystem::LoadSolarSystem(char *file)
{
	FILE *fp = NULL;
	int SunCount = 0;
	int PlanetCount = 0;
	int GenerateOrbits = 0;
	char background_file[MAX_PATH];
	BACKGROUND tmp_back;
	SUN *tmp_suns = NULL;
	PLANET *tmp_planets;
	DATA_FILES *sun_files;
	DATA_FILES *planet_files;
	list<int> tmp;
	int i = 0;
	D3DMATERIAL8 material;

	memset(&tmp_back, 0, sizeof(BACKGROUND));

	fp = fopen(file, "rt");
	if(fp != NULL)
	{
		fscanf(fp, "GeneratePlanetaryOrbits: %d\n", &GenerateOrbits);
		fscanf(fp, "IsGravityActive: %d\n", &IsGravityActive);
		fscanf(fp, "SunCount: %d\n", &SunCount);
		fscanf(fp, "PlanetCount: %d\n\n", &PlanetCount);
		
		fscanf(fp, "BackgroundFile: %s\n", background_file);
		fscanf(fp, "Yaw: %f\n", &(tmp_back.BackgroundData.Yaw));
		fscanf(fp, "Pitch: %f\n", &(tmp_back.BackgroundData.Pitch));
		fscanf(fp, "Roll: %f\n", &(tmp_back.BackgroundData.Roll));
		fscanf(fp, "YawVec: %f\n", &(tmp_back.BackgroundData.YawVec));
		fscanf(fp, "PitchVec: %f\n", &(tmp_back.BackgroundData.PitchVec));
		fscanf(fp, "RollVec: %f\n\n", &(tmp_back.BackgroundData.RollVec));

		tmp_suns = new SUN[SunCount];
		sun_files = new DATA_FILES[SunCount];
		tmp_planets = new PLANET[PlanetCount];
		planet_files = new DATA_FILES[PlanetCount];

		for(i=0; i<SunCount; i++)
		{
			memset(&(tmp_suns[i]), 0, sizeof(SUN));
			tmp_suns[i].Light.Type		= D3DLIGHT_POINT;
			tmp_suns[i].Light.Range		= 1.8E18f;
			tmp_suns[i].Light.Position	= D3DXVECTOR3(0, 0, 0); 
			
			fscanf(fp, "SunBodyFile: %s\n", (sun_files[i].Body));
			fscanf(fp, "SunAtmosphereFile: %s\n", (sun_files[i].Atmosphere));
			fscanf(fp, "DiffuseLightRGBA: %f, %f, %f, %f\n", 
				   &(tmp_suns[i].Light.Diffuse.r), &(tmp_suns[i].Light.Diffuse.g), 
				   &(tmp_suns[i].Light.Diffuse.b), &(tmp_suns[i].Light.Diffuse.a));
			fscanf(fp, "Mass: %f\n", &(tmp_suns[i].Mass));
			fscanf(fp, "X: %f\n", &(tmp_suns[i].X));
			fscanf(fp, "Y: %f\n", &(tmp_suns[i].Y));
			fscanf(fp, "Z: %f\n", &(tmp_suns[i].Z));
			fscanf(fp, "XVec: %f\n", &(tmp_suns[i].XVec));
			fscanf(fp, "YVec: %f\n", &(tmp_suns[i].YVec));
			fscanf(fp, "ZVec: %f\n", &(tmp_suns[i].ZVec));
			fscanf(fp, "BodyYaw: %f\n", &(tmp_suns[i].SunData.Yaw));
			fscanf(fp, "BodyPitch: %f\n", &(tmp_suns[i].SunData.Pitch));
			fscanf(fp, "BodyRoll: %f\n", &(tmp_suns[i].SunData.Roll));
			fscanf(fp, "BodyYawVec: %f\n", &(tmp_suns[i].SunData.YawVec));
			fscanf(fp, "BodyPitchVec: %f\n", &(tmp_suns[i].SunData.PitchVec));
			fscanf(fp, "BodyRollVec: %f\n", &(tmp_suns[i].SunData.RollVec));
			fscanf(fp, "AtmosphereYaw: %f\n", &(tmp_suns[i].AtmosphereData.Yaw));
			fscanf(fp, "AtmospherePitch: %f\n", &(tmp_suns[i].AtmosphereData.Pitch));
			fscanf(fp, "AtmosphereRoll: %f\n", &(tmp_suns[i].AtmosphereData.Roll));
			fscanf(fp, "AtmosphereYawVec: %f\n", &(tmp_suns[i].AtmosphereData.YawVec));
			fscanf(fp, "AtmospherePitchVec: %f\n", &(tmp_suns[i].AtmosphereData.PitchVec));
			fscanf(fp, "AtmosphereRollVec: %f\n", &(tmp_suns[i].AtmosphereData.RollVec));
			fscanf(fp, "Flags: %d\n", &(tmp_suns[i].Flags));
			fscanf(fp, "Extra1: %f\n", &(tmp_suns[i].Extra1));
			fscanf(fp, "Extra2: %f\n", &(tmp_suns[i].Extra2));
			fscanf(fp, "Extra3: %f\n\n", &(tmp_suns[i].Extra3));
		}
		
		for(i=0; i<PlanetCount; i++)
		{
			memset(&(tmp_planets[i]), 0, sizeof(PLANET));
			memset(&material, 0, sizeof(D3DMATERIAL8));

			fscanf(fp, "PlanetBodyFile: %s\n", (planet_files[i].Body));
			fscanf(fp, "PlanetAtmosphereFile: %s\n", (planet_files[i].Atmosphere));
			fscanf(fp, "DiffuseMaterialRGBA: %f, %f, %f, %f\n", 
				   &(material.Diffuse.r), &(material.Diffuse.g), 
				   &(material.Diffuse.b), &(material.Diffuse.a));
			fscanf(fp, "AmbientMaterialRGBA: %f, %f, %f, %f\n", 
				   &(material.Ambient.r), &(material.Ambient.g), 
				   &(material.Ambient.b), &(material.Ambient.a));
			fscanf(fp, "Life: %f\n", &(tmp_planets[i].Life));
			fscanf(fp, "Mass: %f\n", &(tmp_planets[i].Mass));
			fscanf(fp, "X: %f\n", &(tmp_planets[i].X));
			fscanf(fp, "Y: %f\n", &(tmp_planets[i].Y));
			fscanf(fp, "Z: %f\n", &(tmp_planets[i].Z));
			fscanf(fp, "XVec: %f\n", &(tmp_planets[i].XVec));
			fscanf(fp, "YVec: %f\n", &(tmp_planets[i].YVec));
			fscanf(fp, "ZVec: %f\n", &(tmp_planets[i].ZVec));
			fscanf(fp, "BodyYaw: %f\n", &(tmp_planets[i].PlanetData.Yaw));
			fscanf(fp, "BodyPitch: %f\n", &(tmp_planets[i].PlanetData.Pitch));
			fscanf(fp, "BodyRoll: %f\n", &(tmp_planets[i].PlanetData.Roll));
			fscanf(fp, "BodyYawVec: %f\n", &(tmp_planets[i].PlanetData.YawVec));
			fscanf(fp, "BodyPitchVec: %f\n", &(tmp_planets[i].PlanetData.PitchVec));
			fscanf(fp, "BodyRollVec: %f\n", &(tmp_planets[i].PlanetData.RollVec));
			fscanf(fp, "AtmosphereYaw: %f\n", &(tmp_planets[i].AtmosphereData.Yaw));
			fscanf(fp, "AtmospherePitch: %f\n", &(tmp_planets[i].AtmosphereData.Pitch));
			fscanf(fp, "AtmosphereRoll: %f\n", &(tmp_planets[i].AtmosphereData.Roll));
			fscanf(fp, "AtmosphereYawVec: %f\n", &(tmp_planets[i].AtmosphereData.YawVec));
			fscanf(fp, "AtmospherePitchVec: %f\n", &(tmp_planets[i].AtmosphereData.PitchVec));
			fscanf(fp, "AtmosphereRollVec: %f\n", &(tmp_planets[i].AtmosphereData.RollVec));
			fscanf(fp, "Flags: %d\n", &(tmp_planets[i].Flags));
			fscanf(fp, "Extra1: %f\n", &(tmp_planets[i].Extra1));
			fscanf(fp, "Extra2: %f\n", &(tmp_planets[i].Extra2));
			fscanf(fp, "Extra3: %f\n\n", &(tmp_planets[i].Extra3));

			tmp_planets[i].MaterialLibIndex = GFParent->MaterialLib.AddMaterial(&material);
		}
		fclose(fp);
		
		GFParent->SmartLoader.EnqueueModelFile(background_file);
		if(GFParent->TextureLib.IsCompressionEnabled())
		{
			GFParent->TextureLib.EnableTextureCompression(0);
			GFParent->SmartLoader.ProcessModelQueue(GFParent, 20000);
			GFParent->TextureLib.EnableTextureCompression(1);
		}
		else
		{
			GFParent->SmartLoader.ProcessModelQueue(GFParent, 20000);
		}
		GFParent->SmartLoader.DequeProcessedIndices(&tmp);
		tmp_back.BackgroundObjectIndex = tmp.front();
		SetBackgroundUniverse(&tmp_back);

		for(i=0; i<SunCount; i++)
		{
			GFParent->SmartLoader.EnqueueModelFile(sun_files[i].Body);
			GFParent->SmartLoader.EnqueueModelFile(sun_files[i].Atmosphere);
		}

		for(i=0; i<PlanetCount; i++)
		{
			GFParent->SmartLoader.EnqueueModelFile(planet_files[i].Body);
			GFParent->SmartLoader.EnqueueModelFile(planet_files[i].Atmosphere);
		}

		GFParent->SmartLoader.ProcessModelQueue(GFParent, 20000);

		for(i=0; i<SunCount; i++)
		{
			GFParent->SmartLoader.DequeProcessedIndices(&tmp);
			tmp_suns[i].SunObjectIndex = tmp.front();

			GFParent->SmartLoader.DequeProcessedIndices(&tmp);
			tmp_suns[i].AtmosphereObjectIndex = tmp.front();

			AddSun(&(tmp_suns[i]));
		}

		for(i=0; i<PlanetCount; i++)
		{
			GFParent->SmartLoader.DequeProcessedIndices(&tmp);
			tmp_planets[i].PlanetObjectIndex = tmp.front();

			GFParent->SmartLoader.DequeProcessedIndices(&tmp);
			tmp_planets[i].AtmosphereObjectIndex = tmp.front();

			AddPlanet(&(tmp_planets[i]));
		}

		if(GenerateOrbits)
		{
			float start_radius = Suns[0].SunRadius + 1000.0f;
			float orbit_radius = 0;
			float velocity = 0;
			float angle = 0;

			for(i=0; i<PlanetCount; i++)
			{
				orbit_radius = start_radius + (float)(rand()%20000);
				velocity = (float)sqrt((Gc * Suns[0].Mass) / orbit_radius);
				
				Planets[i].X = orbit_radius * (float)cos(angle);
				Planets[i].Y = 0;
				Planets[i].Z = orbit_radius * (float)sin(angle);

				Planets[i].XVec = velocity * (float)sin(angle);
				Planets[i].YVec = 0;
				Planets[i].ZVec = velocity * (float)cos(angle);

				angle += (2 * PI) / 9.0f;
			}
		}

		SAFE_DELETE_ARRAY(tmp_suns);
		SAFE_DELETE_ARRAY(sun_files);
		SAFE_DELETE_ARRAY(tmp_planets);
		SAFE_DELETE_ARRAY(planet_files);
	}

	return 1;
}

void CGFSolarSystem::ScaleSolarSystem(float factor)
{
	if(factor == 0) return;
	int i = 0;

	for(i=0; i<NumSuns; i++)
	{
		Suns[i].Mass /= factor;
		Suns[i].X /= factor;
		Suns[i].Y /= factor;
		Suns[i].Z /= factor;
	}

	for(i=0; i<NumPlanets; i++)
	{
		Planets[i].Mass /= factor;
		Planets[i].X /= factor;
		Planets[i].Y /= factor;
		Planets[i].Z /= factor;
	}	
}

void CGFSolarSystem::Destroy(void)
{
	GFParent = NULL;
	Camera = NULL;
	
	NumPlanets = 0;
	NumPlanetsUsed = 0;
	SAFE_DELETE_ARRAY(Planets);

	NumSuns = 0;
	NumSunsUsed = 0;
	SAFE_DELETE_ARRAY(Suns);
}

void CGFSolarSystem::Update(void)
{
	if(GFParent->IsGamePaused || GFParent->IsGameLocked) return;
	int i = 0;
	float scalar = GFParent->GetTimeDiff();

	for(i=0; i<NumPlanetsUsed; i++)
	{
		Planets[i].X	+= Planets[i].XVec * scalar;
		Planets[i].Y	+= Planets[i].YVec * scalar;
		Planets[i].Z	+= Planets[i].ZVec * scalar;

		Planets[i].PlanetData.Roll			+= Planets[i].PlanetData.RollVec * scalar;
		Planets[i].PlanetData.Pitch			+= Planets[i].PlanetData.PitchVec * scalar;
		Planets[i].PlanetData.Yaw			+= Planets[i].PlanetData.YawVec * scalar;

		Planets[i].AtmosphereData.Roll		+= Planets[i].AtmosphereData.RollVec * scalar;
		Planets[i].AtmosphereData.Pitch		+= Planets[i].AtmosphereData.PitchVec * scalar;
		Planets[i].AtmosphereData.Yaw		+= Planets[i].AtmosphereData.YawVec * scalar;

		if(Planets[i].Modifier != NULL)
		{
			Planets[i].Modifier(&(Planets[i]), GFParent, Camera);
		}
	}

	for(i=0; i<NumSunsUsed; i++)
	{
		Suns[i].X		+= Suns[i].XVec * scalar;
		Suns[i].Y		+= Suns[i].YVec * scalar;
		Suns[i].Z		+= Suns[i].ZVec * scalar;

		Suns[i].SunData.Roll				+= Suns[i].SunData.RollVec * scalar;
		Suns[i].SunData.Pitch				+= Suns[i].SunData.PitchVec * scalar;
		Suns[i].SunData.Yaw					+= Suns[i].SunData.YawVec * scalar;

		Suns[i].AtmosphereData.Roll			+= Suns[i].AtmosphereData.RollVec * scalar;
		Suns[i].AtmosphereData.Pitch		+= Suns[i].AtmosphereData.PitchVec * scalar;
		Suns[i].AtmosphereData.Yaw			+= Suns[i].AtmosphereData.YawVec * scalar;
		
		Suns[i].Light.Position.x = Suns[i].X;
		Suns[i].Light.Position.y = Suns[i].Y;
		Suns[i].Light.Position.z = Suns[i].Z;

		if(Suns[i].Modifier != NULL)
		{
			Suns[i].Modifier(&(Suns[i]), GFParent, Camera);
		}
	}

	if(IsBackgroundActive)
	{
		Background.BackgroundData.Yaw += Background.BackgroundData.YawVec * scalar;
		Background.BackgroundData.Pitch += Background.BackgroundData.PitchVec * scalar;
		Background.BackgroundData.Roll += Background.BackgroundData.RollVec * scalar;

		if(Background.Modifier != NULL)
		{
			Background.Modifier(&Background, GFParent, Camera);
		}
	}

	if(IsGravityActive)
	{
		D3DXVECTOR3 v;
		double distsq = 0;
		double force = 0;
		double accel = 0;
		double limit = 0;

		for(int i=0; i<NumPlanetsUsed; i++)	//i = current planet 
		{
			for(int j=0; j<NumPlanetsUsed; j++)
			{
				if(j != i)
				{
					v.x = Planets[j].X - Planets[i].X;
					v.y = Planets[j].Y - Planets[i].Y;
					v.z = Planets[j].Z - Planets[i].Z;
					distsq = (double) D3DXVec3LengthSq(&v);
				
					limit = (Planets[i].PlanetRadius + Planets[j].PlanetRadius);
					limit *= limit;

					if(ABS(distsq) > limit)
					{
						force = Gc * (Planets[i].Mass * Planets[j].Mass) / distsq;
						D3DXVec3Normalize(&v, &v);
											
						accel = scalar * force / Planets[i].Mass;
						Planets[i].XVec += v.x * (float)accel;
						Planets[i].YVec += v.y * (float)accel;
						Planets[i].ZVec += v.z * (float)accel;
					}
				}
			}
		}

		for(int i=0; i<NumSunsUsed; i++)	//i = current sun 
		{
			for(int j=0; j<NumSunsUsed; j++)
			{
				if(i != j)
				{
					v.x = Suns[j].X - Suns[i].X;
					v.y = Suns[j].Y - Suns[i].Y;
					v.z = Suns[j].Z - Suns[i].Z;
					distsq = (double) D3DXVec3LengthSq(&v);
				
					limit = (Suns[i].SunRadius + Suns[j].SunRadius);
					limit *= limit;

					if(ABS(distsq) > limit)
					{
						force = Gc * (Suns[i].Mass * Suns[j].Mass) / distsq;
						D3DXVec3Normalize(&v, &v);
						
						accel = scalar * force / Suns[i].Mass;
						Suns[i].XVec += v.x * (float)accel;
						Suns[i].YVec += v.y * (float)accel;
						Suns[i].ZVec += v.z * (float)accel;
					}
				}
			}
		}

		for(int i=0; i<NumPlanetsUsed; i++) 
		{
			for(int j=0; j<NumSunsUsed; j++)
			{
				v.x = Suns[j].X - Planets[i].X;
				v.y = Suns[j].Y - Planets[i].Y;
				v.z = Suns[j].Z - Planets[i].Z;
				distsq = (double) D3DXVec3LengthSq(&v);
			
				limit = (Planets[i].PlanetRadius + Suns[j].SunRadius);
				limit *= limit;

				if(ABS(distsq) > limit)
				{
					force = Gc * (Planets[i].Mass * Suns[j].Mass) / distsq;
					D3DXVec3Normalize(&v, &v);
				
					accel = scalar * force / Planets[i].Mass;
					Planets[i].XVec += v.x * (float)accel;
					Planets[i].YVec += v.y * (float)accel;
					Planets[i].ZVec += v.z * (float)accel;

					accel = scalar * force / Suns[j].Mass;
					Suns[j].XVec -= v.x * (float)accel;
					Suns[j].YVec -= v.y * (float)accel;
					Suns[j].ZVec -= v.z * (float)accel;
				}
			}
		}
	}

}

void CGFSolarSystem::Render(D3DXMATRIX *modifier)
{
	if((NumSuns <= 0) || (Suns == NULL) || (NumPlanets <= 0) || (Planets == NULL) || (GFParent == NULL)) return;
	if(GFParent->IsGameLocked) return;

	int i = 0;
	int last_vlib_index = 0;

	D3DXVECTOR3 Up_Vector; 
	D3DXVECTOR3 Right_Vector; 
	D3DXVECTOR3 Look_Vector;

	D3DXMATRIX YawMat, PitchMat, RollMat;
	D3DXMATRIX TransMat;
	D3DXMATRIX WorldMat;

	if(IsBackgroundActive)
	{
		Up_Vector = D3DXVECTOR3(0,1,0);
		Right_Vector = D3DXVECTOR3(1,0,0);
		Look_Vector = D3DXVECTOR3(0,0,1);

		D3DXMatrixRotationAxis(&YawMat, &Up_Vector, Background.BackgroundData.Yaw);
		D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &YawMat);
		D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &YawMat);

		D3DXMatrixRotationAxis(&PitchMat, &Right_Vector, Background.BackgroundData.Pitch);
		D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &PitchMat);
		D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &PitchMat);

		D3DXMatrixRotationAxis(&RollMat, &Look_Vector, Background.BackgroundData.Roll);
		D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &RollMat);
		D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &RollMat);

		D3DXMatrixTranslation(&TransMat, Camera->X, Camera->Y, Camera->Z);
		D3DXMatrixIdentity(&WorldMat);

		D3DXMatrixMultiply(&WorldMat, &RollMat, &TransMat);
		D3DXMatrixMultiply(&WorldMat, &PitchMat, &WorldMat);
		D3DXMatrixMultiply(&WorldMat, &YawMat, &WorldMat);

		const OBJNODE *tmp_node = GFParent->ObjectLib[Background.BackgroundObjectIndex];
		int index = tmp_node->VertexLibraryIndex;
	
		GFParent->D3DDevice->SetStreamSource(0, GFParent->VertexLib[index], GFParent->VertexLib.GetSize(index));
		GFParent->D3DDevice->SetVertexShader(GFParent->VertexLib.GetFVF(index));
		
		GFParent->D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat);

		index = tmp_node->TextureLibraryIndex;
		if(index != -1)
		{
			GFParent->D3DDevice->SetTexture(0, GFParent->TextureLib[index]);
		}

		GFParent->D3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE);
		GFParent->D3DDevice->DrawPrimitive(tmp_node->PrimitiveType, tmp_node->StartVertex, tmp_node->PrimitiveCount);
		GFParent->D3DDevice->SetRenderState( D3DRS_ZENABLE, TRUE);

		GFParent->D3DDevice->SetTexture(0, NULL);
	}		

	GFParent->D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	/****************Render Suns*******************************************/
	for(i=0; i<NumSunsUsed; i++)
	{
		if(Suns[i].IsActive)
		{
			Up_Vector = D3DXVECTOR3(0,1,0);
			Right_Vector = D3DXVECTOR3(1,0,0);
			Look_Vector = D3DXVECTOR3(0,0,1);

			D3DXMatrixRotationAxis(&YawMat, &Up_Vector, Suns[i].SunData.Yaw);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &YawMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &YawMat);

			D3DXMatrixRotationAxis(&PitchMat, &Right_Vector, Suns[i].SunData.Pitch);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &PitchMat);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &PitchMat);

			D3DXMatrixRotationAxis(&RollMat, &Look_Vector, Suns[i].SunData.Roll);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &RollMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &RollMat);

			D3DXMatrixTranslation(&TransMat, Suns[i].X, Suns[i].Y, Suns[i].Z);

			D3DXMatrixIdentity(&WorldMat);
			D3DXMatrixMultiply(&WorldMat, &RollMat, &TransMat);
			D3DXMatrixMultiply(&WorldMat, &PitchMat, &WorldMat);
			D3DXMatrixMultiply(&WorldMat, &YawMat, &WorldMat);

			if(modifier != NULL) D3DXMatrixMultiply(&WorldMat, &WorldMat, modifier);

			const OBJNODE *tmp_node = GFParent->ObjectLib[Suns[i].SunObjectIndex];
			int index = tmp_node->VertexLibraryIndex;
			
			if(last_vlib_index != index)
			{
				GFParent->D3DDevice->SetStreamSource(0, GFParent->VertexLib[index], GFParent->VertexLib.GetSize(index));
				GFParent->D3DDevice->SetVertexShader(GFParent->VertexLib.GetFVF(index));
				last_vlib_index = index;	
			}

			GFParent->D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat);

			/*********Each Sun Object Must Be EXACTLY one mesh item*******/
			tmp_node = GFParent->ObjectLib[Suns[i].SunObjectIndex];
			index = tmp_node->TextureLibraryIndex;
			if(index != -1)
			{
				GFParent->D3DDevice->SetTexture(0, GFParent->TextureLib[index]);
			}
			
			GFParent->D3DDevice->DrawPrimitive(tmp_node->PrimitiveType, tmp_node->StartVertex, tmp_node->PrimitiveCount);
			GFParent->D3DDevice->SetTexture(0, NULL);
		}
	}

	if(IsLightingActive && GFParent->IsLightingEnabled)
	{
		GFParent->D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

		for(i=0; i<NumSunsUsed; i++)
		{
			if(Suns[i].IsActive)
			{
				GFParent->D3DDevice->SetLight(i, &(Suns[i].Light));
				GFParent->D3DDevice->LightEnable(i, TRUE);
			}
		}
	}
	
	/****************Render Planets*******************************************/
	for(i=0; i<NumPlanetsUsed; i++)
	{
		if(Planets[i].IsActive)
		{

			Up_Vector = D3DXVECTOR3(0,1,0);
			Right_Vector = D3DXVECTOR3(1,0,0);
			Look_Vector = D3DXVECTOR3(0,0,1);

			D3DXMatrixRotationAxis(&YawMat, &Up_Vector, Planets[i].PlanetData.Yaw);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &YawMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &YawMat);

			D3DXMatrixRotationAxis(&PitchMat, &Right_Vector, Planets[i].PlanetData.Pitch);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &PitchMat);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &PitchMat);

			D3DXMatrixRotationAxis(&RollMat, &Look_Vector, Planets[i].PlanetData.Roll);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &RollMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &RollMat);

			D3DXMatrixTranslation(&TransMat, Planets[i].X, Planets[i].Y, Planets[i].Z);

			D3DXMatrixIdentity(&WorldMat);
			D3DXMatrixMultiply(&WorldMat, &RollMat, &TransMat);
			D3DXMatrixMultiply(&WorldMat, &PitchMat, &WorldMat);
			D3DXMatrixMultiply(&WorldMat, &YawMat, &WorldMat);

			if(modifier != NULL) D3DXMatrixMultiply(&WorldMat, &WorldMat, modifier);

			const OBJNODE *tmp_node = GFParent->ObjectLib[Planets[i].PlanetObjectIndex];
			int index = tmp_node->VertexLibraryIndex;
			
			if(last_vlib_index != index)
			{
				GFParent->D3DDevice->SetStreamSource(0, GFParent->VertexLib[index], GFParent->VertexLib.GetSize(index));
				GFParent->D3DDevice->SetVertexShader(GFParent->VertexLib.GetFVF(index));
				last_vlib_index = index;	
			}

			GFParent->D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat);

			/*********Each Planet Object Must Be EXACTLY one mesh item*******/
			tmp_node = GFParent->ObjectLib[Planets[i].PlanetObjectIndex];
			index = tmp_node->TextureLibraryIndex;
			if(index != -1)
			{
				GFParent->D3DDevice->SetTexture(0, GFParent->TextureLib[index]);
			}
			
			if(IsLightingActive && GFParent->IsLightingEnabled)
			{
				GFParent->D3DDevice->SetMaterial(&(GFParent->MaterialLib.GetMaterial(Planets[i].MaterialLibIndex)));
			}

			GFParent->D3DDevice->DrawPrimitive(tmp_node->PrimitiveType, tmp_node->StartVertex, tmp_node->PrimitiveCount);
			GFParent->D3DDevice->SetTexture(0, NULL);
		}
	}
	
	/****************Render Planet Atmospheres***********************************/
	GFParent->D3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
	for(i=0; i<NumPlanetsUsed; i++)
	{
		if(Planets[i].IsActive)
		{
			Up_Vector = D3DXVECTOR3(0,1,0);
			Right_Vector = D3DXVECTOR3(1,0,0);
			Look_Vector = D3DXVECTOR3(0,0,1);

			D3DXMatrixRotationAxis(&YawMat, &Up_Vector, Planets[i].AtmosphereData.Yaw);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &YawMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &YawMat);

			D3DXMatrixRotationAxis(&PitchMat, &Right_Vector, Planets[i].AtmosphereData.Pitch);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &PitchMat);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &PitchMat);

			D3DXMatrixRotationAxis(&RollMat, &Look_Vector, Planets[i].AtmosphereData.Roll);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &RollMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &RollMat);

			D3DXMatrixTranslation(&TransMat, Planets[i].X, Planets[i].Y, Planets[i].Z);

			D3DXMatrixIdentity(&WorldMat);
			D3DXMatrixMultiply(&WorldMat, &RollMat, &TransMat);
			D3DXMatrixMultiply(&WorldMat, &PitchMat, &WorldMat);
			D3DXMatrixMultiply(&WorldMat, &YawMat, &WorldMat);

			if(modifier != NULL) D3DXMatrixMultiply(&WorldMat, &WorldMat, modifier);

			const OBJNODE *tmp_node = GFParent->ObjectLib[Planets[i].AtmosphereObjectIndex];
			int index = tmp_node->VertexLibraryIndex;
			
			if(last_vlib_index != index)
			{
				GFParent->D3DDevice->SetStreamSource(0, GFParent->VertexLib[index], GFParent->VertexLib.GetSize(index));
				GFParent->D3DDevice->SetVertexShader(GFParent->VertexLib.GetFVF(index));
				last_vlib_index = index;	
			}

			GFParent->D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat);

			tmp_node = GFParent->ObjectLib[Planets[i].AtmosphereObjectIndex];
			index = tmp_node->TextureLibraryIndex;
			if(index != -1)
			{
				GFParent->D3DDevice->SetTexture(0, GFParent->TextureLib[index]);
			}
			
			if(IsLightingActive && GFParent->IsLightingEnabled)
			{
				GFParent->D3DDevice->SetMaterial(&(GFParent->MaterialLib.GetMaterial(Planets[i].MaterialLibIndex)));
			}

			GFParent->D3DDevice->DrawPrimitive(tmp_node->PrimitiveType, tmp_node->StartVertex, tmp_node->PrimitiveCount);
			GFParent->D3DDevice->SetTexture(0, NULL);
		}
	}
	
	if(IsLightingActive && GFParent->IsLightingEnabled)
	{
		GFParent->D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

		for(i=0; i<NumSunsUsed; i++)
		{
			if(Suns[i].IsActive)
			{
				GFParent->D3DDevice->LightEnable(i, FALSE);
			}
		}
	}

	/****************Render Sun Coronas***********************************/
	for(i=0; i<NumSunsUsed; i++)
	{
		if(Suns[i].IsActive)
		{
			Up_Vector = D3DXVECTOR3(0,1,0);
			Right_Vector = D3DXVECTOR3(1,0,0);
			Look_Vector = D3DXVECTOR3(0,0,1);

			D3DXMatrixRotationAxis(&YawMat, &Up_Vector, Suns[i].AtmosphereData.Yaw);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &YawMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &YawMat);

			D3DXMatrixRotationAxis(&PitchMat, &Right_Vector, Suns[i].AtmosphereData.Pitch);
			D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &PitchMat);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &PitchMat);

			D3DXMatrixRotationAxis(&RollMat, &Look_Vector, Suns[i].AtmosphereData.Roll);
			D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &RollMat);
			D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &RollMat);

			D3DXMatrixTranslation(&TransMat, Suns[i].X, Suns[i].Y, Suns[i].Z);

			D3DXMatrixIdentity(&WorldMat);
			D3DXMatrixMultiply(&WorldMat, &RollMat, &TransMat);
			D3DXMatrixMultiply(&WorldMat, &PitchMat, &WorldMat);
			D3DXMatrixMultiply(&WorldMat, &YawMat, &WorldMat);

			if(modifier != NULL) D3DXMatrixMultiply(&WorldMat, &WorldMat, modifier);

			const OBJNODE *tmp_node = GFParent->ObjectLib[Suns[i].AtmosphereObjectIndex];
			int index = tmp_node->VertexLibraryIndex;
			
			if(last_vlib_index != index)
			{
				GFParent->D3DDevice->SetStreamSource(0, GFParent->VertexLib[index], GFParent->VertexLib.GetSize(index));
				GFParent->D3DDevice->SetVertexShader(GFParent->VertexLib.GetFVF(index));
				last_vlib_index = index;	
			}

			GFParent->D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat);

			tmp_node = GFParent->ObjectLib[Suns[i].AtmosphereObjectIndex];
			index = tmp_node->TextureLibraryIndex;
			if(index != -1)
			{
				GFParent->D3DDevice->SetTexture(0, GFParent->TextureLib[index]);
			}
			
			GFParent->D3DDevice->DrawPrimitive(tmp_node->PrimitiveType, tmp_node->StartVertex, tmp_node->PrimitiveCount);
			GFParent->D3DDevice->SetTexture(0, NULL);
		}
	}
	GFParent->D3DDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_ONE);
	GFParent->D3DDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_ONE);
	GFParent->D3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,FALSE);
	GFParent->D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
}
