/*****************************************************************************
Name            :   effects.cpp
Title           :   Effects
C Author        :   Stel Michael
Created         :   9 Sept 1993

Copyright       :   1992 by VideoLogic Limited. All rights reserved.
		    No part of this software, either material or conceptual
		    may be copied or distributed, transmitted, transcribed,
		    stored in a retrieval system or translated into any
		    human or computer language in any form by any means,
		    electronic, mechanical, manual or other-wise, or
		    disclosed to third parties without the express written
		    permission of VideoLogic Limited, HomePark Estate,
		    King's Langley, Hertfordshire, WD4 8LZ, U.K.

Description     :   Create effects
Program Type    :   Microsoft Visual C++ V2
*****************************************************************************/

#define Cplusplus 
#define BOXSIZE	(10.0f)

#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include "sgl.h" 
#include "math.h"   
#include "sclist.h"
#include "effects.h"  
                       
int err_f,err_l;                       

extern int lballTex;
extern int pointLight2; 
                       
float red[3] = {0.9f,0.7f,0.0f};
float whot[3] = {0.9f,0.9f,0.9f};
float skbl[3] = {0.5f, 0.6f, 0.9f};   


Particle::Particle()     
{
}


/*****************************************************************
* Function Name		: AddExp  
* Inputs			: none
* Outputs			: none
* Returns			: void 
* Description		: adds a cube with 5 simple planes, and one 
*					  textured plane, to the display list
******************************************************************/

void AddExp()
{
	sgl_2d_vec	uv1,uv2,uv3;

	sgl_vector	sidePnt;
	sgl_vector	sideNorm;

	sgl_vector	pnt2;	
	sgl_vector	pnt3;	

   	sgl_create_convex(FALSE);

	sgl_set_texture_map(lballTex,FALSE,FALSE);

	/* Add plane with head texture */
	
	sideNorm[0]=0.0f;
	sideNorm[1]=-1.0f;
	sideNorm[2]=0.0f;

	sidePnt[0]=-BOXSIZE;
	sidePnt[1]=-1.0f;
   	sidePnt[2]=-BOXSIZE;

	uv1[0]=0.0f;
	uv1[1]=0.0f;

	pnt2[0]=BOXSIZE;
	pnt2[1]=-1.0f;
	pnt2[2]=-BOXSIZE;

	uv2[0]=0.0f;
	uv2[1]=1.0f;

	pnt3[0]=-BOXSIZE;
	pnt3[1]=-1.0f;
	pnt3[2]=BOXSIZE;

	uv3[0]=1.0f;
	uv3[1]=0.0f;

	sgl_add_plane(sidePnt,pnt2,pnt3,FALSE,NULL,NULL,NULL,uv1,uv2,uv3); 

	/* Add bounding invisible planes */

 	sideNorm[0] = 1.0f;
	sideNorm[1] = 0.0f;
	sideNorm[2] = 0.0f;

   	sidePnt[0] = sideNorm[0] * BOXSIZE;
   	sidePnt[1] = sideNorm[1] * 1.0f;
   	sidePnt[2] = sideNorm[2] * BOXSIZE;

	sgl_add_simple_plane(sidePnt, sideNorm, TRUE);

 	sideNorm[0] = 0.0f;
	sideNorm[1] = 0.0f;
	sideNorm[2] = 1.0f;
   	
   	sidePnt[0] = sideNorm[0] * BOXSIZE;
   	sidePnt[1] = sideNorm[1] * 1.0f;
   	sidePnt[2] = sideNorm[2]*BOXSIZE;

	sgl_add_simple_plane(sidePnt, sideNorm, TRUE);	

	sideNorm[0]=-1.0f;
	sideNorm[1]=0.0f;
	sideNorm[2]=0.0f;

   	sidePnt[0]=sideNorm[0]*BOXSIZE;
   	sidePnt[1]=sideNorm[1]*1.0f;
   	sidePnt[2]=sideNorm[2]*BOXSIZE;

	sgl_add_simple_plane(sidePnt, sideNorm, TRUE);	

	sideNorm[0]=0.0f;
	sideNorm[1]=0.0f;
	sideNorm[2]=-1.0f;

   	sidePnt[0]=-BOXSIZE;
   	sidePnt[1]=-1.0f;
   	sidePnt[2]=-BOXSIZE;

	sgl_add_simple_plane(sidePnt, sideNorm, TRUE);	

	sideNorm[0]=0.0f;
	sideNorm[1]=1.0f;
	sideNorm[2]=0.0f;

   	sidePnt[0]=sideNorm[0]*BOXSIZE;
   	sidePnt[1]=sideNorm[1]*1.0f;
   	sidePnt[2]=sideNorm[2]*BOXSIZE;

	sgl_add_simple_plane(sidePnt, sideNorm, TRUE);	
}


/*****************************************************************
* Function Name		: Partical::InitPartical  
* Inputs			: none
* Outputs			: none
* Returns			: void 
* Description		: initialise partical
******************************************************************/

void Particle::InitParticle()
{        
	float	mag;

    SetStatus(ALIVE);
                                         
	pos[0]=(((float) ((rand()%20))/2.5f)-4.0f);  	
	pos[1]= (float) fabs(((float) ((rand()%20))/2.5f)-4.0f); 
	pos[2]=(((float) ((rand()%20))/2.5f)-4.0f);
	
	mag = (float) sqrt(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]);         
	
	red[1]=mag/7.0f;
	
	sgl_new_translucent();

	group=sgl_create_list(TRUE,TRUE,FALSE); 

	sgl_set_glow(whot);
	sgl_set_texture_effect(FALSE,FALSE,FALSE, TRUE);

	sgl_set_texture_map(lballTex,FALSE,FALSE);

	tran=sgl_create_transform(TRUE); 

    AddExp();

	sgl_to_parent();	
	                             
	dir[0]=pos[0]/mag;
	dir[1]=pos[1]/mag; 
	dir[2]=pos[2]/mag;
	                             
	speed=((float) ((rand()%10)+10))/2.5f;
	
	size=1.0f;
	
	lifeForce=0;		                
}                       
 

/*****************************************************************
* Function Name		: Partical::Move  
* Inputs			: none
* Outputs			: none
* Returns			: void 
* Description		: move partical
******************************************************************/

void Particle::Move()
{   
	int i;  
	float rv;
	
	for (i=0;i<3;i++)
		pos[i]+=dir[i]*speed*10.0f;   

	rv=((float) (rand()%10))/150.0f;

	speed/=(1.08f+rv);   
	
	rv=((float) (rand()%10))/150.0f;
	
	size*=1.20f+rv;
}


/*****************************************************************
* Function Name		: Effect::Effect  
* Inputs			: nparts - number of parts
*					  pos - translation for animation 
* Outputs			: none
* Returns			: void 
* Description		: create new partical of nparts and set translation 
*					  for animation
******************************************************************/
 
Effect::Effect(int nparts,float pos[3])
{                      	
	NumParts=nparts; 

	EffectPos[0]=pos[0]; 
	EffectPos[1]=pos[1]; 
	EffectPos[2]=pos[2];   

	status=DORMANT;
	
	Particles=new Particle[nparts];
}    


/*****************************************************************
* Function Name		: Effect::Init  
* Inputs			: p[] - starting position 
* Outputs			: none
* Returns			: void 
* Description		: initialise effects and set starting position
******************************************************************/

void Effect::Init(float p[3])
{
	int i;                          

	EffectPos[0]=p[0];
	EffectPos[1]=p[1];
	EffectPos[2]=p[2];

	sgl_switch_light( pointLight2,TRUE,FALSE,FALSE); 

	for (i=0;i<NumParts;i++)
		Particles[i].InitParticle();

	sgl_switch_light( pointLight2,TRUE,FALSE,FALSE); 
}
                                    

/*****************************************************************
* Function Name		: Effect::AnimateParticles  
* Inputs			: none
* Outputs			: none
* Returns			: void 
* Description		: animate particles using predifined translation  
*					  and random rotation
******************************************************************/
                                            
void Effect::AnimateParticles()
{        
	int i,g;
	int curtran;
	static int numfaded=0;	
	
	float xp,yp,zp; 
	float xAng,yAng,zAng;       
    float	Psz;
                                                                  
	for (i=0;i<NumParts;i++)
	{         
		if (Particles[i].GetStatus()==ALIVE)
		{   
			Particles[i].Move();
	
			curtran=Particles[i].GetTran();
			sgl_modify_transform(curtran,TRUE);		
		 
			xp=EffectPos[0]+Particles[i].pos[0];
			yp=EffectPos[1]+Particles[i].pos[1];
			zp=EffectPos[2]+Particles[i].pos[2]; 
		           
			sgl_translate(xp,yp,zp);  
			
			xAng=(float) (rand()%31);
			yAng=(float) (rand()%31);							
            zAng=(float) (rand()%31);
			
		    sgl_rotate(sgl_x_axis, (xAng/10.0f));
			sgl_rotate(sgl_y_axis, (yAng/10.0f));
			sgl_rotate(sgl_z_axis, (zAng/10.0f));   
			             
			Psz=Particles[i].Getsize();             
			             
			sgl_scale(Psz,Psz,Psz);  
			
			Particles[i].AddForce(5+(rand()%5));
			
			if (Particles[i].GetForce()>100) 
			{
				Particles[i].SetStatus(FADED); 
				g=Particles[i].GetGroup();
				sgl_delete_list(g); 
			}
		}
		else    
			numfaded++;
    }   
    
    if (numfaded==NumParts)  
    	status=DORMANT;
}
 
                                            
