#ifndef _TILEMGR_H
#define _TILEMGR_H

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

#include "Scene.h"

//#include "D3D11Effect.h"

#define MAXQUEUE 10

struct TILEVERTEX {
	D3DXVECTOR3 pos;		//12
	D3DXVECTOR3 norm;		//24
	D3DXVECTOR2 tex;		//32
	D3DXVECTOR2 mtex;		//40
};

TILEVERTEX _TVTX( D3DXVECTOR3 pos, D3DXVECTOR3 norm, float tu0, float tv0, float tu1, float tv1 );

//Mesh for tile(L4-L14) or sphere(L1-L3):
struct TILEMESH {
	ID3D11Buffer *VB;
	ID3D11Buffer *IB;
	DWORD nvtx, nidx, nFace;
	D3DXVECTOR3 bsCnt;
	float bsRad;
};

//Contains textures for tile(L4-L14) or sphere(L1-L3) and links tile to its subtiles(L8-L14);
struct TILEDESC {
	ID3D11ShaderResourceView *tex;      // diffuse surface texture
	ID3D11ShaderResourceView *ltex;     // landmask texture, if applicable
	DWORD flag;
	struct TILEDESC *subtile[4];   // sub-tiles for the next resolution level
	DWORD ofs;                     // refers back to the master list entry for the tile
};

#pragma pack(push,1)
struct TILEFILESPEC {
	DWORD sidx;       // index for surface texture (-1: not present)
	DWORD midx;       // index for land-water mask texture (-1: not present)
	DWORD eidx;       // index for elevation data blocks (not used yet; always -1)
	DWORD flags;      // tile flags: bit 0: has diffuse component; bit 1: has specular component; bit 2: has city lights
	DWORD subidx[4];  // subtile indices
};

struct LMASKFILEHEADER { // file header for contents file at level 1-8
	char id[8];          //    ID+version string
	DWORD hsize;         //    header size
	DWORD flag;          //    bitflag content information
	DWORD npatch;        //    number of patches
	BYTE minres;         //    min. resolution level
	BYTE maxres;         //    max. resolution level
};
#pragma pack(pop)

typedef struct {
	float tumin, tumax;
	float tvmin, tvmax;
} TEXCRDRANGE;

class D3D11Effect;
class D3D11Config;
class vPlanet;

class TileManager : public D3D11Effect {
	friend class RingManager;
	friend class TileBuffer;
	friend class CelBackground;
public:
	TileManager( vPlanet *_planet );
	~TileManager();

	static void GlobalInit( D3D11Config *_cfg, ID3D11Device *dev, ID3D11DeviceContext *dctx );
	static void GlobalExit();

	virtual void SetMicrotexture( const char *fname );
	virtual void SetMicrolevel( double lvl );
	void SetAmbientColor( D3DXCOLOR *acol );

	void SaveParams( D3DXMATRIX *wmat, double scale, int level, double viewap = 0.0, bool bfog = false );		//MT
	void Render( /* D3DXMATRIX &wmat, double scale, int level, double viewap = 0.0, bool bfog = false*/ );
protected:
	bool SpecularColor( D3DXCOLOR *col );
	VECTOR3 GetTileCenter( int hemisphere, int ilat, int nlat, int ilng, int nlng );
	void SetWorldMatrix( int ilat, int nlat, int ilng, int nlng );
	bool IsTileInView( int lvl, int ilat, float scale );
	void TileExtents( int hemisphere, int ilat, int nlat, int ilng, int nlng, double &lat1, double &lat2, double &lng1, double &lng2 );

	virtual void InitRenderTile() = 0;
	virtual void EndRenderTile() = 0;

	void ProcessTile( int hemisphere, int lvl, int ilat, int nlat, int ilng, int nlng, TILEDESC *tile,
		const TEXCRDRANGE &range, ID3D11ShaderResourceView *tex, ID3D11ShaderResourceView *ltex, DWORD flag,
		const TEXCRDRANGE &bkp_range, ID3D11ShaderResourceView *bkp_tex, ID3D11ShaderResourceView *bkp_ltex, DWORD bkp_flag );

	virtual void RenderSimple( int lvl, int npatch, TILEDESC *tile, D3DXMATRIX *mWorld ) = 0;
	virtual void RenderTile( int hemisphere, int lvl, int ilat, int nlat, int ilng, int nlng, /*double sdist,*/ TILEDESC *tile,
		const TEXCRDRANGE &range, ID3D11ShaderResourceView *tex, ID3D11ShaderResourceView *ltex, DWORD flag ) = 0;

//Loading:
	void LoadSpecularMaskData();//loads _lmask.bin	L1-L8
	void LoadTileData();		//loads _tile.bin	L8-L14
	void AddSubtileData( TILEDESC &td, TILEFILESPEC *tfs, DWORD idx, DWORD sub, DWORD lvl );		//adds L9-L14 subtiles to L8 tiles of tildesc(L1-L8) array
	void LoadTextures();		//loads L1-L8 textures
	void PreLoadTileTextures( TILEDESC *tile8, DWORD ntex, DWORD nmask );	//preload L9 diffuse and specular textures if preload mode is active
	void AddSubtileTextures( TILEDESC *td, ID3D11ShaderResourceView **tbuf, DWORD nt, ID3D11ShaderResourceView **mbuf, DWORD nm );	//	same thing ^
	void LoadSpecularMasks();	//load L1-L8 specular mask textures
//File paths for some texture files:
	char *Planet_tile_fpath;
	char *Planet_tile_lmask_fpath;
	TILEDESC *tiledesc;			//array of L1-L8 (or lower) tiles
	ID3D11ShaderResourceView **texbuf;		//array of diffuse textures.
	DWORD ntex;
	ID3D11ShaderResourceView **specbuf;		//array of specular mask/lights textures.
	DWORD nmask, nhitex, nhispec;
	ID3D11ShaderResourceView *microtex;		//microtexture

	static bool bSpecular, bLights, bRipple, bPreloadTiles;

	OBJHANDLE obj;
	char *objname;
	vPlanet *planet;

	struct RENDERPARAM {
		D3DXMATRIX mWorld;
		D3DXMATRIX mWorld_tmp;
		MATRIX3 grot;
		VECTOR3 cdir;
		VECTOR3 sdir;
		VECTOR3 cpos;
		double viewap;
		double objsize;
		double cdist;
		double horzdist;
		short tgtlvl;
		bool bFog;
		bool bCockpit;
		double dist_scale;

		double clng;
		double clat;
		double crad;
	} RP0;				//TileManager has 1 RenderParam struct, cloudManager has 2 (+shadow)

	RENDERPARAM *RP;	//RP = &RP0;

	D3DXMATRIX mWorld;
	D3DXCOLOR cAmbient;
	float spec_base, lightfac, microlvl;;	
	const ATMCONST *atmc;
	VECTOR3 pcdir;
	int tilever;	
	DWORD maxlvl;
	DWORD Shader_prev;

	static const D3D11Config *cfg;
	static TileBuffer *tbuf;

	static DWORD maxbaselvl;
	static int patchidx[9];
	static int NLAT[9];
	static int NLNG5[1], NLNG6[2], NLNG7[4], NLNG8[8], *NLNG[9];
//Tile meshes:
	static TILEMESH TPL_1;
	static TILEMESH TPL_2;
	static TILEMESH TPL_3;
	static TILEMESH TPL_4[2];
	static TILEMESH TPL_5;
	static TILEMESH TPL_6[2];
	static TILEMESH TPL_7[4];
	static TILEMESH TPL_8[8];
	static TILEMESH TPL_9[16];
	static TILEMESH TPL_10[32];
	static TILEMESH TPL_11[64];
	static TILEMESH TPL_12[128];
	static TILEMESH TPL_13[256];
	static TILEMESH TPL_14[512];
	static TILEMESH *TPL[15];
//Functions to create or delete them:
	static void CreateSphere( TILEMESH &mesh, DWORD nrings, bool hemisphere, int which_half, int texres );
	static void CreateSpherePatch( TILEMESH &mesh, int ilat, int nlat, int nlng, int res, int bseg = -1, bool reduce = true, bool shift_origin = false );
	static void DeleteTileMesh( TILEMESH &mesh );
//Rotation matrix for south hemisphere:
	static D3DXMATRIX RSouth;
};

struct QUEUEDESC {
	TileManager *TM;
	TILEDESC *td;
};

class TileBuffer {
public:
	TileBuffer();
	~TileBuffer();

	TILEDESC *AddTile();
	void DeleteSubTiles( TILEDESC *tile );
	bool AddTileToLQueue( TileManager *tm, TILEDESC *tile );

	static DWORD LoadTextures( const char *fname, DWORD texcount, DWORD flags, ID3D11ShaderResourceView **out );//L1-L8
	static HRESULT LoadMicroTexture( const char *fname, ID3D11ShaderResourceView **out );
	static CRITICAL_SECTION LQueueCS;
private:
	bool DeleteTile( TILEDESC *tile );
	//buffer for L9-L14 tiles
	TILEDESC **buf;
	DWORD nbuf, bufsize;
	
	static HRESULT LoadTexture( const char *fname, long ofs, ID3D11ShaderResourceView **out );

	static DWORD WINAPI LThreadProc( void *data );
	//Loading queue:
	static QUEUEDESC LQueue[MAXQUEUE];
	static DWORD nqueue;

	static bool bRunLThread;
	static HANDLE hLThread;
	static DWORD LThreadID;	
};

#endif // !__TILEMGR_H
