feat: add gltf and glb as model dumping formats

This commit is contained in:
Jan 2024-04-01 01:45:29 +02:00
parent f2438bea12
commit 8a0c93d3d8
No known key found for this signature in database
GPG Key ID: 44B581F78FF5C57C
12 changed files with 2996 additions and 3002 deletions

View File

@ -3,21 +3,29 @@
#include "Game/IW3/CommonIW3.h" #include "Game/IW3/CommonIW3.h"
#include "Math/Quaternion.h" #include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h"
#include "XModel/Gltf/GltfTextOutput.h"
#include "XModel/Gltf/GltfWriter.h"
#include "XModel/Obj/ObjWriter.h"
#include <cassert> #include <cassert>
#include <sstream> #include <format>
using namespace IW3; using namespace IW3;
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset) namespace
{ {
return !asset->m_name.empty() && asset->m_name[0] != ','; std::string GetFileNameForLod(const std::string& modelName, const unsigned lod, const std::string& extension)
{
return std::format("model_export/{}_lod{}{}", modelName, lod, extension);
} }
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material) GfxImage* GetMaterialColorMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -43,7 +51,7 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material) GfxImage* GetMaterialNormalMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -69,7 +77,7 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material) GfxImage* GetMaterialSpecularMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -95,7 +103,7 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
if (!model->materialHandles) if (!model->materialHandles)
return; return;
@ -124,7 +132,7 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
} }
} }
void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod) void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod)
{ {
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
const auto baseSurfIndex = model->lodInfo[lod].surfIndex; const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
@ -139,7 +147,7 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
} }
} }
void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod) void AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -176,7 +184,7 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, c
} }
} }
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod) void AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -203,10 +211,10 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, cons
} }
} }
void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl"); const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
if (!matFile) if (!matFile)
return; return;
@ -218,13 +226,10 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
writer.WriteMtl(*matFile); writer.WriteMtl(*matFile);
} }
void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
std::ostringstream ss; const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
ss << "model_export/" << model->name << "_lod" << lod << ".OBJ";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile) if (!assetFile)
return; return;
@ -237,21 +242,10 @@ void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XMod
AddObjVertices(writer, model, lod); AddObjVertices(writer, model, lod);
AddObjFaces(writer, model, lod); AddObjFaces(writer, model, lod);
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl"); writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
} }
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{
const auto* model = asset->Asset();
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{
DumpObjLod(context, asset, currentLod);
}
}
void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{ {
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
{ {
@ -273,8 +267,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = bone.globalRotation = Quaternion32(
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
@ -298,7 +292,7 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
} }
} }
void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++) for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
{ {
@ -318,7 +312,7 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
} }
} }
void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -331,7 +325,7 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
} }
} }
void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -370,7 +364,7 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
} }
} }
void AssetDumperXModel::AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection) void AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -397,10 +391,7 @@ void AssetDumperXModel::AllocateXModelBoneWeights(const XModel* model, const uns
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount); weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
} }
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
const XModel* model,
const unsigned lod,
XModelVertexBoneWeightCollection& weightCollection)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -504,7 +495,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4});
} }
handledVertices += surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; handledVertices +=
surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3];
} }
for (; handledVertices < surface.vertCount; handledVertices++) for (; handledVertices < surface.vertCount; handledVertices++)
@ -514,7 +506,7 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod) void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -538,52 +530,74 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
} }
} }
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
{
DistinctMapper<Material*> materialMapper(model->numsurfs);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(model, lod, boneWeightCollection);
AddXModelBones(context, writer, model);
AddXModelMaterials(writer, materialMapper, model);
AddXModelObjects(writer, model, lod);
AddXModelVertices(writer, model, lod);
AddXModelVertexBoneWeights(writer, model, lod, boneWeightCollection);
AddXModelFaces(writer, materialMapper, model, lod);
}
void DumpXModelExportLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
std::ostringstream ss;
ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile) if (!assetFile)
return; return;
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
DistinctMapper<Material*> materialMapper(model->numsurfs); PopulateXModelWriter(context, lod, model, *writer);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(model, lod, boneWeightCollection);
AddXModelBones(context, *writer, model);
AddXModelMaterials(*writer, materialMapper, model);
AddXModelObjects(*writer, model, lod);
AddXModelVertices(*writer, model, lod);
AddXModelVertexBoneWeights(*writer, model, lod, boneWeightCollection);
AddXModelFaces(*writer, materialMapper, model, lod);
writer->Write(*assetFile); writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) template<typename T> void DumpGltfLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod, const std::string& extension)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
{
DumpXModelExportLod(context, asset, currentLod); if (!assetFile)
} return;
const auto output = std::make_unique<T>(*assetFile);
const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
PopulateXModelWriter(context, lod, model, *writer);
writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
if (ObjWriting::Configuration.ModelOutputFormat == ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ)
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
switch (ObjWriting::Configuration.ModelOutputFormat) switch (ObjWriting::Configuration.ModelOutputFormat)
{ {
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
DumpObj(context, asset); DumpObjLod(context, asset, currentLod);
break; break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
DumpXModelExport(context, asset); DumpXModelExportLod(context, asset, currentLod);
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
DumpGltfLod<gltf::TextOutput>(context, asset, currentLod, ".gltf");
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
DumpGltfLod<gltf::BinOutput>(context, asset, currentLod, ".glb");
break; break;
default: default:
@ -591,3 +605,15 @@ void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XMode
break; break;
} }
} }
}
} // namespace
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpXModelSurfs(context, asset);
}

View File

@ -2,37 +2,11 @@
#include "Dumping/AbstractAssetDumper.h" #include "Dumping/AbstractAssetDumper.h"
#include "Game/IW3/IW3.h" #include "Game/IW3/IW3.h"
#include "Utils/DistinctMapper.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Obj/ObjWriter.h"
namespace IW3 namespace IW3
{ {
class AssetDumperXModel final : public AbstractAssetDumper<XModel> class AssetDumperXModel final : public AbstractAssetDumper<XModel>
{ {
static GfxImage* GetMaterialColorMap(const Material* material);
static GfxImage* GetMaterialNormalMap(const Material* material);
static GfxImage* GetMaterialSpecularMap(const Material* material);
static void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, unsigned lod);
static void AddObjVertices(ObjWriter& writer, const XModel* model, unsigned lod);
static void AddObjFaces(ObjWriter& writer, const XModel* model, unsigned lod);
static void DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, unsigned lod);
static void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, unsigned lod);
static void AllocateXModelBoneWeights(const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection);
static void
AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection);
static void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, unsigned lod);
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
protected: protected:
bool ShouldDump(XAssetInfo<XModel>* asset) override; bool ShouldDump(XAssetInfo<XModel>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;

View File

@ -3,15 +3,22 @@
#include "Game/IW4/CommonIW4.h" #include "Game/IW4/CommonIW4.h"
#include "Math/Quaternion.h" #include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h"
#include "XModel/Gltf/GltfTextOutput.h"
#include "XModel/Gltf/GltfWriter.h"
#include "XModel/Obj/ObjWriter.h"
#include <cassert> #include <cassert>
#include <format>
using namespace IW4; using namespace IW4;
namespace IW4 namespace
{ {
class SurfsDumpingZoneState final : public IZoneAssetDumperState class SurfsDumpingZoneState final : public IZoneAssetDumperState
{ {
@ -20,21 +27,15 @@ namespace IW4
public: public:
bool ShouldDumpTechnique(const XModelSurfs* surfs) bool ShouldDumpTechnique(const XModelSurfs* surfs)
{ {
if (m_dumped_surfs.find(surfs) != m_dumped_surfs.end()) if (m_dumped_surfs.contains(surfs))
return false; return false;
m_dumped_surfs.emplace(surfs); m_dumped_surfs.emplace(surfs);
return true; return true;
} }
}; };
} // namespace IW4
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset) GfxImage* GetMaterialColorMap(const Material* material)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -60,7 +61,7 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material) GfxImage* GetMaterialNormalMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -86,7 +87,7 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material) GfxImage* GetMaterialSpecularMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -112,7 +113,7 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
if (!model->materialHandles) if (!model->materialHandles)
return; return;
@ -141,7 +142,7 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
} }
} }
void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex) void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -153,7 +154,7 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
} }
} }
void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs) void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -187,7 +188,7 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* mod
} }
} }
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs) void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -211,10 +212,10 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelS
} }
} }
void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl"); const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
if (!matFile) if (!matFile)
return; return;
@ -226,7 +227,7 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
writer.WriteMtl(*matFile); writer.WriteMtl(*matFile);
} }
void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs; const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
@ -234,7 +235,7 @@ void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInf
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
return; return;
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".obj"); const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.obj", modelSurfs->name));
if (!assetFile) if (!assetFile)
return; return;
@ -247,25 +248,10 @@ void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInf
AddObjVertices(writer, modelSurfs); AddObjVertices(writer, modelSurfs);
AddObjFaces(writer, modelSurfs); AddObjFaces(writer, modelSurfs);
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl"); writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
} }
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{
const auto* model = asset->Asset();
auto* surfZoneState = context.GetZoneAssetDumperState<SurfsDumpingZoneState>();
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{
if (!model->lodInfo[currentLod].modelSurfs || !surfZoneState->ShouldDumpTechnique(model->lodInfo[currentLod].modelSurfs))
continue;
DumpObjLod(context, asset, currentLod);
}
}
void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{ {
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
{ {
@ -287,8 +273,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = bone.globalRotation = Quaternion32(
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
@ -312,7 +298,7 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
} }
} }
void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++) for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
{ {
@ -332,7 +318,7 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
} }
} }
void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs) void AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -343,7 +329,7 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
} }
} }
void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs) void AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -379,7 +365,7 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
} }
} }
void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection) void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
{ {
weightCollection.totalWeightCount = 0u; weightCollection.totalWeightCount = 0u;
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
@ -403,9 +389,7 @@ void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs,
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount); weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
} }
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
const XModelSurfs* modelSurfs,
XModelVertexBoneWeightCollection& weightCollection)
{ {
size_t weightOffset = 0u; size_t weightOffset = 0u;
@ -506,7 +490,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4});
} }
handledVertices += surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; handledVertices +=
surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3];
} }
for (; handledVertices < surface.vertCount; handledVertices++) for (; handledVertices < surface.vertCount; handledVertices++)
@ -516,10 +501,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, void
const DistinctMapper<Material*>& materialMapper, AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, const int baseSurfaceIndex)
const XModelSurfs* modelSurfs,
const int baseSurfaceIndex)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -539,56 +522,78 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
{
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
DistinctMapper<Material*> materialMapper(model->numsurfs);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
AddXModelBones(context, writer, model);
AddXModelMaterials(writer, materialMapper, model);
AddXModelObjects(writer, modelSurfs);
AddXModelVertices(writer, modelSurfs);
AddXModelVertexBoneWeights(writer, modelSurfs, boneWeightCollection);
AddXModelFaces(writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
}
void DumpXModelExportLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs; const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.XMODEL_EXPORT", modelSurfs->name));
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
return;
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".XMODEL_EXPORT");
if (!assetFile) if (!assetFile)
return; return;
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
DistinctMapper<Material*> materialMapper(model->numsurfs); PopulateXModelWriter(context, lod, model, *writer);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
AddXModelBones(context, *writer, model);
AddXModelMaterials(*writer, materialMapper, model);
AddXModelObjects(*writer, modelSurfs);
AddXModelVertices(*writer, modelSurfs);
AddXModelVertexBoneWeights(*writer, modelSurfs, boneWeightCollection);
AddXModelFaces(*writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
writer->Write(*assetFile); writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset) template<typename T> void DumpGltfLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod, const std::string& extension)
{ {
auto* surfZoneState = context.GetZoneAssetDumperState<SurfsDumpingZoneState>();
const auto* model = asset->Asset(); const auto* model = asset->Asset();
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
{ const auto assetFile = context.OpenAssetFile(std::format("model_export/{}{}", modelSurfs->name, extension));
if (!model->lodInfo[currentLod].modelSurfs || !surfZoneState->ShouldDumpTechnique(model->lodInfo[currentLod].modelSurfs))
continue; if (!assetFile)
DumpXModelExportLod(context, asset, currentLod); return;
}
const auto output = std::make_unique<T>(*assetFile);
const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
PopulateXModelWriter(context, lod, model, *writer);
writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
if (ObjWriting::Configuration.ModelOutputFormat == ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ)
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
switch (ObjWriting::Configuration.ModelOutputFormat) switch (ObjWriting::Configuration.ModelOutputFormat)
{ {
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
DumpObj(context, asset); DumpObjLod(context, asset, currentLod);
break; break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
DumpXModelExport(context, asset); DumpXModelExportLod(context, asset, currentLod);
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
DumpGltfLod<gltf::TextOutput>(context, asset, currentLod, ".gltf");
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
DumpGltfLod<gltf::BinOutput>(context, asset, currentLod, ".glb");
break; break;
default: default:
@ -596,3 +601,15 @@ void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XMode
break; break;
} }
} }
}
} // namespace
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpXModelSurfs(context, asset);
}

View File

@ -2,37 +2,11 @@
#include "Dumping/AbstractAssetDumper.h" #include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h" #include "Game/IW4/IW4.h"
#include "Utils/DistinctMapper.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Obj/ObjWriter.h"
namespace IW4 namespace IW4
{ {
class AssetDumperXModel final : public AbstractAssetDumper<XModel> class AssetDumperXModel final : public AbstractAssetDumper<XModel>
{ {
static GfxImage* GetMaterialColorMap(const Material* material);
static GfxImage* GetMaterialNormalMap(const Material* material);
static GfxImage* GetMaterialSpecularMap(const Material* material);
static void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
static void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs);
static void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs);
static void DumpObjLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod);
static void DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
static void AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
static void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
static void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
static void
AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
protected: protected:
bool ShouldDump(XAssetInfo<XModel>* asset) override; bool ShouldDump(XAssetInfo<XModel>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;

View File

@ -3,15 +3,22 @@
#include "Game/IW5/CommonIW5.h" #include "Game/IW5/CommonIW5.h"
#include "Math/Quaternion.h" #include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h"
#include "XModel/Gltf/GltfTextOutput.h"
#include "XModel/Gltf/GltfWriter.h"
#include "XModel/Obj/ObjWriter.h"
#include <cassert> #include <cassert>
#include <format>
using namespace IW5; using namespace IW5;
namespace IW5 namespace
{ {
class SurfsDumpingZoneState final : public IZoneAssetDumperState class SurfsDumpingZoneState final : public IZoneAssetDumperState
{ {
@ -20,21 +27,15 @@ namespace IW5
public: public:
bool ShouldDumpTechnique(const XModelSurfs* surfs) bool ShouldDumpTechnique(const XModelSurfs* surfs)
{ {
if (m_dumped_surfs.find(surfs) != m_dumped_surfs.end()) if (m_dumped_surfs.contains(surfs))
return false; return false;
m_dumped_surfs.emplace(surfs); m_dumped_surfs.emplace(surfs);
return true; return true;
} }
}; };
} // namespace IW5
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset) GfxImage* GetMaterialColorMap(const Material* material)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -60,7 +61,7 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material) GfxImage* GetMaterialNormalMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -86,7 +87,7 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material) GfxImage* GetMaterialSpecularMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -112,7 +113,7 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
if (!model->materialHandles) if (!model->materialHandles)
return; return;
@ -140,7 +141,7 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
} }
} }
void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex) void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -152,7 +153,7 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
} }
} }
void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs) void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -186,7 +187,7 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* mod
} }
} }
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs) void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -210,10 +211,10 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelS
} }
} }
void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl"); const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
if (!matFile) if (!matFile)
return; return;
@ -225,7 +226,7 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
writer.WriteMtl(*matFile); writer.WriteMtl(*matFile);
} }
void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs; const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
@ -233,7 +234,7 @@ void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInf
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
return; return;
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".obj"); const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.obj", modelSurfs->name));
if (!assetFile) if (!assetFile)
return; return;
@ -246,25 +247,10 @@ void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInf
AddObjVertices(writer, modelSurfs); AddObjVertices(writer, modelSurfs);
AddObjFaces(writer, modelSurfs); AddObjFaces(writer, modelSurfs);
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl"); writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
} }
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{
const auto* model = asset->Asset();
auto* surfZoneState = context.GetZoneAssetDumperState<SurfsDumpingZoneState>();
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{
if (!model->lodInfo[currentLod].modelSurfs || !surfZoneState->ShouldDumpTechnique(model->lodInfo[currentLod].modelSurfs))
continue;
DumpObjLod(context, asset, currentLod);
}
}
void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{ {
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
{ {
@ -286,8 +272,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = bone.globalRotation = Quaternion32(
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
@ -311,7 +297,7 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
} }
} }
void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++) for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
{ {
@ -331,7 +317,7 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
} }
} }
void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs) void AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -342,7 +328,7 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
} }
} }
void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs) void AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -378,7 +364,7 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
} }
} }
void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection) void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
{ {
weightCollection.totalWeightCount = 0u; weightCollection.totalWeightCount = 0u;
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
@ -402,9 +388,7 @@ void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs,
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount); weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
} }
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
const XModelSurfs* modelSurfs,
XModelVertexBoneWeightCollection& weightCollection)
{ {
size_t weightOffset = 0u; size_t weightOffset = 0u;
@ -505,7 +489,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4});
} }
handledVertices += surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; handledVertices +=
surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3];
} }
for (; handledVertices < surface.vertCount; handledVertices++) for (; handledVertices < surface.vertCount; handledVertices++)
@ -515,10 +500,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, void
const DistinctMapper<Material*>& materialMapper, AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, const int baseSurfaceIndex)
const XModelSurfs* modelSurfs,
const int baseSurfaceIndex)
{ {
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
{ {
@ -538,56 +521,78 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
{
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
DistinctMapper<Material*> materialMapper(model->numsurfs);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
AddXModelBones(context, writer, model);
AddXModelMaterials(writer, materialMapper, model);
AddXModelObjects(writer, modelSurfs);
AddXModelVertices(writer, modelSurfs);
AddXModelVertexBoneWeights(writer, modelSurfs, boneWeightCollection);
AddXModelFaces(writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
}
void DumpXModelExportLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs; const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.XMODEL_EXPORT", modelSurfs->name));
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
return;
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".XMODEL_EXPORT");
if (!assetFile) if (!assetFile)
return; return;
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
DistinctMapper<Material*> materialMapper(model->numsurfs); PopulateXModelWriter(context, lod, model, *writer);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
AddXModelBones(context, *writer, model);
AddXModelMaterials(*writer, materialMapper, model);
AddXModelObjects(*writer, modelSurfs);
AddXModelVertices(*writer, modelSurfs);
AddXModelVertexBoneWeights(*writer, modelSurfs, boneWeightCollection);
AddXModelFaces(*writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
writer->Write(*assetFile); writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset) template<typename T> void DumpGltfLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod, const std::string& extension)
{ {
auto* surfZoneState = context.GetZoneAssetDumperState<SurfsDumpingZoneState>();
const auto* model = asset->Asset(); const auto* model = asset->Asset();
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
{ const auto assetFile = context.OpenAssetFile(std::format("model_export/{}{}", modelSurfs->name, extension));
if (!model->lodInfo[currentLod].modelSurfs || !surfZoneState->ShouldDumpTechnique(model->lodInfo[currentLod].modelSurfs))
continue; if (!assetFile)
DumpXModelExportLod(context, asset, currentLod); return;
}
const auto output = std::make_unique<T>(*assetFile);
const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
PopulateXModelWriter(context, lod, model, *writer);
writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
if (ObjWriting::Configuration.ModelOutputFormat == ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ)
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
switch (ObjWriting::Configuration.ModelOutputFormat) switch (ObjWriting::Configuration.ModelOutputFormat)
{ {
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
DumpObj(context, asset); DumpObjLod(context, asset, currentLod);
break; break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
DumpXModelExport(context, asset); DumpXModelExportLod(context, asset, currentLod);
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
DumpGltfLod<gltf::TextOutput>(context, asset, currentLod, ".gltf");
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
DumpGltfLod<gltf::BinOutput>(context, asset, currentLod, ".glb");
break; break;
default: default:
@ -595,3 +600,15 @@ void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XMode
break; break;
} }
} }
}
} // namespace
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpXModelSurfs(context, asset);
}

View File

@ -2,37 +2,11 @@
#include "Dumping/AbstractAssetDumper.h" #include "Dumping/AbstractAssetDumper.h"
#include "Game/IW5/IW5.h" #include "Game/IW5/IW5.h"
#include "Utils/DistinctMapper.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Obj/ObjWriter.h"
namespace IW5 namespace IW5
{ {
class AssetDumperXModel final : public AbstractAssetDumper<XModel> class AssetDumperXModel final : public AbstractAssetDumper<XModel>
{ {
static GfxImage* GetMaterialColorMap(const Material* material);
static GfxImage* GetMaterialNormalMap(const Material* material);
static GfxImage* GetMaterialSpecularMap(const Material* material);
static void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
static void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs);
static void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs);
static void DumpObjLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod);
static void DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
static void AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
static void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
static void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
static void
AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
protected: protected:
bool ShouldDump(XAssetInfo<XModel>* asset) override; bool ShouldDump(XAssetInfo<XModel>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;

View File

@ -3,21 +3,29 @@
#include "Game/T5/CommonT5.h" #include "Game/T5/CommonT5.h"
#include "Math/Quaternion.h" #include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h"
#include "XModel/Gltf/GltfTextOutput.h"
#include "XModel/Gltf/GltfWriter.h"
#include "XModel/Obj/ObjWriter.h"
#include <cassert> #include <cassert>
#include <sstream> #include <format>
using namespace T5; using namespace T5;
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset) namespace
{ {
return !asset->m_name.empty() && asset->m_name[0] != ','; std::string GetFileNameForLod(const std::string& modelName, const unsigned lod, const std::string& extension)
{
return std::format("model_export/{}_lod{}{}", modelName, lod, extension);
} }
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material) GfxImage* GetMaterialColorMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -43,7 +51,7 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material) GfxImage* GetMaterialNormalMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -69,7 +77,7 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material) GfxImage* GetMaterialSpecularMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -95,7 +103,7 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
return potentialTextureDefs[0]->u.image; return potentialTextureDefs[0]->u.image;
} }
void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
if (!model->materialHandles) if (!model->materialHandles)
return; return;
@ -124,7 +132,7 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
} }
} }
void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod) void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod)
{ {
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
const auto baseSurfIndex = model->lodInfo[lod].surfIndex; const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
@ -139,7 +147,7 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
} }
} }
void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod) void AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -176,7 +184,7 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, c
} }
} }
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod) void AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -203,10 +211,10 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, cons
} }
} }
void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl"); const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
if (!matFile) if (!matFile)
return; return;
@ -218,13 +226,10 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
writer.WriteMtl(*matFile); writer.WriteMtl(*matFile);
} }
void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
std::ostringstream ss; const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
ss << "model_export/" << model->name << "_lod" << lod << ".OBJ";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile) if (!assetFile)
return; return;
@ -237,21 +242,10 @@ void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XMod
AddObjVertices(writer, model, lod); AddObjVertices(writer, model, lod);
AddObjFaces(writer, model, lod); AddObjFaces(writer, model, lod);
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl"); writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
} }
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{
const auto* model = asset->Asset();
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{
DumpObjLod(context, asset, currentLod);
}
}
void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{ {
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
{ {
@ -273,8 +267,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = bone.globalRotation = Quaternion32(
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
@ -298,7 +292,7 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
} }
} }
void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++) for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
{ {
@ -318,7 +312,7 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
} }
} }
void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -331,7 +325,7 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
} }
} }
void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -370,7 +364,7 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
} }
} }
void AssetDumperXModel::AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection) void AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -397,10 +391,7 @@ void AssetDumperXModel::AllocateXModelBoneWeights(const XModel* model, const uns
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount); weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
} }
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
const XModel* model,
const unsigned lod,
XModelVertexBoneWeightCollection& weightCollection)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -504,7 +495,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4});
} }
handledVertices += surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; handledVertices +=
surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3];
} }
for (; handledVertices < surface.vertCount; handledVertices++) for (; handledVertices < surface.vertCount; handledVertices++)
@ -514,7 +506,7 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod) void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -538,52 +530,74 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
} }
} }
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
{
DistinctMapper<Material*> materialMapper(model->numsurfs);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(model, lod, boneWeightCollection);
AddXModelBones(context, writer, model);
AddXModelMaterials(writer, materialMapper, model);
AddXModelObjects(writer, model, lod);
AddXModelVertices(writer, model, lod);
AddXModelVertexBoneWeights(writer, model, lod, boneWeightCollection);
AddXModelFaces(writer, materialMapper, model, lod);
}
void DumpXModelExportLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
std::ostringstream ss;
ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile) if (!assetFile)
return; return;
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
DistinctMapper<Material*> materialMapper(model->numsurfs); PopulateXModelWriter(context, lod, model, *writer);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(model, lod, boneWeightCollection);
AddXModelBones(context, *writer, model);
AddXModelMaterials(*writer, materialMapper, model);
AddXModelObjects(*writer, model, lod);
AddXModelVertices(*writer, model, lod);
AddXModelVertexBoneWeights(*writer, model, lod, boneWeightCollection);
AddXModelFaces(*writer, materialMapper, model, lod);
writer->Write(*assetFile); writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) template<typename T> void DumpGltfLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod, const std::string& extension)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
{
DumpXModelExportLod(context, asset, currentLod); if (!assetFile)
} return;
const auto output = std::make_unique<T>(*assetFile);
const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
PopulateXModelWriter(context, lod, model, *writer);
writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
if (ObjWriting::Configuration.ModelOutputFormat == ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ)
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
switch (ObjWriting::Configuration.ModelOutputFormat) switch (ObjWriting::Configuration.ModelOutputFormat)
{ {
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
DumpObj(context, asset); DumpObjLod(context, asset, currentLod);
break; break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
DumpXModelExport(context, asset); DumpXModelExportLod(context, asset, currentLod);
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
DumpGltfLod<gltf::TextOutput>(context, asset, currentLod, ".gltf");
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
DumpGltfLod<gltf::BinOutput>(context, asset, currentLod, ".glb");
break; break;
default: default:
@ -591,3 +605,15 @@ void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XMode
break; break;
} }
} }
}
} // namespace
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpXModelSurfs(context, asset);
}

View File

@ -2,37 +2,11 @@
#include "Dumping/AbstractAssetDumper.h" #include "Dumping/AbstractAssetDumper.h"
#include "Game/T5/T5.h" #include "Game/T5/T5.h"
#include "Utils/DistinctMapper.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Obj/ObjWriter.h"
namespace T5 namespace T5
{ {
class AssetDumperXModel final : public AbstractAssetDumper<XModel> class AssetDumperXModel final : public AbstractAssetDumper<XModel>
{ {
static GfxImage* GetMaterialColorMap(const Material* material);
static GfxImage* GetMaterialNormalMap(const Material* material);
static GfxImage* GetMaterialSpecularMap(const Material* material);
static void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, unsigned lod);
static void AddObjVertices(ObjWriter& writer, const XModel* model, unsigned lod);
static void AddObjFaces(ObjWriter& writer, const XModel* model, unsigned lod);
static void DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, unsigned lod);
static void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, unsigned lod);
static void AllocateXModelBoneWeights(const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection);
static void
AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection);
static void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, unsigned lod);
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
protected: protected:
bool ShouldDump(XAssetInfo<XModel>* asset) override; bool ShouldDump(XAssetInfo<XModel>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;

View File

@ -3,21 +3,29 @@
#include "Game/T6/CommonT6.h" #include "Game/T6/CommonT6.h"
#include "Math/Quaternion.h" #include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h"
#include "XModel/Gltf/GltfTextOutput.h"
#include "XModel/Gltf/GltfWriter.h"
#include "XModel/Obj/ObjWriter.h"
#include <cassert> #include <cassert>
#include <sstream> #include <format>
using namespace T6; using namespace T6;
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset) namespace
{ {
return !asset->m_name.empty() && asset->m_name[0] != ','; std::string GetFileNameForLod(const std::string& modelName, const unsigned lod, const std::string& extension)
{
return std::format("model_export/{}_lod{}{}", modelName, lod, extension);
} }
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material) GfxImage* GetMaterialColorMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -55,7 +63,7 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
return potentialTextureDefs[0]->image; return potentialTextureDefs[0]->image;
} }
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material) GfxImage* GetMaterialNormalMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -81,7 +89,7 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
return potentialTextureDefs[0]->image; return potentialTextureDefs[0]->image;
} }
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material) GfxImage* GetMaterialSpecularMap(const Material* material)
{ {
std::vector<MaterialTextureDef*> potentialTextureDefs; std::vector<MaterialTextureDef*> potentialTextureDefs;
@ -107,7 +115,7 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
return potentialTextureDefs[0]->image; return potentialTextureDefs[0]->image;
} }
void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
if (!model->materialHandles) if (!model->materialHandles)
return; return;
@ -136,7 +144,7 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
} }
} }
void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod) void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod)
{ {
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
const auto baseSurfIndex = model->lodInfo[lod].surfIndex; const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
@ -151,7 +159,7 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
} }
} }
void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod) void AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -188,7 +196,7 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, c
} }
} }
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod) void AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -215,10 +223,10 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, cons
} }
} }
void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl"); const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
if (!matFile) if (!matFile)
return; return;
@ -230,13 +238,10 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
writer.WriteMtl(*matFile); writer.WriteMtl(*matFile);
} }
void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
std::ostringstream ss; const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
ss << "model_export/" << model->name << "_lod" << lod << ".OBJ";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile) if (!assetFile)
return; return;
@ -249,21 +254,10 @@ void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XMod
AddObjVertices(writer, model, lod); AddObjVertices(writer, model, lod);
AddObjFaces(writer, model, lod); AddObjFaces(writer, model, lod);
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl"); writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
} }
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{
const auto* model = asset->Asset();
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{
DumpObjLod(context, asset, currentLod);
}
}
void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
{ {
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
{ {
@ -310,7 +304,7 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
} }
} }
void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model) void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
{ {
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++) for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
{ {
@ -330,7 +324,7 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
} }
} }
void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -343,7 +337,7 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
} }
} }
void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -385,7 +379,7 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
} }
} }
void AssetDumperXModel::AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection) void AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -415,10 +409,7 @@ void AssetDumperXModel::AllocateXModelBoneWeights(const XModel* model, const uns
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount); weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
} }
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
const XModel* model,
const unsigned lod,
XModelVertexBoneWeightCollection& weightCollection)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -525,7 +516,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{boneWeightOffset, 4});
} }
handledVertices += surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; handledVertices +=
surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3];
} }
for (; handledVertices < surface.vertCount; handledVertices++) for (; handledVertices < surface.vertCount; handledVertices++)
@ -535,7 +527,7 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
} }
} }
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod) void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
const auto surfCount = model->lodInfo[lod].numsurfs; const auto surfCount = model->lodInfo[lod].numsurfs;
@ -562,52 +554,74 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
} }
} }
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod) void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
{
DistinctMapper<Material*> materialMapper(model->numsurfs);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(model, lod, boneWeightCollection);
AddXModelBones(context, writer, model);
AddXModelMaterials(writer, materialMapper, model);
AddXModelObjects(writer, model, lod);
AddXModelVertices(writer, model, lod);
AddXModelVertexBoneWeights(writer, model, lod, boneWeightCollection);
AddXModelFaces(writer, materialMapper, model, lod);
}
void DumpXModelExportLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
std::ostringstream ss;
ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT";
const auto assetFile = context.OpenAssetFile(ss.str());
if (!assetFile) if (!assetFile)
return; return;
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
DistinctMapper<Material*> materialMapper(model->numsurfs); PopulateXModelWriter(context, lod, model, *writer);
XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(model, lod, boneWeightCollection);
AddXModelBones(context, *writer, model);
AddXModelMaterials(*writer, materialMapper, model);
AddXModelObjects(*writer, model, lod);
AddXModelVertices(*writer, model, lod);
AddXModelVertexBoneWeights(*writer, model, lod, boneWeightCollection);
AddXModelFaces(*writer, materialMapper, model, lod);
writer->Write(*assetFile); writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset) template<typename T> void DumpGltfLod(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod, const std::string& extension)
{ {
const auto* model = asset->Asset(); const auto* model = asset->Asset();
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
{
DumpXModelExportLod(context, asset, currentLod); if (!assetFile)
} return;
const auto output = std::make_unique<T>(*assetFile);
const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
PopulateXModelWriter(context, lod, model, *writer);
writer->Write(*assetFile);
} }
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
{
const auto* model = asset->Asset();
if (ObjWriting::Configuration.ModelOutputFormat == ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ)
DumpObjMat(context, asset);
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
switch (ObjWriting::Configuration.ModelOutputFormat) switch (ObjWriting::Configuration.ModelOutputFormat)
{ {
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
DumpObj(context, asset); DumpObjLod(context, asset, currentLod);
break; break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
DumpXModelExport(context, asset); DumpXModelExportLod(context, asset, currentLod);
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
DumpGltfLod<gltf::TextOutput>(context, asset, currentLod, ".gltf");
break;
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
DumpGltfLod<gltf::BinOutput>(context, asset, currentLod, ".glb");
break; break;
default: default:
@ -615,3 +629,15 @@ void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XMode
break; break;
} }
} }
}
} // namespace
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
{
return !asset->m_name.empty() && asset->m_name[0] != ',';
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpXModelSurfs(context, asset);
}

View File

@ -2,37 +2,11 @@
#include "Dumping/AbstractAssetDumper.h" #include "Dumping/AbstractAssetDumper.h"
#include "Game/T6/T6.h" #include "Game/T6/T6.h"
#include "Utils/DistinctMapper.h"
#include "XModel/AbstractXModelWriter.h"
#include "XModel/Obj/ObjWriter.h"
namespace T6 namespace T6
{ {
class AssetDumperXModel final : public AbstractAssetDumper<XModel> class AssetDumperXModel final : public AbstractAssetDumper<XModel>
{ {
static GfxImage* GetMaterialColorMap(const Material* material);
static GfxImage* GetMaterialNormalMap(const Material* material);
static GfxImage* GetMaterialSpecularMap(const Material* material);
static void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, unsigned lod);
static void AddObjVertices(ObjWriter& writer, const XModel* model, unsigned lod);
static void AddObjFaces(ObjWriter& writer, const XModel* model, unsigned lod);
static void DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpObjMat(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
static void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, unsigned lod);
static void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, unsigned lod);
static void AllocateXModelBoneWeights(const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection);
static void
AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection);
static void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModel* model, unsigned lod);
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
static void DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
protected: protected:
bool ShouldDump(XAssetInfo<XModel>* asset) override; bool ShouldDump(XAssetInfo<XModel>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override; void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;

View File

@ -20,14 +20,16 @@ public:
enum class ModelOutputFormat_e enum class ModelOutputFormat_e
{ {
XMODEL_EXPORT, XMODEL_EXPORT,
OBJ OBJ,
GLTF,
GLB
}; };
bool Verbose = false; bool Verbose = false;
std::vector<bool> AssetTypesToHandleBitfield; std::vector<bool> AssetTypesToHandleBitfield;
ImageOutputFormat_e ImageOutputFormat = ImageOutputFormat_e::DDS; ImageOutputFormat_e ImageOutputFormat = ImageOutputFormat_e::DDS;
ModelOutputFormat_e ModelOutputFormat = ModelOutputFormat_e::XMODEL_EXPORT; ModelOutputFormat_e ModelOutputFormat = ModelOutputFormat_e::GLB;
bool MenuLegacyMode = false; bool MenuLegacyMode = false;
} Configuration; } Configuration;

View File

@ -5,6 +5,7 @@
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/Arguments/UsageInformation.h" #include "Utils/Arguments/UsageInformation.h"
#include "Utils/FileUtils.h" #include "Utils/FileUtils.h"
#include "Utils/StringUtils.h"
#include <iostream> #include <iostream>
#include <regex> #include <regex>
@ -79,7 +80,7 @@ const CommandLineOption* const OPTION_IMAGE_FORMAT =
const CommandLineOption* const OPTION_MODEL_FORMAT = const CommandLineOption* const OPTION_MODEL_FORMAT =
CommandLineOption::Builder::Create() CommandLineOption::Builder::Create()
.WithLongName("model-format") .WithLongName("model-format")
.WithDescription("Specifies the format of dumped model files. Valid values are: XMODEL_EXPORT, OBJ") .WithDescription("Specifies the format of dumped model files. Valid values are: XMODEL_EXPORT, OBJ, GLTF, GLB")
.WithParameter("modelFormatValue") .WithParameter("modelFormatValue")
.Build(); .Build();
@ -179,8 +180,7 @@ void UnlinkerArgs::SetVerbose(const bool isVerbose)
bool UnlinkerArgs::SetImageDumpingMode() bool UnlinkerArgs::SetImageDumpingMode()
{ {
auto specifiedValue = m_argument_parser.GetValueForOption(OPTION_IMAGE_FORMAT); auto specifiedValue = m_argument_parser.GetValueForOption(OPTION_IMAGE_FORMAT);
for (auto& c : specifiedValue) utils::MakeStringLowerCase(specifiedValue);
c = static_cast<char>(tolower(c));
if (specifiedValue == "dds") if (specifiedValue == "dds")
{ {
@ -202,8 +202,7 @@ bool UnlinkerArgs::SetImageDumpingMode()
bool UnlinkerArgs::SetModelDumpingMode() bool UnlinkerArgs::SetModelDumpingMode()
{ {
auto specifiedValue = m_argument_parser.GetValueForOption(OPTION_MODEL_FORMAT); auto specifiedValue = m_argument_parser.GetValueForOption(OPTION_MODEL_FORMAT);
for (auto& c : specifiedValue) utils::MakeStringLowerCase(specifiedValue);
c = static_cast<char>(tolower(c));
if (specifiedValue == "xmodel_export") if (specifiedValue == "xmodel_export")
{ {
@ -217,6 +216,18 @@ bool UnlinkerArgs::SetModelDumpingMode()
return true; return true;
} }
if (specifiedValue == "gltf")
{
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF;
return true;
}
if (specifiedValue == "glb")
{
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::GLB;
return true;
}
const std::string originalValue = m_argument_parser.GetValueForOption(OPTION_MODEL_FORMAT); const std::string originalValue = m_argument_parser.GetValueForOption(OPTION_MODEL_FORMAT);
printf("Illegal value: \"%s\" is not a valid model output format. Use -? to see usage information.\n", originalValue.c_str()); printf("Illegal value: \"%s\" is not a valid model output format. Use -? to see usage information.\n", originalValue.c_str());
return false; return false;
@ -238,8 +249,7 @@ void UnlinkerArgs::ParseCommaSeparatedAssetTypeString(const std::string& input)
size_t endPos; size_t endPos;
std::string lowerInput(input); std::string lowerInput(input);
for (auto& c : lowerInput) utils::MakeStringLowerCase(lowerInput);
c = static_cast<char>(tolower(c));
while (currentPos < lowerInput.size() && (endPos = lowerInput.find_first_of(',', currentPos)) != std::string::npos) while (currentPos < lowerInput.size() && (endPos = lowerInput.find_first_of(',', currentPos)) != std::string::npos)
{ {