#include "glover.h"

WINDLIST windList;

void windInitialise(void)
{
	windList.head.next = windList.head.prev = &windList.head;
	windList.numEntries = 0;
}

// Checks integrity of wind linked list
void windVerify(void)
{
	WIND_DEFSTR *ptr;
	int c=0;

	for(ptr = windList.head.next;ptr != &windList.head;ptr = ptr->next)
	{
		ASSERT(ptr);
		c++;
	}

	ASSERT(c==windList.numEntries);
}

void windClearUpMessAfterwards(void)
{
	WIND_DEFSTR *ptr;

	windVerify();
	
	for(ptr = windList.head.next; ptr != &windList.head; ptr = ptr->next)
	{
		ptr->prev->next = ptr->next;
		ptr->next->prev = ptr->prev;
		windList.numEntries--;

		FREE(ptr);
	}

	ASSERT(windList.numEntries==0);
}

WIND_DEFSTR *windCreate(void)
{
	WIND_DEFSTR *ptr;
	WIND_DEFSTR *pWind;
	int nParticles=33;

	size_t sizeParticles, sizeDepths;

	sizeParticles=	sizeof(VERT)*nParticles;
	sizeDepths=		sizeof(long)*nParticles; // also size of scrXY

	pWind=MALLOC(sizeof(WIND_DEFSTR)+sizeParticles+sizeDepths+sizeDepths, "Wind");
	pWind->nParticles=nParticles;

	DB("Creating wind. # of particles = %d\n", pWind->nParticles);

	windVerify();

	ptr=windList.head.next;

	pWind->next = ptr;
	pWind->prev = ptr->prev;
	ptr->prev->next = pWind;
	ptr->prev = pWind;
	windList.numEntries++;

	pWind->pParticles=	(VERT *)(((size_t)pWind)+sizeof(WIND_DEFSTR));
	pWind->pDepths=		(long *)(((size_t)pWind->pParticles)+sizeParticles);
	pWind->pScrXY=		(long *)(((size_t)pWind->pDepths)+sizeDepths);

	return pWind;
}

int windUpdateObject(COLLDATA *pColl, WIND_DEFSTR *ptr)
{
	int ret=FALSE;
	VECTOR temp;

	temp.vx=pColl->pPos->vx/4096;
	temp.vy=pColl->pPos->vy/4096;
	temp.vz=pColl->pPos->vz/4096;

	if(isObjectInBox(&ptr->pos, &ptr->size, &temp))
	{
		// we need to treat the y differently from the x & z.
		// for x&z, add to position,
		// for y add to velocity

		ret=TRUE;

		if(ptr->dir.vy) // do y
		{
			pColl->pVel->vy+=(ptr->dir.vy*ptr->str)/4096;
		}

		if(ptr->dir.vx || ptr->dir.vz) // do x & z
		{
			COPYVECTOR(&temp, &ptr->dir);
			temp.vy=0;

			SCALEVECTOR(&temp, ptr->str); // multiply wind direction by wind strength
			ADDTOVECTOR(pColl->pPos, &temp);
		}
	}

	return ret;
}

void windDrawParticles(void)
{
	WIND_DEFSTR *ptr;

	TILE_1	*si;
	GsOTA	*otptr;

	gte_SetRotMatrix(&GsWSMATRIX);
	gte_SetTransMatrix(&GsWSMATRIX);


	si = (TILE_1 *) GsOUT_PACKET_P; 

	for(ptr = windList.head.next; ptr != &windList.head; ptr = ptr->next)
	{
		int i;

		if(!ptr->active)
			continue;

		transformVertexListA(ptr->pParticles, ptr->nParticles, ptr->pScrXY, ptr->pDepths);

		for(i=0; i<ptr->nParticles; i++)
		{
			long depth=ptr->pDepths[i]/4;

			if((depth<0) || (depth>=MAXOTZ))
				continue;

			// code is 0x68, and LEN = 0x2000000  WHY AREN'T THESE DOCUMENTED ?
			*(ULONG	*)&si->r0= 0xffffff | ((0x68)<<24);
			*(ULONG	*)&si->x0= ptr->pScrXY[i];

			//otptr=(GsOTA*)(PolyList->org+(ptr->pDepths[i]));
			otptr=(GsOTA*)(PolyList->org+depth);

			PUTPACKETINTABLE(si,otptr, 0x2000000);		
			INCPOLYSDRAWN;

			si++;							//incr. packet building address by sizeof TILE1
		}
	}

	GsOUT_PACKET_P=(PACKET*)si;		 	//return new packet building address
}

#define	WINDCLIP(A, B, C)	{ \
if(ptr->pParticles[i].A>=(ptr->size.A+ptr->pos.A)) \
{ \
	ptr->pParticles[i].B=random(ptr->size.B)+ptr->pos.B; \
	ptr->pParticles[i].C=random(ptr->size.C)+ptr->pos.C; \
	ptr->pParticles[i].A=ptr->pos.A; \
} \
else \
{ \
	if(ptr->pParticles[i].A<ptr->pos.A) \
	{ \
		ptr->pParticles[i].B=random(ptr->size.B)+ptr->pos.B; \
		ptr->pParticles[i].C=random(ptr->size.C)+ptr->pos.C; \
		ptr->pParticles[i].A=(ptr->size.A+ptr->pos.A); \
	} \
} \
}

void windUpdate(void)
{
	WIND_DEFSTR *ptr;
	int i;

	GloveCtrl.inWind=FALSE;
	BallCtrl.inWind=FALSE;

	windDrawParticles();

	for(ptr = windList.head.next; ptr != &windList.head; ptr = ptr->next)
	{
		if(!ptr->active)
			continue;


		if(GloveCtrl.action!=HAND_SLAM)
		{
			if(windUpdateObject(&gloveColl, ptr))
				GloveCtrl.inWind=TRUE;
		}

		if(windUpdateObject(&ballColl, ptr))
			BallCtrl.inWind=TRUE;

		// now update the wind particles
		for(i=0; i<ptr->nParticles; i++)
		{
			ptr->pParticles[i].vx+=(ptr->dir.vx*ptr->str)/0x200000;
			ptr->pParticles[i].vy-=(ptr->dir.vy*ptr->str)/0x200000;
			ptr->pParticles[i].vz+=(ptr->dir.vz*ptr->str)/0x200000;


			WINDCLIP(vx, vy,vz);
			WINDCLIP(vy, vx,vz);
			WINDCLIP(vz, vx,vz);

/*			if(ptr->pParticles[i].vx>=(ptr->size.vx+ptr->pos.vx))
			{
				ptr->pParticles[i].vx=ptr->pos.vx;
			}
			else
				if(ptr->pParticles[i].vx<ptr->pos.vx)
				{

					ptr->pParticles[i].vx=(ptr->size.vx+ptr->pos.vx);
				}

			if(ptr->pParticles[i].vy>=(ptr->size.vy+ptr->pos.vy))
				ptr->pParticles[i].vy=ptr->pos.vy;
			else
				if(ptr->pParticles[i].vy<ptr->pos.vy)
					ptr->pParticles[i].vy=(ptr->size.vy+ptr->pos.vy);

			if(ptr->pParticles[i].vz>=(ptr->size.vz+ptr->pos.vz))
				ptr->pParticles[i].vz=ptr->pos.vz;
			else
				if(ptr->pParticles[i].vz<ptr->pos.vz)
					ptr->pParticles[i].vz=(ptr->size.vz+ptr->pos.vz);
*/
		}

		//DB("pParticles = %p, nParticles = %p, pScrXY = %p, pDepths = %p\n", ptr->pParticles, ptr->nParticles, ptr->pScrXY, ptr->pDepths);
	}
}

void windSetValues(int tag, int activeBool)
{
	WIND_DEFSTR *ptr;

	for(ptr = windList.head.next;ptr != &windList.head;ptr = ptr->next)
	{
		ASSERT(ptr);

		if(ptr->tag==tag)
		{
			DB("Setting wind (tag %d) to %d\n", tag, activeBool);
			ptr->active=activeBool;

			if(activeBool)
			{
				int i;

				//ptr->nParticles=(ABS(ptr->size.vx*ptr->size.vy*ptr->size.vz))>>12;
				//DB("nParticles = %d\n", ptr->nParticles);

				for(i=0; i<ptr->nParticles; i++)
				{
					//ptr->pParticles[i].pad=
					ptr->pParticles[i].vx=random(ptr->size.vx)+ptr->pos.vx;
					ptr->pParticles[i].vy=random(ptr->size.vy)+ptr->pos.vy;
					ptr->pParticles[i].vz=random(ptr->size.vz)+ptr->pos.vz;
				}
			}
		}
	}
}

