Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
894 lines
27 KiB
C++
894 lines
27 KiB
C++
#include "gosFXHeaders.hpp"
|
|
#include <MLR\MLRShape.hpp>
|
|
|
|
//==========================================================================//
|
|
// File: gosFX_DebrisCloud.cpp //
|
|
// Project: gosFX //
|
|
// Contents: Base gosFX::DebrisCloud Component //
|
|
//--------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// 09/28/98 JTR Created //
|
|
// //
|
|
//--------------------------------------------------------------------------//
|
|
// Copyright (C) 1997-1998, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//==========================================================================//
|
|
//
|
|
//############################################################################
|
|
//######################## gosFX::DebrisCloud__Specification #############################
|
|
//############################################################################
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::DebrisCloud__Specification::DebrisCloud__Specification(
|
|
Stuff::MemoryStream *stream,
|
|
int gfx_version
|
|
):
|
|
Effect__Specification(gosFX::DebrisCloudClassID, stream, gfx_version)
|
|
{
|
|
Check_Pointer(this);
|
|
Verify(m_class == DebrisCloudClassID);
|
|
|
|
m_minimumDeviation.Load(stream, gfx_version); // ConstantCurve
|
|
m_maximumDeviation.Load(stream, gfx_version); // SplineCurve
|
|
m_startingSpeed.Load(stream, gfx_version); // SeededCurveOf<ComplexCurve, ComplexCurve,Curve::e_ComplexComplexType>
|
|
m_pLifeSpan.Load(stream, gfx_version); // SeededCurveOf<ComplexCurve, SplineCurve,Curve::e_ComplexSplineType>
|
|
m_pEtherVelocityY.Load(stream, gfx_version); // SeededCurveOf<ConstantCurve, LinearCurve,Curve::e_ConstantLinearType>
|
|
m_pAccelerationY.Load(stream, gfx_version); // SeededCurveOf<SplineCurve, LinearCurve,Curve::e_SplineLinearType>
|
|
m_pDrag.Load(stream, gfx_version); // SeededCurveOf<ComplexCurve, ComplexCurve,Curve::e_ComplexComplexType>
|
|
m_pAlpha.Load(stream, gfx_version); // SeededCurveOf<ComplexCurve, LinearCurve,Curve::e_ComplexLinearType>
|
|
m_pSpin.Load(stream, gfx_version); // SeededCurveOf<ConstantCurve, LinearCurve,Curve::e_ConstantLinearType>
|
|
|
|
*stream >> m_centerOfForce; // Stuff::Point3D
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// For older data, read in the stream then KILL it
|
|
//------------------------------------------------
|
|
//
|
|
if (gfx_version<25)
|
|
{
|
|
LoadGeometry(stream);
|
|
int i, nrOfParticles = m_debrisPieces.GetLength();
|
|
for(i=0;i<nrOfParticles;i++)
|
|
{
|
|
Check_Object(m_debrisPieces[i]);
|
|
m_debrisPieces[i]->DetachReference();
|
|
}
|
|
m_debrisPieces.SetLength(0);
|
|
m_debrisPositions.SetLength(0);
|
|
m_debrisSpheres.SetLength(0);
|
|
m_debrisSeed.SetLength(0);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Otherwise, read in the specified file
|
|
//--------------------------------------
|
|
//
|
|
else
|
|
{
|
|
*stream >> m_shapeFile;
|
|
|
|
if(m_shapeFile)
|
|
EffectLibrary::Instance->LoadDebrisArray(this, m_shapeFile);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::DebrisCloud__Specification::DebrisCloud__Specification():
|
|
Effect__Specification(gosFX::DebrisCloudClassID)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
m_debrisPieces.SetLength(0);
|
|
m_debrisPositions.SetLength(0);
|
|
m_debrisSpheres.SetLength(0);
|
|
m_debrisSeed.SetLength(0);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::DebrisCloud__Specification::~DebrisCloud__Specification()
|
|
{
|
|
Check_Object(this);
|
|
|
|
int i, nrOfParticles = m_debrisPieces.GetLength();
|
|
|
|
for(i=0;i<nrOfParticles;i++)
|
|
{
|
|
Check_Object(m_debrisPieces[i]);
|
|
m_debrisPieces[i]->DetachReference();
|
|
}
|
|
|
|
m_debrisPieces.SetLength(0);
|
|
m_debrisPositions.SetLength(0);
|
|
m_debrisSpheres.SetLength(0);
|
|
m_debrisSeed.SetLength(0);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::DebrisCloud__Specification*
|
|
gosFX::DebrisCloud__Specification::Make(
|
|
Stuff::MemoryStream *stream,
|
|
int gfx_version
|
|
)
|
|
{
|
|
Check_Object(stream);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
DebrisCloud__Specification *spec =
|
|
new gosFX::DebrisCloud__Specification(stream, gfx_version);
|
|
gos_PopCurrentHeap();
|
|
|
|
return spec;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud__Specification::Save(Stuff::MemoryStream *stream)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(stream);
|
|
BaseClass::Save(stream);
|
|
|
|
m_minimumDeviation.Save(stream); // ConstantCurve
|
|
m_maximumDeviation.Save(stream); // SplineCurve
|
|
m_startingSpeed.Save(stream); // SeededCurveOf<ComplexCurve, ComplexCurve,Curve::e_ComplexComplexType>
|
|
m_pLifeSpan.Save(stream); // SeededCurveOf<ComplexCurve, SplineCurve,Curve::e_ComplexSplineType>
|
|
m_pEtherVelocityY.Save(stream); // SeededCurveOf<ConstantCurve, LinearCurve,Curve::e_ConstantLinearType>
|
|
m_pAccelerationY.Save(stream); // SeededCurveOf<SplineCurve, LinearCurve,Curve::e_SplineLinearType>
|
|
m_pDrag.Save(stream); // SeededCurveOf<ComplexCurve, ComplexCurve,Curve::e_ComplexComplexType>
|
|
m_pAlpha.Save(stream); // SeededCurveOf<ComplexCurve, LinearCurve,Curve::e_ComplexLinearType>
|
|
m_pSpin.Save(stream); // SeededCurveOf<ConstantCurve, LinearCurve,Curve::e_ConstantLinearType>
|
|
|
|
*stream << m_centerOfForce; // Stuff::Point3D
|
|
*stream << m_shapeFile;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud__Specification::Copy(DebrisCloud__Specification *spec)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(spec);
|
|
|
|
BaseClass::Copy(spec);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
|
|
m_minimumDeviation = spec->m_minimumDeviation; // ConstantCurve
|
|
m_maximumDeviation = spec->m_maximumDeviation; // SplineCurve
|
|
m_startingSpeed = spec->m_startingSpeed; // SeededCurveOf<ComplexCurve, ComplexCurve,Curve::e_ComplexComplexType>
|
|
m_pLifeSpan = spec->m_pLifeSpan; // SeededCurveOf<ComplexCurve, SplineCurve,Curve::e_ComplexSplineType>
|
|
m_pEtherVelocityY = spec->m_pEtherVelocityY; // SeededCurveOf<ConstantCurve, LinearCurve,Curve::e_ConstantLinearType>
|
|
m_pAccelerationY = spec->m_pAccelerationY; // SeededCurveOf<SplineCurve, LinearCurve,Curve::e_SplineLinearType>
|
|
m_pDrag = spec->m_pDrag; // SeededCurveOf<ComplexCurve, ComplexCurve,Curve::e_ComplexComplexType>
|
|
m_pAlpha = spec->m_pAlpha; // SeededCurveOf<ComplexCurve, LinearCurve,Curve::e_ComplexLinearType>
|
|
m_pSpin = spec->m_pSpin; // SeededCurveOf<ConstantCurve, LinearCurve,Curve::e_ConstantLinearType>
|
|
|
|
m_centerOfForce = spec->m_centerOfForce; // Stuff::Point3D
|
|
m_shapeFile = spec->m_shapeFile;
|
|
|
|
int i, nrOfParticles = spec->m_debrisPieces.GetLength();
|
|
|
|
m_debrisPieces.SetLength(nrOfParticles);
|
|
m_debrisPositions.SetLength(nrOfParticles);
|
|
m_debrisSpheres.SetLength(nrOfParticles);
|
|
m_debrisSeed.SetLength(nrOfParticles);
|
|
|
|
for(i=0;i<nrOfParticles;i++)
|
|
{
|
|
m_debrisPositions[i] = spec->m_debrisPositions[i];
|
|
m_debrisSpheres[i] = spec->m_debrisSpheres[i];
|
|
|
|
m_debrisPieces[i] = spec->m_debrisPieces[i];
|
|
|
|
Check_Object(m_debrisPieces[i]);
|
|
m_debrisPieces[i]->AttachReference();
|
|
|
|
m_debrisSeed[i] = spec->m_debrisSeed[i];
|
|
}
|
|
gos_PopCurrentHeap();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud__Specification::LoadGeometry(Stuff::MemoryStream *stream)
|
|
{
|
|
int i, mlrVersion, nrOfParticles;
|
|
|
|
mlrVersion = MidLevelRenderer::ReadMLRVersion(stream);
|
|
*stream >> nrOfParticles;
|
|
|
|
m_debrisPieces.SetLength(nrOfParticles);
|
|
m_debrisPositions.SetLength(nrOfParticles);
|
|
m_debrisSpheres.SetLength(nrOfParticles);
|
|
m_debrisSeed.SetLength(nrOfParticles);
|
|
|
|
Stuff::Scalar minRadius = 100000000000.0f, maxRadius = 0.0f;
|
|
|
|
for(i=0;i<nrOfParticles;i++)
|
|
{
|
|
*stream >> m_debrisPositions[i];
|
|
|
|
*stream >> m_debrisSpheres[i].center;
|
|
*stream >> m_debrisSpheres[i].radius;
|
|
|
|
if(m_debrisSpheres[i].radius < minRadius)
|
|
minRadius = m_debrisSpheres[i].radius;
|
|
if(m_debrisSpheres[i].radius > maxRadius)
|
|
maxRadius = m_debrisSpheres[i].radius;
|
|
|
|
//
|
|
//---------------
|
|
// Load the shape
|
|
//---------------
|
|
//
|
|
m_debrisPieces[i] =
|
|
MidLevelRenderer::MLRShape::Make(
|
|
stream,
|
|
mlrVersion
|
|
);
|
|
Check_Object(m_debrisPieces[i]);
|
|
}
|
|
|
|
Verify(maxRadius > minRadius);
|
|
for(i=0;i<nrOfParticles;i++)
|
|
{
|
|
m_debrisSeed[i] = (m_debrisSpheres[i].radius-minRadius)/(maxRadius-minRadius);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud__Specification::BuildDefaults()
|
|
{
|
|
|
|
Check_Object(this);
|
|
BaseClass::BuildDefaults();
|
|
|
|
m_centerOfForce = Stuff::Point3D(0.0f, 00.0f, 0.0f);
|
|
|
|
m_lifeSpan.SetCurve(20.0f);
|
|
|
|
m_minimumDeviation.SetCurve(0.0f);
|
|
m_maximumDeviation.SetCurve(Stuff::Pi_Over_6);
|
|
|
|
m_startingSpeed.m_ageCurve.SetCurve(1.0f);
|
|
m_startingSpeed.m_seeded = true;
|
|
m_startingSpeed.m_seedCurve.SetCurve(1.0f, 3.0f);
|
|
|
|
m_pEtherVelocityY.m_ageCurve.SetCurve(0.0f);
|
|
m_pEtherVelocityY.m_seeded = false;
|
|
m_pEtherVelocityY.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pAccelerationY.m_ageCurve.SetCurve(-9.8f);
|
|
m_pAccelerationY.m_seeded = false;
|
|
m_pAccelerationY.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pDrag.m_ageCurve.SetCurve(0.3f);
|
|
m_pDrag.m_seeded = false;
|
|
m_pDrag.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pAlpha.m_ageCurve.SetCurve(1.0f);
|
|
m_pAlpha.m_seeded = false;
|
|
m_pAlpha.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pSpin.m_ageCurve.SetCurve(Stuff::Pi_Over_2);
|
|
m_pSpin.m_seeded = true;
|
|
m_pSpin.m_seedCurve.SetCurve(-1.0f, 1.0f);
|
|
|
|
m_pLifeSpan.m_ageCurve.SetCurve(20.0f);
|
|
m_pLifeSpan.m_seeded = false;
|
|
m_pLifeSpan.m_seedCurve.SetCurve(1.0f);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
bool
|
|
gosFX::DebrisCloud__Specification::IsDataValid(bool fix_data)
|
|
{
|
|
|
|
Check_Object(this);
|
|
return BaseClass::IsDataValid(fix_data);
|
|
/*
|
|
m_centerOfForce = Stuff::Point3D(0.0f, 00.0f, 0.0f);
|
|
|
|
m_lifeSpan.SetCurve(20.0f);
|
|
|
|
m_minimumDeviation.SetCurve(0.0f);
|
|
m_maximumDeviation.SetCurve(Stuff::Pi_Over_6);
|
|
|
|
m_startingSpeed.m_ageCurve.SetCurve(1.0f);
|
|
m_startingSpeed.m_seeded = true;
|
|
m_startingSpeed.m_seedCurve.SetCurve(1.0f, 3.0f);
|
|
|
|
m_pEtherVelocityY.m_ageCurve.SetCurve(0.0f);
|
|
m_pEtherVelocityY.m_seeded = false;
|
|
m_pEtherVelocityY.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pAccelerationY.m_ageCurve.SetCurve(-9.8f);
|
|
m_pAccelerationY.m_seeded = false;
|
|
m_pAccelerationY.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pDrag.m_ageCurve.SetCurve(0.3f);
|
|
m_pDrag.m_seeded = false;
|
|
m_pDrag.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pAlpha.m_ageCurve.SetCurve(1.0f);
|
|
m_pAlpha.m_seeded = false;
|
|
m_pAlpha.m_seedCurve.SetCurve(1.0f);
|
|
|
|
m_pSpin.m_ageCurve.SetCurve(Stuff::Pi_Over_2);
|
|
m_pSpin.m_seeded = true;
|
|
m_pSpin.m_seedCurve.SetCurve(-1.0f, 1.0f);
|
|
|
|
m_pLifeSpan.m_ageCurve.SetCurve(20.0f);
|
|
m_pLifeSpan.m_seeded = false;
|
|
m_pLifeSpan.m_seedCurve.SetCurve(1.0f);
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
//############################################################################
|
|
//########################## gosFX::DebrisCloud ############################
|
|
//############################################################################
|
|
|
|
gosFX::DebrisCloud::ClassData*
|
|
gosFX::DebrisCloud::DefaultData = NULL;
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
DebrisCloudClassID,
|
|
"gosFX::DebrisCloud",
|
|
BaseClass::DefaultData,
|
|
(Effect::Factory)&Make,
|
|
(Specification::Factory)&Specification::Make
|
|
);
|
|
Check_Object(DefaultData);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::DebrisCloud::DebrisCloud(
|
|
Specification *spec,
|
|
unsigned flags
|
|
):
|
|
Effect(DefaultData, spec, flags)
|
|
{
|
|
m_debrisPieces.SetLength(spec->m_debrisPieces.GetLength());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
gosFX::DebrisCloud*
|
|
gosFX::DebrisCloud::Make(
|
|
Specification *spec,
|
|
unsigned flags
|
|
)
|
|
{
|
|
Check_Object(spec);
|
|
|
|
gos_PushCurrentHeap(Heap);
|
|
DebrisCloud *cloud = new gosFX::DebrisCloud(spec, flags);
|
|
gos_PopCurrentHeap();
|
|
|
|
return cloud;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud::Start(struct gosFX::Effect::ExecuteInfo *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(info);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Let effect initialize, then figure out how many particles we want to make
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
BaseClass::Start(info);
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Load the shape if it isn't loaded yet
|
|
//--------------------------------------
|
|
//
|
|
Specification *spec = GetSpecification();
|
|
Check_Object(spec);
|
|
if (spec->m_shapeFile && !spec->m_debrisPieces.GetLength())
|
|
{
|
|
EffectLibrary::Instance->LoadDebrisArray(spec, spec->m_shapeFile);
|
|
Verify(spec->m_debrisPieces.GetLength()>0);
|
|
m_debrisPieces.SetLength(spec->m_debrisPieces.GetLength());
|
|
}
|
|
|
|
Verify(m_debrisPieces.GetLength() == spec->m_debrisPieces.GetLength());
|
|
|
|
int i, numOfParticles = m_debrisPieces.GetLength();
|
|
|
|
for(i=0;i<numOfParticles;i++)
|
|
{
|
|
Particle *particle = &m_debrisPieces[i];
|
|
|
|
particle->m_localToParent = Stuff::LinearMatrix4D::Identity;
|
|
particle->m_localToParent.BuildTranslation(spec->m_debrisPositions[i]);
|
|
|
|
particle->m_age = 0.0f;
|
|
particle->m_seed = spec->m_debrisSeed[i];
|
|
|
|
Stuff::Scalar lifetime =
|
|
spec->m_pLifeSpan.ComputeValue(0.0f, particle->m_seed);
|
|
|
|
Min_Clamp(lifetime, 0.0333333f);
|
|
particle->m_ageRate = 1.0f / lifetime;
|
|
|
|
Stuff::Vector3D v;
|
|
|
|
v.Subtract(spec->m_debrisPositions[i], spec->m_centerOfForce);
|
|
// v.y = 0.0f;
|
|
|
|
Stuff::Scalar lerpFactor =
|
|
Stuff::Lerp(
|
|
spec->m_minimumDeviation.ComputeValue(0.0f, particle->m_seed),
|
|
spec->m_maximumDeviation.ComputeValue(0.0f, particle->m_seed),
|
|
Stuff::Random::GetFraction()
|
|
);
|
|
|
|
particle->m_linearVelocity.Lerp(Stuff::Vector3D::Up, v, lerpFactor);
|
|
particle->m_linearVelocity.Normalize(particle->m_linearVelocity);
|
|
|
|
particle->m_linearVelocity *= spec->m_startingSpeed.ComputeValue(0.0f, particle->m_seed);
|
|
|
|
Stuff::Scalar temp = spec->m_pSpin.ComputeValue(0.0f, particle->m_seed);
|
|
|
|
particle->m_angularVelocity.x = temp*(2*Stuff::Random::GetFraction() - 1.0f);
|
|
particle->m_angularVelocity.y = temp*(2*Stuff::Random::GetFraction() - 1.0f);
|
|
particle->m_angularVelocity.z = temp*(2*Stuff::Random::GetFraction() - 1.0f);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
bool
|
|
gosFX::DebrisCloud::Execute(struct gosFX::Effect::ExecuteInfo *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(info);
|
|
GFX_LOGIC("Execute::DebrisCloud");
|
|
|
|
//
|
|
//----------------------------------------
|
|
// If we aren't supposed to execute, don't
|
|
//----------------------------------------
|
|
//
|
|
if (!IsExecuted())
|
|
return false;
|
|
|
|
//
|
|
//--------------------------------------------------------
|
|
// 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);
|
|
|
|
//
|
|
//-----------------------------------
|
|
// Deal with all the active particles
|
|
//-----------------------------------
|
|
//
|
|
int i;
|
|
Stuff::LinearMatrix4D local_to_world;
|
|
local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
|
|
for (i = 0; i < m_debrisPieces.GetLength(); 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
|
|
//--------------------------------------------------------------------
|
|
//
|
|
GFX_LOGIC("Execute::DebrisCloud::AnimateParticle");
|
|
Particle *particle = GetParticle(i);
|
|
Check_Object(particle);
|
|
if (particle->m_age < 1.0f)
|
|
{
|
|
particle->m_age += dT*particle->m_ageRate;
|
|
|
|
if (AnimateParticle(i, &local_to_world, info->m_time))
|
|
{
|
|
continue;
|
|
}
|
|
DestroyParticle(i);
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------
|
|
// Now let effect do its thing
|
|
//----------------------------
|
|
//
|
|
if(!BaseClass::Execute(info))
|
|
return false;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// If there is no bounds yet, we need to create our extent box around
|
|
// the first legal point we find
|
|
//-------------------------------------------------------------------
|
|
//
|
|
Stuff::ExtentBox box(Stuff::Point3D::Identity, Stuff::Point3D::Identity);
|
|
for(i=0;i<m_debrisPieces.GetLength();i++)
|
|
{
|
|
GFX_LOGIC("Execute::ComputeBounds::DebrisCloud");
|
|
Particle *particle = GetParticle(i);
|
|
Check_Object(particle);
|
|
|
|
//
|
|
//-----------------------------------------------------------
|
|
// We have found our first particle, so put the box around it
|
|
//-----------------------------------------------------------
|
|
//
|
|
if (particle->m_age < 1.0f)
|
|
{
|
|
Stuff::Point3D point;
|
|
Stuff::Scalar radius = spec->m_debrisSpheres[i].radius;
|
|
|
|
point.Multiply(spec->m_debrisSpheres[i].center, particle->m_localToParent);
|
|
|
|
box.maxX = point.x + radius;
|
|
box.minX = point.x - radius;
|
|
|
|
box.maxY = point.y + radius;
|
|
box.minY = point.y - radius;
|
|
|
|
box.maxZ = point.z + radius;
|
|
box.minZ = point.z - radius;
|
|
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
//
|
|
//-----------------------------
|
|
// Look for the other particles
|
|
//-----------------------------
|
|
//
|
|
while (i<m_debrisPieces.GetLength())
|
|
{
|
|
Particle *particle = GetParticle(i);
|
|
Check_Object(particle);
|
|
|
|
if (particle->m_age < 1.0f)
|
|
{
|
|
Stuff::ExtentBox local_box;
|
|
Stuff::Point3D point;
|
|
Stuff::Scalar radius = spec->m_debrisSpheres[i].radius;
|
|
|
|
point.Multiply(spec->m_debrisSpheres[i].center, particle->m_localToParent);
|
|
|
|
local_box.maxX = point.x + radius;
|
|
local_box.minX = point.x - radius;
|
|
|
|
local_box.maxY = point.y + radius;
|
|
local_box.minY = point.y - radius;
|
|
|
|
local_box.maxZ = point.z + radius;
|
|
local_box.minZ = point.z - radius;
|
|
|
|
box.Union(box, local_box);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
//
|
|
//------------------------------------
|
|
// Now, build a info->m_bounds around this box
|
|
//------------------------------------
|
|
//
|
|
Verify(box.maxX >= box.minX);
|
|
Verify(box.maxY >= box.minY);
|
|
Verify(box.maxZ >= box.minZ);
|
|
Stuff::OBB local_bounds = Stuff::OBB::Identity;
|
|
local_bounds.axisExtents.x = 0.5f * (box.maxX - box.minX);
|
|
local_bounds.axisExtents.y = 0.5f * (box.maxY - box.minY);
|
|
local_bounds.axisExtents.z = 0.5f * (box.maxZ - box.minZ);
|
|
local_bounds.localToParent(3,0) = box.minX + local_bounds.axisExtents.x;
|
|
local_bounds.localToParent(3,1) = box.minY + local_bounds.axisExtents.y;
|
|
local_bounds.localToParent(3,2) = box.minZ + local_bounds.axisExtents.z;
|
|
local_bounds.sphereRadius = local_bounds.axisExtents.GetLength() + Stuff::SMALL;
|
|
Stuff::OBB parent_bounds;
|
|
parent_bounds.Multiply(local_bounds, m_localToParent);
|
|
info->m_bounds->Union(*info->m_bounds, parent_bounds);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Tell our caller that we get to keep executing
|
|
//----------------------------------------------
|
|
//
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
bool
|
|
gosFX::DebrisCloud::HasFinished(void)
|
|
{
|
|
Check_Object(this);
|
|
return BaseClass::HasFinished();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud::Kill(void)
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Destroy all the particles and set up an empty particle cloud
|
|
//-------------------------------------------------------------
|
|
//
|
|
for(int i=0; i < m_debrisPieces.GetLength(); i++)
|
|
{
|
|
DestroyParticle(i);
|
|
}
|
|
|
|
//
|
|
//----------------------------------------
|
|
// Now let the base effect handle stopping
|
|
//----------------------------------------
|
|
//
|
|
BaseClass::Kill();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
bool
|
|
gosFX::DebrisCloud::AnimateParticle(
|
|
unsigned index,
|
|
const Stuff::LinearMatrix4D *world_to_new_local,
|
|
Stuff::Time till
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
PARTICLE_LOGIC("Debris");
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Animate the parent then get our pointers
|
|
//-----------------------------------------
|
|
//
|
|
Specification *spec = GetSpecification();
|
|
Check_Object(spec);
|
|
Particle *particle = GetParticle(index);
|
|
Check_Object(particle);
|
|
Stuff::Scalar seed = particle->m_seed;
|
|
Stuff::Scalar age = particle->m_age;
|
|
if (age >= 1.0f)
|
|
return false;
|
|
|
|
//
|
|
//------------------
|
|
// Animate the color
|
|
//------------------
|
|
//
|
|
Set_Statistic(Shape_Count, Shape_Count+1);
|
|
particle->m_alpha = spec->m_pAlpha.ComputeValue(age, seed);
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If this cloud is unparented, we need to transform the point from local
|
|
// space into world space and set the internal position/velocity pointers
|
|
// to these temporary values
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
|
|
Stuff::Point3D translation;
|
|
translation = particle->m_localToParent;
|
|
|
|
Stuff::UnitQuaternion rotation;
|
|
rotation = particle->m_localToParent;
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// First, calculate the drag on the particle. Drag can never assist
|
|
// velocity
|
|
//------------------------------------------------------------------
|
|
//
|
|
Stuff::Scalar drag = -spec->m_pDrag.ComputeValue(age, seed);
|
|
Max_Clamp(drag, 0.0f);
|
|
Stuff::Vector3D ether;
|
|
ether.x = 0.0f;
|
|
ether.y = spec->m_pEtherVelocityY.ComputeValue(age, seed);
|
|
ether.z = 0.0f;
|
|
Stuff::Vector3D accel(Stuff::Vector3D::Identity);
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Deal with pseudo-world simulation. In this mode, we interpret the
|
|
// forces as if they are already in worldspace, and we transform them
|
|
// back to local space
|
|
//-------------------------------------------------------------------
|
|
//
|
|
Stuff::LinearMatrix4D world_to_effect;
|
|
world_to_effect.Invert(m_localToWorld);
|
|
Stuff::Vector3D local_ether;
|
|
local_ether.MultiplyByInverse(ether, world_to_effect);
|
|
Stuff::Vector3D rel_vel;
|
|
rel_vel.Subtract(particle->m_linearVelocity, local_ether);
|
|
accel.Multiply(rel_vel, drag);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Now, add in acceleration of the particle
|
|
//-----------------------------------------
|
|
//
|
|
Stuff::Vector3D world_accel;
|
|
world_accel.x = 0.0f;
|
|
world_accel.y = spec->m_pAccelerationY.ComputeValue(age, seed);
|
|
world_accel.z = 0.0f;
|
|
Stuff::Vector3D local_accel;
|
|
local_accel.Multiply(world_accel, world_to_effect);
|
|
accel += local_accel;
|
|
|
|
//
|
|
//-------------------------------------------------
|
|
// Compute the particle's new velocity and position
|
|
//-------------------------------------------------
|
|
//
|
|
Stuff::Scalar time_slice =
|
|
static_cast<Stuff::Scalar>(till - m_lastRan);
|
|
|
|
particle->m_linearVelocity.AddScaled(particle->m_linearVelocity, accel, time_slice);
|
|
|
|
translation.AddScaled(translation, particle->m_linearVelocity, time_slice);
|
|
|
|
//
|
|
//-----------------------
|
|
// Deal with the rotation
|
|
//-----------------------
|
|
//
|
|
Stuff::Vector3D omega(particle->m_angularVelocity);
|
|
omega *= time_slice;
|
|
Stuff::UnitQuaternion omega_q;
|
|
omega_q = omega;
|
|
|
|
rotation.Multiply(omega_q, Stuff::UnitQuaternion(rotation));
|
|
rotation.Normalize();
|
|
|
|
particle->m_localToParent.BuildRotation(rotation);
|
|
particle->m_localToParent.BuildTranslation(translation);
|
|
|
|
Check_Object(&particle->m_localToParent);
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud::DestroyParticle(unsigned int index)
|
|
{
|
|
Particle *particle = GetParticle(index);
|
|
Check_Object(particle);
|
|
particle->m_age = 1.0f;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void gosFX::DebrisCloud::Draw(DrawInfo *info)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(info);
|
|
Check_Object(info->m_parentToWorld);
|
|
GFX_RENDER("DebrisCloud");
|
|
|
|
//
|
|
//----------------------------
|
|
// Set up the common draw info
|
|
//----------------------------
|
|
//
|
|
Specification *spec = GetSpecification();
|
|
Check_Object(spec);
|
|
|
|
int i, nrOfParticle = m_debrisPieces.GetLength();
|
|
|
|
for(i=0;i<nrOfParticle;i++)
|
|
{
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// If the particle is still alive, concatenate into world space and
|
|
// issue the draw command
|
|
//-----------------------------------------------------------------
|
|
//
|
|
Particle *particle = GetParticle(i);
|
|
Check_Object(particle);
|
|
|
|
if (particle->m_age < 1.0f)
|
|
{
|
|
MidLevelRenderer::DrawScalableShapeInformation dinfo;
|
|
MidLevelRenderer::MLRShape *shape = spec->m_debrisPieces[i];
|
|
if (!shape)
|
|
continue;
|
|
|
|
dinfo.clippingFlags.SetClippingState(0x3f);
|
|
dinfo.worldToShape = NULL;
|
|
dinfo.state.Combine(info->m_state, spec->m_state);
|
|
dinfo.activeLights = NULL;
|
|
dinfo.nrOfActiveLights = 0;
|
|
dinfo.shape = shape;
|
|
Stuff::LinearMatrix4D local_to_world;
|
|
local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// No alignment is necessary, so just multiply out all the active
|
|
// particles
|
|
//---------------------------------------------------------------
|
|
//
|
|
|
|
Stuff::LinearMatrix4D shape_to_world;
|
|
shape_to_world.Multiply(
|
|
particle->m_localToParent,
|
|
local_to_world
|
|
);
|
|
dinfo.shapeToWorld = &shape_to_world;
|
|
dinfo.scaling = NULL;
|
|
Stuff::RGBAColor color(1.0f, 1.0f, 1.0f, particle->m_alpha);
|
|
dinfo.paintMeColor = &color;
|
|
info->m_clipper->DrawScalableShape(&dinfo);
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------
|
|
// Let our parent do its thing
|
|
//----------------------------
|
|
//
|
|
BaseClass::Draw(info);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
void
|
|
gosFX::DebrisCloud::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|