
#ifndef _MAPDRAW_H_
#define _MAPDRAW_H_

#define SHORT_MAP_VERTNOS


// NB - The structures defined in here must match those defined in the PC map compilation tool!

// BFF header types for frog-map segments

// Version 1 (5) mesh headers include flat-poly information. Like what skies used to.
#ifdef SHORT_MAP_VERTNOS
	#define BFF_FMA_MESH_ID (('F'<<0) | ('M'<<8) | ('M'<<16) | (5<<24))
	#define BFF_FMA_MESH4_ID (('F'<<0) | ('M'<<8) | ('M'<<16) | (6<<24))
#else
	#define BFF_FMA_MESH_ID (('F'<<0) | ('M'<<8) | ('M'<<16) | (1<<24))
	#define BFF_FMA_MESH4_ID (('F'<<0) | ('M'<<8) | ('M'<<16) | (4<<24))
#endif

#define BFF_FMA_WORLD_ID (('F'<<0) | ('M'<<8) | ('W'<<16) | (0<<24))
#define BFF_FMA_WORLD2_ID (('F'<<0) | ('M'<<8) | ('W'<<16) | (2<<24))


// frog-map versions of the playstation quad/tri structures

typedef struct FMA_GT3
{
	u_char	r0, g0, b0, code;
	u_char	u0, v0;	u_short	clut;
	u_char	r1, g1, b1, p1;
	u_char	u1, v1;	u_short	tpage;
	u_char	r2, g2, b2, p2;
	u_char	u2, v2;	u_short	pad2;
#ifdef SHORT_MAP_VERTNOS
	short vert0,vert1,vert2,dummyv;
#else
	int vert0,vert1,vert2;
#endif
}FMA_GT3;
typedef struct FMA_GT4
{
	u_char	r0, g0, b0, code;
	u_char	u0, v0;	u_short	clut;
	u_char	r1, g1, b1, p1;
	u_char	u1, v1;	u_short	tpage;
	u_char	r2, g2, b2, p2;
	u_char	u2, v2;	u_short	pad2;
	u_char	r3, g3, b3, p3;
	u_char	u3, v3;	u_short	pad3;
#ifdef SHORT_MAP_VERTNOS
	short vert0,vert1,vert2,vert3;
#else
	int vert0,vert1,vert2,vert3;
#endif
}FMA_GT4;


typedef struct FMA_G3
{
	u_char	r0, g0, b0, code;
	u_char	r1, g1, b1, p1;
	u_char	r2, g2, b2, p2;
#ifdef SHORT_MAP_VERTNOS
	short vert0,vert1,vert2,dummyv;
#else
	int vert0,vert1,vert2;
#endif
}FMA_G3;
typedef struct FMA_G4
{
	u_char	r0, g0, b0, code;
	u_char	r1, g1, b1, p1;
	u_char	r2, g2, b2, p2;
	u_char	r3, g3, b3, p3;
#ifdef SHORT_MAP_VERTNOS
	short vert0,vert1,vert2,vert3;
#else
	int vert0,vert1,vert2,vert3;
#endif
}FMA_G4;



// ** New **
// Double-Polygons ultra-speedy version used for fully textured, non-instanced meshes.
// Woohoo. Ohboy, Jim's going to love this...
typedef struct FMA4_GT3
{
#ifdef SHORT_MAP_VERTNOS
	int vert0,vert1,vert2;
#else
	short vert0,vert1,vert2,dummyv;
#endif
	POLY_GT3 poly[2];	// both of which need u & v to be corrected. Also the tpage & clut
}FMA4_GT3;
typedef struct FMA4_GT4
{
#ifdef SHORT_MAP_VERTNOS
	short vert0,vert1,vert2,vert3;
#else
	int vert0,vert1,vert2,vert3;
#endif
	POLY_GT4 poly[2];
}FMA4_GT4;





// Structure containing all the data for a single mesh object
// (A collection of which make up the map)

typedef struct FMA_MESH_HEADER
{
// start with a BFF header
	unsigned long id;
	int length;
	unsigned long name_crc;

// Follow that up with a bounding box
	int minx,miny,minz, maxx,maxy,maxz;

// pos/rotate, or matrix... Dunno.
// For the MAP (as opposed to platforms), the position will always be zero
//	int posx,posy,posz;
//	short rotx,roty,rotz,rotw;

// when we build an instance mesh, it'll adjust all internal coordinates, and note the edjustment here, for collision purposes
	int offsetx,offsety,offsetz;
	long polyListPtr;			// short dummy1,dummy2,
	short dummy3,dummy4;

//	short dummy1,dummy2;
//	struct FMA_MESH_HEADER *subdiv;

// All map meshes are sorted to a position further away than their actual position,
// so that objects can sit on top of them nicely.
// "Underwater" meshes should have this set higher than that of the water itself.
//	int extra_depth;
	int radius;


// Finally, vertices, triangles, quads, and texture names.
// These are stored as integers in the file, and are converted to pointers after loading.
	int n_verts;
	VERT *verts;

	int n_gt3s;
	FMA_GT3 *gt3s;	// NOTE - Can also be an FMA4_GT3 pointer
	int n_gt4s;
	FMA_GT4 *gt4s;	// NOTE - Can also be an FMA4_GT4 pointer

	int n_tmaps;
	unsigned long *tmap_crcs;

// sky-type polys can now be included in the map mesh
// (Um, which means that the structures are now identical. Hmmmm.
	int n_g3s;
	FMA_G3 *g3s;
	int n_g4s;
	FMA_G4 *g4s;

}FMA_MESH_HEADER;



typedef struct FMA_MESH_HEADER FMA_SKYMESH_HEADER;



// Structure containing a list of FMA_MESH_HEADER pointers, and not much else

typedef struct FMA_WORLD
{
// start with a BFF header
	unsigned long id;
	int length;
	unsigned long name_crc;

// and there really ain't much else...
	int n_meshes;
// Followed immediately by an array of meshname CRC's to be replaced with mesh pointers
}FMA_WORLD;

// New instance-capable version...
// ?How do instances work in 3ds?
/*
typedef struct FMA_WORLDENTRY
{
	int x,y,z;
	int radius;
	FMA_MESH_HEADER *mesh;
}FMA_WORLDENTRY;
*/
typedef struct WORLD_MESH_INSTANCE
{
	int posx,posy,posz;
	short rotx,roty,rotz,rotw;
	int radius;	// read from mesh at loadtime

	short terrain;
	char  enabled;
	char  dummy;

	int tag;
	int sort_depth;

	FMA_MESH_HEADER *mesh;
	struct WORLD_MESH_INSTANCE *subdiv;
}WORLD_MESH_INSTANCE;


typedef struct FMA_WORLD2
{
	unsigned long id;	// start with a BFF header, with an eye to the future
	int length;
	unsigned long name_crc;

	int n_meshes;
// Followed immediately by an array of fma_worldentry's. Um, no. Make that mesh_instances
}FMA_WORLD2;

extern	FMA_WORLD2 *mapplay_fma_world;

// =========== Hurrah... Some functions! =========
// Draw the whole world map
//void MapDraw_DrawFMA_World(FMA_WORLD *world);
void MapDraw_DrawFMA_World(FMA_WORLD2 *world);	// we only understand 2's now...

// Same again, but for untextured polys at the back of the sort-table
void MapDraw_Draw_SkyWorld(FMA_WORLD *world);

// Draw a platform mesh
//void MapDraw_DrawFMA_Mesh(FMA_MESH_HEADER *mesh);
void MapDraw_DrawFMA_Mesh(WORLD_MESH_INSTANCE *instance);

WORLD_MESH_INSTANCE *mapdrawFindInstance(FMA_WORLD2 *world, int tag);



// These are actually defines...
void mapdrawEnable(WORLD_MESH_INSTANCE *instance, int enable);
int mapdrawIsEnabled(WORLD_MESH_INSTANCE *instance);
void mapdrawSetDepth(WORLD_MESH_INSTANCE *instance, int depth);

// Here's the defines for quick & easy functions

//#define mapdrawEnable(instance, enable) (instance)->enabled = (enable);
#define mapdrawIsEnabled(instance) ((instance)->enabled)
//#define mapdrawSetDepth(instance,depth) ((instance)->sort_depth = (depth))


#define mapdrawEnable(instance, enable)  \
	{	\
	(instance)->enabled = (enable); \
	if((instance)->subdiv)	\
	{	\
		WORLD_MESH_INSTANCE *sub;	\
		sub = (instance)->subdiv;	\
		do	\
		{	\
			sub->enabled = enable;	\
			sub = sub->subdiv;	\
		}	\
		while(sub);	\
	}	\
	}

#define mapdrawSetDepth(instance, depth)  \
	{	\
	(instance)->sort_depth = (depth); \
	if((instance)->subdiv)	\
	{	\
		WORLD_MESH_INSTANCE *sub;	\
		sub = (instance)->subdiv;	\
		do	\
		{	\
			sub->sort_depth = depth;	\
			sub = sub->subdiv;	\
		}	\
		while(sub);	\
	}	\
	}

/*
#define mapdrawEnable(instance, enable) { \
	WORLD_MESH_INSTANCE *temp;	\
	temp = (instance);	\
	 do{	\
	temp->enabled = (enable);	\
	temp = temp->subdiv;	\
	 }while(temp); };
*/


/* Mapcam.h
   This module correctly sets the camera position, so it works with the new camera relative world plotter.

	mapCamSetRefView2L(&camera)

	should be called instead of:

	GsSetRefView2L(&camera)

*/

typedef struct tagMAPCAMDATATYPE
{
	GsRVIEW2	gameCam;	// camera that game 'thinks' is real
	GsRVIEW2	realCam;	// actual camera pos. NB, vrx,vry & vrz will normally be zero
}MAPCAMDATATYPE;

extern MAPCAMDATATYPE mapCamData;

void mapCamSetRefView2L(GsRVIEW2 *);

int mapdrawIsSphereVisible(VECTOR *vec, int radius);

extern int max_map_ot_depth;

#endif
