#ifndef _3DGLODEF_H
#define _3DGLODEF_H

#ifdef __cplusplus
extern "C" {
#endif

#include "typedefs.h"



/************************************************************************************
 *			In Here you will find amongst other stuff
 *
 *			prototypes for all 3D library routines
 *			3D system global variable definitions
 ************************************************************************************/

#define BETTER_ROOM_SORT
extern sint32 mid_sort;

/* Water effects */
#define WIBBLE_SIZE 32
#define MAX_WIBBLE  2
#define MAX_SHADE   0x300

#define DPQ_END		20480
#define DPQ_START	12288


extern float wibble_table[];
extern sint32 wibble_offset, water_effect;
extern sint32 rand_table[], shade_effect;
extern sint16 shade_table[];

#define	MAX_VERTICES	1500            // maximum vertices at a go
#define MAX_POLYGONS	4000        	// maximum number of polygons
#define MAX_MATRICES	40				// maximum matrices in stack...
#define MAX_SCANLINES	1200			// maximum height of screen
#define W2V_SHIFT 		14				// Shift scale of View.Frame to World.Frame
#define	W2V_SCALE 		(1<<W2V_SHIFT)	// Scale of View Frame to World Frame
#define	MAX_TEXTURES	4096			
#define MAX_SPRITES		512
#define MAX_TEXTPAGES	32				// Number of Texture pages surported

#define SPRITE_REL			0x00000000
#define SPRITE_ABS			0x01000000
#define SPRITE_SEMITRANS	0x02000000
#define SPRITE_SCALE		0x04000000
#define SPRITE_SHADE		0x08000000
#define SPRITE_TINT			0x10000000
#define SPRITE_TRANS_HALF	0x00000000
#define SPRITE_TRANS_ADD	0x20000000
#define SPRITE_TRANS_SUB	0x40000000
#define SPRITE_TRANS_QUARTER 0x60000000
#define SPRITE_COLOUR(r,g,b) ((r)|((g)<<8)|((b)<<16))

#define phd_PopMatrix()		phd_mxptr -= 12

/***************************** Handy Macro Defines for Insert routines *******************************************/

#define IF_NOT_VIS(vn1,vn2,vn3) if ( (sint32)( (( vn3->xs - vn2->xs ) * ( vn1->ys - vn2->ys ) )\
		  							  		  -(( vn1->xs - vn2->xs ) * ( vn3->ys - vn2->ys ) ) ) < 0 )


enum sort_type {MID_SORT, FAR_SORT, BACK_SORT};

#define BACK_DEPTH 1000000000.0f

#define TRIA_DEPTH_MID(vn1,vn2,vn3)			zdepth = (vn1->zv+vn2->zv+vn3->zv) * 0.333333333333333333f;
#define QUAD_DEPTH_MID(vn1,vn2,vn3,vn4)		zdepth = (vn1->zv+vn2->zv+vn3->zv+vn4->zv) * 0.25f;

#define TRIA_DEPTH_FAR(vn1,vn2,vn3)			zdepth = vn1->zv;\
											if ( vn2->zv>zdepth ) zdepth = vn2->zv;\
											if ( vn3->zv>zdepth ) zdepth = vn3->zv;
#define QUAD_DEPTH_FAR(vn1,vn2,vn3,vn4)		zdepth = vn1->zv;\
											if ( vn2->zv>zdepth ) zdepth = vn2->zv;\
											if ( vn3->zv>zdepth ) zdepth = vn3->zv;\
											if ( vn4->zv>zdepth ) zdepth = vn4->zv;

#define TRIA_DEPTH_NEAR(vn1,vn2,vn3)		zdepth = vn1->zv;\
											if ( vn2->zv<zdepth ) zdepth = vn2->zv;\
											if ( vn3->zv<zdepth ) zdepth = vn3->zv;
#define QUAD_DEPTH_NEAR(vn1,vn2,vn3,vn4)	zdepth =(sint32) vn1->zv;\
											if ( vn2->zv<zdepth ) zdepth =(sint32) vn2->zv;\
											if ( vn3->zv<zdepth ) zdepth =(sint32) vn3->zv;\
											if ( vn4->zv<zdepth ) zdepth =(sint32) vn4->zv;

#define ABS(x) (((x)<0) ? (-(x)):(x))
#define MIN(x,y) ((x)<=(y) ? (x):(y))
#define MAX(x,y) ((x)>=(y) ? (x):(y))

#define	TRIGMULT2(A, B)		( ( (A)*(B) ) >> W2V_SHIFT )
#define	TRIGMULT3(A, B, C)	( TRIGMULT2((TRIGMULT2(A, B)), C ))

enum msoff { M00,M01,M02,M03,
			 M10,M11,M12,M13,
			 M20,M21,M22,M23 };

/*****************************************************************************
 *					Structures And Unions
 ****************************************************************************/

typedef	struct	phd_vector {
			sint32	x;
			sint32	y;
			sint32	z;
}PHD_VECTOR;

typedef	sint16	PHD_ANGLE;


typedef struct	phd_3dpos {
			sint32 		x_pos;
			sint32 		y_pos;
			sint32		z_pos;
			PHD_ANGLE	x_rot;
			PHD_ANGLE	y_rot;
			PHD_ANGLE	z_rot;
}PHD_3DPOS;

typedef struct phdtexturestruct {
		uint16 	drawtype;
		uint16	tpage;
		uint16 	u1,v1;
		uint16 	u2,v2;
		uint16 	u3,v3;
		uint16 	u4,v4;
} PHDTEXTURESTRUCT;

typedef struct phdspritestruct {
		uint16	tpage;
		uint16  offset;
		uint16	width;
		uint16	height;
		sint16	x1;
		sint16	y1;
		sint16	x2;
		sint16	y2;
} PHDSPRITESTRUCT;

typedef struct phd_vbuf {
		float	xv;
		float	yv;
		float	zv;
		float	ooz;
		float	xs;
		float	ys;
		sint32  z;
		sint8	clip;
		uint8	fog;
		sint16	g;
		uint16	u,v;
		int		dynamic;
}PHD_VBUF;

#ifdef OLD_WAY
typedef struct phd_vbuf {
		sint32	xv;
		sint32	yv;
		sint32	zv;
		sint32	xs;
		sint32	ys;
		sint32	dist;
		sint16	clip;
		sint16	g;
		uint16	u,v;
}PHD_VBUF;
#endif

typedef struct xbuf_x {
			sint32	Xleft;
			sint32	Xright;
}XBUF_X;

typedef struct xbuf_xg {
			sint32	Xleft;
			sint32	Gleft;
			sint32	Xright;
			sint32	Gright;
}XBUF_XG;

typedef struct xbuf_xguv {
			sint32	Xleft;
			sint32	Gleft;
			sint32	Uleft;
			sint32	Vleft;
			sint32	Xright;
			sint32	Gright;
			sint32	Uright;
			sint32	Vright;
}XBUF_XGUV;

typedef struct xbuf_persp {
			sint32	Xleft;
			sint32	Gleft;
			int	UOZleft;
			int	VOZleft;
			int OOZleft;
			sint32	Xright;
			sint32	Gright;
			int	UOZright;
			int	VOZright;
			int OOZright;
}XBUF_PERSP;

typedef struct xbuf_persp_fp {
			sint32	Xleft;
			sint32	Gleft;
			float	UOZleft;
			float	VOZleft;
			float 	OOZleft;
			sint32	Xright;
			sint32	Gright;
			float	UOZright;
			float	VOZright;
			float 	OOZright;
}XBUF_PERSP_FP;

typedef struct vertex_info {
	float x, y;
	float ooz;
	float u, v, g;
	int vr,vg,vb;
} VERTEX_INFO;

extern	VERTEX_INFO		v_buffer[];

typedef struct point_info {
	float xv, yv, zv;
	float ooz;
	float xs, ys;
	float u, v;
	float g;
	int vr,vg,vb;
	} POINT_INFO;

/******************************************************************************
 *						General Variables
 *****************************************************************************/

extern	int			edge_id, edge_debug;

extern	sint32		ls_adder;  			// Light Source Thingys
extern	sint32		ls_divider;

extern	int			perspective_distance;

extern	float		phd_leftfloat;  	// Floating point copies of phd_left etc
extern	float		phd_rightfloat;
extern	float		phd_topfloat;
extern	float		phd_bottomfloat;

extern	char		*phd_winptr;		// pointer to 3dwindow
extern	sint32		phd_left;
extern	sint32		phd_right;          // Clipping Values For
extern	sint32		phd_top;
extern	sint32		phd_bottom;
extern	sint16		phd_winxmin;
extern	sint16		phd_winymin;
extern	sint16  		phd_winxmax;        // max X coord of window
extern	sint16		phd_winymax;        // max Y coord of window
extern	sint32		phd_winwidth;		// Width of Window
extern	sint32		phd_winheight;		// Height of Window
extern	sint32		phd_centerx;		// XCenter of Window
extern	sint32		phd_centery;		// YCenter of Window
extern	sint32		phd_znear;			// Minimum Z coord in View Frame
extern	sint32		phd_zfar;			// Maximum Z coord in View Frame
extern	sint32		phd_viewdist;		// Maximum View distance in World Frame
extern	sint32		phd_scrwidth;		// Width of Screen In Pixels
extern	sint32		phd_scrheight;		// Height of Screen In Pixels
extern	sint32		phd_persp;			// Perspective Scale Factor..
extern	sint32		*phd_mxptr;			// Pointer to Current Matrix...
extern  sint32		phd_oopersp;


extern	float		one;				// in 3dinsert.cpp
extern	float		f_znear;			// phd_znear
extern	float		f_zfar;				// phd_zfar
extern	float		f_oneoznear;		// one / phd_znear
extern	float		f_persp;			// phd_persp
extern	float		f_oneopersp;		// one / phd_persp
extern	float		f_perspoznear;		// phd_persp / phd_znear
extern	float		f_centerx;			// phd_centrex
extern	float		f_centery;			// phd_centrey
extern	float		f_invzfar;			// 1.0/phd_zfar (actually 65535/65536 at the moment)
extern	float		f_oneozfar;			// one/phd_zfar
extern	float		f_a,f_b,f_boo;		// a/b factors for z buffering (f_boo is f_b/one)

extern	sint32		w2v_matrix[];		// World to View Matrix...
extern	sint32		matrix_stack[];		// matrix stack for animations etc..

extern	PHD_VECTOR	ls_vector_view;
extern	PHD_ANGLE	phd_ls_yaw,phd_ls_pitch;

extern	sint32		surfacenum;			// polygon list sorting stuff...
extern	sint16		*info3dptr;
extern	sint32		*sort3dptr;

extern  sint32		surfacenumfb;
extern  sint32		surfacenumbf;
extern	sint32		*sort3dptrfb;
extern	sint32		*sort3dptrbf;
extern	sint16		*info3dptrfb;
extern	sint16		*info3dptrbf;

extern	sint32		sort3d_bufferbf[][10];
extern	sint32		sort3d_buffer[][2];

extern	sint16		info3d_buffer[];
extern	sint16		info3d_bufferfb[];
extern	sint16		info3d_bufferbf[];



extern	PHD_VBUF 	vbuf[];
extern	XBUF_PERSP	xbuffer[];
extern	char		*texture_page_ptrs[];

extern	PHDTEXTURESTRUCT 	phdtextinfo[];
extern	PHDSPRITESTRUCT 	phdsprinfo[];

extern	char		depthq_table[33][256];
extern	char		gouraud_table[256][32];
//extern	char		interpolate_table[256][256];

/******************************************************************************
 * 			  Surface Drawing definitions here......
 *****************************************************************************/

enum { DRAW_POLY_GTMAP,
	   DRAW_POLY_WGTMAP,
	   DRAW_POLY_GTMAP_PERSPECTIVE,
	   DRAW_POLY_WGTMAP_PERSPECTIVE,
	   DRAW_POLY_LINE,
	   DRAW_POLY_FLAT,
	   DRAW_POLY_GOURAUD,
	   DRAW_POLY_TRANS,
	   DRAW_SCALED_SPRITE,

	   DRAW_TLV_GT,
	   DRAW_TLV_WGT,
	   DRAW_TLV_G,
	   DRAW_TLV_L,
	   DRAW_TLV_GA,
       DRAW_TLV_GTA,
	   DRAW_TLV_GTT,
};


/******************************************************************************
 ******************************************************************************
 *						Prototypes.
 ******************************************************************************
 *****************************************************************************/

extern  void	(*poly_draw_routines[])(sint16*);			/* Jump tables for different*/

extern	sint16*	(*InsertObjectGT3)	(sint16* objptr,int number,enum sort_type sort_routine);
extern	sint16*	(*InsertObjectGT4)	(sint16* objptr,int number,enum sort_type sort_routine);
extern	sint16*	(*InsertObjectG3)	(sint16* objptr,int number,enum sort_type sort_routine);
extern	sint16*	(*InsertObjectG4)	(sint16* objptr,int number,enum sort_type sort_routine);

extern	sint16*	(*RoomInsertObjectGT3)	(sint16* objptr,int number,enum sort_type sort_routine);
extern	sint16*	(*RoomInsertObjectGT4)	(sint16* objptr,int number,enum sort_type sort_routine);



extern	void	(*InsertSprite)		(int nZDepth,int nX1,int nY1,int nX2,int nY2,int nSprite,int nShade,int nShade1,int drawtype,int offset);
extern	void	(*InsertFlatRect)	(sint32 min_x,sint32 min_y,sint32 max_x,sint32 max_y,int nZDepth,int colour);
extern	void	(*InsertLine)		(sint32 x1,sint32 y1,sint32 x2,sint32 y2,sint32 z,char color);
extern	void	(*InsertTrans8)		(PHD_VBUF* vbuf,sint16 shade);
extern	void	(*InsertTransQuad)	(sint32 sx,sint32 sy,sint32 w,sint32 h,sint32 z);

/*** 3d_gen.cpp ***/
void	phd_GenerateW2V( PHD_3DPOS *viewpos );
void	phd_LookAt( sint32 xsrc, sint32 ysrc, sint32 zsrc, sint32 xtar, sint32 ytar, sint32 ztar, PHD_ANGLE roll );
void	phd_GetVectorAngles( sint32 x, sint32 y, sint32 z, PHD_ANGLE *dest );
void	phd_NormaliseVector( sint32 x, sint32 y, sint32 z, sint32 *dest );
void	phd_NormaliseMatrix( void );
void	phd_GetMatrixAngles( PHD_ANGLE *dest );
void	phd_RotX( PHD_ANGLE rx );
void	phd_RotY( PHD_ANGLE ry );
void	phd_RotZ( PHD_ANGLE rz );
void	phd_RotYXZ( PHD_ANGLE ry, PHD_ANGLE rx, PHD_ANGLE rz );
void	phd_RotYXZpack( sint32 rots );
int		phd_TranslateRel( sint32 x, sint32 y, sint32 z );
void	phd_TranslateAbs( sint32 x, sint32 y, sint32 z );
void	phd_PutPolygons( sint16 *objptr, int clipstatus );
sint16	*calc_vertice_light( sint16 *objptr,sint16* );
sint16	*calc_object_vertices( sint16 *objptr );
sint16	*calc_roomvert( sint16 *objptr, int far_clip );
void	phd_RotateLight( PHD_ANGLE pitch, PHD_ANGLE yaw );
void	phd_PointLight( PHD_3DPOS *destpos, PHD_3DPOS *lightpos );
void	phd_InitPolyList( void );
void	phd_SortPolyList(int,sint32 buffer[][10]);
void	do_quickysorty( int left, int right,sint32 buffer[][10]);
void	phd_PrintPolyList(void* pDest);
void	phd_InitWindow( int x, int y, int width, int height, int nearz, int farz, int view_angle, int scrwidth, int scrheight );
void	AlterFOV( PHD_ANGLE	fov );
void	GenerateDepthQ(char palette[][3]);
void	GetDepthTable(int position, char palette[][3], char *dest);

/*** 3d_gen_a.s ***/
void	__cdecl phd_PushMatrix( void );
void	__cdecl phd_PushUnitMatrix( void );
void	__cdecl phd_UnitMatrix( void );

/*** phd_math.s ***/
sint32	__fastcall phd_cos(sint32 angle);
sint32	__fastcall phd_sin(sint32 angle);
uint32	__fastcall phd_sqrt(uint32 n);
sint16	__fastcall phd_atan(sint32 x, sint32 y);

/*** 3dinsert.cpp ***/
int		visible_zclip(PHD_VBUF *vn1,PHD_VBUF *vn2,PHD_VBUF *vn3);
int		ZedClipper(int number,POINT_INFO* input,VERTEX_INFO* output);
int		XYGUVClipper(int number,VERTEX_INFO *input);
int		XYGClipper(int number,VERTEX_INFO *input);
int		XYClipper(int number,VERTEX_INFO *input);

sint16*	ins_objectGT3(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	ins_objectGT4(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	ins_objectG3(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	ins_objectG4(sint16* objptr,int number,enum sort_type sort_routine);
void	ins_poly_trans8(PHD_VBUF *v,sint16 shade);
void	ins_trans_quad(sint32 sx,sint32 sy,sint32 w,sint32 h,sint32 z);
void	ins_flat_rect(sint32 nX1,sint32 nY1,sint32 nX2,sint32 nY2,int nZDepth,int nColour);
void	ins_line(sint32 x1,sint32 y1,sint32 x2,sint32 y2,sint32 z,char color);

/*** hwinsert.cpp ***/
#ifdef __cplusplus
extern	bool	bBlueEffect;
extern	uint8	G_GouraudPalette[256*4];
#endif

/*
sint16*	HWI_InsertObjectGT3_ZBuffered(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	HWI_InsertObjectGT4_ZBuffered(sint16* objptr,int number,enum sort_type sort_routine);

sint16*	HWI_RoomInsertObjectGT3_ZBuffered(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	HWI_RoomInsertObjectGT4_ZBuffered(sint16* objptr,int number,enum sort_type sort_routine);


sint16*	HWI_InsertObjectG3_ZBuffered(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	HWI_InsertObjectG4_ZBuffered(sint16* objptr,int number,enum sort_type sort_routine);
void	HWI_InsertFlatRect_ZBuffered(sint32 nX1,sint32 nY1,sint32 nX2,sint32 nY2,int nZDepth,int nColour);
void	HWI_InsertLine_ZBuffered(sint32 x1,sint32 y1,sint32 x2,sint32 y2,sint32 z,char color);

sint16*	HWI_InsertObjectGT3_Sorted(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	HWI_InsertObjectGT4_Sorted(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	HWI_InsertObjectG3_Sorted(sint16* objptr,int number,enum sort_type sort_routine);
sint16*	HWI_InsertObjectG4_Sorted(sint16* objptr,int number,enum sort_type sort_routine);
void	HWI_InsertSprite_Sorted(int nZDepth,int nX1,int nY1,int nX2,int nY2,int nSprite,int nShade,int drawtype);
void	HWI_InsertFlatRect_Sorted(sint32 nX1,sint32 nY1,sint32 nX2,sint32 nY2,int nZDepth,int nColour);
void	HWI_InsertLine_Sorted(sint32 x1,sint32 y1,sint32 x2,sint32 y2,sint32 z,char color);
void	HWI_InsertTrans8_Sorted(PHD_VBUF *vbuf,sint16 shade);
void	HWI_InsertTransQuad_Sorted(sint32 sx,sint32 sy,sint32 w,sint32 h,sint32 z);
*/


/*** 3d_out.cpp ***/
void	draw_poly_flat( sint16 *iptr );
void	draw_poly_trans( sint16 *iptr );
void	draw_poly_gouraud( sint16 *iptr );
void	draw_poly_gtmap( sint16 *iptr );
void	draw_poly_wgtmap( sint16 *iptr );
void	draw_poly_gtmap_persp( sint16 *iptr );
void	draw_poly_wgtmap_persp( sint16 *iptr );
void	draw_poly_tmap( sint16 *iptr );
void	draw_poly_wtmap( sint16 *iptr );
int		xgen_x( sint16 *iptr );
int		xgen_xg( sint16 *iptr );
int		xgen_xuv( sint16 *iptr );
int		xgen_xguv( sint16 *iptr );

/*** 3d_xouta.s ***/
void	__cdecl flatA( int min_y, int max_y, char color );
void	__cdecl gourA( int min_y, int max_y, sint16 colbase );
void	__cdecl transA( int min_y, int max_y, sint16 colbase );
void	__cdecl gtmapA( int min_y, int max_y, char *tptr );
void	__cdecl wgtmapA( int min_y, int max_y, char *tptr );

/*** 3d_line.cpp ***/
void	Insert2DLine( sint32 x1, sint32 y1, sint32 x2, sint32 y2, sint32 z, char color );
sint16	*ins_poly_line( sint16 *objptr );
void	draw_line( sint32 x1, sint32 y1, sint32 x2, sint32 y2, char color );
void	draw_poly_line( sint16 *iptr );

/*** scalespr.cpp ***/
void	S_DrawSprite			(uint32 dwFlags,sint32 nX,sint32 nY,sint32 nZ,sint16 nSprite,sint16 nShade,sint16 nScale);
//void	S_DrawPickup			(sint32 x,sint32 y,sint32 scale,sint16 sprnum,sint16 shade,uint16 flags);
void	S_DrawSpriteSize		(sint32 x,sint32 y,sint32 z,sint32 w,sint32 h,sint16 sprnum,sint16 shade,uint16 flags);
void	S_DrawScreenSprite2d	(sint32 sx,sint32 sy,sint32 z,sint32 scaleH,sint32 scaleV,sint16 sprnum,sint16 shade,uint16 flags);
void	S_DrawScreenSprite		(sint32 sx,sint32 sy,sint32 z,sint32 scaleH,sint32 scaleV,sint16 sprnum,sint16 shade,uint16 flags);
void	insert_sprite(int nZDepth,int nX1,int nY1,int nX2,int nY2,int nSprite,int nShade);
sint16  *ins_room_sprite( sint16 *objptr, int num );
void	draw_scaled_spriteC( sint16 *inptr );


void	S_DrawPickup(sint16 x, sint16 y, sint16 object_num);


extern  double chop_temp;



#ifdef __cplusplus
}
#endif

#endif	// _3DGLODEF_H