#ifndef	V_TLIST_H
#define V_TLIST_H

/*
 * Very simple z-sorting engine
 * TODO: convert to object
 */

typedef	struct	tlist_edge_s
{
	vboolean	visible;
	u32_t		triangle;
	u32_t		points[2];
}	tlist_edge_t, *tlist_edge_p;

typedef struct	tlist_vertex_s
{
	vec3_t		vert;
	vec4_t		color;
	vec3_t		normal;
	vec2_t		texcoord;
	u32_t		edge_flag;		/* next edge boundary | non-boundary */
}	tlist_vertex_t, *tlist_vertex_p;

typedef	struct	tlist_face_s
{
	tlist_vertex_t	verts[3];
	vec3_t		center;
	vec3_t		normal;
	/* edge indexes valid only after tlistGenerateEdgeInfo() */
	u32_t		edges[3];
}	tlist_face_t, *tlist_face_p;

typedef struct
{
	matrix3x4_t	xform;
	bstack_t	mstack;
	bstack_t	vlist;	/* triangular faces */
	vp_stack_t	order;	/* order of faces */
	vboolean	sorted;
	vec3_t		last_viewpoint;
	bstack_t	edge_info;
	vec3_t		mins, maxs;
	/* Misc stuff: used when adding faces */
	int			num_vert;	/* [0|1|2] - used when adding faces */
	tlist_face_t tri;
	vec4_t		color;
	vec2_t		texcoord;
	vec3_t		normal;
	u32_t		edge_flag;
}	trilist_t, *trilist_p;

/*
 *	Vertex callback used by tlistAdd[Mesh|Patch]Object()
 */
typedef	void (V_CALL *vertex_proc_t)(
		vec3_t v,	/* Vertex */
		vec4_t c,	/* Color */
		vec3_t n,	/* Normal */
		vec2_t tx,	/* Texture coordinate */
		u32_t *ef,	/* Edge flag */
		void *param	/* User - supplied parameter */
	);

#ifdef	__cplusplus
extern "C" {
#endif	/* __cplusplus */
	/*	Allocates and initializes sortable triangle list */
	trilist_p	V_GLOBAL	tlistCreate(void);
	/*	Clears contents but NOT releases memory in vertex stacks */
	void	V_GLOBAL	tlistClear(trilist_t *list);
	/*	Releases all memory */
	void	V_GLOBAL	tlistDestroy(trilist_t *list);
	/*	Transformation functions */
	void	V_GLOBAL	tlistPushMatrix(trilist_t *list);
	void	V_GLOBAL	tlistPopMatrix(trilist_t *list);
	void	V_GLOBAL	tlistLoadMatrix(trilist_t *list,matrix3x4_t tos);
	void	V_GLOBAL	tlistLoadIdentity(trilist_t *list);
	void	V_GLOBAL	tlistMultMatrix(trilist_t *list,matrix3x4_t mult);
	void	V_GLOBAL	tlistRotatev(trilist_t *list,vec_t radians,
		vec3_t axis);
	void	V_GLOBAL	tlistRotate(trilist_t *list,vec_t radians,
		vec_t ax,vec_t ay,vec_t az);
	void	V_GLOBAL	tlistTranslatev(trilist_t *list,vec3_t v);
	void	V_GLOBAL	tlistTranslate(trilist_t *list,
		vec_t x,vec_t y,vec_t z);
	void	V_GLOBAL	tlistScalev(trilist_t *list,vec3_t scales);
	void	V_GLOBAL	tlistScale(trilist_t *list,
		vec_t sx,vec_t sy,vec_t sz);
	/*	Primitive definition functions */
	void	V_GLOBAL	tlistColor4(trilist_t *list,
		vec_t r,vec_t g,vec_t b,vec_t a);
	void	V_GLOBAL	tlistColor4v(trilist_t *list,vec4_t rgba);
	void	V_GLOBAL	tlistNormal3(trilist_t *list,
		vec_t x,vec_t y,vec_t z);
	void	V_GLOBAL	tlistNormal3v(trilist_t *list,vec3_t normal);
	void	V_GLOBAL	tlistTexCoord2(trilist_t *list,vec_t u,vec_t v);
	void	V_GLOBAL	tlistTexCoord2v(trilist_t *list,vec2_t texcoord);
	void	V_GLOBAL	tlistEdgeFlag(trilist_t *list,u32_t flag);
	void	V_GLOBAL	tlistVertex3(trilist_t *list,
		vec_t x,vec_t y,vec_t z);
	void	V_GLOBAL	tlistVertex3v(trilist_t *list,vec3_t vertex);
	/*
	 *	Adds object from mesh to list. For each vertex 'vertex_proc' will
	 *	be called (useful for lighting).
	 */
	void	V_GLOBAL	tlistAddMeshObject(
		trilist_t *list,	/* List to add object to */
		scene_p scene,		/* Mesh containing object */
		u32_t obj_num,		/* Index of object in mesh */
		vertex_proc_t vertex_proc,	/* Used - supplied callback or NULL */
		void *param			/* Parameter to pass to vertex callback */
		);
	/*
	 *	Adds triangles from patch to list.
	 */
	void	V_GLOBAL	tlistAddPatch(
		trilist_t *list,		/* List to add object to */
		tripatch_t *patch,		/* Patch */
		vertex_proc_t vertex_proc,	/* Used - supplied callback or NULL */
		void *param				/* Parameter to pass to vertex callback */
		);
	/*	Concatenates two lists */
	void	V_GLOBAL	tlistConcat(trilist_t *dst,trilist_t *src,
		vertex_proc_t vertex_proc,void *param);
	/*	Same ideology, but process only current list */
	void	V_GLOBAL	tlistProcess(trilist_t *list,
		vertex_proc_t vertex_proc,void *param);
	/*
	 *	Sorts and draws triangle list. Modelview stack unchanged.
	 */
	void	V_GLOBAL	tlistDraw(trilist_t *list,vec3_t viewpoint,
		vboolean front_to_back);
	/*
	 *	MUST be called at least once before calls to tlistDrawWireframe().
	 *	NOTE. Takes VERY long time to execute.
	 */
	void	V_GLOBAL	tlistGenerateEdgeInfo(trilist_t *list);
	/* Updates list->mins and list->maxs */
	void	V_GLOBAL	tlistGenerateBBox(trilist_t *list);
	/*
	 *	Draws (currently unculled) edges.
	 */
	void	V_GLOBAL	tlistDrawWireframe(trilist_t *list);
#ifdef	__cplusplus
}
#endif	/* __cplusplus */

#endif	/* V_TLIST_H */
