Files
firestorm/Gameleap/code/mw4/Libraries/gosFX/Effect.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

1249 lines
33 KiB
C++

#include "gosFXHeaders.hpp"
//==========================================================================//
// File: gosFX_Effect.cpp //
// Project: gosFX //
// Contents: Base gosFX::Effect 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 //
//==========================================================================//
//
//############################################################################
//######################## EffectSpecification #############################
//############################################################################
//------------------------------------------------------------------------------
//
gosFX::Event::Event(const Event& event):
Plug(DefaultData)
{
Check_Pointer(this);
m_time = event.m_time;
m_flags = event.m_flags;
m_effectID = event.m_effectID;
m_nearLimit = event.m_nearLimit;
m_farLimit = event.m_farLimit;
}
//------------------------------------------------------------------------------
//
gosFX::Event::Event(
Stuff::MemoryStream *stream,
int gfx_version
):
Plug(DefaultData)
{
Check_Pointer(this);
Check_Object(stream);
*stream >> m_time >> m_flags;
if (gfx_version >= 21)
{
*stream >> m_localToParent;
Stuff::MString name;
*stream >> name;
Check_Object(EffectLibrary::Instance);
int id = EffectLibrary::Instance->Find(name);
Verify(id >= 0);
m_effectID = id;
}
else
*stream >> m_effectID >> m_localToParent;
if (gfx_version >= 19)
*stream >> m_nearLimit >> m_farLimit;
else
{
m_nearLimit = 0.0f;
m_farLimit = 6.4e6f;
}
}
//------------------------------------------------------------------------------
//
gosFX::Event*
gosFX::Event::Make(
Stuff::MemoryStream *stream,
int gfx_version
)
{
Check_Object(stream);
gos_PushCurrentHeap(Heap);
Event *event = new Event(stream, gfx_version);
gos_PopCurrentHeap();
return event;
}
//------------------------------------------------------------------------------
//
void
gosFX::Event::Save(Stuff::MemoryStream *stream)
{
Check_Object(this);
*stream << m_time << m_flags << m_localToParent;
Check_Object(EffectLibrary::Instance);
Effect::Specification *effect = EffectLibrary::Instance->Find(m_effectID);
Check_Object(effect);
*stream << effect->m_name << m_nearLimit << m_farLimit;
}
//############################################################################
//######################## EffectSpecification #############################
//############################################################################
#if defined(LAB_ONLY)
bool gosFX::Effect__Specification::s_DeleteIsOK = false;
#endif
//------------------------------------------------------------------------------
//
gosFX::Effect__Specification::Effect__Specification(
Stuff::RegisteredClass::ClassID class_id,
Stuff::MemoryStream *stream,
int gfx_version
):
m_events(NULL)
{
Check_Pointer(this);
Check_Object(stream);
if (gfx_version < 9)
{
STOP(("This version of gosFX is no longer supported"));
return;
}
//
//--------------
// Read the name
//--------------
//
m_class = class_id;
*stream >> m_name;
//
//--------------------------------------------------------------------
// Read the events. If we are using an array, no events will be saved
//--------------------------------------------------------------------
//
unsigned event_count;
*stream >> event_count;
while (event_count-- > 0)
{
Event *event = Event::Make(stream, gfx_version);
Check_Object(event);
m_events.Add(event);
}
//
//--------------------------------------------------------
// Load the curves, variances, and MLRState if appropriate
//--------------------------------------------------------
//
m_lifeSpan.Load(stream, gfx_version);
m_minimumChildSeed.Load(stream, gfx_version);
m_maximumChildSeed.Load(stream, gfx_version);
m_state.Load(stream, MidLevelRenderer::ReadMLRVersion(stream));
if (gfx_version < 14)
{
m_state.SetRenderPermissionMask(
m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::TextureMask
);
}
if (
m_state.GetAlphaMode() != MidLevelRenderer::MLRState::OneZeroMode
&& m_state.GetPriority() < MidLevelRenderer::MLRState::AlphaPriority
)
m_state.SetPriority(MidLevelRenderer::MLRState::AlphaPriority);
}
//------------------------------------------------------------------------------
//
gosFX::Effect__Specification::Effect__Specification(
Stuff::RegisteredClass::ClassID class_id
):
m_events(NULL)
{
Check_Pointer(this);
m_class = class_id;
}
//------------------------------------------------------------------------------
//
gosFX::Effect__Specification::~Effect__Specification()
{
Check_Object(this);
#if defined(LAB_ONLY)
if (!s_DeleteIsOK)
STOP(("An Effect specification is being illegally deleted"));
#endif
Verify(m_class >= Stuff::FirstgosFXClassID && m_class < FirstFreegosFXClassID);
m_events.DeletePlugs();
}
//------------------------------------------------------------------------------
//
gosFX::Effect__Specification*
gosFX::Effect__Specification::Make(
Stuff::MemoryStream *stream,
int gfx_version
)
{
Check_Object(stream);
gos_PushCurrentHeap(Heap);
Effect__Specification *spec =
new gosFX::Effect__Specification(EffectClassID, stream, gfx_version);
gos_PopCurrentHeap();
return spec;
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect__Specification::BuildDefaults()
{
Check_Object(this);
m_lifeSpan.SetCurve(1.0f);
m_minimumChildSeed.SetCurve(0.0f);
m_maximumChildSeed.SetCurve(1.0f);
}
//------------------------------------------------------------------------------
//
bool
gosFX::Effect__Specification::IsDataValid(bool fix_data)
{
Check_Object(this);
Stuff::Scalar minv,maxv;
m_lifeSpan.ExpensiveComputeRange(&minv,&maxv);
if(minv<0.0f)
{
if(fix_data)
{
m_lifeSpan.SetCurve(1.0f);
PAUSE(("Warning: Curve \"lifespan\" in Effect \"%s\" Is Out of Range and has been Reset",(char *)m_name));
}
else
return false;
}
return true;
}
//------------------------------------------------------------------------------
//
gosFX::Effect__Specification*
gosFX::Effect__Specification::Create(
Stuff::MemoryStream *stream,
int gfx_version
)
{
Check_Object(stream);
Stuff::RegisteredClass::ClassID class_id;
*stream >> class_id;
gosFX::Effect::ClassData* class_data =
Cast_Pointer(
gosFX::Effect::ClassData*,
Stuff::RegisteredClass::FindClassData(class_id)
);
Check_Object(class_data);
Check_Pointer(class_data->specificationFactory);
gosFX::Effect__Specification *spec =
(*class_data->specificationFactory)(stream, gfx_version);
Check_Object(spec);
return spec;
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect__Specification::Save(Stuff::MemoryStream *stream)
{
Check_Object(this);
*stream << m_class << m_name;
Stuff::ChainIteratorOf<Event*> events(&m_events);
unsigned count = events.GetSize();
*stream << count;
Event *event;
while ((event = events.ReadAndNext()) != NULL)
{
Check_Object(event);
event->Save(stream);
}
m_lifeSpan.Save(stream);
m_minimumChildSeed.Save(stream);
m_maximumChildSeed.Save(stream);
MidLevelRenderer::WriteMLRVersion(stream);
m_state.Save(stream);
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect__Specification::Copy(Effect__Specification *spec)
{
Check_Object(this);
Check_Object(spec);
gos_PushCurrentHeap(Heap);
Verify(spec->m_class == m_class);
m_name = spec->m_name;
//
//----------------------------------------------
// Copy the events after delete our current ones
//----------------------------------------------
//
m_events.DeletePlugs();
Stuff::ChainIteratorOf<Event*> new_events(&spec->m_events);
Event* event;
while ((event = new_events.ReadAndNext()) != NULL)
{
Check_Object(event);
Event *new_event = new Event(*event);
Check_Object(new_event);
AdoptEvent(new_event);
}
//
//---------------------------------------------------
// Now copy the curves, variance modes, and MLR state
//---------------------------------------------------
//
m_lifeSpan = spec->m_lifeSpan;
m_minimumChildSeed = spec->m_minimumChildSeed;
m_maximumChildSeed = spec->m_maximumChildSeed;
m_state = spec->m_state;
gos_PopCurrentHeap();
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect__Specification::AdoptEvent(Event *event)
{
Check_Object(this);
Check_Object(event);
Verify(event->m_time >= 0.0f && event->m_time <= 1.0f);
//
//-----------------------------------------------------------
// The event must be inserted into the chain in order of time
//-----------------------------------------------------------
//
Stuff::ChainIteratorOf<Event*> events(&m_events);
Event *insert = NULL;
while ((insert = events.GetCurrent()) != NULL)
{
Check_Object(insert);
if (insert->m_time > event->m_time)
{
events.Insert(event);
return;
}
events.Next();
}
m_events.Add(event);
}
//------------------------------------------------------------------------------
//
void gosFX::Effect__Specification::TestInstance() const
{
Verify(m_class >= Stuff::FirstgosFXClassID && m_class < FirstFreegosFXClassID);
}
//############################################################################
//############################## gosFX::Effect ###################################
//############################################################################
gosFX::Effect::ClassData*
gosFX::Effect::DefaultData = NULL;
Stuff::Scalar
gosFX::Effect::LODOffset = 0.0f;
Stuff::Point3D
gosFX::Effect::LastCameraPosition;
static DWORD
Effect_Count;
static bool
__stdcall Check100m()
{
return gosFX::Effect::LODOffset == 10000.0f;
}
static bool
__stdcall Check250m()
{
return gosFX::Effect::LODOffset == 62500.0f;
}
static bool
__stdcall Check500m()
{
return gosFX::Effect::LODOffset == 250000.0f;
}
static void
__stdcall Enable100m()
{
gosFX::Effect::LODOffset = (gosFX::Effect::LODOffset == 10000.0f) ? 0.0f : 10000.0f;
}
static void
__stdcall Enable250m()
{
gosFX::Effect::LODOffset = (gosFX::Effect::LODOffset == 62500.0f) ? 0.0f : 62500.0f;
}
static void
__stdcall Enable500m()
{
gosFX::Effect::LODOffset = (gosFX::Effect::LODOffset == 250000.0f) ? 0.0f : 250000.0f;
}
static bool
Disabled_Events[gosFX::FirstFreegosFXClassID - gosFX::EffectClassID]=
{
false,false,false,false,false,false,
false,false,false,false,false,false,
false,false,false,false,false,false
};
static bool
__stdcall CheckAllEvents()
{
for (int i=0; i<ELEMENTS(Disabled_Events); ++i)
{
if (!Disabled_Events[i])
return false;
}
return true;
}
static void
__stdcall EnableAllEvents()
{
bool checked = !CheckAllEvents();
for (int i=0; i<ELEMENTS(Disabled_Events); ++i)
Disabled_Events[i] = checked;
}
static bool
__stdcall CheckEffectEvents()
{
return Disabled_Events[0];
}
static void
__stdcall EnableEffectEvents()
{
Disabled_Events[0] = !Disabled_Events[0];
}
static bool
__stdcall CheckPointCloudEvents()
{
return Disabled_Events[gosFX::PointCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnablePointCloudEvents()
{
Disabled_Events[gosFX::PointCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::PointCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckShardCloudEvents()
{
return Disabled_Events[gosFX::ShardCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableShardCloudEvents()
{
Disabled_Events[gosFX::ShardCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::ShardCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckPertCloudEvents()
{
return Disabled_Events[gosFX::PertCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnablePertCloudEvents()
{
Disabled_Events[gosFX::PertCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::PertCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckCardCloudEvents()
{
return Disabled_Events[gosFX::CardCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableCardCloudEvents()
{
Disabled_Events[gosFX::CardCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::CardCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckShapeCloudEvents()
{
return Disabled_Events[gosFX::ShapeCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableShapeCloudEvents()
{
Disabled_Events[gosFX::ShapeCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::ShapeCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckEffectCloudEvents()
{
return Disabled_Events[gosFX::EffectCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableEffectCloudEvents()
{
Disabled_Events[gosFX::EffectCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::EffectCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckCardEvents()
{
return Disabled_Events[gosFX::CardClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableCardEvents()
{
Disabled_Events[gosFX::CardClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::CardClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckShapeEvents()
{
return Disabled_Events[gosFX::ShapeClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableShapeEvents()
{
Disabled_Events[gosFX::ShapeClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::ShapeClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckTubeEvents()
{
return Disabled_Events[gosFX::TubeClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableTubeEvents()
{
Disabled_Events[gosFX::TubeClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::TubeClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckDebrisCloudEvents()
{
return Disabled_Events[gosFX::DebrisCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableDebrisCloudEvents()
{
Disabled_Events[gosFX::DebrisCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::DebrisCloudClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckPointLightEvents()
{
return Disabled_Events[gosFX::PointLightClassID-gosFX::EffectClassID];
}
static void
__stdcall EnablePointLightEvents()
{
Disabled_Events[gosFX::PointLightClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::PointLightClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckFlareEvents()
{
return Disabled_Events[gosFX::FlareClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableFlareEvents()
{
Disabled_Events[gosFX::FlareClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::FlareClassID-gosFX::EffectClassID];
}
static bool
__stdcall CheckSpriteCloudEvents()
{
return Disabled_Events[gosFX::SpriteCloudClassID-gosFX::EffectClassID];
}
static void
__stdcall EnableSpriteCloudEvents()
{
Disabled_Events[gosFX::SpriteCloudClassID-gosFX::EffectClassID] =
!Disabled_Events[gosFX::SpriteCloudClassID-gosFX::EffectClassID];
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect::InitializeClass(Stuff::NotationFile *startup_ini)
{
Verify(!DefaultData);
DefaultData =
new ClassData(
EffectClassID,
"gosFX::Effect",
BaseClass::DefaultData,
&Make,
&Specification::Make
);
Check_Object(DefaultData);
LODOffset = 0.0f;
Effect_Count = 0;
#if !defined(NO_STATS)
AddStatistic("Effects Executed", "effects", gos_DWORD, &Effect_Count, Stat_AutoReset);
#endif
AddDebuggerMenuItem("Libraries\\Graphics Options\\+100m Effect LODs", Check100m, Enable100m, 0 );
AddDebuggerMenuItem("Libraries\\Graphics Options\\+250m Effect LODs", Check250m, Enable250m, 0 );
AddDebuggerMenuItem("Libraries\\Graphics Options\\+500m Effect LODs", Check500m, Enable500m, 0 );
//
//-------------------------------------------
// Read the effect LOD from the notation file
//-------------------------------------------
//
if (startup_ini)
{
Check_Object(startup_ini);
Stuff::Page *page = startup_ini->FindPage("Graphics Options");
if (page)
{
Check_Object(page);
page->GetEntry("EffectLOD", &LODOffset);
}
}
AddDebuggerMenuItem("Libraries\\gosFX\\Disable All Events", CheckAllEvents, EnableAllEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable Null Events", CheckEffectEvents, EnableEffectEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable PointCloud Events", CheckPointCloudEvents, EnablePointCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable ShardCloud Events", CheckShardCloudEvents, EnableShardCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable PertCloud Events", CheckPertCloudEvents, EnablePertCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable CardCloud Events", CheckCardCloudEvents, EnableCardCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable ShapeCloud Events", CheckShapeCloudEvents, EnableShapeCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable EffectCloud Events", CheckEffectCloudEvents, EnableEffectCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable Card Events", CheckCardEvents, EnableCardEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable Shape Events", CheckShapeEvents, EnableShapeEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable Tube Events", CheckTubeEvents, EnableTubeEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable DebrisCloud Events", CheckDebrisCloudEvents, EnableDebrisCloudEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable PointLight Events", CheckPointLightEvents, EnablePointLightEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable Flare Events", CheckFlareEvents, EnableFlareEvents, 0 );
AddDebuggerMenuItem("Libraries\\gosFX\\Disable SpriteCloud Events", CheckSpriteCloudEvents, EnableSpriteCloudEvents, 0 );
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect::TerminateClass(Stuff::NotationFile *startup_ini)
{
if (startup_ini)
{
Check_Object(startup_ini);
Stuff::Page *page = startup_ini->SetPage("Graphics Options");
Check_Object(page);
page->SetEntry("EffectLOD", LODOffset);
}
Check_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
gosFX::Effect::Effect(
ClassData *class_data,
Specification *spec,
unsigned flags
):
Plug(class_data),
m_children(NULL),
m_event(&spec->m_events)
{
Check_Pointer(this);
Check_Object(spec);
m_specification = spec;
m_age = 0.0f;
m_flags = flags;
m_lastRan = -1.0f;
m_localToParent = Stuff::LinearMatrix4D::Identity;
}
//------------------------------------------------------------------------------
//
gosFX::Effect::~Effect()
{
Check_Object(this);
m_children.DeletePlugs();
}
//------------------------------------------------------------------------------
//
gosFX::Effect*
gosFX::Effect::Make(
Specification *spec,
unsigned flags
)
{
Check_Object(spec);
gos_PushCurrentHeap(Heap);
Effect *effect = new gosFX::Effect(DefaultData, spec, flags);
gos_PopCurrentHeap();
return effect;
}
//------------------------------------------------------------------------------
//
void
gosFX::Effect::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//------------------------------------------------------------------------------
//
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_ageRate == -1.0f)
{
Stuff::Scalar lifetime =
m_specification->m_lifeSpan.ComputeValue(m_seed, 0.0f);
Min_Clamp(lifetime, 0.033333f);
m_ageRate = 1.0f / lifetime;
}
else
m_ageRate = info->m_ageRate;
m_age = info->m_age;
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();
#if 0
Event *event;
while ((event = m_event.GetCurrent()) != NULL)
{
Check_Object(event);
if (event->m_time > m_age)
break;
//
//---------------------------------------------------------
// Make sure we only launch the effect if we are allowed to
//---------------------------------------------------------
//
#if defined(LAB_ONLY)
if (
Disabled_Events[
EffectLibrary::Instance->Find(event->m_effectID)->GetClassID()
- EffectClassID
]
)
{
m_event.Next();
continue;
}
#endif
//
//------------------------------------------------------
// Make sure the effect is within our known camera range
//------------------------------------------------------
//
Stuff::Vector3D diff(
LastCameraPosition.x - m_localToWorld(3,0),
LastCameraPosition.y - m_localToWorld(3,1),
LastCameraPosition.z - m_localToWorld(3,2)
);
Stuff::Scalar camera_distance = diff.GetLengthSquared() + LODOffset;
Min_Clamp(camera_distance, LODOffset);
if (camera_distance < event->m_nearLimit || camera_distance > event->m_farLimit)
{
m_event.Next();
continue;
}
//
//-------------------------------------------------------------
// This event needs to go, so spawn and bump the effect pointer
//-------------------------------------------------------------
//
GFX_LOGIC("Execute::Effect::CreateChild");
unsigned flags = ExecuteFlag;
if ((event->m_flags&SimulationModeMask) == ParentSimulationMode)
{
Verify((m_flags&SimulationModeMask) != ParentSimulationMode);
flags |= m_flags&SimulationModeMask;
}
else
flags |= event->m_flags&SimulationModeMask;
Effect* effect =
EffectLibrary::Instance->MakeEffect(
event->m_effectID,
flags
);
Check_Object(effect);
m_children.Add(effect);
m_event.Next();
//
//---------------------------------------------
// Now set the info for starting the new effect
//---------------------------------------------
//
effect->m_localToParent = event->m_localToParent;
Stuff::Scalar min_seed =
m_specification->m_minimumChildSeed.ComputeValue(m_age, m_seed);
Stuff::Scalar seed_range =
m_specification->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);
ExecuteInfo
local_info(
info->m_time,
&m_localToWorld,
NULL,
seed
);
effect->Start(&local_info);
}
#endif
gos_PopCurrentHeap();
}
//------------------------------------------------------------------------------
//
bool gosFX::Effect::Execute(ExecuteInfo *info)
{
Check_Object(this);
Check_Pointer(info);
GFX_LOGIC("Execute::Effect");
//
//----------------------------------------
// If we aren't supposed to execute, don't
//----------------------------------------
//
if (!IsExecuted())
return false;
Set_Statistic(Effect_Count, Effect_Count+1);
Verify(IsExecuted());
gos_PushCurrentHeap(Heap);
//
//-----------------------------------------------------
// If a new seed is provided, override the current seed
//-----------------------------------------------------
//
if (info->m_seed != -1.0f)
{
Verify(info->m_seed>=0.0f && info->m_seed<1.0f);
m_seed = info->m_seed;
}
//
//--------------------------------------------
// Figure out the new age and clear the bounds
//--------------------------------------------
//
Stuff::Scalar delta = static_cast<Stuff::Scalar>(info->m_time - m_lastRan);
Stuff::Scalar age = m_age + delta * m_ageRate;
Verify(age >= 0.0f && age >= m_age);
*info->m_bounds = Stuff::OBB::Identity;
//
//--------------------------------
// Update the effectToWorld matrix
//--------------------------------
//
Check_Object(info->m_parentToWorld);
m_localToWorld.Multiply(m_localToParent, *info->m_parentToWorld);
//
//--------------------------------------------------
// Check to see if the top event needs to be handled
//--------------------------------------------------
//
Check_Object(m_specification);
Event *event;
while ((event = m_event.GetCurrent()) != NULL)
{
Check_Object(event);
if (event->m_time > m_age)
break;
//
//---------------------------------------------------------
// Make sure we only launch the effect if we are allowed to
//---------------------------------------------------------
//
#if defined(LAB_ONLY)
if (
Disabled_Events[
EffectLibrary::Instance->Find(event->m_effectID)->GetClassID()
- EffectClassID
]
)
{
m_event.Next();
continue;
}
#endif
//
//------------------------------------------------------
// Make sure the effect is within our known camera range
//------------------------------------------------------
//
Stuff::Vector3D diff(
LastCameraPosition.x - m_localToWorld(3,0),
LastCameraPosition.y - m_localToWorld(3,1),
LastCameraPosition.z - m_localToWorld(3,2)
);
Stuff::Scalar camera_distance = diff.GetLengthSquared() + LODOffset;
Min_Clamp(camera_distance, LODOffset);
if (camera_distance < event->m_nearLimit || camera_distance > event->m_farLimit)
{
m_event.Next();
continue;
}
//
//-------------------------------------------------------------
// This event needs to go, so spawn and bump the effect pointer
//-------------------------------------------------------------
//
GFX_LOGIC("Execute::Effect::CreateChild");
unsigned flags = ExecuteFlag;
if ((event->m_flags&SimulationModeMask) == ParentSimulationMode)
{
Verify((m_flags&SimulationModeMask) != ParentSimulationMode);
flags |= m_flags&SimulationModeMask;
}
else
flags |= event->m_flags&SimulationModeMask;
Effect* effect =
EffectLibrary::Instance->MakeEffect(
event->m_effectID,
flags
);
Check_Object(effect);
m_children.Add(effect);
m_event.Next();
//
//---------------------------------------------
// Now set the info for starting the new effect
//---------------------------------------------
//
effect->m_localToParent = event->m_localToParent;
Stuff::Scalar min_seed =
m_specification->m_minimumChildSeed.ComputeValue(m_age, m_seed);
Stuff::Scalar seed_range =
m_specification->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);
ExecuteInfo
local_info(
info->m_time,
&m_localToWorld,
NULL,
seed
);
effect->Start(&local_info);
}
//
//------------------------------------------------------------
// Execute all the children. If any of them finish, kill them
//------------------------------------------------------------
//
{
GFX_LOGIC("Execute::Effect::ExecuteChildren");
Stuff::ChainIteratorOf<gosFX::Effect*> children(&m_children);
gosFX::Effect *child;
Stuff::OBB child_obb = Stuff::OBB::Identity;
ExecuteInfo
child_info(
info->m_time,
&m_localToWorld,
&child_obb
);
child_info.m_bounds = &child_obb;
while ((child = children.ReadAndNext()) != NULL)
{
Check_Object(child);
if (!child->Execute(&child_info))
{
Check_Object(child);
delete child;
continue;
}
//
//--------------------------------------------------------------
// Merge the bounding sphere of the child into the bounds of the
// parent
//--------------------------------------------------------------
//
Stuff::OBB parent_bounds;
parent_bounds.Multiply(child_obb, m_localToParent);
info->m_bounds->Union(*info->m_bounds, parent_bounds);
}
}
Check_Object(info->m_bounds);
//
//----------------------------------------------------------------------
// Set the new time, then if we have run the course of the effect, start
// over if we loop, otherwise wait for our children to finish before
// killing ourselves
//----------------------------------------------------------------------
//
m_lastRan = info->m_time;
m_age = age;
if (m_age >= 1.0f)
{
m_age = 1.0f;
if (IsLooped())
Start(info);
else if (HasFinished())
Kill();
}
//
//----------------------------------
// Tell our parent if we need to die
//----------------------------------
//
gos_PopCurrentHeap();
return IsExecuted();
}
//------------------------------------------------------------------------------
//
void gosFX::Effect::Stop()
{
Check_Object(this);
//
//-----------------
// Stop this effect
//-----------------
//
m_ageRate = 1.0e6f;
SetLoopOff();
if (m_event.GetCurrent() != NULL)
{
m_event.Last();
m_event.Next();
}
//
//---------------------------
// Now stop all child effects
//---------------------------
//
Stuff::ChainIteratorOf<gosFX::Effect*> children(&m_children);
gosFX::Effect *child;
while ((child = children.ReadAndNext()) != NULL)
{
Check_Object(child);
child->Stop();
}
}
//------------------------------------------------------------------------------
//
void gosFX::Effect::Kill()
{
Check_Object(this);
//
//------------------------------------
// Kill the children then kill ourself
//------------------------------------
//
Stuff::ChainIteratorOf<gosFX::Effect*> children(&m_children);
gosFX::Effect* child;
while ((child = children.ReadAndNext()) != NULL)
{
Check_Object(child);
child->Kill();
}
SetExecuteOff();
}
//------------------------------------------------------------------------------
//
void gosFX::Effect::Draw(DrawInfo *info)
{
Check_Object(this);
Check_Pointer(info);
GFX_RENDER("Effect");
//
//-------------------------------------
// Make sure all the children get drawn
//-------------------------------------
//
DrawInfo new_info;
Check_Object(m_specification);
new_info.m_state.Combine(info->m_state, m_specification->m_state);
Stuff::LinearMatrix4D local_to_world;
local_to_world.Multiply(m_localToParent, *info->m_parentToWorld);
new_info.m_parentToWorld = &local_to_world;
new_info.m_clipper = info->m_clipper;
new_info.m_clippingFlags = info->m_clippingFlags;
Stuff::ChainIteratorOf<gosFX::Effect*> children(&m_children);
gosFX::Effect *child;
while ((child = children.ReadAndNext()) != NULL)
{
Check_Object(child);
child->Draw(&new_info);
}
}
//------------------------------------------------------------------------------
//
bool gosFX::Effect::HasFinished()
{
Check_Object(this);
//
//-------------------------------------------------------------------------
// An effect is not finished if it is executing and its life hasn't expired
//-------------------------------------------------------------------------
//
if (IsExecuted() && m_age < 1.0f)
return false;
//
//-----------------------------------------------
// It is also not finished if it has any children
//-----------------------------------------------
//
Stuff::ChainIteratorOf<gosFX::Effect*> children(&m_children);
return children.GetCurrent() == NULL;
}
//#############################################################################
//########################## gosFX::Effect__ClassData ##########################
//#############################################################################
void
gosFX::Effect__ClassData::TestInstance()
{
Verify(IsDerivedFrom(gosFX::Effect::DefaultData));
}