Beispiel #1
0
//------------------------------------------------------------------------------
//
void
	gosFX::ParticleCloud::Start(ExecuteInfo *info)
{
	Check_Object(this);
	Check_Pointer(info);

	//
	//--------------------------------------------------------------------------
	// Let effect initialize, then figure out how many particles we want to make
	//--------------------------------------------------------------------------
	//
	Effect::Start(info);
	Specification *spec = GetSpecification();
	Check_Object(spec);
	Stuff::Scalar newbies =
		spec->m_startingPopulation.ComputeValue(m_age, m_seed);
	Min_Clamp(newbies, 0.0f);
	m_birthAccumulator += newbies;
}
Beispiel #2
0
//------------------------------------------------------------------------------
//
void
	gosFX::Effect::Start(ExecuteInfo *info)
{
	Check_Object(this);
	Check_Pointer(info);
	gos_PushCurrentHeap(Heap);

	//
	//---------------------------------------------------------------------
	// Don't override m_lastran if we are issuing a Start command while the
	// effect is already running
	//---------------------------------------------------------------------
	//
	if (!IsExecuted() || m_lastRan == -1.0)
		m_lastRan = info->m_time;
	SetExecuteOn();

	//
	//-------------------------------------------
	// If no seed was provided, pick one randomly
	//-------------------------------------------
	//
	m_seed = (info->m_seed == -1.0f) ? Stuff::Random::GetFraction() : info->m_seed;
	Verify(m_seed >= 0.0f && m_seed <= 1.0f);

	//
	//--------------------------------------------------------------------
	// Figure out how long the emitter will live and its initial age based
	// upon the effect seed
	//--------------------------------------------------------------------
	//
	Check_Object(m_specification);
	if (info->m_age == -1.0f)
	{
		Stuff::Scalar lifetime =
			m_specification->m_lifeSpan.ComputeValue(m_seed, 0.0f);
		Min_Clamp(lifetime, 0.033333f);
		m_ageRate = 1.0f / lifetime;
		m_age = 0;
	}
	else
	{
		m_age = info->m_age;
		m_ageRate = info->m_ageRate;
		Verify(m_age >= 0.0f && m_age <= 1.0f);
	}

	//
	//--------------------
	// Set up the matrices
	//--------------------
	//
	Check_Object(info->m_parentToWorld);
	m_localToWorld.Multiply(m_localToParent, *info->m_parentToWorld);

	//
	//-------------------------
	// Set up the event pointer
	//-------------------------
	//
	m_event.First();
	gos_PopCurrentHeap();
}
Beispiel #3
0
//
//#############################################################################
//#############################################################################
//
UnitQuaternion&
	UnitQuaternion::operator=(const LinearMatrix4D &matrix)
{
	Check_Pointer(this);
	Check_Object(&matrix);

	//
	//------------------------------------------------------------------------
	// Compute the w component.  If it is close enough to zero, then we have a
	// 180 degree pivot, so figure out the correct axis to rotate around
	//------------------------------------------------------------------------
	//
	w = (1.0f + matrix(0,0) + matrix(1,1) + matrix(2,2)) * 0.25f;
	if (Small_Enough(w,1e-2f))
	{
		Verify(w >= -SMALL);
		if (w<0.0f)
		{
			w = 0.0f;
		}

		//
		//----------------------------------------------------------------
		// Figure out the length of each component of the axis of rotation
		//----------------------------------------------------------------
		//
		Scalar temp = (1.0f + matrix(0,0)) * 0.5f - w;
		Min_Clamp(temp, 0.0f);
		x = Sqrt(temp);
		temp = (1.0f + matrix(1,1)) * 0.5f - w;
		Min_Clamp(temp, 0.0f);
		y = Sqrt(temp);
		temp = (1.0f + matrix(2,2)) * 0.5f - w;
		Min_Clamp(temp, 0.0f);
		z = Sqrt(temp);
		w = Sqrt(w);

		//
		//-------------------------------------------
		// Now figure out the signs of the components
		//-------------------------------------------
		//
		if (matrix(0,1) < matrix(1,0))
		{
			z = -z;
		}
		if (matrix(2,0) < matrix(0,2))
		{
			y = -y;
		}
		if (matrix(1,2) < matrix(2,1))
		{
			x = -x;
		}
	}

	//
	//----------------------------------------------------------
	// Otherwise, determine x, y, and z directly from the matrix
	//----------------------------------------------------------
	//
	else
	{
		Verify(w>0.0f);
		w = Sqrt(w);
		x = (matrix(1,2) - matrix(2,1)) * 0.25f / w;
		y = (matrix(2,0) - matrix(0,2)) * 0.25f / w;
		z = (matrix(0,1) - matrix(1,0)) * 0.25f / w;
	}

	Normalize();
	return *this;
}
Beispiel #4
0
//------------------------------------------------------------------------------
//
void
	gosFX::ParticleCloud::CreateNewParticle(
		unsigned index,
		Stuff::Point3D *translation
	)
{
	Check_Object(this);

	//
	//----------------------------------------------------
	// Figure out the age and age rate of the new particle
	//----------------------------------------------------
	//
	Specification *spec = GetSpecification();
	Check_Object(spec);
	Particle *particle = GetParticle(index);
	Check_Object(particle);
	particle->m_age = 0.0f;
	Stuff::Scalar min_seed =
		spec->m_minimumChildSeed.ComputeValue(m_age, m_seed);
	Stuff::Scalar seed_range =
		spec->m_maximumChildSeed.ComputeValue(m_age, m_seed) - min_seed;
	Stuff::Scalar seed =
		Stuff::Random::GetFraction()*seed_range + min_seed;
	Clamp(seed, 0.0f, 1.0f);
	particle->m_seed = seed;
	Stuff::Scalar lifetime =
		spec->m_pLifeSpan.ComputeValue(m_age, seed);
	Min_Clamp(lifetime, 0.0333333f);
	particle->m_ageRate = 1.0f / lifetime;

	//
	//--------------------------------
	// Figure out the initial position
	//--------------------------------
	//
	Stuff::YawPitchRange
		initial_p(
			Stuff::Random::GetFraction() * Stuff::Two_Pi,
			Stuff::Random::GetFraction() * Stuff::Pi - Stuff::Pi_Over_2,
			Stuff::Random::GetFraction()
		);
	Stuff::Vector3D position(initial_p);
	translation->x =
		position.x * spec->m_emitterSizeX.ComputeValue(m_age, seed);
	translation->y =
		position.y * spec->m_emitterSizeY.ComputeValue(m_age, seed);
	translation->z =
		position.z * spec->m_emitterSizeZ.ComputeValue(m_age, seed);

	//
	//--------------------------------
	// Figure out the initial velocity
	//--------------------------------
	//
	Stuff::Scalar pitch_min =
		spec->m_minimumDeviation.ComputeValue(m_age, seed);
	Stuff::Scalar pitch_range =
		spec->m_maximumDeviation.ComputeValue(m_age, seed) - pitch_min;
	if (pitch_range < 0.0f)
		pitch_range = 0.0f;
	pitch_min +=
		pitch_range * Stuff::Random::GetFraction() - Stuff::Pi_Over_2;
	Stuff::YawPitchRange
		initial_v(
			Stuff::Random::GetFraction() * Stuff::Two_Pi,
			pitch_min,
			spec->m_startingSpeed.ComputeValue(m_age, seed)
		);
	particle->m_localLinearVelocity = initial_v;
}
Beispiel #5
0
//------------------------------------------------------------------------------
//
bool gosFX::ParticleCloud::Execute(ExecuteInfo *info)
{
	Check_Object(this);
	Check_Object(info);
	Verify(IsExecuted());

	//
	//--------------------------------------------------------------------
	// If we were given a new matrix, see if we have a parent.  If so,
	// concatenate the two and figure out its inverse.  If no parent, then
	// just invert the new matrix, otherwise just use the existing one
	//--------------------------------------------------------------------
	//
	Stuff::LinearMatrix4D new_world_to_local;
	Stuff::LinearMatrix4D *matrix = NULL;
	int sim_mode = GetSimulationMode();
	if (sim_mode == DynamicWorldSpaceSimulationMode)
	{
		Stuff::LinearMatrix4D local_to_world;
		local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
		new_world_to_local.Invert(local_to_world);
		matrix = &new_world_to_local;
	}

	//
	//--------------------------------------------------------
	// Figure out the birth rate and request the new particles
	//--------------------------------------------------------
	//
	Specification *spec = GetSpecification();
	Check_Object(spec);
	Stuff::Scalar dT =
		static_cast<Stuff::Scalar>(info->m_time - m_lastRan);
	Verify(dT >= 0.0f);
	Stuff::Scalar prev_age = m_age;
	m_age += dT * m_ageRate;
	if (m_age >= 1.0f)
		m_birthAccumulator = 0.0f;
	else
	{
		Stuff::Scalar new_life =
			spec->m_particlesPerSecond.ComputeValue(m_age, m_seed);
		Min_Clamp(new_life, 0.0f);
		m_birthAccumulator += dT * new_life;
	}

	//
	//-----------------------------------
	// Deal with all the active particles
	//-----------------------------------
	//
	int i;
	int last_real = -1;
	for (i = 0; i < m_activeParticleCount; i++)
	{
		//
		//--------------------------------------------------------------------
		// If the particle is active, age it and if it is not yet time to die,
		// go to the next particle, otherwise kill it
		//--------------------------------------------------------------------
		//
		Particle *particle = GetParticle(i);
		Check_Object(particle);
		if (particle->m_age < 1.0f)
		{
			particle->m_age += dT*particle->m_ageRate;
			if (AnimateParticle(i, matrix, info->m_time))
			{
				last_real = i;
				continue;
			}
			DestroyParticle(i);
		}

		//
		//--------------------------------------------------------------------
		// If there are new particles to be born, go ahead and create them now
		//--------------------------------------------------------------------
		//
		if (m_birthAccumulator >= 1.0f)
		{
			Stuff::Point3D translation;
			CreateNewParticle(i, &translation);
			if (AnimateParticle(i, matrix, info->m_time))
				last_real = i;
			else
				DestroyParticle(i);
			m_birthAccumulator -= 1.0f;
		}
	}
	m_activeParticleCount = last_real + 1;

	//
	//----------------------------------------------------------------------
	// If there are still new particles to be born, then we must try to grow
	// the active particle count
	//----------------------------------------------------------------------
	//
	while (
		m_birthAccumulator >= 1.0f
		 && m_activeParticleCount < spec->m_maxParticleCount
	)
	{
		i = m_activeParticleCount++;
		Stuff::Point3D translation;
		CreateNewParticle(i, &translation);
		if (!AnimateParticle(i, matrix, info->m_time))
		{
			DestroyParticle(i);
			--m_activeParticleCount;
		}
		m_birthAccumulator -= 1.0f;
	}

	//
	//---------------------------------------------------------
	// Only allow fractional births to carry over to next frame
	//---------------------------------------------------------
	//
	m_birthAccumulator -= static_cast<Stuff::Scalar>(floor(m_birthAccumulator));

	//
	//----------------------------
	// Now let effect do its thing
	//----------------------------
	//
	m_age = prev_age;
	return Effect::Execute(info);
}
Beispiel #6
0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
Line3D::GetDistanceTo(
    const Sphere &sphere,
    Scalar *penetration
) const
{
    Check_Object(this);
    Check_Object(&sphere);
    Check_Pointer(penetration);

    //
    //-------------------------------------------------------------------
    // Determine if ray intersects bounding sphere of object.  If sphere
    // is (X-C)*(X-C) = R^2 and ray is X = t*D+L for t >= 0, then
    // intersection is obtained by plugging X into sphere equation to
    // get quadratic:  (D*D)t^2 + 2*(D*(L-C))t + (L-C)*(L-C) = 0
    // Define a = D*D = 1.0f, b = 2*(D*(L-C)), and c = (L-C)*(L-C).
    //-------------------------------------------------------------------
    //
    Vector3D diff;
    diff.Subtract(origin, sphere.center);
    Scalar b = (direction*diff) * 2.0f;
    Scalar c = (diff*diff) - sphere.radius*sphere.radius;

    //
    //-------------------------------------------------------------------------
    // If penetration is negative, we couldn't hit the sphere at all.  If it is
    // really small, it touches at only one place
    //-------------------------------------------------------------------------
    //
    *penetration = b*b - 4.0f*c;
    if (*penetration < -SMALL)
    {
        return -1.0f;
    }
    b *= -0.5f;
    if (*penetration<SMALL)
    {
        *penetration = 0.0f;
        Min_Clamp(b, 0.0f);
        return (b > length) ? -1.0f : b;
    }

    //
    //-------------------------------------------------------------
    // We know we hit the sphere, so figure out where it first hits
    //-------------------------------------------------------------
    //
    *penetration = 0.5f * Sqrt(*penetration);
    if (b + *penetration < -SMALL)
    {
        return -1.0f;
    }
    b -= *penetration;
    if (b > length)
    {
        return -1.0f;
    }
    Min_Clamp(b, 0.0f);
    return b;
}
Beispiel #7
0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
Line3D::GetDistanceTo(
    const OBB& box,
    int *first_axis
)
{
    Check_Object(this);
    Check_Object(&box);
    Check_Pointer(first_axis);

    //
    //------------------------------------------------------------------------
    // Get the vector from the line to the centerpoint of the OBB.  All planes
    // will be generated relative to this
    //------------------------------------------------------------------------
    //
    Point3D center;
    center = box.localToParent;
    Vector3D delta;
    delta.Subtract(center, origin);

    //
    //--------------------------------------------------
    // Set up the loop to examine each of the three axes
    //--------------------------------------------------
    //
    Scalar enters = -100.0f - length;
    Scalar leaves = length + 100.0f;
    for (int axis=X_Axis; axis <= Z_Axis; ++axis)
    {
        UnitVector3D
        normal(
            box.localToParent(axis, X_Axis),
            box.localToParent(axis, Y_Axis),
            box.localToParent(axis, Z_Axis)
        );

        //
        //----------------------------------------------------------------------
        // Now, we have to calculate how far the line moves along the normal per
        // unit traveled down the line.  If it is perpendicular to the normal,
        // then it will hit or miss based solely upon the origin location
        //----------------------------------------------------------------------
        //
        Scalar drift = direction * normal;
        Scalar distance;
        if (Small_Enough(drift))
        {
            distance = delta * normal;
            if (Fabs(distance) > box.axisExtents[axis])
                return -1.0f;
            else
                continue;
        }

        //
        //--------------------------------------------------------------------
        // We know the line is not parallel, so we will now calculate how long
        // the line will stay inside the box.  We also will calculate how far
        // from the origin to the centerplane of the OBB
        //--------------------------------------------------------------------
        //
        drift = 1.0f / drift;
        Scalar span = box.axisExtents[axis] * Fabs(drift);
        distance = (delta * normal) * drift;

        //
        //--------------------------------------------------------------------
        // Now adjust where the line can enter and leave the OBB, and if it is
        // no longer possible to hit, stop checking
        //--------------------------------------------------------------------
        //
        Scalar enter = distance - span;
        Scalar leave = distance + span;
        if (enter > enters)
        {
            *first_axis = axis;
            enters = enter;
        }
        if (leave < leaves)
            leaves = leave;
        if (enters > leaves)
            return -1.0f;
    }

    //
    //-------------------------------------------------------------------------
    // If we got here, then the line in theory can hit the OBB, so now we check
    // to make sure it hits it within the allowed span of the line
    //-------------------------------------------------------------------------
    //
    if (leaves < 0.0f || enters > length)
        return -1.0f;
    Min_Clamp(enters, 0.0f);
    return enters;
}