#include "3Dglodef.h"

typedef struct output_info {
	sint16	xs;
	sint16	ys;
	sint16	g;
	float	ooz;
	float	u;
	float	v;
} OUTPUT_INFO;

VERTEX_INFO	v_buffer[40];		// 20 possible clipped points

// Paul Store 1.0 as its quicker than generating it every time???
//float   one  = (65536.0f * 8.0f * 16384.0f);               // gives OOZ in range 26214 to 25.6
float   one  = (256.0f * 8.0f * 16384.0f);               // gives OOZ in range 26214 to 25.6	????

/******************************************************************************
*			Is Polygon Visible??  Handles Z-Clipped Polygons
*				Converted to Now use Floating point...
*****************************************************************************/
int visible_zclip(PHD_VBUF *vn1, PHD_VBUF *vn2, PHD_VBUF *vn3)
	{
	/* Cross product of point 1 and 3 with the origin to get plane through origin, 
	then see which side of this plane point 2 lies on */
	float a,b,c;
	
	a = (vn1->yv * vn3->zv) - (vn3->yv * vn1->zv);
	b = (vn1->zv * vn3->xv) - (vn3->zv * vn1->xv);
	c = (vn1->xv * vn3->yv) - (vn3->xv * vn1->yv);
	if ((a * vn2->xv) + (b * vn2->yv) + (c * vn2->zv) < 0.0f)
		return(1);
	return(0);
	}

/******************************************************************************
*				Z-Clipper for X,Y,G,U,V
*****************************************************************************/
int ZedClipper(int number,POINT_INFO* input,VERTEX_INFO* output)
	{
	int 		nVertices;
	POINT_INFO*	A,* B;
	VERTEX_INFO* pOut;
	float 		clipper,fADiff,fBDiff;

	A=input+number-1;
	B=input;
	pOut=output;
	nVertices=0;
	for (;number--;A=B++)
		{
		fADiff=f_znear-A->zv;	// A out if fADiff>=0
		fBDiff=f_znear-B->zv;	// B out if fBDIff>=0
		if (((*(long*)&fADiff)|(*(long*)&fBDiff))>=0)	// if both sign bits clear, both out
			continue;
		if (((*(long*)&fADiff)^(*(long*)&fBDiff))<0)	// if sign bits are different, either A or B is out
			{
			clipper=fBDiff/(A->zv-B->zv);
			pOut->x=(B->xv+(A->xv-B->xv)*clipper)*f_perspoznear+f_centerx;
			pOut->y=(B->yv+(A->yv-B->yv)*clipper)*f_perspoznear+f_centery;
			pOut->g=(B->g+(A->g-B->g)*clipper);
			pOut->ooz=f_oneoznear;
			pOut->u=(B->u+(A->u-B->u)*clipper)*f_oneoznear;
			pOut->v=(B->v+(A->v-B->v)*clipper)*f_oneoznear;
			++pOut;
			++nVertices;
			}
		if ((*(long*)&fBDiff)<0)	// if B not out
			{
			pOut->x=B->xs;
			pOut->y=B->ys;
			pOut->g=B->g;
			pOut->ooz=B->ooz;
			pOut->u=B->u*B->ooz;
			pOut->v=B->v*B->ooz;
			++pOut;
			++nVertices;
			}
		}
	if (nVertices<3)
		return 0;
	return nVertices;
	}

/**********************************************************************************************************
**********************************************************************************************************
*						2D Clipper for X,Y,G,U,V,OOZ
**********************************************************************************************************
*********************************************************************************************************/
#define CLIP_GUV(OUT, B, A) \
	OUT.ooz = B->ooz + (A->ooz - B->ooz) * clipper;	\
	OUT.u = B->u + (A->u - B->u) * clipper; \
	OUT.v = B->v + (A->v - B->v) * clipper; \
	OUT.g = B->g + (A->g - B->g) * clipper

static VERTEX_INFO XYGUV_output[8];

int XYGUVClipper( int number, VERTEX_INFO *input)
	{
	/* Clips to X then to Y and returns new number of points: input must be able to hold extra points! */
	VERTEX_INFO		*A,*B;
	int 			i, j;
	float 			clipper;
	
	/* Clip against X sides */
	B = &input[number-1];
	for (i=j=0; i<number; i++)
		{
		A = B;
		B = &input[i];
		
		/* Clip if point A is off screen */
		if (A->x < phd_leftfloat )
			{
			if (B->x < phd_leftfloat )
				continue;
			
			clipper = (phd_leftfloat - B->x) / (A->x - B->x);
			CLIP_GUV(XYGUV_output[j], B, A);
			XYGUV_output[j].x = phd_leftfloat;
			XYGUV_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else if (A->x > phd_rightfloat )
			{
			if (B->x > phd_rightfloat )
				continue;
			
			clipper = ( phd_rightfloat - B->x) / (A->x - B->x);
			CLIP_GUV(XYGUV_output[j], B, A);
			XYGUV_output[j].x = phd_rightfloat;
			XYGUV_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		
		/* Clip if point B is off screen, else add it's point unclipped */
		if (B->x < phd_leftfloat)
			{
			clipper = (phd_leftfloat - B->x) / (A->x - B->x);
			CLIP_GUV(XYGUV_output[j], B, A);
			XYGUV_output[j].x = phd_leftfloat;
			XYGUV_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else if (B->x > phd_rightfloat)
			{
			clipper = (phd_rightfloat - B->x) / (A->x - B->x);
			CLIP_GUV(XYGUV_output[j], B, A);
			XYGUV_output[j].x = phd_rightfloat;
			XYGUV_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else
			{
			/* Not clipped */
			XYGUV_output[j].x = B->x;
			XYGUV_output[j].y = B->y;
			XYGUV_output[j].g = B->g;
			XYGUV_output[j].ooz = B->ooz;
			XYGUV_output[j].u = B->u;
			XYGUV_output[j++].v = B->v;
			}
		}
	
	/* New number of points in 'XYGUV_output': now clip these against Y */
	if (j < 3)
		return (0);
	number = j;
	
	/* Clip against Y sides */
	B = &XYGUV_output[number-1];
	for (i=j=0; i<number; i++)
		{
		A = B;
		B = &XYGUV_output[i];
		
		/* Clip if point A is off screen */
		if (A->y < phd_topfloat )
			{
			if (B->y < phd_topfloat )
				continue;
			
			clipper = (phd_topfloat - B->y) / (A->y - B->y);
			CLIP_GUV(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_topfloat;
			}
		else if (A->y > phd_bottomfloat )
			{
			if (B->y > phd_bottomfloat )
				continue;
			
			clipper = (phd_bottomfloat - B->y) / (A->y - B->y);
			CLIP_GUV(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_bottomfloat;
			}
		
		/* Clip if point B is off screen, else add its point unclipped */
		if (B->y < phd_topfloat )
			{
			clipper = (phd_topfloat - B->y) / (A->y - B->y);
			CLIP_GUV(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_topfloat;
			}
		else if (B->y > phd_bottomfloat )
			{
			clipper = (phd_bottomfloat - B->y) / (A->y - B->y);
			CLIP_GUV(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_bottomfloat;
			}
		else
			{
			/* Unclipped point */
			input[j].x = B->x;
			input[j].y = B->y;
			input[j].g = B->g;
			input[j].ooz = B->ooz;
			input[j].u = B->u;
			input[j++].v = B->v;
			}
		}
	
	/* Throw away polygons that have been reduced to lines or less */
	if (j<3)
		return (0);
	
	return (j);
}


/******************************************************************************
*			Room Insertion for TextureQuads
*****************************************************************************/
sint16 *ins_objectGT4(sint16 *objptr, int number, enum sort_type sort_routine)
	{
	PHD_VBUF 			*vn1, *vn2, *vn3, *vn4;
	PHDTEXTURESTRUCT 	*tex;
	VERTEX_INFO 		*v;
	POINT_INFO			point[4], *p;
	OUTPUT_INFO 		*outptr;
	int 				i,npoints;
	float zdepth;
	
	for ( ; number>0; number--, objptr+=5)
		{
		vn1 = &vbuf[objptr[0]];
		vn2 = &vbuf[objptr[1]];
		vn3 = &vbuf[objptr[2]];
		vn4 = &vbuf[objptr[3]];
		if (vn1->clip&vn2->clip&vn3->clip&vn4->clip)
			continue;
		
		if ((vn1->clip|vn2->clip|vn3->clip|vn4->clip)<0)
			{
			if (!visible_zclip(vn1,vn2,vn3))
				continue;
			
			/* Need to Z-clip polygon first */
			tex = &phdtextinfo[objptr[4]];
			p = point;
			p->xv = vn1->xv;
			p->yv = vn1->yv;
			p->zv = vn1->zv;
			p->ooz = vn1->ooz;
			p->xs = vn1->xs;
			p->ys = vn1->ys;
			p->g = float(vn1->g);
			p->u = float(tex->u1);
			p->v = float(tex->v1);
			
			p++;
			p->xv = vn2->xv;
			p->yv = vn2->yv;
			p->zv = vn2->zv;
			p->ooz = vn2->ooz;
			p->xs = vn2->xs;
			p->ys = vn2->ys;
			p->g = float(vn2->g);
			p->u = float(tex->u2);
			p->v = float(tex->v2);
			
			p++;
			p->xv = vn3->xv;
			p->yv = vn3->yv;
			p->zv = vn3->zv;
			p->ooz = vn3->ooz;
			p->xs = vn3->xs;
			p->ys = vn3->ys;
			p->g = float(vn3->g);
			p->u = float(tex->u3);
			p->v = float(tex->v3);
			
			p++;
			p->xv = vn4->xv;
			p->yv = vn4->yv;
			p->zv = vn4->zv;
			p->ooz = vn4->ooz;
			p->xs = vn4->xs;
			p->ys = vn4->ys;
			p->g = float(vn4->g);
			p->u = float(tex->u4);
			p->v = float(tex->v4);
			
			npoints = ZedClipper(4, point, v_buffer);
			if (npoints)
				npoints = XYGUVClipper(npoints, v_buffer);
			}
		else if (vn1->clip|vn2->clip|vn3->clip|vn4->clip)
			{
			/* Need to clip polygon to edge of screen */
			IF_NOT_VIS(vn1,vn2,vn3)
				continue;
			
			tex = &phdtextinfo[objptr[4]];
			v = v_buffer;
			v->x = vn1->xs;
			v->y = vn1->ys;
			v->ooz = vn1->ooz;
			v->g = float(vn1->g);
			v->u = tex->u1 * v->ooz;
			v->v = tex->v1 * v->ooz;
			
			v++;
			v->x = vn2->xs;
			v->y = vn2->ys;
			v->ooz = vn2->ooz;
			v->g = float(vn2->g);
			v->u = tex->u2 * v->ooz;
			v->v = tex->v2 * v->ooz;
			
			v++;
			v->x = vn3->xs;
			v->y = vn3->ys;
			v->ooz = vn3->ooz;
			v->g = float(vn3->g);
			v->u = tex->u3 * v->ooz;
			v->v = tex->v3 * v->ooz;
			
			v++;
			v->x = vn4->xs;
			v->y = vn4->ys;
			v->ooz = vn4->ooz;
			v->g = float(vn4->g);
			v->u = tex->u4 * v->ooz;
			v->v = tex->v4 * v->ooz;
			
			npoints = XYGUVClipper(4, v_buffer);
			}
		else
			{
			/* Don't need any clipping, so place straight in list */
			IF_NOT_VIS(vn1,vn2,vn3)
				continue;
			
			switch (sort_routine)
				{
				case FAR_SORT:
					QUAD_DEPTH_FAR(vn1,vn2,vn3,vn4);
					break;
				case MID_SORT:
					QUAD_DEPTH_MID(vn1,vn2,vn3,vn4);
					break;
				default:
					zdepth = BACK_DEPTH;
				}

			sort3dptr[0] = (sint32)(info3dptr);
			sort3dptr[1] = (sint32)zdepth;
			sort3dptr += 2;

			tex = &phdtextinfo[objptr[4]];
			if (zdepth<perspective_distance)
				{
				info3dptr[0] = tex->drawtype + (DRAW_POLY_GTMAP_PERSPECTIVE-DRAW_POLY_GTMAP);
				info3dptr[1] = tex->tpage;
				info3dptr[2] = 4;
				
				outptr = (OUTPUT_INFO *)(info3dptr+3);
				outptr[0].xs = (sint16)vn1->xs;
				outptr[0].ys = (sint16)vn1->ys;
				outptr[0].g = vn1->g;
				outptr[0].ooz = vn1->ooz;
				outptr[0].u = tex->u1 * outptr[0].ooz;
				outptr[0].v = tex->v1 * outptr[0].ooz;
				
				outptr[1].xs = (sint16)vn2->xs;
				outptr[1].ys = (sint16)vn2->ys;
				outptr[1].g = vn2->g;
				outptr[1].ooz = vn2->ooz;
				outptr[1].u = tex->u2 * outptr[1].ooz;
				outptr[1].v = tex->v2 * outptr[1].ooz;
				
				outptr[2].xs = (sint16)vn3->xs;
				outptr[2].ys = (sint16)vn3->ys;
				outptr[2].g = vn3->g;
				outptr[2].ooz = vn3->ooz;
				outptr[2].u = tex->u3 * outptr[2].ooz;
				outptr[2].v = tex->v3 * outptr[2].ooz;
				
				outptr[3].xs = (sint16)vn4->xs;
				outptr[3].ys = (sint16)vn4->ys;
				outptr[3].g = vn4->g;
				outptr[3].ooz = vn4->ooz;
				outptr[3].u = tex->u4 * outptr[3].ooz;
				outptr[3].v = tex->v4 * outptr[3].ooz;
				
				info3dptr = (sint16 *)&outptr[4];
				}
			else
				{
				*((uint32 *)info3dptr) = *((uint32 *)&tex->drawtype);
				info3dptr[2] = 4;
				
				info3dptr[3] = (sint16)vn1->xs;
				info3dptr[4] = (sint16)vn1->ys;
				info3dptr[5] = vn1->g;
				info3dptr[6] = tex->u1;
				info3dptr[7] = tex->v1;
				
				info3dptr[8] = (sint16)vn2->xs;
				info3dptr[9] = (sint16)vn2->ys;
				info3dptr[10] = vn2->g;
				info3dptr[11] = tex->u2;
				info3dptr[12] = tex->v2;
				
				info3dptr[13] = (sint16)vn3->xs;
				info3dptr[14] = (sint16)vn3->ys;
				info3dptr[15] = vn3->g;
				info3dptr[16] = tex->u3;
				info3dptr[17] = tex->v3;
				
				info3dptr[18] = (sint16)vn4->xs;
				info3dptr[19] = (sint16)vn4->ys;
				info3dptr[20] = vn4->g;
				info3dptr[21] = tex->u4;
				info3dptr[22] = tex->v4;
				
				info3dptr += 23;
				}
			surfacenum++;
			continue;
			}
		
		// Now Insert polygon into Output list (only clipped polys use this bit)
		if (npoints)
			{
			switch (sort_routine)
				{
				case FAR_SORT:
					QUAD_DEPTH_FAR(vn1,vn2,vn3,vn4);
					break;
				case MID_SORT:
					QUAD_DEPTH_MID(vn1,vn2,vn3,vn4);
					break;
				default:
					zdepth = BACK_DEPTH;
				}
			sort3dptr[0] = (sint32)( info3dptr );
			sort3dptr[1] = (sint32)zdepth;
			sort3dptr += 2;

			if ( zdepth<perspective_distance )
				{
				
				/* Perspective texture maps */
				info3dptr[0] = tex->drawtype + (DRAW_POLY_GTMAP_PERSPECTIVE-DRAW_POLY_GTMAP);
				info3dptr[1] = tex->tpage;
				info3dptr[2] = npoints;
				outptr = (OUTPUT_INFO *)(info3dptr+3);
				for (i=npoints, v=v_buffer; i>0; i--, v++, outptr++ )
					{
					outptr->xs = (sint16)v->x;
					outptr->ys = (sint16)v->y;
					outptr->g = (sint16)v->g;
					outptr->ooz   = v->ooz;
					outptr->u   = v->u;
					outptr->v   = v->v;
					}
				info3dptr = (sint16 *)outptr;
				}
			else
				{
				/* Non-perspective texture maps */
				*((uint32 *)info3dptr) = *((uint32 *)&tex->drawtype);
				*(info3dptr+2) = npoints;
				info3dptr+=3;
				for (i=npoints, v=v_buffer; i>0; i--, v++, info3dptr+=5 )
					{
					info3dptr[0] = (sint16)v->x;
					info3dptr[1] = (sint16)v->y;
					info3dptr[2] = (sint16)v->g;
					info3dptr[3] = (sint16)(v->u / v->ooz);
					info3dptr[4] = (sint16)(v->v / v->ooz);
					}
				}
			surfacenum++;
			}
	}
	return (objptr);
}

/******************************************************************************
*			Room Insertion for Texture triangles
*****************************************************************************/
sint16 *ins_objectGT3(sint16 *objptr, int number, enum sort_type sort_routine)
	{
	PHD_VBUF 			*vn1, *vn2, *vn3;
	PHDTEXTURESTRUCT 	*tex;
	OUTPUT_INFO			*outptr;
	VERTEX_INFO			*v;
	POINT_INFO 			point[3], *p;
	int 				i, npoints;
	float zdepth;
	
	for ( ; number>0; number--, objptr+=4)
		{
		vn1 = &vbuf[objptr[0]];
		vn2 = &vbuf[objptr[1]];
		vn3 = &vbuf[objptr[2]];
		if (vn1->clip & vn2->clip & vn3->clip)
			continue;
		
		if ((vn1->clip|vn2->clip|vn3->clip) < 0)
			{
			/* Z-clipped */
			if ( !visible_zclip(vn1,vn2,vn3) )
				continue;
			
			tex = &phdtextinfo[*(objptr+3)];
			p = point;
			p->xv = vn1->xv;
			p->yv = vn1->yv;
			p->zv = vn1->zv;
			p->ooz = vn1->ooz;
			p->xs = vn1->xs;
			p->ys = vn1->ys;
			p->g = float(vn1->g);
			p->u = float(tex->u1);
			p->v = float(tex->v1);
			
			p++;
			p->xv = vn2->xv;
			p->yv = vn2->yv;
			p->zv = vn2->zv;
			p->ooz = vn2->ooz;
			p->xs = vn2->xs;
			p->ys = vn2->ys;
			p->g = float(vn2->g);
			p->u = float(tex->u2);
			p->v = float(tex->v2);
			
			p++;
			p->xv = vn3->xv;
			p->yv = vn3->yv;
			p->zv = vn3->zv;
			p->ooz = vn3->ooz;
			p->xs = vn3->xs;
			p->ys = vn3->ys;
			p->g = float(vn3->g);
			p->u = float(tex->u3);
			p->v = float(tex->v3);
			
			npoints = ZedClipper(3, point, v_buffer);
			if (npoints)
				npoints = XYGUVClipper(npoints, v_buffer);
			}
		else if (vn1->clip|vn2->clip|vn3->clip)
			{
			/* Clipped against edge of screen */
			IF_NOT_VIS( vn1,vn2,vn3 )
				continue;
			
			tex = &phdtextinfo[*(objptr+3)];
			v = v_buffer;
			v->x = vn1->xs;
			v->y = vn1->ys;
			v->ooz = vn1->ooz;
			v->g = float(vn1->g);
			v->u = tex->u1 * v->ooz;
			v->v = tex->v1 * v->ooz;
			
			v++;
			v->x = vn2->xs;
			v->y = vn2->ys;
			v->ooz = vn2->ooz;
			v->g = float(vn2->g);
			v->u = tex->u2 * v->ooz;
			v->v = tex->v2 * v->ooz;
			
			v++;
			v->x = vn3->xs;
			v->y = vn3->ys;
			v->ooz = vn3->ooz;
			v->g = float(vn3->g);
			v->u = tex->u3 * v->ooz;
			v->v = tex->v3 * v->ooz;
			
			npoints = XYGUVClipper(3, v_buffer);
			}
		else
			{
			/* Not clipped */
			IF_NOT_VIS(vn1,vn2,vn3)
				continue;
			
			switch (sort_routine)
				{
				case FAR_SORT:
					TRIA_DEPTH_FAR(vn1,vn2,vn3);
					break;
				case MID_SORT:
					TRIA_DEPTH_MID(vn1,vn2,vn3);
					break;
				default:
					zdepth = BACK_DEPTH;
				}
			sort3dptr[0] = (sint32)(info3dptr);
			sort3dptr[1] = (sint32)zdepth;
			sort3dptr += 2;
			
			tex = &phdtextinfo[objptr[3]];
			if (zdepth<perspective_distance)
				{
				info3dptr[0] = tex->drawtype + (DRAW_POLY_GTMAP_PERSPECTIVE-DRAW_POLY_GTMAP);
				info3dptr[1] = tex->tpage;
				info3dptr[2] = 3;
				
				outptr = (OUTPUT_INFO *)(info3dptr+3);
				outptr[0].xs = (sint16)vn1->xs;
				outptr[0].ys = (sint16)vn1->ys;
				outptr[0].g = vn1->g;
				outptr[0].ooz = vn1->ooz;
				outptr[0].u = tex->u1 * outptr[0].ooz;
				outptr[0].v = tex->v1 * outptr[0].ooz;
				
				outptr[1].xs = (sint16)vn2->xs;
				outptr[1].ys = (sint16)vn2->ys;
				outptr[1].g = vn2->g;
				outptr[1].ooz = vn2->ooz;
				outptr[1].u = tex->u2 * outptr[1].ooz;
				outptr[1].v = tex->v2 * outptr[1].ooz;
				
				outptr[2].xs = (sint16)vn3->xs;
				outptr[2].ys = (sint16)vn3->ys;
				outptr[2].g = vn3->g;
				outptr[2].ooz = vn3->ooz;
				outptr[2].u = tex->u3 * outptr[2].ooz;
				outptr[2].v = tex->v3 * outptr[2].ooz;
				
				info3dptr = (sint16 *)&outptr[3];
				}
			else
				{
				*((uint32 *)info3dptr) = *((uint32 *)&tex->drawtype);
				info3dptr[2] = 3;
				
				info3dptr[3] = (sint16)vn1->xs;
				info3dptr[4] = (sint16)vn1->ys;
				info3dptr[5] = vn1->g;
				info3dptr[6] = tex->u1;
				info3dptr[7] = tex->v1;
				
				info3dptr[8] = (sint16)vn2->xs;
				info3dptr[9] = (sint16)vn2->ys;
				info3dptr[10] = vn2->g;
				info3dptr[11] = tex->u2;
				info3dptr[12] = tex->v2;
				
				info3dptr[13] = (sint16)vn3->xs;
				info3dptr[14] = (sint16)vn3->ys;
				info3dptr[15] = vn3->g;
				info3dptr[16] = tex->u3;
				info3dptr[17] = tex->v3;
				
				info3dptr += 18;
				}
			
			surfacenum++;
			
			continue;
			}
		
		if (npoints)
			{
			switch (sort_routine)
				{
				case FAR_SORT:
					TRIA_DEPTH_FAR(vn1,vn2,vn3);
					break;
				case MID_SORT:
					TRIA_DEPTH_MID(vn1,vn2,vn3);
					break;
				default:
					zdepth = BACK_DEPTH;
				}
			*(sort3dptr) = (sint32)( info3dptr );
			*(sort3dptr+1) = (sint32)zdepth;
			sort3dptr += 2;
			if ( zdepth<perspective_distance )
				{
				*(info3dptr) = tex->drawtype + (DRAW_POLY_GTMAP_PERSPECTIVE-DRAW_POLY_GTMAP);
				*(info3dptr+1) = tex->tpage;
				*(info3dptr+2) = npoints;
				outptr = (OUTPUT_INFO *)(info3dptr+3);
				for (i=0, v=v_buffer; i<npoints; i++, v++, outptr++ )
					{
					outptr->xs = (sint16)v->x;
					outptr->ys = (sint16)v->y;
					outptr->g = (sint16)v->g;
					outptr->ooz = v->ooz;
					outptr->u   = v->u;
					outptr->v   = v->v;
					}
				info3dptr = (sint16 *)outptr;
				}
			else
				{
				*((uint32 *)info3dptr) = *((uint32 *)&tex->drawtype);
				*(info3dptr+2) = npoints;
				info3dptr+=3;
				for (i=0, v=v_buffer; i<npoints; i++, v++, info3dptr+=5 )
					{
					*(info3dptr)   = (sint16)v->x;
					*(info3dptr+1) = (sint16)v->y;
					*(info3dptr+2) = (sint16)v->g;
					*(info3dptr+3) = (sint16)(v->u / v->ooz);
					*(info3dptr+4) = (sint16)(v->v / v->ooz);
					}
				}
			surfacenum++;
			}
	}
	return(objptr);
}

/**********************************************************************************************************
**********************************************************************************************************
*							2D Clipper for X,Y,G
**********************************************************************************************************
*********************************************************************************************************/
extern double chop_temp;
#define BIG_NUM     float ((1 << 26) * ((1 << 26) * 1.5))
#define CHOP(x)     ((chop_temp = x + BIG_NUM), *(int*)(&chop_temp))

#define CLIP_G(OUT, B, A) {\
	OUT.ooz = B->ooz + (A->ooz - B->ooz) * clipper;\
	OUT.vr = CHOP(B->vr + (A->vr - B->vr) * clipper);\
	OUT.vg = CHOP(B->vg + (A->vg - B->vg) * clipper);\
	OUT.vb = CHOP(B->vb + (A->vb - B->vb) * clipper);}

static VERTEX_INFO XYG_output[8];

int XYGClipper( int number, VERTEX_INFO *input)
	{
	/* Clips to X then to Y and returns new number of points: input must be able to hold extra points! */
	int 			i, j;
	VERTEX_INFO 	*A, *B;
	float 			clipper;
	
	/* Clip against X sides */
	B = &input[number-1];
	for (i=j=0; i<number; i++)
		{
		A = B;
		B = &input[i];
		
		/* Clip if point A is off screen */
		if (A->x < phd_leftfloat )
			{
			if (B->x < phd_leftfloat )
				continue;
			
			clipper = (phd_leftfloat - B->x) / (A->x - B->x);
			CLIP_G(XYG_output[j], B, A);
			XYG_output[j].x = phd_leftfloat;
			XYG_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else if (A->x > phd_rightfloat )
			{
			if (B->x > phd_rightfloat )
				continue;
			
			clipper = ( phd_rightfloat - B->x) / (A->x - B->x);
			CLIP_G(XYG_output[j], B, A);
			XYG_output[j].x = phd_rightfloat;
			XYG_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		
		/* Clip if point B is off screen, else add it's point unclipped */
		if (B->x < phd_leftfloat)
			{
			clipper = (phd_leftfloat - B->x) / (A->x - B->x);
			CLIP_G(XYG_output[j], B, A);
			XYG_output[j].x = phd_leftfloat;
			XYG_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else if (B->x > phd_rightfloat)
			{
			clipper = (phd_rightfloat - B->x) / (A->x - B->x);
			CLIP_G(XYG_output[j], B, A);
			XYG_output[j].x = phd_rightfloat;
			XYG_output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else
			{
			/* Not clipped */
			XYG_output[j].x = B->x;
			XYG_output[j].y = B->y;
			XYG_output[j].ooz = B->ooz;
//			XYG_output[j++].g = B->g;
			XYG_output[j].vr = B->vr;
			XYG_output[j].vg = B->vg;
			XYG_output[j].vb = B->vb;
			j++;
			}
		}
	
	/* New number of points in 'output': now clip these against Y */
	if (j < 3)
		return (0);
	number = j;
	
	/* Clip against Y sides */
	B = &XYG_output[number-1];
	for (i=j=0; i<number; i++)
		{
		A = B;
		B = &XYG_output[i];
		
		/* Clip if point A is off screen */
		if (A->y < phd_topfloat )
			{
			if (B->y < phd_topfloat )
				continue;
			
			clipper = (phd_topfloat - B->y) / (A->y - B->y);
			CLIP_G(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_topfloat;
			}
		else if (A->y > phd_bottomfloat )
			{
			if (B->y > phd_bottomfloat )
				continue;
			
			clipper = (phd_bottomfloat - B->y) / (A->y - B->y);
			CLIP_G(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_bottomfloat;
			}
		
		/* Clip if point B is off screen, else add its point unclipped */
		if (B->y < phd_topfloat )
			{
			clipper = (phd_topfloat - B->y) / (A->y - B->y);
			CLIP_G(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_topfloat;
			}
		else if (B->y > phd_bottomfloat )
			{
			clipper = (phd_bottomfloat - B->y) / (A->y - B->y);
			CLIP_G(input[j], B, A);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_bottomfloat;
			}
		else
			{
			/* Unclipped point */
			input[j].x = B->x;
			input[j].y = B->y;
			input[j].ooz = B->ooz;
			input[j].ooz = B->ooz;
//			XYG_output[j++].g = B->g;
			input[j].vr = B->vr;
			input[j].vg = B->vg;
			input[j].vb = B->vb;
			j++;
			}
		}
	
	/* Throw away polygons that have been reduced to lines or less */
	if (j<3)
		return (0);
	
	return (j);
}

/******************************************************************************
*					Insert Object Gourauds
*****************************************************************************/
sint16	*ins_objectG4(sint16 *objptr, int number, enum sort_type sort_routine)
	{
	PHD_VBUF 			*vn1, *vn2, *vn3, *vn4;
	VERTEX_INFO			*v;
	sint16				*outptr;
	int 				i,npoints;
	float 				zdepth;
	POINT_INFO 			point[4], *p;
	
	
	outptr = info3dptr;
	for ( ; number>0; number--, objptr+=5)
		{
		vn1 = &vbuf[*(objptr)];
		vn2 = &vbuf[*(objptr+1)];
		vn3 = &vbuf[*(objptr+2)];
		vn4 = &vbuf[*(objptr+3)];
		if (vn1->clip & vn2->clip & vn3->clip & vn4->clip)
			continue;

		if ((vn1->clip|vn2->clip|vn3->clip|vn4->clip)<0)
		{
			/* Z-clipped */
			if ( !visible_zclip(vn1,vn2,vn3) )
				continue;
			
			p = point;
			p->xv = vn1->xv;
			p->yv = vn1->yv;
			p->zv = vn1->zv;
			p->ooz = vn1->ooz;
			p->xs = vn1->xs;
			p->ys = vn1->ys;
			p->g = float(vn1->g);
			
			p++;
			p->xv = vn2->xv;
			p->yv = vn2->yv;
			p->zv = vn2->zv;
			p->ooz = vn2->ooz;
			p->xs = vn2->xs;
			p->ys = vn2->ys;
			p->g = float(vn2->g);
			
			p++;
			p->xv = vn3->xv;
			p->yv = vn3->yv;
			p->zv = vn3->zv;
			p->ooz = vn3->ooz;
			p->xs = vn3->xs;
			p->ys = vn3->ys;
			p->g = float(vn3->g);
			
			p++;
			p->xv = vn4->xv;
			p->yv = vn4->yv;
			p->zv = vn4->zv;
			p->ooz = vn4->ooz;
			p->xs = vn4->xs;
			p->ys = vn4->ys;
			p->g = float(vn4->g);

			npoints = ZedClipper(4, point, v_buffer);
			if (npoints)
				npoints = XYGClipper(npoints, v_buffer);
		}
		else
		{
			IF_NOT_VIS(vn1,vn2,vn3)
				continue;
		
			v = v_buffer;
			v->x = (float)vn1->xs;
			v->y = (float)vn1->ys;
			v->g = (float)vn1->g;
		
			v++;
			v->x = (float)vn2->xs;
			v->y = (float)vn2->ys;
			v->g = (float)vn2->g;
		
			v++;
			v->x = (float)vn3->xs;
			v->y = (float)vn3->ys;
			v->g = (float)vn3->g;
		
			v++;
			v->x = (float)vn4->xs;
			v->y = (float)vn4->ys;
			v->g = (float)vn4->g;
		
			npoints = 4;
			if ( vn1->clip | vn2->clip | vn3->clip | vn4->clip )
				npoints = XYGClipper( npoints, v_buffer );
		}
		
		// Now Insert polygon into Output list
		if (npoints)
			{
			if (sort_routine==MID_SORT)
				{
				QUAD_DEPTH_MID(vn1,vn2,vn3,vn4);
				}
			else
				zdepth = BACK_DEPTH;
			
			*(sort3dptr) = (sint32)( outptr );
			*(sort3dptr+1) = (sint32)zdepth;
			sort3dptr += 2;
			
			*(outptr) = DRAW_POLY_GOURAUD;
			*(outptr+1) = *(objptr+4) & 0x00ff;				//insert Shade
			*(outptr+2) = npoints;
			outptr+=3;
			for (i=0, v=v_buffer; i<npoints; i++, v++, outptr+=3 )
				{
				*(outptr)   = (sint16)v->x;
				*(outptr+1) = (sint16)v->y;
				*(outptr+2) = (sint16)v->g;
				}
			surfacenum++;
			}
		}
	info3dptr = outptr;
	return (objptr);
	}

	/*****************************************************************************************
	*				Insert Routine for Object Gouraud Triangles
****************************************************************************************/
sint16	*ins_objectG3(sint16 *objptr, int number, enum sort_type sort_routine)
	{
	PHD_VBUF 			*vn1, *vn2, *vn3;
	VERTEX_INFO			*v;
	sint16				*outptr;
	int 				i, npoints;
	float 				zdepth;
	POINT_INFO 			point[3], *p;

	
	outptr = info3dptr;
	for ( ; number>0; number--, objptr+=4)
		{
		vn1 = &vbuf[*(objptr)];
		vn2 = &vbuf[*(objptr+1)];
		vn3 = &vbuf[*(objptr+2)];
		if (vn1->clip & vn2->clip & vn3->clip)
			continue;
		
		if ((vn1->clip|vn2->clip|vn3->clip)<0)
		{
			/* Z-clipped */
			if ( !visible_zclip(vn1,vn2,vn3) )
				continue;
			
			p = point;
			p->xv = vn1->xv;
			p->yv = vn1->yv;
			p->zv = vn1->zv;
			p->ooz = vn1->ooz;
			p->xs = vn1->xs;
			p->ys = vn1->ys;
			p->g = float(vn1->g);
			
			p++;
			p->xv = vn2->xv;
			p->yv = vn2->yv;
			p->zv = vn2->zv;
			p->ooz = vn2->ooz;
			p->xs = vn2->xs;
			p->ys = vn2->ys;
			p->g = float(vn2->g);
			
			p++;
			p->xv = vn3->xv;
			p->yv = vn3->yv;
			p->zv = vn3->zv;
			p->ooz = vn3->ooz;
			p->xs = vn3->xs;
			p->ys = vn3->ys;
			p->g = float(vn3->g);
			
			npoints = ZedClipper(3, point, v_buffer);
			if (npoints)
				npoints = XYGClipper(npoints, v_buffer);
		}
		else
		{
			IF_NOT_VIS( vn1,vn2,vn3 )
				continue;
		
			v = v_buffer;
			v->x = (float)vn1->xs;
			v->y = (float)vn1->ys;
			v->g = (float)vn1->g;
		
			v++;
			v->x = (float)vn2->xs;
			v->y = (float)vn2->ys;
			v->g = (float)vn2->g;
		
			v++;
			v->x = (float)vn3->xs;
			v->y = (float)vn3->ys;
			v->g = (float)vn3->g;
		
			npoints = 3;
			if ( vn1->clip | vn2->clip | vn3->clip )
				npoints = XYGClipper( npoints,v_buffer );
		}
		
		if ( npoints )
			{
			if (sort_routine==MID_SORT)
				{
				TRIA_DEPTH_MID(vn1,vn2,vn3);
				}
			else
				zdepth = BACK_DEPTH;
			
			*(sort3dptr) = (sint32)( outptr );
			*(sort3dptr+1) = (sint32)zdepth;
			sort3dptr += 2;
			
			*(outptr) = DRAW_POLY_GOURAUD;
			*(outptr+1) = *(objptr+3) & 0x00ff;				//insert Shade
			*(outptr+2) = npoints;
			outptr+=3;
			for (i=0, v=v_buffer; i<npoints; i++, v++, outptr+=3 )
				{
				*(outptr)   = (sint16)v->x;
				*(outptr+1) = (sint16)v->y;
				*(outptr+2) = (sint16)v->g;
				}
			surfacenum++;
			}
		}
	info3dptr = outptr;
	return(objptr);
	}

	/**********************************************************************************************************
	**********************************************************************************************************
	*							2D Clipper for X,Y
	**********************************************************************************************************
*********************************************************************************************************/
int 	XYClipper( int number, VERTEX_INFO *input)
	{
	/* Clips to X then to Y and returns new number of points: input must be able to hold extra points! */
	int 			i, j;
	VERTEX_INFO 	output[20], *A, *B;
	float 			clipper;
	
	/* Clip against X sides */
	B = &input[number-1];
	for (i=j=0; i<number; i++)
		{
		A = B;
		B = &input[i];
		
		/* Clip if point A is off screen */
		if (A->x < phd_leftfloat )
			{
			if (B->x < phd_leftfloat )
				continue;
			
			clipper = (phd_leftfloat - B->x) / (A->x - B->x);
			output[j].x = phd_leftfloat;
			output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else if (A->x > phd_rightfloat )
			{
			if (B->x > phd_rightfloat )
				continue;
			
			clipper = ( phd_rightfloat - B->x) / (A->x - B->x);
			output[j].x = phd_rightfloat;
			output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		
		/* Clip if point B is off screen, else add it's point unclipped */
		if (B->x < phd_leftfloat)
			{
			clipper = (phd_leftfloat - B->x) / (A->x - B->x);
			output[j].x = phd_leftfloat;
			output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else if (B->x > phd_rightfloat)
			{
			clipper = (phd_rightfloat - B->x) / (A->x - B->x);
			output[j].x = phd_rightfloat;
			output[j++].y = B->y + (A->y - B->y) * clipper;
			}
		else
			{
			/* Not clipped */
			output[j].x = B->x;
			output[j++].y = B->y;
			}
		}
	
	/* New number of points in 'output': now clip these against Y */
	if (j < 3)
		return (0);
	number = j;
	
	/* Clip against Y sides */
	B = &output[number-1];
	for (i=j=0; i<number; i++)
		{
		A = B;
		B = &output[i];
		
		/* Clip if point A is off screen */
		if (A->y < phd_topfloat )
			{
			if (B->y < phd_topfloat )
				continue;
			
			clipper = (phd_topfloat - B->y) / (A->y - B->y);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_topfloat;
			}
		else if (A->y > phd_bottomfloat )
			{
			if (B->y > phd_bottomfloat )
				continue;
			
			clipper = (phd_bottomfloat - B->y) / (A->y - B->y);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_bottomfloat;
			}
		
		/* Clip if point B is off screen, else add its point unclipped */
		if (B->y < phd_topfloat )
			{
			clipper = (phd_topfloat - B->y) / (A->y - B->y);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_topfloat;
			}
		else if (B->y > phd_bottomfloat )
			{
			clipper = (phd_bottomfloat - B->y) / (A->y - B->y);
			input[j].x = B->x + (A->x - B->x) * clipper;
			input[j++].y = phd_bottomfloat;
			}
		else
			{
			/* Unclipped point */
			input[j].x = B->x;
			input[j++].y = B->y;
			}
		}
	
	/* Throw away polygons that have been reduced to lines or less */
	if (j<3)
		return (0);
	
	return (j);
}

/******************************************************************************
*		INSERT FLAT-SHADED TRANSPARENT POLYGON - 8 VERTICES
*****************************************************************************/
void	ins_poly_trans8( PHD_VBUF *vbuf, sint16 shade )
	{
	PHD_VBUF	*vn1,*vn2,*vn3,*vn4,*vn5,*vn6,*vn7,*vn8;
	VERTEX_INFO	*v;
	int			npoints;
	
	
	vn1 = vbuf;
	vn2 = vbuf+1;
	vn3 = vbuf+2;
	vn4 = vbuf+3;
	vn5 = vbuf+4;
	vn6 = vbuf+5;
	vn7 = vbuf+6;
	vn8 = vbuf+7;
	
	if ( ( vn1->clip & vn2->clip & vn3->clip & vn4->clip & vn5->clip & vn6->clip & vn7->clip & vn8->clip  ) ||
	       vn1->clip<0 || vn2->clip<0 || vn3->clip<0 || vn4->clip<0 || vn5->clip<0 || vn6->clip<0 || vn7->clip<0 || vn8->clip<0 )
		   return;
	
	IF_NOT_VIS(vn1,vn2,vn3)
		return;
	
	
	if ( (vn1->clip|vn2->clip|vn3->clip|vn4->clip|vn5->clip|vn6->clip|vn7->clip|vn8->clip)==0 )
		{
		*(sort3dptr) = (sint32)( info3dptr );		//insert pointer to info
		*(sort3dptr+1) = (sint32)(vn1->zv/8 + vn2->zv/8 + vn3->zv/8 + vn4->zv/8 + vn5->zv/8 + vn6->zv/8 + vn7->zv/8 + vn8->zv/8);
		sort3dptr += 2;
		*(info3dptr+0)  = DRAW_POLY_TRANS;
		*(info3dptr+1) = shade;		        		//insert Color
		*(info3dptr+2)  = 8;						//8 coords
		*(info3dptr+3)  = (sint16)vn1->xs;
		*(info3dptr+4)  = (sint16)vn1->ys;
		*(info3dptr+5)  = (sint16)vn2->xs;
		*(info3dptr+6)  = (sint16)vn2->ys;
		*(info3dptr+7)  = (sint16)vn3->xs;
		*(info3dptr+8)  = (sint16)vn3->ys;
		*(info3dptr+9)  = (sint16)vn4->xs;
		*(info3dptr+10) = (sint16)vn4->ys;
		*(info3dptr+11) = (sint16)vn5->xs;
		*(info3dptr+12) = (sint16)vn5->ys;
		*(info3dptr+13) = (sint16)vn6->xs;
		*(info3dptr+14) = (sint16)vn6->ys;
		*(info3dptr+15) = (sint16)vn7->xs;
		*(info3dptr+16) = (sint16)vn7->ys;
		*(info3dptr+17) = (sint16)vn8->xs;
		*(info3dptr+18) = (sint16)vn8->ys;
		info3dptr += 19;
		surfacenum++;
		}
	else
		{
		phd_leftfloat = phd_topfloat = 0.0f;
		phd_rightfloat = (float)phd_winxmax;
		phd_bottomfloat = (float)phd_winymax;
		
		v = v_buffer;
		v->x = (float)vn1->xs;
		v->y = (float)vn1->ys;
		v++;
		v->x = (float)vn2->xs;
		v->y = (float)vn2->ys;
		v++;
		v->x = (float)vn3->xs;
		v->y = (float)vn3->ys;
		v++;
		v->x = (float)vn4->xs;
		v->y = (float)vn4->ys;
		v++;
		v->x = (float)vn5->xs;
		v->y = (float)vn5->ys;
		v++;
		v->x = (float)vn6->xs;
		v->y = (float)vn6->ys;
		v++;
		v->x = (float)vn7->xs;
		v->y = (float)vn7->ys;
		v++;
		v->x = (float)vn8->xs;
		v->y = (float)vn8->ys;
		
		npoints = XYClipper( 8,v_buffer );
		if ( npoints )
			{
			*(sort3dptr) = (sint32)( info3dptr );		//insert pointer to info
			*(sort3dptr+1) = (sint32)(vn1->zv/8 + vn2->zv/8 + vn3->zv/8 + vn4->zv/8 + vn5->zv/8 + vn6->zv/8 + vn7->zv/8 + vn8->zv/8);
			sort3dptr += 2;
			*(info3dptr+0)  = DRAW_POLY_TRANS;
			*(info3dptr+1) = shade;		        		// insert Color
			*(info3dptr+2)  = npoints;					// number coords
			info3dptr+=3;
			for ( v=v_buffer;npoints>0;npoints--,info3dptr+=2,v++ )
				{
				*(info3dptr) = (sint16)v->x;
				*(info3dptr+1) = (sint16)v->y;
				}
			surfacenum++;
			}
		}
	return;
	}


void ins_trans_quad(sint32 sx,sint32 sy,sint32 w,sint32 h,sint32 z)
	{
	*(sort3dptr) = (sint32)(info3dptr);
	*(sort3dptr+1) = phd_znear+(z<<3);
	sort3dptr += 2;

	*(info3dptr) = DRAW_POLY_TRANS;
	*(info3dptr+1) = 32;	// 32 is special transparent depthq table
	*(info3dptr+2) = 4;
	*(info3dptr+3) = (sint16)sx;
	*(info3dptr+4) = (sint16)sy;
	*(info3dptr+5) = (sint16)(sx+w);
	*(info3dptr+6) = (sint16)sy;
	*(info3dptr+7) = (sint16)(sx+w);
	*(info3dptr+8) = (sint16)(sy+h);
	*(info3dptr+9) = (sint16)sx;
	*(info3dptr+10) = (sint16)(sy+h);
	info3dptr += 11;
	surfacenum++;
	}


// This used to be S_InsertBackPolygon
void ins_flat_rect(sint32 min_x,sint32 min_y,sint32 max_x,sint32 max_y,int z,int colour)
	{
	*(sort3dptr+0)=(sint32)(info3dptr);
	*(sort3dptr+1)=z;
	sort3dptr+=2;

	*(info3dptr)=DRAW_POLY_FLAT;
	*(info3dptr+1)=(sint16)colour;
	*(info3dptr+2)=4;
	*(info3dptr+3)=(sint16)min_x;
	*(info3dptr+4)=(sint16)min_y;
	*(info3dptr+5)=(sint16)max_x;
	*(info3dptr+6)=(sint16)min_y;
	*(info3dptr+7)=(sint16)max_x;
	*(info3dptr+8)=(sint16)max_y;
	*(info3dptr+9)=(sint16)min_x;
	*(info3dptr+10)=(sint16)max_y;
	info3dptr+=11;
	++surfacenum;
	}

void ins_line(sint32 x1,sint32 y1,sint32 x2,sint32 y2,sint32 z,char color)
	{
	*(sort3dptr+0)=(sint32)(info3dptr);		// insert pointer to info
	*(sort3dptr+1)=z;                    	// insert max zdepth
	sort3dptr+=2;
	*(info3dptr+0)=DRAW_POLY_LINE;
	*(info3dptr+1)=(sint16)(x1+phd_winxmin);				// insert X1
	*(info3dptr+2)=(sint16)(y1+phd_winymin);	    		// insert Y1
	*(info3dptr+3)=(sint16)(x2+phd_winxmin);	    		// insert X2
	*(info3dptr+4)=(sint16)(y2+phd_winymin);	    		// insert Y2
	*(info3dptr+5)=(sint16)color;			// insert Color
	info3dptr+=6;
	++surfacenum;
	}	

	
	
	//-------------------------------------------------------------------------------------------------------------------------
	//-------------------------------------- SubDivision With Clipping --------------------------------------------------------
	//-------------------------------------------------------------------------------------------------------------------------
#if 0
	
	
	
	sint16	subdivide_tpage;
	sint16	subdivide_draw_type;
	int		subdivide_distance1 = ((3*1024)<<W2V_SHIFT);
	int		subdivide_distance2 = ((1*1024)<<W2V_SHIFT);
	int		subdivide_distance3 = ((0*1024)<<W2V_SHIFT);
	
	
	/******************************************************************************
	*			Room Insertion for TextureQuads
	*****************************************************************************/
	sint16 *ins_roomGT4sub(sint16 *objptr, int number)
		{
		PHD_VBUF 			*vn1, *vn2, *vn3, *vn4;
		PHDTEXTURESTRUCT 	*tex;
		VERTEX_INFO 		*v;
		POINT_INFO			point[4], *p;
		OUTPUT_INFO 		*outptr;
		int 				i,npoints;
		sint32 				zdepth;
		int					level;
		
		
		for ( ; number>0; number--, objptr+=5)
			{
			vn1 = &vbuf[*(objptr)];
			vn2 = &vbuf[*(objptr+1)];
			vn3 = &vbuf[*(objptr+2)];
			vn4 = &vbuf[*(objptr+3)];
			if ( vn1->clip & vn2->clip & vn3->clip & vn4->clip )
				continue;
			
			QUAD_DEPTH_NEAR(vn1,vn2,vn3,vn4)
				if ( zdepth<subdivide_distance1 )
					{
					if ( !visible_zclip( vn1,vn2,vn3 ) )
						continue;
					level = 1;
					if ( zdepth<subdivide_distance2 )
						{
						if ( zdepth<subdivide_distance3 )
							level = 3;
						else
							level = 2;
						}
					tex = &phdtextinfo[*(objptr+4)];
					vn1->u = tex->u1;
					vn1->v = tex->v1;
					vn2->u = tex->u2;
					vn2->v = tex->v2;
					vn3->u = tex->u3;
					vn3->v = tex->v3;
					vn4->u = tex->u4;
					vn4->v = tex->v4;
					subdivide_tpage = tex->tpage;
					subdivide_draw_type = tex->drawtype;
					subdivide_gt4far( vn1,vn2,vn3,vn4,level );
					}
				
				if ( vn1->clip<0 || vn2->clip<0 || vn3->clip<0 || vn4->clip<0 )
					{
					if ( !visible_zclip(vn1,vn2,vn3))
						continue;
					
					tex = &phdtextinfo[*(objptr+4)];
					p = point;
					p->xv = (float)vn1->xv;
					p->yv = (float)vn1->yv;
					p->zv = (float)vn1->zv;
					p->xs = (float)vn1->xs;
					p->ys = (float)vn1->ys;
					p->shade = (float)vn1->shade;
					p->u = (float)tex->u1;
					p->v = (float)tex->v1;
					
					p++;
					p->xv = (float)vn2->xv;
					p->yv = (float)vn2->yv;
					p->zv = (float)vn2->zv;
					p->xs = (float)vn2->xs;
					p->ys = (float)vn2->ys;
					p->shade = (float)vn2->shade;
					p->u = (float)tex->u2;
					p->v = (float)tex->v2;
					
					p++;
					p->xv = (float)vn3->xv;
					p->yv = (float)vn3->yv;
					p->zv = (float)vn3->zv;
					p->xs = (float)vn3->xs;
					p->ys = (float)vn3->ys;
					p->shade = (float)vn3->shade;
					p->u = (float)tex->u3;
					p->v = (float)tex->v3;
					
					p++;
					p->xv = (float)vn4->xv;
					p->yv = (float)vn4->yv;
					p->zv = (float)vn4->zv;
					p->xs = (float)vn4->xs;
					p->ys = (float)vn4->ys;
					p->shade = (float)vn4->shade;
					p->u = (float)tex->u4;
					p->v = (float)tex->v4;
					
					npoints = ZedClipper(4, point, v_buffer);
					if (npoints)
						npoints = XYGUVClipper(npoints, v_buffer);
					}
				else
					{
					IF_NOT_VIS(vn1,vn2,vn3)
						continue;
					
					tex = &phdtextinfo[*(objptr+4)];
					v = v_buffer;
					v->x = (float)vn1->xs;
					v->y = (float)vn1->ys;
					v->ooz = one / vn1->zv;
					v->g = (float)vn1->shade;
					v->u = tex->u1 * v->ooz;
					v->v = tex->v1 * v->ooz;
					
					v++;
					v->x = (float)vn2->xs;
					v->y = (float)vn2->ys;
					v->ooz = one / vn2->zv;
					v->g = (float)vn2->shade;
					v->u = tex->u2 * v->ooz;
					v->v = tex->v2 * v->ooz;
					
					v++;
					v->x = (float)vn3->xs;
					v->y = (float)vn3->ys;
					v->ooz = one / vn3->zv;
					v->g = (float)vn3->shade;
					v->u = tex->u3 * v->ooz;
					v->v = tex->v3 * v->ooz;
					
					v++;
					v->x = (float)vn4->xs;
					v->y = (float)vn4->ys;
					v->ooz = one / vn4->zv;
					v->g = (float)vn4->shade;
					v->u = tex->u4 * v->ooz;
					v->v = tex->v4 * v->ooz;
					
					npoints = 4;
					if ( vn1->clip || vn2->clip || vn3->clip || vn4->clip )
						npoints = XYGUVClipper( npoints, v_buffer );
					}
				
				// Now Insert polygon into Output list
				if (npoints)
					{
					QUAD_DEPTH_FAR(vn1,vn2,vn3,vn4)
						*(sort3dptr) = (sint32)( info3dptr );
					*(sort3dptr+1) = zdepth;
					sort3dptr += 2;
					if ( zdepth<perspective_distance )
						{
						*(info3dptr) = tex->drawtype + (DRAW_POLY_GTMAP_PERSPECTIVE-DRAW_POLY_GTMAP);
						*(info3dptr+1) = tex->tpage;
						*(info3dptr+2) = npoints;
						outptr = (OUTPUT_INFO *)(info3dptr+3);
						for (i=0, v=v_buffer; i<npoints; i++, v++, outptr++ )
							{
							outptr->xs    = v->x;
							outptr->ys    = v->y;
							outptr->shade = v->g;
							//					outptr->ooz   = v->ooz/256.0;
							outptr->ooz   = v->ooz;
							outptr->u   = v->u;
							outptr->v   = v->v;
							}
						info3dptr = (sint16 *)outptr;
						}
					else
						{
						*((uint32 *)info3dptr) = *((uint32 *)&tex->drawtype);
						*(info3dptr+2) = npoints;
						info3dptr+=3;
						for (i=0, v=v_buffer; i<npoints; i++, v++, info3dptr+=5 )
							{
							*(info3dptr)   = v->x;
							*(info3dptr+1) = v->y;
							*(info3dptr+2) = v->g;
							*(info3dptr+3) = v->u / v->ooz;
							*(info3dptr+4) = v->v / v->ooz;
							}
						}
					surfacenum++;
					}
	}
	return (objptr);
}

/******************************************************************************
*				SubDivide Texture ala Playstation
*                 Using Recursive subdivide...
*
*            0--A--1
*            |  |  |
*            B--C--D
*			  |  |  |
*            4--E--3
*
*
*****************************************************************************/
void	subdivide_gt4far( PHD_VBUF *v1, PHD_VBUF *v2, PHD_VBUF *v3, PHD_VBUF *v4, int level )
	{
	
	if ( v1->zv<phd_znear && v2->zv<phd_znear && v3->zv<phd_znear && v4->zv<phd_znear )
		return;
	
	if ( level>0 )
		{
		PHD_VBUF vA,vB,vC,vD,vE;
		
		level--;
		vA.xv = (v1->xv + v2->xv)/2;
		vA.yv = (v1->yv + v2->yv)/2;
		vA.zv = (v1->zv + v2->zv)/2;
		vA.u  = (v1->u + v2->u)/2;
		vA.v  = (v1->v + v2->v)/2;
		vA.shade = (v1->shade + v2->shade)/2;
		vB.xv = (v1->xv + v4->xv)/2;
		vB.yv = (v1->yv + v4->yv)/2;
		vB.zv = (v1->zv + v4->zv)/2;
		vB.u  = (v1->u + v4->u)/2;
		vB.v  = (v1->v + v4->v)/2;
		vB.shade = (v1->shade + v4->shade)/2;
		vC.xv = (v1->xv + v2->xv + v3->xv + v4->xv)/4;
		vC.yv = (v1->yv + v2->yv + v3->yv + v4->yv)/4;
		vC.zv = (v1->zv + v2->zv + v3->zv + v4->zv)/4;
		vC.u  = (v1->u + v2->u + v3->u + v4->u)/4;
		vC.v  = (v1->v + v2->v + v3->v + v4->v)/4;
		vC.shade = (v1->shade + v2->shade + v3->shade + v4->shade)/4;
		vD.xv = (v2->xv + v3->xv)/2;
		vD.yv = (v2->yv + v3->yv)/2;
		vD.zv = (v2->zv + v3->zv)/2;
		vD.u  = (v2->u + v3->u)/2;
		vD.v  = (v2->v + v3->v)/2;
		vD.shade = (v2->shade + v3->shade)/2;
		vE.xv = (v3->xv + v4->xv)/2;
		vE.yv = (v3->yv + v4->yv)/2;
		vE.zv = (v3->zv + v4->zv)/2;
		vE.u  = (v3->u + v4->u)/2;
		vE.v  = (v3->v + v4->v)/2;
		vE.shade = (v3->shade + v4->shade)/2;
		
		subdivide_gt4far( v1,&vA,&vC,&vB,level );
		subdivide_gt4far( &vA,v2,&vD,&vC,level );
		subdivide_gt4far( &vB,&vC,&vE,v4,level );
		subdivide_gt4far( &vC,&vD,v3,&vE,level );
		}
	else
		{
		int		xmin,xmax,ymin,ymax;
		int		x1,y1,x2,y2,x3,y3,x4,y4;
		int		zdepth;
		int		npoints;
		VERTEX_INFO	*v;
		
		zdepth = v1->zv;
		if ( zdepth<phd_znear )
			zdepth = phd_znear;
		zdepth /= phd_persp;
		x1 = v1->xv/zdepth + phd_centerx;
		xmin = xmax = x1;
		y1 = v1->yv/zdepth + phd_centery;
		ymin = ymax = y1;
		
		zdepth = v2->zv;
		if ( zdepth<phd_znear )
			zdepth = phd_znear;
		zdepth /= phd_persp;
		x2 = v2->xv/zdepth + phd_centerx;
		if ( x2<xmin ) xmin = x2;
		if ( x2>xmax ) xmax = x2;
		y2 = v2->yv/zdepth + phd_centery;
		if ( y2<ymin ) ymin = y2;
		if ( y2>ymax ) ymax = y2;
		
		zdepth = v3->zv;
		if ( zdepth<phd_znear )
			zdepth = phd_znear;
		zdepth /= phd_persp;
		x3 = v3->xv/zdepth + phd_centerx;
		if ( x3<xmin ) xmin = x3;
		if ( x3>xmax ) xmax = x3;
		y3 = v3->yv/zdepth + phd_centery;
		if ( y3<ymin ) ymin = y3;
		if ( y3>ymax ) ymax = y3;
		
		zdepth = v4->zv;
		if ( zdepth<phd_znear )
			zdepth = phd_znear;
		zdepth /= phd_persp;
		x4 = v4->xv/zdepth + phd_centerx;
		if ( x4<xmin ) xmin = x4;
		if ( x4>xmax ) xmax = x4;
		y4 = v4->yv/zdepth + phd_centery;
		if ( y4<ymin ) ymin = y4;
		if ( y4>ymax ) ymax = y4;
		
		if ( xmax<phd_left || xmin>phd_right || ymax<phd_top || ymin>phd_bottom )
			return;
		
		if ( xmin>=phd_left && xmax<=phd_right && ymin>=phd_top && ymax<=phd_bottom )
			{
			QUAD_DEPTH_FAR(v1,v2,v3,v4)
				*(sort3dptr) = (sint32)( info3dptr );	  	// insert pointer to info
			*(sort3dptr+1) = zdepth;                  	// insert max zdepth
			sort3dptr += 2;
			
			*(info3dptr) = subdivide_draw_type;			// Draw Type
			*(info3dptr+1) = subdivide_tpage;			// Texture page
			*(info3dptr+2)  = 4;						// 4 coords
			*(info3dptr+3)  = x1;  						// insert X1
			*(info3dptr+4)  = y1;  						// insert Y1
			*(info3dptr+5)  = v1->shade; 				// insert Shade1
			*(info3dptr+6)  = v1->u;				  	// insert U1
			*(info3dptr+7)  = v1->v;              	  	// insert V1
			
			*(info3dptr+8)  = x2;  						// insert X2
			*(info3dptr+9)  = y2;  						// insert Y2
			*(info3dptr+10)  = v2->shade; 				// insert Shade2
			*(info3dptr+11) = v2->u;				  	// insert U2
			*(info3dptr+12) = v2->v;              	  	// insert V2
			
			*(info3dptr+13) = x3;  						// insert X3
			*(info3dptr+14) = y3;  						// insert Y3
			*(info3dptr+15) = v3->shade; 				// insert Shade3
			*(info3dptr+16) = v3->u;				  	// insert U3
			*(info3dptr+17) = v3->v;                	// insert V3
			
			*(info3dptr+18) = x4;  						// insert X4
			*(info3dptr+19) = y4;  						// insert Y4
			*(info3dptr+20) = v4->shade; 				// insert Shade4
			*(info3dptr+21) = v4->u;				  	// insert U4
			*(info3dptr+22) = v4->v;                	// insert V4
			
			info3dptr += 23;
			surfacenum++;
			}
		else
			{
			v = v_buffer;
			v->x = (float)x1;
			v->y = (float)y1;
			v->ooz = one / v1->zv;
			v->g = (float)v1->shade;
			v->u = v1->u * v->ooz;
			v->v = v1->v * v->ooz;
			
			v++;
			v->x = (float)x2;
			v->y = (float)y2;
			v->ooz = one / v2->zv;
			v->g = (float)v2->shade;
			v->u = v2->u * v->ooz;
			v->v = v2->v * v->ooz;
			
			v++;
			v->x = (float)x3;
			v->y = (float)y3;
			v->ooz = one / v3->zv;
			v->g = (float)v3->shade;
			v->u = v3->u * v->ooz;
			v->v = v3->v * v->ooz;
			
			v++;
			v->x = (float)x4;
			v->y = (float)y4;
			v->ooz = one / v4->zv;
			v->g = (float)v4->shade;
			v->u = v4->u * v->ooz;
			v->v = v4->v * v->ooz;
			
			npoints = XYGUVClipper( 4, v_buffer );
			
			if (npoints)
				{
				QUAD_DEPTH_FAR(v1,v2,v3,v4)
					*(sort3dptr) = (sint32)( info3dptr );
				*(sort3dptr+1) = zdepth;
				sort3dptr += 2;
				*(info3dptr) = subdivide_draw_type;
				*(info3dptr+1) = subdivide_tpage;
				*(info3dptr+2) = npoints;
				info3dptr+=3;
				for ( v=v_buffer; npoints>0; npoints--, v++, info3dptr+=5 )
					{
					*(info3dptr)   = v->x;
					*(info3dptr+1) = v->y;
					*(info3dptr+2) = v->g;
					*(info3dptr+3) = v->u / v->ooz;
					*(info3dptr+4) = v->v / v->ooz;
					}
				surfacenum++;
				}
			}
	}
	
}
#endif
