#include "pch.h"
//////////////////////////////////////////////////////////////////////////////
//
// ExplosionGeo
//
//////////////////////////////////////////////////////////////////////////////
class ExplosionGeoImpl :
public ExplosionGeo
{
private:
//////////////////////////////////////////////////////////////////////////////
//
// Types
//
//////////////////////////////////////////////////////////////////////////////
class ExplosionData : IObject {
public:
TRef<AnimatedImage> m_pimage;
Vector m_position;
Vector m_dposition;
float m_angle;
float m_timeStart;
float m_scale;
};
class ShockwaveData : IObject {
public:
TRef<Image> m_pimageShockwave;
Vector m_position;
Vector m_dposition;
Vector m_forward;
Vector m_right;
Color m_color;
float m_timeStart;
float m_scale;
};
typedef TList<ExplosionData> ExplosionDataList;
//////////////////////////////////////////////////////////////////////////////
//
// Members
//
//////////////////////////////////////////////////////////////////////////////
TList<ShockwaveData> m_listShockwave;
TVector<ExplosionDataList> m_vlistExplosion;
//////////////////////////////////////////////////////////////////////////////
//
// Value Members
//
//////////////////////////////////////////////////////////////////////////////
Number* GetTime() { return Number::Cast(GetChild(0)); }
public:
ExplosionGeoImpl(Number* ptime) :
ExplosionGeo(ptime),
m_vlistExplosion(24)
{
}
//////////////////////////////////////////////////////////////////////////////
//
// Methods
//
//////////////////////////////////////////////////////////////////////////////
void AddExplosion(
const Vector& position,
const Vector& forward,
const Vector& right,
const Vector& dposition,
float radiusExplosion,
float radiusShockWave,
const Color& color,
int countDecals,
TVector<TRef<AnimatedImage> > vpimage,
Image* pimageShockwave
) {
//
// Add the shockwave
//
if (pimageShockwave != NULL) {
m_listShockwave.PushFront();
ShockwaveData& sdata = m_listShockwave.GetFront();
sdata.m_timeStart = GetTime()->GetValue();
sdata.m_pimageShockwave = pimageShockwave;
sdata.m_color = color;
sdata.m_position = position;
sdata.m_dposition = dposition;
sdata.m_scale = radiusShockWave;
sdata.m_forward = forward;
sdata.m_right = right;
}
//
// Add the little explosions
//
int countImage = vpimage.GetCount();
int indexImage = 0;
for (int index = 0; index < countDecals; index++) {
ExplosionDataList& list = m_vlistExplosion.Get(index);
list.PushFront();
ExplosionData& edata = list.GetFront();
edata.m_timeStart = GetTime()->GetValue() + index * 0.25f;
edata.m_pimage = vpimage[indexImage];
edata.m_position = position + Vector::RandomPosition(radiusExplosion * 0.5f);
edata.m_dposition = dposition;
edata.m_angle = random(0, 2 * pi);
edata.m_scale = radiusExplosion;
indexImage++;
if (indexImage >= countImage) {
indexImage = 0;
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Value Methods
//
//////////////////////////////////////////////////////////////////////////////
ZString GetFunctionName() { return "ExplosionGeo"; }
//////////////////////////////////////////////////////////////////////////////
//
// Geometry Methods
//
//////////////////////////////////////////////////////////////////////////////
float RenderShockwaves(Context* pcontext)
{
float fill = 0;
TList<ShockwaveData>::Iterator iter(m_listShockwave);
while (!iter.End()) {
ShockwaveData& sdata = iter.Value();
float time = GetTime()->GetValue() - sdata.m_timeStart;
float bright = 1.0f - time * time;
if (bright <= 0) {
iter.Remove();
} else {
float scale = time * sdata.m_scale;
fill +=
pcontext->DrawDecal(
sdata.m_pimageShockwave->GetSurface(),
bright * sdata.m_color,
sdata.m_position + time * sdata.m_dposition,
scale * sdata.m_forward,
scale * sdata.m_right,
0,
0
);
iter.Next();
}
};
return fill;
}
float RenderExplosions(
Context* pcontext,
ExplosionDataList& list
) {
float fill = 0;
ExplosionDataList::Iterator iter(list);
while (!iter.End()) {
ExplosionData& edata = iter.Value();
float time = GetTime()->GetValue() - edata.m_timeStart;
if (time >= 0) {
int frame = (int)(time * 20.0f);
if (frame >= edata.m_pimage->GetCount()) {
iter.Remove();
continue;
} else {
fill +=
pcontext->DrawDecal(
edata.m_pimage->GetSurface(frame),
Color::White(),
edata.m_position + time * edata.m_dposition,
Vector::GetZero(),
Vector::GetZero(),
edata.m_scale,
edata.m_angle
);
}
}
iter.Next();
}
return fill;
}
void Render(Context* pcontext)
{
float fill = 0;
fill += RenderShockwaves(pcontext);
int count = m_vlistExplosion.GetCount();
for (int index = 0; index < count; index++) {
fill += RenderExplosions(pcontext, m_vlistExplosion.Get(index));
//
// If we have passed the fill limit throw away the rest of the explosions
//
if (fill > 2.0f) {
for (int index2 = index + 1; index2 < count; index2++) {
m_vlistExplosion.Get(index2).SetEmpty();
}
return;
}
}
}
};
//////////////////////////////////////////////////////////////////////////////
//
// ExplosionGeo Factory
//
//////////////////////////////////////////////////////////////////////////////
TRef<ExplosionGeo> CreateExplosionGeo(Number* ptime)
{
return new ExplosionGeoImpl(ptime);
}