diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index 5c7e004c..129c9f2c 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -177,11 +177,50 @@ namespace IW5 void* data; }; - typedef float vec2_t[2]; - typedef float vec3_t[3]; - typedef float vec4_t[4]; + union vec2_t + { + float v[2]; + + struct + { + float x; + float y; + }; + }; + + union vec3_t + { + struct + { + float x; + float y; + float z; + }; + + float v[3]; + }; + + union vec4_t + { + float v[4]; + + struct + { + float x; + float y; + float z; + float w; + }; + + struct + { + float r; + float g; + float b; + float a; + }; + }; - typedef tdef_align(16) uint16_t r_index16_t; typedef tdef_align(16) char raw_byte16; typedef tdef_align(16) float raw_float16; typedef tdef_align(128) unsigned int raw_uint128; @@ -220,8 +259,8 @@ namespace IW5 struct Bounds { - float midPoint[3]; - float halfSize[3]; + vec3_t midPoint; + vec3_t halfSize; }; struct cplane_s @@ -446,34 +485,15 @@ namespace IW5 unsigned int packed; }; - struct GfxQuantizedNoColorVertex - { - short xyz[3]; - short binormalSign; - PackedUnitVec normal; - PackedUnitVec tangent; - PackedTexCoords texCoord; - }; - union GfxColor { unsigned int packed; unsigned char array[4]; }; - struct GfxQuantizedVertex - { - short xyz[3]; - short binormalSign; - PackedUnitVec normal; - PackedUnitVec tangent; - PackedTexCoords texCoord; - GfxColor color; - }; - struct type_align(16) GfxPackedVertex { - float xyz[3]; + vec3_t xyz; float binormalSign; GfxColor color; PackedTexCoords texCoord; @@ -481,14 +501,6 @@ namespace IW5 PackedUnitVec tangent; }; - union GfxVertexUnion0 - { - GfxQuantizedNoColorVertex* quantizedNoColorVerts0; - GfxQuantizedVertex* quantizedVerts0; - GfxPackedVertex* packedVerts0; - void* verts0; - }; - struct XSurfaceCollisionAabb { unsigned short mins[3]; @@ -526,6 +538,13 @@ namespace IW5 XSurfaceCollisionTree* collisionTree; }; + struct XSurfaceTri + { + uint16_t i[3]; + }; + + typedef tdef_align(16) XSurfaceTri XSurfaceTri16; + struct XSurface { unsigned char tileMode; @@ -536,9 +555,9 @@ namespace IW5 uint16_t baseTriIndex; uint16_t baseVertIndex; float quantizeScale; - r_index16_t (*triIndices)[3]; + XSurfaceTri16* triIndices; XSurfaceVertexInfo vertInfo; - GfxVertexUnion0 verts0; + GfxPackedVertex* verts0; unsigned int vertListCount; XRigidVertList* vertList; int partBits[6]; @@ -554,8 +573,8 @@ namespace IW5 struct DObjAnimMat { - float quat[4]; - float trans[3]; + vec4_t quat; + vec3_t trans; float transWeight; }; @@ -567,7 +586,7 @@ namespace IW5 XModelSurfs* modelSurfs; int partBits[6]; XSurface* surfs; - char lod; + unsigned char lod; char smcBaseIndexPlusOne; char smcSubIndexMask; char smcBucket; @@ -596,6 +615,11 @@ namespace IW5 float radiusSquared; }; + struct XModelQuat + { + int16_t v[4]; + }; + struct XModel { const char* name; @@ -606,15 +630,15 @@ namespace IW5 unsigned int noScalePartBits[6]; ScriptString* boneNames; unsigned char* parentList; - short (*quats)[4]; - float (*trans)[3]; + XModelQuat* quats; + float* trans; unsigned char* partClassification; DObjAnimMat* baseMat; Material** materialHandles; XModelLodInfo lodInfo[4]; char maxLoadedLod; unsigned char numLods; - unsigned char collLod; + char collLod; unsigned char flags; XModelCollSurf_s* collSurfs; int numCollSurfs; diff --git a/src/ObjCommon/Game/IW5/XModel/JsonXModelIW5.h b/src/ObjCommon/Game/IW5/XModel/JsonXModelIW5.h new file mode 100644 index 00000000..ce7424ff --- /dev/null +++ b/src/ObjCommon/Game/IW5/XModel/JsonXModelIW5.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Json/JsonCommon.h" +#include +#include +#include +#include +#include + +namespace IW5 +{ + class JsonXModelLod + { + public: + std::string file; + float distance; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonXModelLod, file, distance); + + class JsonXModel + { + public: + std::vector lods; + std::optional collLod; + std::optional physPreset; + std::optional physCollmap; + uint8_t flags; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonXModel, lods, collLod, physPreset, physCollmap, flags); +} // namespace IW5 diff --git a/src/ObjCommon/Game/IW5/XModel/XModelConstantsIW5.h b/src/ObjCommon/Game/IW5/XModel/XModelConstantsIW5.h new file mode 100644 index 00000000..a0a129a3 --- /dev/null +++ b/src/ObjCommon/Game/IW5/XModel/XModelConstantsIW5.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Game/IW5/IW5.h" + +namespace IW5 +{ + inline const char* HITLOC_NAMES[]{ + // clang-format off + "none", + "helmet", + "head", + "neck", + "torso_upper", + "torso_lower", + "right_arm_upper", + "left_arm_upper", + "right_arm_lower", + "left_arm_lower", + "right_hand", + "left_hand", + "right_leg_upper", + "left_leg_upper", + "right_leg_lower", + "left_leg_lower", + "right_foot", + "left_foot", + "gun", + "shield", + // clang-format on + }; + static_assert(std::extent_v == HITLOC_COUNT); +} // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp index 18b3007a..19713878 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderWeapon.cpp @@ -814,8 +814,8 @@ namespace for (auto i = 0u; i < originalGraphKnotCount; i++) { const auto& commonKnot = graph.knots[i]; - originalGraphKnots[i][0] = static_cast(commonKnot.x); - originalGraphKnots[i][1] = static_cast(commonKnot.y); + originalGraphKnots[i].x = static_cast(commonKnot.x); + originalGraphKnots[i].y = static_cast(commonKnot.y); } graphKnots = originalGraphKnots; diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.cpp index 2822c257..c4689b39 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.cpp +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.cpp @@ -1,17 +1,42 @@ #include "AssetLoaderXModel.h" #include "Game/IW5/IW5.h" -#include "ObjLoading.h" +#include "Game/IW5/XModel/XModelLoaderIW5.h" #include "Pool/GlobalAssetPool.h" #include +#include +#include using namespace IW5; void* AssetLoaderXModel::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) { - auto* model = memory->Create(); - memset(model, 0, sizeof(XModel)); - model->name = memory->Dup(assetName.c_str()); - return model; + auto* asset = memory->Alloc(); + asset->name = memory->Dup(assetName.c_str()); + return asset; +} + +bool AssetLoaderXModel::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderXModel::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(std::format("xmodel/{}.json", assetName)); + if (!file.IsOpen()) + return false; + + auto* xmodel = memory->Alloc(); + xmodel->name = memory->Dup(assetName.c_str()); + + std::vector dependencies; + if (LoadXModel(*file.m_stream, *xmodel, memory, manager, dependencies)) + manager->AddAsset(assetName, xmodel, std::move(dependencies)); + else + std::cerr << std::format("Failed to load xmodel \"{}\"\n", assetName); + + return true; } diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.h b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.h index 1ea4565d..3bee159f 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.h +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderXModel.h @@ -1,6 +1,6 @@ #pragma once - #include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" #include "Game/IW5/IW5.h" #include "SearchPath/ISearchPath.h" @@ -8,7 +8,12 @@ namespace IW5 { class AssetLoaderXModel final : public BasicAssetLoader { + static std::string GetFileNameForAsset(const std::string& assetName); + public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; }; } // namespace IW5 diff --git a/src/ObjLoading/XModel/XModelLoader.cpp.template b/src/ObjLoading/XModel/XModelLoader.cpp.template index 5cdd8575..100acd52 100644 --- a/src/ObjLoading/XModel/XModelLoader.cpp.template +++ b/src/ObjLoading/XModel/XModelLoader.cpp.template @@ -1,4 +1,4 @@ -#options GAME (T5, T6) +#options GAME(IW5, T5, T6) #filename "Game/" + GAME + "/XModel/XModelLoader" + GAME + ".cpp" @@ -7,7 +7,9 @@ #set CONSTANTS_HEADER "\"Game/" + GAME + "/XModel/XModelConstants" + GAME + ".h\"" #set JSON_HEADER "\"Game/" + GAME + "/XModel/JsonXModel" + GAME + ".h\"" -#if GAME == "T5" +#if GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" #define FEATURE_T5 #elif GAME == "T6" #define FEATURE_T6 @@ -173,15 +175,24 @@ namespace GAME if (common.m_bone_weight_data.weights.empty()) return; - info.bounds[0].x = 0.0f; - info.bounds[0].y = 0.0f; - info.bounds[0].z = 0.0f; - info.bounds[1].x = 0.0f; - info.bounds[1].y = 0.0f; - info.bounds[1].z = 0.0f; - info.offset.x = 0.0f; - info.offset.y = 0.0f; - info.offset.z = 0.0f; +#ifdef FEATURE_IW5 + vec3_t minCoordinate, maxCoordinate; + auto& offset = info.bounds.midPoint; +#else + auto& offset = info.offset; + auto& minCoordinate = info.bounds[0]; + auto& maxCoordinate = info.bounds[1]; +#endif + + minCoordinate.x = 0.0f; + minCoordinate.y = 0.0f; + minCoordinate.z = 0.0f; + maxCoordinate.x = 0.0f; + maxCoordinate.y = 0.0f; + maxCoordinate.z = 0.0f; + offset.x = 0.0f; + offset.y = 0.0f; + offset.z = 0.0f; info.radiusSquared = 0.0f; const auto vertexCount = common.m_vertex_bone_weights.size(); @@ -196,22 +207,31 @@ namespace GAME if (weight.boneIndex != boneIndex) continue; - info.bounds[0].x = std::min(info.bounds[0].x, vertex.coordinates[0]); - info.bounds[0].y = std::min(info.bounds[0].y, vertex.coordinates[1]); - info.bounds[0].z = std::min(info.bounds[0].z, vertex.coordinates[2]); - info.bounds[1].x = std::max(info.bounds[1].x, vertex.coordinates[0]); - info.bounds[1].y = std::max(info.bounds[1].y, vertex.coordinates[1]); - info.bounds[1].z = std::max(info.bounds[1].z, vertex.coordinates[2]); + minCoordinate.x = std::min(minCoordinate.x, vertex.coordinates[0]); + minCoordinate.y = std::min(minCoordinate.y, vertex.coordinates[1]); + minCoordinate.z = std::min(minCoordinate.z, vertex.coordinates[2]); + maxCoordinate.x = std::max(maxCoordinate.x, vertex.coordinates[0]); + maxCoordinate.y = std::max(maxCoordinate.y, vertex.coordinates[1]); + maxCoordinate.z = std::max(maxCoordinate.z, vertex.coordinates[2]); } } - const Eigen::Vector3f minEigen(info.bounds[0].x, info.bounds[0].y, info.bounds[0].z); - const Eigen::Vector3f maxEigen(info.bounds[1].x, info.bounds[1].y, info.bounds[1].z); + const Eigen::Vector3f minEigen(minCoordinate.x, minCoordinate.y, minCoordinate.z); + const Eigen::Vector3f maxEigen(maxCoordinate.x, maxCoordinate.y, maxCoordinate.z); const Eigen::Vector3f boundsCenter = (minEigen + maxEigen) * 0.5f; - info.offset.x = boundsCenter.x(); - info.offset.y = boundsCenter.y(); - info.offset.z = boundsCenter.z(); - info.radiusSquared = Eigen::Vector3f(maxEigen - boundsCenter).squaredNorm(); + const Eigen::Vector3f halfSizeEigen = maxEigen - boundsCenter; +#ifdef FEATURE_IW5 + + info.bounds.halfSize.x = halfSizeEigen.x(); + info.bounds.halfSize.y = halfSizeEigen.y(); + info.bounds.halfSize.z = halfSizeEigen.z(); +#endif + + offset.x = boundsCenter.x(); + offset.y = boundsCenter.y(); + offset.z = boundsCenter.z(); + + info.radiusSquared = halfSizeEigen.squaredNorm(); } bool ApplyCommonBonesToXModel(const JsonXModelLod& jLod, XModel& xmodel, unsigned lodNumber, const XModelCommon& common) const @@ -272,8 +292,10 @@ namespace GAME ApplyBasePose(xmodel.baseMat[boneIndex], bone); CalculateBoneBounds(xmodel.boneInfo[boneIndex], boneIndex, common); +#if defined(FEATURE_T5) || defined(FEATURE_T6) // Other boneInfo data is filled when calculating bone bounds xmodel.boneInfo[boneIndex].collmap = -1; +#endif if (xmodel.numRootBones <= boneIndex) { @@ -678,17 +700,52 @@ namespace GAME lodInfo.partBits[i] |= surface.partBits[i]; } +#ifdef FEATURE_IW5 + auto* modelSurfs = m_memory.Alloc(); + const auto modelSurfsName = std::format("{}_lod{}", xmodel.name, lodNumber); + modelSurfs->name = m_memory.Dup(modelSurfsName.c_str()); + + static_assert(std::extent_v == std::extent_v); + memcpy(modelSurfs->partBits, lodInfo.partBits, sizeof(XModelLodInfo::partBits)); + + modelSurfs->numsurfs = lodInfo.numsurfs; + modelSurfs->surfs = m_memory.Alloc(modelSurfs->numsurfs); + memcpy(modelSurfs->surfs, &m_surfaces[lodInfo.surfIndex], sizeof(XSurface) * modelSurfs->numsurfs); + + m_manager.AddAsset(modelSurfsName, modelSurfs); + + lodInfo.modelSurfs = modelSurfs; + lodInfo.surfs = modelSurfs->surfs; + + lodInfo.lod = static_cast(lodNumber); +#endif + return true; } static void CalculateModelBounds(XModel& xmodel) { +#ifdef FEATURE_IW5 + if (!xmodel.lodInfo[0].modelSurfs || !xmodel.lodInfo[0].modelSurfs->surfs) + return; + + const auto* surfs = xmodel.lodInfo[0].modelSurfs->surfs; + vec3_t minCoordinate, maxCoordinate; +#else if (!xmodel.surfs) return; + auto& minCoordinate = xmodel.mins; + auto& maxCoordinate = xmodel.maxs; +#endif + for (auto surfaceIndex = 0u; surfaceIndex < xmodel.lodInfo[0].numsurfs; surfaceIndex++) { +#ifdef FEATURE_IW5 + const auto& surface = surfs[surfaceIndex]; +#else const auto& surface = xmodel.surfs[surfaceIndex + xmodel.lodInfo[0].surfIndex]; +#endif if (!surface.verts0) continue; @@ -697,19 +754,35 @@ namespace GAME { const auto& vertex = surface.verts0[vertIndex]; - xmodel.mins.x = std::min(xmodel.mins.x, vertex.xyz.v[0]); - xmodel.mins.y = std::min(xmodel.mins.y, vertex.xyz.v[1]); - xmodel.mins.z = std::min(xmodel.mins.z, vertex.xyz.v[2]); - xmodel.maxs.x = std::max(xmodel.maxs.x, vertex.xyz.v[0]); - xmodel.maxs.y = std::max(xmodel.maxs.y, vertex.xyz.v[1]); - xmodel.maxs.z = std::max(xmodel.maxs.z, vertex.xyz.v[2]); + minCoordinate.x = std::min(minCoordinate.x, vertex.xyz.v[0]); + minCoordinate.y = std::min(minCoordinate.y, vertex.xyz.v[1]); + minCoordinate.z = std::min(minCoordinate.z, vertex.xyz.v[2]); + maxCoordinate.x = std::max(maxCoordinate.x, vertex.xyz.v[0]); + maxCoordinate.y = std::max(maxCoordinate.y, vertex.xyz.v[1]); + maxCoordinate.z = std::max(maxCoordinate.z, vertex.xyz.v[2]); } } - const auto maxX = std::max(std::abs(xmodel.mins.x), std::abs(xmodel.maxs.x)); - const auto maxY = std::max(std::abs(xmodel.mins.y), std::abs(xmodel.maxs.y)); - const auto maxZ = std::max(std::abs(xmodel.mins.z), std::abs(xmodel.maxs.z)); +#ifdef FEATURE_IW5 + const Eigen::Vector3f minEigen(minCoordinate.x, minCoordinate.y, minCoordinate.z); + const Eigen::Vector3f maxEigen(maxCoordinate.x, maxCoordinate.y, maxCoordinate.z); + const Eigen::Vector3f boundsCenter = (minEigen + maxEigen) * 0.5f; + const Eigen::Vector3f halfSizeEigen = maxEigen - boundsCenter; + + xmodel.bounds.halfSize.x = halfSizeEigen.x(); + xmodel.bounds.halfSize.y = halfSizeEigen.y(); + xmodel.bounds.halfSize.z = halfSizeEigen.z(); + + xmodel.bounds.midPoint.x = boundsCenter.x(); + xmodel.bounds.midPoint.y = boundsCenter.y(); + xmodel.bounds.midPoint.z = boundsCenter.z(); + xmodel.radius = halfSizeEigen.norm(); +#else + const auto maxX = std::max(std::abs(minCoordinate.x), std::abs(maxCoordinate.x)); + const auto maxY = std::max(std::abs(minCoordinate.y), std::abs(maxCoordinate.y)); + const auto maxZ = std::max(std::abs(minCoordinate.z), std::abs(maxCoordinate.z)); xmodel.radius = Eigen::Vector3f(maxX, maxY, maxZ).norm(); +#endif } bool CreateXModelFromJson(const JsonXModel& jXModel, XModel& xmodel) @@ -722,7 +795,7 @@ namespace GAME } auto lodNumber = 0u; - xmodel.numLods = static_cast(jXModel.lods.size()); + xmodel.numLods = static_cast(jXModel.lods.size()); for (const auto& jLod : jXModel.lods) { if (!LoadLod(jLod, xmodel, lodNumber++)) @@ -736,10 +809,14 @@ namespace GAME return false; } - xmodel.numsurfs = static_cast(m_surfaces.size()); + xmodel.numsurfs = static_cast(m_surfaces.size()); + +#if defined(FEATURE_T5) || defined(FEATURE_T6) xmodel.surfs = m_memory.Alloc(xmodel.numsurfs); - xmodel.materialHandles = m_memory.Alloc(xmodel.numsurfs); memcpy(xmodel.surfs, m_surfaces.data(), sizeof(XSurface) * xmodel.numsurfs); +#endif + + xmodel.materialHandles = m_memory.Alloc(xmodel.numsurfs); memcpy(xmodel.materialHandles, m_materials.data(), sizeof(Material*) * xmodel.numsurfs); CalculateModelBounds(xmodel); @@ -751,7 +828,7 @@ namespace GAME PrintError(xmodel, "Collision lod is not a valid lod"); return false; } - xmodel.collLod = static_cast(jXModel.collLod.value()); + xmodel.collLod = static_cast(jXModel.collLod.value()); } else xmodel.collLod = -1; @@ -772,6 +849,25 @@ namespace GAME xmodel.physPreset = nullptr; } +#if defined(FEATURE_IW5) + if (jXModel.physCollmap) + { + auto* physCollmap = m_manager.LoadDependency(jXModel.physCollmap.value()); + if (!physCollmap) + { + PrintError(xmodel, "Could not find phys collmap"); + return false; + } + m_dependencies.emplace(physCollmap); + xmodel.physCollmap = physCollmap->Asset(); + } + else + { + xmodel.physCollmap = nullptr; + } +#endif + +#if defined(FEATURE_T5) || defined(FEATURE_T6) if (jXModel.physConstraints) { auto* physConstraints = m_manager.LoadDependency(jXModel.physConstraints.value()); @@ -787,6 +883,7 @@ namespace GAME { xmodel.physConstraints = nullptr; } +#endif xmodel.flags = jXModel.flags; diff --git a/src/ObjLoading/XModel/XModelLoader.h.template b/src/ObjLoading/XModel/XModelLoader.h.template index 6aeb6877..3b9d0729 100644 --- a/src/ObjLoading/XModel/XModelLoader.h.template +++ b/src/ObjLoading/XModel/XModelLoader.h.template @@ -1,4 +1,4 @@ -#options GAME (T5, T6) +#options GAME (IW5, T5, T6) #filename "Game/" + GAME + "/XModel/XModelLoader" + GAME + ".h" diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp index dd1bd9d2..15d5fd5b 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp @@ -545,8 +545,8 @@ namespace IW5 for (auto i = 0u; i < originalKnotCount; i++) { auto& knot = graph.knots[i]; - knot.x = originalKnots[i][0]; - knot.y = originalKnots[i][1]; + knot.x = originalKnots[i].x; + knot.y = originalKnots[i].y; } return graph; diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp index 6a0af227..bd882e41 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperXModel.cpp @@ -1,506 +1,9 @@ #include "AssetDumperXModel.h" -#include "Game/IW5/CommonIW5.h" -#include "ObjWriting.h" -#include "Utils/DistinctMapper.h" -#include "Utils/HalfFloat.h" -#include "Utils/QuatInt16.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 "XModel/XModelWriter.h" - -#include -#include +#include "Game/IW5/XModel/XModelDumperIW5.h" using namespace IW5; -namespace -{ - GfxImage* GetMaterialColorMap(const Material* material) - { - std::vector potentialTextureDefs; - - for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) - { - MaterialTextureDef* def = &material->textureTable[textureIndex]; - - if (def->semantic == TS_COLOR_MAP) - potentialTextureDefs.push_back(def); - } - - if (potentialTextureDefs.empty()) - return nullptr; - if (potentialTextureDefs.size() == 1) - return potentialTextureDefs[0]->u.image; - - for (const auto* def : potentialTextureDefs) - { - if (def->nameStart == 'c' && def->nameEnd == 'p') - return def->u.image; - } - - return potentialTextureDefs[0]->u.image; - } - - GfxImage* GetMaterialNormalMap(const Material* material) - { - std::vector potentialTextureDefs; - - for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) - { - MaterialTextureDef* def = &material->textureTable[textureIndex]; - - if (def->semantic == TS_NORMAL_MAP) - potentialTextureDefs.push_back(def); - } - - if (potentialTextureDefs.empty()) - return nullptr; - if (potentialTextureDefs.size() == 1) - return potentialTextureDefs[0]->u.image; - - for (const auto* def : potentialTextureDefs) - { - if (def->nameStart == 'n' && def->nameEnd == 'p') - return def->u.image; - } - - return potentialTextureDefs[0]->u.image; - } - - GfxImage* GetMaterialSpecularMap(const Material* material) - { - std::vector potentialTextureDefs; - - for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) - { - MaterialTextureDef* def = &material->textureTable[textureIndex]; - - if (def->semantic == TS_SPECULAR_MAP) - potentialTextureDefs.push_back(def); - } - - if (potentialTextureDefs.empty()) - return nullptr; - if (potentialTextureDefs.size() == 1) - return potentialTextureDefs[0]->u.image; - - for (const auto* def : potentialTextureDefs) - { - if (def->nameStart == 's' && def->nameEnd == 'p') - return def->u.image; - } - - return potentialTextureDefs[0]->u.image; - } - - void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model) - { - for (auto boneNum = 0u; boneNum < model->numBones; boneNum++) - { - XModelBone bone; - if (model->boneNames[boneNum] < context.m_zone->m_script_strings.Count()) - bone.name = context.m_zone->m_script_strings[model->boneNames[boneNum]]; - else - bone.name = "INVALID_BONE_NAME"; - - if (boneNum >= model->numRootBones) - bone.parentIndex = boneNum - static_cast(model->parentList[boneNum - model->numRootBones]); - else - bone.parentIndex = std::nullopt; - - bone.scale[0] = 1.0f; - bone.scale[1] = 1.0f; - bone.scale[2] = 1.0f; - - bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; - bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; - bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; - bone.globalRotation = { - model->baseMat[boneNum].quat[0], - model->baseMat[boneNum].quat[1], - model->baseMat[boneNum].quat[2], - model->baseMat[boneNum].quat[3], - }; - - if (boneNum < model->numRootBones) - { - bone.localOffset[0] = 0; - bone.localOffset[1] = 0; - bone.localOffset[2] = 0; - bone.localRotation = {0, 0, 0, 1}; - } - else - { - bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0]; - bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1]; - bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2]; - bone.localRotation = { - QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]), - QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]), - QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]), - QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3]), - }; - } - - out.m_bones.emplace_back(std::move(bone)); - } - } - - const char* AssetName(const char* input) - { - if (input && input[0] == ',') - return &input[1]; - - return input; - } - - void AddXModelMaterials(XModelCommon& out, DistinctMapper& materialMapper, const XModel* model) - { - for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++) - { - Material* material = model->materialHandles[surfaceMaterialNum]; - if (materialMapper.Add(material)) - { - XModelMaterial xMaterial; - xMaterial.ApplyDefaults(); - - xMaterial.name = AssetName(material->info.name); - const auto* colorMap = GetMaterialColorMap(material); - if (colorMap) - xMaterial.colorMapName = AssetName(colorMap->name); - - const auto* normalMap = GetMaterialNormalMap(material); - if (normalMap) - xMaterial.normalMapName = AssetName(normalMap->name); - - const auto* specularMap = GetMaterialSpecularMap(material); - if (specularMap) - xMaterial.specularMapName = AssetName(specularMap->name); - - out.m_materials.emplace_back(std::move(xMaterial)); - } - } - } - - void AddXModelObjects(XModelCommon& out, const XModelSurfs* modelSurfs, const DistinctMapper& materialMapper, const int baseSurfaceIndex) - { - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - XModelObject object; - object.name = std::format("surf{}", surfIndex); - object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfaceIndex)); - - out.m_objects.emplace_back(std::move(object)); - } - } - - void AddXModelVertices(XModelCommon& out, 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]; - - XModelVertex vertex{}; - vertex.coordinates[0] = v.xyz[0]; - vertex.coordinates[1] = v.xyz[1]; - vertex.coordinates[2] = v.xyz[2]; - Common::Vec3UnpackUnitVec(v.normal, vertex.normal); - Common::Vec4UnpackGfxColor(v.color, vertex.color); - Common::Vec2UnpackTexCoords(v.texCoord, vertex.uv); - - out.m_vertices.emplace_back(vertex); - } - } - } - - void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection) - { - auto totalWeightCount = 0u; - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - const auto& surface = modelSurfs->surfs[surfIndex]; - - if (surface.vertList) - { - totalWeightCount += surface.vertListCount; - } - - if (surface.vertInfo.vertsBlend) - { - totalWeightCount += surface.vertInfo.vertCount[0] * 1; - totalWeightCount += surface.vertInfo.vertCount[1] * 2; - totalWeightCount += surface.vertInfo.vertCount[2] * 3; - totalWeightCount += surface.vertInfo.vertCount[3] * 4; - } - } - - weightCollection.weights.resize(totalWeightCount); - } - - float BoneWeight16(const uint16_t value) - { - return static_cast(value) / static_cast(std::numeric_limits::max()); - } - - void AddXModelVertexBoneWeights(XModelCommon& out, const XModelSurfs* modelSurfs) - { - auto& weightCollection = out.m_bone_weight_data; - size_t weightOffset = 0u; - - for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++) - { - const auto& surface = modelSurfs->surfs[surfIndex]; - auto handledVertices = 0u; - - if (surface.vertList) - { - for (auto vertListIndex = 0u; vertListIndex < surface.vertListCount; vertListIndex++) - { - const auto& vertList = surface.vertList[vertListIndex]; - const auto boneWeightOffset = weightOffset; - - weightCollection.weights[weightOffset++] = XModelBoneWeight{vertList.boneOffset / sizeof(DObjSkelMat), 1.0f}; - - for (auto vertListVertexOffset = 0u; vertListVertexOffset < vertList.vertCount; vertListVertexOffset++) - { - out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 1); - } - handledVertices += vertList.vertCount; - } - } - - auto vertsBlendOffset = 0u; - if (surface.vertInfo.vertsBlend) - { - // 1 bone weight - for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[0]; vertIndex++) - { - const auto boneWeightOffset = weightOffset; - const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat); - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, 1.0f}; - - vertsBlendOffset += 1; - - out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 1); - } - - // 2 bone weights - for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[1]; vertIndex++) - { - const auto boneWeightOffset = weightOffset; - const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat); - const auto boneIndex1 = surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat); - const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); - const auto boneWeight0 = 1.0f - boneWeight1; - - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0}; - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1}; - - vertsBlendOffset += 3; - - out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 2); - } - - // 3 bone weights - for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[2]; vertIndex++) - { - const auto boneWeightOffset = weightOffset; - const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat); - const auto boneIndex1 = surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat); - const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); - const auto boneIndex2 = surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat); - const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); - const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2; - - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0}; - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1}; - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2}; - - vertsBlendOffset += 5; - - out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 3); - } - - // 4 bone weights - for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[3]; vertIndex++) - { - const auto boneWeightOffset = weightOffset; - const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat); - const auto boneIndex1 = surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat); - const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); - const auto boneIndex2 = surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat); - const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); - const auto boneIndex3 = surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat); - const auto boneWeight3 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 6]); - const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2 - boneWeight3; - - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0}; - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1}; - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2}; - weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex3, boneWeight3}; - - vertsBlendOffset += 7; - - out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 4); - } - - handledVertices += - surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; - } - - for (; handledVertices < surface.vertCount; handledVertices++) - { - out.m_vertex_bone_weights.emplace_back(0, 0); - } - } - } - - void AddXModelFaces(XModelCommon& out, const XModelSurfs* modelSurfs) - { - 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]; - - XModelFace face{}; - face.vertexIndex[0] = tri[0] + surface.baseVertIndex; - face.vertexIndex[1] = tri[1] + surface.baseVertIndex; - face.vertexIndex[2] = tri[2] + surface.baseVertIndex; - object.m_faces.emplace_back(face); - } - } - } - - void PopulateXModelWriter(XModelCommon& out, const AssetDumpingContext& context, const unsigned lod, const XModel* model) - { - const auto* modelSurfs = model->lodInfo[lod].modelSurfs; - - DistinctMapper materialMapper(model->numsurfs); - AllocateXModelBoneWeights(modelSurfs, out.m_bone_weight_data); - - out.m_name = modelSurfs->name; - AddXModelBones(out, context, model); - AddXModelMaterials(out, materialMapper, model); - AddXModelObjects(out, modelSurfs, materialMapper, model->lodInfo[lod].surfIndex); - AddXModelVertices(out, modelSurfs); - AddXModelVertexBoneWeights(out, modelSurfs); - 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(); - const auto* modelSurfs = model->lodInfo[lod].modelSurfs; - const auto assetFile = context.OpenAssetFile(std::format("model_export/{}.XMODEL_EXPORT", modelSurfs->name)); - - if (!assetFile) - return; - - const auto writer = xmodel_export::CreateWriterForVersion6(*assetFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - writer->Write(common); - } - - template - void DumpGltfLod( - const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo* asset, const unsigned lod, const std::string& extension) - { - const auto* model = asset->Asset(); - const auto* modelSurfs = model->lodInfo[lod].modelSurfs; - const auto assetFile = context.OpenAssetFile(std::format("model_export/{}{}", modelSurfs->name, extension)); - - if (!assetFile) - return; - - const auto output = std::make_unique(*assetFile); - const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name); - - writer->Write(common); - } - - void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo* asset) - { - const auto* model = asset->Asset(); - - for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) - { - XModelCommon common; - PopulateXModelWriter(common, context, currentLod, asset->Asset()); - - switch (ObjWriting::Configuration.ModelOutputFormat) - { - case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: - DumpObjLod(common, context, asset, currentLod); - if (currentLod == 0u) - DumpObjMtl(common, context, asset); - break; - - case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: - DumpXModelExportLod(common, context, asset, currentLod); - break; - - case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF: - DumpGltfLod(common, context, asset, currentLod, ".gltf"); - break; - - case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB: - DumpGltfLod(common, context, asset, currentLod, ".glb"); - break; - - default: - assert(false); - break; - } - } - } -} // namespace - bool AssetDumperXModel::ShouldDump(XAssetInfo* asset) { return !asset->m_name.empty() && asset->m_name[0] != ','; @@ -508,5 +11,5 @@ bool AssetDumperXModel::ShouldDump(XAssetInfo* asset) void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { - DumpXModelSurfs(context, asset); + DumpXModel(context, asset); } diff --git a/src/ObjWriting/XModel/XModelDumper.cpp.template b/src/ObjWriting/XModel/XModelDumper.cpp.template index 0a775f19..f3644849 100644 --- a/src/ObjWriting/XModel/XModelDumper.cpp.template +++ b/src/ObjWriting/XModel/XModelDumper.cpp.template @@ -1,4 +1,4 @@ -#options GAME (T5, T6) +#options GAME (IW5, T5, T6) #filename "Game/" + GAME + "/XModel/XModelDumper" + GAME + ".cpp" @@ -6,7 +6,9 @@ #set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\"" #set JSON_HEADER "\"Game/" + GAME + "/XModel/JsonXModel" + GAME + ".h\"" -#if GAME == "T5" +#if GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" #define FEATURE_T5 #elif GAME == "T6" #define FEATURE_T6 @@ -54,8 +56,13 @@ namespace GAME { MaterialTextureDef* def = &material->textureTable[textureIndex]; +#ifdef FEATURE_IW5 + if (def->semantic == TS_COLOR_MAP) + potentialTextureDefs.push_back(def); +#else if (def->semantic == TS_COLOR_MAP || def->semantic >= TS_COLOR0_MAP && def->semantic <= TS_COLOR15_MAP) potentialTextureDefs.push_back(def); +#endif } if (potentialTextureDefs.empty()) @@ -136,15 +143,33 @@ namespace GAME return GetImageFromTextureDef(*potentialTextureDefs[0]); } + bool GetSurfaces(const XModel* model, const unsigned lod, XSurface*& surfs, unsigned& surfCount) + { +#ifdef FEATURE_IW5 + if (!model->lodInfo[lod].modelSurfs || !model->lodInfo[lod].modelSurfs->surfs) + return false; + + surfs = model->lodInfo[lod].modelSurfs->surfs; + surfCount = model->lodInfo[lod].modelSurfs->numsurfs; +#else + if (!model->surfs) + return false; + + surfs = &model->surfs[model->lodInfo[lod].surfIndex]; + surfCount = model->lodInfo[lod].numsurfs; +#endif + + return true; + } + bool HasDefaultArmature(const XModel* model, const unsigned lod) { if (model->numRootBones != 1 || model->numBones != 1) return false; - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - if (!surfs) + XSurface* surfs; + unsigned surfCount; + if (!GetSurfaces(model, lod, surfs, surfCount)) return true; for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) @@ -284,10 +309,9 @@ namespace GAME void AddXModelVertices(XModelCommon& out, const XModel* model, const unsigned lod) { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - if (!surfs) + XSurface* surfs; + unsigned surfCount; + if (!GetSurfaces(model, lod, surfs, surfCount)) return; for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) @@ -313,10 +337,9 @@ namespace GAME void AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection) { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - if (!surfs) + XSurface* surfs; + unsigned surfCount; + if (!GetSurfaces(model, lod, surfs, surfCount)) return; auto totalWeightCount = 0u; @@ -348,13 +371,12 @@ namespace GAME void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod) { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - auto& weightCollection = out.m_bone_weight_data; - - if (!surfs) + XSurface* surfs; + unsigned surfCount; + if (!GetSurfaces(model, lod, surfs, surfCount)) return; + auto& weightCollection = out.m_bone_weight_data; size_t weightOffset = 0u; for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) @@ -467,10 +489,9 @@ namespace GAME void AddXModelFaces(XModelCommon& out, const XModel* model, const unsigned lod) { - const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; - const auto surfCount = model->lodInfo[lod].numsurfs; - - if (!surfs) + XSurface* surfs; + unsigned surfCount; + if (!GetSurfaces(model, lod, surfs, surfCount)) return; for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) @@ -671,8 +692,15 @@ namespace GAME if (xmodel.physPreset && xmodel.physPreset->name) jXModel.physPreset = AssetName(xmodel.physPreset->name); +#ifdef FEATURE_IW5 + if (xmodel.physCollmap && xmodel.physCollmap->name) + jXModel.physCollmap = AssetName(xmodel.physCollmap->name); +#endif + +#if defined(FEATURE_T5) || defined(FEATURE_T6) if (xmodel.physConstraints && xmodel.physConstraints->name) jXModel.physConstraints = AssetName(xmodel.physConstraints->name); +#endif jXModel.flags = xmodel.flags; diff --git a/src/ObjWriting/XModel/XModelDumper.h.template b/src/ObjWriting/XModel/XModelDumper.h.template index 9094c78f..c981ef6b 100644 --- a/src/ObjWriting/XModel/XModelDumper.h.template +++ b/src/ObjWriting/XModel/XModelDumper.h.template @@ -1,4 +1,4 @@ -#options GAME (T5, T6) +#options GAME (IW5, T5, T6) #filename "Game/" + GAME + "/XModel/XModelDumper" + GAME + ".h" diff --git a/src/ZoneCode/Game/IW5/XAssets/XModel.txt b/src/ZoneCode/Game/IW5/XAssets/XModel.txt index 43670572..72a48947 100644 --- a/src/ZoneCode/Game/IW5/XAssets/XModel.txt +++ b/src/ZoneCode/Game/IW5/XAssets/XModel.txt @@ -13,7 +13,7 @@ set count parentList numBones - numRootBones; set reusable quats; set count quats numBones - numRootBones; set reusable trans; -set count trans numBones - numRootBones; +set count trans (numBones - numRootBones) * 3; set reusable partClassification; set count partClassification numBones; set reusable baseMat; diff --git a/src/ZoneCode/Game/IW5/XAssets/XModelSurfs.txt b/src/ZoneCode/Game/IW5/XAssets/XModelSurfs.txt index dd41e7c3..1e939bbf 100644 --- a/src/ZoneCode/Game/IW5/XAssets/XModelSurfs.txt +++ b/src/ZoneCode/Game/IW5/XAssets/XModelSurfs.txt @@ -14,6 +14,9 @@ set count vertList vertListCount; set reusable triIndices; set block triIndices XFILE_BLOCK_INDEX; set count triIndices triCount; +set reusable verts0; +set block verts0 XFILE_BLOCK_VERTEX; +set count verts0 XSurface::vertCount; reorder: zoneHandle vertInfo @@ -29,15 +32,6 @@ set count vertsBlend vertCount[0] + 5 * vertCount[2] + 7 * vertCount[3]; -// GfxVertexUnion0 -use GfxVertexUnion0; -set condition quantizedNoColorVerts0 never; -set condition quantizedVerts0 never; -set condition verts0 never; -set reusable packedVerts0; -set block packedVerts0 XFILE_BLOCK_VERTEX; -set count packedVerts0 XSurface::vertCount; - // XRigidVertList set reusable XRigidVertList::collisionTree;