Cleanup & store extra part bit in msurf instead of lodinfo

This commit is contained in:
Louvenarde 2024-01-28 16:26:24 +01:00
parent adddbd5ecc
commit 4a61617e88
7 changed files with 164 additions and 215 deletions

View File

@ -173,7 +173,7 @@ namespace Components
Register(new Threading()); Register(new Threading());
Register(new Toast()); Register(new Toast());
Register(new UIFeeder()); Register(new UIFeeder());
//Register(new Updater()); Register(new Updater());
Register(new VisionFile()); Register(new VisionFile());
Register(new Voice()); Register(new Voice());
Register(new Vote()); Register(new Vote());

View File

@ -221,7 +221,7 @@ namespace Components
retn retn
} }
} }
#pragma optimize( "", off )
void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name) void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name)
{ {
#ifdef DEBUG #ifdef DEBUG
@ -235,63 +235,6 @@ namespace Components
} }
} }
#endif #endif
if (type == Game::XAssetType::ASSET_TYPE_XANIMPARTS)
{
auto anim = asset.parts;
if (anim->name == "unarmed_cowerstand_idle"s || anim->name == "civilian_walk_cool"s || anim->name == "civilian_run_upright"s)
{
auto str = Game::SL_FindString("j_spinelower");
int interestingPart = 0;
{
if (anim->names[i] == str)
{
interestingPart = i;
}
}
// Something interesting to do there
}
}
if (type == Game::XAssetType::ASSET_TYPE_XMODEL)
//if (name == "body_urban_civ_female_a"s || name == "mp_body_opforce_arab_assault_a"s)
{
if (name == "body_urban_civ_male_aa"s)
{
printf("");
}
const auto model = asset.model;
int total =
model->noScalePartBits[0] |
model->noScalePartBits[1] |
model->noScalePartBits[2] |
model->noScalePartBits[3] |
model->noScalePartBits[4] |
model->noScalePartBits[5];
if (total != 0)
{
printf("");
}
if (!model->quats || !model->trans || model->numBones < 10)
{
// Unlikely candidate
return;
}
static Utils::Memory::Allocator allocator{};
//
//if (name == "body_urban_civ_female_a"s)
{
Assets::IXModel::ConvertPlayerModelFromSingleplayerToMultiplayer(model, allocator);
printf("");
}
}
if (type == Game::ASSET_TYPE_MATERIAL && (name == "gfx_distortion_knife_trail" || name == "gfx_distortion_heat_far" || name == "gfx_distortion_ring_light" || name == "gfx_distortion_heat") && asset.material->info.sortKey >= 43) if (type == Game::ASSET_TYPE_MATERIAL && (name == "gfx_distortion_knife_trail" || name == "gfx_distortion_heat_far" || name == "gfx_distortion_ring_light" || name == "gfx_distortion_heat") && asset.material->info.sortKey >= 43)
{ {
@ -348,7 +291,6 @@ namespace Components
asset.gfxWorld->sortKeyDistortion = 43; asset.gfxWorld->sortKeyDistortion = 43;
} }
} }
#pragma optimize( "", on )
bool AssetHandler::IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset) bool AssetHandler::IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset)
{ {

View File

@ -11,8 +11,19 @@ namespace Assets
{ {
header->model = builder->getIW4OfApi()->read<Game::XModel>(Game::XAssetType::ASSET_TYPE_XMODEL, name); header->model = builder->getIW4OfApi()->read<Game::XModel>(Game::XAssetType::ASSET_TYPE_XMODEL, name);
if (!header->model)
{
// In that case if we want to convert it later potentially we have to grab it now:
header->model = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_XMODEL, name.data()).model;
}
if (header->model) if (header->model)
{ {
if (Components::ZoneBuilder::zb_sp_to_mp.get<bool>())
{
Assets::IXModel::ConvertPlayerModelFromSingleplayerToMultiplayer(header->model, *builder->getAllocator());
}
// ??? // ???
if (header->model->physCollmap) if (header->model->physCollmap)
{ {
@ -305,16 +316,13 @@ namespace Assets
uint8_t IXModel::GetHighestAffectingBoneIndex(const Game::XModelLodInfo* lod) uint8_t IXModel::GetHighestAffectingBoneIndex(const Game::XModelLodInfo* lod)
{ {
uint8_t highestBoneIndex = 0; uint8_t highestBoneIndex = 0;
constexpr auto LENGTH = 6;
{ {
for (auto surfIndex = 0; surfIndex < lod->numsurfs; surfIndex++) for (auto surfIndex = 0; surfIndex < lod->numsurfs; surfIndex++)
{ {
const auto surface = &lod->surfs[surfIndex]; const auto surface = &lod->surfs[surfIndex];
auto vertsBlendOffset = 0; auto vertsBlendOffset = 0;
int rebuiltPartBits[LENGTH]{};
std::unordered_set<uint8_t> affectingBones{}; std::unordered_set<uint8_t> affectingBones{};
const auto registerBoneAffectingSurface = [&](unsigned int offset) { const auto registerBoneAffectingSurface = [&](unsigned int offset) {
@ -380,7 +388,7 @@ namespace Assets
const auto lod = &model->lodInfo[i]; const auto lod = &model->lodInfo[i];
int lodPartBits[6]{}; int lodPartBits[6]{};
for (auto surfIndex = 0; surfIndex < lod->numsurfs; surfIndex++) for (unsigned short surfIndex = 0; surfIndex < lod->numsurfs; surfIndex++)
{ {
const auto surface = &lod->surfs[surfIndex]; const auto surface = &lod->surfs[surfIndex];
@ -400,7 +408,7 @@ namespace Assets
// 1 bone weight // 1 bone weight
for (auto vertIndex = 0; vertIndex < surface->vertInfo.vertCount[0]; vertIndex++) for (unsigned int vertIndex = 0; vertIndex < surface->vertInfo.vertCount[0]; vertIndex++)
{ {
registerBoneAffectingSurface(vertsBlendOffset + 0); registerBoneAffectingSurface(vertsBlendOffset + 0);
@ -408,7 +416,7 @@ namespace Assets
} }
// 2 bone weights // 2 bone weights
for (auto vertIndex = 0; vertIndex < surface->vertInfo.vertCount[1]; vertIndex++) for (unsigned int vertIndex = 0; vertIndex < surface->vertInfo.vertCount[1]; vertIndex++)
{ {
registerBoneAffectingSurface(vertsBlendOffset + 0); registerBoneAffectingSurface(vertsBlendOffset + 0);
registerBoneAffectingSurface(vertsBlendOffset + 1); registerBoneAffectingSurface(vertsBlendOffset + 1);
@ -417,7 +425,7 @@ namespace Assets
} }
// 3 bone weights // 3 bone weights
for (auto vertIndex = 0; vertIndex < surface->vertInfo.vertCount[2]; vertIndex++) for (unsigned int vertIndex = 0; vertIndex < surface->vertInfo.vertCount[2]; vertIndex++)
{ {
registerBoneAffectingSurface(vertsBlendOffset + 0); registerBoneAffectingSurface(vertsBlendOffset + 0);
registerBoneAffectingSurface(vertsBlendOffset + 1); registerBoneAffectingSurface(vertsBlendOffset + 1);
@ -427,7 +435,7 @@ namespace Assets
} }
// 4 bone weights // 4 bone weights
for (auto vertIndex = 0; vertIndex < surface->vertInfo.vertCount[3]; vertIndex++) for (unsigned int vertIndex = 0; vertIndex < surface->vertInfo.vertCount[3]; vertIndex++)
{ {
registerBoneAffectingSurface(vertsBlendOffset + 0); registerBoneAffectingSurface(vertsBlendOffset + 0);
registerBoneAffectingSurface(vertsBlendOffset + 1); registerBoneAffectingSurface(vertsBlendOffset + 1);
@ -437,7 +445,7 @@ namespace Assets
vertsBlendOffset += 7; vertsBlendOffset += 7;
} }
for (auto vertListIndex = 0; vertListIndex < surface->vertListCount; vertListIndex++) for (unsigned int vertListIndex = 0; vertListIndex < surface->vertListCount; vertListIndex++)
{ {
affectingBones.emplace(static_cast<uint8_t>(surface->vertList[vertListIndex].boneOffset / sizeof(Game::DObjSkelMat))); affectingBones.emplace(static_cast<uint8_t>(surface->vertList[vertListIndex].boneOffset / sizeof(Game::DObjSkelMat)));
} }
@ -481,7 +489,7 @@ namespace Assets
// Start with backing up parent links that we will have to restore // Start with backing up parent links that we will have to restore
// We'll restore them at the end // We'll restore them at the end
std::map<std::string, std::string> parentsToRestore{}; std::map<std::string, std::string> parentsToRestore{};
for (int i = model->numRootBones; i < model->numBones; i++) for (uint8_t i = model->numRootBones; i < model->numBones; i++)
{ {
parentsToRestore[Game::SL_ConvertToString(model->boneNames[i])] = GetParentOfBone(model, i); parentsToRestore[Game::SL_ConvertToString(model->boneNames[i])] = GetParentOfBone(model, i);
} }
@ -498,8 +506,6 @@ namespace Assets
const uint8_t newBoneIndex = atPosition; const uint8_t newBoneIndex = atPosition;
const uint8_t newBoneIndexMinusRoot = atPosition - model->numRootBones; const uint8_t newBoneIndexMinusRoot = atPosition - model->numRootBones;
Components::Logger::Print("Inserting bone {} at position {} (between {} and {})\n", boneName, atPosition, Game::SL_ConvertToString(model->boneNames[atPosition - 1]), Game::SL_ConvertToString(model->boneNames[atPosition + 1]));
// Reallocate // Reallocate
const auto newBoneNames = allocator.allocateArray<uint16_t>(newBoneCount); const auto newBoneNames = allocator.allocateArray<uint16_t>(newBoneCount);
const auto newMats = allocator.allocateArray<Game::DObjAnimMat>(newBoneCount); const auto newMats = allocator.allocateArray<Game::DObjAnimMat>(newBoneCount);
@ -518,8 +524,8 @@ namespace Assets
const uint8_t atPositionM1 = atPosition - model->numRootBones; const uint8_t atPositionM1 = atPosition - model->numRootBones;
// should be equal to model->numBones // should be equal to model->numBones
int total = lengthOfFirstPart + lengthOfSecondPart; unsigned int total = lengthOfFirstPart + lengthOfSecondPart;
assert(total = model->numBones); assert(total == model->numBones);
// should be equal to model->numBones - model->numRootBones // should be equal to model->numBones - model->numRootBones
int totalM1 = lengthOfFirstPartM1 + lengthOfSecondPartM1; int totalM1 = lengthOfFirstPartM1 + lengthOfSecondPartM1;
@ -599,9 +605,10 @@ namespace Assets
{ {
const auto lod = &model->lodInfo[lodIndex]; const auto lod = &model->lodInfo[lodIndex];
if ((lod->partBits[5] & 0x1) == 0x1) if ((lod->modelSurfs->partBits[5] & 0x1) == 0x1)
{ {
// surface lod already converted (more efficient) // surface lod already converted (more efficient)
std::memcpy(lod->partBits, lod->modelSurfs->partBits, 6 * sizeof(uint32_t));
continue; continue;
} }
@ -630,7 +637,7 @@ namespace Assets
if (index < 0 || index >= model->numBones) if (index < 0 || index >= model->numBones)
{ {
Components::Logger::Print("Unexpected 'bone index' {} out of {} bones while working vertex blend of model {} lod {} surf {}\n", index, model->numBones, model->name, lodIndex, surfIndex); Components::Logger::Print("Unexpected 'bone index' {} out of {} bones while working vertex blend of: xmodel {} lod {} xmodelsurf {} surf #{}", index, model->numBones, model->name, lodIndex, lod->modelSurfs->name, lodIndex, surfIndex);
assert(false); assert(false);
} }
@ -652,7 +659,7 @@ namespace Assets
if (index < 0 || index >= model->numBones) if (index < 0 || index >= model->numBones)
{ {
Components::Logger::Print("Unexpected 'bone index' {} out of {} bones while working list blend of model {} lod {} surf {}\n", index, model->numBones, model->name, lodIndex, surfIndex); Components::Logger::Print("Unexpected 'bone index' {} out of {} bones while working vertex list of: xmodel {} lod {} xmodelsurf {} surf #{}\n", index, model->numBones, model->name, lodIndex, lod->modelSurfs->name, surfIndex);
assert(false); assert(false);
} }
@ -711,39 +718,17 @@ namespace Assets
const auto key = kv.first; const auto key = kv.first;
const auto beforeVal = kv.second; const auto beforeVal = kv.second;
const auto parentIndex = GetIndexOfBone(model, beforeVal); const auto p = GetIndexOfBone(model, beforeVal);
const auto index = GetIndexOfBone(model, key); const auto index = GetIndexOfBone(model, key);
SetParentIndexOfBone(model, index, parentIndex); SetParentIndexOfBone(model, index, p);
} }
#if DEBUG
// check
for (const auto& kv : parentsToRestore)
{
const auto key = kv.first;
const auto beforeVal = kv.second;
const auto index = GetIndexOfBone(model, key);
const auto afterVal = GetParentOfBone(model, index);
if (beforeVal != afterVal)
{
printf("");
}
}
//
#endif
return atPosition; // Bone index of added bone return atPosition; // Bone index of added bone
}; };
void IXModel::TransferWeights(Game::XModel* model, const uint8_t origin, const uint8_t destination) void IXModel::TransferWeights(Game::XModel* model, const uint8_t origin, const uint8_t destination)
{ {
const auto from = Game::SL_ConvertToString(model->boneNames[origin]);
const auto to = Game::SL_ConvertToString(model->boneNames[destination]);
Components::Logger::Print("Transferring bone weights from {} to {}\n", from, to);
const auto originalWeights = model->baseMat[origin].transWeight; const auto originalWeights = model->baseMat[origin].transWeight;
model->baseMat[origin].transWeight = model->baseMat[destination].transWeight; model->baseMat[origin].transWeight = model->baseMat[destination].transWeight;
model->baseMat[destination].transWeight = originalWeights; model->baseMat[destination].transWeight = originalWeights;
@ -887,15 +872,34 @@ namespace Assets
void IXModel::ConvertPlayerModelFromSingleplayerToMultiplayer(Game::XModel* model, Utils::Memory::Allocator& allocator) void IXModel::ConvertPlayerModelFromSingleplayerToMultiplayer(Game::XModel* model, Utils::Memory::Allocator& allocator)
{ {
auto indexOfSpine = GetIndexOfBone(model, "j_spinelower"); if (model->name == "body_airport_com_a"s)
if (indexOfSpine < UCHAR_MAX) // It has a spine so it must be some sort of humanoid
{ {
printf("");
}
std::string requiredBonesForHumanoid[] = {
"j_spinelower",
"j_spineupper",
"j_spine4",
"j_mainroot"
};
for (const auto& required : requiredBonesForHumanoid)
{
if (GetIndexOfBone(model, required) == UCHAR_MAX)
{
// Not humanoid - nothing to do
return;
}
}
auto indexOfSpine = GetIndexOfBone(model, "j_spinelower");
const auto nameOfParent = GetParentOfBone(model, indexOfSpine); const auto nameOfParent = GetParentOfBone(model, indexOfSpine);
if (GetIndexOfBone(model, "torso_stabilizer") == UCHAR_MAX) // Singleplayer model is likely if (GetIndexOfBone(model, "torso_stabilizer") == UCHAR_MAX) // Singleplayer model is likely
{ {
Components::Logger::Print("Converting {}\n", model->name); Components::Logger::Print("Converting {} skeleton from SP to MP...\n", model->name);
// No stabilizer - let's do surgery // No stabilizer - let's do surgery
// We're trying to get there: // We're trying to get there:
@ -917,13 +921,8 @@ namespace Assets
if (root < UCHAR_MAX) { if (root < UCHAR_MAX) {
// Add pelvis // Add pelvis
#if false
const uint8_t backLow = InsertBone(model, "back_low", "j_spinelower", allocator);
TransferWeights(model, GetIndexOfBone(model, "j_spinelower"), backLow);
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_spineupper"), backLow);
#else
const uint8_t indexOfPelvis = InsertBone(model, "pelvis", "j_mainroot", allocator); const uint8_t indexOfPelvis = InsertBone(model, "pelvis", "j_mainroot", allocator);
SetBoneQuaternion(model, indexOfPelvis, true, -0.494f, -0.506f, -0.506f, 0.494); SetBoneQuaternion(model, indexOfPelvis, true, -0.494f, -0.506f, -0.506f, 0.494f);
TransferWeights(model, root, indexOfPelvis); TransferWeights(model, root, indexOfPelvis);
@ -968,33 +967,35 @@ namespace Assets
// This doesn't feel like it should be necessary // This doesn't feel like it should be necessary
// It is, on singleplayer models unfortunately. Could we add an extra bone to compensate this? // It is, on singleplayer models unfortunately. Could we add an extra bone to compensate this?
// Or compensate it another way? // Or compensate it another way?
SetBoneTrans(model, GetIndexOfBone(model, "j_spinelower"), false, 0.07, 0.0f, 5.2f); SetBoneTrans(model, GetIndexOfBone(model, "j_spinelower"), false, 0.07f, 0.0f, 5.2f);
// These are often messed up on civilian models, but there is no obvious way to tell from code // These are often messed up on civilian models, but there is no obvious way to tell from code
const auto stowedBack = GetIndexOfBone(model, "tag_stowed_back"); auto stowedBack = GetIndexOfBone(model, "tag_stowed_back");
if (stowedBack != UCHAR_MAX) if (stowedBack == UCHAR_MAX)
{ {
SetBoneTrans(model, stowedBack, false, -0.32f, -6.27f, -2.65F); stowedBack = InsertBone(model, "tag_stowed_back", "j_spine4", allocator);
SetBoneQuaternion(model, stowedBack, false, -0.044, 0.088, -0.995, 0.025);
SetBoneTrans(model, stowedBack, true, -9.571f, -2.654f, 51.738f);
SetBoneQuaternion(model, stowedBack, true, -0.071f, 0.0f, -0.997f, 0.0f);
} }
if (stowedBack != UCHAR_MAX) SetBoneTrans(model, stowedBack, false, -0.32f, -6.27f, -2.65F);
SetBoneQuaternion(model, stowedBack, false, -0.044f, 0.088f, -0.995f, 0.025f);
SetBoneTrans(model, stowedBack, true, -9.571f, -2.654f, 51.738f);
SetBoneQuaternion(model, stowedBack, true, -0.071f, 0.0f, -0.997f, 0.0f);
auto stowedRear = GetIndexOfBone(model, "tag_stowed_hip_rear");
if (stowedRear == UCHAR_MAX)
{ {
const auto stowedRear = GetIndexOfBone(model, "tag_stowed_hip_rear"); stowedBack = InsertBone(model, "tag_stowed_hip_rear", "pelvis", allocator);
}
SetBoneTrans(model, stowedRear, false, -0.75f, -6.45f, -4.99f); SetBoneTrans(model, stowedRear, false, -0.75f, -6.45f, -4.99f);
SetBoneQuaternion(model, stowedRear, false, -0.553f, -0.062f, -0.049f, 0.830f); SetBoneQuaternion(model, stowedRear, false, -0.553f, -0.062f, -0.049f, 0.830f);
SetBoneTrans(model, stowedBack, true, -9.866f, -4.989f, 36.315f); SetBoneTrans(model, stowedBack, true, -9.866f, -4.989f, 36.315f);
SetBoneQuaternion(model, stowedRear, true, -0.054, -0.025f, -0.975f, 0.214f); SetBoneQuaternion(model, stowedRear, true, -0.054f, -0.025f, -0.975f, 0.214f);
}
#endif
RebuildPartBits(model); RebuildPartBits(model);
} }
} }
printf("");
}
} }
} }

View File

@ -314,8 +314,6 @@ namespace Components
QuickPatch::QuickPatch() QuickPatch::QuickPatch()
{ {
// Filtering any mapents that is intended for Spec:Ops gamemode (CODO) and prevent them from spawning // Filtering any mapents that is intended for Spec:Ops gamemode (CODO) and prevent them from spawning
Utils::Hook(0x5FBD6E, QuickPatch::IsDynClassname_Stub, HOOK_CALL).install()->quick(); Utils::Hook(0x5FBD6E, QuickPatch::IsDynClassname_Stub, HOOK_CALL).install()->quick();

View File

@ -7,6 +7,8 @@
#include <version.hpp> #include <version.hpp>
#include "AssetInterfaces/ILocalizeEntry.hpp" #include "AssetInterfaces/ILocalizeEntry.hpp"
#include "Events.hpp"
#include "Branding.hpp" #include "Branding.hpp"
namespace Components namespace Components
@ -22,6 +24,8 @@ namespace Components
iw4of::api ZoneBuilder::ExporterAPI(GetExporterAPIParams()); iw4of::api ZoneBuilder::ExporterAPI(GetExporterAPIParams());
std::string ZoneBuilder::DumpingZone{}; std::string ZoneBuilder::DumpingZone{};
Dvar::Var ZoneBuilder::zb_sp_to_mp{};
ZoneBuilder::Zone::Zone(const std::string& name, const std::string& sourceName, const std::string& destination) : ZoneBuilder::Zone::Zone(const std::string& name, const std::string& sourceName, const std::string& destination) :
indexStart(0), externalSize(0), indexStart(0), externalSize(0),
// Reserve 100MB by default. // Reserve 100MB by default.
@ -115,7 +119,7 @@ namespace Components
return &iw4ofApi; return &iw4ofApi;
} }
void ZoneBuilder::Zone::Zone::build() void ZoneBuilder::Zone::build()
{ {
if (!this->dataMap.isValid()) if (!this->dataMap.isValid())
{ {
@ -1300,6 +1304,8 @@ namespace Components
// don't remap techsets // don't remap techsets
Utils::Hook::Nop(0x5BC791, 5); Utils::Hook::Nop(0x5BC791, 5);
ZoneBuilder::zb_sp_to_mp = Game::Dvar_RegisterBool("zb_sp_to_mp", false, Game::DVAR_ARCHIVE, "Attempt to convert singleplayer assets to multiplayer format whenever possible");
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader /* asset*/, const std::string& name, bool* /*restrict*/) AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader /* asset*/, const std::string& name, bool* /*restrict*/)
{ {
if (!ZoneBuilder::TraceZone.empty() && ZoneBuilder::TraceZone == FastFiles::Current()) if (!ZoneBuilder::TraceZone.empty() && ZoneBuilder::TraceZone == FastFiles::Current())

View File

@ -135,6 +135,8 @@ namespace Components
static void BeginAssetTrace(const std::string& zone); static void BeginAssetTrace(const std::string& zone);
static std::vector<std::pair<Game::XAssetType, std::string>> EndAssetTrace(); static std::vector<std::pair<Game::XAssetType, std::string>> EndAssetTrace();
static Dvar::Var zb_sp_to_mp;
static Game::XAssetHeader GetEmptyAssetIfCommon(Game::XAssetType type, const std::string& name, Zone* builder); static Game::XAssetHeader GetEmptyAssetIfCommon(Game::XAssetType type, const std::string& name, Zone* builder);
static std::string GetDumpingZonePath(); static std::string GetDumpingZonePath();
static void RefreshExporterWorkDirectory(); static void RefreshExporterWorkDirectory();

View File

@ -1066,7 +1066,7 @@ namespace Game
struct XSurfaceVertexInfo struct XSurfaceVertexInfo
{ {
__int16 vertCount[4]; unsigned __int16 vertCount[4];
unsigned __int16* vertsBlend; unsigned __int16* vertsBlend;
}; };