Dump iw4 materials as json for data investigation purposes

This commit is contained in:
Jan 2022-04-18 14:46:13 +02:00
parent 0f47e64486
commit 2114b761b0
5 changed files with 258 additions and 10 deletions

View File

@ -632,8 +632,8 @@ namespace IW4
unsigned int nameHash; unsigned int nameHash;
char nameStart; char nameStart;
char nameEnd; char nameEnd;
char samplerState; unsigned char samplerState;
char semantic; unsigned char semantic; // TextureSemantic
MaterialTextureDefInfo u; MaterialTextureDefInfo u;
}; };
@ -735,10 +735,10 @@ namespace IW4
struct MaterialInfo struct MaterialInfo
{ {
const char* name; const char* name;
char gameFlags; unsigned char gameFlags;
char sortKey; unsigned char sortKey;
char textureAtlasRowCount; unsigned char textureAtlasRowCount;
char textureAtlasColumnCount; unsigned char textureAtlasColumnCount;
GfxDrawSurf drawSurf; GfxDrawSurf drawSurf;
unsigned int surfaceTypeBits; unsigned int surfaceTypeBits;
uint16_t hashIndex; uint16_t hashIndex;
@ -747,12 +747,12 @@ namespace IW4
struct Material struct Material
{ {
MaterialInfo info; MaterialInfo info;
char stateBitsEntry[48]; unsigned char stateBitsEntry[48];
unsigned char textureCount; unsigned char textureCount;
unsigned char constantCount; unsigned char constantCount;
unsigned char stateBitsCount; unsigned char stateBitsCount;
char stateFlags; unsigned char stateFlags;
char cameraRegion; unsigned char cameraRegion;
MaterialTechniqueSet* techniqueSet; MaterialTechniqueSet* techniqueSet;
MaterialTextureDef* textureTable; MaterialTextureDef* textureTable;
MaterialConstantDef* constantTable; MaterialConstantDef* constantTable;

View File

@ -567,5 +567,9 @@ namespace IW4
KnownMaterialSource("attenuationMap5"), KnownMaterialSource("attenuationMap5"),
KnownMaterialSource("attenuationMap6"), KnownMaterialSource("attenuationMap6"),
KnownMaterialSource("attenuationMap7"), KnownMaterialSource("attenuationMap7"),
KnownMaterialSource("distortionScale"),
KnownMaterialSource("eyeOffsetParms"),
KnownMaterialSource("falloffBeginColor"),
KnownMaterialSource("falloffEndColor"),
}; };
} }

View File

@ -0,0 +1,229 @@
#include "AssetDumperMaterial.h"
#include <iomanip>
#include <sstream>
#include <nlohmann/json.hpp>
#include "Game/IW4/TechsetConstantsIW4.h"
using namespace IW4;
using json = nlohmann::json;
namespace IW4
{
const char* AssetName(const char* name)
{
if (name && name[0] == ',')
return &name[1];
return name;
}
json BuildComplexTableJson(complex_s* complexTable, const size_t count)
{
auto jArray = json::array();
if (complexTable)
{
for (auto index = 0u; index < count; index++)
{
const auto& entry = complexTable[index];
jArray.emplace_back(json{
{"real", entry.real},
{"imag", entry.imag}
});
}
}
return jArray;
}
json BuildWaterJson(water_t* water)
{
if (!water)
return json{};
return json{
{"floatTime", water->writable.floatTime},
{"H0", BuildComplexTableJson(water->H0, water->M * water->N)},
{"wTerm", water->wTerm ? std::vector(water->wTerm, water->wTerm + (water->M * water->N)) : json::array()},
{"M", water->M},
{"N", water->N},
{"Lx", water->Lx},
{"Lz", water->Lz},
{"windvel", water->windvel},
{"winddir", std::vector(std::begin(water->winddir), std::end(water->winddir))},
{"amplitude", water->amplitude},
{"codeConstant", std::vector(std::begin(water->codeConstant), std::end(water->codeConstant))},
{"image", water->image && water->image->name ? AssetName(water->image->name) : nullptr}
};
}
json BuildTextureTableJson(MaterialTextureDef* textureTable, const size_t count)
{
auto jArray = json::array();
if (textureTable)
{
for (auto index = 0u; index < count; index++)
{
const auto& entry = textureTable[index];
json jEntry = {
{"samplerState", entry.samplerState},
{"semantic", entry.semantic}
};
const auto knownMaterialSourceName = knownMaterialSourceNames.find(entry.nameHash);
if (knownMaterialSourceName != knownMaterialSourceNames.end())
{
jEntry["name"] = knownMaterialSourceName->second;
}
else
{
jEntry.merge_patch({
{"nameHash", entry.nameHash},
{"nameStart", entry.nameStart},
{"nameEnd", entry.nameEnd},
});
}
if (entry.semantic == TS_WATER_MAP)
{
jEntry["water"] = BuildWaterJson(entry.u.water);
}
else
{
jEntry["image"] = entry.u.image && entry.u.image->name ? AssetName(entry.u.image->name) : nullptr;
}
jArray.emplace_back(std::move(jEntry));
}
}
return jArray;
}
json BuildConstantTableJson(MaterialConstantDef* constantTable, const size_t count)
{
auto jArray = json::array();
if (constantTable)
{
for (auto index = 0u; index < count; index++)
{
const auto& entry = constantTable[index];
json jEntry = {
{"literal", std::vector(std::begin(entry.literal), std::end(entry.literal))}
};
const auto nameLen = strnlen(entry.name, std::extent_v<decltype(MaterialConstantDef::name)>);
if (nameLen == std::extent_v<decltype(MaterialConstantDef::name)>)
{
std::string fullLengthName(entry.name, std::extent_v<decltype(MaterialConstantDef::name)>);
const auto fullLengthHash = Common::R_HashString(fullLengthName.c_str(), 0);
if (fullLengthHash == entry.nameHash)
{
jEntry["name"] = fullLengthName;
}
else
{
const auto knownMaterialSourceName = knownMaterialSourceNames.find(entry.nameHash);
if (knownMaterialSourceName != knownMaterialSourceNames.end())
{
jEntry["name"] = knownMaterialSourceName->second;
}
else
{
jEntry.merge_patch({
{"nameHash", entry.nameHash},
{"namePart", fullLengthName}
});
}
}
}
else
{
jEntry["name"] = std::string(entry.name, nameLen);
}
jArray.emplace_back(std::move(jEntry));
}
}
return jArray;
}
json BuildStateBitsTableJson(GfxStateBits* stateBitsTable, const size_t count)
{
auto jArray = json::array();
if (stateBitsTable)
{
for (auto index = 0u; index < count; index++)
{
const auto& entry = stateBitsTable[count];
jArray.emplace_back(json::array({
entry.loadBits[0],
entry.loadBits[1]
}));
}
}
return jArray;
}
}
bool AssetDumperMaterial::ShouldDump(XAssetInfo<Material>* asset)
{
return true;
}
void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset)
{
auto* material = asset->Asset();
std::ostringstream ss;
ss << "materials/" << asset->m_name << ".json";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile)
return;
auto& stream = *assetFile;
const json j = {
{
"info", {
{"gameFlags", material->info.gameFlags},
{"sortKey", material->info.sortKey},
{"textureAtlasRowCount", material->info.textureAtlasRowCount},
{"textureAtlasColumnCount", material->info.textureAtlasColumnCount},
{
"drawSurf", {
{"objectId", static_cast<unsigned>(material->info.drawSurf.fields.objectId)},
{"reflectionProbeIndex", static_cast<unsigned>(material->info.drawSurf.fields.reflectionProbeIndex)},
{"hasGfxEntIndex", static_cast<unsigned>(material->info.drawSurf.fields.hasGfxEntIndex)},
{"customIndex", static_cast<unsigned>(material->info.drawSurf.fields.customIndex)},
{"materialSortedIndex", static_cast<unsigned>(material->info.drawSurf.fields.materialSortedIndex)},
{"prepass", static_cast<unsigned>(material->info.drawSurf.fields.prepass)},
{"useHeroLighting", static_cast<unsigned>(material->info.drawSurf.fields.useHeroLighting)},
{"sceneLightIndex", static_cast<unsigned>(material->info.drawSurf.fields.sceneLightIndex)},
{"surfType", static_cast<unsigned>(material->info.drawSurf.fields.surfType)},
{"primarySortKey", static_cast<unsigned>(material->info.drawSurf.fields.primarySortKey)}
}
},
{"surfaceTypeBits", material->info.surfaceTypeBits},
{"hashIndex", material->info.hashIndex}
}
},
{"stateBitsEntry", std::vector(std::begin(material->stateBitsEntry), std::end(material->stateBitsEntry))},
{"stateFlags", material->stateFlags},
{"cameraRegion", material->cameraRegion},
{"techniqueSet", material->techniqueSet && material->techniqueSet->name ? AssetName(material->techniqueSet->name) : nullptr},
{"textureTable", BuildTextureTableJson(material->textureTable, material->textureCount)},
{"constantTable", BuildConstantTableJson(material->constantTable, material->constantCount)},
{"stateBitsTable", BuildStateBitsTableJson(material->stateBitsTable, material->stateBitsCount)}
};
stream << std::setw(4) << j;
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
namespace IW4
{
class AssetDumperMaterial final : public AbstractAssetDumper<Material>
{
protected:
bool ShouldDump(XAssetInfo<Material>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset) override;
};
}

View File

@ -9,6 +9,7 @@
#include "AssetDumpers/AssetDumperGfxLightDef.h" #include "AssetDumpers/AssetDumperGfxLightDef.h"
#include "AssetDumpers/AssetDumperLoadedSound.h" #include "AssetDumpers/AssetDumperLoadedSound.h"
#include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperLocalizeEntry.h"
#include "AssetDumpers/AssetDumperMaterial.h"
#include "AssetDumpers/AssetDumperMenuDef.h" #include "AssetDumpers/AssetDumperMenuDef.h"
#include "AssetDumpers/AssetDumperMenuList.h" #include "AssetDumpers/AssetDumperMenuList.h"
#include "AssetDumpers/AssetDumperPhysCollmap.h" #include "AssetDumpers/AssetDumperPhysCollmap.h"
@ -47,7 +48,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const
DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap, ASSET_TYPE_PHYSCOLLMAP) DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap, ASSET_TYPE_PHYSCOLLMAP)
// DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts, ASSET_TYPE_XANIMPARTS) // DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts, ASSET_TYPE_XANIMPARTS)
DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel, ASSET_TYPE_XMODEL) DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel, ASSET_TYPE_XMODEL)
// DUMP_ASSET_POOL(AssetDumperMaterial, m_material, ASSET_TYPE_MATERIAL) DUMP_ASSET_POOL(AssetDumperMaterial, m_material, ASSET_TYPE_MATERIAL)
DUMP_ASSET_POOL(AssetDumperPixelShader, m_material_pixel_shader, ASSET_TYPE_PIXELSHADER) DUMP_ASSET_POOL(AssetDumperPixelShader, m_material_pixel_shader, ASSET_TYPE_PIXELSHADER)
DUMP_ASSET_POOL(AssetDumperVertexShader, m_material_vertex_shader, ASSET_TYPE_VERTEXSHADER) DUMP_ASSET_POOL(AssetDumperVertexShader, m_material_vertex_shader, ASSET_TYPE_VERTEXSHADER)
DUMP_ASSET_POOL(AssetDumperTechniqueSet, m_technique_set, ASSET_TYPE_TECHNIQUE_SET) DUMP_ASSET_POOL(AssetDumperTechniqueSet, m_technique_set, ASSET_TYPE_TECHNIQUE_SET)