404 lines
10 KiB
C++
404 lines
10 KiB
C++
// ======================= ZoneTool =======================
|
|
// zonetool, a fastfile linker for various
|
|
// Call of Duty titles.
|
|
//
|
|
// Project: https://github.com/ZoneTool/zonetool
|
|
// Author: RektInator (https://github.com/RektInator)
|
|
// License: GNU GPL v3.0
|
|
// ========================================================
|
|
#include "stdafx.hpp"
|
|
#include "IW5/Assets/FxEffectDef.hpp"
|
|
|
|
namespace ZoneTool
|
|
{
|
|
namespace IW4
|
|
{
|
|
void IFxEffectDef::init(const std::string& name, ZoneMemory* mem)
|
|
{
|
|
this->name_ = name;
|
|
this->asset_ = this->parse(name, mem);
|
|
|
|
if (!this->asset_)
|
|
{
|
|
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).fx;
|
|
}
|
|
}
|
|
|
|
void IFxEffectDef::prepare(ZoneBuffer* buf, ZoneMemory* mem)
|
|
{
|
|
}
|
|
|
|
FxEffectDef* IFxEffectDef::parse(const std::string& name, ZoneMemory* mem)
|
|
{
|
|
const auto iw5_fx = IW5::IFxEffectDef::parse(name, mem);
|
|
|
|
if (!iw5_fx)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
const auto fx = mem->Alloc<FxEffectDef>();
|
|
|
|
memcpy(fx, iw5_fx, sizeof FxEffectDef);
|
|
|
|
// transform elem defs
|
|
const auto elem_count = fx->elemDefCountLooping + fx->elemDefCountEmission + fx->elemDefCountOneShot;
|
|
fx->elemDefs = mem->Alloc<FxElemDef>(elem_count);
|
|
for (auto i = 0; i < elem_count; i++)
|
|
{
|
|
memcpy(&fx->elemDefs[i], &iw5_fx->elemDefs[i], sizeof FxElemDef);
|
|
|
|
if (fx->elemDefs[i].extended.trailDef)
|
|
{
|
|
// iw5 feature, unsupported on iw4
|
|
if (fx->elemDefs[i].elemType == 9)
|
|
{
|
|
fx->elemDefs[i].extended.trailDef = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return fx;
|
|
}
|
|
|
|
void IFxEffectDef::load_depending(IZone* zone)
|
|
{
|
|
auto* data = this->asset_;
|
|
|
|
auto load_fx_elem_visuals = [zone](FxElemDef* def, FxElemDefVisuals* vis)
|
|
{
|
|
if (def->elemType == 11)
|
|
{
|
|
for (auto i = 0; i < def->visualCount; i++)
|
|
{
|
|
if (vis->markArray[i])
|
|
{
|
|
if (vis->markArray[i][0])
|
|
{
|
|
zone->add_asset_of_type(material, vis->markArray[i][0]->name);
|
|
}
|
|
if (vis->markArray[i][1])
|
|
{
|
|
zone->add_asset_of_type(material, vis->markArray[i][1]->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (def->visualCount > 1)
|
|
{
|
|
for (auto i = 0; i < def->visualCount; i++)
|
|
{
|
|
if (def->elemType == 12 && vis->array[i].effectDef)
|
|
{
|
|
zone->add_asset_of_type(fx, vis->array[i].effectDef->name);
|
|
}
|
|
else if (def->elemType == 10 && vis->array[i].soundName)
|
|
{
|
|
zone->add_asset_of_type(sound, vis->array[i].soundName);
|
|
}
|
|
else if (def->elemType == 7 && vis->array[i].xmodel)
|
|
{
|
|
zone->add_asset_of_type(xmodel, vis->array[i].xmodel->name);
|
|
}
|
|
else
|
|
{
|
|
if (def->elemType != 8 && vis->array[i].material)
|
|
{
|
|
zone->add_asset_of_type(material, vis->array[i].material->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (def->elemType == 12 && vis->instance.effectDef)
|
|
{
|
|
zone->add_asset_of_type(fx, vis->instance.effectDef->name);
|
|
}
|
|
else if (def->elemType == 10 && vis->instance.soundName)
|
|
{
|
|
zone->add_asset_of_type(sound, vis->instance.soundName);
|
|
}
|
|
else if (def->elemType == 7 && vis->instance.xmodel)
|
|
{
|
|
zone->add_asset_of_type(xmodel, vis->instance.xmodel->name);
|
|
}
|
|
else
|
|
{
|
|
if (def->elemType != 8 && vis->instance.material)
|
|
{
|
|
zone->add_asset_of_type(material, vis->instance.material->name);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Loop through frames
|
|
for (auto i = 0; i < data->elemDefCountEmission + data->elemDefCountLooping + data->elemDefCountOneShot; i++)
|
|
{
|
|
auto* def = &data->elemDefs[i];
|
|
|
|
// Sub-FX effects
|
|
if (def->effectEmitted)
|
|
{
|
|
zone->add_asset_of_type(fx, def->effectEmitted->name);
|
|
}
|
|
if (def->effectOnDeath)
|
|
{
|
|
zone->add_asset_of_type(fx, def->effectOnDeath->name);
|
|
}
|
|
if (def->effectOnImpact)
|
|
{
|
|
zone->add_asset_of_type(fx, def->effectOnImpact->name);
|
|
}
|
|
|
|
// Visuals
|
|
load_fx_elem_visuals(def, &def->visuals);
|
|
}
|
|
}
|
|
|
|
std::string IFxEffectDef::name()
|
|
{
|
|
return this->name_;
|
|
}
|
|
|
|
std::int32_t IFxEffectDef::type()
|
|
{
|
|
return fx;
|
|
}
|
|
|
|
void IFxEffectDef::write_fx_elem_visuals(IZone* zone, ZoneBuffer* buf, FxElemDef* def,
|
|
FxElemVisuals* dest)
|
|
{
|
|
auto* data = dest;
|
|
|
|
switch (def->elemType)
|
|
{
|
|
case FX_ELEM_TYPE_RUNNER:
|
|
{
|
|
buf->write_str(data->effectDef->name);
|
|
ZoneBuffer::clear_pointer(&dest->effectDef);
|
|
break;
|
|
}
|
|
case FX_ELEM_TYPE_SOUND:
|
|
{
|
|
if (data->soundName)
|
|
{
|
|
buf->write_str(data->soundName);
|
|
ZoneBuffer::clear_pointer(&dest->soundName);
|
|
}
|
|
break;
|
|
}
|
|
case FX_ELEM_TYPE_SPOT_LIGHT:
|
|
{
|
|
dest->anonymous = (data->anonymous)
|
|
? zone->get_asset_pointer(lightdef, ((GfxLightDef*)data->anonymous)->name)
|
|
: nullptr;
|
|
break;
|
|
}
|
|
case FX_ELEM_TYPE_MODEL:
|
|
{
|
|
dest->xmodel = (data->xmodel)
|
|
? reinterpret_cast<XModel*>(zone->get_asset_pointer(xmodel, data->xmodel->name))
|
|
: nullptr;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
if (def->elemType != FX_ELEM_TYPE_OMNI_LIGHT)
|
|
{
|
|
dest->material = (data->material)
|
|
? reinterpret_cast<Material*>(zone->get_asset_pointer(
|
|
material, data->material->name))
|
|
: nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void IFxEffectDef::write_fx_elem_def_visuals(IZone* zone, ZoneBuffer* buf, FxElemDef* def,
|
|
FxElemDefVisuals* dest)
|
|
{
|
|
auto* data = dest;
|
|
|
|
if (def->elemType == FX_ELEM_TYPE_DECAL)
|
|
{
|
|
if (data->markArray)
|
|
{
|
|
auto destvisuals = buf->write(data->markArray, def->visualCount);
|
|
|
|
for (int i = 0; i < def->visualCount; i++)
|
|
{
|
|
destvisuals[i][0] = (data->markArray[i][0])
|
|
? reinterpret_cast<Material*>(zone->get_asset_pointer(
|
|
material, data->markArray[i][0]->name))
|
|
: nullptr;
|
|
destvisuals[i][1] = (data->markArray[i][1])
|
|
? reinterpret_cast<Material*>(zone->get_asset_pointer(
|
|
material, data->markArray[i][1]->name))
|
|
: nullptr;
|
|
}
|
|
}
|
|
}
|
|
else if (def->visualCount > 1)
|
|
{
|
|
auto* vis = buf->write(data->array, def->visualCount);
|
|
|
|
for (auto i = 0; i < def->visualCount; i++)
|
|
{
|
|
write_fx_elem_visuals(zone, buf, def, &vis[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
write_fx_elem_visuals(zone, buf, def, &dest->instance);
|
|
}
|
|
}
|
|
|
|
void IFxEffectDef::write_fx_elem_def(IZone* zone, ZoneBuffer* buf, FxElemDef* dest)
|
|
{
|
|
auto* data = dest;
|
|
|
|
if (data->velSamples)
|
|
{
|
|
buf->align(3);
|
|
buf->write(data->velSamples, data->velIntervalCount + 1);
|
|
ZoneBuffer::clear_pointer(&dest->velSamples);
|
|
}
|
|
|
|
if (data->visSamples)
|
|
{
|
|
buf->align(3);
|
|
buf->write(data->visSamples, data->visStateIntervalCount + 1);
|
|
ZoneBuffer::clear_pointer(&dest->visSamples);
|
|
}
|
|
|
|
write_fx_elem_def_visuals(zone, buf, data, &dest->visuals);
|
|
|
|
if (data->effectOnImpact)
|
|
{
|
|
buf->write_str_raw(data->effectOnImpact->name);
|
|
ZoneBuffer::clear_pointer(&dest->effectOnImpact);
|
|
}
|
|
|
|
if (data->effectOnDeath)
|
|
{
|
|
buf->write_str_raw(data->effectOnDeath->name);
|
|
ZoneBuffer::clear_pointer(&dest->effectOnDeath);
|
|
}
|
|
|
|
if (data->effectEmitted)
|
|
{
|
|
buf->write_str_raw(data->effectEmitted->name);
|
|
ZoneBuffer::clear_pointer(&dest->effectEmitted);
|
|
}
|
|
|
|
if (data->extended.trailDef)
|
|
{
|
|
if (data->elemType == FX_ELEM_TYPE_TRAIL)
|
|
{
|
|
if (data->extended.trailDef)
|
|
{
|
|
buf->align(3);
|
|
buf->write(data->extended.trailDef, sizeof(FxTrailDef));
|
|
|
|
if (data->extended.trailDef->verts)
|
|
{
|
|
buf->align(3);
|
|
buf->write(data->extended.trailDef->verts, data->extended.trailDef->vertCount);
|
|
}
|
|
|
|
if (data->extended.trailDef->inds)
|
|
{
|
|
buf->align(1);
|
|
buf->write(data->extended.trailDef->inds, data->extended.trailDef->indCount);
|
|
}
|
|
|
|
ZoneBuffer::clear_pointer(&dest->extended.trailDef);
|
|
}
|
|
}
|
|
else if (data->elemType == FX_ELEM_TYPE_SPARKFOUNTAIN)
|
|
{
|
|
if (data->extended.sparkFountain)
|
|
{
|
|
buf->align(3);
|
|
buf->write(data->extended.sparkFountain);
|
|
ZoneBuffer::clear_pointer(&dest->extended.sparkFountain);
|
|
}
|
|
}
|
|
else if (data->elemType == FX_ELEM_TYPE_SPOT_LIGHT)
|
|
{
|
|
if (data->extended.unknownDef)
|
|
{
|
|
buf->align(3);
|
|
buf->write_stream(data->extended.unknownDef, 24);
|
|
ZoneBuffer::clear_pointer(&dest->extended.unknownDef);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (data->extended.unknownDef)
|
|
{
|
|
buf->align(1);
|
|
buf->write_stream(data->extended.unknownDef, sizeof(BYTE));
|
|
ZoneBuffer::clear_pointer(&dest->extended.unknownDef);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void IFxEffectDef::write(IZone* zone, ZoneBuffer* buf)
|
|
{
|
|
auto* data = this->asset_;
|
|
auto* dest = buf->write(data);
|
|
|
|
buf->push_stream(3);
|
|
START_LOG_STREAM;
|
|
|
|
dest->name = buf->write_str(this->name());
|
|
|
|
if (data->elemDefs)
|
|
{
|
|
buf->align(3);
|
|
auto* fx_elem_def = buf->write(data->elemDefs,
|
|
data->elemDefCountEmission + data->elemDefCountLooping + data->
|
|
elemDefCountOneShot);
|
|
|
|
for (std::int32_t i = 0; i < (data->elemDefCountEmission + data->elemDefCountLooping + data->
|
|
elemDefCountOneShot); i++)
|
|
{
|
|
write_fx_elem_def(zone, buf, &fx_elem_def[i]);
|
|
}
|
|
|
|
ZoneBuffer::clear_pointer(&dest->elemDefs);
|
|
}
|
|
|
|
END_LOG_STREAM;
|
|
buf->pop_stream();
|
|
}
|
|
|
|
void IFxEffectDef::dump(FxEffectDef* asset)
|
|
{
|
|
auto* iw5_fx = new IW5::FxEffectDef;
|
|
memcpy(iw5_fx, asset, sizeof FxEffectDef);
|
|
memset(iw5_fx->pad, 0, sizeof iw5_fx->pad);
|
|
|
|
// alloc elemdefs
|
|
const auto elem_def_count = iw5_fx->elemDefCountEmission + iw5_fx->elemDefCountLooping + iw5_fx->elemDefCountOneShot;
|
|
iw5_fx->elemDefs = new IW5::FxElemDef[elem_def_count];
|
|
|
|
// transform elemdefs to iw5 format
|
|
for (auto i = 0; i < elem_def_count; i++)
|
|
{
|
|
memcpy(&iw5_fx->elemDefs[i], &asset->elemDefs[i], sizeof IW4::FxElemDef);
|
|
iw5_fx->elemDefs[i].pad = 0;
|
|
}
|
|
|
|
IW5::IFxEffectDef::dump(iw5_fx);
|
|
|
|
delete[] iw5_fx->elemDefs;
|
|
delete iw5_fx;
|
|
}
|
|
}
|
|
}
|