/*
 * Copyright (C) 2000  Jeremie Allard (Hufo / N.A.A.)
 * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
 *
 * hufo_smoke is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * hufo_smoke is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef FIREPART_H
#define FIREPART_H

#include <stdlib.h>

#ifdef _DEBUG
#include <assert.h>
#endif

#include "FMotion.h"
#include "rsRand.h"

#define HVCtrX 0.0
#define HVCtrY 0.0
float FireFoc = 2.0f;

#define FireFocX FireFoc
#define FireFocY FireFoc

#define ProjEX(p) (HVCtrX+FireFocX*(p).x/(p).y)
#define ProjEY(p) (HVCtrY+FireFocY*(p).z/(p).y)
#define ProjEZ(ez,p) (ez)=-((p).y*(float)(1.0/20.0)-1.0)

double nrnd (double d)		// normal distribution randomizer
{
	double r, v1, v2;

	do {
		v1 = rsRandf (2.0) - 1.0;
		v2 = rsRandf (2.0) - 1.0;
		r = v1 * v1 + v2 * v2;
	} while (r >= 1.0 || r == 0.0);

	r = sqrt (-2.0 * log (r) / r);

	return v1 * d * r;
}

#define NBPARTMAX 2048
#define PARTLIFE 2.0
#define PARTINTERV (PARTLIFE/NBPARTMAX)
#define FIRESIZE 1.0f
#define FIREDS 0.7
#define FIREALPHA 0.15f
#define FIREDA 0.4
#define FIRECYLR 0.2f

struct Particle {
	SVector3D p;		// position
	SVector3D v;		// dp/dt
	SVector3D s;		// size
	float a;		// alpha
	float t;		// time to death
	float ex, ey, ez;	// screen pos
	float dx, dy;		// screen size
} TblP[NBPARTMAX];

int np;
float LastPartTime;
Bool FireAnim, FireRotate, FireRecalc;
Bool FireStop;
float FireRot;
float FireAng;

struct Vertex {
	float u, v;
	float ex, ey, ez;
};

SVector3D FireSrc (0.0f, 25.0f, -13.0f);
SVector3D FireDS1 (6.0f, 0.0f, 0.0f);
SVector3D FireDS2 (0.0f, 2.0f, 0.0f);
SVector3D FireDir (0.0f, 0.0f, 10.0f);
SVector3D FPartA (0.0f, 0.0f, 4.0f);

SMatrix3D FireM;
SVector3D FireO;

void FireInit ()
{
	//NoiseInit();
	np = 0;
	LastPartTime = 0.0;
	FireAnim = True;
	FireRotate = False;
	FireRot = PI / 5.0;
	FireAng = 0.0;
	FireStop = False;
	FireRecalc = True;
	FMotionInit ();
/*	np=1;
	TblP[0].p=FireSrc;
	TblP[0].v.Zero();
	TblP[0].a=1.0;;
	TblP[0].s.x=2.0;
	TblP[0].s.y=2.0;
	TblP[0].s.z=2.0;
	TblP[0].t=-1;*/
}

void CalcFire (float t, float dt)
{
	int n;
	Particle *p = TblP;	//+1;

	n = 0;
	float da = pow (FIREDA, dt);
	//float ds = pow (FIREDS, dt);
	//SVector3D v;

	if (FireAnim) {
		FMotionAnimate (dt);
		while (n < np) {
			if ((p->t -= dt) <= 0) {	// kill it
				*p = TblP[--np];
			} else {	// animate it
				//a=p->p; a.z-=5*t;
				//a=FPartA; //+Noise(a)*(p->p.z-FireSrc.z)*1.0; //a.x*=4.0f; a.y*=4.0f;
				p->v += FPartA * dt;
				//GetFMotion(p->p,a); p->v=a+FPartA;
				p->p += p->v * dt;
				//p->p+=FireDir*dt;
				//p->p.z+=dt;
				FMotionWarp (p->p, dt);
				//p->s*=ds;
				//p->s.x=0.67*FIRESIZE+0.4*FIRESIZE*sin(PI*(p->t)/PARTLIFE);
				//p->s.z=0.05*FIRESIZE+0.768*FIRESIZE*(1.0-p->t/PARTLIFE);
				p->a *= da;
				++n;
				++p;
			}
		}
		if (!FireStop)
			while (np < NBPARTMAX && t - LastPartTime >= PARTINTERV) {
				LastPartTime += (float)PARTINTERV;
				p = TblP + (np++);
				p->p = FireSrc + FireDS1 * nrnd (0.25) + FireDS2 * nrnd (0.25);
				p->v = FireDir;
				FMotionWarp (p->p, (t - LastPartTime));
				p->t = PARTLIFE + LastPartTime - t;
				float size = FIRESIZE * (0.5f + nrnd (0.5));
				float alpha = FIREALPHA * (float)pow (size / FIRESIZE, 0.5f);

				p->s.x = size;
				p->s.y = size;
				p->s.z = size;
				p->a = alpha * pow (FIREDA, (t - LastPartTime));
				p->s *= 0.5f + nrnd (0.5);
			}
	} else
		LastPartTime += dt;

	n = 0;
	p = TblP;
	SVector3D v;

	if (FireRotate) {
		FireAng += FireRot * dt;
		FireRecalc = True;
	}

	FireM.FromAngle (0, 0, FireAng);
	FireO.Zero ();
	FireM.Apply (FireSrc, &FireO);
	FireO = FireSrc - FireO;
	while (n < np) {
		FireM.Apply (p->p, &v);
		v += FireO;
		if (v.y > 1.0f) {
			p->ex = ProjEX (v);
			p->ey = ProjEY (v);
			ProjEZ (p->ez, v);
			p->dx = FireFocX * p->s.x / v.y;
			p->dy = FireFocY * p->s.z / v.y;
		} else
			p->dx = 0;
		++n;
		++p;
	}
}

#endif
