diff --git a/src/ObjCommon/XModel/XModelCommon.h b/src/ObjCommon/XModel/XModelCommon.h index a8ee49b2..7f1f0b44 100644 --- a/src/ObjCommon/XModel/XModelCommon.h +++ b/src/ObjCommon/XModel/XModelCommon.h @@ -6,12 +6,6 @@ #include #include -struct XModelObject -{ - std::string name; - int materialIndex; -}; - struct XModelBone { std::string name; @@ -51,7 +45,6 @@ struct XModelVertex struct XModelFace { int vertexIndex[3]; - int objectIndex; }; struct XModelMaterial @@ -88,10 +81,19 @@ struct XModelMaterial float blinn[2]; float phong; std::string colorMapName; + std::string normalMapName; + std::string specularMapName; void ApplyDefaults(); }; +struct XModelObject +{ + std::string name; + int materialIndex; + std::vector m_faces; +}; + struct XModelCommon { std::vector m_objects; @@ -99,7 +101,6 @@ struct XModelCommon std::vector m_materials; std::vector m_vertices; std::vector m_vertex_bone_weights; - std::vector m_faces; XModelVertexBoneWeightCollection m_bone_weight_data; }; diff --git a/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperXModel.cpp index d720515d..ee73a0b6 100644 --- a/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperXModel.cpp +++ b/src/ObjWriting/Game/IW3/AssetDumpers/AssetDumperXModel.cpp @@ -103,148 +103,6 @@ namespace return potentialTextureDefs[0]->u.image; } - void AddObjMaterials(ObjWriter& writer, DistinctMapper& materialMapper, const XModel* model) - { - if (!model->materialHandles) - return; - - for (auto surfIndex = 0u; surfIndex < model->numsurfs; surfIndex++) - { - Material* material = model->materialHandles[surfIndex]; - if (!materialMapper.Add(material)) - continue; - - MtlMaterial mtl; - mtl.materialName = std::string(material->info.name); - - GfxImage* colorMap = GetMaterialColorMap(material); - GfxImage* normalMap = GetMaterialNormalMap(material); - GfxImage* specularMap = GetMaterialSpecularMap(material); - - if (colorMap != nullptr) - mtl.colorMapName = colorMap->name; - if (normalMap != nullptr) - mtl.normalMapName = normalMap->name; - if (specularMap != nullptr) - mtl.specularMapName = specularMap->name; - - writer.AddMaterial(std::move(mtl)); - } - } - - void AddObjObjects(ObjWriter& writer, const DistinctMapper& materialMapper, const XModel* model, const unsigned lod) - { - const auto surfCount = model->lodInfo[lod].numsurfs; - const auto baseSurfIndex = model->lodInfo[lod].surfIndex; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - ObjObject object; - object.name = std::format("surf{}", surfIndex); - object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfIndex)); - - writer.AddObject(std::move(object)); - } - } - - void AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod) - { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - const auto& surface = surfs[surfIndex]; - - for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++) - { - const auto& v = surface.verts0[vertexIndex]; - vec2_t uv; - vec3_t normalVec; - - Common::Vec2UnpackTexCoords(v.texCoord, &uv); - Common::Vec3UnpackUnitVec(v.normal, &normalVec); - - ObjVertex objVertex{}; - ObjNormal objNormal{}; - ObjUv objUv{}; - objVertex.coordinates[0] = v.xyz[0]; - objVertex.coordinates[1] = v.xyz[2]; - objVertex.coordinates[2] = -v.xyz[1]; - objNormal.normal[0] = normalVec[0]; - objNormal.normal[1] = normalVec[2]; - objNormal.normal[2] = -normalVec[1]; - objUv.uv[0] = uv[0]; - objUv.uv[1] = 1.0f - uv[1]; - - writer.AddVertex(static_cast(surfIndex), objVertex); - writer.AddNormal(static_cast(surfIndex), objNormal); - writer.AddUv(static_cast(surfIndex), objUv); - } - } - } - - void AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod) - { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - const auto& surface = surfs[surfIndex]; - for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) - { - const auto& tri = surface.triIndices[triIndex]; - - ObjFace face{}; - face.vertexIndex[0] = tri[2] + surface.baseVertIndex; - face.vertexIndex[1] = tri[1] + surface.baseVertIndex; - face.vertexIndex[2] = tri[0] + surface.baseVertIndex; - face.normalIndex[0] = face.vertexIndex[0]; - face.normalIndex[1] = face.vertexIndex[1]; - face.normalIndex[2] = face.vertexIndex[2]; - face.uvIndex[0] = face.vertexIndex[0]; - face.uvIndex[1] = face.vertexIndex[1]; - face.uvIndex[2] = face.vertexIndex[2]; - writer.AddFace(static_cast(surfIndex), face); - } - } - } - - void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo* asset) - { - const auto* model = asset->Asset(); - const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); - - if (!matFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - writer.WriteMtl(*matFile); - } - - void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) - { - const auto* model = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj")); - - if (!assetFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - AddObjObjects(writer, materialMapper, model, lod); - AddObjVertices(writer, model, lod); - AddObjFaces(writer, model, lod); - - writer.WriteObj(*assetFile, std::format("{}.mtl", model->name)); - } - void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model) { for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) @@ -307,6 +165,14 @@ namespace if (colorMap) xMaterial.colorMapName = std::string(colorMap->name); + const auto* normalMap = GetMaterialNormalMap(material); + if (normalMap) + xMaterial.normalMapName = std::string(normalMap->name); + + const auto* specularMap = GetMaterialSpecularMap(material); + if (specularMap) + xMaterial.specularMapName = std::string(specularMap->name); + out.m_materials.emplace_back(std::move(xMaterial)); } } @@ -517,6 +383,9 @@ namespace for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) { const auto& surface = surfs[surfIndex]; + auto& object = out.m_objects[surfIndex]; + object.m_faces.reserve(surface.triCount); + for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) { const auto& tri = surface.triIndices[triIndex]; @@ -525,8 +394,7 @@ namespace face.vertexIndex[0] = tri[0] + surface.baseVertIndex; face.vertexIndex[1] = tri[1] + surface.baseVertIndex; face.vertexIndex[2] = tri[2] + surface.baseVertIndex; - face.objectIndex = static_cast(surfIndex); - out.m_faces.emplace_back(face); + object.m_faces.emplace_back(face); } } } @@ -544,6 +412,35 @@ namespace AddXModelFaces(out, model, lod); } + void DumpObjMtl(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset) + { + const auto* model = asset->Asset(); + const auto mtlFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); + + if (!mtlFile) + return; + + const auto writer = obj::CreateMtlWriter(*mtlFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + + void DumpObjLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) + { + const auto* model = asset->Asset(); + const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj")); + + if (!assetFile) + return; + + const auto writer = + obj::CreateObjWriter(*assetFile, std::format("{}.mtl", model->name), context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + void DumpXModelExportLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) { const auto* model = asset->Asset(); @@ -576,9 +473,6 @@ namespace { 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++) { XModelCommon common; @@ -587,7 +481,9 @@ namespace switch (ObjWriting::Configuration.ModelOutputFormat) { case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: - DumpObjLod(context, asset, currentLod); + DumpObjLod(common, context, asset, currentLod); + if (currentLod == 0u) + DumpObjMtl(common, context, asset); break; case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperXModel.cpp index a1064a0a..b1019067 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperXModel.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperXModel.cpp @@ -20,21 +20,6 @@ using namespace IW4; namespace { - class SurfsDumpingZoneState final : public IZoneAssetDumperState - { - std::set m_dumped_surfs; - - public: - bool ShouldDumpTechnique(const XModelSurfs* surfs) - { - if (m_dumped_surfs.contains(surfs)) - return false; - - m_dumped_surfs.emplace(surfs); - return true; - } - }; - GfxImage* GetMaterialColorMap(const Material* material) { std::vector potentialTextureDefs; @@ -113,144 +98,6 @@ namespace return potentialTextureDefs[0]->u.image; } - void AddObjMaterials(ObjWriter& writer, DistinctMapper& materialMapper, const XModel* model) - { - if (!model->materialHandles) - return; - - for (auto surfIndex = 0u; surfIndex < model->numsurfs; surfIndex++) - { - Material* material = model->materialHandles[surfIndex]; - if (!materialMapper.Add(material)) - continue; - - MtlMaterial mtl; - mtl.materialName = std::string(material->info.name); - - GfxImage* colorMap = GetMaterialColorMap(material); - GfxImage* normalMap = GetMaterialNormalMap(material); - GfxImage* specularMap = GetMaterialSpecularMap(material); - - if (colorMap != nullptr) - mtl.colorMapName = colorMap->name; - if (normalMap != nullptr) - mtl.normalMapName = normalMap->name; - if (specularMap != nullptr) - mtl.specularMapName = specularMap->name; - - writer.AddMaterial(std::move(mtl)); - } - } - - void AddObjObjects(ObjWriter& writer, const DistinctMapper& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - ObjObject object; - object.name = std::format("surf{}", surfIndex); - object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfaceIndex)); - - writer.AddObject(std::move(object)); - } - } - - void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - const auto& surface = modelSurfs->surfs[surfIndex]; - - for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++) - { - const auto& v = surface.verts0[vertexIndex]; - vec2_t uv; - vec3_t normalVec; - - Common::Vec2UnpackTexCoords(v.texCoord, &uv); - Common::Vec3UnpackUnitVec(v.normal, &normalVec); - - ObjVertex objVertex{}; - ObjNormal objNormal{}; - ObjUv objUv{}; - objVertex.coordinates[0] = v.xyz[0]; - objVertex.coordinates[1] = v.xyz[2]; - objVertex.coordinates[2] = -v.xyz[1]; - objNormal.normal[0] = normalVec[0]; - objNormal.normal[1] = normalVec[2]; - objNormal.normal[2] = -normalVec[1]; - objUv.uv[0] = uv[0]; - objUv.uv[1] = 1.0f - uv[1]; - - writer.AddVertex(static_cast(surfIndex), objVertex); - writer.AddNormal(static_cast(surfIndex), objNormal); - writer.AddUv(static_cast(surfIndex), objUv); - } - } - } - - void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - const auto& surface = modelSurfs->surfs[surfIndex]; - for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) - { - const auto& tri = surface.triIndices[triIndex]; - - ObjFace face{}; - face.vertexIndex[0] = tri[2] + surface.baseVertIndex; - face.vertexIndex[1] = tri[1] + surface.baseVertIndex; - face.vertexIndex[2] = tri[0] + surface.baseVertIndex; - face.normalIndex[0] = face.vertexIndex[0]; - face.normalIndex[1] = face.vertexIndex[1]; - face.normalIndex[2] = face.vertexIndex[2]; - face.uvIndex[0] = face.vertexIndex[0]; - face.uvIndex[1] = face.vertexIndex[1]; - face.uvIndex[2] = face.vertexIndex[2]; - writer.AddFace(static_cast(surfIndex), face); - } - } - } - - void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo* asset) - { - const auto* model = asset->Asset(); - const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); - - if (!matFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - writer.WriteMtl(*matFile); - } - - void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) - { - const auto* model = asset->Asset(); - const auto* modelSurfs = model->lodInfo[lod].modelSurfs; - - if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) - return; - - const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.obj", modelSurfs->name)); - - if (!assetFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - AddObjObjects(writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex); - AddObjVertices(writer, modelSurfs); - AddObjFaces(writer, modelSurfs); - - writer.WriteObj(*assetFile, std::format("{}.mtl", model->name)); - } - void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model) { for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) @@ -313,6 +160,14 @@ namespace if (colorMap) xMaterial.colorMapName = std::string(colorMap->name); + const auto* normalMap = GetMaterialNormalMap(material); + if (normalMap) + xMaterial.normalMapName = std::string(normalMap->name); + + const auto* specularMap = GetMaterialSpecularMap(material); + if (specularMap) + xMaterial.specularMapName = std::string(specularMap->name); + out.m_materials.emplace_back(std::move(xMaterial)); } } @@ -508,6 +363,9 @@ namespace for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) { const auto& surface = modelSurfs->surfs[surfIndex]; + auto& object = out.m_objects[surfIndex]; + object.m_faces.reserve(surface.triCount); + for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) { const auto& tri = surface.triIndices[triIndex]; @@ -516,8 +374,7 @@ namespace face.vertexIndex[0] = tri[0] + surface.baseVertIndex; face.vertexIndex[1] = tri[1] + surface.baseVertIndex; face.vertexIndex[2] = tri[2] + surface.baseVertIndex; - face.objectIndex = static_cast(surfIndex); - out.m_faces.emplace_back(face); + object.m_faces.emplace_back(face); } } } @@ -537,6 +394,40 @@ namespace AddXModelFaces(out, modelSurfs); } + void DumpObjMtl(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset) + { + const auto* model = asset->Asset(); + const auto mtlFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); + + if (!mtlFile) + return; + + const auto writer = obj::CreateMtlWriter(*mtlFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + + void DumpObjLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) + { + const auto* model = asset->Asset(); + const auto* modelSurfs = model->lodInfo[lod].modelSurfs; + + if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) + return; + + const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.obj", modelSurfs->name)); + + if (!assetFile) + return; + + const auto writer = + obj::CreateObjWriter(*assetFile, std::format("{}.mtl", model->name), context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + void DumpXModelExportLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) { const auto* model = asset->Asset(); @@ -571,9 +462,6 @@ namespace { 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++) { XModelCommon common; @@ -582,7 +470,9 @@ namespace switch (ObjWriting::Configuration.ModelOutputFormat) { case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: - DumpObjLod(context, asset, currentLod); + DumpObjLod(common, context, asset, currentLod); + if (currentLod == 0u) + DumpObjMtl(common, context, asset); break; case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp index a11240e8..b9cb4435 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp @@ -20,21 +20,6 @@ using namespace IW5; namespace { - class SurfsDumpingZoneState final : public IZoneAssetDumperState - { - std::set m_dumped_surfs; - - public: - bool ShouldDumpTechnique(const XModelSurfs* surfs) - { - if (m_dumped_surfs.contains(surfs)) - return false; - - m_dumped_surfs.emplace(surfs); - return true; - } - }; - GfxImage* GetMaterialColorMap(const Material* material) { std::vector potentialTextureDefs; @@ -113,143 +98,6 @@ namespace return potentialTextureDefs[0]->u.image; } - void AddObjMaterials(ObjWriter& writer, DistinctMapper& materialMapper, const XModel* model) - { - if (!model->materialHandles) - return; - - for (auto surfIndex = 0u; surfIndex < model->numsurfs; surfIndex++) - { - Material* material = model->materialHandles[surfIndex]; - if (!materialMapper.Add(material)) - continue; - - MtlMaterial mtl; - mtl.materialName = std::string(material->info.name); - GfxImage* colorMap = GetMaterialColorMap(material); - GfxImage* normalMap = GetMaterialNormalMap(material); - GfxImage* specularMap = GetMaterialSpecularMap(material); - - if (colorMap != nullptr) - mtl.colorMapName = colorMap->name; - if (normalMap != nullptr) - mtl.normalMapName = normalMap->name; - if (specularMap != nullptr) - mtl.specularMapName = specularMap->name; - - writer.AddMaterial(std::move(mtl)); - } - } - - void AddObjObjects(ObjWriter& writer, const DistinctMapper& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - ObjObject object; - object.name = std::format("surf{}", surfIndex); - object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfaceIndex)); - - writer.AddObject(std::move(object)); - } - } - - void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - const auto& surface = modelSurfs->surfs[surfIndex]; - - for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++) - { - const auto& v = surface.verts0.packedVerts0[vertexIndex]; - vec2_t uv; - vec3_t normalVec; - - Common::Vec2UnpackTexCoords(v.texCoord, &uv); - Common::Vec3UnpackUnitVec(v.normal, &normalVec); - - ObjVertex objVertex{}; - ObjNormal objNormal{}; - ObjUv objUv{}; - objVertex.coordinates[0] = v.xyz[0]; - objVertex.coordinates[1] = v.xyz[2]; - objVertex.coordinates[2] = -v.xyz[1]; - objNormal.normal[0] = normalVec[0]; - objNormal.normal[1] = normalVec[2]; - objNormal.normal[2] = -normalVec[1]; - objUv.uv[0] = uv[0]; - objUv.uv[1] = 1.0f - uv[1]; - - writer.AddVertex(static_cast(surfIndex), objVertex); - writer.AddNormal(static_cast(surfIndex), objNormal); - writer.AddUv(static_cast(surfIndex), objUv); - } - } - } - - void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - const auto& surface = modelSurfs->surfs[surfIndex]; - for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) - { - const auto& tri = surface.triIndices[triIndex]; - - ObjFace face{}; - face.vertexIndex[0] = tri[2] + surface.baseVertIndex; - face.vertexIndex[1] = tri[1] + surface.baseVertIndex; - face.vertexIndex[2] = tri[0] + surface.baseVertIndex; - face.normalIndex[0] = face.vertexIndex[0]; - face.normalIndex[1] = face.vertexIndex[1]; - face.normalIndex[2] = face.vertexIndex[2]; - face.uvIndex[0] = face.vertexIndex[0]; - face.uvIndex[1] = face.vertexIndex[1]; - face.uvIndex[2] = face.vertexIndex[2]; - writer.AddFace(static_cast(surfIndex), face); - } - } - } - - void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo* asset) - { - const auto* model = asset->Asset(); - const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); - - if (!matFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - writer.WriteMtl(*matFile); - } - - void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) - { - const auto* model = asset->Asset(); - const auto* modelSurfs = model->lodInfo[lod].modelSurfs; - - if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) - return; - - const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.obj", modelSurfs->name)); - - if (!assetFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - AddObjObjects(writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex); - AddObjVertices(writer, modelSurfs); - AddObjFaces(writer, modelSurfs); - - writer.WriteObj(*assetFile, std::format("{}.mtl", model->name)); - } - void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model) { for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) @@ -312,6 +160,14 @@ namespace if (colorMap) xMaterial.colorMapName = std::string(colorMap->name); + const auto* normalMap = GetMaterialNormalMap(material); + if (normalMap) + xMaterial.normalMapName = std::string(normalMap->name); + + const auto* specularMap = GetMaterialSpecularMap(material); + if (specularMap) + xMaterial.specularMapName = std::string(specularMap->name); + out.m_materials.emplace_back(std::move(xMaterial)); } } @@ -507,6 +363,9 @@ namespace for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) { const auto& surface = modelSurfs->surfs[surfIndex]; + auto& object = out.m_objects[surfIndex]; + object.m_faces.reserve(surface.triCount); + for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) { const auto& tri = surface.triIndices[triIndex]; @@ -515,8 +374,7 @@ namespace face.vertexIndex[0] = tri[0] + surface.baseVertIndex; face.vertexIndex[1] = tri[1] + surface.baseVertIndex; face.vertexIndex[2] = tri[2] + surface.baseVertIndex; - face.objectIndex = static_cast(surfIndex); - out.m_faces.emplace_back(face); + object.m_faces.emplace_back(face); } } } @@ -536,6 +394,40 @@ namespace AddXModelFaces(out, modelSurfs); } + void DumpObjMtl(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset) + { + const auto* model = asset->Asset(); + const auto mtlFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); + + if (!mtlFile) + return; + + const auto writer = obj::CreateMtlWriter(*mtlFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + + void DumpObjLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) + { + const auto* model = asset->Asset(); + const auto* modelSurfs = model->lodInfo[lod].modelSurfs; + + if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr) + return; + + const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.obj", modelSurfs->name)); + + if (!assetFile) + return; + + const auto writer = + obj::CreateObjWriter(*assetFile, std::format("{}.mtl", model->name), context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + void DumpXModelExportLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) { const auto* model = asset->Asset(); @@ -570,9 +462,6 @@ namespace { 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++) { XModelCommon common; @@ -581,7 +470,9 @@ namespace switch (ObjWriting::Configuration.ModelOutputFormat) { case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: - DumpObjLod(context, asset, currentLod); + DumpObjLod(common, context, asset, currentLod); + if (currentLod == 0u) + DumpObjMtl(common, context, asset); break; case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperXModel.cpp index 82d59797..ad9c3657 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperXModel.cpp +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperXModel.cpp @@ -103,148 +103,6 @@ namespace return potentialTextureDefs[0]->u.image; } - void AddObjMaterials(ObjWriter& writer, DistinctMapper& materialMapper, const XModel* model) - { - if (!model->materialHandles) - return; - - for (auto surfIndex = 0u; surfIndex < model->numsurfs; surfIndex++) - { - Material* material = model->materialHandles[surfIndex]; - if (!materialMapper.Add(material)) - continue; - - MtlMaterial mtl; - mtl.materialName = std::string(material->info.name); - - GfxImage* colorMap = GetMaterialColorMap(material); - GfxImage* normalMap = GetMaterialNormalMap(material); - GfxImage* specularMap = GetMaterialSpecularMap(material); - - if (colorMap != nullptr) - mtl.colorMapName = colorMap->name; - if (normalMap != nullptr) - mtl.normalMapName = normalMap->name; - if (specularMap != nullptr) - mtl.specularMapName = specularMap->name; - - writer.AddMaterial(std::move(mtl)); - } - } - - void AddObjObjects(ObjWriter& writer, const DistinctMapper& materialMapper, const XModel* model, const unsigned lod) - { - const auto surfCount = model->lodInfo[lod].numsurfs; - const auto baseSurfIndex = model->lodInfo[lod].surfIndex; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - ObjObject object; - object.name = std::format("surf{}", surfIndex); - object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfIndex)); - - writer.AddObject(std::move(object)); - } - } - - void AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod) - { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - const auto& surface = surfs[surfIndex]; - - for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++) - { - const auto& v = surface.verts0[vertexIndex]; - vec2_t uv; - vec3_t normalVec; - - Common::Vec2UnpackTexCoords(v.texCoord, &uv); - Common::Vec3UnpackUnitVec(v.normal, &normalVec); - - ObjVertex objVertex{}; - ObjNormal objNormal{}; - ObjUv objUv{}; - objVertex.coordinates[0] = v.xyz[0]; - objVertex.coordinates[1] = v.xyz[2]; - objVertex.coordinates[2] = -v.xyz[1]; - objNormal.normal[0] = normalVec[0]; - objNormal.normal[1] = normalVec[2]; - objNormal.normal[2] = -normalVec[1]; - objUv.uv[0] = uv[0]; - objUv.uv[1] = 1.0f - uv[1]; - - writer.AddVertex(static_cast(surfIndex), objVertex); - writer.AddNormal(static_cast(surfIndex), objNormal); - writer.AddUv(static_cast(surfIndex), objUv); - } - } - } - - void AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod) - { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - const auto& surface = surfs[surfIndex]; - for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) - { - const auto& tri = surface.triIndices[triIndex]; - - ObjFace face{}; - face.vertexIndex[0] = tri[2] + surface.baseVertIndex; - face.vertexIndex[1] = tri[1] + surface.baseVertIndex; - face.vertexIndex[2] = tri[0] + surface.baseVertIndex; - face.normalIndex[0] = face.vertexIndex[0]; - face.normalIndex[1] = face.vertexIndex[1]; - face.normalIndex[2] = face.vertexIndex[2]; - face.uvIndex[0] = face.vertexIndex[0]; - face.uvIndex[1] = face.vertexIndex[1]; - face.uvIndex[2] = face.vertexIndex[2]; - writer.AddFace(static_cast(surfIndex), face); - } - } - } - - void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo* asset) - { - const auto* model = asset->Asset(); - const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); - - if (!matFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - writer.WriteMtl(*matFile); - } - - void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) - { - const auto* model = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj")); - - if (!assetFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - AddObjObjects(writer, materialMapper, model, lod); - AddObjVertices(writer, model, lod); - AddObjFaces(writer, model, lod); - - writer.WriteObj(*assetFile, std::format("{}.mtl", model->name)); - } - void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model) { for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) @@ -307,6 +165,14 @@ namespace if (colorMap) xMaterial.colorMapName = std::string(colorMap->name); + const auto* normalMap = GetMaterialNormalMap(material); + if (normalMap) + xMaterial.normalMapName = std::string(normalMap->name); + + const auto* specularMap = GetMaterialSpecularMap(material); + if (specularMap) + xMaterial.specularMapName = std::string(specularMap->name); + out.m_materials.emplace_back(std::move(xMaterial)); } } @@ -517,6 +383,9 @@ namespace for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) { const auto& surface = surfs[surfIndex]; + auto& object = out.m_objects[surfIndex]; + object.m_faces.reserve(surface.triCount); + for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) { const auto& tri = surface.triIndices[triIndex]; @@ -525,8 +394,7 @@ namespace face.vertexIndex[0] = tri[0] + surface.baseVertIndex; face.vertexIndex[1] = tri[1] + surface.baseVertIndex; face.vertexIndex[2] = tri[2] + surface.baseVertIndex; - face.objectIndex = static_cast(surfIndex); - out.m_faces.emplace_back(face); + object.m_faces.emplace_back(face); } } } @@ -544,6 +412,35 @@ namespace AddXModelFaces(out, model, lod); } + void DumpObjMtl(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset) + { + const auto* model = asset->Asset(); + const auto mtlFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); + + if (!mtlFile) + return; + + const auto writer = obj::CreateMtlWriter(*mtlFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + + void DumpObjLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) + { + const auto* model = asset->Asset(); + const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj")); + + if (!assetFile) + return; + + const auto writer = + obj::CreateObjWriter(*assetFile, std::format("{}.mtl", model->name), context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + void DumpXModelExportLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) { const auto* model = asset->Asset(); @@ -576,9 +473,6 @@ namespace { 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++) { XModelCommon common; @@ -587,7 +481,9 @@ namespace switch (ObjWriting::Configuration.ModelOutputFormat) { case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: - DumpObjLod(context, asset, currentLod); + DumpObjLod(common, context, asset, currentLod); + if (currentLod == 0u) + DumpObjMtl(common, context, asset); break; case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp index 526dfa68..794367ed 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp @@ -115,148 +115,6 @@ namespace return potentialTextureDefs[0]->image; } - void AddObjMaterials(ObjWriter& writer, DistinctMapper& materialMapper, const XModel* model) - { - if (!model->materialHandles) - return; - - for (auto surfIndex = 0u; surfIndex < model->numsurfs; surfIndex++) - { - Material* material = model->materialHandles[surfIndex]; - if (!materialMapper.Add(material)) - continue; - - MtlMaterial mtl; - mtl.materialName = std::string(material->info.name); - - GfxImage* colorMap = GetMaterialColorMap(material); - GfxImage* normalMap = GetMaterialNormalMap(material); - GfxImage* specularMap = GetMaterialSpecularMap(material); - - if (colorMap != nullptr) - mtl.colorMapName = colorMap->name; - if (normalMap != nullptr) - mtl.normalMapName = normalMap->name; - if (specularMap != nullptr) - mtl.specularMapName = specularMap->name; - - writer.AddMaterial(std::move(mtl)); - } - } - - void AddObjObjects(ObjWriter& writer, const DistinctMapper& materialMapper, const XModel* model, const unsigned lod) - { - const auto surfCount = model->lodInfo[lod].numsurfs; - const auto baseSurfIndex = model->lodInfo[lod].surfIndex; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - ObjObject object; - object.name = std::format("surf{}", surfIndex); - object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfIndex)); - - writer.AddObject(std::move(object)); - } - } - - void AddObjVertices(ObjWriter& writer, const XModel* model, const unsigned lod) - { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - const auto& surface = surfs[surfIndex]; - - for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++) - { - const auto& v = surface.verts0[vertexIndex]; - vec2_t uv{}; - vec3_t normalVec{}; - - Common::Vec2UnpackTexCoords(v.texCoord, &uv); - Common::Vec3UnpackUnitVec(v.normal, &normalVec); - - ObjVertex objVertex{}; - ObjNormal objNormal{}; - ObjUv objUv{}; - objVertex.coordinates[0] = v.xyz.x; - objVertex.coordinates[1] = v.xyz.z; - objVertex.coordinates[2] = -v.xyz.y; - objNormal.normal[0] = normalVec.x; - objNormal.normal[1] = normalVec.z; - objNormal.normal[2] = -normalVec.y; - objUv.uv[0] = uv.x; - objUv.uv[1] = 1.0f - uv.y; - - writer.AddVertex(static_cast(surfIndex), objVertex); - writer.AddNormal(static_cast(surfIndex), objNormal); - writer.AddUv(static_cast(surfIndex), objUv); - } - } - } - - void AddObjFaces(ObjWriter& writer, const XModel* model, const unsigned lod) - { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) - { - const auto& surface = surfs[surfIndex]; - for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) - { - const auto& tri = surface.triIndices[triIndex]; - - ObjFace face{}; - face.vertexIndex[0] = tri[2] + surface.baseVertIndex; - face.vertexIndex[1] = tri[1] + surface.baseVertIndex; - face.vertexIndex[2] = tri[0] + surface.baseVertIndex; - face.normalIndex[0] = face.vertexIndex[0]; - face.normalIndex[1] = face.vertexIndex[1]; - face.normalIndex[2] = face.vertexIndex[2]; - face.uvIndex[0] = face.vertexIndex[0]; - face.uvIndex[1] = face.vertexIndex[1]; - face.uvIndex[2] = face.vertexIndex[2]; - writer.AddFace(static_cast(surfIndex), face); - } - } - } - - void DumpObjMat(const AssetDumpingContext& context, const XAssetInfo* asset) - { - const auto* model = asset->Asset(); - const auto matFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); - - if (!matFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - writer.WriteMtl(*matFile); - } - - void DumpObjLod(const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) - { - const auto* model = asset->Asset(); - const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj")); - - if (!assetFile) - return; - - ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - DistinctMapper materialMapper(model->numsurfs); - - AddObjMaterials(writer, materialMapper, model); - AddObjObjects(writer, materialMapper, model, lod); - AddObjVertices(writer, model, lod); - AddObjFaces(writer, model, lod); - - writer.WriteObj(*assetFile, std::format("{}.mtl", model->name)); - } - void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model) { for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) @@ -319,6 +177,14 @@ namespace if (colorMap) xMaterial.colorMapName = std::string(colorMap->name); + const auto* normalMap = GetMaterialNormalMap(material); + if (normalMap) + xMaterial.normalMapName = std::string(normalMap->name); + + const auto* specularMap = GetMaterialSpecularMap(material); + if (specularMap) + xMaterial.specularMapName = std::string(specularMap->name); + out.m_materials.emplace_back(std::move(xMaterial)); } } @@ -541,6 +407,9 @@ namespace for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) { const auto& surface = surfs[surfIndex]; + auto& object = out.m_objects[surfIndex]; + object.m_faces.reserve(surface.triCount); + for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) { const auto& tri = surface.triIndices[triIndex]; @@ -549,8 +418,7 @@ namespace face.vertexIndex[0] = tri[0] + surface.baseVertIndex; face.vertexIndex[1] = tri[1] + surface.baseVertIndex; face.vertexIndex[2] = tri[2] + surface.baseVertIndex; - face.objectIndex = static_cast(surfIndex); - out.m_faces.emplace_back(face); + object.m_faces.emplace_back(face); } } } @@ -568,6 +436,35 @@ namespace AddXModelFaces(out, model, lod); } + void DumpObjMtl(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset) + { + const auto* model = asset->Asset(); + const auto mtlFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name)); + + if (!mtlFile) + return; + + const auto writer = obj::CreateMtlWriter(*mtlFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + + void DumpObjLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) + { + const auto* model = asset->Asset(); + const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj")); + + if (!assetFile) + return; + + const auto writer = + obj::CreateObjWriter(*assetFile, std::format("{}.mtl", model->name), context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + + writer->Write(common); + } + void DumpXModelExportLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod) { const auto* model = asset->Asset(); @@ -600,9 +497,6 @@ namespace { 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++) { XModelCommon common; @@ -611,7 +505,9 @@ namespace switch (ObjWriting::Configuration.ModelOutputFormat) { case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: - DumpObjLod(context, asset, currentLod); + DumpObjLod(common, context, asset, currentLod); + if (currentLod == 0u) + DumpObjMtl(common, context, asset); break; case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: diff --git a/src/ObjWriting/XModel/Export/XModelExportWriter.cpp b/src/ObjWriting/XModel/Export/XModelExportWriter.cpp index e872d602..f65bc559 100644 --- a/src/ObjWriting/XModel/Export/XModelExportWriter.cpp +++ b/src/ObjWriting/XModel/Export/XModelExportWriter.cpp @@ -116,24 +116,35 @@ class XModelExportWriter6 final : public XModelExportWriterBase void WriteFaces(const XModelCommon& xmodel) const { - m_stream << "NUMFACES " << xmodel.m_faces.size() << "\n"; - for (const auto& face : xmodel.m_faces) + auto totalFaceCount = 0u; + for (const auto& object : xmodel.m_objects) + totalFaceCount += object.m_faces.size(); + + m_stream << "NUMFACES " << totalFaceCount << "\n"; + + auto objectIndex = 0u; + for (const auto& object : xmodel.m_objects) { - const size_t distinctPositions[3]{ - m_vertex_merger.GetDistinctPositionByInputPosition(face.vertexIndex[0]), - m_vertex_merger.GetDistinctPositionByInputPosition(face.vertexIndex[1]), - m_vertex_merger.GetDistinctPositionByInputPosition(face.vertexIndex[2]), - }; + for (const auto& face : object.m_faces) + { + const size_t distinctPositions[3]{ + m_vertex_merger.GetDistinctPositionByInputPosition(face.vertexIndex[0]), + m_vertex_merger.GetDistinctPositionByInputPosition(face.vertexIndex[1]), + m_vertex_merger.GetDistinctPositionByInputPosition(face.vertexIndex[2]), + }; - const XModelVertex& v0 = xmodel.m_vertices[face.vertexIndex[0]]; - const XModelVertex& v1 = xmodel.m_vertices[face.vertexIndex[1]]; - const XModelVertex& v2 = xmodel.m_vertices[face.vertexIndex[2]]; + const XModelVertex& v0 = xmodel.m_vertices[face.vertexIndex[0]]; + const XModelVertex& v1 = xmodel.m_vertices[face.vertexIndex[1]]; + const XModelVertex& v2 = xmodel.m_vertices[face.vertexIndex[2]]; - m_stream << "TRI " << face.objectIndex << " " << xmodel.m_objects[face.objectIndex].materialIndex << " 0 0\n"; - WriteFaceVertex(distinctPositions[0], v0); - WriteFaceVertex(distinctPositions[1], v1); - WriteFaceVertex(distinctPositions[2], v2); - m_stream << "\n"; + m_stream << "TRI " << objectIndex << " " << object.materialIndex << " 0 0\n"; + WriteFaceVertex(distinctPositions[0], v0); + WriteFaceVertex(distinctPositions[1], v1); + WriteFaceVertex(distinctPositions[2], v2); + m_stream << "\n"; + } + + objectIndex++; } } diff --git a/src/ObjWriting/XModel/Obj/ObjWriter.cpp b/src/ObjWriting/XModel/Obj/ObjWriter.cpp index 2c8ad908..e0538943 100644 --- a/src/ObjWriting/XModel/Obj/ObjWriter.cpp +++ b/src/ObjWriting/XModel/Obj/ObjWriter.cpp @@ -1,157 +1,225 @@ #include "ObjWriter.h" -#include "Game/IW4/CommonIW4.h" +#include "Utils/DistinctMapper.h" +#include "XModel/Obj/ObjCommon.h" -ObjWriter::ObjWriter(std::string gameName, std::string zoneName) - : m_game_name(std::move(gameName)), - m_zone_name(std::move(zoneName)) +namespace { -} - -void ObjWriter::AddObject(ObjObject object) -{ - m_objects.emplace_back(std::move(object)); - m_object_data.emplace_back(); -} - -void ObjWriter::AddMaterial(MtlMaterial material) -{ - m_materials.emplace_back(std::move(material)); -} - -void ObjWriter::AddVertex(const int objectId, const ObjVertex vertex) -{ - if (objectId < 0 || static_cast(objectId) >= m_object_data.size()) - return; - - m_object_data[objectId].m_vertices.Add(vertex); -} - -void ObjWriter::AddNormal(const int objectId, const ObjNormal normal) -{ - if (objectId < 0 || static_cast(objectId) >= m_object_data.size()) - return; - - m_object_data[objectId].m_normals.Add(normal); -} - -void ObjWriter::AddUv(const int objectId, const ObjUv uv) -{ - if (objectId < 0 || static_cast(objectId) >= m_object_data.size()) - return; - - m_object_data[objectId].m_uvs.Add(uv); -} - -void ObjWriter::AddFace(const int objectId, const ObjFace face) -{ - if (objectId < 0 || static_cast(objectId) >= m_object_data.size()) - return; - - m_object_data[objectId].m_faces.push_back(face); -} - -void ObjWriter::GetObjObjectDataOffsets(std::vector& inputOffsets, std::vector& distinctOffsets) -{ - ObjObjectDataOffsets currentInputOffsets{}; - ObjObjectDataOffsets currentDistinctOffsets{}; - - for (const auto& objectData : m_object_data) + struct ObjObjectData { - inputOffsets.push_back(currentInputOffsets); - distinctOffsets.push_back(currentDistinctOffsets); + DistinctMapper m_vertices; + DistinctMapper m_normals; + DistinctMapper m_uvs; + }; - currentInputOffsets.vertexOffset += objectData.m_vertices.GetInputValueCount(); - currentInputOffsets.normalOffset += objectData.m_normals.GetInputValueCount(); - currentInputOffsets.uvOffset += objectData.m_uvs.GetInputValueCount(); - currentDistinctOffsets.vertexOffset += objectData.m_vertices.GetDistinctValueCount(); - currentDistinctOffsets.normalOffset += objectData.m_normals.GetDistinctValueCount(); - currentDistinctOffsets.uvOffset += objectData.m_uvs.GetDistinctValueCount(); - } -} - -void ObjWriter::WriteObj(std::ostream& stream) -{ - WriteObj(stream, std::string()); -} - -void ObjWriter::WriteObj(std::ostream& stream, const std::string& mtlName) -{ - stream << "# OpenAssetTools OBJ File ( " << m_game_name << ")\n"; - stream << "# Game Origin: " << m_game_name << "\n"; - stream << "# Zone Origin: " << m_zone_name << "\n"; - - if (!mtlName.empty()) - stream << "mtllib " << mtlName << "\n"; - - std::vector inputOffsetsByObject; - std::vector distinctOffsetsByObject; - GetObjObjectDataOffsets(inputOffsetsByObject, distinctOffsetsByObject); - - auto objectIndex = 0; - for (const auto& object : m_objects) + struct ObjObjectDataOffsets { - const auto& objectData = m_object_data[objectIndex]; - stream << "o " << object.name << "\n"; + size_t vertexOffset; + size_t normalOffset; + size_t uvOffset; + }; - for (const auto& v : objectData.m_vertices.GetDistinctValues()) - stream << "v " << v.coordinates[0] << " " << v.coordinates[1] << " " << v.coordinates[2] << "\n"; - for (const auto& uv : objectData.m_uvs.GetDistinctValues()) - stream << "vt " << uv.uv[0] << " " << uv.uv[1] << "\n"; - for (const auto& n : objectData.m_normals.GetDistinctValues()) - stream << "vn " << n.normal[0] << " " << n.normal[1] << " " << n.normal[2] << "\n"; - - if (object.materialIndex >= 0 && static_cast(object.materialIndex) < m_materials.size()) - stream << "usemtl " << m_materials[object.materialIndex].materialName << "\n"; - - for (const auto& f : objectData.m_faces) + class ObjWriter final : public XModelWriter + { + public: + ObjWriter(std::ostream& stream, std::string gameName, std::string zoneName, std::string mtlName) + : m_stream(stream), + m_mtl_name(std::move(mtlName)), + m_game_name(std::move(gameName)), + m_zone_name(std::move(zoneName)) { - const size_t v[3]{objectData.m_vertices.GetDistinctPositionByInputPosition(f.vertexIndex[0] - inputOffsetsByObject[objectIndex].vertexOffset) - + distinctOffsetsByObject[objectIndex].vertexOffset + 1, - objectData.m_vertices.GetDistinctPositionByInputPosition(f.vertexIndex[1] - inputOffsetsByObject[objectIndex].vertexOffset) - + distinctOffsetsByObject[objectIndex].vertexOffset + 1, - objectData.m_vertices.GetDistinctPositionByInputPosition(f.vertexIndex[2] - inputOffsetsByObject[objectIndex].vertexOffset) - + distinctOffsetsByObject[objectIndex].vertexOffset + 1}; - const size_t n[3]{objectData.m_normals.GetDistinctPositionByInputPosition(f.normalIndex[0] - inputOffsetsByObject[objectIndex].normalOffset) - + distinctOffsetsByObject[objectIndex].normalOffset + 1, - objectData.m_normals.GetDistinctPositionByInputPosition(f.normalIndex[1] - inputOffsetsByObject[objectIndex].normalOffset) - + distinctOffsetsByObject[objectIndex].normalOffset + 1, - objectData.m_normals.GetDistinctPositionByInputPosition(f.normalIndex[2] - inputOffsetsByObject[objectIndex].normalOffset) - + distinctOffsetsByObject[objectIndex].normalOffset + 1}; - const size_t uv[3]{objectData.m_uvs.GetDistinctPositionByInputPosition(f.uvIndex[0] - inputOffsetsByObject[objectIndex].uvOffset) - + distinctOffsetsByObject[objectIndex].uvOffset + 1, - objectData.m_uvs.GetDistinctPositionByInputPosition(f.uvIndex[1] - inputOffsetsByObject[objectIndex].uvOffset) - + distinctOffsetsByObject[objectIndex].uvOffset + 1, - objectData.m_uvs.GetDistinctPositionByInputPosition(f.uvIndex[2] - inputOffsetsByObject[objectIndex].uvOffset) - + distinctOffsetsByObject[objectIndex].uvOffset + 1}; - - stream << "f " << v[0] << "/" << uv[0] << "/" << n[0] << " " << v[1] << "/" << uv[1] << "/" << n[1] << " " << v[2] << "/" << uv[2] << "/" << n[2] - << "\n"; } - objectIndex++; - } -} + void Write(const XModelCommon& xmodel) override + { + m_stream << "# OpenAssetTools OBJ File ( " << m_game_name << ")\n"; + m_stream << "# Game Origin: " << m_game_name << "\n"; + m_stream << "# Zone Origin: " << m_zone_name << "\n"; -void ObjWriter::WriteMtl(std::ostream& stream) -{ - stream << "# OpenAssetTools MAT File ( " << m_game_name << ")\n"; - stream << "# Game Origin: " << m_game_name << "\n"; - stream << "# Zone Origin: " << m_zone_name << "\n"; - stream << "# Material count: " << m_materials.size() << "\n"; + if (!m_mtl_name.empty()) + m_stream << "mtllib " << m_mtl_name << "\n"; - for (const auto& material : m_materials) + std::vector inputOffsetsByObject; + std::vector distinctOffsetsByObject; + GetObjObjectDataOffsets(xmodel, inputOffsetsByObject, distinctOffsetsByObject); + + auto objectIndex = 0; + for (const auto& object : xmodel.m_objects) + { + const auto& objectData = m_object_data[objectIndex]; + m_stream << "o " << object.name << "\n"; + + for (const auto& v : objectData.m_vertices.GetDistinctValues()) + m_stream << "v " << v.coordinates[0] << " " << v.coordinates[1] << " " << v.coordinates[2] << "\n"; + for (const auto& uv : objectData.m_uvs.GetDistinctValues()) + m_stream << "vt " << uv.uv[0] << " " << uv.uv[1] << "\n"; + for (const auto& n : objectData.m_normals.GetDistinctValues()) + m_stream << "vn " << n.normal[0] << " " << n.normal[1] << " " << n.normal[2] << "\n"; + + if (object.materialIndex >= 0 && static_cast(object.materialIndex) < xmodel.m_materials.size()) + m_stream << "usemtl " << xmodel.m_materials[object.materialIndex].name << "\n"; + + auto faceIndex = 0u; + for (const auto& f : object.m_faces) + { + const auto faceVertexOffset = 3u * faceIndex; + const size_t v[3]{ + objectData.m_vertices.GetDistinctPositionByInputPosition(faceVertexOffset + 0) + distinctOffsetsByObject[objectIndex].vertexOffset + 1, + objectData.m_vertices.GetDistinctPositionByInputPosition(faceVertexOffset + 1) + distinctOffsetsByObject[objectIndex].vertexOffset + 1, + objectData.m_vertices.GetDistinctPositionByInputPosition(faceVertexOffset + 2) + distinctOffsetsByObject[objectIndex].vertexOffset + 1, + }; + const size_t n[3]{ + objectData.m_normals.GetDistinctPositionByInputPosition(faceVertexOffset + 0) + distinctOffsetsByObject[objectIndex].normalOffset + 1, + objectData.m_normals.GetDistinctPositionByInputPosition(faceVertexOffset + 1) + distinctOffsetsByObject[objectIndex].normalOffset + 1, + objectData.m_normals.GetDistinctPositionByInputPosition(faceVertexOffset + 2) + distinctOffsetsByObject[objectIndex].normalOffset + 1, + }; + const size_t uv[3]{ + objectData.m_uvs.GetDistinctPositionByInputPosition(faceVertexOffset + 0) + distinctOffsetsByObject[objectIndex].uvOffset + 1, + objectData.m_uvs.GetDistinctPositionByInputPosition(faceVertexOffset + 1) + distinctOffsetsByObject[objectIndex].uvOffset + 1, + objectData.m_uvs.GetDistinctPositionByInputPosition(faceVertexOffset + 2) + distinctOffsetsByObject[objectIndex].uvOffset + 1, + }; + + m_stream << std::format("f {}/{}/{} {}/{}/{} {}/{}/{}\n", v[0], uv[0], n[0], v[1], uv[1], n[1], v[2], uv[2], n[2]); + faceIndex++; + } + + objectIndex++; + } + } + + void GetObjObjectDataOffsets(const XModelCommon& xmodel, + std::vector& inputOffsets, + std::vector& distinctOffsets) + { + ObjObjectDataOffsets currentInputOffsets{}; + ObjObjectDataOffsets currentDistinctOffsets{}; + + AddObjFaces(xmodel); + + for (const auto& objectData : m_object_data) + { + inputOffsets.push_back(currentInputOffsets); + distinctOffsets.push_back(currentDistinctOffsets); + + currentInputOffsets.vertexOffset += objectData.m_vertices.GetInputValueCount(); + currentInputOffsets.normalOffset += objectData.m_normals.GetInputValueCount(); + currentInputOffsets.uvOffset += objectData.m_uvs.GetInputValueCount(); + currentDistinctOffsets.vertexOffset += objectData.m_vertices.GetDistinctValueCount(); + currentDistinctOffsets.normalOffset += objectData.m_normals.GetDistinctValueCount(); + currentDistinctOffsets.uvOffset += objectData.m_uvs.GetDistinctValueCount(); + } + } + + void AddObjFaces(const XModelCommon& common) + { + m_object_data.resize(common.m_objects.size()); + + auto objectIndex = 0u; + for (const auto& commonObject : common.m_objects) + { + auto& objectData = m_object_data[objectIndex]; + + for (const auto& commonFace : commonObject.m_faces) + { + ObjFace face{}; + face.vertexIndex[0] = commonFace.vertexIndex[2]; + face.vertexIndex[1] = commonFace.vertexIndex[1]; + face.vertexIndex[2] = commonFace.vertexIndex[0]; + face.normalIndex[0] = face.vertexIndex[0]; + face.normalIndex[1] = face.vertexIndex[1]; + face.normalIndex[2] = face.vertexIndex[2]; + face.uvIndex[0] = face.vertexIndex[0]; + face.uvIndex[1] = face.vertexIndex[1]; + face.uvIndex[2] = face.vertexIndex[2]; + + // Reverse order for OBJ + AddObjVertex(objectData, common, commonFace.vertexIndex[2]); + AddObjVertex(objectData, common, commonFace.vertexIndex[1]); + AddObjVertex(objectData, common, commonFace.vertexIndex[0]); + } + + objectIndex++; + } + } + + static void AddObjVertex(ObjObjectData& objectData, const XModelCommon& common, const int commonVertexIndex) + { + const auto& commonVertex = common.m_vertices[commonVertexIndex]; + + ObjVertex objVertex{}; + objVertex.coordinates[0] = commonVertex.coordinates[0]; + objVertex.coordinates[1] = commonVertex.coordinates[2]; + objVertex.coordinates[2] = -commonVertex.coordinates[1]; + objectData.m_vertices.Add(objVertex); + + ObjNormal objNormal{}; + objNormal.normal[0] = commonVertex.normal[0]; + objNormal.normal[1] = commonVertex.normal[2]; + objNormal.normal[2] = -commonVertex.normal[1]; + objectData.m_normals.Add(objNormal); + + ObjUv objUv{}; + objUv.uv[0] = commonVertex.uv[0]; + objUv.uv[1] = 1.0f - commonVertex.uv[1]; + objectData.m_uvs.Add(objUv); + } + + std::ostream& m_stream; + std::string m_mtl_name; + std::string m_game_name; + std::string m_zone_name; + std::vector m_object_data; + }; + + class MtlWriter final : public XModelWriter { - stream << "\n"; - stream << "newmtl " << material.materialName << "\n"; + public: + MtlWriter(std::ostream& stream, std::string gameName, std::string zoneName) + : m_stream(stream), + m_game_name(std::move(gameName)), + m_zone_name(std::move(zoneName)) + { + } - if (!material.colorMapName.empty()) - stream << "map_Kd ../images/" << material.colorMapName << ".dds\n"; + void Write(const XModelCommon& xmodel) override + { + m_stream << "# OpenAssetTools MAT File ( " << m_game_name << ")\n"; + m_stream << "# Game Origin: " << m_game_name << "\n"; + m_stream << "# Zone Origin: " << m_zone_name << "\n"; + m_stream << "# Material count: " << xmodel.m_materials.size() << "\n"; - if (!material.normalMapName.empty()) - stream << "map_bump ../images/" << material.normalMapName << ".dds\n"; + for (const auto& material : xmodel.m_materials) + { + m_stream << "\n"; + m_stream << "newmtl " << material.name << "\n"; - if (!material.specularMapName.empty()) - stream << "map_Ks ../images/" << material.specularMapName << ".dds\n"; + if (!material.colorMapName.empty()) + m_stream << "map_Kd ../images/" << material.colorMapName << ".dds\n"; + + if (!material.normalMapName.empty()) + m_stream << "map_bump ../images/" << material.normalMapName << ".dds\n"; + + if (!material.specularMapName.empty()) + m_stream << "map_Ks ../images/" << material.specularMapName << ".dds\n"; + } + } + + private: + std::ostream& m_stream; + std::string m_game_name; + std::string m_zone_name; + }; +} // namespace + +namespace obj +{ + std::unique_ptr CreateObjWriter(std::ostream& stream, std::string mtlName, std::string gameName, std::string zoneName) + { + return std::make_unique(stream, std::move(mtlName), std::move(gameName), std::move(zoneName)); } -} + + std::unique_ptr CreateMtlWriter(std::ostream& stream, std::string gameName, std::string zoneName) + { + return std::make_unique(stream, std::move(gameName), std::move(zoneName)); + } +} // namespace obj diff --git a/src/ObjWriting/XModel/Obj/ObjWriter.h b/src/ObjWriting/XModel/Obj/ObjWriter.h index 8f809282..5d1ff9dd 100644 --- a/src/ObjWriting/XModel/Obj/ObjWriter.h +++ b/src/ObjWriting/XModel/Obj/ObjWriter.h @@ -1,48 +1,11 @@ #pragma once -#include "Utils/DistinctMapper.h" -#include "XModel/Obj/ObjCommon.h" +#include "XModel/XModelWriter.h" #include -#include -class ObjWriter +namespace obj { -protected: - struct ObjObjectData - { - DistinctMapper m_vertices; - DistinctMapper m_normals; - DistinctMapper m_uvs; - std::vector m_faces; - }; - - struct ObjObjectDataOffsets - { - size_t vertexOffset; - size_t normalOffset; - size_t uvOffset; - }; - - std::string m_game_name; - std::string m_zone_name; - std::vector m_objects; - std::vector m_object_data; - std::vector m_materials; - - void GetObjObjectDataOffsets(std::vector& inputOffsets, std::vector& distinctOffsets); - -public: - ObjWriter(std::string gameName, std::string zoneName); - - void AddObject(ObjObject object); - void AddMaterial(MtlMaterial material); - void AddVertex(int objectId, ObjVertex vertex); - void AddNormal(int objectId, ObjNormal normal); - void AddUv(int objectId, ObjUv uv); - void AddFace(int objectId, ObjFace face); - - void WriteObj(std::ostream& stream); - void WriteObj(std::ostream& stream, const std::string& mtlName); - void WriteMtl(std::ostream& stream); -}; + std::unique_ptr CreateObjWriter(std::ostream& stream, std::string mtlName, std::string gameName, std::string zoneName); + std::unique_ptr CreateMtlWriter(std::ostream& stream, std::string gameName, std::string zoneName); +} // namespace obj