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.
1249 lines
33 KiB
C++
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));
|
|
}
|