Initial commit

This commit is contained in:
RektInator
2020-12-16 20:44:46 +01:00
commit f212d7783c
291 changed files with 72238 additions and 0 deletions

34
src/CODO.lua Normal file
View File

@ -0,0 +1,34 @@
CODO = {}
function CODO:include()
includedirs {
path.join(ProjectFolder(), "CODO")
}
end
function CODO:link()
self:include()
links {
"CODO"
}
end
function CODO:project()
local folder = ProjectFolder();
project "CODO"
kind "StaticLib"
language "C++"
pchheader "stdafx.hpp"
pchsource(path.join(folder, "CODO/stdafx.cpp"))
files {
path.join(folder, "CODO/**.h"),
path.join(folder, "CODO/**.hpp"),
path.join(folder, "CODO/**.cpp")
}
self:include()
ZoneUtils:include()
end

View File

@ -0,0 +1,63 @@
// ======================= 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"
namespace ZoneTool::CODO
{
ILocalizeEntry::ILocalizeEntry()
{
}
ILocalizeEntry::~ILocalizeEntry()
{
}
void ILocalizeEntry::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).localize;
}
void ILocalizeEntry::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ILocalizeEntry::load_depending(IZone* zone)
{
}
std::string ILocalizeEntry::name()
{
return this->name_;
}
std::int32_t ILocalizeEntry::type()
{
return localize;
}
void ILocalizeEntry::write(IZone* zone, ZoneBuffer* buf)
{
auto data = this->asset_;
auto dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->localizedString = buf->write_str(data->localizedString);
dest->name = buf->write_str(data->name);
END_LOG_STREAM;
buf->pop_stream();
}
void ILocalizeEntry::dump(LocalizeEntry* asset)
{
}
}

View File

@ -0,0 +1,33 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool::CODO
{
class ILocalizeEntry : public IAsset
{
private:
std::string name_;
LocalizeEntry* asset_;
public:
ILocalizeEntry();
~ILocalizeEntry();
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(LocalizeEntry* asset);
};
}

View File

@ -0,0 +1,229 @@
// ======================= 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"
namespace ZoneTool::CODO
{
// LEGACY ZONETOOL CODE, FIX ME!
class CSV
{
protected:
std::string _name;
std::vector<std::vector<std::string>> _data;
public:
CSV(std::string name, char sep = ',')
: _name(name)
{
auto fp = FileSystem::FileOpen(name, "r"s);
if (fp)
{
long len = FileSystem::FileSize(fp);
auto buf = std::make_unique<char[]>(len + 1);
memset(buf.get(), 0, len + 1);
fread(buf.get(), len, 1, fp);
fclose(fp);
std::vector<std::string> rows = split(buf.get(), '\n');
for (auto& row : rows)
{
// Replace literal characters
std::size_t pos;
while ((pos = row.find("\\n")) != std::string::npos)
{
row.replace(pos, 2, "\n");
}
while ((pos = row.find("\\t")) != std::string::npos)
{
row.replace(pos, 2, "\t");
}
_data.push_back(split(row, sep));
}
}
}
std::string entry(std::size_t row, std::size_t column)
{
return _data[row][column];
}
std::size_t rows()
{
return _data.size();
}
std::size_t columns(std::size_t row)
{
return _data[row].size();
}
std::size_t max_columns()
{
std::size_t _max = 0;
for (std::size_t row = 0; row < this->rows(); row++)
{
if (_max < this->columns(row))
_max = this->columns(row);
}
return _max;
}
void clear()
{
for (std::size_t i = 0; i < _data.size(); i++)
{
for (std::size_t j = 0; j < _data[i].size(); j++)
_data[i][j].clear();
_data[i].clear();
}
_data.clear();
}
};
int StringTable_Hash(const char* string)
{
int hash = 0;
char* data = _strdup(string);
while (*data != 0)
{
hash = tolower(*data) + (31 * hash);
data++;
}
return hash;
}
StringTable* StringTable_Parse(std::string name, ZoneMemory* mem)
{
auto table = std::make_unique<CSV>(name);
auto stringtable = mem->Alloc<StringTable>();
stringtable->name = _strdup(name.c_str());
stringtable->rows = table->rows();
stringtable->columns = table->max_columns();
stringtable->strings = mem->Alloc<StringTableCell>(stringtable->rows * stringtable->columns);
for (int row = 0; row < table->rows(); row++)
{
for (int col = 0; col < table->columns(row); col++)
{
int entry = (row * stringtable->columns) + col;
stringtable->strings[entry].string = strdup(table->entry(row, col).c_str());
stringtable->strings[entry].hash = StringTable_Hash(stringtable->strings[entry].string);
}
}
return stringtable;
}
IStringTable::IStringTable()
{
}
IStringTable::~IStringTable()
{
}
void IStringTable::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).stringtable;
if (FileSystem::FileExists(name))
{
ZONETOOL_INFO("Parsing stringtable %s...", name.data());
this->asset_ = StringTable_Parse(name, mem);
}
}
void IStringTable::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IStringTable::load_depending(IZone* zone)
{
}
std::string IStringTable::name()
{
return this->name_;
}
std::int32_t IStringTable::type()
{
return stringtable;
}
void IStringTable::write(IZone* zone, ZoneBuffer* buf)
{
auto data = this->asset_;
auto dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
// TODO
StringTable;
dest->name = buf->write_str(this->name());
if (data->strings)
{
buf->align(3);
auto destStrings = buf->write(data->strings, data->columns * data->rows);
if (data->columns * data->rows > 0)
{
for (int i = 0; i < data->columns * data->rows; i++)
{
destStrings[i].string = buf->write_str(data->strings[i].string);
}
}
ZoneBuffer::clear_pointer(&dest->strings);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IStringTable::dump(StringTable* asset)
{
std::string path = asset->name;
auto file = FileSystem::FileOpen(path, "w"s);
for (int row = 0; row < asset->rows; row++)
{
for (int column = 0; column < asset->columns; column++)
{
fprintf(
file,
"%s%s",
(asset->strings[(row * asset->columns) + column].string)
? asset->strings[(row * asset->columns) + column].string
: "",
(column == asset->columns - 1) ? "\n" : ","
);
}
}
FileSystem::FileClose(file);
}
}

View File

@ -0,0 +1,33 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool::CODO
{
class IStringTable : public IAsset
{
private:
std::string name_;
StringTable* asset_;
public:
IStringTable();
~IStringTable();
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(StringTable* asset);
};
}

140
src/CODO/CODO.cpp Normal file
View File

@ -0,0 +1,140 @@
// ======================= 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 <unordered_map>
namespace ZoneTool::CODO
{
const char* Linker::version()
{
return "CODO";
}
bool Linker::is_used()
{
return false;
}
const char* Linker::GetAssetName(XAssetType type, XAssetHeader header)
{
// todo
if (type == image)
{
return header.gfximage->name;
}
if (type == menu)
{
//
}
else
{
return header.rawfile->name;
}
return "";
}
void Linker::startup()
{
if (this->is_used())
{
// todo
}
}
std::shared_ptr<IZone> Linker::alloc_zone(const std::string& zone)
{
// allocate zone
auto ptr = std::make_shared<Zone>(zone, this);
return ptr;
}
std::shared_ptr<ZoneBuffer> Linker::alloc_buffer()
{
auto ptr = std::make_shared<ZoneBuffer>();
ptr->init_streams(8);
return ptr;
}
void Linker::load_zone(const std::string& name)
{
ZONETOOL_INFO("Loading zone \"%s\"...", name.data());
XZoneInfo zone = {name.data(), 20, 0};
// DB_LoadXAssets(&zone, 1, 0);
ZONETOOL_INFO("Zone \"%s\" loaded.", name.data());
}
void Linker::unload_zones()
{
}
bool Linker::is_valid_asset_type(const std::string& type)
{
return this->type_to_int(type) >= 0;
}
std::int32_t Linker::type_to_int(std::string type)
{
auto xassettypes = reinterpret_cast<char**>(0x00799278);
for (std::int32_t i = 0; i < max; i++)
{
if (xassettypes[i] == type)
return i;
}
return -1;
}
std::string Linker::type_to_string(std::int32_t type)
{
auto xassettypes = reinterpret_cast<char**>(0x00799278);
return xassettypes[type];
}
bool Linker::supports_building()
{
return false;
}
bool Linker::supports_version(const zone_target_version version)
{
return false;
}
void Linker::dump_zone(const std::string& name)
{
//is_dumping_complete = false;
//is_dumping = true;
//currentDumpingZone = name;
load_zone(name);
//while (!is_dumping_complete)
//{
// Sleep(1);
//}
}
void Linker::verify_zone(const std::string& name)
{
//isVerifying = true;
//currentDumpingZone = name;
load_zone(name);
}
Linker::Linker()
{
}
Linker::~Linker()
{
}
}

45
src/CODO/CODO.hpp Normal file
View File

@ -0,0 +1,45 @@
// ======================= 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
// ========================================================
#pragma once
#include <ZoneUtils.hpp>
#include "Functions.hpp"
#include "Structs.hpp"
#include "../IW5/Structs.hpp"
#include "Zone.hpp"
namespace ZoneTool::CODO
{
using GfxImageFileHeader = IW5::GfxImageFileHeader;
class Linker : public ILinker
{
public:
Linker();
~Linker();
const char* version() override;
bool is_used() override;
void startup() override;
std::shared_ptr<IZone> alloc_zone(const std::string& zone) override;
std::shared_ptr<ZoneBuffer> alloc_buffer() override;
void load_zone(const std::string& name) override;
void unload_zones() override;
bool is_valid_asset_type(const std::string& type) override;
std::int32_t type_to_int(std::string type) override;
std::string type_to_string(std::int32_t type) override;
bool supports_building() override;
bool supports_version(const zone_target_version version) override;
void dump_zone(const std::string& name) override;
void verify_zone(const std::string& name) override;
static const char* GetAssetName(XAssetType type, XAssetHeader header);
};
}

32
src/CODO/Functions.hpp Normal file
View File

@ -0,0 +1,32 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool::CODO
{
union XAssetHeader;
// TODO: fix offsets!
static Function<XAssetHeader(std::int32_t, const char*)> DB_FindXAssetHeader = 0x407930;
static Function<void(XZoneInfo*, std::uint32_t, std::uint32_t)> DB_LoadXAssets = 0x4E5930;
typedef int (__cdecl * DB_GetXAssetSizeHandler_t)();
static DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x799488;
static const char* SL_ConvertToString(std::uint16_t index)
{
return Memory::func<const char*(int)>(0x004EC1D0)(index);
}
static short SL_AllocString(const std::string& string)
{
return Memory::func<short(const char*, std::uint32_t, std::size_t)>(0x00436B40)(
string.data(), 1, string.size() + 1);
}
}

3444
src/CODO/Structs.hpp Normal file

File diff suppressed because it is too large Load Diff

298
src/CODO/Zone.cpp Normal file
View File

@ -0,0 +1,298 @@
// ======================= 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"
namespace ZoneTool::CODO
{
IAsset* Zone::find_asset(std::int32_t type, const std::string& name)
{
for (auto idx = 0u; idx < m_assets.size(); idx++)
{
if (m_assets[idx]->type() == type && m_assets[idx]->name() == name)
{
return m_assets[idx].get();
}
}
return nullptr;
}
void* Zone::get_asset_pointer(std::int32_t type, const std::string& name)
{
for (auto idx = 0u; idx < m_assets.size(); idx++)
{
if (m_assets[idx]->type() == type && m_assets[idx]->name() == name)
{
auto ptr = reinterpret_cast<void*>((3 << 28) | ((this->m_assetbase + (8 * idx) + 4) & 0x0FFFFFFF) +
1);
// ZONETOOL_INFO("Asset pointer is %u", ptr);
return ptr;
}
}
return nullptr;
}
void Zone::add_asset_of_type_by_pointer(std::int32_t type, void* pointer)
{
#ifdef USE_VMPROTECT
VMProtectBeginUltra("IW4::Zone::AddAssetOfTypePtr");
#endif
// don't add asset if it already exists
for (std::size_t idx = 0; idx < m_assets.size(); idx++)
{
if (m_assets[idx]->type() == type && m_assets[idx]->pointer() == pointer)
{
return;
}
}
#define DECLARE_ASSET(__type__, __interface__) \
if (type == __type__) \
{ \
auto asset = std::make_shared < __interface__ >(); \
asset->init(pointer, this->m_zonemem); \
asset->load_depending(this); \
m_assets.push_back(asset); \
}
// declare asset interfaces
// DECLARE_ASSET(xmodelsurfs, IXSurface);
// DECLARE_ASSET(image, IGfxImage);
// DECLARE_ASSET(pixelshader, IPixelShader);
// DECLARE_ASSET(vertexshader, IVertexShader);
// DECLARE_ASSET(vertexdecl, IVertexDecl);
#ifdef USE_VMPROTECT
VMProtectEnd();
#endif
}
void Zone::add_asset_of_type(std::int32_t type, const std::string& name)
{
#ifdef USE_VMPROTECT
VMProtectBeginUltra("IW4::Zone::AddAssetOfType");
#endif
// don't add asset if it already exists
if (get_asset_pointer(type, name))
{
return;
}
#define DECLARE_ASSET(__type__, __interface__) \
if (type == __type__) \
{ \
auto asset = std::make_shared < __interface__ >(); \
asset->init(name, this->m_zonemem.get()); \
asset->load_depending(this); \
m_assets.push_back(asset); \
}
// declare asset interfaces
// DECLARE_ASSET(xanim, IXAnimParts);
// DECLARE_ASSET(pixelshader, IPixelShader);
// DECLARE_ASSET(vertexdecl, IVertexDecl);
// DECLARE_ASSET(vertexshader, IVertexShader);
// DECLARE_ASSET(techset, ITechset);
// DECLARE_ASSET(image, IGfxImage);
// DECLARE_ASSET(material, IMaterial)
// DECLARE_ASSET(xmodelsurfs, IXSurface);
// DECLARE_ASSET(xmodel, IXModel);
// DECLARE_ASSET(map_ents, IMapEnts);
// DECLARE_ASSET(rawfile, IRawFile);
// DECLARE_ASSET(com_map, IComWorld);
// DECLARE_ASSET(font, IFontDef);
DECLARE_ASSET(localize, ILocalizeEntry);
// DECLARE_ASSET(physpreset, IPhysPreset);
// DECLARE_ASSET(phys_collmap, IPhysCollmap);
DECLARE_ASSET(stringtable, IStringTable);
// DECLARE_ASSET(sound, ISound);
// DECLARE_ASSET(loaded_sound, ILoadedSound);
// DECLARE_ASSET(sndcurve, ISoundCurve);
// DECLARE_ASSET(game_map_mp, IGameWorldMp);
// DECLARE_ASSET(game_map_sp, IGameWorldSp);
// DECLARE_ASSET(fx_map, IFxWorld);
// DECLARE_ASSET(tracer, ITracerDef);
// DECLARE_ASSET(gfx_map, IGfxWorld);
// DECLARE_ASSET(col_map_mp, IClipMap);
// DECLARE_ASSET(fx, IFxEffectDef);
// DECLARE_ASSET(lightdef, ILightDef);
//DECLARE_ASSET(weapon, IWeaponDef); //still a work in progress, the CPP file isnt complete
//DECLARE_ASSET(structureddatadef, IStructuredDataDef);
#ifdef USE_VMPROTECT
VMProtectEnd();
#endif
}
void Zone::add_asset_of_type(const std::string& type, const std::string& name)
{
std::int32_t itype = m_linker->type_to_int(type);
this->add_asset_of_type(itype, name);
}
std::int32_t Zone::get_type_by_name(const std::string& type)
{
return m_linker->type_to_int(type);
}
void Zone::build(ZoneBuffer* buf)
{
auto startTime = GetTickCount64();
// make a folder in main, for the map images
std::filesystem::create_directories("main\\" + this->name_ + "\\images");
ZONETOOL_INFO("Compiling fastfile \"%s\"...", this->name_.data());
constexpr std::size_t num_streams = 8;
XZoneMemory<num_streams> mem;
std::size_t headersize = sizeof XZoneMemory<num_streams>;
memset(&mem, 0, headersize);
auto zone = buf->at<XZoneMemory<num_streams>>();
// write zone header
buf->write(&mem);
std::uintptr_t pad = 0xFFFFFFFF;
std::uintptr_t zero = 0;
// write asset types to header
for (auto i = 0u; i < m_assets.size(); i++)
{
m_assets[i]->prepare(buf, this->m_zonemem.get());
}
// write scriptstring count
std::uint32_t stringcount = buf->scriptstring_count();
buf->write<std::uint32_t>(&stringcount);
buf->write<std::uintptr_t>(stringcount > 0 ? (&pad) : (&zero));
// write asset count
std::uint32_t asset_count = m_assets.size();
buf->write<std::uint32_t>(&asset_count);
buf->write<std::uintptr_t>(asset_count > 0 ? (&pad) : (&zero));
// push stream
buf->push_stream(3);
START_LOG_STREAM;
if (stringcount)
{
// write pointer for every scriptstring
for (std::size_t idx = 0; idx < stringcount; idx++)
{
buf->write<std::uintptr_t>(&pad);
}
// write scriptstrings
buf->align(3);
for (std::size_t idx = 0; idx < stringcount; idx++)
{
buf->write_str(buf->get_scriptstring(idx));
}
}
buf->pop_stream();
buf->push_stream(3);
// align buffer
buf->align(3);
// set asset ptr base
this->m_assetbase = buf->stream_offset(3);
// write asset types to header
for (auto i = 0u; i < asset_count; i++)
{
// write asset data to zone
auto type = m_assets[i]->type();
buf->write(&type);
buf->write(&pad);
}
// write assets
for (auto& asset : m_assets)
{
// push stream
buf->push_stream(0);
buf->align(3);
// write asset
asset->write(this, buf);
// pop stream
buf->pop_stream();
}
// pop stream
END_LOG_STREAM;
buf->pop_stream();
// update zone header
zone->size = buf->size() - headersize;
zone->externalsize = 0;
// Update stream data
for (int i = 0; i < num_streams; i++)
{
zone->streams[i] = buf->stream_offset(i);
}
// Dump zone to disk (DEBUGGING PURPOSES)
buf->save("debug\\" + this->name_ + ".zone");
// Compress buffer
auto buf_compressed = buf->compress_zlib();
// Generate FF header
auto header = this->m_zonemem->Alloc<XFileHeader>();
strcpy(header->header, "IWffu100");
header->version = 423;
header->allowOnlineUpdate = 0;
// Encrypt fastfile
// ZoneBuffer encrypted(buf_compressed);
// encrypted.encrypt();
// Save fastfile
ZoneBuffer fastfile(buf_compressed.size() + 21);
fastfile.init_streams(1);
fastfile.write_stream(header, 21);
fastfile.write(buf_compressed.data(), buf_compressed.size());
fastfile.save("zone\\english\\" + this->name_ + ".ff");
ZONETOOL_INFO("Successfully compiled fastfile \"%s\"!", this->name_.data());
ZONETOOL_INFO("Compiling took %u msec.", GetTickCount64() - startTime);
// this->m_linker->UnloadZones();
}
Zone::Zone(std::string name, ILinker* linker)
{
currentzone = name;
this->m_linker = linker;
this->name_ = name;
this->m_zonemem = std::make_shared<ZoneMemory>(MAX_ZONE_SIZE);
}
Zone::~Zone()
{
// wipe all assets
m_assets.clear();
}
}

69
src/CODO/Zone.hpp Normal file
View File

@ -0,0 +1,69 @@
// ======================= 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
// ========================================================
#pragma once
extern std::string currentzone;
// #include "Assets/RawFile.hpp"
// #include "Assets/PhysPreset.hpp"
// #include "Assets/WeaponDef.hpp"
// #include "Assets/VertexDecl.hpp"
// #include "Assets/PixelShader.hpp"
// #include "Assets/VertexShader.hpp"
// #include "Assets/Techset.hpp"
// #include "Assets/GfxImage.hpp"
// #include "Assets/Material.hpp"
// #include "Assets/XSurface.hpp"
// #include "Assets/Sound.hpp"
// #include "Assets/LoadedSound.hpp"
// #include "Assets/SoundCurve.hpp"
// #include "Assets/FontDef.hpp"
// #include "Assets/PhysCollmap.hpp"
// #include "Assets/Xmodel.hpp"
// #include "Assets/GameWorldMp.hpp"
// #include "Assets/GameWorldSp.hpp"
// #include "Assets/FxWorld.hpp"
// #include "Assets/MapEnts.hpp"
// #include "Assets/ComWorld.hpp"
// #include "Assets/XAnimParts.hpp"
#include "Assets/StringTable.hpp"
#include "Assets/LocalizeEntry.hpp"
// #include "Assets/TracerDef.hpp"
// #include "Assets/GfxWorld.hpp"
// #include "Assets/ClipMap.hpp"
// #include "Assets/FxEffectDef.hpp"
// #include "Assets/LightDef.hpp"
namespace ZoneTool::CODO
{
class Zone : public IZone
{
private:
std::uintptr_t m_assetbase;
std::string name_;
ILinker* m_linker;
std::vector<std::shared_ptr<IAsset>> m_assets;
std::shared_ptr<ZoneMemory> m_zonemem;
public:
Zone(std::string name, ILinker* linker);
~Zone();
IAsset* find_asset(std::int32_t type, const std::string& name) override;
void* Zone::get_asset_pointer(std::int32_t type, const std::string& name) override;
void add_asset_of_type_by_pointer(std::int32_t type, void* pointer) override;
void add_asset_of_type(std::int32_t type, const std::string& name) override;
void add_asset_of_type(const std::string& type, const std::string& name) override;
std::int32_t get_type_by_name(const std::string& type) override;
void build(ZoneBuffer* buf) override;
};
}

9
src/CODO/stdafx.cpp Normal file
View File

@ -0,0 +1,9 @@
// ======================= 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"

29
src/CODO/stdafx.hpp Normal file
View File

@ -0,0 +1,29 @@
// ======================= 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
// ========================================================
#pragma once
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#undef min
#undef max
#undef add
#include <iostream>
#include <sstream>
#include <memory>
#include <vector>
// Namespaces
using namespace std::literals;
using namespace string_literals;
#include "CODO.hpp"

35
src/IW3.lua Normal file
View File

@ -0,0 +1,35 @@
IW3 = {}
function IW3:include()
includedirs {
path.join(ProjectFolder(), "IW3")
}
end
function IW3:link()
self:include()
links {
"IW3"
}
end
function IW3:project()
local folder = ProjectFolder();
project "IW3"
kind "StaticLib"
language "C++"
pchheader "stdafx.hpp"
pchsource(path.join(folder, "IW3/stdafx.cpp"))
files {
path.join(folder, "IW3/**.h"),
path.join(folder, "IW3/**.hpp"),
path.join(folder, "IW3/**.cpp")
}
self:include()
IW4:include()
ZoneUtils:include()
end

215
src/IW3/Assets/ClipMap.cpp Normal file
View File

@ -0,0 +1,215 @@
// ======================= ZoneTool =======================
// zonetool, a fastfile linker for various
// Call of Duty titles.
//
// Project: https://github.com/ZoneTool/zonetool
// Author: momo5502 (https://github.com/momo5502)
// License: GNU GPL v3.0
// ========================================================
#include "stdafx.hpp"
#include "../IW4/Assets/ClipMap.hpp"
#include "ClipMap.hpp"
namespace ZoneTool
{
namespace IW3
{
void IClipMap::dump(clipMap_t* asset, ZoneMemory* mem)
{
if (!asset) return;
auto* iw4_clipmap = mem->Alloc<IW4::clipMap_t>();
memset(iw4_clipmap, 0, sizeof IW4::clipMap_t);
// convert clipmap to IW4 format
iw4_clipmap->name = asset->name;
iw4_clipmap->isInUse = asset->isInUse;
iw4_clipmap->numCPlanes = asset->planeCount;
iw4_clipmap->cPlanes = (IW4::cplane_s*)asset->planes;
iw4_clipmap->numStaticModels = (int)asset->numStaticModels;
iw4_clipmap->staticModelList = mem->Alloc<IW4::cStaticModel_s>(iw4_clipmap->numStaticModels);
for (unsigned int i = 0; i < asset->numStaticModels; ++i)
{
std::memcpy(&iw4_clipmap->staticModelList[i], &asset->staticModelList[i].xmodel,
sizeof(IW4::cStaticModel_s));
iw4_clipmap->staticModelList[i].absBounds.compute();
}
iw4_clipmap->numMaterials = (int)asset->numMaterials;
iw4_clipmap->materials = mem->Alloc<IW4::dmaterial_t>(iw4_clipmap->numMaterials);
for (auto i = 0u; i < iw4_clipmap->numMaterials; i++)
{
iw4_clipmap->materials[i].material = mem->StrDup(asset->materials[i].material);
iw4_clipmap->materials[i].contentFlags = asset->materials[i].contentFlags;
iw4_clipmap->materials[i].surfaceFlags = asset->materials[i].surfaceFlags;
}
iw4_clipmap->numCBrushSides = (int)asset->numBrushSides;
iw4_clipmap->cBrushSides = mem->Alloc<IW4::cbrushside_t>(iw4_clipmap->numCBrushSides);
std::unordered_map<cbrushside_t*, IW4::cbrushside_t*> mapped_brush_sides;
for (unsigned int i = 0; i < asset->numBrushSides; ++i)
{
mapped_brush_sides[&asset->brushsides[i]] = &iw4_clipmap->cBrushSides[i];
iw4_clipmap->cBrushSides[i].plane = (IW4::cplane_s*)asset->brushsides[i].plane;
iw4_clipmap->cBrushSides[i].materialNum = asset->brushsides[i].materialNum;
iw4_clipmap->cBrushSides[i].firstAdjacentSideOffset = (char)asset->brushsides[i].firstAdjacentSideOffset;
iw4_clipmap->cBrushSides[i].edgeCount = asset->brushsides[i].edgeCount;
}
iw4_clipmap->numCBrushEdges = (int)asset->numBrushEdges;
iw4_clipmap->cBrushEdges = (IW4::cbrushedge_t*)asset->brushEdges;
iw4_clipmap->numCNodes = (int)asset->numNodes;
iw4_clipmap->cNodes = (IW4::cNode_t*)asset->nodes;
iw4_clipmap->numCLeaf = (int)asset->numLeafs;
iw4_clipmap->cLeaf = mem->Alloc<IW4::cLeaf_t>(iw4_clipmap->numCLeaf);
for (unsigned int i = 0; i < asset->numLeafs; ++i)
{
std::memcpy(&iw4_clipmap->cLeaf[i], &asset->leafs[i], sizeof(IW4::cLeaf_t));
iw4_clipmap->cLeaf[i].bounds.compute();
}
iw4_clipmap->numCLeafBrushNodes = (int)asset->leafbrushNodesCount;
iw4_clipmap->cLeafBrushNodes = (IW4::cLeafBrushNode_s*)asset->leafbrushNodes;
iw4_clipmap->numLeafBrushes = (int)asset->numLeafBrushes;
iw4_clipmap->leafBrushes = (short*)asset->leafbrushes;
iw4_clipmap->numLeafSurfaces = (int)asset->numLeafSurfaces;
iw4_clipmap->leafSurfaces = (int*)asset->leafsurfaces;
iw4_clipmap->numVerts = (int)asset->vertCount;
iw4_clipmap->verts = (IW4::VecInternal<3>*)asset->verts;
iw4_clipmap->numTriIndices = asset->triCount;
iw4_clipmap->triIndices = (short*)asset->triIndices;
iw4_clipmap->triEdgeIsWalkable = asset->triEdgeIsWalkable;
iw4_clipmap->numCollisionBorders = asset->borderCount;
iw4_clipmap->collisionBorders = (IW4::CollisionBorder*)asset->borders;
iw4_clipmap->numCollisionPartitions = asset->partitionCount;
iw4_clipmap->collisionPartitions = (IW4::CollisionPartition*)asset->partitions;
iw4_clipmap->numCollisionAABBTrees = asset->aabbTreeCount;
iw4_clipmap->collisionAABBTrees = mem->Alloc<IW4::CollisionAabbTree>(iw4_clipmap->numCollisionAABBTrees);
for (int i = 0; i < asset->aabbTreeCount; ++i)
{
std::memcpy(&iw4_clipmap->collisionAABBTrees[i].origin, &asset->aabbTrees[i].origin, 12);
std::memcpy(&iw4_clipmap->collisionAABBTrees[i].halfSize, &asset->aabbTrees[i].halfSize, 12);
iw4_clipmap->collisionAABBTrees[i].materialIndex = asset->aabbTrees[i].materialIndex;
iw4_clipmap->collisionAABBTrees[i].childCount = asset->aabbTrees[i].childCount;
iw4_clipmap->collisionAABBTrees[i].u.firstChildIndex = asset->aabbTrees[i].u.firstChildIndex;
}
// cmodels!
iw4_clipmap->numCModels = (int)asset->numSubModels;
iw4_clipmap->cModels = mem->Alloc<IW4::cmodel_t>(iw4_clipmap->numCModels);
for (unsigned int i = 0; i < asset->numSubModels; ++i)
{
std::memcpy(&iw4_clipmap->cModels[i], &asset->cmodels[i], sizeof(IW4::cmodel_t));
iw4_clipmap->cModels[i].bounds.compute();
iw4_clipmap->cModels[i].leaf.bounds.compute();
}
iw4_clipmap->numBrushes = (short)asset->numBrushes;
iw4_clipmap->brushes = mem->Alloc<IW4::cbrush_t>(iw4_clipmap->numBrushes);
iw4_clipmap->brushBounds = mem->Alloc<IW4::Bounds>(iw4_clipmap->numBrushes);
iw4_clipmap->brushContents = mem->Alloc<int>(iw4_clipmap->numBrushes);
for (unsigned int i = 0; i < asset->numBrushes; ++i)
{
std::memcpy(&iw4_clipmap->brushes[i].axialMaterialNum, &asset->brushes[i].axialMaterialNum,
sizeof(iw4_clipmap->brushes[i].axialMaterialNum));
std::memcpy(&iw4_clipmap->brushes[i].firstAdjacentSideOffsets,
&asset->brushes[i].firstAdjacentSideOffsets,
sizeof(iw4_clipmap->brushes[i].firstAdjacentSideOffsets));
std::memcpy(&iw4_clipmap->brushes[i].edgeCount, &asset->brushes[i].edgeCount,
sizeof(iw4_clipmap->brushes[i].edgeCount));
iw4_clipmap->brushes[i].numsides = asset->brushes[i].numsides;
iw4_clipmap->brushes[i].sides = mapped_brush_sides.find(asset->brushes[i].sides)->second;
iw4_clipmap->brushes[i].edge = asset->brushes[i].baseAdjacentSide;
iw4_clipmap->brushes[i].numsides = asset->brushes[i].numsides;
iw4_clipmap->brushBounds[i].compute(asset->brushes[i].mins, asset->brushes[i].maxs);
iw4_clipmap->brushContents[i] = asset->brushes[i].contents;
}
iw4_clipmap->smodelNodeCount = 1;
iw4_clipmap->smodelNodes = mem->Alloc<IW4::SModelAabbNode>();
if (asset->numStaticModels == 0)
{
iw4_clipmap->smodelNodes[0].bounds.halfSize[0] = -131072.000f;
iw4_clipmap->smodelNodes[0].bounds.halfSize[1] = -131072.000f;
iw4_clipmap->smodelNodes[0].bounds.halfSize[2] = -131072.000f;
}
else
{
float maxs[3];
float mins[3];
maxs[0] = asset->staticModelList[0].absmax[0];
maxs[1] = asset->staticModelList[1].absmax[1];
maxs[2] = asset->staticModelList[2].absmax[2];
mins[0] = asset->staticModelList[0].absmin[0];
mins[1] = asset->staticModelList[1].absmin[1];
mins[2] = asset->staticModelList[2].absmin[2];
for (unsigned int i = 1; i < asset->numStaticModels; i++)
{
maxs[0] = max(maxs[0], asset->staticModelList[i].absmax[0]);
maxs[1] = max(maxs[1], asset->staticModelList[i].absmax[1]);
maxs[2] = max(maxs[2], asset->staticModelList[i].absmax[2]);
mins[0] = min(mins[0], asset->staticModelList[i].absmin[0]);
mins[1] = min(mins[1], asset->staticModelList[i].absmin[1]);
mins[2] = min(mins[2], asset->staticModelList[i].absmin[2]);
}
iw4_clipmap->smodelNodes[0].bounds.compute(mins, maxs);
iw4_clipmap->smodelNodes[0].childCount = static_cast<short>(asset->numStaticModels);
iw4_clipmap->smodelNodes[0].firstChild = 0;
}
iw4_clipmap->mapEnts = mem->Alloc<IW4::MapEnts>(); // asset->mapEnts;
memcpy(iw4_clipmap->mapEnts, asset->mapEnts, sizeof MapEnts);
iw4_clipmap->mapEnts->stageCount = 1;
iw4_clipmap->mapEnts->stageNames = mem->Alloc<IW4::Stage>();
iw4_clipmap->mapEnts->stageNames[0].stageName = mem->StrDup("stage 0");
iw4_clipmap->mapEnts->stageNames[0].triggerIndex = 0x400;
iw4_clipmap->mapEnts->stageNames[0].sunPrimaryLightIndex = 0x1;
iw4_clipmap->dynEntCount[0] = asset->dynEntCount[0];
iw4_clipmap->dynEntCount[1] = asset->dynEntCount[1];
iw4_clipmap->dynEntDefList[0] = (IW4::DynEntityDef*)asset->dynEntDefList[0];
iw4_clipmap->dynEntDefList[1] = (IW4::DynEntityDef*)asset->dynEntDefList[1];
iw4_clipmap->dynEntPoseList[0] = (IW4::DynEntityPose*)asset->dynEntPoseList[0];
iw4_clipmap->dynEntPoseList[1] = (IW4::DynEntityPose*)asset->dynEntPoseList[1];
iw4_clipmap->dynEntClientList[0] = (IW4::DynEntityClient*)asset->dynEntClientList[0];
iw4_clipmap->dynEntClientList[1] = (IW4::DynEntityClient*)asset->dynEntClientList[1];
iw4_clipmap->dynEntCollList[0] = (IW4::DynEntityColl*)asset->dynEntCollList[0];
iw4_clipmap->dynEntCollList[1] = (IW4::DynEntityColl*)asset->dynEntCollList[1];
iw4_clipmap->checksum = asset->checksum;
//iw4_clipmap->stageCount = 1;
//iw4_clipmap-> = mem->Alloc<IW4::Stage>();
IW4::IClipMap::dump(iw4_clipmap);
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= ZoneTool =======================
// zonetool, a fastfile linker for various
// Call of Duty titles.
//
// Project: https://github.com/ZoneTool/zonetool
// Author: momo5502 (https://github.com/momo5502)
// License: GNU GPL v3.0
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IClipMap
{
public:
static void dump(clipMap_t* asset, ZoneMemory* mem);
};
}
}

View File

@ -0,0 +1,18 @@
// ======================= 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 "IW4/Assets/ComWorld.hpp"
namespace ZoneTool::IW3
{
void IComWorld::dump(ComWorld* asset, [[maybe_unused]] ZoneMemory* mem)
{
IW4::IComWorld::dump(reinterpret_cast<IW4::ComWorld*>(asset));
}
}

View File

@ -0,0 +1,18 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool::IW3
{
class IComWorld
{
public:
static void dump(ComWorld* asset, ZoneMemory* mem);
};
}

View File

@ -0,0 +1,54 @@
// ======================= 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 "IW4/Assets/FxEffectDef.hpp"
namespace ZoneTool
{
namespace IW3
{
void IFxEffectDef::dump(FxEffectDef* asset, ZoneMemory* mem)
{
const auto iw4_fx = mem->Alloc<IW4::FxEffectDef>();
memcpy(iw4_fx, asset, sizeof IW4::FxEffectDef);
const auto elem_count = iw4_fx->elemDefCountEmission + iw4_fx->elemDefCountOneShot + iw4_fx->elemDefCountLooping;
iw4_fx->elemDefs = mem->Alloc<IW4::FxElemDef>(elem_count);
for (auto i = 0; i < elem_count; i++)
{
memcpy(&iw4_fx->elemDefs[i], &asset->elemDefs[i], sizeof IW4::FxElemDef);
if (iw4_fx->elemDefs[i].elemType >= 5)
{
iw4_fx->elemDefs[i].elemType += 2;
}
iw4_fx->elemDefs[i].collBounds.compute(iw4_fx->elemDefs[i].collBounds.midPoint, iw4_fx->elemDefs[i].collBounds.halfSize);
if (iw4_fx->elemDefs[i].elemType == 3 && iw4_fx->elemDefs[i].extended.trailDef)
{
iw4_fx->elemDefs[i].extended.trailDef = mem->Alloc<IW4::FxTrailDef>();
iw4_fx->elemDefs[i].extended.trailDef->scrollTimeMsec = asset->elemDefs[i].trailDef->scrollTimeMsec;
iw4_fx->elemDefs[i].extended.trailDef->repeatDist = asset->elemDefs[i].trailDef->repeatDist;
iw4_fx->elemDefs[i].extended.trailDef->vertCount = asset->elemDefs[i].trailDef->vertCount;
iw4_fx->elemDefs[i].extended.trailDef->verts = reinterpret_cast<IW4::FxTrailVertex*>(asset->elemDefs[i].trailDef->verts);
iw4_fx->elemDefs[i].extended.trailDef->indCount = asset->elemDefs[i].trailDef->indCount;
iw4_fx->elemDefs[i].extended.trailDef->inds = asset->elemDefs[i].trailDef->inds;
}
else
{
iw4_fx->elemDefs[i].extended.trailDef = nullptr;
}
}
IW4::IFxEffectDef::dump(iw4_fx);
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IFxEffectDef
{
public:
static void dump(FxEffectDef* asset, ZoneMemory* mem);
};
}
}

View File

@ -0,0 +1,20 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW3
{
void IGameWorldMp::dump(GameWorldMp* asset)
{
// lol, GameWorldMp contains no data in IW3
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IGameWorldMp
{
public:
static void dump(GameWorldMp* asset);
};
}
}

View File

@ -0,0 +1,54 @@
// ======================= 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 "../IW4/Assets/GfxImage.hpp"
namespace ZoneTool
{
namespace IW3
{
IW4::GfxImage* IGfxImage::GenerateIW4Image(GfxImage* image, ZoneMemory* mem)
{
auto* iw4_image = mem->Alloc<IW4::GfxImage>();
// copy image data
iw4_image->mapType = image->mapType;
iw4_image->semantic = image->semantic;
iw4_image->category = image->category;
iw4_image->dataLen1 = image->cardMemory.platform[0];
iw4_image->dataLen2 = image->cardMemory.platform[1];
iw4_image->width = image->width;
iw4_image->height = image->height;
iw4_image->depth = image->depth;
iw4_image->pad = image->delayLoadPixels;
iw4_image->name = (char*)image->name;
// alloc texture
iw4_image->texture = (IW4::GfxImageLoadDef*)image->texture.loadDef;
return iw4_image;
}
void IGfxImage::dump(GfxImage* asset, ZoneMemory* mem)
{
if (!asset)
{
return;
}
ZONETOOL_INFO("dumping map image %s", asset->name);
// alloc IW4 image
auto* iw4_image = IGfxImage::GenerateIW4Image(asset, mem);
// dump IW4 image
IW4::IGfxImage::dump(iw4_image);
}
}
}

View File

@ -0,0 +1,22 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IGfxImage
{
public:
static IW4::GfxImage* GenerateIW4Image(GfxImage* image, ZoneMemory* mem);
static void dump(GfxImage* asset, ZoneMemory* mem);
};
}
}

353
src/IW3/Assets/GfxWorld.cpp Normal file
View File

@ -0,0 +1,353 @@
// ======================= 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 "../IW4/Assets/GfxWorld.hpp"
namespace ZoneTool
{
namespace IW3
{
void IGfxWorld::dump(GfxWorld* world, ZoneMemory* mem)
{
if (!world) return;
IW4::GfxSky sky;
IW4::GfxWorld map;
ZeroMemory(&sky, sizeof(sky));
ZeroMemory(&map, sizeof(map));
map.name = world->name;
map.baseName = world->baseName;
map.planeCount = world->planeCount;
map.nodeCount = world->nodeCount;
map.surfaceCount = world->surfaceCount;
map.skyCount = 1;
map.skies = &sky;
sky.skyImage = (IW4::GfxImage*)world->skyImage;
sky.skySamplerState = world->skySamplerState & 0xFF;
sky.skyStartSurfs = (uint32_t*)world->skyStartSurfs;
sky.skySurfCount = world->skySurfCount;
map.sunPrimaryLightIndex = world->sunPrimaryLightIndex;
map.primaryLightCount = world->primaryLightCount;
// map.dpvsPlanes = world->dpvsPlanes;
memcpy(&map.dpvsPlanes, &world->dpvsPlanes, sizeof world->dpvsPlanes);
// AABBTree data is stored as part of the cells.
// However, in IW4 it's not, so we have to extract the data
if (world->cells)
{
map.aabbTreeCounts = mem->Alloc<IW4::GfxCellTreeCount>(world->dpvsPlanes.cellCount);
map.aabbTree = mem->Alloc<IW4::GfxCellTree>(world->dpvsPlanes.cellCount);
map.cells = mem->Alloc<IW4::GfxCell>(world->dpvsPlanes.cellCount);
for (int i = 0; i < world->dpvsPlanes.cellCount; ++i)
{
map.aabbTreeCounts[i].aabbTreeCount = world->cells[i].aabbTreeCount;
map.cells[i].bounds.compute(world->cells[i].mins, world->cells[i].maxs); // Verified
map.cells[i].portalCount = world->cells[i].portalCount;
map.cells[i].reflectionProbeCount = world->cells[i].reflectionProbeCount;
map.cells[i].reflectionProbes = world->cells[i].reflectionProbes;
if (world->cells[i].aabbTree)
{
map.aabbTree[i].aabbtree = mem->Alloc<IW4::GfxAabbTree>(world->cells[i].aabbTreeCount);
std::memcpy(map.aabbTree[i].aabbtree, world->cells[i].aabbTree, sizeof(IW4::GfxAabbTree) * world->cells[i].aabbTreeCount);
for (int j = 0; j < world->cells[i].aabbTreeCount; ++j)
{
static_assert(sizeof IW4::GfxAabbTree == sizeof IW3::GfxAabbTree, "Size mismatch");
map.aabbTree[i].aabbtree[j].bounds.compute(world->cells[i].aabbTree[j].mins, world->cells[i].aabbTree[j].maxs); // Verified
}
}
if (world->cells[i].portals)
{
map.cells[i].portals = mem->Alloc<IW4::GfxPortal>(world->cells[i].portalCount);
// Map all portals, so we have them ready for the next loop (might be unnecessary, as they are mapped at runtime)
std::unordered_map<IW3::GfxPortal*, IW4::GfxPortal*> portalMap = { { nullptr, nullptr } };
for (int j = 0; j < world->cells[i].portalCount; ++j)
{
portalMap[&world->cells[i].portals[j]] = &map.cells[i].portals[j];
}
for (int j = 0; j < world->cells[i].portalCount; ++j)
{
IW3::GfxPortal* portal = &world->cells[i].portals[j];
IW4::GfxPortal* destPortal = &map.cells[i].portals[j];
destPortal->cellIndex = static_cast<unsigned short>(portal->cell - world->cells);
if (destPortal->cellIndex >= static_cast<unsigned short>(world->dpvsPlanes.cellCount))
{
ZONETOOL_FATAL("Unable to calculate cell index. This should not happen!\n");
destPortal->cellIndex = 0;
}
destPortal->vertices = portal->vertices;
destPortal->vertexCount = portal->vertexCount;
destPortal->writable.isQueued = portal->writable.isQueued;
destPortal->writable.isAncestor = portal->writable.isAncestor;
destPortal->writable.recursionDepth = portal->writable.recursionDepth;
destPortal->writable.hullPointCount = portal->writable.hullPointCount;
destPortal->writable.hullPoints = portal->writable.hullPoints;
if (portalMap.find(portal->writable.queuedParent) != portalMap.end())
{
destPortal->writable.queuedParent = portalMap[portal->writable.queuedParent];
}
else
{
if (portal->writable.queuedParent) ZONETOOL_ERROR("Unmapped portal. This shouldn't happen. Nulling it...\n");
destPortal->writable.queuedParent = nullptr;
}
std::memcpy(destPortal->plane.coeffs, portal->plane.coeffs, sizeof(destPortal->plane.coeffs));
std::memcpy(destPortal->hullAxis, portal->hullAxis, sizeof(destPortal->hullAxis));
}
}
}
}
map.draw.reflectionProbeCount = world->reflectionProbeCount;
map.draw.reflectionProbeTextures = (IW4::GfxTexture*)world->reflectionProbeTextures;
map.draw.lightmapCount = world->lightmapCount;
map.draw.lightmaps = mem->Alloc<IW4::GfxLightmapArray>(world->lightmapCount); // (IW4::GfxLightmapArray*)world->lightmaps;
for (auto i = 0; i < world->lightmapCount; i++)
{
if (world->lightmaps[i].primary)
{
IGfxImage::dump(world->lightmaps[i].primary, mem);
map.draw.lightmaps[i].primary = IGfxImage::GenerateIW4Image(world->lightmaps[i].primary, mem);
}
if (world->lightmaps[i].secondary)
{
IGfxImage::dump(world->lightmaps[i].secondary, mem);
map.draw.lightmaps[i].secondary = IGfxImage::GenerateIW4Image(world->lightmaps[i].secondary, mem);
}
}
map.draw.lightmapPrimaryTextures = (IW4::GfxTexture*)world->lightmapPrimaryTextures;
map.draw.lightmapSecondaryTextures = (IW4::GfxTexture*)world->lightmapSecondaryTextures;
map.draw.skyImage = IGfxImage::GenerateIW4Image(world->skyImage, mem);
map.draw.outdoorImage = IGfxImage::GenerateIW4Image(world->outdoorImage, mem);
map.draw.vertexCount = world->vertexCount;
memcpy(&map.draw.vd, &world->vd, sizeof world->vd);
map.draw.vertexLayerDataSize = world->vertexLayerDataSize;
memcpy(&map.draw.vld, &world->vld, sizeof world->vld);
map.draw.indexCount = world->indexCount;
// Split reflection images and probes
if (world->reflectionProbes)
{
map.draw.reflectionImages = mem->Alloc<IW4::GfxImage*>(world->reflectionProbeCount);
map.draw.reflectionProbes = mem->Alloc<IW4::GfxReflectionProbe>(world->reflectionProbeCount);
for (unsigned int i = 0; i < world->reflectionProbeCount; ++i)
{
map.draw.reflectionImages[i] = IGfxImage::GenerateIW4Image(world->reflectionProbes[i].reflectionImage, mem);
IGfxImage::dump(world->reflectionProbes[i].reflectionImage, mem);
std::memcpy(map.draw.reflectionProbes[i].offset, world->reflectionProbes[i].origin, sizeof(map.draw.reflectionProbes[i].offset));
}
}
memcpy(&map.lightGrid, &world->lightGrid, sizeof world->lightGrid);
assert(sizeof IW3::GfxBrushModel == 56);
assert(sizeof IW4::GfxBrushModel == 60);
map.bounds.compute(world->mins, world->maxs);
map.checksum = world->checksum;
map.materialMemoryCount = world->materialMemoryCount;
map.materialMemory = (IW4::MaterialMemory*)world->materialMemory;
memcpy(&map.sun, &world->sun, sizeof world->sun);
std::memcpy(map.outdoorLookupMatrix, world->outdoorLookupMatrix, sizeof(map.outdoorLookupMatrix));
map.outdoorImage = map.draw.outdoorImage; // (IW4::GfxImage*)world->outdoorImage;
IGfxImage::dump(world->outdoorImage, mem);
map.cellCasterBits[0] = world->cellCasterBits;
map.cellCasterBits[1] = world->cellCasterBits; // This mustn't be null!
map.sceneDynModel = (IW4::GfxSceneDynModel*)world->sceneDynModel;
map.sceneDynBrush = (IW4::GfxSceneDynBrush*)world->sceneDynBrush;
map.primaryLightEntityShadowVis = (unsigned char*)world->primaryLightEntityShadowVis;
map.primaryLightDynEntShadowVis[0] = world->primaryLightDynEntShadowVis[0];
map.primaryLightDynEntShadowVis[1] = world->primaryLightDynEntShadowVis[1];
map.primaryLightForModelDynEnt = world->nonSunPrimaryLightForModelDynEnt;
map.shadowGeom = (IW4::GfxShadowGeometry*)world->shadowGeom;
map.lightRegion = (IW4::GfxLightRegion*)world->lightRegion;
map.dpvs.smodelCount = world->dpvs.smodelCount;
map.dpvs.staticSurfaceCount = world->dpvs.staticSurfaceCount;
map.dpvs.staticSurfaceCountNoDecal = world->dpvs.staticSurfaceCountNoDecal;
// Not sure if correct
// update: slightly more sure but not much lol
map.dpvs.litOpaqueSurfsBegin = world->dpvs.litSurfsBegin;
map.dpvs.litOpaqueSurfsEnd = world->dpvs.decalSurfsEnd;
// these don't exist in iw3 so skip
map.dpvs.litTransSurfsBegin = world->dpvs.decalSurfsEnd;
map.dpvs.litTransSurfsEnd = world->dpvs.decalSurfsEnd;
// Skip those as well
map.dpvs.shadowCasterSurfsBegin = world->dpvs.decalSurfsEnd;
map.dpvs.shadowCasterSurfsEnd = world->dpvs.decalSurfsEnd;
map.dpvs.emissiveSurfsBegin = world->dpvs.emissiveSurfsBegin;
map.dpvs.emissiveSurfsEnd = world->dpvs.emissiveSurfsEnd;
map.dpvs.smodelVisDataCount = world->dpvs.smodelVisDataCount;
map.dpvs.surfaceVisDataCount = world->dpvs.surfaceVisDataCount;
std::memcpy(map.dpvs.smodelVisData, world->dpvs.smodelVisData, sizeof(map.dpvs.smodelVisData));
std::memcpy(map.dpvs.surfaceVisData, world->dpvs.surfaceVisData, sizeof(map.dpvs.surfaceVisData));
map.dpvs.sortedSurfIndex = world->dpvs.sortedSurfIndex;
if (world->dpvs.smodelInsts)
{
map.dpvs.smodelInsts = mem->Alloc<IW4::GfxStaticModelInst>(world->dpvs.smodelCount);
for (unsigned int i = 0; i < world->dpvs.smodelCount; ++i)
{
map.dpvs.smodelInsts[i].bounds.compute(world->dpvs.smodelInsts[i].mins, world->dpvs.smodelInsts[i].maxs); // Verified
// I guess the sun is always a good lighting source ;)
map.dpvs.smodelInsts[i].lightingOrigin[0] = world->sun.sunFxPosition[0];
map.dpvs.smodelInsts[i].lightingOrigin[1] = world->sun.sunFxPosition[1];
map.dpvs.smodelInsts[i].lightingOrigin[2] = world->sun.sunFxPosition[2];
}
}
if (world->dpvs.surfaces)
{
map.dpvs.surfaces = mem->Alloc<IW4::GfxSurface>(world->surfaceCount);
map.dpvs.surfacesBounds = mem->Alloc<IW4::GfxCullGroup>(world->surfaceCount);
assert(sizeof(IW3::srfTriangles_t) == sizeof(IW4::srfTriangles_t));
for (auto i = 0; i < world->surfaceCount; ++i)
{
std::memcpy(&map.dpvs.surfaces[i].tris, &world->dpvs.surfaces[i].tris, sizeof(IW4::srfTriangles_t));
map.dpvs.surfaces[i].material = (IW4::Material*)world->dpvs.surfaces[i].material;
map.dpvs.surfaces[i].lightmapIndex = world->dpvs.surfaces[i].lightmapIndex;
map.dpvs.surfaces[i].reflectionProbeIndex = world->dpvs.surfaces[i].reflectionProbeIndex;
map.dpvs.surfaces[i].primaryLightIndex = world->dpvs.surfaces[i].primaryLightIndex;
map.dpvs.surfaces[i].flags = world->dpvs.surfaces[i].flags;
map.dpvs.surfacesBounds[i].bounds.compute(world->dpvs.surfaces[i].bounds[0], world->dpvs.surfaces[i].bounds[1]); // Verified
assert(map.dpvs.surfaces[i].material != nullptr);
}
}
if (world->dpvs.smodelDrawInsts)
{
map.dpvs.smodelDrawInsts = mem->Alloc<IW4::GfxStaticModelDrawInst>(world->dpvs.smodelCount);
for (unsigned int i = 0; i < world->dpvs.smodelCount; ++i)
{
std::memcpy(&map.dpvs.smodelDrawInsts[i].placement, &world->dpvs.smodelDrawInsts[i].placement, sizeof(GfxPackedPlacement));
std::memcpy(map.dpvs.smodelDrawInsts[i].cacheId, world->dpvs.smodelDrawInsts[i].smodelCacheIndex, sizeof(map.dpvs.smodelDrawInsts[i].cacheId));
map.dpvs.smodelDrawInsts[i].model = (IW4::XModel*)world->dpvs.smodelDrawInsts[i].model;
map.dpvs.smodelDrawInsts[i].cullDist = static_cast<unsigned short>(world->dpvs.smodelDrawInsts[i].cullDist);
map.dpvs.smodelDrawInsts[i].reflectionProbeIndex = world->dpvs.smodelDrawInsts[i].reflectionProbeIndex;
map.dpvs.smodelDrawInsts[i].primaryLightIndex = world->dpvs.smodelDrawInsts[i].primaryLightIndex;
map.dpvs.smodelDrawInsts[i].lightingHandle = world->dpvs.smodelDrawInsts[i].lightingHandle;
map.dpvs.smodelDrawInsts[i].flags = world->dpvs.smodelDrawInsts[i].flags;
// This has been moved
if (world->dpvs.smodelInsts) map.dpvs.smodelDrawInsts[i].groundLighting.packed = world->dpvs.smodelInsts[i].groundLighting.packed;
}
}
map.dpvs.surfaceMaterials = (IW4::GfxDrawSurf*)world->dpvs.surfaceMaterials;
map.dpvs.surfaceCastsSunShadow = world->dpvs.surfaceCastsSunShadow;
map.dpvs.usageCount = world->dpvs.usageCount;
memcpy(&map.dpvsDyn, &world->dpvsDyn, sizeof world->dpvsDyn);
// Should we set that to true? :O
map.fogTypesAllowed = 3; // iw4_credits has 0x3
map.sortKeyLitDecal = 0x6;
map.sortKeyEffectDecal = 0x27;
map.sortKeyEffectAuto = 0x30;
map.sortKeyDistortion = 0x2b;
// sort models
map.modelCount = world->modelCount;
if (world->models)
{
map.models = mem->Alloc<IW4::GfxBrushModel>(world->modelCount);
std::vector<IW4::GfxBrushModel> models;
models.resize(world->modelCount);
for (auto i = 0; i < world->modelCount; ++i)
{
models[i].writable.bounds.compute(world->models[i].writable.mins, world->models[i].writable.maxs); // Irrelevant, runtime data
models[i].bounds.compute(world->models[i].bounds[0], world->models[i].bounds[1]); // Verified
auto* half_size = models[i].bounds.halfSize;
models[i].radius = std::sqrt(std::pow(half_size[0], 2) + std::pow(half_size[1], 2) + std::pow(half_size[2], 2));
models[i].surfaceCount = world->models[i].surfaceCount;
models[i].startSurfIndex = world->models[i].startSurfIndex;
models[i].surfaceCountNoDecal = world->models[i].surfaceCountNoDecal;
}
std::sort(models.begin(), models.end(), [](const IW4::GfxBrushModel& m1, const IW4::GfxBrushModel& m2)
{
return m1.startSurfIndex > m2.startSurfIndex;
});
std::memcpy(map.models, models.data(), sizeof(IW4::GfxBrushModel) * world->modelCount);
}
// sort triangles & vertices
auto tri_index = 0;
map.draw.indices = mem->Alloc<unsigned short>(map.draw.indexCount);
for (auto i = 0; i < map.surfaceCount; i++)
{
auto* surface = &map.dpvs.surfaces[i];
// triangles
std::memcpy(&map.draw.indices[tri_index], &world->indices[surface->tris.baseIndex], surface->tris.triCount * 6);
surface->tris.baseIndex = tri_index;
tri_index += surface->tris.triCount * 3;
}
if (tri_index != map.draw.indexCount)
{
ZONETOOL_WARNING("Warning: Didn't sort all indicies for draw");
}
// Specify that it's a custom map
map.checksum = 0xDEADBEEF;
IW4::IGfxWorld::dump(&map);
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IGfxWorld
{
public:
static void dump(GfxWorld* asset, ZoneMemory* mem);
};
}
}

View File

@ -0,0 +1,92 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW3
{
void ILoadedSound::dump(LoadedSound* asset, ZoneMemory* mem)
{
if (asset->struct1.waveFormat != 1)
{
ZONETOOL_ERROR("Audio format other than PCM currently not supported. Sound: %s\n", asset->name);
return;
}
const auto fp = FileSystem::FileOpen("loaded_sound\\"s + asset->name, "wb");
if (!fp)
{
return;
}
// --- RIF HEADER
// ChunkID
char chunkID[] = { 'R', 'I', 'F', 'F' };
fwrite(chunkID, 4, 1, fp);
// ChunkSize
int subchunk1Size = 16;
int subchunk2Size = asset->struct1.dataLength;
int chunkSize = 4 + (8 + subchunk1Size) + (8 + subchunk2Size);
fwrite(&chunkSize, 4, 1, fp);
// Format
char format[] = { 'W', 'A', 'V', 'E' };
fwrite(format, 4, 1, fp);
// --- FMT SUBCHUNK
// Subchunk1ID
char subchunk1ID[] = { 'f', 'm', 't', ' ' };
fwrite(subchunk1ID, 4, 1, fp);
// Subchunk1Size
fwrite(&subchunk1Size, 4, 1, fp);
// AudioFormat
short audioFormat = asset->struct1.waveFormat;
fwrite(&audioFormat, 2, 1, fp);
// NumChannels
short numChannels = asset->struct1.channelCount;
fwrite(&numChannels, 2, 1, fp);
// SampleRate
int sampleRate = asset->struct1.sampleRate;
fwrite(&sampleRate, 4, 1, fp);
// ByteRate
int byteRate = asset->struct1.sampleRate * asset->struct1.channelCount * asset->struct1.bitPerChannel / 8;
fwrite(&byteRate, 4, 1, fp);
// BlockAlign
short blockAlign = asset->struct1.blockAlign;
fwrite(&blockAlign, 2, 1, fp);
// BitsPerSample
short bitsPerSample = asset->struct1.bitPerChannel;
fwrite(&bitsPerSample, 2, 1, fp);
// --- DATA SUBCHUNK
// Subchunk2ID
char subchunk2ID[] = { 'd', 'a', 't', 'a' };
fwrite(subchunk2ID, 4, 1, fp);
// Subchunk2Size
fwrite(&subchunk2Size, 4, 1, fp);
// Data
fwrite(asset->struct1.soundData, asset->struct1.dataLength, 1, fp);
FileSystem::FileClose(fp);
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class ILoadedSound
{
public:
static void dump(LoadedSound* asset, ZoneMemory* mem);
};
}
}

261
src/IW3/Assets/MapEnts.cpp Normal file
View File

@ -0,0 +1,261 @@
// ======================= ZoneTool =======================
// zonetool, a fastfile linker for various
// Call of Duty titles.
//
// Project: https://github.com/ZoneTool/zonetool
// Author: momo5502 (https://github.com/momo5502)
// License: GNU GPL v3.0
// ========================================================
#include "stdafx.hpp"
#include "../IW4/Assets/MapEnts.hpp"
#include "MapEnts.hpp"
namespace ZoneTool
{
namespace IW3
{
bool StartsWith(const std::string& haystack, const std::string& needle)
{
return (haystack.size() >= needle.size() && !strncmp(needle.data(), haystack.data(), needle.size()));
}
std::string StrToLower(std::string input)
{
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
return input;
}
class Entities
{
public:
Entities()
{
};
Entities(const char* string, size_t lenPlusOne) : Entities(std::string(string, lenPlusOne - 1))
{
}
Entities(std::string buffer) : Entities() { this->parse(buffer); };
Entities(const Entities& obj) : entities(obj.entities)
{
};
std::string build()
{
std::string entityString;
for (auto& entity : this->entities)
{
entityString.append("{\n");
for (auto& property : entity)
{
entityString.push_back('"');
entityString.append(property.first);
entityString.append("\" \"");
entityString.append(property.second);
entityString.append("\"\n");
}
entityString.append("}\n");
}
return entityString;
}
std::vector<std::string> getModels()
{
std::vector<std::string> models;
for (auto& entity : this->entities)
{
if (entity.find("model") != entity.end())
{
std::string model = entity["model"];
if (!model.empty() && model[0] != '*' && model[0] != '?') // Skip brushmodels
{
if (std::find(models.begin(), models.end(), model) == models.end())
{
models.push_back(model);
}
}
}
}
return models;
}
void deleteTriggers()
{
for (auto i = this->entities.begin(); i != this->entities.end();)
{
if (i->find("classname") != i->end())
{
std::string classname = (*i)["classname"];
if (StartsWith(classname, "trigger_"))
{
i = this->entities.erase(i);
continue;
}
}
++i;
}
}
void deleteWeapons(bool keepTurrets)
{
for (auto i = this->entities.begin(); i != this->entities.end();)
{
if (i->find("weaponinfo") != i->end() || (i->find("targetname") != i->end() && (*i)["targetname"] ==
"oldschool_pickup"s))
{
if (!keepTurrets || i->find("classname") == i->end() || (*i)["classname"] != "misc_turret"s)
{
i = this->entities.erase(i);
continue;
}
}
++i;
}
}
void convertTurrets()
{
for (auto& entity : this->entities)
{
if (entity.find("classname") != entity.end())
{
if (entity["classname"] == "misc_turret"s)
{
entity["weaponinfo"] = "turret_minigun_mp";
entity["model"] = "weapon_minigun";
}
}
}
}
private:
enum
{
PARSE_AWAIT_KEY,
PARSE_READ_KEY,
PARSE_AWAIT_VALUE,
PARSE_READ_VALUE,
};
std::vector<std::unordered_map<std::string, std::string>> entities;
void parse(std::string buffer)
{
int parseState = 0;
std::string key;
std::string value;
std::unordered_map<std::string, std::string> entity;
for (unsigned int i = 0; i < buffer.size(); ++i)
{
const char character = buffer[i];
if (character == '{')
{
entity.clear();
}
switch (character)
{
case '{':
{
entity.clear();
break;
}
case '}':
{
this->entities.push_back(entity);
entity.clear();
break;
}
case '"':
{
if (parseState == PARSE_AWAIT_KEY)
{
key.clear();
parseState = PARSE_READ_KEY;
}
else if (parseState == PARSE_READ_KEY)
{
parseState = PARSE_AWAIT_VALUE;
}
else if (parseState == PARSE_AWAIT_VALUE)
{
value.clear();
parseState = PARSE_READ_VALUE;
}
else if (parseState == PARSE_READ_VALUE)
{
entity[StrToLower(key)] = value;
parseState = PARSE_AWAIT_KEY;
}
else
{
throw std::runtime_error("Parsing error!");
}
break;
}
default:
{
if (parseState == PARSE_READ_KEY) key.push_back(character);
else if (parseState == PARSE_READ_VALUE) value.push_back(character);
break;
}
}
}
}
};
void AdaptEntities(IW4::MapEnts* ents, ZoneMemory* mem)
{
std::string entString(ents->entityString, ents->numEntityChars - 1);
Entities mapEnts(entString);
mapEnts.deleteTriggers();
mapEnts.deleteWeapons(/*true*/false); // For now delete turrets, as we can't write weapons
mapEnts.convertTurrets();
entString = mapEnts.build();
ents->numEntityChars = entString.size() + 1;
ents->entityString = mem->Alloc<char>(ents->numEntityChars);
std::memcpy((char*)ents->entityString, entString.data(), ents->numEntityChars);
}
void IMapEnts::dump(MapEnts* asset, ZoneMemory* mem)
{
if (!asset) return;
auto* mapents = mem->Alloc<IW4::MapEnts>();
memset(mapents, 0, sizeof IW4::MapEnts);
mapents->name = asset->name;
mapents->entityString = asset->entityString;
mapents->numEntityChars = asset->numEntityChars;
mapents->stageCount = 1;
mapents->stageNames = mem->Alloc<IW4::Stage>();
mapents->stageNames[0].stageName = mem->StrDup("stage 0");
mapents->stageNames[0].triggerIndex = 0x400;
mapents->stageNames[0].sunPrimaryLightIndex = 0x1;
// Remove unsupported stuff
AdaptEntities(mapents, mem);
IW4::IMapEnts::dump(mapents);
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= ZoneTool =======================
// zonetool, a fastfile linker for various
// Call of Duty titles.
//
// Project: https://github.com/ZoneTool/zonetool
// Author: momo5502 (https://github.com/momo5502)
// License: GNU GPL v3.0
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IMapEnts
{
public:
static void dump(MapEnts* asset, ZoneMemory* mem);
};
}
}

249
src/IW3/Assets/Material.cpp Normal file
View File

@ -0,0 +1,249 @@
// ======================= 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"
// Material parsing
#define MATERIAL_INT(entry) \
mat->entry = matdata[#entry].get<int>();
#define MATERIAL_DUMP_INT(entry) \
matdata[#entry] = mat->entry;
#define MATERIAL_DUMP_STRING(entry) \
matdata[#entry] = std::string(mat->entry);
#define MATERIAL_DUMP_MATIMG_ARRAY(entry,size) \
nlohmann::json matimg##entry; \
for (int i = 0; i < size; i++) \
{ \
nlohmann::json img##entry; \
img##entry["image"] = mat->entry[i].image->name; \
img##entry["semantic"] = (int)mat->entry[i].semantic; \
img##entry["sampleState"] = (int)mat->entry[i].sampleState; \
img##entry["lastCharacter"] = (char)mat->entry[i].secondLastCharacter; \
img##entry["firstCharacter"] = (char)mat->entry[i].firstCharacter; \
img##entry["typeHash"] = (unsigned int)mat->entry[i].typeHash; \
matimg##entry[i] = img##entry; \
} \
matdata[#entry] = matimg##entry;
#define MATERIAL_DUMP_CONST_ARRAY(entry,size) \
nlohmann::json carr##entry; \
for (int i = 0; i < size; i++) \
{ \
nlohmann::json cent##entry; \
cent##entry["name"] = mat->entry[i].name; \
nlohmann::json centliteral##entry; \
centliteral##entry[0] = mat->entry[i].literal[0]; \
centliteral##entry[1] = mat->entry[i].literal[1]; \
centliteral##entry[2] = mat->entry[i].literal[2]; \
centliteral##entry[3] = mat->entry[i].literal[3]; \
cent##entry["nameHash"] = mat->entry[i].nameHash; \
cent##entry["literal"] = centliteral##entry; \
carr##entry[i] = cent##entry; \
} \
matdata[#entry] = carr##entry;
#define MATERIAL_DUMP_STATE_MAP(entry,size) \
nlohmann::json carr##entry; \
for (int i = 0; i < size; i++) \
{ \
nlohmann::json cent##entry; \
cent##entry[0] = mat->entry[i].loadBits[0]; \
cent##entry[1] = mat->entry[i].loadBits[1]; \
carr##entry[i] = cent##entry; \
} \
matdata[#entry] = carr##entry;
#define MATERIAL_DUMP_BITS_ENTRY(entry,size) \
nlohmann::json carr##entry; \
for (int i = 0; i < size; i++) \
{ \
carr##entry[i] = mat->entry[i]; \
} \
matdata[#entry] = carr##entry;
namespace ZoneTool
{
namespace IW3
{
void IMaterial::dump_statebits(Material* mat)
{
if (mat && mat->techniqueSet)
{
ITechset::dump_statebits(va("iw3/%s", mat->techniqueSet->name), mat->stateBitsEntry);
}
}
//std::map<std::uint32_t, std::uint32_t> mapped_keys
//{
// { 0, 43 },
// { 3, 0 },
// { 4, 1 },
// { 5, 2 },
// { 6, 3 },
// { 7, 4 },
// { 8, 5 },
// { 9, 6 },
// { 10, 7 },
// { 11, 8 },
// { 12, 9 },
// { 24, 13 },
// { 38, 24 },
// { 39, 25 },
// { 40, 26 },
// { 41, 27 },
// { 42, 28 },
// { 43, 29 },
// { 48, 48 },
// { 58, 51 },
// { 59, 33 },
//};
std::map<std::uint32_t, std::uint32_t> mapped_keys
{
{ 0, 43 },
{ 3, 0 },
{ 4, 1 },
{ 5, 2 },
{ 9, 6 }, // not sure!
{ 10, 7 },
{ 11, 8 }, // not sure!
{ 12, 0 },
{ 24, 9 },
{ 38, 28 }, // not sure!
{ 39, 29 },
{ 43, 29 }, // was 47 but that crashes, not sure!
{ 48, 48 },
{ 59, 53 },
};
void IMaterial::dump(Material* mat, ZoneMemory* mem)
{
if (mat)
{
dump_statebits(mat);
auto path = "materials\\"s + mat->name;
auto file = FileSystem::FileOpen(path, "wb");
if (!file)
{
return;
}
nlohmann::json matdata;
MATERIAL_DUMP_STRING(name);
if (mat->techniqueSet)
{
matdata["techniqueSet->name"] = va("iw3/%s", mat->techniqueSet->name);
}
MATERIAL_DUMP_INT(gameFlags);
// MATERIAL_DUMP_INT(sortKey);
MATERIAL_DUMP_INT(animationX);
MATERIAL_DUMP_INT(animationY);
auto key_itr = mapped_keys.find(mat->sortKey);
if (key_itr != mapped_keys.end())
{
matdata["sortKey"] = key_itr->second;
}
else
{
matdata["sortKey"] = mat->sortKey;
ZONETOOL_WARNING("[%s]: sortKey %u is not mapped!", mat->name, mat->sortKey);
}
matdata["unknown"] = 0;
MATERIAL_DUMP_INT(surfaceTypeBits);
MATERIAL_DUMP_INT(stateFlags);
MATERIAL_DUMP_INT(cameraRegion);
MATERIAL_DUMP_CONST_ARRAY(constantTable, mat->constantCount);
MATERIAL_DUMP_STATE_MAP(stateMap, mat->stateBitsCount);
nlohmann::json material_images;
for (int i = 0; i < mat->numMaps; i++)
{
nlohmann::json image;
// watermap
if (mat->maps[i].semantic == 11)
{
water_t* waterData = reinterpret_cast<water_t*>(mat->maps[i].image);
image["image"] = waterData->image->name;
nlohmann::json waterdata;
waterdata["floatTime"] = waterData->writable.floatTime;
waterdata["codeConstant"][0] = waterData->codeConstant[0];
waterdata["codeConstant"][1] = waterData->codeConstant[1];
waterdata["codeConstant"][2] = waterData->codeConstant[2];
waterdata["codeConstant"][3] = waterData->codeConstant[3];
waterdata["M"] = waterData->M;
waterdata["N"] = waterData->N;
waterdata["Lx"] = waterData->Lx;
waterdata["Lz"] = waterData->Lz;
waterdata["gravity"] = waterData->gravity;
waterdata["windvel"] = waterData->windvel;
waterdata["winddir"][0] = waterData->winddir[0];
waterdata["winddir"][1] = waterData->winddir[1];
waterdata["amplitude"] = waterData->amplitude;
nlohmann::json waterComplexData;
nlohmann::json wTerm;
for (int i = 0; i < waterData->M * waterData->N; i++)
{
nlohmann::json complexdata;
nlohmann::json curWTerm;
complexdata["real"] = waterData->H0[i].real;
complexdata["imag"] = waterData->H0[i].imag;
curWTerm[i] = waterData->wTerm[i];
waterComplexData[i] = complexdata;
}
waterdata["complex"] = waterComplexData;
waterdata["wTerm"] = wTerm;
image["waterinfo"] = waterdata;
}
else
{
image["image"] = mat->maps[i].image->name;
}
image["semantic"] = mat->maps[i].semantic;
image["sampleState"] = mat->maps[i].sampleState;
image["lastCharacter"] = mat->maps[i].secondLastCharacter;
image["firstCharacter"] = mat->maps[i].firstCharacter;
image["typeHash"] = mat->maps[i].typeHash;
// add image data to material
material_images[i] = image;
}
matdata["maps"] = material_images;
auto assetData = matdata.dump(4);
// write data to disk
fwrite(&assetData[0], assetData.size(), 1, file);
FileSystem::FileClose(file);
}
}
}
}

View File

@ -0,0 +1,22 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IMaterial
{
public:
static void dump(Material* asset, ZoneMemory* mem);
static void dump_statebits(Material* mat);
};
}
}

34
src/IW3/Assets/Sound.cpp Normal file
View File

@ -0,0 +1,34 @@
// ======================= 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 "IW4/Assets/Sound.hpp"
namespace ZoneTool
{
namespace IW3
{
void ISound::dump(snd_alias_list_t* asset, ZoneMemory* mem)
{
const auto iw4_asset = mem->Alloc<IW4::snd_alias_list_t>(); // new IW4::snd_alias_list_t;
memcpy(iw4_asset, asset, sizeof snd_alias_list_t);
iw4_asset->head = mem->Alloc<IW4::snd_alias_t>(iw4_asset->count);
memset(iw4_asset->head, 0, sizeof IW4::snd_alias_t * iw4_asset->count);
for (auto i = 0; i < asset->count; i++)
{
memcpy(&iw4_asset->head[i], &asset->head[i], 16);
memcpy(&iw4_asset->head[i].soundFile, &asset->head[i].soundFile, sizeof snd_alias_t - 16 - 20);
memcpy(&iw4_asset->head[i].volumeFalloffCurve, &asset->head[i].volumeFalloffCurve, 20);
}
IW4::ISound::dump(iw4_asset);
}
}
}

21
src/IW3/Assets/Sound.hpp Normal file
View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class ISound
{
public:
static void dump(snd_alias_list_t* asset, ZoneMemory* mem);
};
}
}

449
src/IW3/Assets/Techset.cpp Normal file
View File

@ -0,0 +1,449 @@
// ======================= 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 "../IW4/Assets/VertexDecl.hpp"
#include "../IW4/Assets/VertexShader.hpp"
#include "../IW4/Assets/PixelShader.hpp"
#include "IW4/Assets/Techset.hpp"
static const unsigned int crcTable[] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
std::uint32_t Crc32(void* buffer, const std::size_t size, const std::uint32_t initialCrc)
{
auto curPtr = reinterpret_cast<std::uint8_t*>(buffer);
auto remaining = size;
auto crc = ~initialCrc;
for (; remaining--; ++curPtr)
{
crc = (crc >> 8) ^ crcTable[(crc ^ *curPtr) & 0xFF];
}
return (~crc);
}
namespace ZoneTool
{
namespace IW3
{
std::string GenerateNameForVertexDecl(MaterialVertexDeclaration* vertexDecl)
{
// base name + crc32
auto name = "iw3_vertexdecl_"s;
auto crc32 = Crc32(vertexDecl->routing.data, sizeof MaterialVertexDeclaration, 0);
// append crc32 to vertexdecl name
name += std::to_string(crc32);
// return generated name
return name;
}
IW4::VertexDecl* ITechset::dump_vertex_decl(const std::string& name, MaterialVertexDeclaration* vertex, ZoneMemory* mem)
{
// convert to IW4
auto* asset = mem->Alloc<IW4::VertexDecl>();
asset->name = mem->StrDup(va("iw3/%s", name.data()));
asset->hasOptionalSource = vertex->hasOptionalSource;
asset->streamCount = vertex->streamCount;
memcpy(asset->streams, vertex->routing.data, sizeof asset->streams);
memcpy(asset->declarations, vertex->routing.decl, sizeof(void*) * 16);
for (auto i = 0; i < asset->streamCount; i++)
{
if (asset->streams[i].dest >= 4)
{
asset->streams[i].dest += 1;
}
}
// shit out a warning
if (asset->streamCount > 13)
{
ZONETOOL_ERROR("Vertexdecl %s has more than 13 streams.", name.data());
}
// lets pray it works
IW4::IVertexDecl::dump(asset);
return asset;
}
IW4::VertexShader* ITechset::dump_vertex_shader(MaterialVertexShader* shader, ZoneMemory* mem)
{
// convert to IW4
auto* asset = mem->Alloc<IW4::VertexShader>();
asset->name = mem->StrDup(va("iw3/%s", shader->name));
asset->shader = shader->prog.vs;
asset->codeLen = shader->prog.loadDef.programSize;
asset->bytecode = PDWORD(shader->prog.loadDef.program);
// dump shader
IW4::IVertexShader::dump(asset);
return asset;
}
IW4::PixelShader* ITechset::dump_pixel_shader(MaterialPixelShader* shader, ZoneMemory* mem)
{
// convert to IW4
auto* asset = mem->Alloc<IW4::PixelShader>();
asset->name = mem->StrDup(va("iw3/%s", shader->name));
asset->shader = shader->prog.ps;
asset->codeLen = shader->prog.loadDef.programSize;
asset->bytecode = PDWORD(shader->prog.loadDef.program);
// dump shader
IW4::IPixelShader::dump(asset);
return asset;
}
std::unordered_map<std::int32_t, std::int32_t> iw3_technique_map =
{
{IW3::TECHNIQUE_DEPTH_PREPASS, IW4::TECHNIQUE_DEPTH_PREPASS},
{IW3::TECHNIQUE_BUILD_FLOAT_Z, IW4::TECHNIQUE_BUILD_FLOAT_Z},
{IW3::TECHNIQUE_BUILD_SHADOWMAP_DEPTH, IW4::TECHNIQUE_BUILD_SHADOWMAP_DEPTH},
{IW3::TECHNIQUE_BUILD_SHADOWMAP_COLOR, IW4::TECHNIQUE_BUILD_SHADOWMAP_COLOR},
{IW3::TECHNIQUE_UNLIT, IW4::TECHNIQUE_UNLIT},
{IW3::TECHNIQUE_EMISSIVE, IW4::TECHNIQUE_EMISSIVE},
{IW3::TECHNIQUE_EMISSIVE_SHADOW, IW4::TECHNIQUE_EMISSIVE_SHADOW},
{IW3::TECHNIQUE_LIT_BEGIN, IW4::TECHNIQUE_LIT_BEGIN},
{IW3::TECHNIQUE_LIT, IW4::TECHNIQUE_LIT},
{IW3::TECHNIQUE_LIT_SUN, IW4::TECHNIQUE_LIT_SUN},
{IW3::TECHNIQUE_LIT_SUN_SHADOW, IW4::TECHNIQUE_LIT_SUN_SHADOW},
{IW3::TECHNIQUE_LIT_SPOT, IW4::TECHNIQUE_LIT_SPOT},
{IW3::TECHNIQUE_LIT_SPOT_SHADOW, IW4::TECHNIQUE_LIT_SPOT_SHADOW},
{IW3::TECHNIQUE_LIT_OMNI, IW4::TECHNIQUE_LIT_OMNI},
{IW3::TECHNIQUE_LIT_OMNI_SHADOW, IW4::TECHNIQUE_LIT_OMNI_SHADOW},
{IW3::TECHNIQUE_LIT_INSTANCED, IW4::TECHNIQUE_LIT_INSTANCED},
{IW3::TECHNIQUE_LIT_INSTANCED_SUN, IW4::TECHNIQUE_LIT_INSTANCED_SUN},
{IW3::TECHNIQUE_LIT_INSTANCED_SUN_SHADOW, IW4::TECHNIQUE_LIT_INSTANCED_SUN_SHADOW},
{IW3::TECHNIQUE_LIT_INSTANCED_SPOT, IW4::TECHNIQUE_LIT_INSTANCED_SPOT},
{IW3::TECHNIQUE_LIT_INSTANCED_OMNI, IW4::TECHNIQUE_LIT_INSTANCED_OMNI},
{IW3::TECHNIQUE_LIT_END, IW4::TECHNIQUE_LIT_END},
{IW3::TECHNIQUE_LIGHT_SPOT, IW4::TECHNIQUE_LIGHT_SPOT},
{IW3::TECHNIQUE_LIGHT_OMNI, IW4::TECHNIQUE_LIGHT_OMNI},
{IW3::TECHNIQUE_LIGHT_SPOT_SHADOW, IW4::TECHNIQUE_LIGHT_SPOT_SHADOW},
{IW3::TECHNIQUE_FAKELIGHT_NORMAL, IW4::TECHNIQUE_FAKELIGHT_NORMAL},
{IW3::TECHNIQUE_FAKELIGHT_VIEW, IW4::TECHNIQUE_FAKELIGHT_VIEW},
{IW3::TECHNIQUE_SUNLIGHT_PREVIEW, IW4::TECHNIQUE_SUNLIGHT_PREVIEW},
{IW3::TECHNIQUE_CASE_TEXTURE, IW4::TECHNIQUE_CASE_TEXTURE},
{IW3::TECHNIQUE_WIREFRAME_SOLID, IW4::TECHNIQUE_WIREFRAME_SOLID},
{IW3::TECHNIQUE_WIREFRAME_SHADED, IW4::TECHNIQUE_WIREFRAME_SHADED},
{IW3::TECHNIQUE_SHADOWCOOKIE_CASTER, 0xFFFFFFFF},
{IW3::TECHNIQUE_SHADOWCOOKIE_RECEIVER, 0xFFFFFFFF},
{IW3::TECHNIQUE_DEBUG_BUMPMAP, IW4::TECHNIQUE_DEBUG_BUMPMAP},
{IW3::TECHNIQUE_DEBUG_BUMPMAP_INSTANCED, IW4::TECHNIQUE_DEBUG_BUMPMAP_INSTANCED},
{IW3::TECHNIQUE_COUNT, IW4::TECHNIQUE_COUNT},
{IW3::TECHNIQUE_TOTAL_COUNT, IW4::TECHNIQUE_TOTAL_COUNT},
{IW3::TECHNIQUE_NONE, IW4::TECHNIQUE_NONE},
};
std::unordered_map<std::int32_t, std::int32_t> iw3_code_const_map =
{
{IW3::CONST_SRC_CODE_LIGHT_POSITION, IW4::CONST_SRC_CODE_LIGHT_POSITION},
{IW3::CONST_SRC_CODE_LIGHT_DIFFUSE, IW4::CONST_SRC_CODE_LIGHT_DIFFUSE},
{IW3::CONST_SRC_CODE_LIGHT_SPECULAR, IW4::CONST_SRC_CODE_LIGHT_SPECULAR},
{IW3::CONST_SRC_CODE_LIGHT_SPOTDIR, IW4::CONST_SRC_CODE_LIGHT_SPOTDIR},
{IW3::CONST_SRC_CODE_LIGHT_SPOTFACTORS, IW4::CONST_SRC_CODE_LIGHT_SPOTFACTORS},
{IW3::CONST_SRC_CODE_NEARPLANE_ORG, IW4::CONST_SRC_CODE_NEARPLANE_ORG},
{IW3::CONST_SRC_CODE_NEARPLANE_DX, IW4::CONST_SRC_CODE_NEARPLANE_DX},
{IW3::CONST_SRC_CODE_NEARPLANE_DY, IW4::CONST_SRC_CODE_NEARPLANE_DY},
{IW3::CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET, IW4::CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET},
{IW3::CONST_SRC_CODE_RENDER_TARGET_SIZE, IW4::CONST_SRC_CODE_RENDER_TARGET_SIZE},
{IW3::CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT, IW4::CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT},
{
IW3::CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR,
IW4::CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR
},
{IW3::CONST_SRC_CODE_DOF_EQUATION_SCENE, IW4::CONST_SRC_CODE_DOF_EQUATION_SCENE},
{IW3::CONST_SRC_CODE_DOF_LERP_SCALE, IW4::CONST_SRC_CODE_DOF_LERP_SCALE},
{IW3::CONST_SRC_CODE_DOF_LERP_BIAS, IW4::CONST_SRC_CODE_DOF_LERP_BIAS},
{IW3::CONST_SRC_CODE_DOF_ROW_DELTA, IW4::CONST_SRC_CODE_DOF_ROW_DELTA},
{IW3::CONST_SRC_CODE_PARTICLE_CLOUD_COLOR, IW4::CONST_SRC_CODE_PARTICLE_CLOUD_COLOR},
{IW3::CONST_SRC_CODE_GAMETIME, IW4::CONST_SRC_CODE_GAMETIME},
{IW3::CONST_SRC_CODE_PIXEL_COST_FRACS, IW4::CONST_SRC_CODE_PIXEL_COST_FRACS},
{IW3::CONST_SRC_CODE_PIXEL_COST_DECODE, IW4::CONST_SRC_CODE_PIXEL_COST_DECODE},
{IW3::CONST_SRC_CODE_FILTER_TAP_0, IW4::CONST_SRC_CODE_FILTER_TAP_0},
{IW3::CONST_SRC_CODE_FILTER_TAP_1, IW4::CONST_SRC_CODE_FILTER_TAP_1},
{IW3::CONST_SRC_CODE_FILTER_TAP_2, IW4::CONST_SRC_CODE_FILTER_TAP_2},
{IW3::CONST_SRC_CODE_FILTER_TAP_3, IW4::CONST_SRC_CODE_FILTER_TAP_3},
{IW3::CONST_SRC_CODE_FILTER_TAP_4, IW4::CONST_SRC_CODE_FILTER_TAP_4},
{IW3::CONST_SRC_CODE_FILTER_TAP_5, IW4::CONST_SRC_CODE_FILTER_TAP_5},
{IW3::CONST_SRC_CODE_FILTER_TAP_6, IW4::CONST_SRC_CODE_FILTER_TAP_6},
{IW3::CONST_SRC_CODE_FILTER_TAP_7, IW4::CONST_SRC_CODE_FILTER_TAP_7},
{IW3::CONST_SRC_CODE_COLOR_MATRIX_R, IW4::CONST_SRC_CODE_COLOR_MATRIX_R},
{IW3::CONST_SRC_CODE_COLOR_MATRIX_G, IW4::CONST_SRC_CODE_COLOR_MATRIX_G},
{IW3::CONST_SRC_CODE_COLOR_MATRIX_B, IW4::CONST_SRC_CODE_COLOR_MATRIX_B},
{IW3::CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION, IW4::CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION},
{IW3::CONST_SRC_CODE_SHADOWMAP_SCALE, IW4::CONST_SRC_CODE_SHADOWMAP_SCALE},
{IW3::CONST_SRC_CODE_ZNEAR, IW4::CONST_SRC_CODE_ZNEAR},
{IW3::CONST_SRC_CODE_SUN_POSITION, IW4::CONST_SRC_CODE_LIGHT_POSITION},
{IW3::CONST_SRC_CODE_SUN_DIFFUSE, IW4::CONST_SRC_CODE_LIGHT_DIFFUSE},
{IW3::CONST_SRC_CODE_SUN_SPECULAR, IW4::CONST_SRC_CODE_LIGHT_SPECULAR},
{IW3::CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE, IW4::CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE},
{IW3::CONST_SRC_CODE_DEBUG_BUMPMAP, IW4::CONST_SRC_CODE_DEBUG_BUMPMAP},
{IW3::CONST_SRC_CODE_MATERIAL_COLOR, IW4::CONST_SRC_CODE_MATERIAL_COLOR},
{IW3::CONST_SRC_CODE_FOG, IW4::CONST_SRC_CODE_FOG},
{IW3::CONST_SRC_CODE_FOG_COLOR, IW4::CONST_SRC_CODE_FOG_COLOR_LINEAR},
{IW3::CONST_SRC_CODE_GLOW_SETUP, IW4::CONST_SRC_CODE_GLOW_SETUP},
{IW3::CONST_SRC_CODE_GLOW_APPLY, IW4::CONST_SRC_CODE_GLOW_APPLY},
{IW3::CONST_SRC_CODE_COLOR_BIAS, IW4::CONST_SRC_CODE_COLOR_BIAS},
{IW3::CONST_SRC_CODE_COLOR_TINT_BASE, IW4::CONST_SRC_CODE_COLOR_TINT_BASE},
{IW3::CONST_SRC_CODE_COLOR_TINT_DELTA, IW4::CONST_SRC_CODE_COLOR_TINT_DELTA},
{IW3::CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS, IW4::CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS},
{IW3::CONST_SRC_CODE_ENVMAP_PARMS, IW4::CONST_SRC_CODE_ENVMAP_PARMS},
{IW3::CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST, IW4::CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST},
{IW3::CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE, IW4::CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE},
{IW3::CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET, IW4::CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET},
{IW3::CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX, IW4::CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX0},
{IW3::CONST_SRC_CODE_DEPTH_FROM_CLIP, IW4::CONST_SRC_CODE_DEPTH_FROM_CLIP},
{IW3::CONST_SRC_CODE_CODE_MESH_ARG_0, IW4::CONST_SRC_CODE_CODE_MESH_ARG_0},
{IW3::CONST_SRC_CODE_CODE_MESH_ARG_1, IW4::CONST_SRC_CODE_CODE_MESH_ARG_1},
{IW3::CONST_SRC_CODE_CODE_MESH_ARG_LAST, IW4::CONST_SRC_CODE_CODE_MESH_ARG_LAST},
{IW3::CONST_SRC_CODE_BASE_LIGHTING_COORDS, IW4::CONST_SRC_CODE_BASE_LIGHTING_COORDS},
{IW3::CONST_SRC_CODE_COUNT_FLOAT4, IW4::CONST_SRC_CODE_COUNT_FLOAT4},
{IW3::CONST_SRC_FIRST_CODE_MATRIX, IW4::CONST_SRC_FIRST_CODE_MATRIX},
{IW3::CONST_SRC_CODE_WORLD_MATRIX, IW4::CONST_SRC_CODE_WORLD_MATRIX0},
{IW3::CONST_SRC_CODE_INVERSE_WORLD_MATRIX, IW4::CONST_SRC_CODE_INVERSE_WORLD_MATRIX0},
{IW3::CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX, IW4::CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0},
{IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX, IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0},
{IW3::CONST_SRC_CODE_VIEW_MATRIX, IW4::CONST_SRC_CODE_VIEW_MATRIX},
{IW3::CONST_SRC_CODE_INVERSE_VIEW_MATRIX, IW4::CONST_SRC_CODE_INVERSE_VIEW_MATRIX},
{IW3::CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, IW4::CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX},
{IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX},
{IW3::CONST_SRC_CODE_PROJECTION_MATRIX, IW4::CONST_SRC_CODE_PROJECTION_MATRIX},
{IW3::CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX, IW4::CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX},
{IW3::CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX, IW4::CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX},
{
IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX
},
{IW3::CONST_SRC_CODE_WORLD_VIEW_MATRIX, IW4::CONST_SRC_CODE_WORLD_VIEW_MATRIX0},
{IW3::CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX, IW4::CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0},
{IW3::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX, IW4::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0},
{
IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0
},
{IW3::CONST_SRC_CODE_VIEW_PROJECTION_MATRIX, IW4::CONST_SRC_CODE_VIEW_PROJECTION_MATRIX},
{IW3::CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX, IW4::CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX},
{
IW3::CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX,
IW4::CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX
},
{
IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX
},
{IW3::CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX, IW4::CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0},
{
IW3::CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0
},
{
IW3::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX,
IW4::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0
},
{
IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0
},
{IW3::CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, IW4::CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX},
{IW3::CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX, IW4::CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX},
{IW3::CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, IW4::CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX},
{
IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX
},
{IW3::CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX, IW4::CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX},
{
IW3::CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX
},
{
IW3::CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX,
IW4::CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX
},
{
IW3::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX,
IW4::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX
},
};
void ITechset::dump_statebits(const std::string& techset, char* statebits)
{
char iw4_statebits[48];
memset(iw4_statebits, 0xFF, sizeof iw4_statebits);
for (int i = 0; i < 34; i++)
{
const auto itr = iw3_technique_map.find(i);
if (itr != iw3_technique_map.end())
{
if (itr->second >= 0)
{
iw4_statebits[itr->second] = statebits[i];
if (iw4_statebits[itr->second] >= 7)
{
iw4_statebits[itr->second] += 1;
}
if (itr->second >= 5 && itr->second <= 36)
{
iw4_statebits[itr->second + 1] = iw4_statebits[itr->second];
}
}
}
}
IW4::ITechset::dump_statebits(techset, iw4_statebits);
}
void ITechset::dump(MaterialTechniqueSet* asset, ZoneMemory* mem)
{
auto* iw4_techset = mem->Alloc<IW4::MaterialTechniqueSet>();
iw4_techset->name = mem->StrDup(va("iw3/%s", asset->name));
iw4_techset->pad = asset->pad;
for (int i = 0; i < 34; i++)
{
const auto itr = iw3_technique_map.find(i);
if (itr != iw3_technique_map.end())
{
if (asset->techniques[i] && itr->second >= 0)
{
const auto size = sizeof(IW4::MaterialTechniqueHeader) + (sizeof(IW4::MaterialPass) * asset->techniques[i]->hdr.numPasses);
iw4_techset->techniques[itr->second] = mem->ManualAlloc<IW4::MaterialTechnique>(size);
if (itr->second >= 5 && itr->second <= 36)
{
iw4_techset->techniques[itr->second + 1] = iw4_techset->techniques[itr->second];
}
memcpy(iw4_techset->techniques[itr->second], asset->techniques[i], size);
auto& iw3_technique = asset->techniques[i];
auto& technique = iw4_techset->techniques[itr->second];
technique->hdr.name = mem->StrDup(va("iw3/%s", technique->hdr.name));
if ((technique->hdr.flags & 0x10) == 0x10)
{
technique->hdr.flags &= ~0x10;
technique->hdr.flags |= 0x40;
}
for (short pass = 0; pass < technique->hdr.passCount; pass++)
{
auto* iw3_pass_def = &iw3_technique->pass[pass];
auto* pass_def = &technique->pass[pass];
auto vertex_decl_name = GenerateNameForVertexDecl(iw3_pass_def->vertexDecl);
if (iw3_pass_def->pixelShader) pass_def->pixelShader = dump_pixel_shader(iw3_pass_def->pixelShader, mem);
if (iw3_pass_def->vertexDecl) pass_def->vertexDecl = dump_vertex_decl(vertex_decl_name, iw3_pass_def->vertexDecl, mem);
if (iw3_pass_def->vertexShader) pass_def->vertexShader = dump_vertex_shader(iw3_pass_def->vertexShader, mem);
const auto arg_count = pass_def->perPrimArgCount + pass_def->perObjArgCount + pass_def->stableArgCount;
if (arg_count > 0)
{
pass_def->argumentDef = mem->Alloc<IW4::ShaderArgumentDef>(arg_count);
memcpy(pass_def->argumentDef, iw3_pass_def->args, sizeof(IW4::ShaderArgumentDef) * arg_count);
}
for (auto arg = 0; arg < pass_def->perPrimArgCount + pass_def->perObjArgCount + pass_def->stableArgCount; arg++)
{
auto* arg_def = &pass_def->argumentDef[arg];
if (arg_def->type == 3 || arg_def->type == 5)
{
if (iw3_code_const_map.find(arg_def->u.codeConst.index) != iw3_code_const_map.end())
{
arg_def->u.codeConst.index = iw3_code_const_map[arg_def->u.codeConst.index];
}
else
{
if (IsDebuggerPresent())
{
__debugbreak();
}
else
{
ZONETOOL_WARNING("Missing const mapping for constant %u!", arg_def->u.codeConst.index);
}
}
}
}
}
}
}
}
IW4::ITechset::dump(iw4_techset);
}
}
}

View File

@ -0,0 +1,27 @@
// ======================= 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
// ========================================================
#pragma once
#include "IW4/Structs.hpp"
namespace ZoneTool
{
namespace IW3
{
class ITechset
{
public:
static void dumpTechniquePass(MaterialTechnique* asset);
static void dump(MaterialTechniqueSet* asset, ZoneMemory* mem);
static IW4::VertexDecl* dump_vertex_decl(const std::string& name, MaterialVertexDeclaration* vertex, ZoneMemory* mem);
static IW4::VertexShader* dump_vertex_shader(MaterialVertexShader* shader, ZoneMemory* mem);
static IW4::PixelShader* dump_pixel_shader(MaterialPixelShader* shader, ZoneMemory* mem);
static void dump_statebits(const std::string& techset, char* statebits);
};
}
}

View File

@ -0,0 +1,76 @@
// ======================= 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 "../IW4/Assets/XAnimParts.hpp"
namespace ZoneTool
{
namespace IW3
{
void IXAnimParts::dump(XAnimParts* anim, ZoneMemory* mem)
{
if (anim)
{
auto asset = mem->Alloc<IW4::XAnimParts>();
#define XAE_CopyElement(name) asset->name = anim->name
XAE_CopyElement(name);
XAE_CopyElement(dataByteCount);
XAE_CopyElement(dataShortCount);
XAE_CopyElement(dataIntCount);
XAE_CopyElement(randomDataByteCount);
XAE_CopyElement(randomDataIntCount);
XAE_CopyElement(framecount);
asset->flags = 0;
if (anim->bLoop)
{
asset->flags |= IW4::ANIM_LOOP;
}
if (anim->bDelta)
{
asset->flags |= IW4::ANIM_DELTA;
}
for (auto i = 0; i < 10; i++)
{
XAE_CopyElement(boneCount[i]);
}
XAE_CopyElement(notifyCount);
XAE_CopyElement(assetType);
XAE_CopyElement(isDefault);
XAE_CopyElement(randomDataShortCount);
XAE_CopyElement(indexcount);
XAE_CopyElement(framerate);
XAE_CopyElement(frequency);
XAE_CopyElement(tagnames);
XAE_CopyElement(dataByte);
XAE_CopyElement(dataShort);
XAE_CopyElement(dataInt);
XAE_CopyElement(randomDataShort);
XAE_CopyElement(randomDataByte);
XAE_CopyElement(randomDataInt);
XAE_CopyElement(indices.data);
asset->notify = reinterpret_cast<IW4::XAnimNotifyInfo*>(anim->notify);
if (anim->delta)
{
asset->delta = mem->Alloc<IW4::XAnimDeltaPart>();
asset->delta->quat = reinterpret_cast<IW4::XAnimDeltaPartQuat*>(anim->delta->quat);
asset->delta->trans = reinterpret_cast<IW4::XAnimPartTrans*>(anim->delta->trans);
}
// dump asset
IW4::IXAnimParts::dump(asset, SL_ConvertToString);
}
}
}
}

View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IXAnimParts
{
public:
static void dump(XAnimParts* anim, ZoneMemory* mem);
};
}
}

146
src/IW3/Assets/XModel.cpp Normal file
View File

@ -0,0 +1,146 @@
// ======================= 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 "../IW4/Assets/Xmodel.hpp"
#include "../IW4/Assets/XSurface.hpp"
namespace ZoneTool
{
namespace IW3
{
IW4::XSurface* GenerateIW4Surface(XSurface* asset, ZoneMemory* mem)
{
// allocate IW4 XSurface structure
const auto xsurface = mem->Alloc<IW4::XSurface>();
xsurface->tileMode = asset->tileMode;
xsurface->deformed = asset->deformed;
xsurface->vertCount = asset->vertCount;
xsurface->triCount = asset->triCount;
xsurface->zoneHandle = asset->zoneHandle;
xsurface->baseTriIndex = asset->baseTriIndex;
xsurface->baseVertIndex = asset->baseVertIndex;
xsurface->triIndices = reinterpret_cast<IW4::Face *>(asset->triIndices);
memcpy(&xsurface->vertexInfo, &asset->vertInfo, sizeof IW4::XSurfaceVertexInfo);
xsurface->verticies = reinterpret_cast<IW4::GfxPackedVertex *>(asset->verts0);
xsurface->vertListCount = asset->vertListCount;
xsurface->rigidVertLists = reinterpret_cast<IW4::XRigidVertList *>(asset->vertList);
memcpy(&xsurface->partBits, &asset->partBits, sizeof(int[4]));
return xsurface;
}
IW4::XModel* GenerateIW4Model(XModel* asset, ZoneMemory* mem)
{
// allocate IW4 XModel structure
const auto xmodel = mem->Alloc<IW4::XModel>();
// copy data over
xmodel->name = const_cast<char*>(asset->name);
xmodel->numBones = asset->numBones;
xmodel->numRootBones = asset->numRootBones;
xmodel->numSurfaces = asset->numsurfs;
xmodel->lodRampType = asset->lodRampType;
xmodel->scale = 1.0f;
memset(xmodel->noScalePartBits, 0, sizeof(int) * 6);
xmodel->parentList = reinterpret_cast<unsigned char*>(asset->parentList);
xmodel->boneNames = reinterpret_cast<short*>(asset->boneNames);
xmodel->tagAngles = reinterpret_cast<IW4::XModelAngle*>(asset->quats);
xmodel->tagPositions = reinterpret_cast<IW4::XModelTagPos*>(asset->trans);
xmodel->partClassification = asset->partClassification;
xmodel->animMatrix = reinterpret_cast<IW4::DObjAnimMat*>(asset->baseMat);
xmodel->materials = reinterpret_cast<IW4::Material**>(asset->materialHandles);
// convert level of detail data
for (int i = 0; i < asset->numLods; i++)
{
xmodel->lods[i].dist = asset->lodInfo[i].dist;
xmodel->lods[i].numSurfacesInLod = asset->lodInfo[i].numsurfs;
xmodel->lods[i].surfIndex = asset->lodInfo[i].surfIndex;
memcpy(xmodel->lods[i].partBits, asset->lodInfo[i].partBits, sizeof(int[4]));
memcpy(&xmodel->lods[i].lod, &asset->lodInfo[i].lod, 3);
// generate ModelSurface object
xmodel->lods[i].surfaces = mem->Alloc<IW4::XModelSurfs>();;
xmodel->lods[i].surfaces->name = mem->StrDup(va("zonetool_%s_%u", xmodel->name, i).data());
xmodel->lods[i].surfaces->numsurfs = xmodel->lods[i].numSurfacesInLod;
memcpy(xmodel->lods[i].surfaces->partBits, asset->lodInfo[i].partBits, sizeof(int[4]));
// allocate xsurficies
xmodel->lods[i].surfaces->surfs = mem->Alloc<IW4::XSurface>(xmodel->lods[i].numSurfacesInLod);
// loop through surfaces in current Level-of-Detail
for (int surf = xmodel->lods[i].surfIndex; surf <
xmodel->lods[i].surfIndex + xmodel->lods[i].numSurfacesInLod; surf++)
{
// generate iw4 surface
const auto surface = GenerateIW4Surface(&asset->surfs[surf], mem);
// copy XSurface into iw4 structure
memcpy(
&xmodel->lods[i].surfaces->surfs[surf - xmodel->lods[i].surfIndex],
surface,
sizeof IW4::XSurface
);
}
}
xmodel->numLods = asset->numLods;
xmodel->collLod = asset->collLod;
xmodel->flags = asset->flags;
xmodel->colSurf = reinterpret_cast<IW4::XModelCollSurf_s*>(asset->collSurfs);
xmodel->numColSurfs = asset->numCollSurfs;
xmodel->contents = asset->contents;
// convert colsurf bounds
for (int i = 0; i < xmodel->numColSurfs; i++)
{
xmodel->colSurf[i].bounds.compute();
}
// convert boneinfo
xmodel->boneInfo = mem->Alloc<IW4::XBoneInfo>(xmodel->numBones);
for (int i = 0; i < xmodel->numBones; i++)
{
memcpy(&xmodel->boneInfo[i].bounds, &asset->boneInfo[i].bounds, sizeof(Bounds));
xmodel->boneInfo[i].packedBounds.compute();
xmodel->boneInfo[i].radiusSquared = asset->boneInfo[i].radiusSquared;
}
xmodel->radius = asset->radius;
xmodel->memUsage = asset->memUsage;
xmodel->bad = asset->bad;
xmodel->physPreset = reinterpret_cast<IW4::PhysPreset*>(asset->physPreset);
xmodel->bounds.compute(asset->mins, asset->maxs);
return xmodel;
}
void IXModel::dump(XModel* asset, ZoneMemory* mem)
{
// generate iw4 model
auto iw4_model = GenerateIW4Model(asset, mem);
// dump iw4 model
IW4::IXModel::dump(iw4_model, SL_ConvertToString);
// dump all xsurfaces
for (int i = 0; i < iw4_model->numLods; i++)
{
IW4::IXSurface::dump(iw4_model->lods[i].surfaces);
}
}
}
}

21
src/IW3/Assets/XModel.hpp Normal file
View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW3
{
class IXModel
{
public:
static void dump(XModel* asset, ZoneMemory* mem);
};
}
}

38
src/IW3/Functions.hpp Normal file
View File

@ -0,0 +1,38 @@
// ======================= 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
// ========================================================
#pragma once
//!!!!!!!!!!!!!!!!!
//!!!!!!!TODO!!!!!!
//!!!CHANGE OFFSETS
//!!!!!!!!!!!!!!!!!
namespace ZoneTool
{
namespace IW3
{
union XAssetHeader;
static Function<XAssetHeader(std::int32_t, const char*)> DB_FindXAssetHeader = 0x489570;
static Function<void(XZoneInfo*, std::uint32_t, std::uint32_t)> DB_LoadXAssets; //add offset
typedef int (__cdecl * DB_GetXAssetSizeHandler_t)();
static DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x726A10;
static const char* SL_ConvertToString(std::uint16_t index)
{
return reinterpret_cast<const char*>(*reinterpret_cast<char**>(0x14E8A04) + 12 * index + 4);
}
static short SL_AllocString(const std::string& string)
{
// TODO
}
}
}

365
src/IW3/IW3.cpp Normal file
View File

@ -0,0 +1,365 @@
// ======================= 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 "ZoneTool.hpp"
namespace ZoneTool
{
namespace IW3
{
bool isDumping = false;
bool isVerifying = false;
auto currentDumpingZone = ""s;
Linker::Linker()
{
}
Linker::~Linker()
{
}
const char* Linker::version()
{
return "CoD4";
}
bool Linker::is_used()
{
return !strncmp(reinterpret_cast<char *>(0x006CF584), this->version(), 4);
}
typedef void*(__cdecl * Dvar_RegisterBool_t)(const char*, bool, unsigned int, const char*);
Dvar_RegisterBool_t Dvar_RegisterBool = (Dvar_RegisterBool_t)0x56C600;
void* Linker::Dedicated_RegisterDvarBool(const char* name, bool defaultValue, unsigned int flags,
const char* description)
{
return Dvar_RegisterBool(name, true, 0x2000, description);
}
void** DB_XAssetPool = (void**)0x7265E0;
unsigned int* g_poolSize = (unsigned int*)0x7263A0;
void* DB_FindXAssetHeader_Unsafe(const XAssetType type, const std::string& name)
{
const static auto DB_FindXAssetHeader_Internal = 0x4892A0;
const auto name_ptr = name.data();
const auto type_int = static_cast<std::int32_t>(type);
const XAsset* asset_header = nullptr;
__asm
{
mov edi, name_ptr;
push type_int;
call DB_FindXAssetHeader_Internal;
add esp, 4;
mov asset_header, eax;
}
return (asset_header) ? asset_header->ptr.data : nullptr;
}
const char* Linker::GetAssetName(XAsset* asset)
{
// todo
if (asset->type == image)
{
return asset->ptr.image->name;
}
if (asset->type == menu)
{
// return asset->ptr.menu->name;
}
else
{
return asset->ptr.rawfile->name;
}
return "";
}
void Linker::HandleAsset(XAsset* asset)
{
static std::shared_ptr<ZoneMemory> memory;
static std::vector<std::pair<XAssetType, std::string>> referencedAssets;
if (!memory)
{
memory = std::make_shared<ZoneMemory>(1024 * 1024 * 128); // 128mb
}
// nice meme
if (isVerifying)
{
// print asset name to console
ZONETOOL_INFO("Loading asset \"%s\" of type %s.", Linker::GetAssetName(asset), reinterpret_cast<char**>(
0x00726840)[asset->type]);
}
#define DECLARE_ASSET(__TYPE__, __ASSET__) \
if (asset->type == __TYPE__) \
{ \
__ASSET__::dump(asset->ptr.__TYPE__, memory.get()); \
}
// fastfile name
auto fastfile = static_cast<std::string>(*(const char**)0xE344CC);
if (asset->type == rawfile && GetAssetName(asset) == currentDumpingZone)
{
for (auto& ref : referencedAssets)
{
if (ref.second.length() <= 1 || ref.first == XAssetType::loaded_sound)
{
continue;
}
const auto asset_name = &ref.second[1];
const auto ref_asset = DB_FindXAssetHeader_Unsafe(ref.first, asset_name);
if (ref_asset == nullptr)
{
ZONETOOL_ERROR("Could not find referenced asset \"%s\"!", asset_name);
continue;
}
XAsset asset;
asset.type = ref.first;
asset.ptr.data = ref_asset;
ZONETOOL_INFO("Dumping additional asset \"%s\" because it is referenced by %s.", asset_name, currentDumpingZone.data());
HandleAsset(&asset);
}
ZONETOOL_INFO("Zone \"%s\" dumped.", &fastfile[0]);
// clear referenced assets array because we are done dumping
referencedAssets.clear();
// free memory
memory->Free();
memory = nullptr;
FileSystem::SetFastFile("");
isDumping = false;
isVerifying = false;
}
// dump shit
if (isDumping)
{
FileSystem::SetFastFile(fastfile);
// check if the asset is a reference asset
if (GetAssetName(asset)[0] == ',')
{
referencedAssets.push_back({asset->type, GetAssetName(asset)});
}
else
{
// DECLARE_ASSET(image, IGfxImage);
DECLARE_ASSET(xmodel, IXModel);
DECLARE_ASSET(material, IMaterial);
DECLARE_ASSET(xanim, IXAnimParts);
DECLARE_ASSET(techset, ITechset);
DECLARE_ASSET(loaded_sound, ILoadedSound);
DECLARE_ASSET(sound, ISound);
DECLARE_ASSET(fx, IFxEffectDef);
DECLARE_ASSET(gfx_map, IGfxWorld);
DECLARE_ASSET(col_map_mp, IClipMap);
DECLARE_ASSET(map_ents, IMapEnts);
DECLARE_ASSET(com_map, IComWorld);
}
}
}
void* Linker::DB_AddXAsset(XAsset* asset, int unk)
{
HandleAsset(asset);
// call original function
return Memory::func<void*(XAsset* asset, int unk)>(0x489B00)(asset, unk);
}
void* ReallocateAssetPool(uint32_t type, unsigned int newSize)
{
int elSize = DB_GetXAssetSizeHandlers[type]();
void* poolEntry = malloc(newSize * elSize);
DB_XAssetPool[type] = poolEntry;
g_poolSize[type] = newSize;
return poolEntry;
}
void* ReallocateAssetPoolM(uint32_t type, int multiplier)
{
int elSize = DB_GetXAssetSizeHandlers[type]();
int newSize = multiplier * g_poolSize[type];
void* poolEntry = malloc(newSize * elSize);
DB_XAssetPool[type] = poolEntry;
g_poolSize[type] = newSize;
return poolEntry;
}
void Com_PrintfHook(int channel, const char* data, int unk)
{
printf(data);
}
void Linker::startup()
{
if (this->is_used())
{
// Realloc asset pools
ReallocateAssetPoolM(localize, 2);
ReallocateAssetPoolM(material, 2);
ReallocateAssetPoolM(font, 2);
ReallocateAssetPoolM(image, 2);
ReallocateAssetPoolM(techset, 2);
ReallocateAssetPoolM(fx, 4);
ReallocateAssetPoolM(xanim, 2);
ReallocateAssetPoolM(xmodel, 2);
ReallocateAssetPoolM(physpreset, 2);
ReallocateAssetPoolM(weapon, 2);
ReallocateAssetPoolM(game_map_sp, 2);
ReallocateAssetPoolM(game_map_mp, 2);
ReallocateAssetPoolM(map_ents, 5);
ReallocateAssetPoolM(com_map, 5);
ReallocateAssetPoolM(col_map_mp, 5);
ReallocateAssetPoolM(gfx_map, 5);
ReallocateAssetPoolM(rawfile, 2);
ReallocateAssetPoolM(loaded_sound, 2);
ReallocateAssetPoolM(sound, 2);
ReallocateAssetPoolM(stringtable, 2);
// Asset dump hook
Memory(0x00489E72).call(DB_AddXAsset);
// Always use dedicated mode
Memory(0x4FEA9E).call(Dedicated_RegisterDvarBool);
Memory(0x4FEAC2).call(Dedicated_RegisterDvarBool);
Memory(0x4FFE37).call(Dedicated_RegisterDvarBool);
Memory(0x4FFE5D).call(Dedicated_RegisterDvarBool);
// Don't touch image data
Memory(0x616E9C).nop(3);
// idc if you can't initialise PunkBuster
Memory(0x5776DF).nop(5);
Memory(0x5776EC).nop(5);
// Initialise console_mp.log
Memory(0x4FCBA3).nop(2);
// We don't need recommended settings
Memory(0x4FE99A).set<std::uint8_t>(0xEB);
Memory(0x4FE993).nop(7);
// We do not need to load the config_mp.cfg
Memory(0x55EEA6).set<std::uint8_t>(0xEB);
// Don't give a frametime warning
Memory(0x4FFD9D).nop(5);
// Disabling loadedsound touching
Memory(0x4794C2).nop(5);
// No huffmann message
Memory(0x507982).nop(5);
// Disable console window
Memory(0x0046CE55).nop(5);
// Obtain console output from IW3
Memory(0x4FCC00).call(Com_PrintfHook);
}
}
std::shared_ptr<IZone> Linker::alloc_zone(const std::string& zone)
{
ZONETOOL_ERROR("AllocZone called but IW3 is not intended to compile zones!");
return nullptr;
}
std::shared_ptr<ZoneBuffer> Linker::alloc_buffer()
{
ZONETOOL_ERROR("AllocBuffer called but IW3 is not intended to compile zones!");
return nullptr;
}
void Linker::load_zone(const std::string& name)
{
static XZoneInfo zone;
zone.zone = _strdup(&name[0]);
zone.loadFlags = 0;
zone.unloadFlags = 0;
Memory::func<void(XZoneInfo*, int, int)>(0x48A2B0)(&zone, 1, 0);
}
void Linker::unload_zones()
{
}
bool Linker::is_valid_asset_type(const std::string& type)
{
return this->type_to_int(type) >= 0;
}
std::int32_t Linker::type_to_int(std::string type)
{
auto xassettypes = reinterpret_cast<char**>(0x00726840);
for (std::int32_t i = 0; i < max; i++)
{
if (xassettypes[i] == type)
return i;
}
return -1;
}
std::string Linker::type_to_string(std::int32_t type)
{
auto xassettypes = reinterpret_cast<char**>(0x00726840);
return xassettypes[type];
}
bool Linker::supports_building()
{
return false;
}
bool Linker::supports_version(const zone_target_version version)
{
return version == zone_target_version::iw3_alpha_253 || version == zone_target_version::iw3_alpha_290 ||
version == zone_target_version::iw3_alpha_328;
}
void Linker::dump_zone(const std::string& name)
{
isDumping = true;
currentDumpingZone = name;
load_zone(name);
}
void Linker::verify_zone(const std::string& name)
{
isVerifying = true;
currentDumpingZone = name;
load_zone(name);
}
}
}

70
src/IW3/IW3.hpp Normal file
View File

@ -0,0 +1,70 @@
// ======================= 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
// ========================================================
#pragma once
#include <ZoneUtils.hpp>
#include "Functions.hpp"
#include "Structs.hpp"
#include "Assets/XModel.hpp"
#include "Assets/Material.hpp"
#include "Assets/XAnimParts.hpp"
#include "Assets/Techset.hpp"
#include "Assets/GfxWorld.hpp"
#include "Assets/GfxImage.hpp"
#include "Assets/GameWorldMp.hpp"
#include "Assets/LoadedSound.hpp"
#include "Assets/Sound.hpp"
#include "Assets/FxEffectDef.hpp"
#include "Assets/ClipMap.hpp"
#include "Assets/MapEnts.hpp"
#include "Assets/ComWorld.hpp"
// oh nee toch niet
namespace ZoneTool
{
namespace IW3
{
struct XAsset
{
XAssetType type;
XAssetHeader ptr;
};
class Linker : public ILinker
{
public:
Linker();
~Linker();
const char* version() override;
bool is_used() override;
void startup() override;
std::shared_ptr<IZone> alloc_zone(const std::string& zone) override;
std::shared_ptr<ZoneBuffer> alloc_buffer() override;
void load_zone(const std::string& name) override;
void unload_zones() override;
bool is_valid_asset_type(const std::string& type) override;
std::int32_t type_to_int(std::string type) override;
std::string type_to_string(std::int32_t type) override;
bool supports_building() override;
bool supports_version(const zone_target_version version) override;
void dump_zone(const std::string& name) override;
void verify_zone(const std::string& name) override;
static void* Dedicated_RegisterDvarBool(const char* name, bool defaultValue, unsigned int flags,
const char* description);
static void* DB_AddXAsset(XAsset* asset, int unk);
static const char* GetAssetName(XAsset* asset);
static void HandleAsset(XAsset* asset);
};
}
}

1930
src/IW3/Structs.hpp Normal file

File diff suppressed because it is too large Load Diff

10
src/IW3/stdafx.cpp Normal file
View File

@ -0,0 +1,10 @@
// ======================= 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"

21
src/IW3/stdafx.hpp Normal file
View File

@ -0,0 +1,21 @@
// ======================= 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
// ========================================================
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <vector>
#include <string>
using namespace std::string_literals;
#include "IW3.hpp"
#include "IW4/Structs.hpp"

36
src/IW4.lua Normal file
View File

@ -0,0 +1,36 @@
IW4 = {}
function IW4:include()
includedirs {
path.join(ProjectFolder(), "IW4")
}
end
function IW4:link()
self:include()
links {
"IW4"
}
end
function IW4:project()
local folder = ProjectFolder();
project "IW4"
kind "StaticLib"
language "C++"
pchheader "stdafx.hpp"
pchsource(path.join(folder, "IW4/stdafx.cpp"))
files {
path.join(folder, "IW4/**.h"),
path.join(folder, "IW4/**.hpp"),
path.join(folder, "IW4/**.cpp")
}
self:include()
ZoneUtils:include()
IW5:include()
zlib:include()
end

View File

@ -0,0 +1,147 @@
// ======================= 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 "ZoneUtils/Utils/BinaryDumper.hpp"
namespace ZoneTool
{
namespace IW4
{
AddonMapEnts* IAddonMapEnts::parse(std::string name, ZoneMemory* mem)
{
// check if we can open a filepointer
if (!FileSystem::FileExists(name))
{
return nullptr;
}
auto file = FileSystem::FileOpen(name, "rb");
// let them know that we're parsing a custom mapents file
ZONETOOL_INFO("Parsing addon mapents \"%s\"...", name.c_str());
// alloc mapents
auto ents = mem->Alloc<AddonMapEnts>();
ents->name = mem->StrDup(name);
ents->numEntityChars = FileSystem::FileSize(file) + 1;
ents->entityString = mem->Alloc<char>(ents->numEntityChars);
memset((char*)ents->entityString, 0, ents->numEntityChars);
fread((char*)ents->entityString, ents->numEntityChars - 1, 1, file);
#ifdef CONVERT_IW5_MAPENTS
// convert the mapents!
IMapEnts::convert_ents(reinterpret_cast<MapEnts*>(ents), mem);
#endif
// close filepointer
FileSystem::FileClose(file);
AssetReader triggerReader(mem);
AssetReader stageReader(mem);
if (triggerReader.open(name + ".triggers"))
{
ents->trigger.modelCount = triggerReader.read_int();
ents->trigger.models = triggerReader.read_array<TriggerModel>();
ents->trigger.hullCount = triggerReader.read_int();
ents->trigger.hulls = triggerReader.read_array<TriggerHull>();
ents->trigger.slabCount = triggerReader.read_int();
ents->trigger.slabs = triggerReader.read_array<TriggerSlab>();
}
triggerReader.close();
// return mapents
return ents;
}
void IAddonMapEnts::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".mapents"; // name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), name.data()).addon_map_ents;
}
}
void IAddonMapEnts::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IAddonMapEnts::load_depending(IZone* zone)
{
}
std::string IAddonMapEnts::name()
{
return this->name_;
}
std::int32_t IAddonMapEnts::type()
{
return addon_map_ents;
}
void IAddonMapEnts::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->entityString)
{
buf->align(0);
buf->write(data->entityString, data->numEntityChars);
ZoneBuffer::clear_pointer(&dest->entityString);
}
IMapEnts::write_triggers(zone, buf, &dest->trigger);
END_LOG_STREAM;
buf->pop_stream();
}
void IAddonMapEnts::dump(AddonMapEnts* asset)
{
auto* file = FileSystem::FileOpen(asset->name, "wb");
if (file)
{
fwrite(asset->entityString, asset->numEntityChars, 1, file);
FileSystem::FileClose(file);
}
AssetDumper trigger_dumper;
if (trigger_dumper.open(asset->name + ".triggers"s))
{
trigger_dumper.dump_int(asset->trigger.modelCount);
trigger_dumper.dump_array<TriggerModel>(asset->trigger.models, asset->trigger.modelCount);
trigger_dumper.dump_int(asset->trigger.hullCount);
trigger_dumper.dump_array<TriggerHull>(asset->trigger.hulls, asset->trigger.hullCount);
trigger_dumper.dump_int(asset->trigger.slabCount);
trigger_dumper.dump_array<TriggerSlab>(asset->trigger.slabs, asset->trigger.slabCount);
trigger_dumper.close();
}
}
}
}

View File

@ -0,0 +1,35 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IAddonMapEnts : public IAsset
{
private:
std::string name_;
AddonMapEnts* asset_ = nullptr;
public:
AddonMapEnts* parse(std::string name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(AddonMapEnts* asset);
};
}
}

631
src/IW4/Assets/ClipMap.cpp Normal file
View File

@ -0,0 +1,631 @@
// ======================= 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/ClipMap.hpp"
namespace ZoneTool
{
namespace IW4
{
clipMap_t* IClipMap::parse(const std::string& name, ZoneMemory* mem)
{
auto* iw5_colmap = IW5::IClipMap::parse(name, mem);
if (!iw5_colmap)
{
return nullptr;
}
// allocate collision map
auto* colmap = mem->Alloc<clipMap_t>();
// copy data from IW5 to IW4
colmap->name = iw5_colmap->name;
colmap->isInUse = iw5_colmap->isInUse;
colmap->numCPlanes = iw5_colmap->info.numCPlanes;
colmap->cPlanes = (cplane_s*)iw5_colmap->info.cPlanes;
colmap->numStaticModels = iw5_colmap->numStaticModels;
colmap->staticModelList = (cStaticModel_s*)iw5_colmap->staticModelList;
colmap->numMaterials = iw5_colmap->info.numMaterials;
colmap->materials = (dmaterial_t*)iw5_colmap->info.materials;
colmap->numCBrushSides = iw5_colmap->info.numCBrushSides;
colmap->cBrushSides = (cbrushside_t*)iw5_colmap->info.cBrushSides;
colmap->numCBrushEdges = iw5_colmap->info.numCBrushEdges;
colmap->cBrushEdges = (cbrushedge_t*)iw5_colmap->info.cBrushEdges;
colmap->numCNodes = iw5_colmap->numCNodes;
colmap->cNodes = (cNode_t*)iw5_colmap->cNodes;
colmap->numCLeaf = iw5_colmap->numCLeaf;
colmap->cLeaf = (cLeaf_t*)iw5_colmap->cLeaf;
colmap->numCLeafBrushNodes = iw5_colmap->info.numCLeafBrushNodes;
colmap->cLeafBrushNodes = (cLeafBrushNode_s*)iw5_colmap->info.cLeafBrushNodes;
colmap->numLeafBrushes = iw5_colmap->info.numLeafBrushes;
colmap->leafBrushes = iw5_colmap->info.leafBrushes;
// leafSurfaces todo!
colmap->numVerts = iw5_colmap->numVerts;
colmap->verts = (VecInternal<3>*)iw5_colmap->verts;
colmap->numTriIndices = iw5_colmap->numTriIndices;
colmap->triIndices = iw5_colmap->triIndices;
colmap->triEdgeIsWalkable = iw5_colmap->triEdgeIsWalkable;
colmap->numCollisionBorders = iw5_colmap->numCollisionBorders;
colmap->collisionBorders = (CollisionBorder*)iw5_colmap->collisionBorders;
colmap->numCollisionPartitions = iw5_colmap->numCollisionPartitions;
colmap->collisionPartitions = (CollisionPartition*)iw5_colmap->collisionPartitions;
colmap->numCollisionAABBTrees = iw5_colmap->numCollisionAABBTrees;
colmap->collisionAABBTrees = (CollisionAabbTree*)iw5_colmap->collisionAABBTrees;
// cmodels!
colmap->numCModels = iw5_colmap->numCModels;
colmap->cModels = new cmodel_t[colmap->numCModels];
memset(colmap->cModels, 0, sizeof(cmodel_t) * colmap->numCModels);
for (int i = 0; i < colmap->numCModels; i++)
{
memcpy(colmap->cModels[i]._portpad0, iw5_colmap->cModels[i]._portpad0, 28);
memcpy(colmap->cModels[i]._portpad1, iw5_colmap->cModels[i]._portpad1, 40);
}
colmap->numBrushes = iw5_colmap->info.numBrushes;
colmap->brushes = (cbrush_t*)iw5_colmap->info.brushes;
colmap->brushBounds = (Bounds*)iw5_colmap->info.brushBounds;
colmap->brushContents = iw5_colmap->info.brushContents;
colmap->mapEnts = (MapEnts*)iw5_colmap->mapEnts;
colmap->smodelNodeCount = iw5_colmap->smodelNodeCount;
colmap->smodelNodes = (SModelAabbNode*)iw5_colmap->smodelNodes;
// return converted colmap
return colmap;
}
void IClipMap::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".d3dbsp"; // name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), name.data()).clipmap;
}
}
void IClipMap::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IClipMap::load_depending(IZone* zone)
{
auto* data = this->asset_;
if (data->staticModelList)
{
for (auto i = 0u; i < data->numStaticModels; i++)
{
if (data->staticModelList[i].xmodel)
{
zone->add_asset_of_type(xmodel, data->staticModelList[i].xmodel->name);
}
}
}
if (data->dynEntDefList[0])
{
for (auto i = 0u; i < data->dynEntCount[0]; i++)
{
if (data->dynEntDefList[0][i].xModel)
{
zone->add_asset_of_type(xmodel, data->dynEntDefList[0][i].xModel->name);
}
if (data->dynEntDefList[0][i].destroyFx)
{
// zone->AddAssetOfType(fx, data->dynEntDefList[0][i].destroyFx->name);
}
if (data->dynEntDefList[0][i].physPreset)
{
zone->add_asset_of_type(physpreset, data->dynEntDefList[0][i].physPreset->name);
}
}
}
if (data->dynEntDefList[1])
{
for (auto i = 0u; i < data->dynEntCount[1]; i++)
{
if (data->dynEntDefList[1][i].xModel)
{
zone->add_asset_of_type(xmodel, data->dynEntDefList[1][i].xModel->name);
}
if (data->dynEntDefList[1][i].destroyFx)
{
// zone->AddAssetOfType(fx, data->dynEntDefList[1][i].destroyFx->name);
}
if (data->dynEntDefList[1][i].physPreset)
{
zone->add_asset_of_type(physpreset, data->dynEntDefList[1][i].physPreset->name);
}
}
}
if (data->mapEnts)
{
zone->add_asset_of_type(map_ents, this->asset_->mapEnts->name);
}
}
std::string IClipMap::name()
{
return this->name_;
}
std::int32_t IClipMap::type()
{
return col_map_sp;
}
void IClipMap::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write<clipMap_t>(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
if (data->cPlanes)
{
cplane_s* dest_cplanes = nullptr;
dest->cPlanes = buf->write_s(3, data->cPlanes, data->numCPlanes, sizeof cplane_s, &dest_cplanes);
}
if (data->staticModelList)
{
buf->align(3);
auto* static_model = buf->write(data->staticModelList, data->numStaticModels);
for (auto i = 0; i < data->numStaticModels; i++)
{
if (data->staticModelList[i].xmodel)
{
static_model[i].xmodel = reinterpret_cast<XModel*>(zone->get_asset_pointer(
xmodel, data->staticModelList[i].xmodel->name));
}
}
ZoneBuffer::clear_pointer(&data->staticModelList);
}
if (data->materials)
{
dmaterial_t* dmaterial;
dest->materials = buf->write_s(3, data->materials, data->numMaterials, sizeof dmaterial_t, &dmaterial);
if (dest->materials == reinterpret_cast<dmaterial_t*>(-1))
{
for (auto i = 0; i < data->numMaterials; i++)
{
if (data->materials[i].material)
{
dmaterial[i].material = buf->write_str(data->materials[i].material);
}
}
}
}
if (data->cBrushSides)
{
cbrushside_t* brush_side;
dest->cBrushSides = buf->write_s(3, data->cBrushSides, data->numCBrushSides, sizeof cbrushside_t,
&brush_side);
if (dest->cBrushSides == reinterpret_cast<cbrushside_t*>(-1))
{
for (auto i = 0; i < data->numCBrushSides; i++)
{
if (data->cBrushSides[i].plane)
{
// should use zone pointer, no need to convert
brush_side[i].plane = buf->write_s(3, data->cBrushSides[i].plane);
}
if (zone->get_target() != zone_target::pc)
{
endian_convert(&brush_side[i].plane);
endian_convert(&brush_side[i].materialNum);
}
}
}
}
if (data->cBrushEdges)
{
dest->cBrushEdges = buf->write_s(0, data->cBrushEdges, data->numCBrushEdges);
}
if (data->cNodes)
{
buf->align(3);
auto* node = buf->write(data->cNodes, data->numCNodes);
for (auto i = 0; i < data->numCNodes; i++)
{
if (data->cNodes[i].plane)
{
// should use zone pointer, no need to convert
node[i].plane = buf->write_s(3, data->cNodes[i].plane);
}
}
ZoneBuffer::clear_pointer(&dest->cNodes);
}
if (data->cLeaf)
{
buf->align(3);
auto* dest_leaf = buf->write(data->cLeaf, data->numCLeaf);
ZoneBuffer::clear_pointer(&dest->cLeaf);
}
if (data->leafBrushes)
{
short* dest_leaf_brushes = nullptr;
dest->leafBrushes = buf->write_s(1, data->leafBrushes, data->numLeafBrushes, sizeof (short), &dest_leaf_brushes);
}
if (data->cLeafBrushNodes)
{
cLeafBrushNode_s* leaf_brush_node = nullptr;
dest->cLeafBrushNodes = buf->write_s(3, data->cLeafBrushNodes, data->numCLeafBrushNodes,
sizeof cLeafBrushNode_s, &leaf_brush_node);
if (dest->cLeafBrushNodes == reinterpret_cast<cLeafBrushNode_s*>(-1))
{
for (auto i = 0; i < data->numCLeafBrushNodes; i++)
{
if (data->cLeafBrushNodes[i].leafBrushCount > 0 && data->cLeafBrushNodes[i].data.leaf.brushes)
{
unsigned short* dest_leaf_brushes = nullptr;
leaf_brush_node[i].data.leaf.brushes = buf->write_s(
1, data->cLeafBrushNodes[i].data.leaf.brushes, data->cLeafBrushNodes[i].leafBrushCount, sizeof (unsigned short), &dest_leaf_brushes);
}
}
}
}
if (data->verts)
{
buf->align(3);
auto* dest_verts = buf->write(data->verts, data->numVerts);
ZoneBuffer::clear_pointer(&dest->verts);
}
if (data->triIndices)
{
buf->align(1);
auto* dest_tri_indices = buf->write(data->triIndices, data->numTriIndices * 3);
ZoneBuffer::clear_pointer(&dest->triIndices);
}
if (data->triEdgeIsWalkable)
{
buf->align(0);
buf->write(data->triEdgeIsWalkable, 4 * ((3 * data->numTriIndices + 31) >> 5));
ZoneBuffer::clear_pointer(&dest->triEdgeIsWalkable);
}
if (data->collisionBorders)
{
buf->align(3);
auto* dest_borders = buf->write_p(data->collisionBorders, data->numCollisionBorders);
ZoneBuffer::clear_pointer(&dest->collisionBorders);
}
if (data->collisionPartitions)
{
buf->align(3);
auto* collision_partition = buf->write(data->collisionPartitions, data->numCollisionPartitions);
for (auto i = 0; i < data->numCollisionPartitions; i++)
{
if (data->collisionPartitions[i].borders)
{
collision_partition[i].borders = buf->write_s(3, data->collisionPartitions[i].borders);
}
}
ZoneBuffer::clear_pointer(&dest->collisionPartitions);
}
if (data->collisionAABBTrees)
{
buf->align(15);
auto* dest_aabb_trees = buf->write(data->collisionAABBTrees, data->numCollisionAABBTrees);
ZoneBuffer::clear_pointer(&dest->collisionAABBTrees);
}
if (data->cModels)
{
buf->align(3);
auto* dest_c_models = buf->write(data->cModels, data->numCModels);
ZoneBuffer::clear_pointer(&dest->cModels);
}
// brushes
if (data->brushes)
{
cbrush_t* brush = nullptr;
dest->brushes = buf->write_s(127, data->brushes, data->numBrushes, sizeof cbrush_t, &brush);
if (dest->brushes == reinterpret_cast<cbrush_t*>(-1))
{
for (auto i = 0; i < data->numBrushes; i++)
{
if (data->brushes[i].sides)
{
cbrushside_t* side = nullptr;
brush[i].sides = buf->write_s(3, data->brushes[i].sides, 1, sizeof cbrushside_t, &side);
if (brush[i].sides == reinterpret_cast<cbrushside_t*>(-1) && side)
{
if (side->plane)
{
// should use zone pointer
side->plane = buf->write_s(3, side->plane);
}
}
}
if (data->brushes[i].edge)
{
// should use zone pointer
brush[i].edge = buf->write_s(0, data->brushes[i].edge);
}
}
}
}
// brushBounds
if (data->brushBounds)
{
Bounds* dest_bounds = nullptr;
dest->brushBounds = buf->write_s(127, data->brushBounds, data->numBrushes, sizeof Bounds, &dest_bounds);
}
// brushContents
if (data->brushContents)
{
int* destBrushContents = nullptr;
dest->brushContents = buf->write_s(3, data->brushContents, data->numBrushes, sizeof (int), &destBrushContents);
}
if (data->smodelNodes)
{
buf->align(3);
auto* dest_smodels = buf->write(data->smodelNodes, data->smodelNodeCount);
ZoneBuffer::clear_pointer(&dest->smodelNodes);
}
if (data->mapEnts)
{
dest->mapEnts = reinterpret_cast<MapEnts*>(zone->get_asset_pointer(map_ents, this->name()));
}
if (data->dynEntDefList[0])
{
buf->align(3);
auto* dyn_entity_def = buf->write(data->dynEntDefList[0], data->dynEntCount[0]);
for (std::uint16_t i = 0; i < data->dynEntCount[0]; i++)
{
if (data->dynEntDefList[0][i].xModel)
{
dyn_entity_def[i].xModel = reinterpret_cast<XModel*>(zone->get_asset_pointer(
xmodel, data->dynEntDefList[0][i].xModel->name));
}
if (data->dynEntDefList[0][i].destroyFx)
{
// dyn_entity_def[i].destroyFx = reinterpret_cast<FxEffectDef*>(zone->GetAssetPointer(fx, data->dynEntDefList[0][i].destroyFx->name));
}
if (data->dynEntDefList[0][i].physPreset)
{
dyn_entity_def[i].physPreset = reinterpret_cast<PhysPreset*>(zone->get_asset_pointer(
physpreset, data->dynEntDefList[0][i].physPreset->name));
}
/*if (data->dynEntDefList[0][i].hinge)
{
dyn_entity_def[i].hinge = buf->write_s(3, dyn_entity_def[i].hinge, 1);
}*/
}
ZoneBuffer::clear_pointer(&dest->dynEntDefList[0]);
}
if (data->dynEntDefList[1])
{
buf->align(3);
auto* dyn_entity_def = buf->write(data->dynEntDefList[1], data->dynEntCount[1]);
for (std::uint16_t i = 0; i < data->dynEntCount[1]; i++)
{
if (data->dynEntDefList[1][i].xModel)
{
dyn_entity_def[i].xModel = reinterpret_cast<XModel*>(zone->get_asset_pointer(
xmodel, data->dynEntDefList[1][i].xModel->name));
}
if (data->dynEntDefList[1][i].destroyFx)
{
// dyn_entity_def[i].destroyFx = reinterpret_cast<FxEffectDef*>(zone->GetAssetPointer(fx, data->dynEntDefList[1][i].destroyFx->name));
}
if (data->dynEntDefList[1][i].physPreset)
{
dyn_entity_def[i].physPreset = reinterpret_cast<PhysPreset*>(zone->get_asset_pointer(
physpreset, data->dynEntDefList[1][i].physPreset->name));
}
/*if (data->dynEntDefList[1][i].hinge)
{
dyn_entity_def[i].hinge = buf->write_s(3, dyn_entity_def[i].hinge, 1);
}*/
}
ZoneBuffer::clear_pointer(&dest->dynEntDefList[1]);
}
buf->push_stream(2);
if (data->dynEntPoseList[0])
{
buf->align(3);
buf->write(data->dynEntPoseList[0], data->dynEntCount[0]);
ZoneBuffer::clear_pointer(&dest->dynEntPoseList[0]);
}
if (data->dynEntPoseList[1])
{
buf->align(3);
buf->write(data->dynEntPoseList[1], data->dynEntCount[1]);
ZoneBuffer::clear_pointer(&dest->dynEntPoseList[1]);
}
if (data->dynEntClientList[0])
{
buf->align(3);
buf->write(data->dynEntClientList[0], data->dynEntCount[0]);
ZoneBuffer::clear_pointer(&dest->dynEntClientList[0]);
}
if (data->dynEntClientList[1])
{
buf->align(3);
buf->write(data->dynEntClientList[1], data->dynEntCount[1]);
ZoneBuffer::clear_pointer(&dest->dynEntClientList[1]);
}
if (data->dynEntCollList[0])
{
buf->align(3);
buf->write(data->dynEntCollList[0], data->dynEntCount[0]);
ZoneBuffer::clear_pointer(&dest->dynEntCollList[0]);
}
if (data->dynEntCollList[1])
{
buf->align(3);
buf->write(data->dynEntCollList[1], data->dynEntCount[1]);
ZoneBuffer::clear_pointer(&dest->dynEntCollList[1]);
}
buf->pop_stream();
END_LOG_STREAM;
buf->pop_stream();
}
void IClipMap::dump(clipMap_t* asset)
{
auto* iw5_clipmap = new IW5::clipMap_t;
memset(iw5_clipmap, 0, sizeof IW5::clipMap_t);
// convert clipmap to IW5 format
iw5_clipmap->name = asset->name;
iw5_clipmap->isInUse = asset->isInUse;
iw5_clipmap->info.numCPlanes = asset->numCPlanes;
iw5_clipmap->info.cPlanes = (IW5::cplane_s*)asset->cPlanes;
iw5_clipmap->numStaticModels = asset->numStaticModels;
iw5_clipmap->staticModelList = (IW5::cStaticModel_s*)asset->staticModelList;
iw5_clipmap->info.numMaterials = asset->numMaterials;
iw5_clipmap->info.materials = (IW5::dmaterial_t*)asset->materials;
iw5_clipmap->info.numCBrushSides = asset->numCBrushSides;
iw5_clipmap->info.cBrushSides = (IW5::cbrushside_t*)asset->cBrushSides;
iw5_clipmap->info.numCBrushEdges = asset->numCBrushEdges;
iw5_clipmap->info.cBrushEdges = (IW5::cbrushedge_t*)asset->cBrushEdges;
iw5_clipmap->numCNodes = asset->numCNodes;
iw5_clipmap->cNodes = (IW5::cNode_t*)asset->cNodes;
iw5_clipmap->numCLeaf = asset->numCLeaf;
iw5_clipmap->cLeaf = (IW5::cLeaf_t*)asset->cLeaf;
iw5_clipmap->info.numCLeafBrushNodes = asset->numCLeafBrushNodes;
iw5_clipmap->info.cLeafBrushNodes = (IW5::cLeafBrushNode_s*)asset->cLeafBrushNodes;
iw5_clipmap->info.numLeafBrushes = asset->numLeafBrushes;
iw5_clipmap->info.leafBrushes = asset->leafBrushes;
// leafSurfaces todo!
iw5_clipmap->numVerts = asset->numVerts;
iw5_clipmap->verts = (IW5::VecInternal<3>*)asset->verts;
iw5_clipmap->numTriIndices = asset->numTriIndices;
iw5_clipmap->triIndices = asset->triIndices;
iw5_clipmap->triEdgeIsWalkable = asset->triEdgeIsWalkable;
iw5_clipmap->numCollisionBorders = asset->numCollisionBorders;
iw5_clipmap->collisionBorders = (IW5::CollisionBorder*)asset->collisionBorders;
iw5_clipmap->numCollisionPartitions = asset->numCollisionPartitions;
iw5_clipmap->collisionPartitions = (IW5::CollisionPartition*)asset->collisionPartitions;
iw5_clipmap->numCollisionAABBTrees = asset->numCollisionAABBTrees;
iw5_clipmap->collisionAABBTrees = (IW5::CollisionAabbTree*)asset->collisionAABBTrees;
// cmodels!
iw5_clipmap->numCModels = asset->numCModels;
iw5_clipmap->cModels = new IW5::cmodel_t[iw5_clipmap->numCModels];
memset(iw5_clipmap->cModels, 0, sizeof(IW5::cmodel_t) * iw5_clipmap->numCModels);
for (int i = 0; i < iw5_clipmap->numCModels; i++)
{
memcpy(iw5_clipmap->cModels[i]._portpad0, asset->cModels[i]._portpad0, 28);
memcpy(iw5_clipmap->cModels[i]._portpad1, asset->cModels[i]._portpad1, 40);
}
iw5_clipmap->info.numBrushes = asset->numBrushes;
iw5_clipmap->info.brushes = (IW5::cbrush_t*)asset->brushes;
iw5_clipmap->info.brushBounds = (IW5::Bounds*)asset->brushBounds;
iw5_clipmap->info.brushContents = asset->brushContents;
iw5_clipmap->mapEnts = (IW5::MapEnts*)asset->mapEnts;
iw5_clipmap->stageCount = asset->mapEnts->stageCount;
iw5_clipmap->stages = (IW5::Stage*)asset->mapEnts->stageNames;
iw5_clipmap->smodelNodeCount = asset->smodelNodeCount;
iw5_clipmap->smodelNodes = (IW5::SModelAabbNode*)asset->smodelNodes;
// dump clipmap
IW5::IClipMap::dump(iw5_clipmap);
// free memory_
delete[] iw5_clipmap->cModels;
delete iw5_clipmap;
}
}
}

View File

@ -0,0 +1,35 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IClipMap : public IAsset
{
private:
std::string name_;
clipMap_t* asset_ = nullptr;
public:
clipMap_t* parse(const std::string& name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(clipMap_t* asset);
};
}
}

131
src/IW4/Assets/ComWorld.cpp Normal file
View File

@ -0,0 +1,131 @@
// ======================= 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/ComWorld.hpp"
namespace ZoneTool
{
namespace IW4
{
ComWorld* IComWorld::parse(const std::string& name, ZoneMemory* mem)
{
auto* iw5_comworld = IW5::IComWorld::parse(name, mem);
if (!iw5_comworld)
{
return nullptr;
}
// fixup data
auto* light_array = mem->Alloc<ComPrimaryLight>(iw5_comworld->primaryLightCount);
// convert structure
for (auto i = 0u; i < iw5_comworld->primaryLightCount; i++)
{
memcpy(light_array[i]._portpad0, iw5_comworld->primaryLights[i]._portpad0, 28);
memcpy(light_array[i]._portpad1, iw5_comworld->primaryLights[i]._portpad1, 40);
}
// set pointer
iw5_comworld->primaryLights = (IW5::ComPrimaryLight*)light_array;
// asset is the exact same so just cast to the correct type here
return (ComWorld*)iw5_comworld;
}
void IComWorld::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".d3dbsp"; // name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), name.data()).comworld;
}
}
void IComWorld::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IComWorld::load_depending(IZone* zone)
{
auto* asset = this->asset_;
for (auto i = 0u; i < asset->primaryLightCount; i++)
{
if (asset->primaryLights[i].defName)
{
zone->add_asset_of_type(lightdef, asset->primaryLights[i].defName);
}
}
}
std::string IComWorld::name()
{
return this->name_;
}
std::int32_t IComWorld::type()
{
return com_map;
}
void IComWorld::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
dest->name = buf->write_str(this->name());
if (data->primaryLights)
{
buf->align(3);
auto* primary_light = buf->write(data->primaryLights, data->primaryLightCount);
for (auto i = 0u; i < data->primaryLightCount; i++)
{
if (data->primaryLights[i].defName)
{
primary_light[i].defName = buf->write_str(data->primaryLights[i].defName);
}
}
}
buf->pop_stream();
}
void IComWorld::dump(ComWorld* asset)
{
// alloc comworld
auto* iw5_comworld = new IW5::ComWorld;
memcpy(iw5_comworld, asset, sizeof ComWorld);
// alloc lights
iw5_comworld->primaryLights = new IW5::ComPrimaryLight[iw5_comworld->primaryLightCount];
memset(iw5_comworld->primaryLights, 0, sizeof(IW5::ComPrimaryLight) * iw5_comworld->primaryLightCount);
// copy data
for (unsigned int i = 0; i < iw5_comworld->primaryLightCount; i++)
{
memcpy(iw5_comworld->primaryLights[i]._portpad0, asset->primaryLights[i]._portpad0, 28);
memcpy(iw5_comworld->primaryLights[i]._portpad1, asset->primaryLights[i]._portpad1, 40);
}
// dump comworld
IW5::IComWorld::dump(iw5_comworld);
// free memory_
delete[] iw5_comworld->primaryLights;
delete[] iw5_comworld;
}
}
}

View File

@ -0,0 +1,35 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IComWorld : public IAsset
{
private:
std::string name_;
ComWorld* asset_ = nullptr;
public:
ComWorld* parse(const std::string& name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(ComWorld* asset);
};
}
}

101
src/IW4/Assets/FontDef.cpp Normal file
View File

@ -0,0 +1,101 @@
// ======================= 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/FontDef.hpp"
namespace ZoneTool
{
namespace IW4
{
void IFontDef::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()).font;
}
}
void IFontDef::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IFontDef::load_depending(IZone* zone)
{
auto* data = this->asset_;
if (data->material)
{
zone->add_asset_of_type(material, data->material->name);
}
if (data->glowMaterial)
{
zone->add_asset_of_type(material, data->glowMaterial->name);
}
}
std::string IFontDef::name()
{
return this->name_;
}
std::int32_t IFontDef::type()
{
return font;
}
void IFontDef::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->fontName = buf->write_str(this->name());
if (data->material)
{
dest->material = reinterpret_cast<Material*>(
zone->get_asset_pointer(material, data->material->name)
);
}
if (data->glowMaterial)
{
dest->glowMaterial = reinterpret_cast<Material*>(
zone->get_asset_pointer(material, data->glowMaterial->name)
);
}
if (data->glyphs)
{
buf->align(3);
auto* dest_glyphs = buf->write(data->glyphs, data->glyphCount);
ZoneBuffer::clear_pointer(&dest->glyphs);
}
END_LOG_STREAM;
buf->pop_stream();
}
Font_s* IFontDef::parse(const std::string& name, ZoneMemory* mem)
{
return reinterpret_cast<Font_s*>(IW5::IFontDef::parse(name, mem));
}
void IFontDef::dump(Font_s* asset)
{
IW5::IFontDef::dump(reinterpret_cast<IW5::Font_s*>(asset));
}
}
}

View File

@ -0,0 +1,34 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IFontDef : public IAsset
{
private:
std::string name_;
Font_s* asset_ = nullptr;
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(Font_s* asset);
static Font_s* parse(const std::string& name, ZoneMemory* mem);
};
}
}

View File

@ -0,0 +1,403 @@
// ======================= 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;
}
}
}

View File

@ -0,0 +1,41 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IFxEffectDef : public IAsset
{
private:
std::string name_;
FxEffectDef* asset_ = nullptr;
static void write_fx_elem_def_visuals(IZone* zone, ZoneBuffer* buf, FxElemDef* def,
FxElemDefVisuals* dest);
static void write_fx_elem_def(IZone* zone, ZoneBuffer* buf, FxElemDef* dest);
static void write_fx_elem_visuals(IZone* zone, ZoneBuffer* buf, FxElemDef* def,
FxElemVisuals* dest);
FxEffectDef* parse(const std::string& name, ZoneMemory* mem);
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(FxEffectDef* asset);
};
}
}

209
src/IW4/Assets/FxWorld.cpp Normal file
View File

@ -0,0 +1,209 @@
// ======================= 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/FxWorld.hpp"
namespace ZoneTool
{
namespace IW4
{
FxWorld* IFxWorld::parse(const std::string& name, ZoneMemory* mem)
{
auto* iw5_fxworld = IW5::IFxWorld::parse(name, mem);
if (!iw5_fxworld)
{
return nullptr;
}
// asset is actually the same so just cast
return reinterpret_cast<FxWorld*>(iw5_fxworld);
}
void IFxWorld::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".d3dbsp"; // name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), name.data()).fxworld;
}
}
void IFxWorld::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IFxWorld::load_depending(IZone* zone)
{
auto* data = this->asset_;
if (data->glassSys.defs)
{
for (unsigned int i = 0; i < data->glassSys.defCount; i++)
{
if (data->glassSys.defs[i].physPreset)
{
zone->add_asset_of_type(physpreset, data->glassSys.defs[i].physPreset->name);
}
if (data->glassSys.defs[i].material)
{
zone->add_asset_of_type(material, data->glassSys.defs[i].material->name);
}
if (data->glassSys.defs[i].materialShattered)
{
zone->add_asset_of_type(material, data->glassSys.defs[i].materialShattered->name);
}
}
}
}
std::string IFxWorld::name()
{
return this->name_;
}
std::int32_t IFxWorld::type()
{
return fx_map;
}
void IFxWorld::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->glassSys.defs)
{
buf->align(3);
auto* glass_def = buf->write(data->glassSys.defs, data->glassSys.defCount);
for (std::uint32_t i = 0; i < data->glassSys.defCount; i++)
{
if (data->glassSys.defs[i].physPreset)
{
glass_def[i].physPreset = reinterpret_cast<PhysPreset*>(zone->get_asset_pointer(
physpreset, data->glassSys.defs[i].physPreset->name));
}
if (data->glassSys.defs[i].material)
{
glass_def[i].material = reinterpret_cast<Material*>(zone->get_asset_pointer(
material, data->glassSys.defs[i].material->name));
}
if (data->glassSys.defs[i].materialShattered)
{
glass_def[i].materialShattered = reinterpret_cast<Material*>(zone->get_asset_pointer(
material, data->glassSys.defs[i].materialShattered->name));
}
}
ZoneBuffer::clear_pointer(&dest->glassSys.defs);
}
buf->push_stream(2);
if (data->glassSys.piecePlaces)
{
buf->align(3);
buf->write(data->glassSys.piecePlaces, data->glassSys.pieceLimit);
ZoneBuffer::clear_pointer(&dest->glassSys.piecePlaces);
}
if (data->glassSys.pieceStates)
{
buf->align(3);
buf->write(data->glassSys.pieceStates, data->glassSys.pieceLimit);
ZoneBuffer::clear_pointer(&dest->glassSys.pieceStates);
}
if (data->glassSys.pieceDynamics)
{
buf->align(3);
buf->write(data->glassSys.pieceDynamics, data->glassSys.pieceLimit);
ZoneBuffer::clear_pointer(&dest->glassSys.pieceDynamics);
}
if (data->glassSys.geoData)
{
buf->align(3);
buf->write(data->glassSys.geoData, data->glassSys.geoDataLimit);
ZoneBuffer::clear_pointer(&dest->glassSys.geoData);
}
if (data->glassSys.isInUse)
{
buf->align(3);
buf->write(data->glassSys.isInUse, data->glassSys.pieceWordCount);
ZoneBuffer::clear_pointer(&dest->glassSys.isInUse);
}
if (data->glassSys.cellBits)
{
buf->align(3);
buf->write(data->glassSys.cellBits, data->glassSys.pieceWordCount * data->glassSys.cellCount);
ZoneBuffer::clear_pointer(&dest->glassSys.cellBits);
}
if (data->glassSys.visData)
{
buf->align(15);
buf->write(data->glassSys.visData, (data->glassSys.pieceLimit + 15) & 0xFFFFFFF0);
ZoneBuffer::clear_pointer(&dest->glassSys.visData);
}
if (data->glassSys.linkOrg)
{
buf->align(3);
buf->write(data->glassSys.linkOrg, data->glassSys.pieceLimit);
ZoneBuffer::clear_pointer(&dest->glassSys.linkOrg);
}
if (data->glassSys.halfThickness)
{
buf->align(15);
buf->write(data->glassSys.halfThickness, (data->glassSys.pieceLimit + 3) & 0xFFFFFFFC);
ZoneBuffer::clear_pointer(&dest->glassSys.halfThickness);
}
buf->pop_stream();
if (data->glassSys.lightingHandles)
{
buf->align(1);
buf->write(data->glassSys.lightingHandles, data->glassSys.initPieceCount);
ZoneBuffer::clear_pointer(&dest->glassSys.lightingHandles);
}
if (data->glassSys.initPieceStates)
{
buf->align(3);
buf->write(data->glassSys.initPieceStates, data->glassSys.initPieceCount);
ZoneBuffer::clear_pointer(&dest->glassSys.initPieceStates);
}
if (data->glassSys.initGeoData)
{
buf->align(3);
buf->write(data->glassSys.initGeoData, data->glassSys.initGeoDataCount);
ZoneBuffer::clear_pointer(&dest->glassSys.initGeoData);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IFxWorld::dump(FxWorld* asset)
{
IW5::IFxWorld::dump((IW5::FxWorld*)asset);
}
}
}

View File

@ -0,0 +1,35 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IFxWorld : public IAsset
{
private:
std::string name_;
FxWorld* asset_ = nullptr;
FxWorld* parse(const std::string& name, ZoneMemory* mem);
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(FxWorld* asset);
};
}
}

View File

@ -0,0 +1,26 @@
// ======================= 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/GlassWorld.hpp"
namespace ZoneTool
{
namespace IW4
{
std::int32_t IGameWorldMp::type()
{
return game_map_mp;
}
void IGameWorldMp::dump(GameWorldMp* asset)
{
IGlassWorld::dump(reinterpret_cast<IW5::GlassWorld*>(asset));
}
}
}

View File

@ -0,0 +1,24 @@
// ======================= 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
// ========================================================
#pragma once
#include "../IW5/Assets/GlassWorld.hpp"
namespace ZoneTool
{
namespace IW4
{
class IGameWorldMp : public IW5::IGlassWorld
{
public:
std::int32_t type() override;
static void dump(GameWorldMp* asset);
};
}
}

View File

@ -0,0 +1,119 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
void IGameWorldSp::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".d3dbsp";
auto* mp_asset = IGameWorldMp::parse(name, mem);
if (!mp_asset)
{
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).game_map_sp;
}
else
{
// generate sp asset based on mp one
this->asset_ = mem->Alloc<GameWorldSp>();
this->asset_->name = mp_asset->name;
this->asset_->g_glassData = reinterpret_cast<G_GlassData*>(mp_asset->g_glassData);
}
}
void IGameWorldSp::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IGameWorldSp::load_depending(IZone* zone)
{
}
std::string IGameWorldSp::name()
{
return this->name_;
}
void IGameWorldSp::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
assert(sizeof GameWorldSp, 56);
assert(sizeof G_GlassData, 128);
assert(sizeof G_GlassPiece, 12);
assert(sizeof G_GlassName, 12);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
if (data->g_glassData)
{
buf->align(3);
auto* glass_data = data->g_glassData;
auto* dest_glass_data = buf->write(glass_data);
if (glass_data->glassPieces)
{
buf->align(3);
buf->write(glass_data->glassPieces, glass_data->pieceCount);
ZoneBuffer::clear_pointer(&dest_glass_data->glassPieces);
}
if (glass_data->glassNames)
{
buf->align(3);
const auto namedest = buf->write(glass_data->glassNames, glass_data->glassNameCount);
for (unsigned int i = 0; i < glass_data->glassNameCount; i++)
{
namedest[i].nameStr = buf->write_str(glass_data->glassNames[i].nameStr);
if (glass_data->glassNames[i].pieceCount)
{
buf->align(1);
buf->write(glass_data->glassNames[i].pieceIndices, glass_data->glassNames[i].pieceCount);
ZoneBuffer::clear_pointer(&glass_data->glassNames[i].pieceIndices);
}
}
ZoneBuffer::clear_pointer(&dest_glass_data->glassNames);
}
ZoneBuffer::clear_pointer(&dest->g_glassData);
}
END_LOG_STREAM;
buf->pop_stream();
}
std::int32_t IGameWorldSp::type()
{
return game_map_sp;
}
void IGameWorldSp::dump(GameWorldSp* asset)
{
auto* mp_asset = new GameWorldMp;
memset(mp_asset, 0, sizeof GameWorldMp);
mp_asset->name = asset->name;
mp_asset->g_glassData = asset->g_glassData;
IGameWorldMp::dump(mp_asset);
delete mp_asset;
}
}
}

View File

@ -0,0 +1,35 @@
// ======================= 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
// ========================================================
#pragma once
#include "../IW5/Assets/GlassWorld.hpp"
namespace ZoneTool
{
namespace IW4
{
class IGameWorldSp : public IAsset
{
private:
std::string name_;
GameWorldSp* asset_ = nullptr;
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(GameWorldSp* asset);
};
}
}

423
src/IW4/Assets/GfxImage.cpp Normal file
View File

@ -0,0 +1,423 @@
// ======================= 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/GfxImage.hpp"
namespace ZoneTool
{
namespace IW4
{
std::string IGfxImage::clean_name(const std::string& name)
{
auto newName = name;
for (auto i = 0u; i < name.size(); i++)
{
switch (newName[i])
{
case '*':
newName[i] = '_';
break;
}
}
return newName;
}
GfxImage* IGfxImage::parse(const std::string& name, ZoneMemory* mem)
{
auto path = "images\\" + this->clean_name(name) + ".ffimg";
if (!FileSystem::FileExists(path))
{
return nullptr;
}
auto fp = FileSystem::FileOpen(path, "rb");
if (!fp)
{
return nullptr;
}
ZONETOOL_INFO("Parsing GfxImage \"%s\"...", name.data());
auto reader = FileSystem::ToReader(fp);
auto img = mem->Alloc<GfxImage>();
img->mapType = reader->Read<char>();
img->semantic = reader->Read<char>();
img->category = reader->Read<char>();
img->flags = reader->Read<char>();
img->cardMemory = reader->Read<int>();
img->dataLen1 = reader->Read<int>();
img->dataLen2 = reader->Read<int>();
img->height = reader->Read<int>();
img->width = reader->Read<int>();
img->depth = reader->Read<int>();
img->loaded = reader->Read<char>();
img->name = mem->StrDup(reader->ReadString());
auto loaddef = mem->Alloc<GfxImageLoadDef>();
loaddef->mipLevels = reader->Read<char>();
loaddef->flags = reader->Read<char>();
loaddef->dimensions[0] = reader->Read<int>();
loaddef->dimensions[1] = reader->Read<int>();
loaddef->dimensions[2] = reader->Read<int>();
loaddef->format = reader->Read<int>();
loaddef->dataSize = reader->Read<int>();
GfxImageLoadDef* finalLoaddef = nullptr;
if (loaddef->dataSize > 4)
{
finalLoaddef = mem->ManualAlloc<GfxImageLoadDef>(
sizeof GfxImageLoadDef +
(loaddef->dataSize - 4));
memcpy(finalLoaddef, loaddef, sizeof GfxImageLoadDef);
reader->ReadManual(&finalLoaddef->texture, loaddef->dataSize, 1);
}
else
{
finalLoaddef = loaddef;
}
img->texture = finalLoaddef;
FileSystem::FileClose(fp);
return img;
}
void IGfxImage::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = this->parse(name, mem);
this->isMapImage = (this->name_.size() >= 6)
? ((this->name_.substr(0, 6) == "*light" || this->name_.substr(0, 6) == "*refle" ||
this->name_ == "$outdoor")
? true
: false)
: false;
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), this->name_.data()).gfximage;
}
}
void IGfxImage::init(void* asset, ZoneMemory* mem)
{
this->asset_ = reinterpret_cast<GfxImage*>(asset);
this->name_ = this->asset_->name;
this->isMapImage = (this->name_.size() >= 6)
? ((this->name_.substr(0, 6) == "*light" || this->name_.substr(0, 6) == "*refle" ||
this->name_ == "$outdoor")
? true
: false)
: false;
auto parsed = this->parse(this->name_, mem);
if (parsed)
{
this->asset_ = parsed;
}
}
void IGfxImage::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IGfxImage::load_depending(IZone* zone)
{
}
std::string IGfxImage::name()
{
return this->name_;
}
std::int32_t IGfxImage::type()
{
return image;
}
void IGfxImage::write(IZone* zone, ZoneBuffer* buf)
{
if (zone->get_target() == zone_target::pc)
{
IW5::IGfxImage::dump_iwi(this->name());
auto data = this->asset_;
auto dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
// set loaded to false
dest->loaded = false;
buf->push_stream(0);
if (data->texture)
{
buf->align(3);
auto desttext = buf->at<GfxImageLoadDef>();
buf->write_stream(data->texture, sizeof GfxImageLoadDef - sizeof std::uintptr_t);
if (isMapImage && desttext->dataSize)
{
buf->write_stream(&data->texture->texture, data->texture->dataSize);
}
else
{
desttext->dataSize = 0;
}
ZoneBuffer::clear_pointer(&dest->texture);
}
buf->pop_stream();
END_LOG_STREAM;
buf->pop_stream();
}
else
{
alpha::GfxImage alpha_image = {};
// transform iwi
if (!FileSystem::FileExists(va("images/%s.iwi", this->name().data())) && !this->isMapImage)
{
ZONETOOL_FATAL("Image %s is missing!", this->name().data());
}
std::vector<std::uint8_t> pixels;
auto fp = FileSystem::FileOpen(va("images/%s.iwi", this->name().data()), "rb");
if (fp || this->isMapImage)
{
if (!this->isMapImage)
{
auto file_size = FileSystem::FileSize(fp);
auto img_data = FileSystem::ReadBytes(fp, file_size);
auto iwi_header = (GfxImageFileHeader*)img_data.data();
sizeof GfxImageFileHeader;
auto pixel_data = img_data.data() + 32;
auto pixel_data_size = img_data.size() - 32;
pixels.resize(pixel_data_size);
memcpy(&pixels[0], pixel_data, pixel_data_size);
// add image to imagepak
// zone images
alpha_image.cached = false;
alpha_image.cardMemory.platform[0] = pixels.size();
// pakfile images
//alpha_image.cached = true;
//alpha_image.cardMemory.platform[0] = 0;
//alpha_image.streams[0].width = iwi_header->dimensions[0];
//alpha_image.streams[0].height = iwi_header->dimensions[1];
//alpha_image.streams[0].pixelSize = 1;
//buf->add_image(pixels);
alpha_image.format = 0x1A200154;
alpha_image.width = iwi_header->dimensions[0];
alpha_image.height = iwi_header->dimensions[1];
alpha_image.depth = iwi_header->dimensions[2];
alpha_image.levelCount = 1;
alpha_image.mapType = 3;
alpha_image.category = 3;
}
else
{
pixels.resize(this->asset_->texture->dataSize);
memcpy(&pixels[0], &this->asset_->texture->texture, pixels.size());
alpha_image.cached = false;
alpha_image.cardMemory.platform[0] = pixels.size();
if (this->name().starts_with("*refle"))
{
alpha_image.format = 0x18280186;
alpha_image.mapType = 5;
alpha_image.semantic = 1;
alpha_image.category = 1;
}
else if (this->name().starts_with("*light"))
{
alpha_image.format = 0x2800017A;
alpha_image.mapType = 3;
alpha_image.semantic = 1;
alpha_image.category = 2;
}
else if (this->name() == "$outdoor")
{
alpha_image.format = 0x28000102;
alpha_image.mapType = 3;
alpha_image.semantic = 1;
alpha_image.category = 1;
}
else
{
ZONETOOL_FATAL("you goofed");
}
alpha_image.width = this->asset_->width;
alpha_image.height = this->asset_->height;
alpha_image.depth = this->asset_->depth;
alpha_image.levelCount = 1;
}
}
else
{
ZONETOOL_FATAL("Cannot open image %s!", this->name().data());
}
auto data = &alpha_image;
auto dest = buf->write(data);
buf->push_stream(3);
dest->name = buf->write_str(this->name());
buf->push_stream(1);
if (data->cardMemory.platform[0])
{
buf->align(4095);
buf->write(pixels.data(), pixels.size());
ZoneBuffer::clear_pointer(&dest->pixels);
}
else
{
dest->pixels = nullptr;
}
buf->pop_stream();
buf->pop_stream();
endian_convert(&dest->name);
endian_convert(&dest->format);
endian_convert(&dest->width);
endian_convert(&dest->height);
endian_convert(&dest->depth);
endian_convert(&dest->pixels);
endian_convert(&dest->cardMemory.platform[0]);
for (auto i = 0; i < 4; i++)
{
endian_convert(&dest->streams[i].width);
endian_convert(&dest->streams[i].height);
endian_convert(&dest->streams[i].pixelSize);
}
}
}
// Legacy cancer code
void fwritestr(FILE* file, const char* str)
{
if (!str)
return;
while (*str)
{
fwrite(str, 1, 1, file);
str++;
}
fwrite(str, 1, 1, file);
}
void fwriteint(FILE* file, int value)
{
int _val = value;
fwrite(&_val, 4, 1, file);
}
void fwriteuint(FILE* file, unsigned int value)
{
unsigned int _val = value;
fwrite(&_val, 4, 1, file);
}
void fwritechar(FILE* file, char c)
{
char _val = c;
fwrite(&_val, 1, 1, file);
}
char cleanAssetName[50];
char* ClearAssetName(char* name, int maxSize = 50)
{
int size = strnlen(name, maxSize);
char* newName = cleanAssetName;
memset(newName, 0, size + 1);
strncpy(newName, name, maxSize);
for (int i = 0; i < size; i++)
{
switch (newName[i])
{
case '*':
newName[i] = '_';
break;
}
}
return newName;
}
void IGfxImage::dump(GfxImage* asset)
{
if (asset->texture && asset->texture->dataSize)
{
char* newName = ClearAssetName((char*)asset->name);
auto fp = FileSystem::FileOpen("images/"s + newName + ".ffImg"s, "wb");
if (!fp) return;
#define fwstr(_str) fwritestr(fp, _str)
#define fwint(_int) fwriteint(fp, _int)
#define fwchr(_chr) fwritechar(fp, _chr)
#define frstr() freadstr(fp)
#define frint() freadint(fp)
#define frchr() freadchar(fp)
// Header
fwchr(asset->mapType);
fwchr(asset->semantic);
fwchr(asset->category);
fwchr(asset->flags);
fwint((int)asset->cardMemory);
fwint(asset->dataLen1);
fwint(asset->dataLen2);
fwint(asset->height);
fwint(asset->width);
fwint(asset->depth);
fwstr(asset->name);
// LoadDef
fwchr(asset->texture->mipLevels);
fwchr(asset->texture->flags);
fwint(asset->texture->dimensions[0]);
fwint(asset->texture->dimensions[1]);
fwint(asset->texture->dimensions[2]);
fwint(asset->texture->format);
fwint(asset->texture->dataSize);
fwrite(&asset->texture->texture, 1, asset->texture->dataSize, fp);
FileSystem::FileClose(fp);
}
}
}
}

View File

@ -0,0 +1,40 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IGfxImage : public IAsset
{
private:
std::string name_;
GfxImage* asset_ = nullptr;
bool isMapImage;
std::string clean_name(const std::string& name);
GfxImage* parse(const std::string& name, ZoneMemory* mem);
public:
void init(const std::string& name, ZoneMemory* mem) override;
void init(void* asset, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
void* pointer() override { return asset_; }
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(GfxImage* asset);
};
}
}

850
src/IW4/Assets/GfxWorld.cpp Normal file
View File

@ -0,0 +1,850 @@
// ======================= 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/GfxWorld.hpp"
namespace ZoneTool
{
namespace IW4
{
/*legacy zonetool code, refactor me!*/
GfxWorld* IGfxWorld::parse(const std::string& name, ZoneMemory* mem)
{
auto iw5_gfxmap = IW5::IGfxWorld::parse(name, mem);
if (!iw5_gfxmap)
{
return nullptr;
}
// convert to IW4 format
auto gfxmap = mem->Alloc<GfxWorld>();
// copy struct data
memcpy(&gfxmap->name, &iw5_gfxmap->name, Difference(&gfxmap->cells, &gfxmap->name));
// allocate cells
gfxmap->cells = new GfxCell[gfxmap->dpvsPlanes.cellCount];
memset(gfxmap->cells, 0, sizeof(GfxCell) * gfxmap->dpvsPlanes.cellCount);
// copy cell data
for (int i = 0; i < gfxmap->dpvsPlanes.cellCount; i++)
{
memcpy(&gfxmap->cells[i], &iw5_gfxmap->cells[i], sizeof GfxCell);
}
// copy draw data
memcpy(gfxmap->draw._portpad0, iw5_gfxmap->worldDraw._portpad0, 16);
memcpy(gfxmap->draw._portpad1, iw5_gfxmap->worldDraw._portpad1, 56);
// copy remaining GfxWorld data
memcpy(&gfxmap->lightGrid, &iw5_gfxmap->lightGrid,
Difference(&gfxmap->fogTypesAllowed + 1, &gfxmap->lightGrid));
// return converted gfxmap
return gfxmap;
}
IGfxWorld::IGfxWorld()
{
}
IGfxWorld::~IGfxWorld()
{
}
void IGfxWorld::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".d3dbsp"; // name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), name.data()).gfxworld;
}
}
void IGfxWorld::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IGfxWorld::load_depending(IZone* zone)
{
auto* data = this->asset_;
// Skies
if (data->skyCount)
{
for (unsigned int i = 0; i < data->skyCount; i++)
{
if (data->skies[i].skyImage)
{
zone->add_asset_of_type(image, data->skies[i].skyImage->name);
}
}
}
// ReflectionImages
if (data->draw.reflectionImages)
{
for (unsigned int i = 0; i < data->draw.reflectionProbeCount; i++)
{
if (data->draw.reflectionImages[i])
{
zone->add_asset_of_type(image, data->draw.reflectionImages[i]->name);
}
}
}
// Lightmaps
if (data->draw.lightmaps)
{
for (int i = 0; i < data->draw.lightmapCount; i++)
{
if (data->draw.lightmaps[i].primary)
{
zone->add_asset_of_type(image, data->draw.lightmaps[i].primary->name);
}
if (data->draw.lightmaps[i].secondary)
{
zone->add_asset_of_type(image, data->draw.lightmaps[i].secondary->name);
}
}
}
// SkyImage (Unused?)
if (data->draw.skyImage)
{
zone->add_asset_of_type(image, data->draw.skyImage->name);
}
// OutdoorImage (Unused?)
if (data->draw.outdoorImage)
{
zone->add_asset_of_type(image, data->draw.outdoorImage->name);
}
if (zone->get_target() != zone_target::pc)
{
return;
}
// MaterialMemory
if (data->materialMemory)
{
for (int i = 0; i < data->materialMemoryCount; i++)
{
if (data->materialMemory[i].material)
{
zone->add_asset_of_type(material, data->materialMemory[i].material->name);
}
}
}
// Sunflare_t
if (data->sun.spriteMaterial)
{
zone->add_asset_of_type(material, data->sun.spriteMaterial->name);
}
if (data->sun.flareMaterial)
{
zone->add_asset_of_type(material, data->sun.flareMaterial->name);
}
// OutdoorImage
if (data->outdoorImage)
{
zone->add_asset_of_type(image, data->outdoorImage->name);
}
// Dpvs.Surfaces
if (data->dpvs.surfaces)
{
for (int i = 0; i < data->surfaceCount; i++)
{
if (data->dpvs.surfaces[i].material)
{
zone->add_asset_of_type(material, data->dpvs.surfaces[i].material->name);
}
}
}
if (data->dpvs.smodelDrawInsts)
{
for (unsigned int i = 0; i < data->dpvs.smodelCount; i++)
{
if (data->dpvs.smodelDrawInsts[i].model)
{
zone->add_asset_of_type(xmodel, data->dpvs.smodelDrawInsts[i].model->name);
}
}
}
}
std::string IGfxWorld::name()
{
return this->name_;
}
std::int32_t IGfxWorld::type()
{
return gfx_map;
}
void IGfxWorld::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
if (data->name)
{
dest->name = buf->write_str(this->name());
}
if (data->baseName)
{
dest->baseName = buf->write_str(this->name());
}
if (data->skies)
{
buf->align(3);
auto skiesArray = buf->write(data->skies, data->skyCount);
for (std::uint32_t i = 0; i < data->skyCount; i++)
{
if (data->skies[i].skyStartSurfs)
{
buf->align(3);
buf->write_p(data->skies[i].skyStartSurfs, data->skies[i].skySurfCount);
ZoneBuffer::clear_pointer(&skiesArray[i].skyStartSurfs);
}
if (data->skies[i].skyImage)
{
skiesArray[i].skyImage = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->skies[i].skyImage->name));
}
}
ZoneBuffer::clear_pointer(&dest->skies);
}
if (dest->dpvsPlanes.planes)
{
dest->dpvsPlanes.planes = buf->write_s(3, data->dpvsPlanes.planes, data->planeCount);
}
if (dest->dpvsPlanes.nodes)
{
buf->align(1);
buf->write_p(data->dpvsPlanes.nodes, data->nodeCount);
ZoneBuffer::clear_pointer(&dest->dpvsPlanes.nodes);
}
buf->push_stream(2);
if (dest->dpvsPlanes.sceneEntCellBits)
{
buf->align(3);
buf->write(data->dpvsPlanes.sceneEntCellBits, data->dpvsPlanes.cellCount << 11);
ZoneBuffer::clear_pointer(&dest->dpvsPlanes.sceneEntCellBits);
}
buf->pop_stream();
if (data->aabbTreeCounts)
{
buf->align(3);
buf->write_p(data->aabbTreeCounts, data->dpvsPlanes.cellCount);
ZoneBuffer::clear_pointer(&dest->aabbTreeCounts);
}
if (data->aabbTree)
{
buf->align(127);
auto cell_tree = buf->write_p(data->aabbTree, data->dpvsPlanes.cellCount);
for (std::int32_t i = 0; i < data->dpvsPlanes.cellCount; i++)
{
if (data->aabbTree[i].aabbtree)
{
buf->align(3);
auto gfx_aabb_tree = buf->write_p(data->aabbTree[i].aabbtree,
data->aabbTreeCounts[i].aabbTreeCount);
for (std::int32_t i2 = 0; i2 < data->aabbTreeCounts[i].aabbTreeCount; i2++)
{
if (data->aabbTree[i].aabbtree[i2].smodelIndexes)
{
gfx_aabb_tree[i2].smodelIndexes = buf->write_s(
1, data->aabbTree[i].aabbtree[i2].smodelIndexes,
data->aabbTree[i].aabbtree[i2].smodelIndexCount);
}
}
ZoneBuffer::clear_pointer(&cell_tree[i].aabbtree);
}
}
ZoneBuffer::clear_pointer(&dest->aabbTree);
}
if (data->cells)
{
buf->align(3);
auto gfx_cell = buf->write(data->cells, data->dpvsPlanes.cellCount);
for (std::int32_t i = 0; i < data->dpvsPlanes.cellCount; i++)
{
if (data->cells[i].portals)
{
buf->align(3);
auto gfx_portal = buf->write(data->cells[i].portals, data->cells[i].portalCount);
for (std::int32_t i2 = 0; i2 < data->cells[i].portalCount; i2++)
{
if (data->cells[i].portals[i2].vertices)
{
buf->align(3);
buf->write(data->cells[i].portals[i2].vertices, data->cells[i].portals[i2].vertexCount);
ZoneBuffer::clear_pointer(&gfx_portal[i2].vertices);
}
}
ZoneBuffer::clear_pointer(&gfx_cell[i].portals);
}
if (data->cells[i].reflectionProbes)
{
buf->align(0);
buf->write(data->cells[i].reflectionProbes, data->cells[i].reflectionProbeCount);
ZoneBuffer::clear_pointer(&gfx_cell[i].reflectionProbes);
}
ZoneBuffer::clear_pointer(&dest->cells);
}
}
if (data->draw.reflectionImages)
{
buf->align(3);
auto reflectionProbes = buf->write(data->draw.reflectionImages,
data->draw.reflectionProbeCount);
for (std::uint64_t i = 0; i < data->draw.reflectionProbeCount; i++)
{
if (reflectionProbes[i])
{
reflectionProbes[i] = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->draw.reflectionImages[i]->name));
}
}
ZoneBuffer::clear_pointer(&dest->draw.reflectionImages);
}
if (data->draw.reflectionProbes)
{
buf->align(3);
buf->write(data->draw.reflectionProbes, data->draw.reflectionProbeCount);
ZoneBuffer::clear_pointer(&dest->draw.reflectionProbes);
}
buf->push_stream(2);
if (data->draw.reflectionProbeTextures)
{
buf->align(3);
buf->write(data->draw.reflectionProbeTextures, data->draw.reflectionProbeCount);
ZoneBuffer::clear_pointer(&dest->draw.reflectionProbeTextures);
}
buf->pop_stream();
if (data->draw.lightmaps)
{
buf->align(3);
auto gfx_lightmap_array = buf->write(data->draw.lightmaps, data->draw.lightmapCount);
for (std::int32_t i = 0; i < data->draw.lightmapCount; i++)
{
if (data->draw.lightmaps[i].primary)
{
gfx_lightmap_array[i].primary = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->draw.lightmaps[i].primary->name));
}
if (data->draw.lightmaps[i].secondary)
{
gfx_lightmap_array[i].secondary = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->draw.lightmaps[i].secondary->name));
}
}
ZoneBuffer::clear_pointer(&dest->draw.lightmaps);
}
buf->push_stream(2);
if (data->draw.lightmapPrimaryTextures)
{
buf->align(3);
buf->write_p(data->draw.lightmapPrimaryTextures, data->draw.lightmapCount);
ZoneBuffer::clear_pointer(&dest->draw.lightmapPrimaryTextures);
}
if (data->draw.lightmapSecondaryTextures)
{
buf->align(3);
buf->write_p(data->draw.lightmapSecondaryTextures, data->draw.lightmapCount);
ZoneBuffer::clear_pointer(&dest->draw.lightmapSecondaryTextures);
}
buf->pop_stream();
if (data->draw.skyImage)
{
dest->draw.skyImage = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->draw.skyImage->name));
}
if (data->draw.outdoorImage)
{
dest->draw.outdoorImage = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->draw.outdoorImage->name));
}
if (data->draw.vd.vertices)
{
buf->align(3);
buf->write_p(data->draw.vd.vertices, data->draw.vertexCount);
ZoneBuffer::clear_pointer(&dest->draw.vd.vertices);
}
if (data->draw.vld.data)
{
buf->align(0);
buf->write_p(data->draw.vld.data, data->draw.vertexLayerDataSize);
ZoneBuffer::clear_pointer(&dest->draw.vld.data);
}
if (data->draw.indices)
{
buf->align(1);
buf->write_p(data->draw.indices, data->draw.indexCount);
ZoneBuffer::clear_pointer(&dest->draw.indices);
}
if (data->lightGrid.rowDataStart)
{
buf->align(1);
buf->write_p(data->lightGrid.rowDataStart,
data->lightGrid.maxs[data->lightGrid.rowAxis] - data->lightGrid.mins[data
->lightGrid.rowAxis] +
1);
ZoneBuffer::clear_pointer(&dest->lightGrid.rowDataStart);
}
if (data->lightGrid.rawRowData)
{
buf->align(0);
buf->write_p(data->lightGrid.rawRowData, data->lightGrid.rawRowDataSize);
ZoneBuffer::clear_pointer(&dest->lightGrid.rawRowData);
}
if (data->lightGrid.entries)
{
buf->align(3);
buf->write(data->lightGrid.entries, data->lightGrid.entryCount);
ZoneBuffer::clear_pointer(&dest->lightGrid.entries);
}
if (data->lightGrid.colors)
{
buf->align(3);
buf->write(data->lightGrid.colors, data->lightGrid.colorCount);
ZoneBuffer::clear_pointer(&dest->lightGrid.colors);
}
if (data->models)
{
buf->align(3);
buf->write(data->models, data->modelCount);
ZoneBuffer::clear_pointer(&dest->models);
}
if (data->materialMemory)
{
buf->align(3);
auto memory = buf->write(data->materialMemory, data->materialMemoryCount);
for (std::int32_t i = 0; i < data->materialMemoryCount; i++)
{
memory[i].material = reinterpret_cast<Material*>(zone->get_asset_pointer(
material, data->materialMemory[i].material->name));
}
ZoneBuffer::clear_pointer(&dest->materialMemory);
}
if (data->sun.spriteMaterial)
{
dest->sun.spriteMaterial = reinterpret_cast<Material*>(zone->get_asset_pointer(
material, data->sun.spriteMaterial->name));
}
if (data->sun.flareMaterial)
{
dest->sun.flareMaterial = reinterpret_cast<Material*>(zone->get_asset_pointer(
material, data->sun.flareMaterial->name));
}
if (data->outdoorImage)
{
dest->outdoorImage = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(image, data->outdoorImage->name)
);
}
buf->push_stream(2);
if (data->cellCasterBits[0])
{
buf->align(3);
buf->write(data->cellCasterBits[0],
data->dpvsPlanes.cellCount * ((data->dpvsPlanes.cellCount + 31) >> 5));
ZoneBuffer::clear_pointer(&dest->cellCasterBits[0]);
}
if (data->cellCasterBits[1])
{
buf->align(3);
buf->write(data->cellCasterBits[1], (data->dpvsPlanes.cellCount + 31) >> 5);
ZoneBuffer::clear_pointer(&dest->cellCasterBits[1]);
}
if (data->sceneDynModel)
{
buf->align(3);
buf->write(data->sceneDynModel, data->dpvsDyn.dynEntClientCount[0]);
ZoneBuffer::clear_pointer(&dest->sceneDynModel);
}
if (data->sceneDynBrush)
{
buf->align(3);
buf->write(data->sceneDynBrush, data->dpvsDyn.dynEntClientCount[1]);
ZoneBuffer::clear_pointer(&dest->sceneDynBrush);
}
if (data->primaryLightEntityShadowVis)
{
buf->align(3);
buf->write(data->primaryLightEntityShadowVis,
(data->primaryLightCount - data->sunPrimaryLightIndex - 1) << 15);
ZoneBuffer::clear_pointer(&dest->primaryLightEntityShadowVis);
}
if (data->primaryLightDynEntShadowVis[0])
{
buf->align(3);
buf->write(data->primaryLightDynEntShadowVis[0],
data->dpvsDyn.dynEntClientCount[0] * (data->primaryLightCount - data->sunPrimaryLightIndex -
1));
ZoneBuffer::clear_pointer(&dest->primaryLightDynEntShadowVis[0]);
}
if (data->primaryLightDynEntShadowVis[1])
{
buf->align(3);
buf->write(data->primaryLightDynEntShadowVis[1],
data->dpvsDyn.dynEntClientCount[1] * (data->primaryLightCount - data->sunPrimaryLightIndex -
1));
ZoneBuffer::clear_pointer(&dest->primaryLightDynEntShadowVis[1]);
}
if (data->primaryLightForModelDynEnt)
{
buf->align(0);
buf->write(data->primaryLightForModelDynEnt, data->dpvsDyn.dynEntClientCount[0]);
ZoneBuffer::clear_pointer(&dest->primaryLightForModelDynEnt);
}
buf->pop_stream();
if (data->shadowGeom)
{
buf->align(3);
auto shadow_geometry = buf->write(data->shadowGeom, data->primaryLightCount);
for (std::int32_t i = 0; i < data->primaryLightCount; i++)
{
if (data->shadowGeom[i].sortedSurfIndex)
{
buf->align(1);
buf->write_p(data->shadowGeom[i].sortedSurfIndex, data->shadowGeom[i].surfaceCount);
ZoneBuffer::clear_pointer(&shadow_geometry[i].sortedSurfIndex);
}
if (data->shadowGeom[i].smodelIndex)
{
buf->align(1);
buf->write_p(data->shadowGeom[i].smodelIndex, data->shadowGeom[i].smodelCount);
ZoneBuffer::clear_pointer(&shadow_geometry[i].smodelIndex);
}
}
ZoneBuffer::clear_pointer(&dest->shadowGeom);
}
if (data->lightRegion)
{
buf->align(3);
auto light_region = buf->write(data->lightRegion, data->primaryLightCount);
for (std::int32_t i = 0; i < data->primaryLightCount; i++)
{
if (data->lightRegion[i].hulls)
{
buf->align(3);
auto light_region_hull = buf->write(data->lightRegion[i].hulls, data->lightRegion[i].hullCount);
for (std::uint32_t i2 = 0; i2 < data->lightRegion[i].hullCount; i2++)
{
if (data->lightRegion[i].hulls[i2].axis)
{
buf->align(3);
buf->write(data->lightRegion[i].hulls[i2].axis,
data->lightRegion[i].hulls[i2].axisCount);
ZoneBuffer::clear_pointer(&light_region_hull[i2].axis);
}
}
ZoneBuffer::clear_pointer(&light_region[i].hulls);
}
}
ZoneBuffer::clear_pointer(&dest->lightRegion);
}
buf->push_stream(2);
if (data->dpvs.smodelVisData[0])
{
buf->align(0);
buf->write(data->dpvs.smodelVisData[0], data->dpvs.smodelCount);
ZoneBuffer::clear_pointer(&dest->dpvs.smodelVisData[0]);
}
if (data->dpvs.smodelVisData[1])
{
buf->align(0);
buf->write(data->dpvs.smodelVisData[1], data->dpvs.smodelCount);
ZoneBuffer::clear_pointer(&dest->dpvs.smodelVisData[1]);
}
if (data->dpvs.smodelVisData[2])
{
buf->align(0);
buf->write(data->dpvs.smodelVisData[2], data->dpvs.smodelCount);
ZoneBuffer::clear_pointer(&dest->dpvs.smodelVisData[2]);
}
if (data->dpvs.surfaceVisData[0])
{
buf->align(0);
buf->write(data->dpvs.surfaceVisData[0], data->dpvs.staticSurfaceCount);
ZoneBuffer::clear_pointer(&dest->dpvs.surfaceVisData[0]);
}
if (data->dpvs.surfaceVisData[1])
{
buf->align(0);
buf->write(data->dpvs.surfaceVisData[1], data->dpvs.staticSurfaceCount);
ZoneBuffer::clear_pointer(&dest->dpvs.surfaceVisData[1]);
}
if (data->dpvs.surfaceVisData[2])
{
buf->align(0);
buf->write(data->dpvs.surfaceVisData[2], data->dpvs.staticSurfaceCount);
ZoneBuffer::clear_pointer(&dest->dpvs.surfaceVisData[2]);
}
buf->pop_stream();
if (data->dpvs.sortedSurfIndex)
{
buf->align(1);
buf->write_p(data->dpvs.sortedSurfIndex,
data->dpvs.staticSurfaceCount + data->dpvs.staticSurfaceCountNoDecal);
ZoneBuffer::clear_pointer(&dest->dpvs.sortedSurfIndex);
}
if (data->dpvs.smodelInsts)
{
buf->align(3);
buf->write(data->dpvs.smodelInsts, data->dpvs.smodelCount);
ZoneBuffer::clear_pointer(&dest->dpvs.smodelInsts);
}
if (data->dpvs.surfaces)
{
buf->align(3);
auto surface = buf->write(data->dpvs.surfaces, data->surfaceCount);
for (std::int32_t i = 0; i < data->surfaceCount; i++)
{
if (data->dpvs.surfaces[i].material)
{
surface[i].material = reinterpret_cast<Material*>(zone->get_asset_pointer(
material, data->dpvs.surfaces[i].material->name));
}
}
ZoneBuffer::clear_pointer(&dest->dpvs.surfaces);
}
if (data->dpvs.surfacesBounds)
{
buf->align(3);
buf->write(data->dpvs.surfacesBounds, data->surfaceCount);
ZoneBuffer::clear_pointer(&dest->dpvs.surfacesBounds);
}
if (data->dpvs.smodelDrawInsts)
{
buf->align(3);
auto static_model_draw_inst = buf->write(data->dpvs.smodelDrawInsts, data->dpvs.smodelCount);
for (std::uint32_t i = 0; i < data->dpvs.smodelCount; i++)
{
if (data->dpvs.smodelDrawInsts[i].model)
{
static_model_draw_inst[i].model = reinterpret_cast<XModel*>(zone->get_asset_pointer(
xmodel, data->dpvs.smodelDrawInsts[i].model->name));
}
}
ZoneBuffer::clear_pointer(&dest->dpvs.smodelDrawInsts);
}
buf->push_stream(2);
if (data->dpvs.surfaceMaterials)
{
buf->align(7);
buf->write(data->dpvs.surfaceMaterials, data->surfaceCount);
ZoneBuffer::clear_pointer(&dest->dpvs.smodelDrawInsts);
}
if (data->dpvs.surfaceCastsSunShadow)
{
buf->align(127);
buf->write(data->dpvs.surfaceCastsSunShadow, data->dpvs.surfaceVisDataCount);
ZoneBuffer::clear_pointer(&dest->dpvs.surfaceCastsSunShadow);
}
if (data->dpvsDyn.dynEntCellBits[0])
{
buf->align(3);
buf->write(data->dpvsDyn.dynEntCellBits[0],
data->dpvsDyn.dynEntClientWordCount[0] * data->dpvsPlanes.cellCount);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntCellBits[0]);
}
if (data->dpvsDyn.dynEntCellBits[1])
{
buf->align(3);
buf->write(data->dpvsDyn.dynEntCellBits[1],
data->dpvsDyn.dynEntClientWordCount[1] * data->dpvsPlanes.cellCount);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntCellBits[1]);
}
if (data->dpvsDyn.dynEntVisData[0][0])
{
buf->align(15);
buf->write(data->dpvsDyn.dynEntVisData[0][0], 32 * data->dpvsDyn.dynEntClientWordCount[0]);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntVisData[0][0]);
}
if (data->dpvsDyn.dynEntVisData[1][0])
{
buf->align(15);
buf->write(data->dpvsDyn.dynEntVisData[1][0], 32 * data->dpvsDyn.dynEntClientWordCount[1]);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntVisData[1][0]);
}
if (data->dpvsDyn.dynEntVisData[0][1])
{
buf->align(15);
buf->write(data->dpvsDyn.dynEntVisData[0][1], 32 * data->dpvsDyn.dynEntClientWordCount[0]);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntVisData[0][1]);
}
if (data->dpvsDyn.dynEntVisData[1][1])
{
buf->align(15);
buf->write(data->dpvsDyn.dynEntVisData[1][1], 32 * data->dpvsDyn.dynEntClientWordCount[1]);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntVisData[1][1]);
}
if (data->dpvsDyn.dynEntVisData[0][2])
{
buf->align(15);
buf->write(data->dpvsDyn.dynEntVisData[0][2], 32 * data->dpvsDyn.dynEntClientWordCount[0]);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntVisData[0][2]);
}
if (data->dpvsDyn.dynEntVisData[1][2])
{
buf->align(15);
buf->write(data->dpvsDyn.dynEntVisData[1][2], 32 * data->dpvsDyn.dynEntClientWordCount[1]);
ZoneBuffer::clear_pointer(&dest->dpvsDyn.dynEntVisData[1][2]);
}
buf->pop_stream();
if (data->heroLights)
{
buf->align(3);
buf->write(data->heroLights, data->heroLightCount);
ZoneBuffer::clear_pointer(&dest->heroLights);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IGfxWorld::dump(GfxWorld* asset)
{
// convert asset to IW5 format
auto* iw5_asset = new IW5::GfxWorld;
memset(iw5_asset, 0, sizeof IW5::GfxWorld);
// copy struct data
memcpy(&iw5_asset->name, &asset->name, Difference(&iw5_asset->cells, &iw5_asset->name));
// allocate cells
iw5_asset->cells = new IW5::GfxCell[iw5_asset->dpvsPlanes.cellCount];
memset(iw5_asset->cells, 0, sizeof(IW5::GfxCell) * iw5_asset->dpvsPlanes.cellCount);
// copy cell data
for (int i = 0; i < iw5_asset->dpvsPlanes.cellCount; i++)
{
memcpy(&iw5_asset->cells[i], &asset->cells[i], sizeof GfxCell);
}
// copy draw data
memcpy(iw5_asset->worldDraw._portpad0, asset->draw._portpad0, 16);
memcpy(iw5_asset->worldDraw._portpad1, asset->draw._portpad1, 56);
// copy remaining GfxWorld data
memcpy(&iw5_asset->lightGrid, &asset->lightGrid,
Difference(&iw5_asset->fogTypesAllowed + 1, &iw5_asset->lightGrid));
// dump asset
IW5::IGfxWorld::dump(iw5_asset);
// free memory_
delete[] iw5_asset->cells;
delete iw5_asset;
}
}
}

View File

@ -0,0 +1,37 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IGfxWorld : public IAsset
{
private:
std::string name_;
GfxWorld* asset_ = nullptr;
public:
GfxWorld* parse(const std::string& name, ZoneMemory* mem);
IGfxWorld();
~IGfxWorld();
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(GfxWorld* asset);
};
}
}

125
src/IW4/Assets/LightDef.cpp Normal file
View File

@ -0,0 +1,125 @@
// ======================= 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/LightDef.hpp"
namespace ZoneTool
{
namespace IW4
{
ILightDef::ILightDef()
{
}
ILightDef::~ILightDef()
{
}
GfxLightDef* ILightDef::parse(const std::string& name, ZoneMemory* mem)
{
// parse iw5 lightdef
auto iw5_asset = IW5::ILightDef::parse(name, mem);
if (!iw5_asset)
{
return nullptr;
}
// fixup iw4 structure
auto asset = mem->Alloc<GfxLightDef>();
memcpy(asset, iw5_asset, sizeof GfxLightDef);
asset->lmapLookupStart, iw5_asset->lmapLookupStart;
// return converted asset
return asset;
}
void ILightDef::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()).lightdef;
}
}
void ILightDef::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ILightDef::load_depending(IZone* zone)
{
auto asset = this->asset_;
if (asset->attenuation.image)
{
zone->add_asset_of_type(image, asset->attenuation.image->name);
}
}
std::string ILightDef::name()
{
return this->name_;
}
std::int32_t ILightDef::type()
{
return lightdef;
}
void ILightDef::write(IZone* zone, ZoneBuffer* buf)
{
assert(sizeof(GfxLightDef), 16);
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->attenuation.image)
{
dest->attenuation.image = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->attenuation.image->name));
}
if (zone->get_target() != zone_target::pc)
{
endian_convert(&dest->name);
endian_convert(&dest->attenuation.image);
endian_convert(&dest->attenuation.samplerState);
endian_convert(&dest->lmapLookupStart);
}
END_LOG_STREAM;
buf->pop_stream();
}
void ILightDef::dump(GfxLightDef* asset)
{
// allocate memory_ for the asset
auto iw5_asset = new IW5::GfxLightDef;
// copy data
memcpy(iw5_asset, asset, sizeof GfxLightDef);
memset(&iw5_asset->cucoloris, 0, sizeof GfxLightImage);
iw5_asset->lmapLookupStart = asset->lmapLookupStart;
// dump data
IW5::ILightDef::dump(iw5_asset);
// free memory_
delete iw5_asset;
}
}
}

View File

@ -0,0 +1,38 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ILightDef : public IAsset
{
private:
std::string name_;
GfxLightDef* asset_ = nullptr;
public:
ILightDef();
~ILightDef();
GfxLightDef* parse(const std::string& name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(GfxLightDef* asset);
};
}
}

View File

@ -0,0 +1,260 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
ILoadedSound::ILoadedSound()
{
}
ILoadedSound::~ILoadedSound()
{
}
LoadedSound* ILoadedSound::parse(const std::string& name, ZoneMemory* mem)
{
auto path = "loaded_sound/" + name;
if (!FileSystem::FileExists(path))
{
return nullptr;
}
ZONETOOL_INFO("Parsing loaded_sound \"%s\"...", name.data());
auto fp = FileSystem::FileOpen(path, "rb");
auto result = mem->Alloc<LoadedSound>();
unsigned int chunkIDBuffer;
unsigned int chunkSize;
fread(&chunkIDBuffer, 4, 1, fp);
if (chunkIDBuffer != 0x46464952) // RIFF
{
ZONETOOL_ERROR("%s: Invalid RIFF Header.", name.c_str());
fclose(fp);
return nullptr;
}
fread(&chunkSize, 4, 1, fp);
fread(&chunkIDBuffer, 4, 1, fp);
if (chunkIDBuffer != 0x45564157) // WAVE
{
ZONETOOL_ERROR("%s: Invalid WAVE Header.", name.c_str());
fclose(fp);
return nullptr;
}
char* data;
while (!result->sound.data && !feof(fp))
{
fread(&chunkIDBuffer, 4, 1, fp);
fread(&chunkSize, 4, 1, fp);
switch (chunkIDBuffer)
{
case 0x20746D66: // fmt
if (chunkSize >= 16)
{
short format;
fread(&format, 2, 1, fp);
if (format != 1 && format != 17)
{
ZONETOOL_ERROR("%s: Invalid wave format %i.", name.c_str(), format);
fclose(fp);
return nullptr;
}
result->sound.info.format = format;
short numChannels;
fread(&numChannels, 2, 1, fp);
result->sound.info.channels = numChannels;
int sampleRate;
fread(&sampleRate, 4, 1, fp);
result->sound.info.rate = sampleRate;
int byteRate;
fread(&byteRate, 4, 1, fp);
short blockAlign;
fread(&blockAlign, 2, 1, fp);
result->sound.info.block_size = blockAlign;
short bitPerSample;
fread(&bitPerSample, 2, 1, fp);
result->sound.info.bits = bitPerSample;
if (chunkSize > 16)
{
fseek(fp, chunkSize - 16, SEEK_CUR);
}
}
break;
case 0x61746164: // data
result->sound.info.data_len = chunkSize;
data = (char*)malloc(result->sound.info.data_len);
fread(data, 1, result->sound.info.data_len, fp);
result->sound.data = data;
break;
default:
if (chunkSize > 0)
{
fseek(fp, chunkSize, SEEK_CUR);
}
break;
}
}
if (!result->sound.data)
{
ZONETOOL_ERROR("%s: Could not read sounddata.", name.c_str());
fclose(fp);
return nullptr;
}
result->name = mem->StrDup(name);
FileSystem::FileClose(fp);
return result;
}
void ILoadedSound::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
ZONETOOL_WARNING("Sound %s not found, it will probably sound like a motorboat ingame!", name.data());
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).loadedsound;
}
}
void ILoadedSound::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ILoadedSound::load_depending(IZone* zone)
{
}
std::string ILoadedSound::name()
{
return this->name_;
}
std::int32_t ILoadedSound::type()
{
return loaded_sound;
}
void ILoadedSound::write(IZone* zone, ZoneBuffer* buf)
{
sizeof LoadedSound;
auto data = this->asset_;
auto dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
buf->push_stream(0);
if (data->sound.data)
{
buf->align(0);
buf->write(data->sound.data, data->sound.info.data_len);
ZoneBuffer::clear_pointer(&dest->sound.data);
}
buf->pop_stream();
END_LOG_STREAM;
buf->pop_stream();
}
void ILoadedSound::dump(LoadedSound* asset)
{
auto sound = asset;
auto fp = FileSystem::FileOpen("loaded_sound/"s + asset->name, "wb");
if (fp)
{
char chunkID[] = {'R', 'I', 'F', 'F'};
fwrite(chunkID, 4, 1, fp);
// ChunkSize
int subchunk1Size = 16;
int subchunk2Size = sound->sound.info.data_len;
int chunkSize = 4 + (8 + subchunk1Size) + (8 + subchunk2Size);
fwrite(&chunkSize, 4, 1, fp);
// Format
char format[] = {'W', 'A', 'V', 'E'};
fwrite(format, 4, 1, fp);
// --- FMT SUBCHUNK
// Subchunk1ID
char subchunk1ID[] = {'f', 'm', 't', ' '};
fwrite(subchunk1ID, 4, 1, fp);
// Subchunk1Size
fwrite(&subchunk1Size, 4, 1, fp);
// AudioFormat
short audioFormat = sound->sound.info.format;
fwrite(&audioFormat, 2, 1, fp);
// NumChannels
short numChannels = sound->sound.info.channels;
fwrite(&numChannels, 2, 1, fp);
// SampleRate
int sampleRate = sound->sound.info.rate;
fwrite(&sampleRate, 4, 1, fp);
// ByteRate
int byteRate = sound->sound.info.rate * sound->sound.info.channels * sound->sound.info.bits / 8;
fwrite(&byteRate, 4, 1, fp);
// BlockAlign
short blockAlign = sound->sound.info.block_size;
fwrite(&blockAlign, 2, 1, fp);
// BitsPerSample
short bitsPerSample = sound->sound.info.bits;
fwrite(&bitsPerSample, 2, 1, fp);
// --- DATA SUBCHUNK
// Subchunk2ID
char subchunk2ID[] = {'d', 'a', 't', 'a'};
fwrite(subchunk2ID, 4, 1, fp);
// Subchunk2Size
fwrite(&subchunk2Size, 4, 1, fp);
// Data
fwrite(sound->sound.data, sound->sound.info.data_len, 1, fp);
}
FileSystem::FileClose(fp);
}
}
}

View File

@ -0,0 +1,38 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ILoadedSound : public IAsset
{
private:
std::string name_;
LoadedSound* asset_ = nullptr;
public:
ILoadedSound();
~ILoadedSound();
LoadedSound* parse(const std::string& name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(LoadedSound* asset);
};
}
}

View File

@ -0,0 +1,72 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
ILocalizeEntry::ILocalizeEntry()
{
}
ILocalizeEntry::~ILocalizeEntry()
{
}
void ILocalizeEntry::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).localize;
}
void ILocalizeEntry::init(void* asset, ZoneMemory* mem)
{
this->asset_ = reinterpret_cast<LocalizeEntry*>(asset);
this->name_ = this->asset_->name;
}
void ILocalizeEntry::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ILocalizeEntry::load_depending(IZone* zone)
{
}
std::string ILocalizeEntry::name()
{
return this->name_;
}
std::int32_t ILocalizeEntry::type()
{
return localize;
}
void ILocalizeEntry::write(IZone* zone, ZoneBuffer* buf)
{
auto data = this->asset_;
auto dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->localizedString = buf->write_str(data->localizedString);
dest->name = buf->write_str(data->name);
END_LOG_STREAM;
buf->pop_stream();
}
void ILocalizeEntry::dump(LocalizeEntry* asset)
{
}
}
}

View File

@ -0,0 +1,38 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ILocalizeEntry : public IAsset
{
private:
std::string name_;
LocalizeEntry* asset_ = nullptr;
public:
ILocalizeEntry();
~ILocalizeEntry();
void init(const std::string& name, ZoneMemory* mem) override;
void init(void* asset, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(LocalizeEntry* asset);
};
}
}

403
src/IW4/Assets/MapEnts.cpp Normal file
View File

@ -0,0 +1,403 @@
// ======================= 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 "ZoneUtils/Utils/BinaryDumper.hpp"
#include "../IW5/Assets/MapEnts.hpp"
namespace ZoneTool
{
namespace IW4
{
#ifdef CONVERT_IW5_MAPENTS
std::unordered_map<std::string, std::string> key_conversion =
{
{"1", "pl#"},
{"1668", "classname"},
{"1669", "origin"},
{"1670", "model"},
{"1671", "spawnflags"},
{"1672", "target"},
{"1673", "targetname"},
{"1676", "dmg"},
{"1677", "angles"},
{"1679", "script_linkname"},
{"1705", "intensity"},
{"1774", "script_noteworthy"},
{"1775", "speed"},
{"1776", "lookahead"},
{"1782", "radius"},
{"1783", "height"},
{"1788", "script_speed"},
{"1983", "animscript"},
{"1987", "ambient"},
{"1989", "sunlight"},
{"1990", "suncolor"},
{"1991", "sundirection"},
{"2009", "script_exploder"},
{"2328", "script_linkto"},
{"2369", "destructible_type"},
{"2810", "sunRadiosity"},
{"2811", "skycolor"},
{"2812", "skylight"},
{"2813", "_color"},
{"2814", "ltOrigin"},
{"2815", "gndLt"},
{"2816", "sound_csv_include"},
{"2817", "csv_include"},
{"2818", "precache_script"},
{"2820", "maxbounces"},
{"2821", "radiosityScale"},
{"2823", "def"},
{"2824", "exponent"},
{"2825", "fov_inner"},
{"2826", "fov_outer"},
{"2827", "__smorigin"},
{"2828", "__smangles"},
{"2829", "__smname"},
{"2830", "__smid"},
{"3717", "script_destruct_collision"},
{"4630", "script_bombmode_original"},
{"7712", "modelscale"},
{"7876", "script_accel"},
{"10338", "script_targetoffset_z"},
{"10396", "script_airspeed"},
// we don't need this one for MP maps
// { "11039", "animation" },
{"11848", "script_gameobjectname"},
{"11996", "script_label"},
};
std::unordered_map<std::string, std::string> key_conversion_reversed;
void IMapEnts::convert_ents(MapEnts* ents, ZoneMemory* mem)
{
ZONETOOL_INFO("Converting mapents!");
std::string new_ents_string;
std::string current_entity;
std::string last_key;
bool is_valid_entity;
bool is_parsing_key;
// make sure key_conversion_reversed is prepared
key_conversion_reversed.clear();
// prepare key_conversion_reversed
for (auto& key : key_conversion)
{
key_conversion_reversed[key.second] = key.first;
}
// parse expressions
ExpressionParser parser(ents->entityString);
//
std::string expression = parser.Parse(true);
while (!expression.empty())
{
// convert token to lower
std::transform(expression.begin(), expression.end(), expression.begin(), tolower);
// start parsing new entity
if (expression == "{"s)
{
// clear data from previous entity
current_entity.clear();
is_valid_entity = true;
is_parsing_key = true;
// add expression to current expression buffer
current_entity += expression + "\n";
}
// finalize current entity
else if (expression == "}"s)
{
// add expression to current expression buffer
current_entity += expression + "\n";
// check if the entity we're about to add to the mapents is valid
if (is_valid_entity)
{
// add current expression to entity buffer
new_ents_string += current_entity;
}
else
{
ZONETOOL_INFO("Not adding entity because it contains invalid keys! Data was %s", &current_entity[0]);
}
}
// check key values
else
{
if (is_parsing_key)
{
auto itr1 = key_conversion.find(expression);
auto itr2 = key_conversion_reversed.find(expression);
// checks if the key is unknown to both iw4 and iw5
if (itr1 == key_conversion.end() && itr2 == key_conversion_reversed.end())
{
ZONETOOL_INFO("Unknown mapents key \"%s\". Removing entity from mapents...", &expression[0]
);
// remove current entity from mapents file
is_valid_entity = false;
}
// when converting the key
else if (itr1 != key_conversion.end())
{
current_entity += "\"" + itr1->second + "\"";
last_key = itr1->second;
}
// when the key is already in iw4 format
else
{
current_entity += "\"" + expression + "\"";
last_key = expression;
}
}
else
{
// check if we actually need the current key/value combo
if (
(last_key == "classname"s && expression.length() >= 5 && expression.substr(0, 5) == "node_"s)
||
(last_key == "targetname"s && expression == "delete_on_load"s)
)
{
// remove current entity from mapents file
is_valid_entity = false;
}
// add expression to current expression buffer
current_entity += " \"" + expression + "\"\n";
}
// invert parsing key state
is_parsing_key = !is_parsing_key;
}
// parse next expression
expression = parser.Parse(true);
}
// ZONETOOL_INFO("Entity string is %s", newEntsString.data());
// replace mapents if needed
if (!new_ents_string.empty())
{
ents->numEntityChars = new_ents_string.size() + 1;
ents->entityString = mem->Alloc<char>(ents->numEntityChars);
memset((void*)ents->entityString, 0, ents->numEntityChars);
memcpy((void*)ents->entityString, &new_ents_string[0], ents->numEntityChars - 1);
}
}
#endif
MapEnts* IMapEnts::parse(std::string name, ZoneMemory* mem)
{
// check if we can open a filepointer
if (!FileSystem::FileExists(name + ".ents"))
{
return nullptr;
}
auto* file = FileSystem::FileOpen(name + ".ents", "rb");
// let them know that we're parsing a custom mapents file
ZONETOOL_INFO("Parsing mapents \"%s\"...", name.c_str());
// alloc mapents
auto* ents = mem->Alloc<MapEnts>();
ents->name = mem->StrDup(name);
ents->numEntityChars = FileSystem::FileSize(file);
ents->entityString = mem->Alloc<char>(ents->numEntityChars + 1);
memset((char*)ents->entityString, 0, ents->numEntityChars);
fread((char*)ents->entityString, ents->numEntityChars, 1, file);
((char*)ents->entityString)[ents->numEntityChars] = '\0';
#ifdef CONVERT_IW5_MAPENTS
// convert the mapents!
this->convert_ents(ents, mem);
#endif
// close filepointer
FileSystem::FileClose(file);
AssetReader trigger_reader(mem);
AssetReader stage_reader(mem);
if (trigger_reader.open(name + ".ents.triggers"))
{
ents->trigger.modelCount = trigger_reader.read_int();
ents->trigger.models = trigger_reader.read_array<TriggerModel>();
ents->trigger.hullCount = trigger_reader.read_int();
ents->trigger.hulls = trigger_reader.read_array<TriggerHull>();
ents->trigger.slabCount = trigger_reader.read_int();
ents->trigger.slabs = trigger_reader.read_array<TriggerSlab>();
}
if (stage_reader.open(name + ".ents.stages"))
{
ZONETOOL_INFO("Parsing entity stages...");
ents->stageCount = stage_reader.read_int();
if (ents->stageCount)
{
ents->stageNames = stage_reader.read_array<Stage>();
for (auto i = 0; i < ents->stageCount; i++)
{
ents->stageNames[i].stageName = stage_reader.read_string();
}
}
}
stage_reader.close();
trigger_reader.close();
// return mapents
return ents;
}
void IMapEnts::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = "maps/"s + (currentzone.substr(0, 3) == "mp_" ? "mp/" : "") + currentzone + ".d3dbsp"; // name;
this->asset_ = this->parse(name, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), name.data()).mapents;
}
}
void IMapEnts::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IMapEnts::load_depending(IZone* zone)
{
// IW5::IMapEnts::load_depending_internal(zone, this->asset_->entityString);
}
std::string IMapEnts::name()
{
return this->name_;
}
std::int32_t IMapEnts::type()
{
return map_ents;
}
void IMapEnts::write_triggers(IZone* zone, ZoneBuffer* buf, MapTriggers* dest)
{
if (dest->models)
{
dest->models = buf->write_s(3, dest->models, dest->modelCount);
}
if (dest->hulls)
{
dest->hulls = buf->write_s(3, dest->hulls, dest->hullCount);
}
if (dest->slabs)
{
dest->slabs = buf->write_s(3, dest->slabs, dest->slabCount);
}
}
void IMapEnts::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->entityString)
{
buf->align(0);
buf->write(data->entityString, data->numEntityChars);
ZoneBuffer::clear_pointer(&dest->entityString);
}
write_triggers(zone, buf, &dest->trigger);
if (data->stageNames)
{
buf->align(3);
auto* stage = buf->write(data->stageNames, data->stageCount);
for (auto i = 0; i < data->stageCount; i++)
{
if (data->stageNames[i].stageName)
{
buf->write_str(data->stageNames[i].stageName);
ZoneBuffer::clear_pointer(&stage[i].stageName);
}
}
ZoneBuffer::clear_pointer(&dest->stageNames);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IMapEnts::dump(MapEnts* asset)
{
auto* file = FileSystem::FileOpen(asset->name + ".ents"s, "wb");
if (file)
{
fwrite(asset->entityString, asset->numEntityChars, 1, file);
FileSystem::FileClose(file);
}
AssetDumper trigger_dumper;
if (trigger_dumper.open(asset->name + ".ents.triggers"s))
{
trigger_dumper.dump_int(asset->trigger.modelCount);
trigger_dumper.dump_array<TriggerModel>(asset->trigger.models, asset->trigger.modelCount);
trigger_dumper.dump_int(asset->trigger.hullCount);
trigger_dumper.dump_array<TriggerHull>(asset->trigger.hulls, asset->trigger.hullCount);
trigger_dumper.dump_int(asset->trigger.slabCount);
trigger_dumper.dump_array<TriggerSlab>(asset->trigger.slabs, asset->trigger.slabCount);
trigger_dumper.close();
}
AssetDumper stage_dumper;
if (stage_dumper.open(asset->name + ".ents.stages"s))
{
stage_dumper.dump_int(asset->stageCount);
if (asset->stageCount)
{
stage_dumper.dump_array(asset->stageNames, asset->stageCount);
for (auto i = 0; i < asset->stageCount; i++)
{
stage_dumper.dump_string(asset->stageNames[i].stageName);
}
}
}
stage_dumper.close();
}
}
}

View File

@ -0,0 +1,42 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IMapEnts : public IAsset
{
private:
std::string name_;
MapEnts* asset_ = nullptr;
public:
#ifdef CONVERT_IW5_MAPENTS
static void convert_ents(MapEnts* ents, ZoneMemory* mem);
#endif
MapEnts* parse(std::string name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(MapEnts* asset);
// sadly, this cannot be moved to a CPP file.
static void write_triggers(IZone* zone, ZoneBuffer* buf, MapTriggers* dest);
};
}
}

563
src/IW4/Assets/Material.cpp Normal file
View File

@ -0,0 +1,563 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
// watermap structures, same across most games.
struct WaterWritable
{
float floatTime;
};
struct complex_s
{
float real;
float imag;
};
struct water_t
{
WaterWritable writable;
complex_s* H0;
float* wTerm;
int M;
int N;
float Lx;
float Lz;
float gravity;
float windvel;
float winddir[2];
float amplitude;
float codeConstant[4];
GfxImage* image;
};
#define MATERIAL_DUMP_STRING(entry) \
matdata[#entry] = std::string(asset->entry);
#define MATERIAL_DUMP_INT(entry) \
matdata[#entry] = asset->entry;
#define MATERIAL_INT(entry) \
mat->entry = matdata[#entry].get<int>();
#define STATEBITENTRYNUM 48
#define MATERIAL_DUMP_BITS_ENTRY(entry,size) \
nlohmann::json carr##entry; \
for (int i = 0; i < size; i++) \
{ \
carr##entry[i] = asset->entry[i]; \
} \
matdata[#entry] = carr##entry;
#define MATERIAL_DUMP_CONST_ARRAY(entry,size) \
nlohmann::json carr##entry; \
for (int i = 0; i < size; i++) \
{ \
nlohmann::json cent##entry; \
cent##entry["name"] = asset->entry[i].name; \
cent##entry["nameHash"] = asset->entry[i].nameHash; \
nlohmann::json centliteral##entry; \
centliteral##entry[0] = asset->entry[i].literal[0]; \
centliteral##entry[1] = asset->entry[i].literal[1]; \
centliteral##entry[2] = asset->entry[i].literal[2]; \
centliteral##entry[3] = asset->entry[i].literal[3]; \
cent##entry["literal"] = centliteral##entry; \
carr##entry[i] = cent##entry; \
} \
matdata[#entry] = carr##entry;
#define MATERIAL_DUMP_STATE_MAP(entry,size) \
nlohmann::json carr##entry; \
for (int i = 0; i < size; i++) \
{ \
nlohmann::json cent##entry; \
cent##entry[0] = asset->entry[i].loadBits[0]; \
cent##entry[1] = asset->entry[i].loadBits[1]; \
carr##entry[i] = cent##entry; \
} \
matdata[#entry] = carr##entry;
// Legacy zonetool code: REFACTOR ME!
enum IWI_COMPRESSION_e
{
IWI_INVALID = 0x0,
IWI_ARGB = 0x1,
IWI_RGB8 = 0x2,
IWI_DXT1 = 0xB,
IWI_DXT3 = 0xC,
IWI_DXT5 = 0xD,
} IWI_COMPRESSION;
enum MaterialMapHashes
{
HASH_COLORMAP = 0xa0ab1041,
HASH_DETAILMAP = 0xeb529b4d,
HASH_SPECULARMAP = 0x34ecccb3,
HASH_NORMALMAP = 0x59d30d0f
};
enum MaterialSemantic
{
SEMANTIC_2D = 0x0,
SEMANTIC_FUNCTION = 0x1,
SEMANTIC_COLOR_MAP = 0x2,
SEMANTIC_NORMAL_MAP = 0x5,
SEMANTIC_SPECULAR_MAP = 0x8,
SEMANTIC_WATER_MAP = 0xB
};
typedef struct
{
char magic[3]; //IWi
char version; // 8
int flags;
short format; // see above
short xsize;
short ysize;
short depth;
int mipAddr4;
int mipAddr3;
int mipAddr2;
int mipAddr1;
} _IWI;
// Image parsing
_IWI* LoadIWIHeader(std::string name, ZoneMemory* mem)
{
auto path = "images\\" + name + ".iwi";
if (FileSystem::FileExists(path))
{
auto buf = mem->Alloc<_IWI>();
auto fp = FileSystem::FileOpen(path, "rb"s);
if (fp)
{
fread(buf, sizeof(_IWI), 1, fp);
}
FileSystem::FileClose(fp);
return buf;
} // ZONETOOL_ERROR("Image \"%s\" does not exist!", name.c_str());
return nullptr;
}
GfxImageLoadDef* GenerateLoadDef(GfxImage* image, short iwi_format, ZoneMemory* mem)
{
auto texture = mem->Alloc<GfxImageLoadDef>();
switch (iwi_format)
{
case IWI_ARGB:
texture->format = 21;
break;
case IWI_RGB8:
texture->format = 20;
break;
case IWI_DXT1:
texture->format = 0x31545844;
break;
case IWI_DXT3:
texture->format = 0x33545844;
break;
case IWI_DXT5:
texture->format = 0x35545844;
break;
}
texture->dimensions[0] = image->width;
texture->dimensions[1] = image->height;
texture->dimensions[2] = image->depth;
return texture;
}
GfxImage* Image_Parse(const char* name, char semantic, char category, char flags,
ZoneMemory* mem)
{
_IWI* buf = LoadIWIHeader(name, mem);
if (buf)
{
auto ret = mem->Alloc<GfxImage>();
ret->height = buf->xsize;
ret->width = buf->ysize;
ret->depth = buf->depth;
ret->dataLen1 = buf->mipAddr4 - 32;
ret->dataLen2 = buf->mipAddr4 - 32;
ret->name = strdup(name);
ret->semantic = semantic;
ret->category = category;
ret->flags = flags;
ret->mapType = 3; // hope that works lol
ret->texture = GenerateLoadDef(ret, buf->format, mem);
return ret;
}
return DB_FindXAssetHeader(image, name).gfximage;
}
MaterialImage* Material_ParseMaps(const std::string& material, nlohmann::json& matdata,
ZoneMemory* mem)
{
auto mat = mem->Alloc<MaterialImage>(matdata.size());
for (std::size_t i = 0; i < matdata.size(); i++)
{
mat[i].firstCharacter = matdata[i]["firstCharacter"].get<char>();
mat[i].secondLastCharacter = matdata[i]["lastCharacter"].get<char>();
mat[i].sampleState = matdata[i]["sampleState"].get<char>();
mat[i].semantic = matdata[i]["semantic"].get<char>();
mat[i].typeHash = matdata[i]["typeHash"].get<unsigned int>();
std::string img = matdata[i]["image"].get<std::string>();
mat[i].image = Image_Parse(img.data(), mat[i].semantic, 0, 0, mem);
if (img.empty())
{
MessageBoxA(nullptr, &va("Image name for material %s seems to be empty!", &material[0])[0], nullptr,
0);
}
}
return mat;
}
unsigned int R_HashString(const char* string)
{
unsigned int hash = 0;
while (*string)
{
hash = (*string | 0x20) ^ (33 * hash);
string++;
}
return hash;
}
__declspec(noinline) Material* IMaterial::parse(std::string name, ZoneMemory* mem)
{
auto path = "materials\\" + name;
auto file = FileSystem::FileOpen(path, "rb"s);
if (!file)
{
return nullptr;
}
ZONETOOL_INFO("Parsing material \"%s\"...", name.c_str());
auto size = FileSystem::FileSize(file);
auto bytes = FileSystem::ReadBytes(file, size);
FileSystem::FileClose(file);
nlohmann::json matdata = nlohmann::json::parse(bytes);
auto mat = mem->Alloc<Material>();
mat->name = mem->StrDup(name);
MATERIAL_INT(gameFlags);
MATERIAL_INT(sortKey);
MATERIAL_INT(animationX);
MATERIAL_INT(animationY);
mat->surfaceTypeBits = matdata["surfaceTypeBits"].get<unsigned int>();
mat->stateFlags = matdata["stateFlags"].get<char>();
mat->cameraRegion = matdata["cameraRegion"].get<unsigned short>();
std::string techset = matdata["techniqueSet->name"].get<std::string>();
if (!techset.empty())
{
mat->techniqueSet = DB_FindXAssetHeader(XAssetType::techset, techset.data()).techset;
}
auto maps = matdata["maps"];
if (!maps.empty())
{
mat->maps = Material_ParseMaps(mat->name, maps, mem);
}
mat->numMaps = maps.size();
auto constantTable = matdata["constantTable"];
if (!constantTable.empty())
{
auto constant_def = mem->Alloc<MaterialConstantDef>(constantTable.size());
for (auto i = 0; i < constantTable.size(); i++)
{
strncpy(constant_def[i].name, constantTable[i]["name"].get<std::string>().c_str(), 11);
constant_def[i].name[11] = '\0';
constant_def[i].nameHash = constantTable[i]["nameHash"].get<unsigned int>();
constant_def[i].literal[0] = constantTable[i]["literal"][0].get<float>();
constant_def[i].literal[1] = constantTable[i]["literal"][1].get<float>();
constant_def[i].literal[2] = constantTable[i]["literal"][2].get<float>();
constant_def[i].literal[3] = constantTable[i]["literal"][3].get<float>();
}
mat->constantTable = constant_def;
}
else
{
mat->constantTable = nullptr;
}
mat->constantCount = constantTable.size();
auto stateMap = matdata["stateMap"];
if (!stateMap.empty())
{
auto stateBits = mem->Alloc<GfxStateBits>(stateMap.size());
for (auto i = 0; i < stateMap.size(); i++)
{
stateBits[i].loadBits[0] = stateMap[i][0].get<unsigned int>();
stateBits[i].loadBits[1] = stateMap[i][1].get<unsigned int>();
}
mat->stateMap = stateBits;
}
else
{
mat->stateMap = nullptr;
}
mat->stateBitsCount = stateMap.size();
if (mat->techniqueSet)
{
auto statebits = ITechset::parse_statebits(mat->techniqueSet->name, mem);
memcpy(mat->stateBitsEntry, statebits, sizeof mat->stateBitsEntry);
}
return mat;
}
IMaterial::IMaterial()
{
}
IMaterial::~IMaterial()
{
}
void IMaterial::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()).material;
}
}
void IMaterial::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IMaterial::load_depending(IZone* zone)
{
auto data = this->asset_;
if (data->techniqueSet)
{
zone->add_asset_of_type(techset, data->techniqueSet->name);
}
for (char i = 0; i < data->numMaps; i++)
{
if (data->maps[i].image)
{
// use pointer rather than name here
zone->add_asset_of_type_by_pointer(image, data->maps[i].image);
}
}
}
std::string IMaterial::name()
{
return this->name_;
}
std::int32_t IMaterial::type()
{
return material;
}
void IMaterial::write(IZone* zone, ZoneBuffer* buf)
{
auto dest = buf->at<Material>();
auto data = this->asset_;
buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
if (data->techniqueSet)
{
dest->techniqueSet = reinterpret_cast<MaterialTechniqueSet*>(zone->get_asset_pointer(
techset, data->techniqueSet->name));
}
if (data->maps)
{
buf->align(3);
auto destmaps = buf->write(data->maps, data->numMaps);
for (int i = 0; i < data->numMaps; i++)
{
if (data->maps[i].semantic == 11)
{
ZONETOOL_ERROR("Watermaps are not supported.");
destmaps[i].image = nullptr;
}
else
{
if (data->maps[i].image)
{
destmaps[i].image = reinterpret_cast<GfxImage*>(zone->get_asset_pointer(
image, data->maps[i].image->name));
}
}
}
ZoneBuffer::clear_pointer(&dest->maps);
}
if (data->constantTable)
{
dest->constantTable = buf->write_s(15, data->constantTable, data->constantCount);
}
if (data->stateMap)
{
dest->stateMap = buf->write_s(3, data->stateMap, data->stateBitsCount);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IMaterial::dump(Material* asset)
{
if (asset && asset->techniqueSet)
{
ITechset::dump_statebits(asset->techniqueSet->name, asset->stateBitsEntry);
}
nlohmann::json matdata;
MATERIAL_DUMP_STRING(name);
if (asset->techniqueSet)
{
MATERIAL_DUMP_STRING(techniqueSet->name);
}
MATERIAL_DUMP_INT(gameFlags);
MATERIAL_DUMP_INT(sortKey);
MATERIAL_DUMP_INT(animationX);
MATERIAL_DUMP_INT(animationY);
MATERIAL_DUMP_INT(unknown);
MATERIAL_DUMP_INT(surfaceTypeBits);
MATERIAL_DUMP_INT(stateFlags);
MATERIAL_DUMP_INT(cameraRegion);
MATERIAL_DUMP_CONST_ARRAY(constantTable, asset->constantCount);
MATERIAL_DUMP_STATE_MAP(stateMap, asset->stateBitsCount);
nlohmann::json material_images;
for (int i = 0; i < asset->numMaps; i++)
{
nlohmann::json image;
// watermap
if (asset->maps[i].semantic == 11)
{
ZONETOOL_INFO("Dumping water data for image %s\n", asset->name);
water_t* waterData = reinterpret_cast<water_t*>(asset->maps[i].image);
image["image"] = waterData->image->name;
nlohmann::json waterdata;
waterdata["floatTime"] = waterData->writable.floatTime;
waterdata["codeConstant"][0] = waterData->codeConstant[0];
waterdata["codeConstant"][1] = waterData->codeConstant[1];
waterdata["codeConstant"][2] = waterData->codeConstant[2];
waterdata["codeConstant"][3] = waterData->codeConstant[3];
waterdata["M"] = waterData->M;
waterdata["N"] = waterData->N;
waterdata["Lx"] = waterData->Lx;
waterdata["Lz"] = waterData->Lz;
waterdata["gravity"] = waterData->gravity;
waterdata["windvel"] = waterData->windvel;
waterdata["winddir"][0] = waterData->winddir[0];
waterdata["winddir"][1] = waterData->winddir[1];
waterdata["amplitude"] = waterData->amplitude;
nlohmann::json waterComplexData;
nlohmann::json wTerm;
for (int i = 0; i < waterData->M * waterData->N; i++)
{
nlohmann::json complexdata;
nlohmann::json curWTerm;
complexdata["real"] = waterData->H0[i].real;
complexdata["imag"] = waterData->H0[i].imag;
curWTerm[i] = waterData->wTerm[i];
waterComplexData[i] = complexdata;
}
waterdata["complex"] = waterComplexData;
waterdata["wTerm"] = wTerm;
image["waterinfo"] = waterdata;
}
else
{
image["image"] = asset->maps[i].image->name;
}
image["semantic"] = asset->maps[i].semantic;
image["sampleState"] = asset->maps[i].sampleState;
image["lastCharacter"] = asset->maps[i].secondLastCharacter;
image["firstCharacter"] = asset->maps[i].firstCharacter;
image["typeHash"] = asset->maps[i].typeHash;
// add image data to material
material_images[i] = image;
}
matdata["maps"] = material_images;
std::string assetstr = matdata.dump(4);
auto assetPath = "materials\\"s + asset->name;
auto fileAsset = FileSystem::FileOpen(assetPath, "wb");
if (fileAsset)
{
fwrite(assetstr.c_str(), assetstr.size(), 1, fileAsset);
FileSystem::FileClose(fileAsset);
}
}
}
}

View File

@ -0,0 +1,39 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IMaterial : public IAsset
{
private:
std::string name_;
Material* asset_ = nullptr;
Material* parse(std::string name, ZoneMemory* mem);
public:
IMaterial();
~IMaterial();
void FixStatebits(IZone* zone);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(Material* asset);
};
}
}

View File

@ -0,0 +1,270 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
PhysCollmap* IPhysCollmap::parse(const std::string& name, ZoneMemory* mem)
{
auto version = 4;
auto path = "physcollmap/" + name + ".cme4";
if (!FileSystem::FileExists(path))
{
version = 3;
path = "physcollmap/" + name + ".cme3";
if (!FileSystem::FileExists(path))
{
return nullptr;
}
}
AssetReader read(mem);
if (!read.open(path))
{
return nullptr;
}
ZONETOOL_INFO("Parsing phys_collmap \"%s\"...", name.c_str());
auto* phys_collmap = read.read_array<PhysCollmap>();
phys_collmap->name = mem->StrDup(name);
if (read.read_int())
{
phys_collmap->info = read.read_array<PhysGeomInfo>();
for (auto i = 0u; i < phys_collmap->numInfo; i++)
{
if (read.read_int())
{
phys_collmap->info[i].brush = read.read_array<BrushWrapper>();
if (version == 4)
{
if (read.read_int())
{
phys_collmap->info[i].brush->plane = read.read_array<cplane_s>();
}
}
if (read.read_int())
{
phys_collmap->info[i].brush->side = read.read_array<cbrushside_t>();
for (auto j = 0u; j < phys_collmap->info[i].brush->numPlaneSide; j++)
{
if (read.read_int())
{
phys_collmap->info[i].brush->side[j].plane = read.read_array<cplane_s>();
}
}
}
if (read.read_int())
{
phys_collmap->info[i].brush->edge = read.read_array<char>();
}
if (version == 3)
{
if (read.read_int())
{
phys_collmap->info[i].brush->plane = read.read_array<cplane_s>();
}
}
}
}
}
return phys_collmap;
}
void IPhysCollmap::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()).physcollmap;
}
}
void IPhysCollmap::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IPhysCollmap::load_depending(IZone* zone)
{
}
std::string IPhysCollmap::name()
{
return this->name_;
}
std::int32_t IPhysCollmap::type()
{
return phys_collmap;
}
void IPhysCollmap::write_brush_wrapper(IZone* zone, ZoneBuffer* buf, BrushWrapper* data)
{
auto* dest = buf->write(data);
if (data->side)
{
buf->align(3);
auto* cbrushside = buf->write(data->side, data->numPlaneSide);
for (auto i = 0; i < data->numPlaneSide; i++)
{
cbrushside[i].plane = buf->write_s(3, data->side[i].plane);
}
ZoneBuffer::clear_pointer(&dest->side);
}
if (data->edge)
{
buf->align(0);
buf->write(data->edge, data->numEdge);
ZoneBuffer::clear_pointer(&dest->edge);
}
if (data->plane)
{
dest->plane = buf->write_s(3, data->plane, data->numPlaneSide);
}
}
void IPhysCollmap::write_phys_geom_info(IZone* zone, ZoneBuffer* buf, PhysGeomInfo* dest)
{
auto* data = dest;
if (data->brush)
{
buf->align(3);
this->write_brush_wrapper(zone, buf, data->brush);
ZoneBuffer::clear_pointer(&dest->brush);
}
}
void IPhysCollmap::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
dest->name = buf->write_str(this->name());
if (data->info)
{
buf->align(3);
auto* phys_geom_info = buf->write(data->info, data->numInfo);
for (int i = 0; i < data->numInfo; i++)
{
this->write_phys_geom_info(zone, buf, &phys_geom_info[i]);
}
}
buf->pop_stream();
}
void IPhysCollmap::dump(PhysCollmap* asset)
{
const auto path = "physcollmap/" + std::string(asset->name) + ".cme4";
AssetDumper dump;
dump.open(path.data());
dump.dump_array(asset, 1);
if (asset->info)
{
dump.dump_int(1);
dump.dump_array(asset->info, asset->numInfo);
for (auto i = 0; i < asset->numInfo; i++)
{
if (asset->info[i].brush)
{
dump.dump_int(1);
dump.dump_array(asset->info[i].brush, 1);
if (asset->info[i].brush->plane)
{
dump.dump_int(1);
dump.dump_array(asset->info[i].brush->plane, asset->info[i].brush->numPlaneSide);
// printf("phys_collmap \"%s\"[%i] has %i collision planes.\n", asset->name, i, asset->info[i].brush->numPlaneSide);
}
else
{
dump.dump_int(0);
}
if (asset->info[i].brush->side)
{
// printf("phys_collmap \"%s\"[%i] has %i collision sides.\n", asset->name, i, asset->info[i].brush->numPlaneSide);
dump.dump_int(1);
dump.dump_array(asset->info[i].brush->side, asset->info[i].brush->numPlaneSide);
for (int j = 0; j < asset->info[i].brush->numPlaneSide; j++)
{
if (asset->info[i].brush->side[j].plane)
{
dump.dump_int(1);
dump.dump_array(asset->info[i].brush->side[j].plane, 1);
}
else
{
dump.dump_int(0);
}
}
}
else
{
dump.dump_int(0);
}
if (asset->info[i].brush->edge)
{
// printf("phys_collmap \"%s\"[%i] has %i collision edges.\n", asset->name, i, asset->info[i].brush->numEdge);
dump.dump_int(1);
dump.dump_array(asset->info[i].brush->edge, asset->info[i].brush->numEdge);
}
else
{
dump.dump_int(0);
}
}
else
{
dump.dump_int(0);
}
}
}
else
{
dump.dump_int(0);
}
dump.close();
}
}
}

View File

@ -0,0 +1,37 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IPhysCollmap : public IAsset
{
private:
std::string name_;
PhysCollmap* asset_ = nullptr;
public:
PhysCollmap* parse(const std::string& name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write_brush_wrapper(IZone* zone, ZoneBuffer* buf, BrushWrapper* data);
void write_phys_geom_info(IZone* zone, ZoneBuffer* buf, PhysGeomInfo* dest);
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(PhysCollmap* asset);
};
}
}

View File

@ -0,0 +1,60 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
void IPhysPreset::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).physpreset;
}
void IPhysPreset::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IPhysPreset::load_depending(IZone* zone)
{
}
std::string IPhysPreset::name()
{
return this->name_;
}
std::int32_t IPhysPreset::type()
{
return physpreset;
}
void IPhysPreset::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
dest->name = buf->write_str(this->name());
if (data->sndAliasPrefix)
{
dest->sndAliasPrefix = buf->write_str(data->sndAliasPrefix);
}
buf->pop_stream();
}
void IPhysPreset::dump(PhysPreset* asset)
{
}
}
}

View File

@ -0,0 +1,33 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IPhysPreset : public IAsset
{
private:
std::string name_;
PhysPreset* asset_ = nullptr;
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(PhysPreset* asset);
};
}
}

View File

@ -0,0 +1,85 @@
// ======================= 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/PixelShader.hpp"
namespace ZoneTool
{
namespace IW4
{
PixelShader* IPixelShader::parse(const std::string& name, ZoneMemory* mem, bool preferLocal)
{
return reinterpret_cast<PixelShader*>(IW5::IPixelShader::parse(name, mem, preferLocal));
}
void IPixelShader::init(void* asset, ZoneMemory* mem)
{
this->asset_ = reinterpret_cast<PixelShader*>(asset);
this->name_ = this->asset_->name + "_IW5"s;
}
void IPixelShader::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()).pixelshader;
if (DB_IsXAssetDefault(this->type(), this->name().data()))
{
ZONETOOL_FATAL("PixelShader %s not found.", &name[0]);
}
}
}
void IPixelShader::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IPixelShader::load_depending(IZone* zone)
{
}
std::string IPixelShader::name()
{
return this->name_;
}
std::int32_t IPixelShader::type()
{
return pixelshader;
}
void IPixelShader::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->bytecode)
{
dest->bytecode = buf->write_s(3, data->bytecode, data->codeLen);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IPixelShader::dump(PixelShader* asset)
{
return IW5::IPixelShader::dump(reinterpret_cast<IW5::PixelShader*>(asset));
}
}
}

View File

@ -0,0 +1,37 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IPixelShader : public IAsset
{
private:
std::string name_;
PixelShader* asset_ = nullptr;
public:
static PixelShader* parse(const std::string& name, ZoneMemory* mem,
bool preferLocal = false);
void init(void* asset, ZoneMemory* mem) override;
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(PixelShader* asset);
};
}
}

133
src/IW4/Assets/RawFile.cpp Normal file
View File

@ -0,0 +1,133 @@
// ======================= 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 <zlib.h>
#define ZONETOOL_BRANDING "Compiled using ZoneTool by RektInator."
namespace ZoneTool
{
namespace IW4
{
RawFile* IRawFile::parse(const std::string& name, ZoneMemory* mem)
{
if (FileSystem::FileExists(name))
{
auto* rawfile = mem->Alloc<RawFile>();
rawfile->name = mem->StrDup(name);
auto* file = FileSystem::FileOpen(name, "rb"s);
if (file)
{
const auto size = FileSystem::FileSize(file);
auto data = FileSystem::ReadBytes(file, size);
ZoneBuffer buf(data);
auto compressed = buf.compress_zlib();
rawfile->len = size;
rawfile->compressedLen = compressed.size();
rawfile->buffer = mem->Alloc<char>(size);
memcpy(
const_cast<char*>(rawfile->buffer),
compressed.data(),
size);
FileSystem::FileClose(file);
}
return rawfile;
}
return nullptr;
}
void IRawFile::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = parse(name, mem);
if (name == FileSystem::GetFastFile())
{
this->asset_ = mem->Alloc<RawFile>();
this->asset_->name = mem->StrDup(name);
this->asset_->buffer = mem->StrDup(ZONETOOL_BRANDING);
this->asset_->len = strlen(this->asset_->buffer);
}
else if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), this->name_.data()).rawfile;
}
}
void IRawFile::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IRawFile::load_depending(IZone* zone)
{
}
std::string IRawFile::name()
{
return this->name_;
}
std::int32_t IRawFile::type()
{
return rawfile;
}
void IRawFile::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write<RawFile>(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
if (data->buffer)
{
buf->align(0);
buf->write(data->buffer, data->compressedLen ? data->compressedLen : data->len + 1);
ZoneBuffer::clear_pointer(&dest->buffer);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IRawFile::dump(RawFile* asset)
{
auto* fp = FileSystem::FileOpen(asset->name, "wb");
if (fp)
{
if (asset->compressedLen > 0)
{
std::vector<std::uint8_t> uncompressed;
uncompressed.resize(asset->len);
auto status = uncompress(uncompressed.data(), (uLongf*)&asset->len, (Bytef*)asset->buffer,
asset->compressedLen);
fwrite(uncompressed.data(), uncompressed.size(), 1, fp);
}
else if (asset->len > 0)
{
fwrite(asset->buffer, asset->len, 1, fp);
}
}
FileSystem::FileClose(fp);
}
}
}

View File

@ -0,0 +1,35 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IRawFile : public IAsset
{
private:
std::string name_;
RawFile* asset_ = nullptr;
RawFile* parse(const std::string& name, ZoneMemory* mem);
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(RawFile* asset);
};
}
}

245
src/IW4/Assets/Sound.cpp Normal file
View File

@ -0,0 +1,245 @@
// ======================= 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/Sound.hpp"
namespace ZoneTool
{
namespace IW4
{
snd_alias_list_t* ISound::parse(const std::string& name, ZoneMemory* mem)
{
auto* iw5_asset = IW5::ISound::parse(name, mem);
if (!iw5_asset)
{
return nullptr;
}
auto* asset = mem->Alloc<snd_alias_list_t>();
memset(asset, 0, sizeof snd_alias_list_t);
asset->name = iw5_asset->name;
asset->count = iw5_asset->count;
asset->head = mem->Alloc<snd_alias_t>(asset->count);
memset(asset->head, 0, sizeof(snd_alias_t) * asset->count);
for (auto i = 0; i < asset->count; i++)
{
auto* current_iw4 = &asset->head[i];
auto* current_iw5 = &iw5_asset->head[i];
memcpy(current_iw4, current_iw5, 36);
memcpy(&current_iw4->pitchMin, &current_iw5->pitchMin, 24);
if (current_iw5->masterPercentage == 0.0f || current_iw5->slavePercentage > current_iw5->masterPercentage)
{
current_iw4->___u15.slavePercentage = current_iw5->slavePercentage;
}
else
{
current_iw4->___u15.masterPercentage = current_iw5->masterPercentage;
}
memcpy(&current_iw4->probability, &current_iw5->probability, 36);
}
return asset;
}
void ISound::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()).sound;
}
}
void ISound::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ISound::load_depending(IZone* zone)
{
auto* data = this->asset_;
for (auto i = 0u; i < data->count; i++)
{
auto* head = &data->head[i];
if (head->volumeFalloffCurve)
{
zone->add_asset_of_type(sndcurve, head->volumeFalloffCurve->filename);
}
if (head->soundFile)
{
if (head->soundFile->type == SAT_LOADED)
{
zone->add_asset_of_type(loaded_sound, head->soundFile->sound.loadSnd->name);
}
}
}
}
std::string ISound::name()
{
return this->name_;
}
std::int32_t ISound::type()
{
return sound;
}
void ISound::write_soundfile(IZone* zone, ZoneBuffer* buf, SoundFile* data)
{
auto* dest = buf->write(data);
if (data->type == SAT_STREAMED || data->type == SAT_PRIMED)
{
if (data->sound.streamSnd.dir)
{
dest->sound.streamSnd.dir = buf->write_str(data->sound.streamSnd.dir);
}
if (data->sound.streamSnd.name)
{
dest->sound.streamSnd.name = buf->write_str(data->sound.streamSnd.name);
}
}
else if (data->type == SAT_LOADED)
{
if (data->sound.loadSnd)
{
dest->sound.loadSnd = static_cast<LoadedSound*>(zone->get_asset_pointer(
loaded_sound, data->sound.loadSnd->name));
}
}
}
void ISound::write_head(IZone* zone, ZoneBuffer* buf, snd_alias_t* dest)
{
auto* data = dest;
if (data->aliasName)
{
dest->aliasName = buf->write_str(data->aliasName);
}
if (data->subtitle)
{
dest->subtitle = buf->write_str(data->subtitle);
}
if (data->secondaryAliasName)
{
dest->secondaryAliasName = buf->write_str(data->secondaryAliasName);
}
if (data->chainAliasName)
{
dest->chainAliasName = buf->write_str(data->chainAliasName);
}
if (data->mixerGroup)
{
dest->mixerGroup = buf->write_str(data->mixerGroup);
}
if (data->soundFile)
{
buf->align(3);
write_soundfile(zone, buf, data->soundFile);
ZoneBuffer::clear_pointer(&dest->soundFile);
}
if (data->volumeFalloffCurve)
{
dest->volumeFalloffCurve = static_cast<SndCurve*>(zone->get_asset_pointer(
sndcurve, data->volumeFalloffCurve->filename));
}
if (data->speakerMap)
{
buf->align(3);
auto* speaker_map = buf->write(data->speakerMap);
if (speaker_map->name)
{
speaker_map->name = buf->write_str(speaker_map->name);
}
ZoneBuffer::clear_pointer(&dest->speakerMap);
}
}
void ISound::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 (dest->head)
{
buf->align(3);
auto* dest_sound = buf->write(data->head, data->count);
for (auto i = 0; i < data->count; i++)
{
write_head(zone, buf, &dest_sound[i]);
}
ZoneBuffer::clear_pointer(&dest->head);
}
END_LOG_STREAM;
buf->pop_stream();
}
void ISound::dump(snd_alias_list_t* asset)
{
auto* iw5_asset = new IW5::snd_alias_list_t;
memset(iw5_asset, 0, sizeof IW5::snd_alias_list_t);
iw5_asset->name = asset->name;
iw5_asset->count = asset->count;
iw5_asset->head = new IW5::snd_alias_t[iw5_asset->count];
memset(iw5_asset->head, 0, sizeof(IW5::snd_alias_t) * iw5_asset->count);
for (auto i = 0; i < iw5_asset->count; i++)
{
auto* current_iw4 = &asset->head[i];
auto* current_iw5 = &iw5_asset->head[i];
memcpy(current_iw5, &asset->head[i], 36);
current_iw5->volModIndex = 0x12;
memcpy(&current_iw5->pitchMin, &current_iw4->pitchMin, 24);
current_iw5->masterPriority = 2;
current_iw5->masterPercentage = current_iw4->___u15.masterPercentage;
current_iw5->slavePercentage = current_iw4->___u15.slavePercentage;
memcpy(&current_iw5->probability, &current_iw4->probability, 36);
}
IW5::ISound::dump(iw5_asset);
delete[] iw5_asset->head;
delete iw5_asset;
}
}
}

38
src/IW4/Assets/Sound.hpp Normal file
View File

@ -0,0 +1,38 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ISound : public IAsset
{
private:
std::string name_;
snd_alias_list_t* asset_ = nullptr;
static void write_soundfile(IZone* zone, ZoneBuffer* buf, SoundFile* dest);
static void write_head(IZone* zone, ZoneBuffer* buf, snd_alias_t* dest);
public:
static snd_alias_list_t* parse(const std::string& name, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(snd_alias_list_t* asset);
};
}
}

View File

@ -0,0 +1,57 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
void ISoundCurve::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).soundcurve;
}
void ISoundCurve::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ISoundCurve::load_depending(IZone* zone)
{
}
std::string ISoundCurve::name()
{
return this->name_;
}
std::int32_t ISoundCurve::type()
{
return sndcurve;
}
void ISoundCurve::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->filename = buf->write_str(this->name());
END_LOG_STREAM;
buf->pop_stream();
}
void ISoundCurve::dump(SndCurve* asset)
{
}
}
}

View File

@ -0,0 +1,33 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ISoundCurve : public IAsset
{
private:
std::string name_;
SndCurve* asset_ = nullptr;
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(SndCurve* asset);
};
}
}

View File

@ -0,0 +1,222 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
// LEGACY ZONETOOL CODE, FIX ME!
class CSV
{
protected:
std::string _name;
std::vector<std::vector<std::string>> _data;
public:
CSV(std::string name, char sep = ',')
: _name(name)
{
auto fp = FileSystem::FileOpen(name, "r"s);
if (fp)
{
long len = FileSystem::FileSize(fp);
auto buf = std::make_unique<char[]>(len + 1);
memset(buf.get(), 0, len + 1);
fread(buf.get(), len, 1, fp);
fclose(fp);
std::vector<std::string> rows = split(std::string(buf.get()), '\n');
for (auto& row : rows)
{
// Replace literal characters
std::size_t pos;
while ((pos = row.find("\\n")) != std::string::npos)
{
row.replace(pos, 2, "\n");
}
while ((pos = row.find("\\t")) != std::string::npos)
{
row.replace(pos, 2, "\t");
}
_data.push_back(split(row, sep));
}
}
}
std::string entry(std::size_t row, std::size_t column)
{
return _data[row][column];
}
std::size_t rows()
{
return _data.size();
}
std::size_t columns(std::size_t row)
{
return _data[row].size();
}
std::size_t max_columns()
{
std::size_t _max = 0;
for (std::size_t row = 0; row < this->rows(); row++)
{
if (_max < this->columns(row))
_max = this->columns(row);
}
return _max;
}
void clear()
{
for (std::size_t i = 0; i < _data.size(); i++)
{
for (std::size_t j = 0; j < _data[i].size(); j++)
_data[i][j].clear();
_data[i].clear();
}
_data.clear();
}
};
int StringTable_Hash(const char* string)
{
int hash = 0;
char* data = _strdup(string);
while (*data != 0)
{
hash = tolower(*data) + (31 * hash);
data++;
}
return hash;
}
StringTable* StringTable_Parse(std::string name, ZoneMemory* mem)
{
auto table = std::make_unique<CSV>(name);
auto stringtable = mem->Alloc<StringTable>();
stringtable->name = mem->StrDup(name.c_str());
stringtable->rows = table->rows();
stringtable->columns = table->max_columns();
stringtable->strings = mem->Alloc<StringTableCell>(stringtable->rows * stringtable->columns);
for (int row = 0; row < table->rows(); row++)
{
for (int col = 0; col < table->columns(row); col++)
{
int entry = (row * stringtable->columns) + col;
stringtable->strings[entry].string = mem->StrDup(table->entry(row, col).c_str());
stringtable->strings[entry].hash = StringTable_Hash(stringtable->strings[entry].string);
}
}
return stringtable;
}
void IStringTable::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).stringtable;
if (FileSystem::FileExists(name))
{
ZONETOOL_INFO("Parsing stringtable %s...", name.data());
this->asset_ = StringTable_Parse(name, mem);
}
}
void IStringTable::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IStringTable::load_depending(IZone* zone)
{
}
std::string IStringTable::name()
{
return this->name_;
}
std::int32_t IStringTable::type()
{
return stringtable;
}
void IStringTable::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->strings)
{
buf->align(3);
auto* dest_strings = buf->write(data->strings, data->columns * data->rows);
if (data->columns * data->rows > 0)
{
for (auto i = 0; i < data->columns * data->rows; i++)
{
if (data->strings[i].string)
{
dest_strings[i].string = buf->write_str(data->strings[i].string);
}
}
}
ZoneBuffer::clear_pointer(&dest->strings);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IStringTable::dump(StringTable* asset)
{
const std::string path = asset->name;
auto* file = FileSystem::FileOpen(path, "w"s);
for (auto row = 0; row < asset->rows; row++)
{
for (auto column = 0; column < asset->columns; column++)
{
fprintf(
file,
"%s%s",
(asset->strings[(row * asset->columns) + column].string)
? asset->strings[(row * asset->columns) + column].string
: "",
(column == asset->columns - 1) ? "\n" : ","
);
}
}
FileSystem::FileClose(file);
}
}
}

View File

@ -0,0 +1,33 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IStringTable : public IAsset
{
private:
std::string name_;
StringTable* asset_ = nullptr;
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(StringTable* asset);
};
}
}

View File

@ -0,0 +1,294 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
void IStructuredDataDef::add_entry(const enum_type type, const int stat_index_offset, const std::string& entry_name, ZoneMemory* mem)
{
const auto new_entry = mem->Alloc<newEnumEntry>();
new_entry->name = _strdup(entry_name.data());
new_entry->statIndexOffset = stat_index_offset;
newEntries[type][newEntries[type].size()] = new_entry;
}
bool check_alphabetical_order(std::string entry1, std::string entry2)
{
std::transform(entry1.begin(), entry1.end(), entry1.begin(), tolower);
std::transform(entry2.begin(), entry2.end(), entry2.begin(), tolower);
const auto len = std::min(entry1.size(), entry2.size());
const auto e1_l = entry1.data();
const auto e2_l = entry2.data();
for (int i = 0; i < len; i++)
{
if (*(e1_l + i) > *(e2_l + i))
return false;
if (*(e1_l + i) < *(e2_l + i))
return true;
}
return entry1.size() <= entry2.size();
}
void IStructuredDataDef::patch_enum_with_map(StructuredDataDefSet* data, enum_type enumIndex,
std::map<int, newEnumEntry*> map, ZoneMemory* mem)
{
const auto current_enum = &data->defs->enums[enumIndex];
// Check if new enum has already been built
if (newIndexCount[enumIndex])
{
current_enum->entryCount = newIndexCount[enumIndex];
current_enum->entries = newIndices[enumIndex];
return;
}
// Check if new weapons share the same index or if it is invalid
for (std::size_t i = 0; i < map.size(); i++)
{
if (map[i]->statIndexOffset < 1)
{
ZONETOOL_ERROR("Invalid index (%d) for entry %s\n ", map[i]->statIndexOffset, map[i]->name);
}
for (std::size_t j = 0; j < map.size(); j++)
{
if (i == j) continue;
if (map[i]->statIndexOffset == map[j]->statIndexOffset)
{
ZONETOOL_ERROR("Index duplication (%d) for entries %s and %s\n", map[i]->statIndexOffset, map[i]
->name, map[j]->name);
}
}
}
// Define new amount of indices
newIndexCount[enumIndex] = current_enum->entryCount + map.size();
// Find last cac index
auto last_cac_index = 0;
for (auto i = 0; i < current_enum->entryCount; i++)
{
if (current_enum->entries[i].index > last_cac_index)
{
last_cac_index = current_enum->entries[i].index;
}
}
// Create new enum
newIndices[enumIndex] = mem->ManualAlloc<StructuredDataEnumEntry>(sizeof(StructuredDataEnumEntry) * (current_enum->entryCount + map.size() + 1));
memcpy(newIndices[enumIndex], current_enum->entries, sizeof(StructuredDataEnumEntry) * current_enum->entryCount);
// Apply new weapons to enum
for (std::size_t i = 0; i < map.size(); i++)
{
auto entry_pos = 0;
for (; entry_pos < current_enum->entryCount + i; entry_pos++)
{
if (!strcmp(map[i]->name, newIndices[enumIndex][entry_pos].name))
{
ZONETOOL_FATAL("Duplicate playerdatadef entry found: %s", map[i]->name);
}
// Search weapon position
if (check_alphabetical_order(map[i]->name, (char*)newIndices[enumIndex][entry_pos].name))
{
break;
}
}
for (int j = current_enum->entryCount + i; j > entry_pos; j--)
{
newIndices[enumIndex][j] = newIndices[enumIndex][j - 1];
}
newIndices[enumIndex][entry_pos].index = map[i]->statIndexOffset + last_cac_index;
newIndices[enumIndex][entry_pos].name = map[i]->name;
}
// Apply stuff to current player data
current_enum->entryCount = newIndexCount[enumIndex];
current_enum->entries = newIndices[enumIndex];
}
// Adds new entries to the structuredDataDef
void IStructuredDataDef::manipulate(StructuredDataDefSet* data, ZoneMemory* mem)
{
// clear existing data if present
for (auto i = 0; i < enum_type::count; i++)
{
if (!newEntries[i].empty())
{
newEntries[i].clear();
}
}
// Patch mp/playerdata.def if needed
if (!strcmp(data->name, "mp/playerdata.def"))
{
// add new entries here
add_entry(enum_type::weapons, 1, "cm901", mem);
ZONETOOL_INFO("Statfiles patched.");
}
// Increment version
data->defs->version += 1;
// Patch enums
for (auto i = 0; i < enum_type::count; i++)
{
if (!newEntries[i].empty())
{
patch_enum_with_map(data, static_cast<enum_type>(i), newEntries[i], mem);
}
}
}
void IStructuredDataDef::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).structureddatadef;
memset(newIndices, 0, sizeof(StructuredDataEnumEntry*) * enum_type::count);
memset(newIndexCount, 0, sizeof(int) * enum_type::count);
for (int i = 0; i < enum_type::count; i++)
{
newEntries[i].clear();
}
// touch the asset
manipulate(this->asset_, mem);
}
void IStructuredDataDef::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IStructuredDataDef::load_depending(IZone* zone)
{
}
std::string IStructuredDataDef::name()
{
return this->name_;
}
std::int32_t IStructuredDataDef::type()
{
return structureddatadef;
}
void IStructuredDataDef::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->defs)
{
buf->align(3);
auto defs = buf->write(data->defs, data->defCount);
for (unsigned int i = 0; i < data->defCount; i++)
{
auto curdef = &data->defs[i];
if (curdef->enums)
{
buf->align(3);
auto enums = buf->write(curdef->enums, curdef->enumCount);
for (int j = 0; j < curdef->enumCount; j++)
{
if (enums[j].entries)
{
buf->align(3);
auto entries = buf->write(enums[j].entries, enums[j].entryCount);
for (int k = 0; k < enums[j].entryCount; k++)
{
if (entries[k].name)
{
buf->write_str(entries[k].name);
ZoneBuffer::clear_pointer(&entries[k].name);
}
}
ZoneBuffer::clear_pointer(&enums[j].entries);
}
}
ZoneBuffer::clear_pointer(&defs[i].enums);
}
if (curdef->structs)
{
buf->align(3);
auto structs = buf->write(curdef->structs, curdef->structCount);
for (int j = 0; j < curdef->structCount; j++)
{
if (structs[j].properties)
{
buf->align(3);
auto props = buf->write(structs[j].properties, structs[j].propertyCount);
for (int k = 0; k < structs[j].propertyCount; k++)
{
if (props[k].name)
{
buf->write_str(props[k].name);
ZoneBuffer::clear_pointer(&props[k].name);
}
}
ZoneBuffer::clear_pointer(&structs[j].properties);
}
}
ZoneBuffer::clear_pointer(&defs[i].structs);
}
if (curdef->indexedArrays)
{
buf->align(3);
buf->write(curdef->indexedArrays, curdef->indexedArrayCount);
ZoneBuffer::clear_pointer(&defs[i].indexedArrays);
}
if (curdef->enumedArrays)
{
buf->align(3);
buf->write(curdef->enumedArrays, curdef->enumedArrayCount);
ZoneBuffer::clear_pointer(&defs[i].enumedArrays);
}
}
}
END_LOG_STREAM;
buf->pop_stream();
}
void IStructuredDataDef::dump(StructuredDataDefSet* asset)
{
}
}
}

View File

@ -0,0 +1,65 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
struct newEnumEntry
{
char* name;
int statIndexOffset;
};
enum enum_type
{
features,
weapons,
attachments,
challenges,
camos,
perks,
killstreaks,
accolades,
cardicons,
cardtitles,
cardnameplates,
teams,
gametypes,
count,
};
class IStructuredDataDef : public IAsset
{
private:
StructuredDataEnumEntry* newIndices[enum_type::count];
int newIndexCount[enum_type::count];
std::map<int, newEnumEntry*> newEntries[enum_type::count];
std::string name_;
StructuredDataDefSet* asset_ = nullptr;
void add_entry(enum_type type, int stat_index_offset, const std::string& entry_name, ZoneMemory* mem);
void patch_enum_with_map(StructuredDataDefSet* data, enum_type enumIndex, std::map<int, newEnumEntry*> map, ZoneMemory* mem);
void manipulate(StructuredDataDefSet* data, ZoneMemory* mem);
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(StructuredDataDefSet* asset);
};
}
}

593
src/IW4/Assets/Techset.cpp Normal file
View File

@ -0,0 +1,593 @@
// ======================= 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 <d3d9.h>
#include "IW5/Assets/Techset.hpp"
namespace ZoneTool
{
namespace IW4
{
std::unordered_map<std::int32_t, std::int32_t> constant_map =
{
{ IW5::CONST_SRC_CODE_LIGHT_POSITION, CONST_SRC_CODE_LIGHT_POSITION },
{ IW5::CONST_SRC_CODE_LIGHT_DIFFUSE, CONST_SRC_CODE_LIGHT_DIFFUSE },
{ IW5::CONST_SRC_CODE_LIGHT_SPECULAR, CONST_SRC_CODE_LIGHT_SPECULAR },
{ IW5::CONST_SRC_CODE_LIGHT_SPOTDIR, CONST_SRC_CODE_LIGHT_SPOTDIR },
{ IW5::CONST_SRC_CODE_LIGHT_SPOTFACTORS, CONST_SRC_CODE_LIGHT_SPOTFACTORS },
{ IW5::CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT, CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_COLOR, CONST_SRC_CODE_PARTICLE_CLOUD_COLOR },
{ IW5::CONST_SRC_CODE_GAMETIME, CONST_SRC_CODE_GAMETIME },
//{ IW5::CONST_SRC_CODE_EYEOFFSET, CONST_SRC_CODE_EYEOFFSET },
//{ IW5::CONST_SRC_CODE_COLOR_SATURATION_R, CONST_SRC_CODE_COLOR_SATURATION_R },
//{ IW5::CONST_SRC_CODE_COLOR_SATURATION_G, CONST_SRC_CODE_COLOR_SATURATION_G },
//{ IW5::CONST_SRC_CODE_COLOR_SATURATION_B, CONST_SRC_CODE_COLOR_SATURATION_B },
{ IW5::CONST_SRC_CODE_PIXEL_COST_FRACS, CONST_SRC_CODE_PIXEL_COST_FRACS },
{ IW5::CONST_SRC_CODE_PIXEL_COST_DECODE, CONST_SRC_CODE_PIXEL_COST_DECODE },
{ IW5::CONST_SRC_CODE_FILTER_TAP_0, CONST_SRC_CODE_FILTER_TAP_0 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_1, CONST_SRC_CODE_FILTER_TAP_1 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_2, CONST_SRC_CODE_FILTER_TAP_2 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_3, CONST_SRC_CODE_FILTER_TAP_3 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_4, CONST_SRC_CODE_FILTER_TAP_4 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_5, CONST_SRC_CODE_FILTER_TAP_5 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_6, CONST_SRC_CODE_FILTER_TAP_6 },
{ IW5::CONST_SRC_CODE_FILTER_TAP_7, CONST_SRC_CODE_FILTER_TAP_7 },
{ IW5::CONST_SRC_CODE_COLOR_MATRIX_R, CONST_SRC_CODE_COLOR_MATRIX_R },
{ IW5::CONST_SRC_CODE_COLOR_MATRIX_G, CONST_SRC_CODE_COLOR_MATRIX_G },
{ IW5::CONST_SRC_CODE_COLOR_MATRIX_B, CONST_SRC_CODE_COLOR_MATRIX_B },
{ IW5::CONST_SRC_CODE_RENDER_TARGET_SIZE, CONST_SRC_CODE_RENDER_TARGET_SIZE },
{ IW5::CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET, CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET},
//{ IW5::CONST_SRC_CODE_RENDER_SOURCE_SIZE, CONST_SRC_CODE_RENDER_SOURCE_SIZE },
{ IW5::CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR, CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR },
{ IW5::CONST_SRC_CODE_DOF_EQUATION_SCENE, CONST_SRC_CODE_DOF_EQUATION_SCENE },
{ IW5::CONST_SRC_CODE_DOF_LERP_SCALE, CONST_SRC_CODE_DOF_LERP_SCALE },
{ IW5::CONST_SRC_CODE_DOF_LERP_BIAS, CONST_SRC_CODE_DOF_LERP_BIAS },
{ IW5::CONST_SRC_CODE_DOF_ROW_DELTA, CONST_SRC_CODE_DOF_ROW_DELTA },
{ IW5::CONST_SRC_CODE_MOTION_MATRIX_X, CONST_SRC_CODE_MOTION_MATRIX_X },
{ IW5::CONST_SRC_CODE_MOTION_MATRIX_Y, CONST_SRC_CODE_MOTION_MATRIX_Y },
{ IW5::CONST_SRC_CODE_MOTION_MATRIX_W, CONST_SRC_CODE_MOTION_MATRIX_W },
{ IW5::CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION, CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION },
{ IW5::CONST_SRC_CODE_SHADOWMAP_SCALE, CONST_SRC_CODE_SHADOWMAP_SCALE },
{ IW5::CONST_SRC_CODE_ZNEAR, CONST_SRC_CODE_ZNEAR },
{ IW5::CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE, CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE },
{ IW5::CONST_SRC_CODE_DEBUG_BUMPMAP, CONST_SRC_CODE_DEBUG_BUMPMAP },
{ IW5::CONST_SRC_CODE_MATERIAL_COLOR, CONST_SRC_CODE_MATERIAL_COLOR },
{ IW5::CONST_SRC_CODE_FOG, CONST_SRC_CODE_FOG },
{ IW5::CONST_SRC_CODE_FOG_COLOR_LINEAR, CONST_SRC_CODE_FOG_COLOR_LINEAR },
{ IW5::CONST_SRC_CODE_FOG_COLOR_GAMMA, CONST_SRC_CODE_FOG_COLOR_GAMMA },
{ IW5::CONST_SRC_CODE_FOG_SUN_CONSTS, CONST_SRC_CODE_FOG_SUN_CONSTS },
{ IW5::CONST_SRC_CODE_FOG_SUN_COLOR_LINEAR, CONST_SRC_CODE_FOG_SUN_COLOR_LINEAR },
{ IW5::CONST_SRC_CODE_FOG_SUN_COLOR_GAMMA, CONST_SRC_CODE_FOG_SUN_COLOR_GAMMA },
{ IW5::CONST_SRC_CODE_FOG_SUN_DIR, CONST_SRC_CODE_FOG_SUN_DIR },
{ IW5::CONST_SRC_CODE_GLOW_SETUP, CONST_SRC_CODE_GLOW_SETUP },
{ IW5::CONST_SRC_CODE_GLOW_APPLY, CONST_SRC_CODE_GLOW_APPLY },
{ IW5::CONST_SRC_CODE_COLOR_BIAS, CONST_SRC_CODE_COLOR_BIAS },
{ IW5::CONST_SRC_CODE_COLOR_TINT_BASE, CONST_SRC_CODE_COLOR_TINT_BASE },
{ IW5::CONST_SRC_CODE_COLOR_TINT_DELTA, CONST_SRC_CODE_COLOR_TINT_DELTA },
{ IW5::CONST_SRC_CODE_COLOR_TINT_QUADRATIC_DELTA, CONST_SRC_CODE_COLOR_TINT_QUADRATIC_DELTA },
{ IW5::CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS, CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS },
{ IW5::CONST_SRC_CODE_ENVMAP_PARMS, CONST_SRC_CODE_ENVMAP_PARMS },
{ IW5::CONST_SRC_CODE_SUN_SHADOWMAP_PIXEL_ADJUST, CONST_SRC_CODE_SUN_SHADOWMAP_PIXEL_ADJUST },
{ IW5::CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST, CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST },
{ IW5::CONST_SRC_CODE_COMPOSITE_FX_DISTORTION, CONST_SRC_CODE_COMPOSITE_FX_DISTORTION },
{ IW5::CONST_SRC_CODE_POSTFX_FADE_EFFECT, CONST_SRC_CODE_POSTFX_FADE_EFFECT },
{ IW5::CONST_SRC_CODE_VIEWPORT_DIMENSIONS, CONST_SRC_CODE_VIEWPORT_DIMENSIONS },
{ IW5::CONST_SRC_CODE_FRAMEBUFFER_READ, CONST_SRC_CODE_FRAMEBUFFER_READ },
//{ IW5::CONST_SRC_CODE_THERMAL_COLOR_OFFSET, CONST_SRC_CODE_THERMAL_COLOR_OFFSET },
//{ IW5::CONST_SRC_CODE_PLAYLIST_POPULATION_PARAMS, CONST_SRC_CODE_PLAYLIST_POPULATION_PARAMS },
{ IW5::CONST_SRC_CODE_BASE_LIGHTING_COORDS, CONST_SRC_CODE_BASE_LIGHTING_COORDS },
{ IW5::CONST_SRC_CODE_LIGHT_PROBE_AMBIENT, CONST_SRC_CODE_LIGHT_PROBE_AMBIENT },
{ IW5::CONST_SRC_CODE_NEARPLANE_ORG, CONST_SRC_CODE_NEARPLANE_ORG },
{ IW5::CONST_SRC_CODE_NEARPLANE_DX, CONST_SRC_CODE_NEARPLANE_DX },
{ IW5::CONST_SRC_CODE_NEARPLANE_DY, CONST_SRC_CODE_NEARPLANE_DY },
{ IW5::CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE, CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE },
{ IW5::CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET, CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX0, CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX0 },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX1, CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX1 },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX2, CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX2 },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR0, CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR0 },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR1, CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR1 },
{ IW5::CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR2, CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR2 },
{ IW5::CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM0, CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM0 },
{ IW5::CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM1, CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM1 },
{ IW5::CONST_SRC_CODE_DEPTH_FROM_CLIP, CONST_SRC_CODE_DEPTH_FROM_CLIP },
{ IW5::CONST_SRC_CODE_CODE_MESH_ARG_0, CONST_SRC_CODE_CODE_MESH_ARG_0 },
{ IW5::CONST_SRC_CODE_CODE_MESH_ARG_1, CONST_SRC_CODE_CODE_MESH_ARG_1 },
{ IW5::CONST_SRC_CODE_VIEW_MATRIX, CONST_SRC_CODE_VIEW_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_VIEW_MATRIX, CONST_SRC_CODE_INVERSE_VIEW_MATRIX },
{ IW5::CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX },
{ IW5::CONST_SRC_CODE_PROJECTION_MATRIX, CONST_SRC_CODE_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX, CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX, CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX, CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_VIEW_PROJECTION_MATRIX, CONST_SRC_CODE_VIEW_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX, CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX, CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX, CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX },
{ IW5::CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX, CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX, CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX, CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX },
{ IW5::CONST_SRC_CODE_WORLD_MATRIX0, CONST_SRC_CODE_WORLD_MATRIX0 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_MATRIX0, CONST_SRC_CODE_INVERSE_WORLD_MATRIX0 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0, CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0 },
{ IW5::CONST_SRC_CODE_WORLD_VIEW_MATRIX0, CONST_SRC_CODE_WORLD_VIEW_MATRIX0 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0, CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0, CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0 },
{ IW5::CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0, CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0, CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0 },
{ IW5::CONST_SRC_CODE_WORLD_MATRIX1, CONST_SRC_CODE_WORLD_MATRIX1 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_MATRIX1, CONST_SRC_CODE_INVERSE_WORLD_MATRIX1 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX1, CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX1 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX1, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX1 },
{ IW5::CONST_SRC_CODE_WORLD_VIEW_MATRIX1, CONST_SRC_CODE_WORLD_VIEW_MATRIX1 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX1, CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX1 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX1, CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX1 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1 },
{ IW5::CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX1, CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX1 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX1, CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX1 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1 },
{ IW5::CONST_SRC_CODE_WORLD_MATRIX2, CONST_SRC_CODE_WORLD_MATRIX2 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_MATRIX2, CONST_SRC_CODE_INVERSE_WORLD_MATRIX2 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX2, CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX2 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX2, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX2 },
{ IW5::CONST_SRC_CODE_WORLD_VIEW_MATRIX2, CONST_SRC_CODE_WORLD_VIEW_MATRIX2 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX2, CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX2 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX2, CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX2 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2 },
{ IW5::CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX2, CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX2 },
{ IW5::CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX2, CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX2 },
{ IW5::CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2 },
{ IW5::CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2 },
{ IW5::CONST_SRC_TOTAL_COUNT, CONST_SRC_TOTAL_COUNT },
{ IW5::CONST_SRC_NONE, CONST_SRC_NONE },
};
std::unordered_map<std::int32_t, std::int32_t> constant_map_reversed;
MaterialTechniqueSet* ITechset::parse(const std::string& name, ZoneMemory* mem)
{
const auto iw5_techset = IW5::ITechset::parse(name, mem);
if (!iw5_techset)
{
return nullptr;
}
auto* asset = mem->Alloc<MaterialTechniqueSet>();
memcpy(asset, iw5_techset, 12);
memset(asset->techniques, 0, sizeof asset->techniques);
// port techniques to the correct index
for (int i = 0; i < 54; i++)
{
auto dest_index = i;
if (i >= (46 + 6))
{
dest_index -= 6;
}
else if (i >= (40 + 5))
{
dest_index -= 5;
}
else if (i >= (31 + 4))
{
dest_index -= 4;
}
else if (i >= (19 + 2))
{
dest_index -= 2;
}
if (iw5_techset->techniques[i])
{
const auto technique_size = sizeof(MaterialTechnique) + (sizeof(MaterialPass) * iw5_techset->techniques[i]->hdr.passCount);
asset->techniques[dest_index] = mem->ManualAlloc<MaterialTechnique>(technique_size);
memcpy(asset->techniques[dest_index], iw5_techset->techniques[i], technique_size);
auto& technique = asset->techniques[dest_index];
for (short pass = 0; pass < technique->hdr.passCount; pass++)
{
auto* pass_def = &technique->pass[pass];
const auto arg_count = pass_def->perObjArgCount + pass_def->perPrimArgCount + pass_def->stableArgCount;
if (arg_count)
{
pass_def->argumentDef = mem->Alloc<ShaderArgumentDef>(arg_count);
memcpy(pass_def->argumentDef, iw5_techset->techniques[i]->pass[pass].argumentDef, sizeof(ShaderArgumentDef) * arg_count);
}
for (auto arg = 0; arg < arg_count; arg++)
{
auto* arg_def = &pass_def->argumentDef[arg];
if (arg_def->type > 2)
{
arg_def->type--;
}
if (arg_def->type == 3 || arg_def->type == 5)
{
const auto itr = constant_map.find(arg_def->u.codeConst.index);
if (itr != constant_map.end())
{
arg_def->u.codeConst.index = itr->second;
}
else
{
ZONETOOL_WARNING("code constant %u is not mapped for technique %s!", arg_def->u.codeConst.index, technique->hdr.name);
if (arg_def->u.codeConst.index >= 66)
{
arg_def->u.codeConst.index -= 8;
}
else if (arg_def->u.codeConst.index >= 37)
{
arg_def->u.codeConst.index -= 6;
}
else if (arg_def->u.codeConst.index >= 26)
{
arg_def->u.codeConst.index -= 5;
}
}
}
}
}
}
}
return asset;
}
void ITechset::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = this->parse(this->name_, mem);
if (!this->asset_)
{
this->asset_ = DB_FindXAssetHeader(this->type(), &this->name()[0]).techset;
if (DB_IsXAssetDefault(this->type(), this->name().data()))
{
ZONETOOL_FATAL("Techset %s not found.", &name[0]);
}
}
}
void ITechset::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ITechset::load_depending(IZone* zone)
{
auto* data = this->asset_;
for (auto technique = 0; technique < 48; technique++)
{
if (data->techniques[technique])
{
for (auto pass = 0; pass < data->techniques[technique]->hdr.passCount; pass++)
{
auto& techniquePass = data->techniques[technique]->pass[pass];
if (techniquePass.vertexDecl)
{
zone->add_asset_of_type(vertexdecl, techniquePass.vertexDecl->name);
}
if (techniquePass.vertexShader)
{
zone->add_asset_of_type(vertexshader, techniquePass.vertexShader->name);
}
if (techniquePass.pixelShader)
{
zone->add_asset_of_type(pixelshader, techniquePass.pixelShader->name);
}
}
}
}
}
std::string ITechset::name()
{
return this->name_;
}
std::int32_t ITechset::type()
{
return techset;
}
void ITechset::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());
dest->remappedTechniques = static_cast<MaterialTechniqueSet*>(zone->get_asset_pointer(techset, this->name()));
for (std::int32_t technique = 0; technique < 48; technique++)
{
if (!data->techniques[technique])
{
continue;
}
buf->align(3);
auto* technique_header = buf->write(&data->techniques[technique]->hdr);
auto* technique_passes = buf->write(data->techniques[technique]->pass, technique_header->passCount);
for (std::int32_t pass = 0; pass < technique_header->passCount; pass++)
{
if (technique_passes[pass].vertexDecl)
{
technique_passes[pass].vertexDecl =
reinterpret_cast<VertexDecl*>(zone->get_asset_pointer(
vertexdecl, technique_passes[pass].vertexDecl->name));
}
if (technique_passes[pass].vertexShader)
{
technique_passes[pass].vertexShader =
reinterpret_cast<VertexShader*>(zone->get_asset_pointer(
vertexshader, technique_passes[pass].vertexShader->name));
}
if (technique_passes[pass].pixelShader)
{
technique_passes[pass].pixelShader =
reinterpret_cast<PixelShader*>(zone->get_asset_pointer(
pixelshader, technique_passes[pass].pixelShader->name));
}
if (technique_passes[pass].argumentDef)
{
buf->align(3);
auto* dest_args = buf->write(technique_passes[pass].argumentDef,
technique_passes[pass].perPrimArgCount +
technique_passes[pass].perObjArgCount +
technique_passes[pass].stableArgCount);
for (auto arg = 0; arg <
technique_passes[pass].perPrimArgCount +
technique_passes[pass].perObjArgCount +
technique_passes[pass].stableArgCount; arg++)
{
auto* cur_arg = &technique_passes[pass].argumentDef[arg];
if (cur_arg->type == 1 || cur_arg->type == 7)
{
if (dest_args[arg].u.literalConst)
{
dest_args[arg].u.literalConst = buf->write_s(3, dest_args[arg].u.literalConst, 4);
}
}
}
ZoneBuffer::clear_pointer(&technique_passes[pass].argumentDef);
}
}
buf->write_str(technique_header->name);
ZoneBuffer::clear_pointer(&technique_header->name);
ZoneBuffer::clear_pointer(&dest->techniques[technique]);
}
END_LOG_STREAM;
buf->pop_stream();
}
char* ITechset::parse_statebits(const std::string& techset, ZoneMemory* mem)
{
auto* iw5_statebits = IW5::ITechset::parse_statebits(techset, mem);
auto* statebits = mem->Alloc<char>(48);
memset(statebits, 0xFF, 48);
for (int i = 0; i < 54; i++)
{
auto dest_index = i;
if (i >= (46 + 6))
{
dest_index -= 6;
}
else if (i >= (40 + 5))
{
dest_index -= 5;
}
else if (i >= (31 + 4))
{
dest_index -= 4;
}
else if (i >= (19 + 2))
{
dest_index -= 2;
}
statebits[dest_index] = iw5_statebits[i];
}
return statebits;
}
void ITechset::dump_statebits(const std::string& techset, char* statebits)
{
char iw5_statebits[54];
memset(iw5_statebits, 0xFF, sizeof iw5_statebits);
for (int i = 0; i < 48; i++)
{
auto dest_index = i;
if (i >= 46)
{
dest_index += 6;
}
else if (i >= 40)
{
dest_index += 5;
}
else if (i >= 31)
{
dest_index += 4;
}
else if (i >= 19)
{
dest_index += 2;
}
iw5_statebits[dest_index] = statebits[i];
}
iw5_statebits[19] = iw5_statebits[17];
iw5_statebits[20] = iw5_statebits[18];
iw5_statebits[33] = iw5_statebits[35];
iw5_statebits[34] = iw5_statebits[36];
iw5_statebits[44] = iw5_statebits[43];
IW5::ITechset::dump_statebits(techset, iw5_statebits);
}
void ITechset::dump(MaterialTechniqueSet* asset)
{
if (constant_map_reversed.empty())
{
for (auto& const_map : constant_map)
{
constant_map_reversed[const_map.second] = const_map.first;
}
}
auto* iw5_techset = new IW5::MaterialTechniqueSet;
memset(iw5_techset, 0, sizeof IW5::MaterialTechniqueSet);
iw5_techset->name = asset->name;
iw5_techset->pad = asset->pad;
for (int i = 0; i < 48; i++)
{
auto dest_index = i;
if (i >= 46)
{
dest_index += 6;
}
else if (i >= 40)
{
dest_index += 5;
}
else if (i >= 31)
{
dest_index += 4;
}
else if (i >= 19)
{
dest_index += 2;
}
if (asset->techniques[i])
{
const auto size = sizeof IW5::MaterialTechniqueHeader + (sizeof(MaterialPass) * asset->techniques[i]->hdr.passCount);
iw5_techset->techniques[dest_index] = reinterpret_cast<IW5::MaterialTechnique*>(
new char[size]);
memcpy(iw5_techset->techniques[dest_index], asset->techniques[i], size);
auto& technique = iw5_techset->techniques[dest_index];
for (short pass = 0; pass < technique->hdr.passCount; pass++)
{
const auto pass_def = &technique->pass[pass];
const auto arg_count = pass_def->perPrimArgCount + pass_def->perObjArgCount + pass_def->stableArgCount;
if (arg_count > 0)
{
pass_def->argumentDef = new IW5::ShaderArgumentDef[arg_count];
memcpy(pass_def->argumentDef, asset->techniques[i]->pass[pass].argumentDef, sizeof(IW5::ShaderArgumentDef) * arg_count);
}
for (auto arg = 0; arg < arg_count; arg++)
{
auto arg_def = &pass_def->argumentDef[arg];
if (arg_def->type > 1)
{
arg_def->type++;
}
if (arg_def->type == 4 || arg_def->type == 6)
{
const auto itr = constant_map_reversed.find(arg_def->u.codeConst.index);
if (itr != constant_map_reversed.end())
{
arg_def->u.codeConst.index = itr->second;
}
else
{
ZONETOOL_WARNING("code constant %u is not mapped for technique %s!", arg_def->u.codeConst.index, technique->hdr.name);
if (arg_def->u.codeConst.index >= 58)
{
arg_def->u.codeConst.index += 8;
}
else if (arg_def->u.codeConst.index >= 31)
{
arg_def->u.codeConst.index += 6;
}
else if (arg_def->u.codeConst.index >= 21)
{
arg_def->u.codeConst.index += 5;
}
}
}
}
}
}
}
// yeet
iw5_techset->techniques[19] = iw5_techset->techniques[17];
iw5_techset->techniques[20] = iw5_techset->techniques[18];
iw5_techset->techniques[33] = iw5_techset->techniques[35];
iw5_techset->techniques[34] = iw5_techset->techniques[36];
iw5_techset->techniques[44] = iw5_techset->techniques[43];
// IW5::ITechset::dump_technique_data(iw5_techset, false);
IW5::ITechset::dump(iw5_techset);
for (int i = 0; i < 54; i++)
{
if (i == 19 || i == 20 || i == 33 || i == 34 || i == 44) continue;
if (iw5_techset->techniques[i])
{
for (short pass = 0; pass < iw5_techset->techniques[i]->hdr.passCount; pass++)
{
delete iw5_techset->techniques[i]->pass[pass].argumentDef;
}
delete iw5_techset->techniques[i];
}
}
delete iw5_techset;
}
}
}

View File

@ -0,0 +1,39 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ITechset : public IAsset
{
private:
std::string name_;
MaterialTechniqueSet* asset_ = nullptr;
public:
static MaterialTechniqueSet* parse(const std::string& name, ZoneMemory* mem);
static char* parse_statebits(const std::string& techset, ZoneMemory* mem);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
void* pointer() override { return asset_; }
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump_statebits(const std::string& techset, char* statebits);
static void dump(MaterialTechniqueSet* asset);
};
}
}
#pragma once

View File

@ -0,0 +1,62 @@
// ======================= 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"
namespace ZoneTool
{
namespace IW4
{
void ITracerDef::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().data()).tracer;
}
void ITracerDef::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void ITracerDef::load_depending(IZone* zone)
{
}
std::string ITracerDef::name()
{
return this->name_;
}
std::int32_t ITracerDef::type()
{
return tracer;
}
void ITracerDef::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->material)
{
dest->material = static_cast<Material*>(zone->get_asset_pointer(material, data->material->name));
}
END_LOG_STREAM;
buf->pop_stream();
}
void ITracerDef::dump(TracerDef* asset)
{
}
}
}

View File

@ -0,0 +1,33 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class ITracerDef : public IAsset
{
private:
std::string name_;
TracerDef* asset_ = nullptr;
public:
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(TracerDef* asset);
};
}
}

View File

@ -0,0 +1,74 @@
// ======================= 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/VertexDecl.hpp"
namespace ZoneTool
{
namespace IW4
{
VertexDecl* IVertexDecl::parse(const std::string& name, ZoneMemory* mem, bool preferLocal)
{
return reinterpret_cast<VertexDecl*>(IW5::IVertexDecl::parse(name, mem, preferLocal));
}
void IVertexDecl::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()).vertexdecl;
if (DB_IsXAssetDefault(this->type(), this->name().data()))
{
ZONETOOL_FATAL("VertexDecl %s not found.", &name[0]);
}
}
}
void IVertexDecl::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IVertexDecl::load_depending(IZone* zone)
{
}
std::string IVertexDecl::name()
{
return this->name_;
}
std::int32_t IVertexDecl::type()
{
return vertexdecl;
}
void IVertexDecl::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());
END_LOG_STREAM;
buf->pop_stream();
}
void IVertexDecl::dump(VertexDecl* asset)
{
IW5::IVertexDecl::dump(reinterpret_cast<IW5::VertexDecl*>(asset));
}
}
}

View File

@ -0,0 +1,36 @@
// ======================= 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
// ========================================================
#pragma once
namespace ZoneTool
{
namespace IW4
{
class IVertexDecl : public IAsset
{
private:
std::string name_;
VertexDecl* asset_ = nullptr;
public:
static VertexDecl* parse(const std::string& name, ZoneMemory* mem,
bool preferLocal = false);
void init(const std::string& name, ZoneMemory* mem) override;
void prepare(ZoneBuffer* buf, ZoneMemory* mem) override;
void load_depending(IZone* zone) override;
std::string name() override;
std::int32_t type() override;
void write(IZone* zone, ZoneBuffer* buffer) override;
static void dump(VertexDecl* asset);
};
}
}

View File

@ -0,0 +1,81 @@
// ======================= 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/VertexShader.hpp"
namespace ZoneTool
{
namespace IW4
{
VertexShader* IVertexShader::parse(const std::string& name, ZoneMemory* mem, bool preferLocal)
{
return reinterpret_cast<VertexShader*>(IW5::IVertexShader::parse(name, mem, preferLocal));
}
void IVertexShader::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()).vertexshader;
if (DB_IsXAssetDefault(this->type(), this->name().data()))
{
ZONETOOL_FATAL("VertexShader %s not found.", &name[0]);
}
}
}
void IVertexShader::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IVertexShader::load_depending(IZone* zone)
{
}
std::string IVertexShader::name()
{
return this->name_;
}
std::int32_t IVertexShader::type()
{
return vertexshader;
}
void IVertexShader::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->bytecode)
{
buf->align(3);
buf->write(data->bytecode, data->codeLen);
ZoneBuffer::clear_pointer(&dest->bytecode);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IVertexShader::dump(VertexShader* asset)
{
IW5::IVertexShader::dump(reinterpret_cast<IW5::VertexShader*>(asset));
}
}
}

Some files were not shown because too many files have changed in this diff Show More