Ejemplo n.º 1
0
/*
===============
idParticleStage::ParticleOrigin
===============
*/
void idParticleStage::ParticleOrigin( particleGen_t* g, idVec3& origin ) const
{
	if( customPathType == PPATH_STANDARD )
	{
		//
		// find intial origin distribution
		//
		float radiusSqr, angle1, angle2;
		
		switch( distributionType )
		{
			case PDIST_RECT:  	// ( sizeX sizeY sizeZ )
			{
				origin[0] = ( ( randomDistribution ) ? g->random.CRandomFloat() : 1.0f ) * distributionParms[0];
				origin[1] = ( ( randomDistribution ) ? g->random.CRandomFloat() : 1.0f ) * distributionParms[1];
				origin[2] = ( ( randomDistribution ) ? g->random.CRandomFloat() : 1.0f ) * distributionParms[2];
				break;
			}
			case PDIST_CYLINDER:  	// ( sizeX sizeY sizeZ ringFraction )
			{
				angle1 = ( ( randomDistribution ) ? g->random.CRandomFloat() : 1.0f ) * idMath::TWO_PI;
				
				idMath::SinCos16( angle1, origin[0], origin[1] );
				origin[2] = ( ( randomDistribution ) ? g->random.CRandomFloat() : 1.0f );
				
				// reproject points that are inside the ringFraction to the outer band
				if( distributionParms[3] > 0.0f )
				{
					radiusSqr = origin[0] * origin[0] + origin[1] * origin[1];
					if( radiusSqr < distributionParms[3] * distributionParms[3] )
					{
						// if we are inside the inner reject zone, rescale to put it out into the good zone
						float f = sqrt( radiusSqr ) / distributionParms[3];
						float invf = 1.0f / f;
						float newRadius = distributionParms[3] + f * ( 1.0f - distributionParms[3] );
						float rescale = invf * newRadius;
						
						origin[0] *= rescale;
						origin[1] *= rescale;
					}
				}
				origin[0] *= distributionParms[0];
				origin[1] *= distributionParms[1];
				origin[2] *= distributionParms[2];
				break;
			}
			case PDIST_SPHERE:  	// ( sizeX sizeY sizeZ ringFraction )
			{
				// iterating with rejection is the only way to get an even distribution over a sphere
				if( randomDistribution )
				{
					do
					{
						origin[0] = g->random.CRandomFloat();
						origin[1] = g->random.CRandomFloat();
						origin[2] = g->random.CRandomFloat();
						radiusSqr = origin[0] * origin[0] + origin[1] * origin[1] + origin[2] * origin[2];
					}
					while( radiusSqr > 1.0f );
				}
				else
				{
					origin.Set( 1.0f, 1.0f, 1.0f );
					radiusSqr = 3.0f;
				}
				
				if( distributionParms[3] > 0.0f )
				{
					// we could iterate until we got something that also satisfied ringFraction,
					// but for narrow rings that could be a lot of work, so reproject inside points instead
					if( radiusSqr < distributionParms[3] * distributionParms[3] )
					{
						// if we are inside the inner reject zone, rescale to put it out into the good zone
						float f = sqrt( radiusSqr ) / distributionParms[3];
						float invf = 1.0f / f;
						float newRadius = distributionParms[3] + f * ( 1.0f - distributionParms[3] );
						float rescale = invf * newRadius;
						
						origin[0] *= rescale;
						origin[1] *= rescale;
						origin[2] *= rescale;
					}
				}
				origin[0] *= distributionParms[0];
				origin[1] *= distributionParms[1];
				origin[2] *= distributionParms[2];
				break;
			}
		}
		
		// offset will effect all particle origin types
		// add this before the velocity and gravity additions
		origin += offset;
		
		//
		// add the velocity over time
		//
		idVec3	dir;
		
		switch( directionType )
		{
			case PDIR_CONE:
			{
				// angle is the full angle, so 360 degrees is any spherical direction
				angle1 = g->random.CRandomFloat() * directionParms[0] * idMath::M_DEG2RAD;
				angle2 = g->random.CRandomFloat() * idMath::PI;
				
				float s1, c1, s2, c2;
				idMath::SinCos16( angle1, s1, c1 );
				idMath::SinCos16( angle2, s2, c2 );
				
				dir[0] = s1 * c2;
				dir[1] = s1 * s2;
				dir[2] = c1;
				break;
			}
			case PDIR_OUTWARD:
			{
				dir = origin;
				dir.Normalize();
				dir[2] += directionParms[0];
				break;
			}
		}
		
		// add speed
		float iSpeed = speed.Integrate( g->frac, g->random );
		origin += dir * iSpeed * particleLife;
		
	}
	else
	{
		//
		// custom paths completely override both the origin and velocity calculations, but still
		// use the standard gravity
		//
		float angle1, angle2, speed1, speed2;
		switch( customPathType )
		{
			case PPATH_HELIX:  		// ( sizeX sizeY sizeZ radialSpeed axialSpeed )
			{
				speed1 = g->random.CRandomFloat();
				speed2 = g->random.CRandomFloat();
				angle1 = g->random.RandomFloat() * idMath::TWO_PI + customPathParms[3] * speed1 * g->age;
				
				float s1, c1;
				idMath::SinCos16( angle1, s1, c1 );
				
				origin[0] = c1 * customPathParms[0];
				origin[1] = s1 * customPathParms[1];
				origin[2] = g->random.RandomFloat() * customPathParms[2] + customPathParms[4] * speed2 * g->age;
				break;
			}
			case PPATH_FLIES:  		// ( radialSpeed axialSpeed size )
			{
				speed1 = idMath::ClampFloat( 0.4f, 1.0f, g->random.CRandomFloat() );
				speed2 = idMath::ClampFloat( 0.4f, 1.0f, g->random.CRandomFloat() );
				angle1 = g->random.RandomFloat() * idMath::PI * 2 + customPathParms[0] * speed1 * g->age;
				angle2 = g->random.RandomFloat() * idMath::PI * 2 + customPathParms[1] * speed1 * g->age;
				
				float s1, c1, s2, c2;
				idMath::SinCos16( angle1, s1, c1 );
				idMath::SinCos16( angle2, s2, c2 );
				
				origin[0] = c1 * c2;
				origin[1] = s1 * c2;
				origin[2] = -s2;
				origin *= customPathParms[2];
				break;
			}
			case PPATH_ORBIT:  		// ( radius speed axis )
			{
				angle1 = g->random.RandomFloat() * idMath::TWO_PI + customPathParms[1] * g->age;
				
				float s1, c1;
				idMath::SinCos16( angle1, s1, c1 );
				
				origin[0] = c1 * customPathParms[0];
				origin[1] = s1 * customPathParms[0];
				origin.ProjectSelfOntoSphere( customPathParms[0] );
				break;
			}
			case PPATH_DRIP:  		// ( speed )
			{
				origin[0] = 0.0f;
				origin[1] = 0.0f;
				origin[2] = -( g->age * customPathParms[0] );
				break;
			}
			default:
			{
				common->Error( "idParticleStage::ParticleOrigin: bad customPathType" );
			}
		}
		
		origin += offset;
	}
	
	// adjust for the per-particle smoke offset
	origin *= g->axis;
	origin += g->origin;
	
	// add gravity after adjusting for axis
	if( worldGravity )
	{
		idVec3 gra( 0, 0, -gravity );
		gra *= g->renderEnt->axis.Transpose();
		origin += gra * g->age * g->age;
	}
	else
	{
		origin[2] -= gravity * g->age * g->age;
	}
}