Initial commit
This commit is contained in:
34
src/CODO.lua
Normal file
34
src/CODO.lua
Normal 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
|
63
src/CODO/Assets/LocalizeEntry.cpp
Normal file
63
src/CODO/Assets/LocalizeEntry.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
33
src/CODO/Assets/LocalizeEntry.hpp
Normal file
33
src/CODO/Assets/LocalizeEntry.hpp
Normal 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);
|
||||
};
|
||||
}
|
229
src/CODO/Assets/StringTable.cpp
Normal file
229
src/CODO/Assets/StringTable.cpp
Normal 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);
|
||||
}
|
||||
}
|
33
src/CODO/Assets/StringTable.hpp
Normal file
33
src/CODO/Assets/StringTable.hpp
Normal 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
140
src/CODO/CODO.cpp
Normal 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
45
src/CODO/CODO.hpp
Normal 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
32
src/CODO/Functions.hpp
Normal 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
3444
src/CODO/Structs.hpp
Normal file
File diff suppressed because it is too large
Load Diff
298
src/CODO/Zone.cpp
Normal file
298
src/CODO/Zone.cpp
Normal 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
69
src/CODO/Zone.hpp
Normal 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
9
src/CODO/stdafx.cpp
Normal 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
29
src/CODO/stdafx.hpp
Normal 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
35
src/IW3.lua
Normal 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
215
src/IW3/Assets/ClipMap.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/ClipMap.hpp
Normal file
21
src/IW3/Assets/ClipMap.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
18
src/IW3/Assets/ComWorld.cpp
Normal file
18
src/IW3/Assets/ComWorld.cpp
Normal 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));
|
||||
}
|
||||
}
|
18
src/IW3/Assets/ComWorld.hpp
Normal file
18
src/IW3/Assets/ComWorld.hpp
Normal 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);
|
||||
};
|
||||
}
|
54
src/IW3/Assets/FxEffectDef.cpp
Normal file
54
src/IW3/Assets/FxEffectDef.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/FxEffectDef.hpp
Normal file
21
src/IW3/Assets/FxEffectDef.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
20
src/IW3/Assets/GameWorldMp.cpp
Normal file
20
src/IW3/Assets/GameWorldMp.cpp
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/GameWorldMp.hpp
Normal file
21
src/IW3/Assets/GameWorldMp.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
54
src/IW3/Assets/GfxImage.cpp
Normal file
54
src/IW3/Assets/GfxImage.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
22
src/IW3/Assets/GfxImage.hpp
Normal file
22
src/IW3/Assets/GfxImage.hpp
Normal 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
353
src/IW3/Assets/GfxWorld.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/GfxWorld.hpp
Normal file
21
src/IW3/Assets/GfxWorld.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
92
src/IW3/Assets/LoadedSound.cpp
Normal file
92
src/IW3/Assets/LoadedSound.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/LoadedSound.hpp
Normal file
21
src/IW3/Assets/LoadedSound.hpp
Normal 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
261
src/IW3/Assets/MapEnts.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/MapEnts.hpp
Normal file
21
src/IW3/Assets/MapEnts.hpp
Normal 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
249
src/IW3/Assets/Material.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
src/IW3/Assets/Material.hpp
Normal file
22
src/IW3/Assets/Material.hpp
Normal 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
34
src/IW3/Assets/Sound.cpp
Normal 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
21
src/IW3/Assets/Sound.hpp
Normal 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
449
src/IW3/Assets/Techset.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
27
src/IW3/Assets/Techset.hpp
Normal file
27
src/IW3/Assets/Techset.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
76
src/IW3/Assets/XAnimParts.cpp
Normal file
76
src/IW3/Assets/XAnimParts.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
src/IW3/Assets/XAnimParts.hpp
Normal file
21
src/IW3/Assets/XAnimParts.hpp
Normal 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
146
src/IW3/Assets/XModel.cpp
Normal 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
21
src/IW3/Assets/XModel.hpp
Normal 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
38
src/IW3/Functions.hpp
Normal 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
365
src/IW3/IW3.cpp
Normal 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
70
src/IW3/IW3.hpp
Normal 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
1930
src/IW3/Structs.hpp
Normal file
File diff suppressed because it is too large
Load Diff
10
src/IW3/stdafx.cpp
Normal file
10
src/IW3/stdafx.cpp
Normal 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
21
src/IW3/stdafx.hpp
Normal 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
36
src/IW4.lua
Normal 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
|
147
src/IW4/Assets/AddonMapEnts.cpp
Normal file
147
src/IW4/Assets/AddonMapEnts.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
src/IW4/Assets/AddonMapEnts.hpp
Normal file
35
src/IW4/Assets/AddonMapEnts.hpp
Normal 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
631
src/IW4/Assets/ClipMap.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
35
src/IW4/Assets/ClipMap.hpp
Normal file
35
src/IW4/Assets/ClipMap.hpp
Normal 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
131
src/IW4/Assets/ComWorld.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
35
src/IW4/Assets/ComWorld.hpp
Normal file
35
src/IW4/Assets/ComWorld.hpp
Normal 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
101
src/IW4/Assets/FontDef.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
34
src/IW4/Assets/FontDef.hpp
Normal file
34
src/IW4/Assets/FontDef.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
403
src/IW4/Assets/FxEffectDef.cpp
Normal file
403
src/IW4/Assets/FxEffectDef.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
41
src/IW4/Assets/FxEffectDef.hpp
Normal file
41
src/IW4/Assets/FxEffectDef.hpp
Normal 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
209
src/IW4/Assets/FxWorld.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
35
src/IW4/Assets/FxWorld.hpp
Normal file
35
src/IW4/Assets/FxWorld.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
26
src/IW4/Assets/GameWorldMp.cpp
Normal file
26
src/IW4/Assets/GameWorldMp.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
24
src/IW4/Assets/GameWorldMp.hpp
Normal file
24
src/IW4/Assets/GameWorldMp.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
119
src/IW4/Assets/GameWorldSp.cpp
Normal file
119
src/IW4/Assets/GameWorldSp.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
35
src/IW4/Assets/GameWorldSp.hpp
Normal file
35
src/IW4/Assets/GameWorldSp.hpp
Normal 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
423
src/IW4/Assets/GfxImage.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
src/IW4/Assets/GfxImage.hpp
Normal file
40
src/IW4/Assets/GfxImage.hpp
Normal 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
850
src/IW4/Assets/GfxWorld.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
37
src/IW4/Assets/GfxWorld.hpp
Normal file
37
src/IW4/Assets/GfxWorld.hpp
Normal 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
125
src/IW4/Assets/LightDef.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
38
src/IW4/Assets/LightDef.hpp
Normal file
38
src/IW4/Assets/LightDef.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
260
src/IW4/Assets/LoadedSound.cpp
Normal file
260
src/IW4/Assets/LoadedSound.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
38
src/IW4/Assets/LoadedSound.hpp
Normal file
38
src/IW4/Assets/LoadedSound.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
72
src/IW4/Assets/LocalizeEntry.cpp
Normal file
72
src/IW4/Assets/LocalizeEntry.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
38
src/IW4/Assets/LocalizeEntry.hpp
Normal file
38
src/IW4/Assets/LocalizeEntry.hpp
Normal 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
403
src/IW4/Assets/MapEnts.cpp
Normal 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", ¤t_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();
|
||||
}
|
||||
}
|
||||
}
|
42
src/IW4/Assets/MapEnts.hpp
Normal file
42
src/IW4/Assets/MapEnts.hpp
Normal 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
563
src/IW4/Assets/Material.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
src/IW4/Assets/Material.hpp
Normal file
39
src/IW4/Assets/Material.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
270
src/IW4/Assets/PhysCollmap.cpp
Normal file
270
src/IW4/Assets/PhysCollmap.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
37
src/IW4/Assets/PhysCollmap.hpp
Normal file
37
src/IW4/Assets/PhysCollmap.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
60
src/IW4/Assets/PhysPreset.cpp
Normal file
60
src/IW4/Assets/PhysPreset.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
33
src/IW4/Assets/PhysPreset.hpp
Normal file
33
src/IW4/Assets/PhysPreset.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
85
src/IW4/Assets/PixelShader.cpp
Normal file
85
src/IW4/Assets/PixelShader.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
37
src/IW4/Assets/PixelShader.hpp
Normal file
37
src/IW4/Assets/PixelShader.hpp
Normal 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
133
src/IW4/Assets/RawFile.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
35
src/IW4/Assets/RawFile.hpp
Normal file
35
src/IW4/Assets/RawFile.hpp
Normal 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
245
src/IW4/Assets/Sound.cpp
Normal 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(¤t_iw4->pitchMin, ¤t_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(¤t_iw4->probability, ¤t_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(¤t_iw5->pitchMin, ¤t_iw4->pitchMin, 24);
|
||||
current_iw5->masterPriority = 2;
|
||||
current_iw5->masterPercentage = current_iw4->___u15.masterPercentage;
|
||||
current_iw5->slavePercentage = current_iw4->___u15.slavePercentage;
|
||||
memcpy(¤t_iw5->probability, ¤t_iw4->probability, 36);
|
||||
}
|
||||
|
||||
IW5::ISound::dump(iw5_asset);
|
||||
|
||||
delete[] iw5_asset->head;
|
||||
delete iw5_asset;
|
||||
}
|
||||
}
|
||||
}
|
38
src/IW4/Assets/Sound.hpp
Normal file
38
src/IW4/Assets/Sound.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
57
src/IW4/Assets/SoundCurve.cpp
Normal file
57
src/IW4/Assets/SoundCurve.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
33
src/IW4/Assets/SoundCurve.hpp
Normal file
33
src/IW4/Assets/SoundCurve.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
222
src/IW4/Assets/StringTable.cpp
Normal file
222
src/IW4/Assets/StringTable.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
33
src/IW4/Assets/StringTable.hpp
Normal file
33
src/IW4/Assets/StringTable.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
294
src/IW4/Assets/StructuredDataDef.cpp
Normal file
294
src/IW4/Assets/StructuredDataDef.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
65
src/IW4/Assets/StructuredDataDef.hpp
Normal file
65
src/IW4/Assets/StructuredDataDef.hpp
Normal 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
593
src/IW4/Assets/Techset.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
39
src/IW4/Assets/Techset.hpp
Normal file
39
src/IW4/Assets/Techset.hpp
Normal 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
|
62
src/IW4/Assets/TracerDef.cpp
Normal file
62
src/IW4/Assets/TracerDef.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
33
src/IW4/Assets/TracerDef.hpp
Normal file
33
src/IW4/Assets/TracerDef.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
74
src/IW4/Assets/VertexDecl.cpp
Normal file
74
src/IW4/Assets/VertexDecl.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
36
src/IW4/Assets/VertexDecl.hpp
Normal file
36
src/IW4/Assets/VertexDecl.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
}
|
81
src/IW4/Assets/VertexShader.cpp
Normal file
81
src/IW4/Assets/VertexShader.cpp
Normal 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
Reference in New Issue
Block a user