#ifndef _OBJ_H
#define _OBJ_H

#if C2504
#pragma message("vObject.h")
#endif

#include "Scene.h"

class D3D11Mesh;
class Scene;
class RingManager;
class SurfaceManager;
class HazeManager;
class CloudManager;

class vObject {
	friend class Scene;
	friend class D3D11Mesh;
public:
	vObject( OBJHANDLE _obj );
	~vObject();

	virtual int VisEvent( DWORD msg, UINT context ) = 0;
	virtual MESHHANDLE clbkGetMesh( UINT idx ) = 0;

	void IsActive();
	virtual void SaveData();
	virtual void Update();
	virtual void Render() {	}

	static void InitRenderDot();
	void RenderDot();

	VECTOR3 GetCPos()	{	return CPos;	}
	double GetCDist()	{	return CDist;	}
	double GetAppRadius()	{	return apprad; }
	
	OBJHANDLE obj;
	double rad;
	bool active;

protected:
	virtual void CheckResolution() = 0;
	void ConstructWorldMatrix( D3DXMATRIX *out, MATRIX3 *rot, VECTOR3 *pos );
	
	D3DXMATRIX mWorld, mWorld_new;
	double
		CDist,
		CDist_new,
		apprad;

	VECTOR3
		GPos,
		GPos_new,
		CPos,
		CPos_new;

	MATRIX3
		mROT,
		mROT_new;

	D3DXVECTOR4
		SunDir,
		SunDir_new;

	char name[64];
	int obj_type;

	static double SunSize;
	static VECTOR3 pSun;
	static Sun_spec def_SunLight;
};

//=====================================
//		Planets
class vBase;

class vPlanet : public vObject {
	friend class Scene;
	friend class vBase;
	friend class vVessel;
	friend class D3D11ParticleStream;
	friend class ExhaustStream;
	friend class ReentryStream;
public:
	vPlanet( OBJHANDLE _obj );
	~vPlanet();

	int VisEvent( DWORD msg, UINT context )	{	return 0;	}
	MESHHANDLE clbkGetMesh( UINT idx )		{	return NULL;	}

	void Update();
	void Render();

	OBJHANDLE GetObject() { return obj;		}
	double GetRad()	{	return rad;	}

	ATM_FOG_PARAMS *GetAtmParams() { return &AP; };
private:
	void CheckResolution();

	void InitLegacyAtmosphere();
	bool InitFogParams( bool bfog );

//mesh ?
	D3D11Mesh *PlanetMesh;	//for non-spherical small planets
	SurfaceManager *SM;		//large planets
	HazeManager *HM;		//planetary haze

	struct CLOUDPRM {
		CloudManager *CM;	//clouds and cloud shadows
		D3DXMATRIX mW_cloud;
		D3DXMATRIX mW_cloudshadow;
		DWORD RenderMode;
		double cloud_rad;
		double viewap;
		bool bCloudShadow;
		float fShadowAlpha;
		double micro_alt0, micro_alt1;
	} *CloudData;

	struct RINGPRM {		//planetary rings
		RingManager *RM;
		double minrad;
		double maxrad;
		DWORD res;
	} *RingData;

//atmosphere params
	double Mass;			//mass of a a planet
	const ATMCONST *atmc;
	ATM_FOG_PARAMS AP;
	FogParam Fog;
	bool bFog;
	VECTOR3 gpos;
//misc
	float dist_scale;
	DWORD ring_res;		//0/1/2

	//***
	float rad, render_rad;
	bool bRipple;

	float shadow_alpha;
	bool bVesselShadows;

	int patchres;

	vBase **Base;
	DWORD nbase;
};

//=====================================
//		Vessels
//=====================================

struct BBVertex {
	D3DXVECTOR3 pos;
	D3DXVECTOR2 tex;
};

class vVessel : public vObject {
	friend class Scene;
	friend class D3D11ParticleStream;
	friend class ExhaustStream;
	friend class ReentryStream;
	friend class vObject;
public:
	vVessel( OBJHANDLE _obj );
	~vVessel();

	static void GlobalInit();
	static void GlobalExit();

	int VisEvent( DWORD msg, UINT context );
	MESHHANDLE clbkGetMesh( UINT idx );

	void SaveData();
	void Update();

	//renders vessel sahdows
	void RenderShadows( vPlanet *PLN );
	//mesh
	static void InitRender();
	static void RenderCompleted();
	void Render();
	//focus vessel only:
	//cockpit and VC
	void RenderCockpit();
	void RenderVC();	

	//beacons, exhaust and reentry billboards
	static void InitRenderBeacons();
	static void InitRenderExhaust();
	void RenderBeacons();
	void RenderExhaust();
	void RenderReentry();
	void RenderBoundingBox();

	float GetBoundingSphereRad( );

	//bounding sphere:
	D3DXVECTOR3 AABB[2];
	float bsRad;
	bool bsRecompute;
protected:
	void CheckResolution() {	}

	void Animate( UINT midx, UINT anim, double state );
	void AnimateComponent( ANIMATIONCOMP *AnimComp, D3DXMATRIX &T );
	void TransformPoint( VECTOR3 &p, D3DXMATRIX &T );
	void TransformDirection( VECTOR3 &a, D3DXMATRIX &T, bool normalize );

	int InsertMesh( UINT idx );
	int DelMesh( UINT idx );
	int SetVisibilityMode( UINT idx );
	int SetMeshOffset( UINT idx );

	int ResetAnimations( UINT idx );
	int ClearAnimations( UINT idx );
	int DelAnimation( UINT idx );
	int NewAnimation( UINT idx );

	VESSEL *VSL;

	VECTOR3 CDir;
	DWORD nex;
	double MaxExhaustLenght, simt, nxtsimt;

//animations:
	ANIMATION *ANIM;
	double *animstate;
	UINT nanim;

	DWORD nbls, nblsmax;
	struct BeaconData {
		BEACONLIGHTSPEC bls;
		VECTOR3 pos;
		VECTOR3 col;
	} *BC;

	struct ExhaustData {
		VECTOR3
			ldir,
			lpos;

		double
			level,
			modulate,
			wsize,
			lsize,
			lofs;

		Texture *tex;
	} *espc;

	struct ReentryData {
		double pressure, airspeed, size;
		VECTOR3 d;
	} rspc;

//meshes:
	struct VSLMESH {
		D3D11Mesh *MSH;
		WORD vis_mode;
		D3DXMATRIX ofs;
	} *MESH;
	DWORD nmesh;

//current sun light:
	Sun_spec SunLight;

	static BBVertex  _VB[8];

	static ID3D11InputLayout
		*IL_BillBoard;
	static ID3D11VertexShader
		*VS_BillBoard;
	static ID3D11PixelShader
		*PS_BillBoard;
	static ID3D11Buffer
		*VB, *IB;

	static Texture
		*Ball[3],
		*def_Exhaust,
		*def_Reentry;

	bool update_vc, bAMSO;
	VCHUDSPEC specHUD;
	VCMFDSPEC specMFD[MAXMFD];
	Texture *texHUD, *texMFD[MAXMFD];
	DWORD nmfd;
private:
	static ID3D11VertexShader
		*VS_Mesh;				//Vessel.fx
	static ID3D11PixelShader
		*PS_Mesh;

	static ID3D11Buffer * beaconsBuffer;
};

//=====================================
//		Stars
//=====================================
//	Sun

class vStar : public vObject
{
	friend class vObject;
	friend class vVessel;
public:
	vStar( OBJHANDLE _obj ) ;
	~vStar();

	static void GlobalInit();
	static void GlobalExit();

	int VisEvent( DWORD msg, UINT context ) {	return 0; }
	MESHHANDLE clbkGetMesh( UINT idx ) { return NULL; }

	void Update();
	void Render();
protected:
	void CheckResolution() {	}

	double size;
	double maxdist;

	static Texture *Tex;
	static ID3D11InputLayout *IL_BBVertex;
	static ID3D11VertexShader *VS;
	static ID3D11PixelShader *PS;
	static ID3D11Buffer *VB;
};

//=====================================
//		Surface bases
//=====================================

class vBase : public vObject
{
public:
	vBase( vPlanet *_PLN, OBJHANDLE _planet, OBJHANDLE _obj );
	~vBase();

	int VisEvent( DWORD msg, UINT context ) { return 0; }
	MESHHANDLE clbkGetMesh( UINT idx ) { return NULL; }

	void Update();

	void RenderSurface();
	void RenderStructuresBS();
	void RenderStructuresAS();

	static void InitRenderShadows();
	void RenderShadows();
private:
	void CheckResolution() {	}
	void SetupShadowMeshes();

	//time vars...

//tiles and meshes:
	const SurftileSpec *tspec;
	DWORD
		ntile,
		nstructs_bs,
		nstructs_as,
		nshadow_mesh;

	D3D11Mesh
		*tilemesh,		//meshes for base tiles
		**structs_bs,	//structures before shadows
		**structs_as;	//structures after shadows

	bool p_night;		//use night textures for base objects
	//local lights to do...

	struct ShadowMesh {
		ID3D11Buffer *VB, *IB;
		DWORD nvtx, nidx;
		double ecorr;
	} *shadow_mesh;

	DWORD nshmesh;
	OBJHANDLE planet;
	vPlanet *PLN;

	struct RPARAM {
		MATRIX3 vR;
		VECTOR3
			pp,
			sd;
	} RP;

	Sun_spec SunLight;
};

#endif