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,22 +3,30 @@
#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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -41,10 +49,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -67,10 +75,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -93,10 +101,10 @@ 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;
@ -122,10 +130,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
writer.AddMaterial(std::move(mtl)); writer.AddMaterial(std::move(mtl));
} }
} }
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;
@ -137,10 +145,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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;
@ -174,10 +182,10 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, c
writer.AddUv(static_cast<int>(surfIndex), objUv); writer.AddUv(static_cast<int>(surfIndex), objUv);
} }
} }
} }
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;
@ -201,12 +209,12 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, cons
writer.AddFace(static_cast<int>(surfIndex), face); writer.AddFace(static_cast<int>(surfIndex), face);
} }
} }
} }
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;
@ -216,15 +224,12 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
AddObjMaterials(writer, materialMapper, model); AddObjMaterials(writer, materialMapper, model);
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,22 +242,11 @@ 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)
{
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) void 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++)
{ {
XModelBone bone; XModelBone bone;
@ -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)
{ {
@ -296,10 +290,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
writer.AddBone(std::move(bone)); writer.AddBone(std::move(bone));
} }
} }
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++)
{ {
Material* material = model->materialHandles[surfaceMaterialNum]; Material* material = model->materialHandles[surfaceMaterialNum];
@ -316,10 +310,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
writer.AddMaterial(std::move(xMaterial)); writer.AddMaterial(std::move(xMaterial));
} }
} }
} }
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;
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
@ -329,10 +323,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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;
@ -368,10 +362,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
writer.AddVertex(vertex); writer.AddVertex(vertex);
} }
} }
} }
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;
@ -395,13 +389,10 @@ 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++)
@ -512,10 +504,10 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
} }
} }
} }
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;
const auto baseSurfIndex = model->lodInfo[lod].surfIndex; const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
@ -536,58 +528,92 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
writer.AddFace(face); writer.AddFace(face);
} }
} }
} }
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();
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
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 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++) for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
DumpXModelExportLod(context, asset, currentLod);
}
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
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:
assert(false); assert(false);
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,22 +27,16 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -58,10 +59,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -84,10 +85,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -110,10 +111,10 @@ 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;
@ -139,10 +140,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
writer.AddMaterial(std::move(mtl)); writer.AddMaterial(std::move(mtl));
} }
} }
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++)
{ {
ObjObject object; ObjObject object;
@ -151,10 +152,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -185,10 +186,10 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* mod
writer.AddUv(static_cast<int>(surfIndex), objUv); writer.AddUv(static_cast<int>(surfIndex), objUv);
} }
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -209,12 +210,12 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelS
writer.AddFace(static_cast<int>(surfIndex), face); writer.AddFace(static_cast<int>(surfIndex), face);
} }
} }
} }
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;
@ -224,17 +225,17 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
AddObjMaterials(writer, materialMapper, model); AddObjMaterials(writer, materialMapper, model);
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;
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,26 +248,11 @@ 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)
{
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) void 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++)
{ {
XModelBone bone; XModelBone bone;
@ -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)
{ {
@ -310,10 +296,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
writer.AddBone(std::move(bone)); writer.AddBone(std::move(bone));
} }
} }
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++)
{ {
Material* material = model->materialHandles[surfaceMaterialNum]; Material* material = model->materialHandles[surfaceMaterialNum];
@ -330,10 +316,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
writer.AddMaterial(std::move(xMaterial)); writer.AddMaterial(std::move(xMaterial));
} }
} }
} }
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++)
{ {
XModelObject object; XModelObject object;
@ -341,10 +327,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -377,10 +363,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
writer.AddVertex(vertex); writer.AddVertex(vertex);
} }
} }
} }
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++)
{ {
@ -401,12 +387,10 @@ 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;
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
@ -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++)
@ -514,13 +499,11 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
} }
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -537,62 +520,96 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
writer.AddFace(face); writer.AddFace(face);
} }
} }
} }
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* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs; const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) DistinctMapper<Material*> materialMapper(model->numsurfs);
return; XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".XMODEL_EXPORT"); 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* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.XMODEL_EXPORT", modelSurfs->name));
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();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile(std::format("model_export/{}{}", modelSurfs->name, extension));
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 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++) for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
if (!model->lodInfo[currentLod].modelSurfs || !surfZoneState->ShouldDumpTechnique(model->lodInfo[currentLod].modelSurfs))
continue;
DumpXModelExportLod(context, asset, currentLod);
}
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
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:
assert(false); assert(false);
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,22 +27,16 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -58,10 +59,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -84,10 +85,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -110,10 +111,10 @@ 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;
@ -138,10 +139,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
writer.AddMaterial(std::move(mtl)); writer.AddMaterial(std::move(mtl));
} }
} }
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++)
{ {
ObjObject object; ObjObject object;
@ -150,10 +151,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -184,10 +185,10 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* mod
writer.AddUv(static_cast<int>(surfIndex), objUv); writer.AddUv(static_cast<int>(surfIndex), objUv);
} }
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -208,12 +209,12 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelS
writer.AddFace(static_cast<int>(surfIndex), face); writer.AddFace(static_cast<int>(surfIndex), face);
} }
} }
} }
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;
@ -223,17 +224,17 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
AddObjMaterials(writer, materialMapper, model); AddObjMaterials(writer, materialMapper, model);
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;
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,26 +247,11 @@ 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)
{
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) void 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++)
{ {
XModelBone bone; XModelBone bone;
@ -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)
{ {
@ -309,10 +295,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
writer.AddBone(std::move(bone)); writer.AddBone(std::move(bone));
} }
} }
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++)
{ {
Material* material = model->materialHandles[surfaceMaterialNum]; Material* material = model->materialHandles[surfaceMaterialNum];
@ -329,10 +315,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
writer.AddMaterial(std::move(xMaterial)); writer.AddMaterial(std::move(xMaterial));
} }
} }
} }
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++)
{ {
XModelObject object; XModelObject object;
@ -340,10 +326,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -376,10 +362,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
writer.AddVertex(vertex); writer.AddVertex(vertex);
} }
} }
} }
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++)
{ {
@ -400,12 +386,10 @@ 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;
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
@ -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++)
@ -513,13 +498,11 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
} }
} }
} }
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++)
{ {
const auto& surface = modelSurfs->surfs[surfIndex]; const auto& surface = modelSurfs->surfs[surfIndex];
@ -536,62 +519,96 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
writer.AddFace(face); writer.AddFace(face);
} }
} }
} }
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* model = asset->Asset();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs; const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) DistinctMapper<Material*> materialMapper(model->numsurfs);
return; XModelVertexBoneWeightCollection boneWeightCollection;
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".XMODEL_EXPORT"); 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* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.XMODEL_EXPORT", modelSurfs->name));
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();
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
const auto assetFile = context.OpenAssetFile(std::format("model_export/{}{}", modelSurfs->name, extension));
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 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++) for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
if (!model->lodInfo[currentLod].modelSurfs || !surfZoneState->ShouldDumpTechnique(model->lodInfo[currentLod].modelSurfs))
continue;
DumpXModelExportLod(context, asset, currentLod);
}
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
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:
assert(false); assert(false);
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,22 +3,30 @@
#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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -41,10 +49,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -67,10 +75,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -93,10 +101,10 @@ 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;
@ -122,10 +130,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
writer.AddMaterial(std::move(mtl)); writer.AddMaterial(std::move(mtl));
} }
} }
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;
@ -137,10 +145,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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;
@ -174,10 +182,10 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, c
writer.AddUv(static_cast<int>(surfIndex), objUv); writer.AddUv(static_cast<int>(surfIndex), objUv);
} }
} }
} }
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;
@ -201,12 +209,12 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, cons
writer.AddFace(static_cast<int>(surfIndex), face); writer.AddFace(static_cast<int>(surfIndex), face);
} }
} }
} }
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;
@ -216,15 +224,12 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
AddObjMaterials(writer, materialMapper, model); AddObjMaterials(writer, materialMapper, model);
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,22 +242,11 @@ 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)
{
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) void 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++)
{ {
XModelBone bone; XModelBone bone;
@ -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)
{ {
@ -296,10 +290,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
writer.AddBone(std::move(bone)); writer.AddBone(std::move(bone));
} }
} }
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++)
{ {
Material* material = model->materialHandles[surfaceMaterialNum]; Material* material = model->materialHandles[surfaceMaterialNum];
@ -316,10 +310,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
writer.AddMaterial(std::move(xMaterial)); writer.AddMaterial(std::move(xMaterial));
} }
} }
} }
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;
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
@ -329,10 +323,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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;
@ -368,10 +362,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
writer.AddVertex(vertex); writer.AddVertex(vertex);
} }
} }
} }
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;
@ -395,13 +389,10 @@ 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++)
@ -512,10 +504,10 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
} }
} }
} }
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;
const auto baseSurfIndex = model->lodInfo[lod].surfIndex; const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
@ -536,58 +528,92 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
writer.AddFace(face); writer.AddFace(face);
} }
} }
} }
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();
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
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 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++) for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
DumpXModelExportLod(context, asset, currentLod);
}
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
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:
assert(false); assert(false);
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,22 +3,30 @@
#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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -53,10 +61,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -79,10 +87,10 @@ 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;
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
@ -105,10 +113,10 @@ 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;
@ -134,10 +142,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
writer.AddMaterial(std::move(mtl)); writer.AddMaterial(std::move(mtl));
} }
} }
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;
@ -149,10 +157,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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;
@ -186,10 +194,10 @@ void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModel* model, c
writer.AddUv(static_cast<int>(surfIndex), objUv); writer.AddUv(static_cast<int>(surfIndex), objUv);
} }
} }
} }
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;
@ -213,12 +221,12 @@ void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModel* model, cons
writer.AddFace(static_cast<int>(surfIndex), face); writer.AddFace(static_cast<int>(surfIndex), face);
} }
} }
} }
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;
@ -228,15 +236,12 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
AddObjMaterials(writer, materialMapper, model); AddObjMaterials(writer, materialMapper, model);
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,22 +254,11 @@ 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)
{
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) void 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++)
{ {
XModelBone bone; XModelBone bone;
@ -308,10 +302,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
writer.AddBone(std::move(bone)); writer.AddBone(std::move(bone));
} }
} }
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++)
{ {
Material* material = model->materialHandles[surfaceMaterialNum]; Material* material = model->materialHandles[surfaceMaterialNum];
@ -328,10 +322,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
writer.AddMaterial(std::move(xMaterial)); writer.AddMaterial(std::move(xMaterial));
} }
} }
} }
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;
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
@ -341,10 +335,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
writer.AddObject(std::move(object)); writer.AddObject(std::move(object));
} }
} }
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;
@ -383,10 +377,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
writer.AddVertex(vertex); writer.AddVertex(vertex);
} }
} }
} }
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;
@ -413,13 +407,10 @@ 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++)
@ -533,10 +525,10 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0}); writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
} }
} }
} }
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;
const auto baseSurfIndex = model->lodInfo[lod].surfIndex; const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
@ -560,58 +552,92 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
writer.AddFace(face); writer.AddFace(face);
} }
} }
} }
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();
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
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 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++) for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
{ {
DumpXModelExportLod(context, asset, currentLod);
}
}
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
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:
assert(false); assert(false);
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)
{ {