Начинающий
- Статус
- Оффлайн
- Регистрация
- 15 Окт 2019
- Сообщения
- 45
- Реакции
- 8
bonesetup.h:
#pragma once
class IBoneSetup {
public:
IBoneSetup(CStudioHdr* hdr, int boneMask, float* poseParams)
: m_pStudioHdr(hdr), m_boneMask(boneMask), m_poseParams(poseParams) {
}
void InitPose(vec3_t* pos, quaternion_t* q) {
static auto init_pose = patterns::bone_setup_init_pose.as<uint64_t>();
__asm
{
mov eax, this
mov esi, q
mov edx, pos
mov ecx, [eax] // m_pStudioHdr is the first member
push dword ptr[ecx + 4] // pass studiohdr_t* (skip vtable if present)
mov ecx, [eax]
push esi
call init_pose
add esp, 8
}
}
void AccumulatePose(vec3_t* pos, quaternion_t* q, int sequence, float cycle, float weight, float time, void* ik) {
using Fn = void(__thiscall*)(void*, vec3_t*, quaternion_t*, int, float, float, float, void*);
static Fn fn = nullptr;
if (!fn) {
fn = patterns::accumulate_pose.as<Fn>();
}
fn(this, pos, q, sequence, cycle, weight, time, ik);
}
void CalcAutoplaySequences(vec3_t* pos, quaternion_t* q, float time, void* ik) {
using Fn = void(__thiscall*)(void*, vec3_t*, quaternion_t*, float, void*);
static Fn fn = nullptr;
if (!fn) {
fn = patterns::bone_setup_calc_autoplay_sequences.as<Fn>();
}
fn(this, pos, q, time, ik);
}
void CalcBoneAdj(vec3_t* pos, quaternion_t* q, float* controllers) {
static auto calc_bone_adj = patterns::bone_setup_calc_bone_adjust.as<uint64_t>();
__asm
{
mov eax, controllers
mov ecx, this
mov edx, pos; a2
push dword ptr[ecx + 4]; a5
mov ecx, [ecx]; a1
push eax; a4
push q; a3
call calc_bone_adj
add esp, 0xC
}
}
private:
CStudioHdr* m_pStudioHdr;
int m_boneMask;
float* m_poseParams;
};
class Bones {
public:
};
extern Bones g_bones;
bonesetup.cpp:
#include "../../includes.h"
Bones g_bones;
// builds bone-to-world matrices from pose and quaternion arrays.
void Studio_BuildMatrices(CStudioHdr* pStudioHdr, const ang_t& angles, const vec3_t& origin, const vec3_t* pos, const quaternion_t* q, int iBone, float flScale, matrix3x4a_t* pBoneToWorld, int boneMask) {
if (!pStudioHdr || !pStudioHdr->_m_pStudioHdr)
return;
const studiohdr_t* hdr = pStudioHdr->_m_pStudioHdr;
int nBones = hdr->m_num_bones;
// compute the root transformation matrix.
matrix3x4_t rootMatrix;
rootMatrix.AngleMatrix(angles, origin);
// temporary array to store parent transforms.
matrix3x4a_t boneMatrices[128];
for (int i = 0; i < nBones; ++i) {
const mstudiobone_t* bone = hdr->GetBone(i);
if (!bone)
continue;
if (!(bone->m_flags & boneMask))
continue;
// build local bone matrix from quaternion and position.
matrix3x4a_t localMatrix;
math::QuaternionMatrix(q[i], pos[i], localMatrix);
int parent = bone->m_parent;
if (parent == -1) {
// root bone: multiply by entity's root transform.
math::ConcatTransforms(rootMatrix, localMatrix, boneMatrices[i]);
}
else {
// child bone: multiply by parent's transform.
math::ConcatTransforms(boneMatrices[parent], localMatrix, boneMatrices[i]);
}
// write to output.
if (pBoneToWorld)
pBoneToWorld[i] = boneMatrices[i];
}
}
bool Player::SetupBones(matrix3x4_t* bonetoworld, int maxbones, int bonemask, float currenttime) {
if (!this)
return false;
auto renderable = GetClientRenderable();
if (!renderable)
return false;
// get model and validate.
CStudioHdr* pStudioHdr = GetModelPtr();
if (!pStudioHdr /*|| !pStudioHdr->IsValid()*/)
return false;
// backup original state.
const auto m_pIk_backup = m_pIK();
const auto client_ent_flags_backup = m_ClientEntEffects();
const auto effects_backup = m_fEffects();
const auto animlod_backup = m_nAnimLODflags();
const auto jiggle_bones_backup = m_bIsJiggleBonesEnabled();
const auto bone_counter_backup = m_iMostRecentModelBoneCounter();
const auto bone_setup_request_backup = m_iMostRecentBoneSetupRequest();
const auto last_bone_setup_time_backup = m_flLastBoneSetupTime();
const auto prev_bone_mask_backup = m_iPrevBoneMask();
const auto accumulated_bone_mask_backup = m_iAccumulatedBoneMask();
// backup global vars.
const auto framecount_backup = m_global_vars->m_frame;
const auto curtime_backup = m_global_vars->m_curtime;
const auto realtime_backup = m_global_vars->m_realtime;
const auto frametime_backup = m_global_vars->m_frametime;
const auto absoluteframetime_backup = m_global_vars->m_abs_frametime;
const auto tickcount_backup = m_global_vars->m_tick_count;
const auto interpolation_amount_backup = m_global_vars->m_interp_amt;
// set up time context for bone calculation.
float simulation_time = m_flSimulationTime();
int ticks = game::TIME_TO_TICKS(simulation_time);
m_global_vars->m_curtime = currenttime;
m_global_vars->m_realtime = currenttime;
m_global_vars->m_frametime = m_global_vars->m_interval;
m_global_vars->m_abs_frametime = m_global_vars->m_interval;
m_global_vars->m_tick_count = ticks;
m_global_vars->m_interp_amt = 0.0f;
m_global_vars->m_frame = -1; // force bone recalculation.
// prepare bone setup state.
InvalidateBoneCache();
// clear IK and disable features that can interfere.
m_pIK() = nullptr;
m_nAnimLODflags() &= ~ANIMLODFLAG_OUTSIDEVIEWFRUSTUM;
m_nCustomBlendingRuleMask() = -1;
m_ClientEntEffects() |= NOINTERP; // 2 // Disable interpolation.
m_fEffects() |= EF_NOINTERP;
m_bIsJiggleBonesEnabled() = false;
// reset bone cache state.
m_iMostRecentModelBoneCounter() = 0;
m_iMostRecentBoneSetupRequest() = 0;
m_flLastBoneSetupTime() = -FLT_MAX;
m_iPrevBoneMask() = 0;
m_iAccumulatedBoneMask() = 0;
// ensure bone accessor is ready.
m_BoneAccessor().m_ReadableBones = 0;
m_BoneAccessor().m_WritableBones = 0;
bool bone_result = false;
try
{
// use engine's bone setup path.
g_csgo.m_bInBoneSetup[EntIndex()] = true;
// call the actual engine SetupBones.
bone_result = renderable->SetupBones(bonetoworld, maxbones, bonemask, currenttime);
// alternative: direct bone calculation if renderable fails.
if (!bone_result && pStudioHdr->_m_pStudioHdr->m_num_bones > 0)
{
// initialize bone arrays.
vec3_t pos[128];
quaternion_t q[128];
// create bone setup context.
IBoneSetup boneSetup(pStudioHdr, bonemask, GetPoseParameterArray());
// initialize pose with model's default bone positions.
boneSetup.InitPose(pos, q);
// accumulate base sequence.
if (GetSequence() >= 0 && GetSequence() < GetNumSeq())
{
boneSetup.AccumulatePose(pos, q, GetSequence(), GetCycle(), 1.0f, currenttime, nullptr);
}
Player* player = this;
for (int i = 0; i < player->m_AnimOverlay().Count(); ++i) {
C_AnimationLayer* layer = &player->m_AnimOverlay()[i];
if (layer && layer->IsActive() && layer->m_weight > 0.0f) {
boneSetup.AccumulatePose(pos, q, layer->m_sequence,
layer->m_cycle, layer->m_weight, currenttime, nullptr);
}
}
// calculate autoplay sequences.
boneSetup.CalcAutoplaySequences(pos, q, currenttime, nullptr);
// apply bone controllers.
boneSetup.CalcBoneAdj(pos, q, GetEncodedControllerArray());
// build final bone-to-world matrices.
Studio_BuildMatrices(pStudioHdr, GetAbsAngles(), GetAbsOrigin(),pos, q, -1, 1.0f, reinterpret_cast<matrix3x4a_t*>(bonetoworld), bonemask);
bone_result = true;
}
}
catch (...)
{
bone_result = false;
}
g_csgo.m_bInBoneSetup[EntIndex()] = false;
// restore original state.
m_pIK() = m_pIk_backup;
m_ClientEntEffects() = client_ent_flags_backup;
m_fEffects() = effects_backup;
m_nAnimLODflags() = animlod_backup;
m_bIsJiggleBonesEnabled() = jiggle_bones_backup;
m_iMostRecentModelBoneCounter() = bone_counter_backup;
m_iMostRecentBoneSetupRequest() = bone_setup_request_backup;
m_flLastBoneSetupTime() = last_bone_setup_time_backup;
m_iPrevBoneMask() = prev_bone_mask_backup;
m_iAccumulatedBoneMask() = accumulated_bone_mask_backup;
// restore global vars.
m_global_vars->m_frame = framecount_backup;
m_global_vars->m_curtime = curtime_backup;
m_global_vars->m_realtime = realtime_backup;
m_global_vars->m_frametime = frametime_backup;
m_global_vars->m_abs_frametime = absoluteframetime_backup;
m_global_vars->m_tick_count = tickcount_backup;
m_global_vars->m_interp_amt = interpolation_amount_backup;
return bone_result;
}