#include "stdafx.h"
#include "psys.h"


bool blobstar::CorrectPoint(v3 &p)
{	
	// return true if corrected
	p-=curp1;
	v3 d = curp2 - curp1;
	float length = Length(d);
	float erad = 6.f;
	v3 dn = d / length;

	float along = DotProduct(dn,p);
	if (along < -erad || along >= length+erad) 
	{
		p+=curp1;
		return false;
	}
	if (along<=0)
	{
		float ds = LengthSquared(p);
		if (ds>erad)
		{
			p+=curp1;
			return false;
		}
		else 
		{
			p=p/(sqrtf(ds)/erad);
			p+=curp1;
			return true;
		}
	}
	if (along>=length)
	{
		float ds = LengthSquared(p-d);
		if (ds>erad)
		{
			p+=curp1;
			return false;
		}
		else 
		{
			p=d+((p-d)/(sqrtf(ds)/erad));
			p+=curp1;
			return true;
		}
	}
	float frad = 0;
	if (along<length/2) frad=along/(length/2); else frad=2-along/(length/2);
	frad*=fat;

	frad+=erad;
	frad*=frad; // squared please

	v3 online = dn * along;
	float across=LengthSquared(p-online);

	if (across>frad)
	{
		p+=curp1;
		return false;
	}

	p=online+((p-online)/(sqrtf(across/frad)));

	p+=curp1;
	return true;
}

void psysBox::Update(float GETDT,  blobstar *stars, int numstars, float rainfall)
{
	float nump=EvaluatePort(1);
	float drag=EvaluatePort(2);
	float follow=EvaluatePort(3);
	float gravity=EvaluatePort(4);
	v3 amount=EvaluatePortV3(5);
	v3 noisefreq=EvaluatePortV3(6);
	v3 noisespeed=EvaluatePortV3(7);
	v3 seedrad=EvaluatePortV3(8);
	v3 seedpos=EvaluatePortV3(9);
	float reseed=EvaluatePort(10);

	float speed=EvaluatePort(13);
	v3 texscale=EvaluatePortV3(12);

	amount *=0.25f;
	nump=bound(0,nump,1);
	int inump=nump*MAXP;

	if (realtime) inump/=4;

	//totalrespawn=1;
	if (inump>0)
	{
	

		P *pp=p;
		P *op=p+inump-1;
		float dt=GETDT * speed;
		if (drag<0) drag=0;
		drag=pow(0.25f,drag);
		float edrag=pow(drag,dt);

		

		pos.x+=dt * noisespeed.x;
		pos.y+=dt * noisespeed.y;
		pos.z+=dt * noisespeed.z;


		float tx=pos.x;
		float ty=pos.y;
		float tz=pos.z;

		
		for (int c1=0;c1<inump;c1++)
		{
			if (pp->age<0 || totalrespawn || rand() < reseed * 1024 || LengthSquared(pp->p)>4)
			{
				pp->v=v3(0,0,0);
				float z=Random(-0.99f,0.99f);
				float xr=sqrt(1-z*z);
				pp->p=seedpos+v3(seedrad.x * xr * Random(-1,1),seedrad.y * xr * Random(-1,1),seedrad.z * z);
				pp->age=0;
				pp->size=GaussRandom(0,1);
			}
			pp->age+=dt;
			pp->v-=pp->p * gravity * dt * 0.1f;		// gravity
			
			pp->v+=(op->p-pp->p) * follow * dt ; // follow
			v3 &v=pp->p;
			v3 w(v.x*noisefreq.x,v.y*noisefreq.y,v.z*noisefreq.z);
			
			pp->v+=v3(Perlin::Noise3o(w.x,w.y+tx,w.z)*amount.x,Perlin::Noise3o(w.x,w.y,w.z+ty)*amount.y,Perlin::Noise3o(w.x+tz,w.y,w.z)*amount.z);

			
			pp->v*=edrag;			// drag
			pp->p+=pp->v*dt; // speed control

			
			int itsok=0;
			int iter=0;
			if (rainfall==0) while (!itsok && iter<4)
			{
				iter++;
				itsok=1;
				v3 p=pp->p * SCALEFAC;				
				for (int st=0;st<numstars;st++)
				{
					itsok&=!stars[st].CorrectPoint(p);
				}				
				pp->p = p / SCALEFAC;
				
			}

			op=pp++;

		}

		for (;c1<MAXP;c1++)
		{
			pp->age=-1;
			pp++;
		}

		v3 centa(0,0,0);
		pp=p;
		for (c1=0;c1<inump;c1++)
		{
			
			centa += pp->p;
			pp++;
		}
		pp=p;
		centa/=float(inump);
		for (c1=0;c1<inump;c1++)
		{
			pp->p-=centa ;//* 0.2f;
			pp++;
		}


		totalrespawn=0;

	}

}



void psysBox::Run(SimpleBufferUV2 &bout,  DWORD col, float size, float rainfall)
{
	//Value r=EvaluatePort(0);
	float nump=EvaluatePort(1);
	float drag=EvaluatePort(2);
	float follow=EvaluatePort(3);
	float gravity=EvaluatePort(4);
	v3 amount=EvaluatePortV3(5);
	v3 noisefreq=EvaluatePortV3(6);
	v3 noisespeed=EvaluatePortV3(7);
	v3 seedrad=EvaluatePortV3(8);
	v3 seedpos=EvaluatePortV3(9);
	float reseed=EvaluatePort(10);

	float speed=EvaluatePort(13);
	v3 texscale=EvaluatePortV3(12);

	amount *=0.25f;
	nump=bound(0,nump,1);
	int inump=nump*MAXP;

	//totalrespawn=1;
	if (inump>0)
	{
	

		P *pp=p;
		P *op=p+inump-1;
		
		

		float tx=pos.x;
		float ty=pos.y;
		float tz=pos.z;

		for (int c1=0;c1<inump;c1++)
		{
			
			float uu = pp->p.x*texscale.x+0.5f;
			float vv = pp->p.y*texscale.y+0.5f;

			float rf=rainfall-c1/float(inump)*3;
			float dy;
			if (rf<0) dy=0; else if (rf<1) dy=rf*rf; else dy=rf-floor(rf);

			v3 p2=pp->p*SCALEFAC+v3(0,INSKY*(1-dy*1.5f),0);
			if (p2.y>0) bout.AddBlob(p2,col,pp->size * size,0,0,0,1,1,uu,vv,uu,vv);
			bout.Flush();
			
			/* TODO WRITE BLOB HERE
			vi.GetPos() = pp->p;
			if (fabs(pp->v.x)+fabs(pp->v.y)+fabs(pp->v.z)<0.00001f)
			{
				vi.GetNorm() = v3(1,0,0);
			}
			else
			vi.GetNorm() = BS3::Normalize(pp->v);
			float *uv = vi.GetUV();
			uv[0]=pp->p.x*texscale.x+0.5f;
			uv[1]=pp->p.y*texscale.y+0.5f;
			++vi;
			*/

			op=pp++;
			
		}
		
		
	}		

	bout.Draw();
}

	
