diff --git a/src/Common/Game/IW3/CommonIW3.cpp b/src/Common/Game/IW3/CommonIW3.cpp index 9df6bd5a..cea4d616 100644 --- a/src/Common/Game/IW3/CommonIW3.cpp +++ b/src/Common/Game/IW3/CommonIW3.cpp @@ -21,12 +21,12 @@ GfxColor Common::Vec4PackGfxColor(const vec4_t* in) void Common::Vec2UnpackTexCoords(const PackedTexCoords& in, vec2_t* out) { - Pack32::Vec2UnpackTexCoords(in.packed, reinterpret_cast(out)); + Pack32::Vec2UnpackTexCoordsVU(in.packed, reinterpret_cast(out)); } void Common::Vec3UnpackUnitVec(const PackedUnitVec& in, vec3_t* out) { - Pack32::Vec3UnpackUnitVec(in.packed, reinterpret_cast(out)); + Pack32::Vec3UnpackUnitVecScaleBased(in.packed, reinterpret_cast(out)); } void Common::Vec4UnpackGfxColor(const GfxColor& in, vec4_t* out) diff --git a/src/Common/Game/IW4/CommonIW4.cpp b/src/Common/Game/IW4/CommonIW4.cpp index c9fc6bd4..9c010880 100644 --- a/src/Common/Game/IW4/CommonIW4.cpp +++ b/src/Common/Game/IW4/CommonIW4.cpp @@ -21,12 +21,12 @@ GfxColor Common::Vec4PackGfxColor(const vec4_t* in) void Common::Vec2UnpackTexCoords(const PackedTexCoords& in, vec2_t* out) { - Pack32::Vec2UnpackTexCoords(in.packed, reinterpret_cast(out)); + Pack32::Vec2UnpackTexCoordsVU(in.packed, reinterpret_cast(out)); } void Common::Vec3UnpackUnitVec(const PackedUnitVec& in, vec3_t* out) { - Pack32::Vec3UnpackUnitVec(in.packed, reinterpret_cast(out)); + Pack32::Vec3UnpackUnitVecScaleBased(in.packed, reinterpret_cast(out)); } void Common::Vec4UnpackGfxColor(const GfxColor& in, vec4_t* out) diff --git a/src/Common/Game/IW5/CommonIW5.cpp b/src/Common/Game/IW5/CommonIW5.cpp index 00965d1d..569399aa 100644 --- a/src/Common/Game/IW5/CommonIW5.cpp +++ b/src/Common/Game/IW5/CommonIW5.cpp @@ -21,12 +21,12 @@ GfxColor Common::Vec4PackGfxColor(const vec4_t* in) void Common::Vec2UnpackTexCoords(const PackedTexCoords& in, vec2_t* out) { - Pack32::Vec2UnpackTexCoords(in.packed, reinterpret_cast(out)); + Pack32::Vec2UnpackTexCoordsVU(in.packed, reinterpret_cast(out)); } void Common::Vec3UnpackUnitVec(const PackedUnitVec& in, vec3_t* out) { - Pack32::Vec3UnpackUnitVec(in.packed, reinterpret_cast(out)); + Pack32::Vec3UnpackUnitVecScaleBased(in.packed, reinterpret_cast(out)); } void Common::Vec4UnpackGfxColor(const GfxColor& in, vec4_t* out) diff --git a/src/Common/Game/T5/CommonT5.cpp b/src/Common/Game/T5/CommonT5.cpp index c9e7c1a6..48e76a1b 100644 --- a/src/Common/Game/T5/CommonT5.cpp +++ b/src/Common/Game/T5/CommonT5.cpp @@ -75,12 +75,12 @@ GfxColor Common::Vec4PackGfxColor(const vec4_t* in) void Common::Vec2UnpackTexCoords(const PackedTexCoords& in, vec2_t* out) { - Pack32::Vec2UnpackTexCoords(in.packed, reinterpret_cast(out)); + Pack32::Vec2UnpackTexCoordsVU(in.packed, reinterpret_cast(out)); } void Common::Vec3UnpackUnitVec(const PackedUnitVec& in, vec3_t* out) { - Pack32::Vec3UnpackUnitVec(in.packed, reinterpret_cast(out)); + Pack32::Vec3UnpackUnitVecScaleBased(in.packed, reinterpret_cast(out)); } void Common::Vec4UnpackGfxColor(const GfxColor& in, vec4_t* out) diff --git a/src/Common/Game/T6/CommonT6.cpp b/src/Common/Game/T6/CommonT6.cpp index 87270121..3d181616 100644 --- a/src/Common/Game/T6/CommonT6.cpp +++ b/src/Common/Game/T6/CommonT6.cpp @@ -2,7 +2,11 @@ #include -int CommonT6::Com_HashKey(const char* str, const int maxLen) +#include "Utils/Pack.h" + +using namespace T6; + +int Common::Com_HashKey(const char* str, const int maxLen) { if (str == nullptr) return 0; @@ -19,7 +23,7 @@ int CommonT6::Com_HashKey(const char* str, const int maxLen) return hash ^ ((hash ^ (hash >> 10)) >> 10); } -int CommonT6::Com_HashString(const char* str) +int Common::Com_HashString(const char* str) { if (!str) return 0; @@ -35,7 +39,7 @@ int CommonT6::Com_HashString(const char* str) return result; } -int CommonT6::Com_HashString(const char* str, const int len) +int Common::Com_HashString(const char* str, const int len) { if (!str) return 0; @@ -52,4 +56,34 @@ int CommonT6::Com_HashString(const char* str, const int len) } return result; +} + +PackedTexCoords Common::Vec2PackTexCoords(const vec2_t* in) +{ + return PackedTexCoords{ Pack32::Vec2PackTexCoords(in->v) }; +} + +PackedUnitVec Common::Vec3PackUnitVec(const vec3_t* in) +{ + return PackedUnitVec{ Pack32::Vec3PackUnitVec(in->v) }; +} + +GfxColor Common::Vec4PackGfxColor(const vec4_t* in) +{ + return GfxColor{ Pack32::Vec4PackGfxColor(in->v) }; +} + +void Common::Vec2UnpackTexCoords(const PackedTexCoords& in, vec2_t* out) +{ + Pack32::Vec2UnpackTexCoordsUV(in.packed, out->v); +} + +void Common::Vec3UnpackUnitVec(const PackedUnitVec& in, vec3_t* out) +{ + Pack32::Vec3UnpackUnitVecThirdBased(in.packed, out->v); +} + +void Common::Vec4UnpackGfxColor(const GfxColor& in, vec4_t* out) +{ + Pack32::Vec4UnpackGfxColor(in.packed, out->v); } \ No newline at end of file diff --git a/src/Common/Game/T6/CommonT6.h b/src/Common/Game/T6/CommonT6.h index 5c5badd3..ad8f38c0 100644 --- a/src/Common/Game/T6/CommonT6.h +++ b/src/Common/Game/T6/CommonT6.h @@ -1,9 +1,21 @@ #pragma once -class CommonT6 +#include "T6.h" + +namespace T6 { -public: - static int Com_HashKey(const char* str, int maxLen); - static int Com_HashString(const char* str); - static int Com_HashString(const char* str, int len); -}; \ No newline at end of file + class Common + { + public: + static int Com_HashKey(const char* str, int maxLen); + static int Com_HashString(const char* str); + static int Com_HashString(const char* str, int len); + + static PackedTexCoords Vec2PackTexCoords(const vec2_t* in); + static PackedUnitVec Vec3PackUnitVec(const vec3_t* in); + static GfxColor Vec4PackGfxColor(const vec4_t* in); + static void Vec2UnpackTexCoords(const PackedTexCoords& in, vec2_t* out); + static void Vec3UnpackUnitVec(const PackedUnitVec& in, vec3_t* out); + static void Vec4UnpackGfxColor(const GfxColor& in, vec4_t* out); + }; +} \ No newline at end of file diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 9d9ab2d8..374463a6 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -375,14 +375,16 @@ namespace T6 void* data; }; - - struct XModelPieces + union vec2_t { - const char* name; - int numpieces; - XModelPiece* pieces; - }; + float v[2]; + struct + { + float x; + float y; + }; + }; union vec3_t { @@ -396,6 +398,34 @@ namespace T6 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; + }; + }; + + struct XModelPieces + { + const char* name; + int numpieces; + XModelPiece* pieces; + }; + struct PhysPresetInfo { float mass; @@ -555,6 +585,11 @@ namespace T6 XAnimDeltaPart* deltaPart; }; + struct DObjSkelMat + { + vec4_t axis[3]; + vec4_t origin; + }; struct XModelLodInfo { @@ -573,8 +608,8 @@ namespace T6 unsigned char numsurfs; char lodRampType; uint16_t* boneNames; - char* parentList; - int16_t (*quats)[4]; + unsigned char* parentList; + uint16_t (*quats)[4]; float (*trans)[4]; char* partClassification; DObjAnimMat* baseMat; @@ -588,14 +623,14 @@ namespace T6 float radius; vec3_t mins; vec3_t maxs; - int16_t numLods; - int16_t collLod; + uint16_t numLods; + uint16_t collLod; float* himipInvSqRadii; int memUsage; int flags; bool bad; PhysPreset* physPreset; - char numCollmaps; + unsigned char numCollmaps; Collmap* collmaps; PhysConstraints* physConstraints; vec3_t lightingOriginOffset; @@ -647,9 +682,9 @@ namespace T6 { MaterialInfo info; char stateBitsEntry[36]; - char textureCount; - char constantCount; - char stateBitsCount; + unsigned char textureCount; + unsigned char constantCount; + unsigned char stateBitsCount; char stateFlags; char cameraRegion; char probeMipBits; @@ -746,6 +781,50 @@ namespace T6 uint32_t valid : 1; }; + enum TextureSemantic + { + TS_2D = 0x0, + TS_FUNCTION = 0x1, + TS_COLOR_MAP = 0x2, + TS_UNUSED_1 = 0x3, + TS_UNUSED_2 = 0x4, + TS_NORMAL_MAP = 0x5, + TS_UNUSED_3 = 0x6, + TS_UNUSED_4 = 0x7, + TS_SPECULAR_MAP = 0x8, + TS_UNUSED_5 = 0x9, + TS_OCCLUSION_MAP = 0xA, + TS_UNUSED_6 = 0xB, + TS_COLOR0_MAP = 0xC, + TS_COLOR1_MAP = 0xD, + TS_COLOR2_MAP = 0xE, + TS_COLOR3_MAP = 0xF, + TS_COLOR4_MAP = 0x10, + TS_COLOR5_MAP = 0x11, + TS_COLOR6_MAP = 0x12, + TS_COLOR7_MAP = 0x13, + TS_COLOR8_MAP = 0x14, + TS_COLOR9_MAP = 0x15, + TS_COLOR10_MAP = 0x16, + TS_COLOR11_MAP = 0x17, + TS_COLOR12_MAP = 0x18, + TS_COLOR13_MAP = 0x19, + TS_COLOR14_MAP = 0x1A, + TS_COLOR15_MAP = 0x1B, + TS_THROW_MAP = 0x1C, + }; + + enum ImageCategory + { + IMG_CATEGORY_UNKNOWN = 0x0, + IMG_CATEGORY_AUTO_GENERATED = 0x1, + IMG_CATEGORY_LIGHTMAP = 0x2, + IMG_CATEGORY_LOAD_FROM_FILE = 0x3, + IMG_CATEGORY_RAW = 0x4, + IMG_CATEGORY_FIRST_UNMANAGED = 0x5, + IMG_CATEGORY_RENDERTARGET = 0x5, + IMG_CATEGORY_TEMP = 0x6, + }; struct GfxImage { @@ -1027,29 +1106,6 @@ namespace T6 int* leafRefs; }; - - union vec4_t - { - float v[4]; - - struct - { - float x; - float y; - float z; - float w; - }; - - struct - { - float r; - float g; - float b; - float a; - }; - }; - - struct GfxWorldSun { unsigned int control; @@ -2025,19 +2081,6 @@ namespace T6 float vertResistDown; }; - - union vec2_t - { - float v[2]; - - struct - { - float x; - float y; - }; - }; - - enum TractionType { TRACTION_TYPE_FRONT = 0x0, diff --git a/src/Common/Utils/Pack.cpp b/src/Common/Utils/Pack.cpp index 5681e963..42f61ca3 100644 --- a/src/Common/Utils/Pack.cpp +++ b/src/Common/Utils/Pack.cpp @@ -34,10 +34,17 @@ uint32_t Pack32::Vec4PackGfxColor(const float* in) | static_cast(std::clamp(in[3], 0.0f, 1.0f) * 255.0f) << 24; } -void Pack32::Vec2UnpackTexCoords(const uint32_t in, float* out) +void Pack32::Vec2UnpackTexCoordsUV(const uint32_t in, float* out) { - PackUtil32 packTemp{}; + const auto inHiDw = static_cast((in >> 16) & UINT16_MAX); + const auto inLoDw = static_cast(in & UINT16_MAX); + out[0] = HalfFloat::ToFloat(inLoDw); + out[1] = HalfFloat::ToFloat(inHiDw); +} + +void Pack32::Vec2UnpackTexCoordsVU(const uint32_t in, float* out) +{ const auto inHiDw = static_cast((in >> 16) & UINT16_MAX); const auto inLoDw = static_cast(in & UINT16_MAX); @@ -45,7 +52,7 @@ void Pack32::Vec2UnpackTexCoords(const uint32_t in, float* out) out[1] = HalfFloat::ToFloat(inLoDw); } -void Pack32::Vec3UnpackUnitVec(const uint32_t in, float* out) +void Pack32::Vec3UnpackUnitVecScaleBased(const uint32_t in, float* out) { assert(out != nullptr); @@ -56,6 +63,20 @@ void Pack32::Vec3UnpackUnitVec(const uint32_t in, float* out) out[2] = (static_cast(_in.uc[2]) + -127.0f) * decodeScale; } +void Pack32::Vec3UnpackUnitVecThirdBased(const uint32_t in, float* out) +{ + PackUtil32 v0{ (in >> 0) & 0x3FF }; + PackUtil32 v1{ (in >> 10) & 0x3FF }; + PackUtil32 v2{ (in >> 20) & 0x3FF }; + + v0.u = v0.u - 2 * (v0.u & 0x200) + 0x40400000; + v1.u = v1.u - 2 * (v1.u & 0x200) + 0x40400000; + v2.u = v2.u - 2 * (v2.u & 0x200) + 0x40400000; + out[0] = (v0.f - 3.0f) * 8208.0312f; + out[1] = (v1.f - 3.0f) * 8208.0312f; + out[2] = (v2.f - 3.0f) * 8208.0312f; +} + void Pack32::Vec4UnpackGfxColor(uint32_t in, float* out) { out[0] = static_cast(in & UINT8_MAX) / 255.0f; diff --git a/src/Common/Utils/Pack.h b/src/Common/Utils/Pack.h index 7745818c..7dc1fdcb 100644 --- a/src/Common/Utils/Pack.h +++ b/src/Common/Utils/Pack.h @@ -10,7 +10,9 @@ public: static uint32_t Vec2PackTexCoords(const float* in); static uint32_t Vec3PackUnitVec(const float* in); static uint32_t Vec4PackGfxColor(const float* in); - static void Vec2UnpackTexCoords(uint32_t in, float* out); - static void Vec3UnpackUnitVec(uint32_t in, float* out); + static void Vec2UnpackTexCoordsUV(uint32_t in, float* out); + static void Vec2UnpackTexCoordsVU(uint32_t in, float* out); + static void Vec3UnpackUnitVecScaleBased(uint32_t in, float* out); + static void Vec3UnpackUnitVecThirdBased(uint32_t in, float* out); static void Vec4UnpackGfxColor(uint32_t in, float* out); }; \ No newline at end of file diff --git a/src/Linker/Game/T6/ZoneCreatorT6.cpp b/src/Linker/Game/T6/ZoneCreatorT6.cpp index b45eadbe..c65d1bb2 100644 --- a/src/Linker/Game/T6/ZoneCreatorT6.cpp +++ b/src/Linker/Game/T6/ZoneCreatorT6.cpp @@ -84,13 +84,13 @@ void ZoneCreator::HandleMetadata(Zone* zone, ZoneCreationContext& context) const } else { - keyHash = CommonT6::Com_HashKey(strValue.c_str(), 64); + keyHash = Common::Com_HashKey(strValue.c_str(), 64); } KeyValuePair kvp { keyHash, - CommonT6::Com_HashKey(zone->m_name.c_str(), 64), + Common::Com_HashKey(zone->m_name.c_str(), 64), zone->GetMemory()->Dup(metaData->m_value.c_str()) }; kvpList.push_back(kvp); diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderFontIcon.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderFontIcon.cpp index 57dad330..ae0682fa 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderFontIcon.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderFontIcon.cpp @@ -84,7 +84,7 @@ bool AssetLoaderFontIcon::ParseHashStr(int& value, const std::string& str) } else { - value = CommonT6::Com_HashString(str.c_str()); + value = Common::Com_HashString(str.c_str()); } return true; @@ -121,7 +121,7 @@ bool AssetLoaderFontIcon::ReadIconRow(const std::vector& row, FontI icon.fontIconMaterialHandle = static_cast(materialDependency->m_ptr); icon.fontIconName.string = memory->Dup(row[ROW_ICON_NAME].c_str()); - icon.fontIconName.hash = CommonT6::Com_HashString(icon.fontIconName.string); + icon.fontIconName.hash = Common::Com_HashString(icon.fontIconName.string); return true; } diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderStringTable.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderStringTable.cpp index 5ee2d766..d8f17744 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderStringTable.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderStringTable.cpp @@ -66,7 +66,7 @@ bool AssetLoaderStringTable::LoadFromRaw(const std::string& assetName, ISearchPa else cell.string = memory->Dup(rowValues[col].c_str()); - cell.hash = CommonT6::Com_HashString(cell.string); + cell.hash = Common::Com_HashString(cell.string); } } diff --git a/src/ObjLoading/Game/T6/InfoString/InfoStringToStructConverter.cpp b/src/ObjLoading/Game/T6/InfoString/InfoStringToStructConverter.cpp index c296cdaf..8acf6f11 100644 --- a/src/ObjLoading/Game/T6/InfoString/InfoStringToStructConverter.cpp +++ b/src/ObjLoading/Game/T6/InfoString/InfoStringToStructConverter.cpp @@ -25,7 +25,7 @@ bool InfoStringToStructConverter::GetHashValue(const std::string& value, unsigne return endPtr == &value[value.size()]; } - hash = CommonT6::Com_HashString(value.c_str()); + hash = Common::Com_HashString(value.c_str()); return true; } diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 38673a97..3ede1764 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -30,8 +30,8 @@ namespace T6 { - const int ObjLoader::IPAK_READ_HASH = CommonT6::Com_HashKey("ipak_read", 64); - const int ObjLoader::GLOBAL_HASH = CommonT6::Com_HashKey("GLOBAL", 64); + const int ObjLoader::IPAK_READ_HASH = Common::Com_HashKey("ipak_read", 64); + const int ObjLoader::GLOBAL_HASH = Common::Com_HashKey("GLOBAL", 64); ObjLoader::ObjLoader() { @@ -292,7 +292,7 @@ namespace T6 void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const { auto* assetPoolT6 = dynamic_cast(zone->m_pools.get()); - const auto zoneNameHash = CommonT6::Com_HashKey(zone->m_name.c_str(), 64); + const auto zoneNameHash = Common::Com_HashKey(zone->m_name.c_str(), 64); LoadCommonIPaks(searchPath, zone); diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp index e0750d74..cbb02436 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperFontIcon.cpp @@ -18,7 +18,7 @@ class AssetDumperFontIconInternal explicit KnownAlias(std::string aliasName) : m_name(std::move(aliasName)) { - m_hash = CommonT6::Com_HashString(m_name.c_str(), 0); + m_hash = Common::Com_HashString(m_name.c_str(), 0); } }; diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp new file mode 100644 index 00000000..43b9414f --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.cpp @@ -0,0 +1,642 @@ +#include "AssetDumperXModel.h" + +#include +#include + +#include "ObjWriting.h" +#include "Game/T6/CommonT6.h" +#include "Math/Quaternion.h" +#include "Model/XModel/XModelExportWriter.h" +#include "Utils/HalfFloat.h" +#include "Utils/QuatInt16.h" + +using namespace T6; + +bool AssetDumperXModel::ShouldDump(XAssetInfo* asset) +{ + return !asset->m_name.empty() && asset->m_name[0] != ','; +} + +GfxImage* AssetDumperXModel::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 || def->semantic >= TS_COLOR0_MAP && def->semantic <= TS_COLOR15_MAP) + potentialTextureDefs.push_back(def); + } + + if (potentialTextureDefs.empty()) + return nullptr; + if (potentialTextureDefs.size() == 1) + return potentialTextureDefs[0]->image; + + for(const auto* def : potentialTextureDefs) + { + if (def->nameStart == 'c' && def->nameEnd == 'p') + return def->image; + } + + return potentialTextureDefs[0]->image; +} + +GfxImage* AssetDumperXModel::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]->image; + + for (const auto* def : potentialTextureDefs) + { + if (def->nameStart == 'n' && def->nameEnd == 'p') + return def->image; + } + + return potentialTextureDefs[0]->image; +} + +GfxImage* AssetDumperXModel::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]->image; + + for (const auto* def : potentialTextureDefs) + { + if (def->nameStart == 's' && def->nameEnd == 'p') + return def->image; + } + + return potentialTextureDefs[0]->image; +} + +void AssetDumperXModel::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 AssetDumperXModel::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 = "surf" + std::to_string(surfIndex); + object.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfIndex)); + + writer.AddObject(std::move(object)); + } +} + +void AssetDumperXModel::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 AssetDumperXModel::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 AssetDumperXModel::DumpObjMat(const AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto* model = asset->Asset(); + const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl"); + + 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 AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo* asset, const unsigned lod) +{ + const auto* model = asset->Asset(); + std::ostringstream ss; + ss << "model_export/" << model->name << "_lod" << lod << ".OBJ"; + + const auto assetFile = context.OpenAssetFile(ss.str()); + + 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::string(model->name) + ".mtl"); +} + +void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto* model = asset->Asset(); + + DumpObjMat(context, asset); + for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) + { + DumpObjLod(context, asset, currentLod); + } +} + +void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model) +{ + 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 = -1; + else + bone.parentIndex = static_cast(boneNum - static_cast(model->parentList[boneNum - model->numRootBones])); + + bone.scale[0] = 1.0f; + bone.scale[1] = 1.0f; + bone.scale[2] = 1.0f; + + bone.globalOffset[0] = model->baseMat[boneNum].trans.x; + bone.globalOffset[1] = model->baseMat[boneNum].trans.y; + bone.globalOffset[2] = model->baseMat[boneNum].trans.z; + bone.globalRotation = Quaternion32(model->baseMat[boneNum].quat.x, model->baseMat[boneNum].quat.y, model->baseMat[boneNum].quat.z, model->baseMat[boneNum].quat.w); + + if (boneNum < model->numRootBones) + { + bone.localOffset[0] = 0; + bone.localOffset[1] = 0; + bone.localOffset[2] = 0; + bone.localRotation = Quaternion32(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 = Quaternion32( + 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]) + ); + } + + writer.AddBone(std::move(bone)); + } +} + +void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, 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 = material->info.name; + const auto* colorMap = GetMaterialColorMap(material); + if (colorMap) + xMaterial.colorMapName = std::string(colorMap->name); + + writer.AddMaterial(std::move(xMaterial)); + } + } +} + +void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) +{ + const auto surfCount = model->lodInfo[lod].numsurfs; + + for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) + { + XModelObject object; + object.name = "surf" + std::to_string(surfIndex); + + writer.AddObject(std::move(object)); + } +} + +void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, const unsigned lod) +{ + const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; + const auto surfCount = model->lodInfo[lod].numsurfs; + + 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{}; + vec4_t color{}; + + Common::Vec2UnpackTexCoords(v.texCoord, &uv); + Common::Vec3UnpackUnitVec(v.normal, &normalVec); + Common::Vec4UnpackGfxColor(v.color, &color); + + XModelVertex vertex{}; + vertex.coordinates[0] = v.xyz.x; + vertex.coordinates[1] = v.xyz.y; + vertex.coordinates[2] = v.xyz.z; + vertex.normal[0] = normalVec.x; + vertex.normal[1] = normalVec.y; + vertex.normal[2] = normalVec.z; + vertex.color[0] = color.x; + vertex.color[1] = color.y; + vertex.color[2] = color.z; + vertex.color[3] = color.w; + vertex.uv[0] = uv.x; + vertex.uv[1] = uv.y; + + writer.AddVertex(vertex); + } + } +} + +void AssetDumperXModel::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; + + weightCollection.totalWeightCount = 0u; + for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) + { + const auto& surface = surfs[surfIndex]; + + if (surface.vertList) + { + weightCollection.totalWeightCount += surface.vertListCount; + } + + if (surface.vertInfo.vertsBlend) + { + weightCollection.totalWeightCount += surface.vertInfo.vertCount[0] * 1; + weightCollection.totalWeightCount += surface.vertInfo.vertCount[1] * 2; + weightCollection.totalWeightCount += surface.vertInfo.vertCount[2] * 3; + weightCollection.totalWeightCount += surface.vertInfo.vertCount[3] * 4; + } + } + + weightCollection.weights = std::make_unique(weightCollection.totalWeightCount); +} + +void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection) +{ + const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; + const auto surfCount = model->lodInfo[lod].numsurfs; + + size_t weightOffset = 0u; + + for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++) + { + const auto& surface = 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 = &weightCollection.weights[weightOffset]; + + weightCollection.weights[weightOffset++] = XModelBoneWeight{ + static_cast(vertList.boneOffset / sizeof(DObjSkelMat)), + 1.0f + }; + + for (auto vertListVertexOffset = 0u; vertListVertexOffset < vertList.vertCount; vertListVertexOffset++) + { + writer.AddVertexBoneWeights(XModelVertexBoneWeights{ + 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 = &weightCollection.weights[weightOffset]; + const auto boneIndex0 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); + weightCollection.weights[weightOffset++] = XModelBoneWeight{ + boneIndex0, + 1.0f + }; + + vertsBlendOffset += 1; + + writer.AddVertexBoneWeights(XModelVertexBoneWeights{ + boneWeightOffset, + 1 + }); + } + + // 2 bone weights + for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[1]; vertIndex++) + { + const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; + const auto boneIndex0 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); + const auto boneIndex1 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); + const auto boneWeight1 = HalfFloat::ToFloat(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; + + writer.AddVertexBoneWeights(XModelVertexBoneWeights{ + boneWeightOffset, + 2 + }); + } + + // 3 bone weights + for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[2]; vertIndex++) + { + const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; + const auto boneIndex0 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); + const auto boneIndex1 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); + const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); + const auto boneIndex2 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); + const auto boneWeight2 = HalfFloat::ToFloat(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; + + writer.AddVertexBoneWeights(XModelVertexBoneWeights{ + boneWeightOffset, + 3 + }); + } + + // 4 bone weights + for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[3]; vertIndex++) + { + const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; + const auto boneIndex0 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); + const auto boneIndex1 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); + const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); + const auto boneIndex2 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); + const auto boneWeight2 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); + const auto boneIndex3 = static_cast(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat)); + const auto boneWeight3 = HalfFloat::ToFloat(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; + + writer.AddVertexBoneWeights(XModelVertexBoneWeights{ + boneWeightOffset, + 4 + }); + } + + handledVertices += surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3]; + } + + for (; handledVertices < surface.vertCount; handledVertices++) + { + writer.AddVertexBoneWeights(XModelVertexBoneWeights{ + nullptr, + 0 + }); + } + } +} + +void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper& materialMapper, const XModel* model, const unsigned lod) +{ + const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; + const auto surfCount = model->lodInfo[lod].numsurfs; + const auto baseSurfIndex = model->lodInfo[lod].surfIndex; + + 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]; + + XModelFace face{}; + 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); + face.materialIndex = static_cast(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfIndex)); + writer.AddFace(face); + } + } +} + +void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo* asset, const unsigned lod) +{ + const auto* model = asset->Asset(); + + std::ostringstream ss; + ss << "model_export/" << model->name << "_lod" << lod << ".XMODEL_EXPORT"; + + const auto assetFile = context.OpenAssetFile(ss.str()); + + if (!assetFile) + return; + + const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name); + DistinctMapper materialMapper(model->numsurfs); + XModelVertexBoneWeightCollection boneWeightCollection; + AllocateXModelBoneWeights(model, lod, boneWeightCollection); + + AddXModelBones(context, *writer, model); + AddXModelMaterials(*writer, materialMapper, model); + AddXModelObjects(*writer, model, lod); + AddXModelVertices(*writer, model, lod); + AddXModelVertexBoneWeights(*writer, model, lod, boneWeightCollection); + AddXModelFaces(*writer, materialMapper, model, lod); + + writer->Write(*assetFile); +} + +void AssetDumperXModel::DumpXModelExport(const AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto* model = asset->Asset(); + for (auto currentLod = 0u; currentLod < model->numLods; currentLod++) + { + DumpXModelExportLod(context, asset, currentLod); + } +} + +void AssetDumperXModel::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + switch (ObjWriting::Configuration.ModelOutputFormat) + { + case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ: + DumpObj(context, asset); + break; + + case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT: + DumpXModelExport(context, asset); + break; + + default: + assert(false); + break; + } +} diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.h b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.h new file mode 100644 index 00000000..1cb67379 --- /dev/null +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperXModel.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" +#include "Utils/DistinctMapper.h" +#include "Model/XModel/AbstractXModelWriter.h" +#include "Model/Obj/ObjWriter.h" + +namespace T6 +{ + class AssetDumperXModel final : public AbstractAssetDumper + { + static GfxImage* GetMaterialColorMap(const Material* material); + static GfxImage* GetMaterialNormalMap(const Material* material); + static GfxImage* GetMaterialSpecularMap(const Material* material); + + static void AddObjMaterials(ObjWriter& writer, DistinctMapper& materialMapper, const XModel* model); + static void AddObjObjects(ObjWriter& writer, const DistinctMapper& materialMapper, const XModel* model, unsigned lod); + static void AddObjVertices(ObjWriter& writer, const XModel* model, unsigned lod); + static void AddObjFaces(ObjWriter& writer, const XModel* model, unsigned lod); + static void DumpObjLod(AssetDumpingContext& context, XAssetInfo* asset, unsigned lod); + static void DumpObjMat(const AssetDumpingContext& context, XAssetInfo* asset); + static void DumpObj(AssetDumpingContext& context, XAssetInfo* asset); + + static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model); + static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper& materialMapper, const XModel* model); + static void AddXModelObjects(AbstractXModelWriter& writer, const XModel* model, unsigned lod); + static void AddXModelVertices(AbstractXModelWriter& writer, const XModel* model, unsigned lod); + static void AllocateXModelBoneWeights(const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection); + static void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModel* model, unsigned lod, XModelVertexBoneWeightCollection& weightCollection); + static void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper& materialMapper, const XModel* model, unsigned lod); + static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo* asset, unsigned lod); + static void DumpXModelExport(const AssetDumpingContext& context, XAssetInfo* asset); + + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} diff --git a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp index e8f7e229..98d451e4 100644 --- a/src/ObjWriting/Game/T6/ZoneDumperT6.cpp +++ b/src/ObjWriting/Game/T6/ZoneDumperT6.cpp @@ -19,6 +19,7 @@ #include "AssetDumpers/AssetDumperWeapon.h" #include "AssetDumpers/AssetDumperWeaponAttachment.h" #include "AssetDumpers/AssetDumperWeaponAttachmentUnique.h" +#include "AssetDumpers/AssetDumperXModel.h" #include "AssetDumpers/AssetDumperZBarrier.h" using namespace T6; @@ -43,7 +44,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const DUMP_ASSET_POOL(AssetDumperPhysConstraints, m_phys_constraints); // DUMP_ASSET_POOL(AssetDumperDestructibleDef, m_destructible_def); // DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts); - // DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel); + DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel); // DUMP_ASSET_POOL(AssetDumperMaterial, m_material); // DUMP_ASSET_POOL(AssetDumperTechniqueSet, m_technique_set); DUMP_ASSET_POOL(AssetDumperGfxImage, m_image); diff --git a/src/Unlinker/Game/T6/ZoneDefWriterT6.cpp b/src/Unlinker/Game/T6/ZoneDefWriterT6.cpp index 0584cfbb..8f0ff78c 100644 --- a/src/Unlinker/Game/T6/ZoneDefWriterT6.cpp +++ b/src/Unlinker/Game/T6/ZoneDefWriterT6.cpp @@ -20,7 +20,7 @@ namespace T6 explicit KeyValuePairKnownKey(std::string key) { m_key = std::move(key); - m_hash = CommonT6::Com_HashKey(m_key.c_str(), 64); + m_hash = Common::Com_HashKey(m_key.c_str(), 64); } };