Files
zonetool/src/IW4/Assets/FxEffectDef.cpp
2020-12-16 20:44:46 +01:00

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;
}
}
}