#include "ui.h"


static float dizdx=0.0f, duizdx=0.0f, dvizdx=0.0f, dizdy=0.0f, duizdy=0.0f, dvizdy=0.0f;
static float xa=0.0f, xb=0.0f, iza=0.0f, uiza=0.0f, viza=0.0f;
static float dxdya=0.0f, dxdyb=0.0f, dizdya=0.0f, duizdya=0.0f, dvizdya=0.0f;
static char *texture;

static char drawtpolyperspsubtriseg(int y1, int y2, SDL_Surface *screen, SDL_Surface *texture );

void StretchBlit( SDL_Surface *scr, SDL_Surface *texture, int x, int y, int w, int h )
{
	TPolytri poly;

	if( !x )
    	poly.x1 = 0;
	else
    	poly.x1 = (float)x;
	if( !w )
    	poly.x2 = (float)scr->w;
	else
    	poly.x2 = (float)w;
	if( !w )
    	poly.x3 = (float)scr->w;
	else
    	poly.x3 = (float)w;


	if( !y )
    	poly.y1 = 0;
	else
    	poly.y1 = (float)y;
	if( !y )
    	poly.y2 = 0;
	else
    	poly.y2 = (float)y;
	if( !h )
    	poly.y3 = (float)scr->h;
	else
    	poly.y3 = (float)h;

	poly.z1 = 1;
	poly.z2 = 1;
	poly.z3 = 1;

	poly.u1 = 0;
	poly.u2 = (float)texture->w;
	poly.u3 = (float)texture->w;

	poly.v1 = 0;
	poly.v2 = 0;
	poly.v3 = (float)texture->h;

	drawtpolyperspsubtri( &poly, scr, texture );

	if( !x )
    	poly.x1 = 0;
	else
    	poly.x1 = (float)x;

	if( !w )
    	poly.x2 = (float)scr->w;
	else
    	poly.x2 = (float)w;

	if( !x )
    	poly.x3 = 0;
	else
    	poly.x3 = (float)x;


	if( !y )
    	poly.y1 = 0;
	else
    	poly.y1 = (float)y;

	if( !h )
    	poly.y2 = (float)scr->h;
	else
    	poly.y2 = (float)h;

	if( !h )
    	poly.y3 = (float)scr->h;
	else
    	poly.y3 = (float)h;


	poly.z1 = 1;
	poly.z2 = 1;
	poly.z3 = 1;

	poly.u1 = 0;
	poly.u2 = (float)texture->w;
	poly.u3 = 0;

	poly.v1 = 0;
	poly.v2 = (float)texture->h;
	poly.v3 = (float)texture->h;

	drawtpolyperspsubtri( &poly, scr, texture );
}

char drawtpolyperspsubtri(TPolytri *poly, SDL_Surface *screen, SDL_Surface *texture )
{
	float x1=0.0f, y1=0.0f, x2=0.0f, y2=0.0f, x3=0.0f, y3=0.0f;
	float iz1=0.0f, uiz1=0.0f, viz1=0.0f, iz2=0.0f, uiz2=0.0f, viz2=0.0f, iz3=0.0f, uiz3=0.0f, viz3=0.0f;
	float dxdy1=0.0f, dxdy2=0.0f, dxdy3=0.0f;
	float tempf=0.0f;
	float denom=0.0f;
	float dy=0.0f;
	int y1i, y2i, y3i;
	int side;
	char crash=0;


	x1 = (float)poly->x1 + 0.5f;
	y1 = (float)poly->y1 + 0.5f;
	x2 = (float)poly->x2 + 0.5f;
	y2 = (float)poly->y2 + 0.5f;
	x3 = (float)poly->x3 + 0.5f;
	y3 = (float)poly->y3 + 0.5f;


	if( poly->z1 )
		iz1 = 1 / poly->z1;
	else
		iz1 = 0.0f;


	if( poly->z2 )
		iz2 = 1 / poly->z2;
	else
		iz2 = 0.0f;
	if( poly->z3 )
		iz3 = 1 / poly->z3;
	else
		iz3 = 0.0f;
	uiz1 = poly->u1 * iz1;
	viz1 = poly->v1 * iz1;
	uiz2 = poly->u2 * iz2;
	viz2 = poly->v2 * iz2;
	uiz3 = poly->u3 * iz3;
	viz3 = poly->v3 * iz3;

#define swapfloat(x, y) tempf = x; x = y; y = tempf;
	if (y1 > y2)
	{
		swapfloat(x1, x2);
		swapfloat(y1, y2);
		swapfloat(iz1, iz2);
		swapfloat(uiz1, uiz2);
		swapfloat(viz1, viz2);
	}
	if (y1 > y3)
	{
		swapfloat(x1, x3);
		swapfloat(y1, y3);
		swapfloat(iz1, iz3);
		swapfloat(uiz1, uiz3);
		swapfloat(viz1, viz3);
	}
	if (y2 > y3)
	{
		swapfloat(x2, x3);
		swapfloat(y2, y3);
		swapfloat(iz2, iz3);
		swapfloat(uiz2, uiz3);
		swapfloat(viz2, viz3);
	}
#undef swapfloat

	y1i = (int)y1;
	y2i = (int)y2;
	y3i = (int)y3;

	if ((y1i == y2i && y1i == y3i)
	    || ((int) x1 == (int) x2 && (int) x1 == (int) x3))
		return crash;

	denom = ((x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1));

	if (!denom)		
		return crash;	

	denom = 1 / denom;	
	dizdx = ((iz3 - iz1) * (y2 - y1) - (iz2 - iz1) * (y3 - y1)) * denom;
	duizdx = ((uiz3 - uiz1) * (y2 - y1) - (uiz2 - uiz1) * (y3 - y1)) * denom;
	dvizdx = ((viz3 - viz1) * (y2 - y1) - (viz2 - viz1) * (y3 - y1)) * denom;
	dizdy = ((iz2 - iz1) * (x3 - x1) - (iz3 - iz1) * (x2 - x1)) * denom;
	duizdy = ((uiz2 - uiz1) * (x3 - x1) - (uiz3 - uiz1) * (x2 - x1)) * denom;
	dvizdy = ((viz2 - viz1) * (x3 - x1) - (viz3 - viz1) * (x2 - x1)) * denom;


	if (y2 > y1)
		dxdy1 = (x2 - x1) / (y2 - y1);
	if (y3 > y1)
		dxdy2 = (x3 - x1) / (y3 - y1);
	if (y3 > y2)
		dxdy3 = (x3 - x2) / (y3 - y2);


	side = dxdy2 > dxdy1;

	if (y1 == y2)
		side = x1 > x2;
	if (y2 == y3)
		side = x3 > x2;

	if (!side)	// Longer edge is on the left side
	{
		dxdya = dxdy2;
		dizdya = dxdy2 * dizdx + dizdy;
		duizdya = dxdy2 * duizdx + duizdy;
		dvizdya = dxdy2 * dvizdx + dvizdy;

		dy = 1 - (y1 - y1i);
		xa = x1 + dy * dxdya;
		iza = iz1 + dy * dizdya;
		uiza = uiz1 + dy * duizdya;
		viza = viz1 + dy * dvizdya;

		if (y1i < y2i)	// Draw upper segment if possibly visible
		{
			xb = x1 + dy * dxdy1;
			dxdyb = dxdy1;

			crash |= drawtpolyperspsubtriseg(y1i, y2i, screen, texture );
		}
		if (y2i < y3i)	// Draw lower segment if possibly visible
		{
			xb = x2 + (1 - (y2 - y2i)) * dxdy3;
			dxdyb = dxdy3;

			crash |= drawtpolyperspsubtriseg(y2i, y3i, screen, texture );
		}
	}
	else	// Longer edge is on the right side
	{
		dxdyb = dxdy2;
		dy = 1 - (y1 - y1i);
		xb = x1 + dy * dxdyb;

		if (y1i < y2i)	// Draw upper segment if possibly visible
		{
			dxdya = dxdy1;
			dizdya = dxdy1 * dizdx + dizdy;
			duizdya = dxdy1 * duizdx + duizdy;
			dvizdya = dxdy1 * dvizdx + dvizdy;
			xa = x1 + dy * dxdya;
			iza = iz1 + dy * dizdya;
			uiza = uiz1 + dy * duizdya;
			viza = viz1 + dy * dvizdya;

			crash |= drawtpolyperspsubtriseg(y1i, y2i, screen, texture );
		}
		if (y2i < y3i)	// Draw lower segment if possibly visible
		{
			dxdya = dxdy3;
			dizdya = dxdy3 * dizdx + dizdy;
			duizdya = dxdy3 * duizdx + duizdy;
			dvizdya = dxdy3 * dvizdx + dvizdy;
			dy = 1 - (y2 - y2i);
			xa = x2 + dy * dxdya;
			iza = iz2 + dy * dizdya;
			uiza = uiz2 + dy * duizdya;
			viza = viz2 + dy * dvizdya;

			crash |= drawtpolyperspsubtriseg(y2i, y3i, screen, texture );
		}
	}
	return crash;
}

static char drawtpolyperspsubtriseg(int y1, int y2, SDL_Surface *screen, SDL_Surface *texture )
{
	DWORD *scr;
	int x1, x2;
	float z=0.0f, u=0.0f, v=0.0f, dx=0.0f;
	float iz=0.0f, uiz=0.0f, viz=0.0f;
	char crashdetection=0;

	while (y1 <  y2)		// Loop through all lines in the segment
	{
		x1 = (int)xa;
		x2 = (int)xb;

		dx = 1 - (xa - x1);
		iz = iza + dx * dizdx;
		uiz = uiza + dx * duizdx;
		viz = viza + dx * dvizdx;
	
		if(( y1 < screen->h ) && ( y1 > 0 ))
		{
			scr = (DWORD*)&((DWORD*)(screen->pixels))[(y1 * screen->pitch>>2) + x1];
			
			while (x1++ < x2)	// Draw horizontal line
			{
				u = uiz;// * z;
				v = viz;// * z;
				if(( x1 < screen->w ) && ( x1 > 0 ))
				{
					int vv = min( (int)v, texture->h-1 );
					int uu = min( (int)u, texture->w-1 );
					
					DWORD texel = ((DWORD*)texture->pixels)[((vv)  * (texture->pitch>>2)) + (uu)];
					if( texel && (texel >>24) )
						*(scr++) = texel;
					else
						scr++;
				}
				else
					scr++;
				uiz += duizdx;
				viz += dvizdx;
			}
		}
		xa += dxdya;
		xb += dxdyb;
		iza += dizdya;
		uiza += duizdya;
		viza += dvizdya;

		y1++;
	}
	return crashdetection; 
}
