mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-11 07:18:11 -05:00
feat: add gltf and glb as model dumping formats
This commit is contained in:
@ -3,22 +3,30 @@
|
||||
#include "Game/IW3/CommonIW3.h"
|
||||
#include "Math/Quaternion.h"
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "Utils/HalfFloat.h"
|
||||
#include "Utils/QuatInt16.h"
|
||||
#include "XModel/AbstractXModelWriter.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 <sstream>
|
||||
#include <format>
|
||||
|
||||
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;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -41,10 +49,10 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -67,10 +75,10 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -93,10 +101,10 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -122,10 +130,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
|
||||
|
||||
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 baseSurfIndex = model->lodInfo[lod].surfIndex;
|
||||
|
||||
@ -137,10 +145,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl");
|
||||
const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
|
||||
|
||||
if (!matFile)
|
||||
return;
|
||||
@ -216,15 +224,12 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
|
||||
|
||||
AddObjMaterials(writer, materialMapper, model);
|
||||
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();
|
||||
std::ostringstream ss;
|
||||
ss << "model_export/" << model->name << "_lod" << lod << ".OBJ";
|
||||
|
||||
const auto assetFile = context.OpenAssetFile(ss.str());
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
@ -237,22 +242,11 @@ void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XMod
|
||||
AddObjVertices(writer, model, lod);
|
||||
AddObjFaces(writer, model, lod);
|
||||
|
||||
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl");
|
||||
}
|
||||
|
||||
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);
|
||||
writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
XModelBone bone;
|
||||
@ -273,8 +267,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
|
||||
bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
|
||||
bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
|
||||
bone.globalRotation =
|
||||
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
bone.globalRotation = Quaternion32(
|
||||
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
|
||||
if (boneNum < model->numRootBones)
|
||||
{
|
||||
@ -296,10 +290,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
|
||||
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++)
|
||||
{
|
||||
Material* material = model->materialHandles[surfaceMaterialNum];
|
||||
@ -316,10 +310,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
|
||||
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;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
@ -329,10 +323,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
|
||||
|
||||
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 surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
@ -368,10 +362,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
const XModel* model,
|
||||
const unsigned lod,
|
||||
XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
@ -504,7 +495,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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++)
|
||||
@ -512,10 +504,10 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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 surfCount = model->lodInfo[lod].numsurfs;
|
||||
const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
|
||||
@ -536,58 +528,92 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
|
||||
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();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT";
|
||||
|
||||
const auto assetFile = context.OpenAssetFile(ss.str());
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
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);
|
||||
PopulateXModelWriter(context, lod, model, *writer);
|
||||
|
||||
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 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++)
|
||||
{
|
||||
DumpXModelExportLod(context, asset, currentLod);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||
{
|
||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
DumpObj(context, asset);
|
||||
DumpObjLod(context, asset, currentLod);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
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);
|
||||
}
|
||||
|
@ -2,37 +2,11 @@
|
||||
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/IW3/IW3.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "XModel/AbstractXModelWriter.h"
|
||||
#include "XModel/Obj/ObjWriter.h"
|
||||
|
||||
namespace IW3
|
||||
{
|
||||
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:
|
||||
bool ShouldDump(XAssetInfo<XModel>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;
|
||||
|
@ -3,15 +3,22 @@
|
||||
#include "Game/IW4/CommonIW4.h"
|
||||
#include "Math/Quaternion.h"
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "Utils/HalfFloat.h"
|
||||
#include "Utils/QuatInt16.h"
|
||||
#include "XModel/AbstractXModelWriter.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 <format>
|
||||
|
||||
using namespace IW4;
|
||||
|
||||
namespace IW4
|
||||
namespace
|
||||
{
|
||||
class SurfsDumpingZoneState final : public IZoneAssetDumperState
|
||||
{
|
||||
@ -20,22 +27,16 @@ namespace IW4
|
||||
public:
|
||||
bool ShouldDumpTechnique(const XModelSurfs* surfs)
|
||||
{
|
||||
if (m_dumped_surfs.find(surfs) != m_dumped_surfs.end())
|
||||
if (m_dumped_surfs.contains(surfs))
|
||||
return false;
|
||||
|
||||
m_dumped_surfs.emplace(surfs);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace IW4
|
||||
|
||||
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
|
||||
{
|
||||
return !asset->m_name.empty() && asset->m_name[0] != ',';
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialColorMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -58,10 +59,10 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -84,10 +85,10 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -110,10 +111,10 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -139,10 +140,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
|
||||
|
||||
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++)
|
||||
{
|
||||
ObjObject object;
|
||||
@ -151,10 +152,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
|
||||
|
||||
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++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
|
||||
{
|
||||
void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
|
||||
{
|
||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl");
|
||||
const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
|
||||
|
||||
if (!matFile)
|
||||
return;
|
||||
@ -224,17 +225,17 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
|
||||
|
||||
AddObjMaterials(writer, materialMapper, model);
|
||||
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* modelSurfs = model->lodInfo[lod].modelSurfs;
|
||||
|
||||
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
|
||||
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)
|
||||
return;
|
||||
@ -247,26 +248,11 @@ void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInf
|
||||
AddObjVertices(writer, modelSurfs);
|
||||
AddObjFaces(writer, modelSurfs);
|
||||
|
||||
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl");
|
||||
}
|
||||
|
||||
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);
|
||||
writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
XModelBone bone;
|
||||
@ -287,8 +273,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
|
||||
bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
|
||||
bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
|
||||
bone.globalRotation =
|
||||
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
bone.globalRotation = Quaternion32(
|
||||
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
|
||||
if (boneNum < model->numRootBones)
|
||||
{
|
||||
@ -310,10 +296,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
|
||||
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++)
|
||||
{
|
||||
Material* material = model->materialHandles[surfaceMaterialNum];
|
||||
@ -330,10 +316,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
|
||||
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++)
|
||||
{
|
||||
XModelObject object;
|
||||
@ -341,10 +327,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
|
||||
|
||||
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++)
|
||||
{
|
||||
const auto& surface = modelSurfs->surfs[surfIndex];
|
||||
@ -377,10 +363,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
|
||||
writer.AddVertex(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
weightCollection.totalWeightCount = 0u;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
const XModelSurfs* modelSurfs,
|
||||
XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
size_t weightOffset = 0u;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||
@ -506,7 +490,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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++)
|
||||
@ -514,13 +499,11 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
|
||||
const DistinctMapper<Material*>& materialMapper,
|
||||
const XModelSurfs* modelSurfs,
|
||||
const int baseSurfaceIndex)
|
||||
{
|
||||
void
|
||||
AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, const int baseSurfaceIndex)
|
||||
{
|
||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||
{
|
||||
const auto& surface = modelSurfs->surfs[surfIndex];
|
||||
@ -537,62 +520,96 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
|
||||
writer.AddFace(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
|
||||
{
|
||||
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
|
||||
|
||||
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
|
||||
return;
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
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)
|
||||
return;
|
||||
|
||||
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
XModelVertexBoneWeightCollection boneWeightCollection;
|
||||
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
|
||||
|
||||
AddXModelBones(context, *writer, model);
|
||||
AddXModelMaterials(*writer, materialMapper, model);
|
||||
AddXModelObjects(*writer, modelSurfs);
|
||||
AddXModelVertices(*writer, modelSurfs);
|
||||
AddXModelVertexBoneWeights(*writer, modelSurfs, boneWeightCollection);
|
||||
AddXModelFaces(*writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
|
||||
PopulateXModelWriter(context, lod, model, *writer);
|
||||
|
||||
writer->Write(*assetFile);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||
{
|
||||
auto* surfZoneState = context.GetZoneAssetDumperState<SurfsDumpingZoneState>();
|
||||
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* 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++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
DumpObj(context, asset);
|
||||
DumpObjLod(context, asset, currentLod);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
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);
|
||||
}
|
||||
|
@ -2,37 +2,11 @@
|
||||
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "XModel/AbstractXModelWriter.h"
|
||||
#include "XModel/Obj/ObjWriter.h"
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
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:
|
||||
bool ShouldDump(XAssetInfo<XModel>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;
|
||||
|
@ -3,15 +3,22 @@
|
||||
#include "Game/IW5/CommonIW5.h"
|
||||
#include "Math/Quaternion.h"
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "Utils/HalfFloat.h"
|
||||
#include "Utils/QuatInt16.h"
|
||||
#include "XModel/AbstractXModelWriter.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 <format>
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
namespace IW5
|
||||
namespace
|
||||
{
|
||||
class SurfsDumpingZoneState final : public IZoneAssetDumperState
|
||||
{
|
||||
@ -20,22 +27,16 @@ namespace IW5
|
||||
public:
|
||||
bool ShouldDumpTechnique(const XModelSurfs* surfs)
|
||||
{
|
||||
if (m_dumped_surfs.find(surfs) != m_dumped_surfs.end())
|
||||
if (m_dumped_surfs.contains(surfs))
|
||||
return false;
|
||||
|
||||
m_dumped_surfs.emplace(surfs);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace IW5
|
||||
|
||||
bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
|
||||
{
|
||||
return !asset->m_name.empty() && asset->m_name[0] != ',';
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialColorMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -58,10 +59,10 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -84,10 +85,10 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -110,10 +111,10 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -138,10 +139,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
|
||||
|
||||
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++)
|
||||
{
|
||||
ObjObject object;
|
||||
@ -150,10 +151,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
|
||||
|
||||
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++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
|
||||
{
|
||||
void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
|
||||
{
|
||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl");
|
||||
const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
|
||||
|
||||
if (!matFile)
|
||||
return;
|
||||
@ -223,17 +224,17 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
|
||||
|
||||
AddObjMaterials(writer, materialMapper, model);
|
||||
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* modelSurfs = model->lodInfo[lod].modelSurfs;
|
||||
|
||||
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
|
||||
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)
|
||||
return;
|
||||
@ -246,26 +247,11 @@ void AssetDumperXModel::DumpObjLod(const AssetDumpingContext& context, XAssetInf
|
||||
AddObjVertices(writer, modelSurfs);
|
||||
AddObjFaces(writer, modelSurfs);
|
||||
|
||||
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl");
|
||||
}
|
||||
|
||||
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);
|
||||
writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
XModelBone bone;
|
||||
@ -286,8 +272,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
|
||||
bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
|
||||
bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
|
||||
bone.globalRotation =
|
||||
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
bone.globalRotation = Quaternion32(
|
||||
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
|
||||
if (boneNum < model->numRootBones)
|
||||
{
|
||||
@ -309,10 +295,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
|
||||
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++)
|
||||
{
|
||||
Material* material = model->materialHandles[surfaceMaterialNum];
|
||||
@ -329,10 +315,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
|
||||
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++)
|
||||
{
|
||||
XModelObject object;
|
||||
@ -340,10 +326,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
|
||||
|
||||
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++)
|
||||
{
|
||||
const auto& surface = modelSurfs->surfs[surfIndex];
|
||||
@ -376,10 +362,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
|
||||
writer.AddVertex(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
weightCollection.totalWeightCount = 0u;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
const XModelSurfs* modelSurfs,
|
||||
XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
size_t weightOffset = 0u;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||
@ -505,7 +489,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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++)
|
||||
@ -513,13 +498,11 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
writer.AddVertexBoneWeights(XModelVertexBoneWeights{nullptr, 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
|
||||
const DistinctMapper<Material*>& materialMapper,
|
||||
const XModelSurfs* modelSurfs,
|
||||
const int baseSurfaceIndex)
|
||||
{
|
||||
void
|
||||
AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, const int baseSurfaceIndex)
|
||||
{
|
||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||
{
|
||||
const auto& surface = modelSurfs->surfs[surfIndex];
|
||||
@ -536,62 +519,96 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer,
|
||||
writer.AddFace(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
void PopulateXModelWriter(const AssetDumpingContext& context, const unsigned lod, const XModel* model, AbstractXModelWriter& writer)
|
||||
{
|
||||
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
|
||||
|
||||
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
|
||||
return;
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
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)
|
||||
return;
|
||||
|
||||
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
XModelVertexBoneWeightCollection boneWeightCollection;
|
||||
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
|
||||
|
||||
AddXModelBones(context, *writer, model);
|
||||
AddXModelMaterials(*writer, materialMapper, model);
|
||||
AddXModelObjects(*writer, modelSurfs);
|
||||
AddXModelVertices(*writer, modelSurfs);
|
||||
AddXModelVertexBoneWeights(*writer, modelSurfs, boneWeightCollection);
|
||||
AddXModelFaces(*writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
|
||||
PopulateXModelWriter(context, lod, model, *writer);
|
||||
|
||||
writer->Write(*assetFile);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpXModelExport(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||
{
|
||||
auto* surfZoneState = context.GetZoneAssetDumperState<SurfsDumpingZoneState>();
|
||||
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* 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++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
DumpObj(context, asset);
|
||||
DumpObjLod(context, asset, currentLod);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
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);
|
||||
}
|
||||
|
@ -2,37 +2,11 @@
|
||||
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/IW5/IW5.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "XModel/AbstractXModelWriter.h"
|
||||
#include "XModel/Obj/ObjWriter.h"
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
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:
|
||||
bool ShouldDump(XAssetInfo<XModel>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;
|
||||
|
@ -3,22 +3,30 @@
|
||||
#include "Game/T5/CommonT5.h"
|
||||
#include "Math/Quaternion.h"
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "Utils/HalfFloat.h"
|
||||
#include "Utils/QuatInt16.h"
|
||||
#include "XModel/AbstractXModelWriter.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 <sstream>
|
||||
#include <format>
|
||||
|
||||
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;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -41,10 +49,10 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -67,10 +75,10 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->u.image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -93,10 +101,10 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -122,10 +130,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
|
||||
|
||||
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 baseSurfIndex = model->lodInfo[lod].surfIndex;
|
||||
|
||||
@ -137,10 +145,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl");
|
||||
const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
|
||||
|
||||
if (!matFile)
|
||||
return;
|
||||
@ -216,15 +224,12 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
|
||||
|
||||
AddObjMaterials(writer, materialMapper, model);
|
||||
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();
|
||||
std::ostringstream ss;
|
||||
ss << "model_export/" << model->name << "_lod" << lod << ".OBJ";
|
||||
|
||||
const auto assetFile = context.OpenAssetFile(ss.str());
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
@ -237,22 +242,11 @@ void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XMod
|
||||
AddObjVertices(writer, model, lod);
|
||||
AddObjFaces(writer, model, lod);
|
||||
|
||||
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl");
|
||||
}
|
||||
|
||||
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);
|
||||
writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
XModelBone bone;
|
||||
@ -273,8 +267,8 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
|
||||
bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
|
||||
bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
|
||||
bone.globalRotation =
|
||||
Quaternion32(model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
bone.globalRotation = Quaternion32(
|
||||
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]);
|
||||
|
||||
if (boneNum < model->numRootBones)
|
||||
{
|
||||
@ -296,10 +290,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
|
||||
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++)
|
||||
{
|
||||
Material* material = model->materialHandles[surfaceMaterialNum];
|
||||
@ -316,10 +310,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
|
||||
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;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
@ -329,10 +323,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
|
||||
|
||||
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 surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
@ -368,10 +362,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
const XModel* model,
|
||||
const unsigned lod,
|
||||
XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
@ -504,7 +495,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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++)
|
||||
@ -512,10 +504,10 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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 surfCount = model->lodInfo[lod].numsurfs;
|
||||
const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
|
||||
@ -536,58 +528,92 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
|
||||
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();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT";
|
||||
|
||||
const auto assetFile = context.OpenAssetFile(ss.str());
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
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);
|
||||
PopulateXModelWriter(context, lod, model, *writer);
|
||||
|
||||
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 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++)
|
||||
{
|
||||
DumpXModelExportLod(context, asset, currentLod);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||
{
|
||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
DumpObj(context, asset);
|
||||
DumpObjLod(context, asset, currentLod);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
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);
|
||||
}
|
||||
|
@ -2,37 +2,11 @@
|
||||
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/T5/T5.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "XModel/AbstractXModelWriter.h"
|
||||
#include "XModel/Obj/ObjWriter.h"
|
||||
|
||||
namespace T5
|
||||
{
|
||||
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:
|
||||
bool ShouldDump(XAssetInfo<XModel>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;
|
||||
|
@ -3,22 +3,30 @@
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "Math/Quaternion.h"
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "Utils/HalfFloat.h"
|
||||
#include "Utils/QuatInt16.h"
|
||||
#include "XModel/AbstractXModelWriter.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 <sstream>
|
||||
#include <format>
|
||||
|
||||
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;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -53,10 +61,10 @@ GfxImage* AssetDumperXModel::GetMaterialColorMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -79,10 +87,10 @@ GfxImage* AssetDumperXModel::GetMaterialNormalMap(const Material* material)
|
||||
}
|
||||
|
||||
return potentialTextureDefs[0]->image;
|
||||
}
|
||||
}
|
||||
|
||||
GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
GfxImage* GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
@ -105,10 +113,10 @@ GfxImage* AssetDumperXModel::GetMaterialSpecularMap(const Material* material)
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
@ -134,10 +142,10 @@ void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Materi
|
||||
|
||||
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 baseSurfIndex = model->lodInfo[lod].surfIndex;
|
||||
|
||||
@ -149,10 +157,10 @@ void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Ma
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl");
|
||||
const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
|
||||
|
||||
if (!matFile)
|
||||
return;
|
||||
@ -228,15 +236,12 @@ void AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInf
|
||||
|
||||
AddObjMaterials(writer, materialMapper, model);
|
||||
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();
|
||||
std::ostringstream ss;
|
||||
ss << "model_export/" << model->name << "_lod" << lod << ".OBJ";
|
||||
|
||||
const auto assetFile = context.OpenAssetFile(ss.str());
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
@ -249,22 +254,11 @@ void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XMod
|
||||
AddObjVertices(writer, model, lod);
|
||||
AddObjFaces(writer, model, lod);
|
||||
|
||||
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl");
|
||||
}
|
||||
|
||||
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);
|
||||
writer.WriteObj(*assetFile, std::format("{}.mtl", model->name));
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
XModelBone bone;
|
||||
@ -308,10 +302,10 @@ void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, Abstr
|
||||
|
||||
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++)
|
||||
{
|
||||
Material* material = model->materialHandles[surfaceMaterialNum];
|
||||
@ -328,10 +322,10 @@ void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, Distinc
|
||||
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;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
@ -341,10 +335,10 @@ void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XMo
|
||||
|
||||
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 surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
@ -383,10 +377,10 @@ void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XM
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
const XModel* model,
|
||||
const unsigned lod,
|
||||
XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
@ -525,7 +516,8 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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++)
|
||||
@ -533,10 +525,10 @@ void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer,
|
||||
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 surfCount = model->lodInfo[lod].numsurfs;
|
||||
const auto baseSurfIndex = model->lodInfo[lod].surfIndex;
|
||||
@ -560,58 +552,92 @@ void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const Disti
|
||||
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();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT";
|
||||
|
||||
const auto assetFile = context.OpenAssetFile(ss.str());
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
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);
|
||||
PopulateXModelWriter(context, lod, model, *writer);
|
||||
|
||||
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 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++)
|
||||
{
|
||||
DumpXModelExportLod(context, asset, currentLod);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||
{
|
||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
DumpObj(context, asset);
|
||||
DumpObjLod(context, asset, currentLod);
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
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);
|
||||
}
|
||||
|
@ -2,37 +2,11 @@
|
||||
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "XModel/AbstractXModelWriter.h"
|
||||
#include "XModel/Obj/ObjWriter.h"
|
||||
|
||||
namespace T6
|
||||
{
|
||||
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:
|
||||
bool ShouldDump(XAssetInfo<XModel>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<XModel>* asset) override;
|
||||
|
@ -20,14 +20,16 @@ public:
|
||||
enum class ModelOutputFormat_e
|
||||
{
|
||||
XMODEL_EXPORT,
|
||||
OBJ
|
||||
OBJ,
|
||||
GLTF,
|
||||
GLB
|
||||
};
|
||||
|
||||
bool Verbose = false;
|
||||
std::vector<bool> AssetTypesToHandleBitfield;
|
||||
|
||||
ImageOutputFormat_e ImageOutputFormat = ImageOutputFormat_e::DDS;
|
||||
ModelOutputFormat_e ModelOutputFormat = ModelOutputFormat_e::XMODEL_EXPORT;
|
||||
ModelOutputFormat_e ModelOutputFormat = ModelOutputFormat_e::GLB;
|
||||
bool MenuLegacyMode = false;
|
||||
|
||||
} Configuration;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/Arguments/UsageInformation.h"
|
||||
#include "Utils/FileUtils.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
@ -79,7 +80,7 @@ const CommandLineOption* const OPTION_IMAGE_FORMAT =
|
||||
const CommandLineOption* const OPTION_MODEL_FORMAT =
|
||||
CommandLineOption::Builder::Create()
|
||||
.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")
|
||||
.Build();
|
||||
|
||||
@ -179,8 +180,7 @@ void UnlinkerArgs::SetVerbose(const bool isVerbose)
|
||||
bool UnlinkerArgs::SetImageDumpingMode()
|
||||
{
|
||||
auto specifiedValue = m_argument_parser.GetValueForOption(OPTION_IMAGE_FORMAT);
|
||||
for (auto& c : specifiedValue)
|
||||
c = static_cast<char>(tolower(c));
|
||||
utils::MakeStringLowerCase(specifiedValue);
|
||||
|
||||
if (specifiedValue == "dds")
|
||||
{
|
||||
@ -202,8 +202,7 @@ bool UnlinkerArgs::SetImageDumpingMode()
|
||||
bool UnlinkerArgs::SetModelDumpingMode()
|
||||
{
|
||||
auto specifiedValue = m_argument_parser.GetValueForOption(OPTION_MODEL_FORMAT);
|
||||
for (auto& c : specifiedValue)
|
||||
c = static_cast<char>(tolower(c));
|
||||
utils::MakeStringLowerCase(specifiedValue);
|
||||
|
||||
if (specifiedValue == "xmodel_export")
|
||||
{
|
||||
@ -217,6 +216,18 @@ bool UnlinkerArgs::SetModelDumpingMode()
|
||||
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);
|
||||
printf("Illegal value: \"%s\" is not a valid model output format. Use -? to see usage information.\n", originalValue.c_str());
|
||||
return false;
|
||||
@ -238,8 +249,7 @@ void UnlinkerArgs::ParseCommaSeparatedAssetTypeString(const std::string& input)
|
||||
size_t endPos;
|
||||
|
||||
std::string lowerInput(input);
|
||||
for (auto& c : lowerInput)
|
||||
c = static_cast<char>(tolower(c));
|
||||
utils::MakeStringLowerCase(lowerInput);
|
||||
|
||||
while (currentPos < lowerInput.size() && (endPos = lowerInput.find_first_of(',', currentPos)) != std::string::npos)
|
||||
{
|
||||
|
Reference in New Issue
Block a user