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