#ifndef _COLLIDE_H_
#define _COLLIDE_H_

#define COLL_PRINTF

#define	MAXCOLLCUBES	16384
#define COLLISIONBOXES	32
#define TEMPARRAY		512
#define MAXHITS			16
#define MAXPLATHITS		4

#define COLLFLAGS_ISACTOR 1


#define	HITDIFFERENCE	4096*4


// the Ulong pointer pM points to one of these
typedef struct tagRAMPHEADER
{
	short nVerts;
	short nFaces;
	ULONG *pFaces;
	VECTOR *pVerts;

	short normal_x;	// new....
	short normal_y;
	short normal_z;
	short plane;

}RAMPHEADER;

typedef struct tagCOLLBOX
{
	long	pX,pY,pZ;
	long	oldpX,oldpY,oldpZ;
	long	sX,sY,sZ;
	// bit 0  0=box 1=mesh

// Chris pointed out last night that tom's using some other bits as terrain type...(!)
	ULONG	flags; //maybe could use the other 3 bytes.
//	 flags;
//	char pad;
//	short boxnum;
	RAMPHEADER*	rampheader;
}COLLBOX;




// if mesh flag is set, the following data follows this structure:


// char    nVerts,nFaces
// SVECTOR vert[nVerts]
// ALIGN   (4)
// char    face[nFaces*4] (char 0=flags, chars 1&2=verts 0,1,2&3 in nybbles, char 3=pad (0) )
// ALIGN   (4)

// flags: bit 0:   0=tri, 1=quad
//        bit 1&2: 00=arbitrary poly, 01=XY plane, 10=XZ plane, 11=YZ plane

extern COLLBOX *collBox;
extern int bCtr;
extern long	numCollBoxes;

typedef struct tagHITPLAT
{
	void *pPlatform;
}HITPLAT;

typedef struct tagREBDATA
{
	VECTOR		pos;
	VECTOR		rampPos;
	VECTOR		vel;	// both changed from FVECTOR
	VECTOR		normal;
	COLLBOX		*pCollBox;
	short		plane;
	short		type;
}HITDATA;

extern HITDATA pHitData[MAXHITS]; // max number of hits

/*
typedef struct tagDYNCOLLBOX
{
	struct tagDYNCOLLBOX *next,*prev;
	COLLBOX cb;
	NEWMODEL *pModel;
}DYNCOLLBOX;

typedef struct
{
	DYNCOLLBOX head;
	int numEntries;
}DYNCOLLBOXLIST;
*/
typedef	struct _Behaviour_Physics
{
	long	mass;
	long	gravity;
	long	bounce;		//(4096=full 0=none)
	long	drag;		//(4096=none 0=full)
	long	maxSpeed;
	long	radius;
	long	accel;
	long	squash;

}BEHAVIOUR_PHYSICS;

typedef	struct _Enemy_Behaviour_Physics
{
	long	mass;
//	long	gravity;
//	long	bounce;		//(4096=full 0=none)
//	long	drag;		//(4096=none 0=full)
//	long	maxSpeed;
	long	radius;
//	long	accel;
//	long	squash;
	ULONG	flags;

}ENEMY_PHYSICS;


typedef struct tagCOLLDATA
{
	int		nBoxes;
//	int		bounce;
	int		radius;
	COLLBOX	*pCollBox;
	VECTOR	*pVel;
	VECTOR	*pPos;
	VECTOR	*pRot;	// changed from FVECTOR
	int		nCornerHits;
	int		nPlaneHits;
	int		nRampHits;
	int		nEdgeHits;
	int		nHitPlats;
	HITPLAT	hitPlats[MAXPLATHITS];
	VECTOR	normal;

	BEHAVIOUR_PHYSICS	*physics;
	int		physicsModel;
	ULONG	dbug;
	ULONG	flags;

	// internal use only
	VECTOR	oldPos;
	VECTOR	oldRot;
	VECTOR	oldVel;
	VECTOR	preVel;
	VECTOR	hitPos;	// changed from FVECTOR
	int		lastHit;
}COLLDATA;


// box orientations

#define N	0
#define NE	1
#define E	2
#define SE 	3
#define S	4
#define SW	5
#define	W	6
#define NW	7

// HIT types
#define PLANE		0
#define EDGE		1
#define CORNER		2
#define	CYLINDER	3
#define	SPHERE_H	4
#define RAMP_H		5


// Box types
#define BOX			0
#define RAMP		1
#define	CYLINDER_X	2	/* X axis aligned cylinder*/
#define	CYLINDER_Y	4	/* Y axis aligned cylinder*/
#define	CYLINDER_Z	8	/* Z axis aligned cylinder*/
#define	SPHERE		16
#define	BOXPLANE	32


// Bits for type and special
#define TYPEPART	0xff
#define	SPECIALPART	0xffffff00
#define	SPECIALWITHMOVE	0xfffffe00
// This may cause some terrain type not to work with moving platforms
// Box special cases 

//#define MOVE	0x100

#define	MOVE				(1<<0)*256
#define	C_STICKY			(1<<1)*256
#define	C_ICE				(1<<2)*256
#define	C_SNOW				(1<<3)*256
#define	C_CONVEYERXP		(1<<4)*256
#define	C_CONVEYERXN		(1<<5)*256
#define	C_CONVEYERZP		(1<<6)*256
#define	C_CONVEYERZN		(1<<7)*256
#define	C_LAVA				(1<<8)*256
#define	C_TRAMPOLINE		(1<<9)*256
#define	C_WATERY			(1<<10)*256
#define	C_SPIKE				(1<<11)*256
#define	C_MEGASTICKY		(1<<12)*256
#define	C_SNOWANDICE		(1<<13)*256
#define	C_NOCAMCOLLISION	(1<<14)*256

// same flags but for physics

#define	P_STICKY			(1<<1)
#define	P_ICE				(1<<2)
#define	P_SNOW				(1<<3)
#define	P_CONVEYERXP		(1<<4)
#define	P_CONVEYERXN		(1<<5)
#define	P_CONVEYERZP		(1<<6)
#define	P_CONVEYERZN		(1<<7)
#define	P_LAVA				(1<<8)
#define	P_TRAMPOLINE		(1<<9)
#define	P_WATERY			(1<<10)
#define	P_SPIKE				(1<<11)
#define	P_MEGASTICKY		(1<<12)
#define	P_SNOWANDICE		(1<<13)
#define	P_NOCAMCOLLISION	(1<<14)

/*
#define	MOVE			1*256
#define	C_STICKY		2*256
#define	C_ICE			3*256
#define	C_SNOW			4*256

#define	C_CONVEYERXP	5*256
#define	C_CONVEYERXN	6*256
#define	C_CONVEYERYP	7*256
#define	C_CONVEYERYN	8*256

#define	C_LAVA			9*256
#define	C_TRAMPOLINE	10*256
#define	C_WATERY		11*256
#define	C_SPIKE			12*256
#define	C_MEGASTICKY	13*256
#define	C_SNOWANDICE	14*356
#define	C_NOCAMCOLLISION	15*256
*/
// same flags but for physics
/*
#define	P_STICKY		2
#define	P_ICE			3
#define	P_SNOW			4

#define	P_CONVEYERXP	5
#define	P_CONVEYERXN	6
#define	P_CONVEYERZP	7
#define	P_CONVEYERZN	8

#define	P_LAVA			9
#define	P_TRAMPOLINE	10
#define	P_WATERY		11
#define	P_SPIKE			12
#define	P_MEGASTICKY	13
#define	P_SNOWANDICE	14
#define	P_NOCAMCOLLISION	15
*/

#define	XPOS			1
#define	XNEG			2
#define	ZPOS			3
#define	ZNEG			4

#define XAXIS 1
#define YAXIS 2
#define ZAXIS 4

#define D_XZPLANE 1
#define D_XYPLANE 2
#define D_YZPLANE 4

#define U_XZPLANE 8
#define U_XYPLANE 16
#define U_YZPLANE 32

#define LARGERTOSMALLER 0
#define SMALLERTOLARGER 1
#define MAXCOLLOSIONS 20

extern int pFaceOrder[];

extern int pEdgeOrder[];

extern int pCornerOrder[];
extern ULONG	*reducedCollBox;
extern long gravity;

COLLBOX *collisionLoadMeshCRC(long crc);

ULONG	CheckCorners( COLLBOX *pB , COLLDATA *pD, HITDATA *pHitData );
int		collboxHasBallHitCorner(COLLDATA *pD, int x, int y, int z);
ULONG	CheckEdges(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData );
//int		collboxHasBallHitEdge(COLLDATA *pD, int axis, int l1, int l2, int x, int y);
ULONG	CheckPlanes(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData );
//int		collboxHasVectorCrossedPoly(COLLDATA *pD, int plane, int planePos, int r, int x1, int y1, int x2, int y2);
ULONG	CheckRamps(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData );

ULONG	CheckCylinders(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData );
ULONG	CheckSpheres(COLLBOX *pB , COLLDATA *pD , HITDATA *pHitData );

void	ReducePlanes(int nPolysHit);
void	MergeBounceNormals(int nPolysHit);

void	UpdateRampCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound);

void	UpdateMultiRampCollision(COLLDATA *pD , VECTOR *collPos , VECTOR *rebound);

void	UpdateEdgeCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound); 
void	UpdateCornerCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound);
void	UpdatePlaneCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound);

void	UpdateCylinderCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound);
void	UpdateSphereCollision(COLLDATA *pD , HITDATA *pHitData , VECTOR *collPos , VECTOR *rebound);

//void collboxAddBox(int pX,int pY,int pZ, int sX,int sY,int sZ,int orient, int boxType, int bColl);

void ReduceCollision(COLLBOX *pcollbox);	//,long offset,char *filename)

long	RemoveRedundantEdges(COLLDATA *pD , int *nPolysHit);

void	setupCollision(char *);
int		collboxCheckSphere(COLLDATA *pD);
long	getHeightAt(long x,long y,long z);
long	getHeightAtCam(long x,long y,long z);

long	getHeightAtSlow(long x,long y,long z);
long isPointSolid(long x,long y,long z);
void	doBounceOnVel(VECTOR *rebound,VECTOR *start,BEHAVIOUR_PHYSICS *Physics);
void	doBounceOnVelBall(VECTOR *rebound,VECTOR *start,BEHAVIOUR_PHYSICS *Physics);
LONG	doConveyerStuff(LONG	flags);
#endif
