
#include "global.h"
#include "main.h"
#include "maths.h"
#include "map_draw.h"
#include "collide.h"
#include "camera.h"
#include "debris.h"

#include "particle.h"


PARTICLEFXLIST particleList;

PARTICLEFX *particleAdd(VECTOR *origin, TextureType *pSpr, int numParticles, int speed, int maxLife, unsigned long colour, unsigned long flags)
{
	PARTICLEFX *ptr;
	int i;
	PARTICLEFX *pNew=MALLOC(sizeof(PARTICLEFX) + (sizeof(PARTICLE) * numParticles));

	ASSERT(pSpr);
	ASSERT(numParticles);
	ASSERT(speed);
	ASSERT(maxLife);
	ASSERT(origin);

	memset(pNew, 0, sizeof(PARTICLEFX));

	ASSERT(pNew);
	
	ptr=particleList.head.next;
	ASSERT(ptr);

	pNew->next=ptr;
	pNew->prev=ptr->prev;
	ptr->prev->next=pNew;
	ptr->prev=pNew;

	pNew->pParticles = (PARTICLE *)ADD2POINTER(pNew, sizeof(PARTICLEFX));
	pNew->nParticles = numParticles;
	pNew->flags = flags;
	pNew->pSprite = pSpr;
	pNew->colour = colour;

	speed*=256;

	COPYVECTOR(&(pNew->origin), origin);
	pNew->origin.vx*=256;
	pNew->origin.vy*=256;
	pNew->origin.vz*=256;

	for(i=0; i<numParticles; i++)
	{
		COPYVECTOR(&(pNew->pParticles[i].pos), origin);
		pNew->pParticles[i].pos.vx*=256;
		pNew->pParticles[i].pos.vy*=256;
		pNew->pParticles[i].pos.vz*=256;

		pNew->pParticles[i].maxLife = maxLife;
		pNew->pParticles[i].gravAccel = 0;

		// CPW: set up particle velocities (but we didn't lose the coffees)
		if(flags & PARTICLE_SPHERICAL)
		{
			pNew->pParticles[i].lifeCtr = pNew->pParticles[i].maxLife;

			pNew->pParticles[i].vel.vx = 2047 - utilRandomInt(4095);
			pNew->pParticles[i].vel.vy = 2047 - utilRandomInt(4095);
			pNew->pParticles[i].vel.vz = 2047 - utilRandomInt(4095);

			MakeUnit(&pNew->pParticles[i].vel);

			pNew->pParticles[i].vel.vx = (pNew->pParticles[i].vel.vx * speed) / 4096;
			pNew->pParticles[i].vel.vy = (pNew->pParticles[i].vel.vy * speed) / 4096;
			pNew->pParticles[i].vel.vz = (pNew->pParticles[i].vel.vz * speed) / 4096;
		}
		else
		{
			pNew->pParticles[i].lifeCtr = utilRandomInt(pNew->pParticles[i].maxLife);

			pNew->pParticles[i].vel.vx = speed - utilRandomInt(speed * 2);
			pNew->pParticles[i].vel.vy = speed - utilRandomInt(speed * 2);
			pNew->pParticles[i].vel.vz = speed - utilRandomInt(speed * 2);

			// CPW: DB("init %d, %d, %d\n", pNew->pParticles[i].vel.vx, pNew->pParticles[i].vel.vy, pNew->pParticles[i].vel.vz);
		}
	}


	particleList.numEntries++;

	// CPW: DB("Created PARTICLEFX %p\n", pNew);
	return pNew;
}

void particleDelete(PARTICLEFX *pE)
{
// Unhook
	pE->prev->next = pE->next;
	pE->next->prev = pE->prev;

	FREE(pE);

	particleList.numEntries--;
//	DB("PARTICLEFX DELETE 0x%p (not yet implemented)\n", pE);
}

void particleDeleteAll(void)
{
	while(particleList.head.next != &particleList.head)
	{
		particleDelete(particleList.head.next);
	}
}


int particleInitialiseList(void)
{
	particleList.head.next=particleList.head.prev=&particleList.head;
	particleList.numEntries=0;

	return 0;
}

int particleCount(void)
{
	PARTICLEFX *ptr;
	int turtle = 0;

	// CPW: when the game's released, just return particleList.numEntries
	for(ptr=particleList.head.next; ptr != &particleList.head; ptr = ptr->next)
		turtle++;

	ASSERT(turtle==particleList.numEntries);

	return turtle;
}

int particleProcessAll(void)
{
	PARTICLEFX *ptr;
	int i;
	int alive;

	// CPW: step through the list
	for(ptr=particleList.head.next; ptr != &particleList.head; ptr = ptr->next)
	{
		alive=0;

		for(i=0; i<ptr->nParticles; i++)
		{
			ADDTOVECTOR(&ptr->pParticles[i].pos, &ptr->pParticles[i].vel);
			
			if(ptr->flags & PARTICLE_GRAVITY)
			{
				ptr->pParticles[i].pos.vy+=ptr->pParticles[i].gravAccel;
				ptr->pParticles[i].gravAccel+=512;
			}

			(ptr->pParticles[i].lifeCtr)--;

			if(ptr->pParticles[i].lifeCtr==0)
			{
				COPYVECTOR(&ptr->pParticles[i].pos, &ptr->origin);

				if(ptr->flags & PARTICLE_REINCARNATION)
				{
					if(ptr->flags & PARTICLE_SPHERICAL)
					{
						ptr->pParticles[i].lifeCtr = ptr->pParticles[i].maxLife;
						ptr->pParticles[i].gravAccel = 0;
					}
					else
					{
						ptr->pParticles[i].lifeCtr = utilRandomInt(ptr->pParticles[i].maxLife);
						ptr->pParticles[i].gravAccel = 0;
					}
				}
			}
			
			if(ptr->pParticles[i].lifeCtr>0)
				alive++;
		}

		if(alive==0)
		{
			particleDelete(ptr);
		}
	}

	return 0;
}

int particleDrawAll(void)
{
	PARTICLEFX *ptr;
	VERT v;
	int i;
	PARTICLE *p;
// CPW: 	int r,g,b, a;

	int c = 0;

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

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

		ASSERT(ptr->nParticles);
		ASSERT(ptr->pSprite);

		for(i=0; i<ptr->nParticles; i++)
		{
			p = ptr->pParticles + i;
			ASSERT(p);

			v.vx = (p->pos.vx/256) - mycamera.vpx;
			v.vy = (p->pos.vy/256) - mycamera.vpy;
			v.vz = (p->pos.vz/256) - mycamera.vpz;


/*
			a = (p->lifeCtr*256)/p->maxLife;

			r = ptr->colour & 0xff;
			g = (ptr->colour & 0xff00)>>8;
			b = (ptr->colour & 0xff0000)>>16;

			r = (r*a)>>8;
			g = (g*a)>>8;
			b = (b*a)>>8;

			Print3DSelfAlphaSprite(ptr->pSprite, &v, 128, r|(g<<8)|(b<<16)|(a<<24));
*/

			Print3DSelfAlphaSprite(ptr->pSprite, &v, 128, ptr->colour);
			c++;
		}
	}


	return c;
}
