Cleanup & store extra part bit in msurf instead of lodinfo
This commit is contained in:
parent
adddbd5ecc
commit
4a61617e88
@ -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());
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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,114 +872,130 @@ 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
|
|
||||||
{
|
{
|
||||||
const auto nameOfParent = GetParentOfBone(model, indexOfSpine);
|
|
||||||
|
|
||||||
if (GetIndexOfBone(model, "torso_stabilizer") == UCHAR_MAX) // Singleplayer model is likely
|
|
||||||
{
|
|
||||||
|
|
||||||
Components::Logger::Print("Converting {}\n", model->name);
|
|
||||||
|
|
||||||
// No stabilizer - let's do surgery
|
|
||||||
// We're trying to get there:
|
|
||||||
// tag_origin
|
|
||||||
// j_main_root
|
|
||||||
// pelvis
|
|
||||||
// j_hip_le
|
|
||||||
// j_hip_ri
|
|
||||||
// tag_stowed_hip_rear
|
|
||||||
// torso_stabilizer
|
|
||||||
// j_spinelower
|
|
||||||
// back_low
|
|
||||||
// j_spineupper
|
|
||||||
// back_mid
|
|
||||||
// j_spine4
|
|
||||||
|
|
||||||
|
|
||||||
const auto root = GetIndexOfBone(model, "j_mainroot");
|
|
||||||
if (root < UCHAR_MAX) {
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
SetBoneQuaternion(model, indexOfPelvis, true, -0.494f, -0.506f, -0.506f, 0.494);
|
|
||||||
|
|
||||||
TransferWeights(model, root, indexOfPelvis);
|
|
||||||
|
|
||||||
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_hip_le"), indexOfPelvis);
|
|
||||||
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_hip_ri"), indexOfPelvis);
|
|
||||||
SetParentIndexOfBone(model, GetIndexOfBone(model, "tag_stowed_hip_rear"), indexOfPelvis);
|
|
||||||
|
|
||||||
// These two are optional
|
|
||||||
if (GetIndexOfBone(model, "j_coatfront_le") == UCHAR_MAX)
|
|
||||||
{
|
|
||||||
InsertBone(model, "j_coatfront_le", "pelvis", allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetIndexOfBone(model, "j_coatfront_ri") == UCHAR_MAX)
|
|
||||||
{
|
|
||||||
InsertBone(model, "j_coatfront_ri", "pelvis", allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t torsoStabilizer = InsertBone(model, "torso_stabilizer", "pelvis", allocator);
|
|
||||||
const uint8_t lowerSpine = GetIndexOfBone(model, "j_spinelower");
|
|
||||||
SetParentIndexOfBone(model, lowerSpine, torsoStabilizer);
|
|
||||||
|
|
||||||
const uint8_t backLow = InsertBone(model, "back_low", "j_spinelower", allocator);
|
|
||||||
TransferWeights(model, lowerSpine, backLow);
|
|
||||||
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_spineupper"), backLow);
|
|
||||||
|
|
||||||
const uint8_t backMid = InsertBone(model, "back_mid", "j_spineupper", allocator);
|
|
||||||
TransferWeights(model, GetIndexOfBone(model, "j_spineupper"), backMid);
|
|
||||||
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_spine4"), backMid);
|
|
||||||
|
|
||||||
|
|
||||||
assert(root == GetIndexOfBone(model, "j_mainroot"));
|
|
||||||
assert(indexOfPelvis == GetIndexOfBone(model, "pelvis"));
|
|
||||||
assert(backLow == GetIndexOfBone(model, "back_low"));
|
|
||||||
assert(backMid == GetIndexOfBone(model, "back_mid"));
|
|
||||||
|
|
||||||
// Twister bone
|
|
||||||
SetBoneQuaternion(model, lowerSpine, false, -0.492f, -0.507f, -0.507f, 0.492f);
|
|
||||||
SetBoneQuaternion(model, torsoStabilizer, false, 0.494f, 0.506f, 0.506f, 0.494f);
|
|
||||||
|
|
||||||
|
|
||||||
// This doesn't feel like it should be necessary
|
|
||||||
// It is, on singleplayer models unfortunately. Could we add an extra bone to compensate this?
|
|
||||||
// Or compensate it another way?
|
|
||||||
SetBoneTrans(model, GetIndexOfBone(model, "j_spinelower"), false, 0.07, 0.0f, 5.2f);
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
if (stowedBack != UCHAR_MAX)
|
|
||||||
{
|
|
||||||
SetBoneTrans(model, stowedBack, false, -0.32f, -6.27f, -2.65F);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
const auto stowedRear = GetIndexOfBone(model, "tag_stowed_hip_rear");
|
|
||||||
SetBoneTrans(model, stowedRear, false, -0.75f, -6.45f, -4.99f);
|
|
||||||
SetBoneQuaternion(model, stowedRear, false, -0.553f, -0.062f, -0.049f, 0.830f);
|
|
||||||
SetBoneTrans(model, stowedBack, true, -9.866f, -4.989f, 36.315f);
|
|
||||||
SetBoneQuaternion(model, stowedRear, true, -0.054, -0.025f, -0.975f, 0.214f);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RebuildPartBits(model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("");
|
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);
|
||||||
|
|
||||||
|
if (GetIndexOfBone(model, "torso_stabilizer") == UCHAR_MAX) // Singleplayer model is likely
|
||||||
|
{
|
||||||
|
|
||||||
|
Components::Logger::Print("Converting {} skeleton from SP to MP...\n", model->name);
|
||||||
|
|
||||||
|
// No stabilizer - let's do surgery
|
||||||
|
// We're trying to get there:
|
||||||
|
// tag_origin
|
||||||
|
// j_main_root
|
||||||
|
// pelvis
|
||||||
|
// j_hip_le
|
||||||
|
// j_hip_ri
|
||||||
|
// tag_stowed_hip_rear
|
||||||
|
// torso_stabilizer
|
||||||
|
// j_spinelower
|
||||||
|
// back_low
|
||||||
|
// j_spineupper
|
||||||
|
// back_mid
|
||||||
|
// j_spine4
|
||||||
|
|
||||||
|
|
||||||
|
const auto root = GetIndexOfBone(model, "j_mainroot");
|
||||||
|
if (root < UCHAR_MAX) {
|
||||||
|
|
||||||
|
// Add pelvis
|
||||||
|
const uint8_t indexOfPelvis = InsertBone(model, "pelvis", "j_mainroot", allocator);
|
||||||
|
SetBoneQuaternion(model, indexOfPelvis, true, -0.494f, -0.506f, -0.506f, 0.494f);
|
||||||
|
|
||||||
|
TransferWeights(model, root, indexOfPelvis);
|
||||||
|
|
||||||
|
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_hip_le"), indexOfPelvis);
|
||||||
|
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_hip_ri"), indexOfPelvis);
|
||||||
|
SetParentIndexOfBone(model, GetIndexOfBone(model, "tag_stowed_hip_rear"), indexOfPelvis);
|
||||||
|
|
||||||
|
// These two are optional
|
||||||
|
if (GetIndexOfBone(model, "j_coatfront_le") == UCHAR_MAX)
|
||||||
|
{
|
||||||
|
InsertBone(model, "j_coatfront_le", "pelvis", allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetIndexOfBone(model, "j_coatfront_ri") == UCHAR_MAX)
|
||||||
|
{
|
||||||
|
InsertBone(model, "j_coatfront_ri", "pelvis", allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t torsoStabilizer = InsertBone(model, "torso_stabilizer", "pelvis", allocator);
|
||||||
|
const uint8_t lowerSpine = GetIndexOfBone(model, "j_spinelower");
|
||||||
|
SetParentIndexOfBone(model, lowerSpine, torsoStabilizer);
|
||||||
|
|
||||||
|
const uint8_t backLow = InsertBone(model, "back_low", "j_spinelower", allocator);
|
||||||
|
TransferWeights(model, lowerSpine, backLow);
|
||||||
|
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_spineupper"), backLow);
|
||||||
|
|
||||||
|
const uint8_t backMid = InsertBone(model, "back_mid", "j_spineupper", allocator);
|
||||||
|
TransferWeights(model, GetIndexOfBone(model, "j_spineupper"), backMid);
|
||||||
|
SetParentIndexOfBone(model, GetIndexOfBone(model, "j_spine4"), backMid);
|
||||||
|
|
||||||
|
|
||||||
|
assert(root == GetIndexOfBone(model, "j_mainroot"));
|
||||||
|
assert(indexOfPelvis == GetIndexOfBone(model, "pelvis"));
|
||||||
|
assert(backLow == GetIndexOfBone(model, "back_low"));
|
||||||
|
assert(backMid == GetIndexOfBone(model, "back_mid"));
|
||||||
|
|
||||||
|
// Twister bone
|
||||||
|
SetBoneQuaternion(model, lowerSpine, false, -0.492f, -0.507f, -0.507f, 0.492f);
|
||||||
|
SetBoneQuaternion(model, torsoStabilizer, false, 0.494f, 0.506f, 0.506f, 0.494f);
|
||||||
|
|
||||||
|
|
||||||
|
// This doesn't feel like it should be necessary
|
||||||
|
// It is, on singleplayer models unfortunately. Could we add an extra bone to compensate this?
|
||||||
|
// Or compensate it another way?
|
||||||
|
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
|
||||||
|
auto stowedBack = GetIndexOfBone(model, "tag_stowed_back");
|
||||||
|
if (stowedBack == UCHAR_MAX)
|
||||||
|
{
|
||||||
|
stowedBack = InsertBone(model, "tag_stowed_back", "j_spine4", allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
stowedBack = InsertBone(model, "tag_stowed_hip_rear", "pelvis", allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetBoneTrans(model, stowedRear, false, -0.75f, -6.45f, -4.99f);
|
||||||
|
SetBoneQuaternion(model, stowedRear, false, -0.553f, -0.062f, -0.049f, 0.830f);
|
||||||
|
SetBoneTrans(model, stowedBack, true, -9.866f, -4.989f, 36.315f);
|
||||||
|
SetBoneQuaternion(model, stowedRear, true, -0.054f, -0.025f, -0.975f, 0.214f);
|
||||||
|
|
||||||
|
|
||||||
|
RebuildPartBits(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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())
|
||||||
{
|
{
|
||||||
@ -1189,7 +1193,7 @@ namespace Components
|
|||||||
|
|
||||||
Game::DB_LoadXAssets(&info, 1, true);
|
Game::DB_LoadXAssets(&info, 1, true);
|
||||||
AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, "default"); // Lock until zone is unloaded
|
AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, "default"); // Lock until zone is unloaded
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneBuilder::ZoneBuilder()
|
ZoneBuilder::ZoneBuilder()
|
||||||
@ -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())
|
||||||
@ -1402,7 +1408,7 @@ namespace Components
|
|||||||
if (assetHeader.data)
|
if (assetHeader.data)
|
||||||
{
|
{
|
||||||
ExporterAPI.write(type, assetHeader.data);
|
ExporterAPI.write(type, assetHeader.data);
|
||||||
const auto typeName = Game::DB_GetXAssetTypeName(type) ;
|
const auto typeName = Game::DB_GetXAssetTypeName(type);
|
||||||
|
|
||||||
if (type != lastTypeEncountered)
|
if (type != lastTypeEncountered)
|
||||||
{
|
{
|
||||||
@ -1541,8 +1547,8 @@ namespace Components
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Command::Add("listassets", [](const Command::Params* params)
|
Command::Add("listassets", [](const Command::Params* params)
|
||||||
{
|
{
|
||||||
@ -1558,7 +1564,7 @@ namespace Components
|
|||||||
}, &type, false);
|
}, &type, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneBuilder::~ZoneBuilder()
|
ZoneBuilder::~ZoneBuilder()
|
||||||
|
@ -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();
|
||||||
|
@ -1066,7 +1066,7 @@ namespace Game
|
|||||||
|
|
||||||
struct XSurfaceVertexInfo
|
struct XSurfaceVertexInfo
|
||||||
{
|
{
|
||||||
__int16 vertCount[4];
|
unsigned __int16 vertCount[4];
|
||||||
unsigned __int16* vertsBlend;
|
unsigned __int16* vertsBlend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user