www.pudn.com > Particles1.zip > particles.cpp


#include "particles.h" 
#include "math.h" 
 
//Generates a random float in the range [0;1] 
#define RANDOM_FLOAT (((float)rand())/RAND_MAX) 
/************************************* 
 
METHODS OF CCCParticle class 
 
**************************************/ 
 
void CCCParticle::Initialize(CCCParticleSystem *ParentSystem) 
{ 
 
  //Calculate the age, the particle will live: 
	m_fDieAge = ParentSystem->m_fMinDieAge +  
			     ((ParentSystem->m_fMaxDieAge - ParentSystem->m_fMinDieAge)*RANDOM_FLOAT); 
	if (m_fDieAge == 0.0f) return;  //make sure there is no div 0 
	m_fAge = 0.0f; 
 
  //set the position: 
	if (ParentSystem->m_bParticlesLeaveSystem) 
	{ 
		//start with "global" coordinates (the current coordinates of the emitter position) 
		m_Position = ParentSystem->m_EmitterPosition; 
	} 
	else 
	{ 
		//In this case we assume a local coordinate system: 
		m_Position = NULL_VECTOR; 
	} 
	//Add the deviation from the emitter position: 
	m_Position.x += ParentSystem->m_MaxCreationDeviation.x*(RANDOM_FLOAT*2.0f-1.0f); 
	m_Position.y += ParentSystem->m_MaxCreationDeviation.y*(RANDOM_FLOAT*2.0f-1.0f); 
	m_Position.z += ParentSystem->m_MaxCreationDeviation.z*(RANDOM_FLOAT*2.0f-1.0f); 
  //set the emission velocity 
	m_Velocity.x = ParentSystem->m_StandardEmitDirection.x + ParentSystem->m_MaxEmitDirectionDeviation.x*(RANDOM_FLOAT*2.0f-1.0f); 
	m_Velocity.y = ParentSystem->m_StandardEmitDirection.y + ParentSystem->m_MaxEmitDirectionDeviation.y*(RANDOM_FLOAT*2.0f-1.0f); 
	m_Velocity.z = ParentSystem->m_StandardEmitDirection.z + ParentSystem->m_MaxEmitDirectionDeviation.z*(RANDOM_FLOAT*2.0f-1.0f); 
	m_Velocity = m_Velocity * ((ParentSystem->m_fMinEmitSpeed +  
		                         (ParentSystem->m_fMaxEmitSpeed - ParentSystem->m_fMinEmitSpeed)*RANDOM_FLOAT)); 
  //set the acceleration vector: 
	m_Acceleration = ParentSystem->m_AccelerationDirection*  
		              (ParentSystem->m_fMinAcceleration + (ParentSystem->m_fMaxAcceleration-ParentSystem->m_fMinAcceleration)*RANDOM_FLOAT); 
  //set the alpha / color values: 
	m_Color = ParentSystem->m_MinEmitColor +  
		   ((ParentSystem->m_MaxEmitColor-ParentSystem->m_MinEmitColor) * RANDOM_FLOAT); 
	//calculate the "end color" (in order to get the ColorChange): 
	SF3dVector EndColor = ParentSystem->m_MinDieColor +  
		   ((ParentSystem->m_MaxDieColor-ParentSystem->m_MinDieColor) * RANDOM_FLOAT); 
	m_ColorChange = (EndColor-m_Color) / m_fDieAge; 
 
	m_fAlpha = ParentSystem->m_fMinEmitAlpha  
		       + ((ParentSystem->m_fMaxEmitAlpha - ParentSystem->m_fMinEmitAlpha) * RANDOM_FLOAT); 
	float fEndAlpha = ParentSystem->m_fMinDieAlpha  
		       + ((ParentSystem->m_fMaxDieAlpha - ParentSystem->m_fMinDieAlpha) * RANDOM_FLOAT); 
	m_fAlphaChange = (fEndAlpha - m_fAlpha) / m_fDieAge; 
 
  //set the size values: 
	m_fSize = ParentSystem->m_fMinEmitSize + 
			 ((ParentSystem->m_fMaxEmitSize - ParentSystem->m_fMinEmitSize) * RANDOM_FLOAT); 
	float fEndSize = ParentSystem->m_fMinDieSize + 
			 ((ParentSystem->m_fMaxDieSize - ParentSystem->m_fMinDieSize) * RANDOM_FLOAT); 
	m_fSizeChange = (fEndSize - m_fSize) / m_fDieAge; 
 
  //spin values: 
	m_fSpinAngle = 0.0f; 
	m_fSpinSpeed = ParentSystem->m_fMinEmitSpinSpeed + 
			((ParentSystem->m_fMaxEmitSpinSpeed - ParentSystem->m_fMinEmitSpinSpeed) * RANDOM_FLOAT); 
	m_fSpinAcceleration = ParentSystem->m_fMinSpinAcceleration + 
			((ParentSystem->m_fMaxSpinAcceleration - ParentSystem->m_fMinSpinAcceleration) * RANDOM_FLOAT); 
 
 
 
  //Ok, we're done: 
	m_bIsAlive = true; 
	m_ParentSystem = ParentSystem; 
 
 
} 
 
void CCCParticle::Update(float timePassed) 
{ 
	//Update all time-dependent values: 
	m_fAge += timePassed; 
	if (m_fAge >= m_fDieAge)  
	{ 
		if (m_ParentSystem->m_bRecreateWhenDied)  
		{ 
			Initialize(m_ParentSystem); 
			Update(RANDOM_FLOAT * timePassed);  //see comment in UpdateSystem 
		} 
		else 
		{ 
			m_fAge = 0.0f; 
			m_bIsAlive = false; 
			m_ParentSystem->m_iParticlesInUse--; 
		} 
 
		return; 
	} 
 
	m_fSize  += m_fSizeChange *timePassed; 
	m_fAlpha += m_fAlphaChange*timePassed; 
	m_Color = m_Color + m_ColorChange*timePassed; 
	m_Velocity = m_Velocity + m_Acceleration*timePassed; 
	//Note: exact would be: m_Position = 1/2*m_Acceleration*timePassed˛ + m_VelocityOLD*timePassed; 
	//But this approach is ok, I think! 
	m_Position = m_Position + (m_Velocity*timePassed); 
 
	m_fSpinSpeed += m_fSpinAcceleration*timePassed; 
	m_fSpinAngle += m_fSpinSpeed*timePassed; 
 
	//That's all! 
} 
 
void CCCParticle::Render() 
{ 
	if (!m_ParentSystem->m_bUseTexture)  
	{ 
		glPointSize(m_fSize*m_ParentSystem->m_fCurrentPointSize); 
		float color[4]; 
		color[0] = m_Color.x; 
		color[1] = m_Color.y; 
		color[2] = m_Color.z; 
		color[3] = m_fAlpha; 
 
		glColor4fv(&color[0]); 
 
		glBegin(GL_POINTS); 
			glVertex3fv(&m_Position.x); 
		glEnd(); 
	} 
	else 
	{ 
		//render using texture: (texture was already set active by the Render method of the particle system) 
		 
		float color[4]; 
		color[0] = m_Color.x; 
		color[1] = m_Color.y; 
		color[2] = m_Color.z; 
		color[3] = m_fAlpha; 
		glColor4fv(&color[0]); 
 
		SF3dVector RotatedX = m_ParentSystem->m_BillboardedX; 
		SF3dVector RotatedY = m_ParentSystem->m_BillboardedY; 
 
 
	   //If spinning is switched on, rotate the particle now: 
		if (m_fSpinAngle > 0.0f) 
		{ 
			RotatedX = m_ParentSystem->m_BillboardedX * cos(m_fSpinAngle)  
				       + m_ParentSystem->m_BillboardedY * sin(m_fSpinAngle); 
			RotatedY = m_ParentSystem->m_BillboardedY * cos(m_fSpinAngle)  
				       - m_ParentSystem->m_BillboardedX * sin(m_fSpinAngle); 
		} 
	 
		 
		//Render a quadrangle with the size m_fSize 
		SF3dVector coords = m_Position - (RotatedX*(0.5f*m_fSize)) 
									   - (RotatedY*(0.5f*m_fSize)); 
		glBegin(GL_POLYGON); 
		  glVertex3fv(&coords.x); 
		  glTexCoord2f(0.0f,1.0f); 
		  coords = coords + RotatedY * m_fSize; 
		  glVertex3fv(&coords.x); 
		  glTexCoord2f(1.0f,1.0f); 
		  coords = coords + RotatedX * m_fSize;		   
		  glVertex3fv(&coords.x); 
		  glTexCoord2f(1.0f,0.0f); 
		  coords = coords - RotatedY * m_fSize; 
		  glVertex3fv(&coords.x); 
		  glTexCoord2f(0.0f,0.0f); 
		glEnd(); 
 
 
	} 
 
} 
 
/************************************* 
 
METHODS OF CCCParticleSytem class 
 
**************************************/ 
 
 
CCCParticleSystem::CCCParticleSystem() 
{ 
	//Set default values: 
	 
	//motion: 
	this->m_EmitterPosition = NULL_VECTOR; 
	this->m_MaxCreationDeviation = NULL_VECTOR; 
 
	this->m_StandardEmitDirection = NULL_VECTOR; 
	this->m_MaxEmitDirectionDeviation = NULL_VECTOR; 
	this->m_fMaxEmitSpeed = 0.0f; 
	this->m_fMinEmitSpeed = 0.0f; 
 
	this->m_AccelerationDirection = NULL_VECTOR; 
	this->m_fMaxAcceleration = 0.0f; 
	this->m_fMinAcceleration = 0.0f; 
 
	this->m_fMinEmitSpinSpeed = 0.0f; 
	this->m_fMaxEmitSpinSpeed = 0.0f; 
	 
	this->m_fMaxSpinAcceleration = 0.0f; 
	this->m_fMinSpinAcceleration = 0.0f; 
 
 
	//look: 
	this->m_fMaxEmitAlpha = 0.0f; 
	this->m_fMinEmitAlpha = 0.0f; 
	this->m_fMaxDieAlpha = 1.0f; 
	this->m_fMinDieAlpha = 1.0f; 
 
	this->m_MaxEmitColor = NULL_VECTOR; 
	this->m_MinEmitColor = NULL_VECTOR; 
	this->m_MaxDieColor = NULL_VECTOR; 
	this->m_MinDieColor = NULL_VECTOR; 
 
	this->m_Texture = NULL; 
	this->m_bUseTexture = false; 
	this->m_iBillboarding = BILLBOARDING_NONE; 
 
	//size: 
	this->m_fMaxEmitSize = 0.0f; 
	this->m_fMinEmitSize = 0.0f; 
	this->m_fMaxDieSize = 0.0f; 
	this->m_fMinDieSize = 0.0f; 
 
 
	//behavior: 
	this->m_bRecreateWhenDied = false; 
	 
	this->m_fMaxDieAge = 1.0f; 
	this->m_fMinDieAge = 1.0f; 
 
	this->m_iMaxParticles = 0;  //array is not yet created 
	this->m_iParticlesInUse = 0; 
 
	this->m_iParticlesCreatedPerSec = 0; 
	this->m_fCreationVariance = 0.0f; 
	this->m_bParticlesLeaveSystem = false; 
	this->m_pParticles = NULL; 
 
} 
//********************************************************* 
void CCCParticleSystem::SetEmitter(float x, float y, float z, float EmitterDeviationX,float EmitterDeviationY,float EmitterDeviationZ) 
{ 
	SetEmitter(F3dVector(x,y,z),F3dVector(EmitterDeviationX,EmitterDeviationY,EmitterDeviationZ)); 
} 
 
void CCCParticleSystem::SetEmitter(SF3dVector pos, SF3dVector dev) 
{ 
	m_EmitterPosition = pos; 
	m_MaxCreationDeviation = dev; 
} 
 
void CCCParticleSystem::SetEmissionDirection(float x, float y, float z, 
											 float MaxDeviationX, float MaxDeviationY, float MaxDeviationZ) 
{ 
	SetEmissionDirection(F3dVector(x,y,z),F3dVector(MaxDeviationX,MaxDeviationY,MaxDeviationZ)); 
} 
 
 
void CCCParticleSystem::SetEmissionDirection(SF3dVector direction, SF3dVector Deviation) 
{ 
	m_StandardEmitDirection = direction; 
	m_MaxEmitDirectionDeviation = Deviation; 
} 
 
 
 
 
void CCCParticleSystem::SetSpinSpeed(float min, float max) 
{ 
	m_fMinEmitSpinSpeed = min; 
	m_fMaxEmitSpinSpeed = max; 
} 
 
 
void CCCParticleSystem::SetAcceleration(float x, float y, float z, float Min, float Max) 
{ 
	SetAcceleration(F3dVector(x,y,z),Min,Max); 
} 
 
void CCCParticleSystem::SetAcceleration(SF3dVector acc, float Min, float Max) 
{ 
	m_AccelerationDirection = acc; 
	m_fMaxAcceleration = Max; 
	m_fMinAcceleration = Min; 
} 
 
void CCCParticleSystem::SetCreationColor(float minr, float ming, float minb, 
						   				 float maxr, float maxg, float maxb) 
{ 
	SetCreationColor(F3dVector(minr,ming,minb),F3dVector(maxr,maxg,maxb)); 
} 
 
void CCCParticleSystem::SetCreationColor(SF3dVector min, SF3dVector max) 
{ 
	m_MinEmitColor = min; 
	m_MaxEmitColor = max; 
} 
 
 
void CCCParticleSystem::SetDieColor	(float minr, float ming, float minb, 
						   		     float maxr, float maxg, float maxb) 
{ 
	SetDieColor(F3dVector(minr,ming,minb),F3dVector(maxr,maxg,maxb)); 
} 
 
void CCCParticleSystem::SetDieColor		(SF3dVector min, SF3dVector max) 
{ 
	m_MinDieColor = min; 
	m_MaxDieColor = max; 
} 
 
void CCCParticleSystem::SetAlphaValues (float MinEmit, float MaxEmit, float MinDie, float MaxDie) 
{ 
	m_fMinEmitAlpha = MinEmit; 
	m_fMaxEmitAlpha = MaxEmit; 
	m_fMinDieAlpha = MinDie; 
	m_fMaxDieAlpha = MaxDie; 
} 
 
void CCCParticleSystem::SetSizeValues (float EmitMin, float EmitMax, float DieMin, float DieMax) 
{ 
	m_fMinEmitSize = EmitMin; 
	m_fMaxEmitSize = EmitMax; 
	m_fMinDieSize = DieMin; 
	m_fMaxDieSize = DieMax; 
} 
//********************************************************* 
 
bool CCCParticleSystem::Initialize(int iNumParticles) 
{ 
	this->m_pParticles = new CCCParticle[iNumParticles]; 
	if (m_pParticles == NULL)  
	{ 
		return false; 
		this->m_iMaxParticles = 0; 
		this->m_iParticlesInUse = 0; 
	} 
 
	this->m_iMaxParticles = iNumParticles; 
	this->m_iParticlesInUse = 0; 
 
	//Set the status of each particle to DEAD 
	for (int i = 0; i < iNumParticles; i++) 
	{ 
		m_pParticles[i].m_bIsAlive = false; 
	} 
 
	return true; 
 
 
	 
} 
 
 
void CCCParticleSystem::UpdateSystem(float timePassed) 
{ 
	//We have to  
	//  -update the particles (= move the particles, change their alpha, color, speed values) 
	//  -create new particles, if desired and there are "free" particles 
 
	//First get the number of particles we want to create (randomly in a certain dimension (dependent of m_CreationVariance) 
	 
	int iParticlesToCreate = (int) ((float)m_iParticlesCreatedPerSec 
										   *timePassed 
		                                   *(1.0f+m_fCreationVariance*(RANDOM_FLOAT-0.5f))); 
	 
 
	//loop through the particles and update / create them 
	for (int i = 0; i < m_iMaxParticles; i++) 
	{ 
		if (m_pParticles[i].m_bIsAlive) 
		{ 
			m_pParticles[i].Update(timePassed); 
		} 
 
		//Should we create the particle? 
		if (iParticlesToCreate > 0) 
		{ 
			if (!m_pParticles[i].m_bIsAlive) 
			{ 
				m_pParticles[i].Initialize(this); 
				//Update the particle: This has an effect, as if the particle would have 
				//been emitted some milliseconds ago. This is very useful on slow PCs: 
				//Especially if you simulate something like rain, then you could see that  
				//many particles are emitted at the same time (same "UpdateSystem" call), 
				//if you would not call this function:				 
				m_pParticles[i].Update(RANDOM_FLOAT*timePassed);   
				iParticlesToCreate--; 
			} 
		} 
 
	} 
	 
} 
 
bool CCCParticleSystem::LoadTextureFromFile(char * Filename) 
{ 
	//Create the texture pointer: 
	m_Texture = new COGLTexture; 
 
	if (m_Texture == NULL) return false; 
 
	if (!m_Texture->LoadFromTGA(Filename,NULL,true)) return false;  //pass NULL as 2. param (only required if you want to combine rgb and alpha maps) 
 
	m_Texture->SetActive(); 
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
	 
	 
	m_bUseTexture = true; 
 
 
	return true; 
 
} 
 
 
void CCCParticleSystem::Render() 
{ 
	//the calling method must switch on texturing! 
 
	if (m_bUseTexture) 
	{ 
		m_Texture->SetActive(); 
		//Calculate the "billboarding vectors" (the particles only store their positions, but we need quadrangles!) 
		switch (m_iBillboarding) 
		{ 
		case BILLBOARDING_NONE: 
			{ 
				//independent from camera / view direction 
				m_BillboardedX = F3dVector(1.0f,0.0f,0.0f); 
				m_BillboardedY = F3dVector(0.0f,1.0f,0.0f); 
				break; 
			} 
		case BILLBOARDING_PERPTOVIEWDIR: 
			{ 
				//Retrieve the up and right vector from the modelview matrix: 
				float fModelviewMatrix[16]; 
				glGetFloatv(GL_MODELVIEW_MATRIX, fModelviewMatrix); 
 
				//Assign the x-Vector for billboarding: 
				m_BillboardedX = F3dVector(fModelviewMatrix[0], fModelviewMatrix[4], fModelviewMatrix[8]); 
 
				//Assign the y-Vector for billboarding: 
				m_BillboardedY = F3dVector(fModelviewMatrix[1], fModelviewMatrix[5], fModelviewMatrix[9]); 
				break; 
			} 
		case BILLBOARDING_PERPTOVIEWDIR_BUTVERTICAL: 
			{ 
				//Retrieve the right vector from the modelview matrix: 
				float fModelviewMatrix[16]; 
				glGetFloatv(GL_MODELVIEW_MATRIX, fModelviewMatrix); 
 
				//Assign the x-Vector for billboarding: 
				m_BillboardedX = F3dVector(fModelviewMatrix[0], fModelviewMatrix[4], fModelviewMatrix[8]); 
 
				//Assign the y-Vector: 
				m_BillboardedY = F3dVector(0.0f,1.0f,0.0f);				 
				break; 
			} 
		} 
	} 
	else 
	{ 
		glGetFloatv(GL_POINT_SIZE,&m_fCurrentPointSize); 
	} 
	for (int i = 0; i < m_iMaxParticles; i++) 
	{ 
		if (m_pParticles[i].m_bIsAlive) 
			m_pParticles[i].Render(); 
	} 
}