Dump IW4 xmodels as obj

This commit is contained in:
Jan
2021-08-01 00:30:12 +02:00
parent 2c96bc5ef8
commit 24145e15e2
11 changed files with 365 additions and 5 deletions

View File

@ -0,0 +1,183 @@
#include "AssetDumperXModel.h"
#include <set>
#include "Game/IW4/CommonIW4.h"
using namespace IW4;
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
{
return true;
}
void AssetDumperXModel::DumpObjMatMaterial(AssetDumpingContext& context, const Material* material, std::ostream& stream)
{
stream << "\n";
stream << "newmtl " << material->info.name << "\n";
GfxImage* colorMap = nullptr;
GfxImage* normalMap = nullptr;
GfxImage* specularMap = nullptr;
for(auto i = 0u; i < material->textureCount; i++)
{
const auto& texture = material->textureTable[i];
switch (texture.semantic)
{
case TS_COLOR_MAP:
colorMap = texture.u.image;
break;
case TS_NORMAL_MAP:
normalMap = texture.u.image;
break;
case TS_SPECULAR_MAP:
specularMap = texture.u.image;
break;
default:
break;
}
}
if (colorMap)
stream << "map_Ka " << colorMap->name << ".dds\n";
if (normalMap)
stream << "map_bump " << normalMap->name << ".dds\n";
if (specularMap)
stream << "map_Ks " << specularMap->name << ".dds\n";
}
void AssetDumperXModel::DumpObjMat(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
const auto matFile = context.OpenAssetFile("xmodelsurfs/" + std::string(model->name) + ".mat");
if (!matFile)
return;
auto& stream = *matFile;
stream << "# OpenAssetTools MAT File (IW4)\n";
if (model->numsurfs == 0 || model->materialHandles == nullptr)
return;
std::set<Material*> uniqueMaterials;
for (auto i = 0u; i < model->numsurfs; i++)
{
if(model->materialHandles[i] != nullptr)
uniqueMaterials.emplace(model->materialHandles[i]);
}
stream << "# Material count: " << uniqueMaterials.size() << "\n";
for(const auto* material : uniqueMaterials)
{
DumpObjMatMaterial(context, material, stream);
}
}
void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod)
{
const auto* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile("xmodelsurfs/" + std::string(modelSurfs->name) + ".obj");
if (!assetFile)
return;
auto& stream = *assetFile;
stream << "# OpenAssetTools OBJ File (IW4)\n";
stream << "mtllib " << model->name << ".mtl\n";
if (model->lodInfo[lod].modelSurfs == nullptr || model->lodInfo[lod].modelSurfs->surfs == nullptr)
return;
for (auto i = 0; i < model->lodInfo[lod].numsurfs; i++)
{
const auto* surf = &modelSurfs->surfs[i];
stream << "o surf" << i << "\n";
for (auto vi = 0; vi < surf->vertCount; vi++)
{
const auto* vertex = &surf->verts0[vi];
stream << "v " << vertex->xyz[0] << " " << vertex->xyz[1] << " " << vertex->xyz[2] << "\n";
}
stream << "\n";
for (auto vi = 0; vi < surf->vertCount; vi++)
{
const auto* vertex = &surf->verts0[vi];
vec2_t texCoords;
Common::Vec2UnpackTexCoords(vertex->texCoord, &texCoords);
stream << "vt " << texCoords[0] << " " << (1.0f - texCoords[1]) << "\n";
}
stream << "\n";
for (auto vi = 0; vi < surf->vertCount; vi++)
{
const auto* vertex = &surf->verts0[vi];
vec3_t normalVec;
Common::Vec3UnpackUnitVec(vertex->normal, &normalVec);
stream << "vn " << normalVec[0] << " " << normalVec[1] << " " << normalVec[2] << "\n";
}
stream << "\n";
if(model->numsurfs > i && model->materialHandles && model->materialHandles[i])
{
stream << "usemtl " << model->materialHandles[i]->info.name << "\n";
}
stream << "\n";
for (auto ti = 0; ti < surf->triCount; ti++)
{
const auto* indices = reinterpret_cast<r_index16_t*>(surf->triIndices);
const auto i0 = surf->baseVertIndex + indices[ti * 3 + 0] + 1;
const auto i1 = surf->baseVertIndex + indices[ti * 3 + 1] + 1;
const auto i2 = surf->baseVertIndex + indices[ti * 3 + 2] + 1;
stream << "f " << i2 << "/" << i2 << "/" << i2
<< " " << i1 << "/" << i1 << "/" << i1
<< " " << i0 << "/" << i0 << "/" << i0
<< "\n";
}
}
}
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{
DumpObjLod(context, asset, currentLod);
}
}
void AssetDumperXModel::DumpXModelExportLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod)
{
}
void AssetDumperXModel::DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpObj(context, asset);
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <ostream>
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
namespace IW4
{
class AssetDumperXModel final : public AbstractAssetDumper<XModel>
{
static void DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpObjMatMaterial(AssetDumpingContext& context, const Material* material, std::ostream& stream);
static void DumpObjMat(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpXModelExportLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
protected:
bool ShouldDump(XAssetInfo<XModel>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;
};
}

View File

@ -11,6 +11,7 @@
#include "AssetDumpers/AssetDumperStringTable.h"
#include "AssetDumpers/AssetDumperVehicle.h"
#include "AssetDumpers/AssetDumperWeapon.h"
#include "AssetDumpers/AssetDumperXModel.h"
using namespace IW4;
@ -33,7 +34,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const
// DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset)
// DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap)
// DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts)
// DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel)
DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel)
// DUMP_ASSET_POOL(AssetDumperMaterial, m_material)
// DUMP_ASSET_POOL(AssetDumperMaterialPixelShader, m_material_pixel_shader)
// DUMP_ASSET_POOL(AssetDumperMaterialVertexShader, m_material_vertex_shader)

View File

@ -14,8 +14,15 @@ public:
IWI
};
enum class ModelOutputFormat_e
{
XMODEL_EXPORT,
OBJ
};
bool Verbose = false;
ImageOutputFormat_e ImageOutputFormat = ImageOutputFormat_e::DDS;
ModelOutputFormat_e ModelOutputFormat = ModelOutputFormat_e::XMODEL_EXPORT;
} Configuration;