Files
firestorm/Gameleap/code/mw4/Libraries/gosFX/CardCloud.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

803 lines
20 KiB
C++

#include "gosFXHeaders.hpp"
#include <MLR\MLRCardCloud.hpp>
#include <MLR\MLRClipper.hpp>
//------------------------------------------------------------------------------
//
gosFX::CardCloud__Specification::CardCloud__Specification(
Stuff::MemoryStream *stream,
int gfx_version
):
SpinningCloud__Specification(gosFX::CardCloudClassID, stream, gfx_version)
{
Check_Pointer(this);
Check_Object(stream);
Verify(m_class == CardCloudClassID);
m_halfHeight.Load(stream, gfx_version);
m_aspectRatio.Load(stream, gfx_version);
//
//-------------------------------------------------------------------
// If we are reading an old version of the card cloud, ignore all the
// animation on the UV channels
//-------------------------------------------------------------------
//
if (gfx_version < 10)
{
m_pIndex.m_ageCurve.SetCurve(0.0f);
m_pIndex.m_seedCurve.SetCurve(1.0f);
m_pIndex.m_seeded = false;
SeededCurveOf<ComplexCurve, LinearCurve,Curve::e_ComplexLinearType> temp;
temp.Load(stream, gfx_version);
Stuff::Scalar v = temp.ComputeValue(0.0f, 0.0f);
m_UOffset.SetCurve(v);
temp.Load(stream, gfx_version);
v = temp.ComputeValue(0.0f, 0.0f);
m_VOffset.SetCurve(v);
m_USize.Load(stream, gfx_version);
m_VSize.Load(stream, gfx_version);
m_animated = false;
}
//
//------------------------------
// Otherwise, read in the curves
//------------------------------
//
else
{
m_pIndex.Load(stream, gfx_version);
m_UOffset.Load(stream, gfx_version);
m_VOffset.Load(stream, gfx_version);
m_USize.Load(stream, gfx_version);
m_VSize.Load(stream, gfx_version);
*stream >> m_animated;
}
SetWidth();
m_totalParticleSize = gosFX::CardCloud::ParticleSize;
m_particleClassSize = sizeof(gosFX::CardCloud::Particle);
}
//------------------------------------------------------------------------------
//
gosFX::CardCloud__Specification::~CardCloud__Specification()
{
Check_Object(this);
}
//------------------------------------------------------------------------------
//
gosFX::CardCloud__Specification::CardCloud__Specification():
SpinningCloud__Specification(gosFX::CardCloudClassID)
{
Check_Pointer(this);
m_animated = false;
m_width = 1;
m_totalParticleSize = gosFX::CardCloud::ParticleSize;
m_particleClassSize = sizeof(gosFX::CardCloud::Particle);
}
//------------------------------------------------------------------------------
//
gosFX::CardCloud__Specification*
gosFX::CardCloud__Specification::Make(
Stuff::MemoryStream *stream,
int gfx_version
)
{
Check_Object(stream);
gos_PushCurrentHeap(Heap);
CardCloud__Specification *spec =
new gosFX::CardCloud__Specification(stream, gfx_version);
gos_PopCurrentHeap();
return spec;
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud__Specification::Save(Stuff::MemoryStream *stream)
{
Check_Object(this);
Check_Object(stream);
BaseClass::Save(stream);
m_halfHeight.Save(stream);
m_aspectRatio.Save(stream);
m_pIndex.Save(stream);
m_UOffset.Save(stream);
m_VOffset.Save(stream);
m_USize.Save(stream);
m_VSize.Save(stream);
*stream << m_animated;
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud__Specification::BuildDefaults()
{
Check_Object(this);
BaseClass::BuildDefaults();
m_halfHeight.m_ageCurve.SetCurve(1.0f);
m_halfHeight.m_seeded = false;
m_halfHeight.m_seedCurve.SetCurve(1.0f);
m_aspectRatio.m_ageCurve.SetCurve(1.0f);
m_aspectRatio.m_seeded = false;
m_aspectRatio.m_seedCurve.SetCurve(1.0f);
m_pIndex.m_ageCurve.SetCurve(0.0f);
m_pIndex.m_seeded = false;
m_pIndex.m_seedCurve.SetCurve(1.0f);
m_UOffset.SetCurve(0.0f);
m_VOffset.SetCurve(0.0f);
m_USize.SetCurve(1.0f);
m_VSize.SetCurve(1.0f);
m_animated = false;
m_width = 1;
}
//------------------------------------------------------------------------------
//
bool
gosFX::CardCloud__Specification::IsDataValid(bool fix_data)
{
Check_Object(this);
//
//-----------------------------------------
// Make sure we don't overwrite MLR buffers
//-----------------------------------------
//
int particle_limit = MidLevelRenderer::Limits::Max_Number_Vertices_Per_Effect/4;
if (m_maxParticleCount > particle_limit)
{
if (fix_data)
{
m_maxParticleCount = particle_limit;
PAUSE(("Warning: Max Particle Count in Effect \"%s\" is too big and has been reset",(char *)m_name));
}
else
return false;
}
//
//------------------------------------
// Calculate the worst case UV offsets
//------------------------------------
//
Stuff::Scalar max_offset, min_offset;
Stuff::Scalar max_scale, min_scale;
m_USize.ExpensiveComputeRange(&min_scale, &max_scale);
Stuff::Scalar lower = min_scale;
if (lower > 0.0f)
lower = 0.0f;
Stuff::Scalar upper = max_scale;
m_VOffset.ExpensiveComputeRange(&min_offset, &max_offset);
lower += min_offset;
upper += max_offset;
if (upper > 99.0f || lower < -99.0f)
{
if(fix_data)
{
m_VOffset.SetCurve(0.0f);
PAUSE(("Warning: Curve \"VOffset\" in Effect \"%s\" Is Out of Range and has been Reset",(char *)m_name));
}
else
return false;
}
m_VSize.ExpensiveComputeRange(&min_scale, &max_scale);
lower = min_scale;
if (lower > 0.0f)
lower = 0.0f;
upper = max_scale;
//
//------------------------------------
// Calculate the worst case UV offsets
//------------------------------------
//
max_offset, min_offset;
m_UOffset.ExpensiveComputeRange(&min_offset, &max_offset);
lower += min_offset;
upper += max_offset;
if (upper > 99.0f || lower < -99.0f)
{
if(fix_data)
{
m_UOffset.SetCurve(0.0f);
PAUSE(("Warning: Curve \"UOffset\" in Effect \"%s\" Is Out of Range and has been Reset",(char *)m_name));
}
else
return false;
}
return BaseClass::IsDataValid(fix_data);
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud__Specification::Copy(CardCloud__Specification *spec)
{
Check_Object(this);
Check_Object(spec);
BaseClass::Copy(spec);
gos_PushCurrentHeap(Heap);
m_halfHeight = spec->m_halfHeight;
m_aspectRatio = spec->m_aspectRatio;
m_pIndex = spec->m_pIndex;
m_UOffset = spec->m_UOffset;
m_VOffset = spec->m_VOffset;
m_USize = spec->m_USize;
m_VSize = spec->m_VSize;
m_animated = spec->m_animated;
m_width = spec->m_width;
gos_PopCurrentHeap();
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud__Specification::SetWidth()
{
m_width =
static_cast<BYTE>(1.0f / m_USize.ComputeValue(0.0f, 0.0f));
}
//############################################################################
//############################## gosFX::CardCloud ################################
//############################################################################
gosFX::CardCloud::ClassData*
gosFX::CardCloud::DefaultData = NULL;
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud::InitializeClass()
{
Verify(!DefaultData);
DefaultData =
new ClassData(
CardCloudClassID,
"gosFX::CardCloud",
BaseClass::DefaultData,
(Effect::Factory)&Make,
(Specification::Factory)&Specification::Make
);
Check_Object(DefaultData);
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud::TerminateClass()
{
Check_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//------------------------------------------------------------------------------
//
gosFX::CardCloud::CardCloud(
Specification *spec,
unsigned flags
):
SpinningCloud(DefaultData, spec, flags)
{
Check_Object(spec);
gos_PushCurrentHeap(MidLevelRenderer::EffectHeap);
m_cloudImplementation =
new MidLevelRenderer::MLRCardCloud(spec->m_maxParticleCount);
Check_Object(m_cloudImplementation);
gos_PopCurrentHeap();
unsigned index = spec->m_maxParticleCount*sizeof(Particle);
m_P_vertices = Cast_Pointer(Stuff::Point3D*, &m_data[index]);
index += 4*spec->m_maxParticleCount*sizeof(Stuff::Point3D);
m_P_color = Cast_Pointer(Stuff::RGBAColor*, &m_data[index]);
index += spec->m_maxParticleCount * sizeof(Stuff::RGBAColor);
m_P_uvs = Cast_Pointer(Stuff::Vector2DOf<Stuff::Scalar>*, &m_data[index]);
m_cloudImplementation->SetData(
Cast_Pointer(const int *, &m_activeParticleCount),
m_P_vertices,
m_P_color,
m_P_uvs
);
}
//------------------------------------------------------------------------------
//
gosFX::CardCloud::~CardCloud()
{
Check_Object(this);
Check_Object(m_cloudImplementation);
delete m_cloudImplementation;
}
//------------------------------------------------------------------------------
//
gosFX::CardCloud*
gosFX::CardCloud::Make(
Specification *spec,
unsigned flags
)
{
Check_Object(spec);
gos_PushCurrentHeap(Heap);
CardCloud *cloud = new gosFX::CardCloud(spec, flags);
gos_PopCurrentHeap();
return cloud;
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud::CreateNewParticle(
unsigned index,
Stuff::Point3D *translation
)
{
Check_Object(this);
//
//-------------------------------------------------------------------
// Let our parent do creation, then turn on the particle in the cloud
//-------------------------------------------------------------------
//
BaseClass::CreateNewParticle(index, translation);
m_cloudImplementation->TurnOn(index);
Verify(m_cloudImplementation->IsOn(index));
//
//-----------------------------
// Figure out the particle size
//-----------------------------
//
Specification *spec = GetSpecification();
Check_Object(spec);
Particle *particle = GetParticle(index);
Check_Object(particle);
particle->m_halfY =
spec->m_halfHeight.ComputeValue(m_age, particle->m_seed);
particle->m_halfX =
particle->m_halfY * spec->m_aspectRatio.ComputeValue(m_age, particle->m_seed);
particle->m_radius =
Stuff::Sqrt(
particle->m_halfX * particle->m_halfX
+ particle->m_halfY * particle->m_halfY
);
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud::SetVertexData(
unsigned index,
const Stuff::LinearMatrix4D &card_to_cloud
)
{
Check_Object(this);
//
//-----------------------------------------
// 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;
//
//-------------------------------------------------
// Figure out the scale, then build the four points
//-------------------------------------------------
//
Stuff::Scalar scale = particle->m_scale;
unsigned vert = index*4;
m_P_vertices[vert++].Multiply(
Stuff::Point3D(
scale*particle->m_halfX,
-scale*particle->m_halfY,
0.0f
),
card_to_cloud
);
m_P_vertices[vert++].Multiply(
Stuff::Point3D(
-scale*particle->m_halfX,
-scale*particle->m_halfY,
0.0f
),
card_to_cloud
);
m_P_vertices[vert++].Multiply(
Stuff::Point3D(
-scale*particle->m_halfX,
scale*particle->m_halfY,
0.0f
),
card_to_cloud
);
m_P_vertices[vert++].Multiply(
Stuff::Point3D(
scale*particle->m_halfX,
scale*particle->m_halfY,
0.0f
),
card_to_cloud
);
//
//------------------
// Animate the color
//------------------
//
Check_Pointer(m_P_color);
m_P_color[index].red = spec->m_pRed.ComputeValue(age, seed);
m_P_color[index].green = spec->m_pGreen.ComputeValue(age, seed);
m_P_color[index].blue = spec->m_pBlue.ComputeValue(age, seed);
m_P_color[index].alpha = spec->m_pAlpha.ComputeValue(age, seed);
//
//----------------
// Animate the uvs
//----------------
//
Stuff::Scalar u = spec->m_UOffset.ComputeValue(age, seed);
Stuff::Scalar v = spec->m_VOffset.ComputeValue(age, seed);
Stuff::Scalar u2 = spec->m_USize.ComputeValue(age, seed);
Stuff::Scalar v2 = spec->m_VSize.ComputeValue(age, seed);
//
//--------------------------------------------------------------
// If we are animated, figure out the row/column to be displayed
//--------------------------------------------------------------
//
if (spec->m_animated)
{
BYTE columns =
Stuff::Truncate_Float_To_Byte(
spec->m_pIndex.ComputeValue(age, seed)
);
BYTE rows = static_cast<BYTE>(columns / spec->m_width);
columns = static_cast<BYTE>(columns - rows*spec->m_width);
//
//---------------------------
// Now compute the end points
//---------------------------
//
u += u2*columns;
v += v2*rows;
}
u2 += u;
v2 += v;
index *= 4;
m_P_uvs[index].x = u;
m_P_uvs[index].y = v2;
m_P_uvs[++index].x = u2;
m_P_uvs[index].y = v2;
m_P_uvs[++index].x = u2;
m_P_uvs[index].y = v;
m_P_uvs[++index].x = u;
m_P_uvs[index].y = v;
}
//------------------------------------------------------------------------------
//
void gosFX::CardCloud::DestroyParticle(unsigned index)
{
Check_Object(this);
m_cloudImplementation->TurnOff(index);
Verify(!m_cloudImplementation->IsOn(index));
BaseClass::DestroyParticle(index);
}
//------------------------------------------------------------------------------
//
void gosFX::CardCloud::Draw(DrawInfo *info)
{
Check_Object(this);
Check_Object(info);
GFX_RENDER("CardCloud");
//
//---------------------------------------------------------
// If we have active particles, set up the draw information
//---------------------------------------------------------
//
if (m_activeParticleCount)
{
MidLevelRenderer::DrawEffectInformation dInfo;
dInfo.effect = m_cloudImplementation;
Specification *spec = GetSpecification();
Check_Object(spec);
dInfo.state.Combine(info->m_state, spec->m_state);
dInfo.clippingFlags = info->m_clippingFlags;
Stuff::LinearMatrix4D local_to_world;
local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
dInfo.effectToWorld = &local_to_world;
//
//--------------------------------------------------------------
// Check the orientation mode. The first case is XY orientation
//--------------------------------------------------------------
//
unsigned i;
if (spec->m_alignZUsingX)
{
if (spec->m_alignZUsingY)
{
//
//-----------------------------------------
// Get the camera location into local space
//-----------------------------------------
//
Stuff::Point3D
camera_in_world(info->m_clipper->GetCameraToWorldMatrix());
Stuff::Point3D camera_in_cloud;
camera_in_cloud.MultiplyByInverse(
camera_in_world,
local_to_world
);
//
//--------------------------------------
// Spin through all the active particles
//--------------------------------------
//
for (i = 0; i < m_activeParticleCount; i++)
{
Particle *particle = GetParticle(i);
Check_Object(particle);
if (particle->m_age < 1.0f)
{
//
//--------------------------------
// Build the local to cloud matrix
//--------------------------------
//
Stuff::Vector3D direction_in_cloud;
direction_in_cloud.Subtract(
camera_in_cloud,
particle->m_localTranslation
);
Stuff::LinearMatrix4D card_to_cloud;
card_to_cloud.BuildRotation(particle->m_localRotation);
card_to_cloud.AlignLocalAxisToWorldVector(
direction_in_cloud,
Stuff::Z_Axis,
Stuff::Y_Axis,
Stuff::X_Axis
);
card_to_cloud.BuildTranslation(
particle->m_localTranslation
);
//
//-----------------
// Fill in the data
//-----------------
//
SetVertexData(i, card_to_cloud);
}
}
}
//
//-----------------------
// Handle X-only rotation
//-----------------------
//
else
{
//
//-----------------------------------------
// Get the camera location into local space
//-----------------------------------------
//
Stuff::Point3D
camera_in_world(info->m_clipper->GetCameraToWorldMatrix());
Stuff::Point3D camera_in_cloud;
camera_in_cloud.MultiplyByInverse(
camera_in_world,
local_to_world
);
//
//--------------------------------------
// Spin through all the active particles
//--------------------------------------
//
for (i = 0; i < m_activeParticleCount; i++)
{
Particle *particle = GetParticle(i);
Check_Object(particle);
if (particle->m_age < 1.0f)
{
//
//--------------------------------
// Build the local to cloud matrix
//--------------------------------
//
Stuff::Vector3D direction_in_cloud;
direction_in_cloud.Subtract(
camera_in_cloud,
particle->m_localTranslation
);
Stuff::LinearMatrix4D card_to_cloud;
card_to_cloud.BuildRotation(particle->m_localRotation);
card_to_cloud.AlignLocalAxisToWorldVector(
direction_in_cloud,
Stuff::Z_Axis,
Stuff::X_Axis,
-1
);
card_to_cloud.BuildTranslation(particle->m_localTranslation);
//
//-----------------
// Fill in the data
//-----------------
//
SetVertexData(i, card_to_cloud);
}
}
}
}
//
//-------------------------------------------------------
// Each matrix needs to be aligned to the camera around Y
//-------------------------------------------------------
//
else if (spec->m_alignZUsingY)
{
//
//-----------------------------------------
// Get the camera location into local space
//-----------------------------------------
//
Stuff::Point3D
camera_in_world(info->m_clipper->GetCameraToWorldMatrix());
Stuff::Point3D camera_in_cloud;
camera_in_cloud.MultiplyByInverse(
camera_in_world,
local_to_world
);
//
//--------------------------------------
// Spin through all the active particles
//--------------------------------------
//
for (i = 0; i < m_activeParticleCount; i++)
{
Particle *particle = GetParticle(i);
Check_Object(particle);
if (particle->m_age < 1.0f)
{
//
//--------------------------------
// Build the local to cloud matrix
//--------------------------------
//
Stuff::Vector3D direction_in_cloud;
direction_in_cloud.Subtract(
camera_in_cloud,
particle->m_localTranslation
);
Stuff::LinearMatrix4D card_to_cloud;
card_to_cloud.BuildRotation(particle->m_localRotation);
card_to_cloud.AlignLocalAxisToWorldVector(
direction_in_cloud,
Stuff::Z_Axis,
Stuff::Y_Axis,
-1
);
card_to_cloud.BuildTranslation(particle->m_localTranslation);
//
//-----------------
// Fill in the data
//-----------------
//
SetVertexData(i, card_to_cloud);
}
}
}
//
//---------------------------------------------------------------
// No alignment is necessary, so just multiply out all the active
// particles
//---------------------------------------------------------------
//
else
{
for (i = 0; i < m_activeParticleCount; i++)
{
Particle *particle = GetParticle(i);
Check_Object(particle);
if (particle->m_age < 1.0f)
{
//
//--------------------------------
// Build the local to cloud matrix
//--------------------------------
//
Stuff::LinearMatrix4D card_to_cloud;
card_to_cloud.BuildRotation(particle->m_localRotation);
card_to_cloud.BuildTranslation(particle->m_localTranslation);
//
//-----------------
// Fill in the data
//-----------------
//
SetVertexData(i, card_to_cloud);
}
}
}
//
//---------------------
// Now just do the draw
//---------------------
//
info->m_clipper->DrawEffect(&dInfo);
}
BaseClass::Draw(info);
}
//------------------------------------------------------------------------------
//
void
gosFX::CardCloud::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}