Added gamelib physics and effects.
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
#include "gamelib/effects/electricbolt.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
bool GameLib_GetElectricBoltParameters(const idDeclElectricBolt* decl,
|
||||
idElectricBoltParameters& parameters);
|
||||
void GameLib_SubmitElectricBolt(idRenderModelBeam* beamModel,
|
||||
const idMaterial* material, const segment_t* segments, int numSegments,
|
||||
int currentTime, int startTime, float startWidth, float endWidth,
|
||||
const idVec4& color, float brightness, bool applyGradient,
|
||||
int revealTime, int branchLevel);
|
||||
|
||||
namespace {
|
||||
|
||||
struct BoltRandom {
|
||||
explicit BoltRandom(const std::uint32_t seed) : state(seed) {}
|
||||
|
||||
float Unit() {
|
||||
state = state * 1664525u + 1013904223u;
|
||||
return static_cast<float>((state >> 8) & 0x00FFFFFFu) *
|
||||
(1.0f / 16777216.0f);
|
||||
}
|
||||
|
||||
float Centered() { return Unit() * 2.0f - 1.0f; }
|
||||
std::uint32_t state;
|
||||
};
|
||||
|
||||
idVec3 SafePerpendicular(const idVec3& direction, BoltRandom& random) {
|
||||
idVec3 reference = std::fabs(direction.z) < 0.75f
|
||||
? idVec3(0.0f, 0.0f, 1.0f)
|
||||
: idVec3(0.0f, 1.0f, 0.0f);
|
||||
idVec3 side = direction.Cross(reference);
|
||||
if (side.NormalizeFast() == 0.0f) {
|
||||
side = idVec3(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
idVec3 up = direction.Cross(side);
|
||||
up.NormalizeFast();
|
||||
idVec3 result = side * random.Centered() + up * random.Centered();
|
||||
if (result.NormalizeFast() == 0.0f) {
|
||||
return side;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SubdivideBolt_r(const idVec3& startPos, const idVec3& endPos,
|
||||
boltStats_t& stats, BoltRandom& random, int subdivisionLevel,
|
||||
int branchLevel, int numSubdivisions, float deviation,
|
||||
idStaticList<segment_t, 128>& segments) {
|
||||
if (segments.Num() >= segments.Max()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const idVec3 delta = endPos - startPos;
|
||||
const float length = delta.Length();
|
||||
if (subdivisionLevel >= numSubdivisions || length <= 0.001f) {
|
||||
segment_t segment{};
|
||||
segment.startPos = startPos;
|
||||
segment.endPos = endPos;
|
||||
segment.lengthFrac = length * stats.invTotalLength;
|
||||
segments.Append(segment);
|
||||
++stats.numNodes;
|
||||
return;
|
||||
}
|
||||
|
||||
idVec3 direction = delta;
|
||||
direction.NormalizeFast();
|
||||
const float falloff = 1.0f / static_cast<float>(1 << subdivisionLevel);
|
||||
const idVec3 offset = SafePerpendicular(direction, random) *
|
||||
(deviation * falloff * random.Centered());
|
||||
const idVec3 middle = (startPos + endPos) * 0.5f + offset;
|
||||
SubdivideBolt_r(startPos, middle, stats, random,
|
||||
subdivisionLevel + 1, branchLevel, numSubdivisions, deviation,
|
||||
segments);
|
||||
SubdivideBolt_r(middle, endPos, stats, random,
|
||||
subdivisionLevel + 1, branchLevel, numSubdivisions, deviation,
|
||||
segments);
|
||||
}
|
||||
|
||||
void GenerateBranch(const idVec3& origin, const idVec3& parentDirection,
|
||||
boltStats_t& stats, BoltRandom& random,
|
||||
const idElectricBoltParameters& parameters, int branchLevel,
|
||||
int currentTime, idRenderModelBeam* beamModel) {
|
||||
if (branchLevel > parameters.maxBranchLevels) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float minimumLength = (std::min)(parameters.branchLength.x,
|
||||
parameters.branchLength.y);
|
||||
const float maximumLength = (std::max)(parameters.branchLength.x,
|
||||
parameters.branchLength.y);
|
||||
const float branchLength = minimumLength +
|
||||
(maximumLength - minimumLength) * random.Unit();
|
||||
const float angleScale = std::sin(parameters.maxBranchAngle *
|
||||
0.01745329251994329577f * random.Unit());
|
||||
idVec3 direction = parentDirection +
|
||||
SafePerpendicular(parentDirection, random) * angleScale;
|
||||
direction.NormalizeFast();
|
||||
|
||||
idStaticList<segment_t, 128> branchSegments;
|
||||
SubdivideBolt_r(origin, origin + direction * branchLength, stats, random,
|
||||
0, branchLevel, (std::max)(0, parameters.branchSubdivisions),
|
||||
parameters.maxBranchDeviation, branchSegments);
|
||||
if (branchSegments.Num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const idMaterial* material = parameters.useBranchOverride &&
|
||||
parameters.branchMaterial != nullptr
|
||||
? parameters.branchMaterial : parameters.material;
|
||||
float branchStartWidth = parameters.branchStartWidth;
|
||||
float branchEndWidth = parameters.branchEndWidth;
|
||||
if (parameters.useBranchOverride && parameters.branchWidth > 0) {
|
||||
branchStartWidth = static_cast<float>(parameters.branchWidth);
|
||||
branchEndWidth = 0.0f;
|
||||
}
|
||||
GameLib_SubmitElectricBolt(beamModel, material, branchSegments.Ptr(),
|
||||
branchSegments.Num(), currentTime, stats.boltStartTime,
|
||||
branchStartWidth, branchEndWidth, parameters.color,
|
||||
parameters.brightness, parameters.applyGradient,
|
||||
parameters.revealTime, branchLevel);
|
||||
++stats.numBranches;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// The authoritative generator first recursively subdivides each control
|
||||
// segment, then emits probabilistic branches from the resulting nodes.
|
||||
void GenerateBolt(idStaticList<segment_t, 128>& currentSegments,
|
||||
boltStats_t& stats, idRenderModelBeam* beamModel,
|
||||
const idDeclElectricBolt* eboltDecl, int currentTime, int diversity,
|
||||
int branchLevel, float maxDeviation, int maxSubdivisions) {
|
||||
idElectricBoltParameters parameters{};
|
||||
if (beamModel == nullptr || eboltDecl == nullptr ||
|
||||
!GameLib_GetElectricBoltParameters(eboltDecl, parameters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BoltRandom random(static_cast<std::uint32_t>(diversity) ^
|
||||
static_cast<std::uint32_t>(stats.boltStartTime * 1103515245u));
|
||||
idStaticList<segment_t, 128> generated;
|
||||
for (int index = 0; index < currentSegments.Num(); ++index) {
|
||||
const segment_t& source = currentSegments[index];
|
||||
SubdivideBolt_r(source.startPos, source.endPos, stats, random, 0,
|
||||
branchLevel, (std::max)(0, maxSubdivisions), maxDeviation,
|
||||
generated);
|
||||
}
|
||||
|
||||
if (generated.Num() == 0) {
|
||||
return;
|
||||
}
|
||||
GameLib_SubmitElectricBolt(beamModel, parameters.material,
|
||||
generated.Ptr(), generated.Num(), currentTime, stats.boltStartTime,
|
||||
parameters.startWidth, parameters.endWidth, parameters.color,
|
||||
parameters.brightness, parameters.applyGradient,
|
||||
parameters.revealTime, branchLevel);
|
||||
|
||||
if (branchLevel < parameters.maxBranchLevels &&
|
||||
parameters.branchProbability > 0.0f) {
|
||||
for (int index = 0; index < generated.Num(); ++index) {
|
||||
if (random.Unit() >= parameters.branchProbability) {
|
||||
continue;
|
||||
}
|
||||
idVec3 parentDirection = generated[index].endPos -
|
||||
generated[index].startPos;
|
||||
if (parentDirection.NormalizeFast() == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
GenerateBranch(generated[index].endPos, parentDirection, stats,
|
||||
random, parameters, branchLevel + 1, currentTime, beamModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idElectricBolt::idElectricBolt()
|
||||
: eboltDecl(nullptr)
|
||||
, beamModel(nullptr)
|
||||
, controlNodes()
|
||||
, startTime(0)
|
||||
, diversity(0) {
|
||||
}
|
||||
|
||||
idElectricBolt::~idElectricBolt() {
|
||||
eboltDecl = nullptr;
|
||||
beamModel = nullptr;
|
||||
controlNodes.Clear();
|
||||
}
|
||||
|
||||
void idElectricBolt::Init(idRenderModelBeam* const beamModel_,
|
||||
const idDeclElectricBolt* const eboltDecl_) {
|
||||
beamModel = beamModel_;
|
||||
eboltDecl = eboltDecl_;
|
||||
}
|
||||
|
||||
void idElectricBolt::UpdateControlNodes(
|
||||
const idStaticList<eboltControlNode_t, 32>& newControlNodes) {
|
||||
controlNodes = newControlNodes;
|
||||
}
|
||||
|
||||
void idElectricBolt::StartElectricBolt(const int newStartTime,
|
||||
const idVec3& startPos, const idVec3& endPos,
|
||||
const float newDiversity) {
|
||||
if (beamModel == nullptr || eboltDecl == nullptr) {
|
||||
controlNodes.Clear();
|
||||
return;
|
||||
}
|
||||
startTime = newStartTime;
|
||||
diversity = static_cast<int>(newDiversity * 32767.0f);
|
||||
controlNodes.SetNum(1);
|
||||
controlNodes[0].startPos = startPos;
|
||||
controlNodes[0].endPos = endPos;
|
||||
}
|
||||
|
||||
void idElectricBolt::StartElectricBolt(const int newStartTime,
|
||||
const idStaticList<eboltControlNode_t, 32>& newControlNodes,
|
||||
const float newDiversity) {
|
||||
startTime = newStartTime;
|
||||
diversity = static_cast<int>(newDiversity * 32767.0f);
|
||||
controlNodes = newControlNodes;
|
||||
}
|
||||
|
||||
void idElectricBolt::StopElectricBolt() {
|
||||
controlNodes.Clear();
|
||||
}
|
||||
|
||||
void idElectricBolt::Update(const int currentTime) {
|
||||
if (beamModel == nullptr || eboltDecl == nullptr ||
|
||||
controlNodes.Num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
idElectricBoltParameters parameters{};
|
||||
if (!GameLib_GetElectricBoltParameters(eboltDecl, parameters)) {
|
||||
return;
|
||||
}
|
||||
|
||||
idStaticList<segment_t, 128> segments;
|
||||
float totalLength = 0.0f;
|
||||
for (int index = 0; index < controlNodes.Num(); ++index) {
|
||||
segment_t source{};
|
||||
source.startPos = controlNodes[index].startPos;
|
||||
source.endPos = controlNodes[index].endPos;
|
||||
source.lengthFrac = 1.0f;
|
||||
segments.Append(source);
|
||||
totalLength += (source.endPos - source.startPos).Length();
|
||||
}
|
||||
|
||||
boltStats_t stats{};
|
||||
stats.invTotalLength = totalLength > 0.001f ? 1.0f / totalLength : 0.0f;
|
||||
stats.boltStartPos = controlNodes[0].startPos;
|
||||
stats.boltStartTime = startTime;
|
||||
GenerateBolt(segments, stats, beamModel, eboltDecl, currentTime,
|
||||
diversity, 0, parameters.maxDeviation, parameters.subdivisions);
|
||||
}
|
||||
@@ -1,197 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\effects\electricbolt.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "idlib/containers/staticlist.h"
|
||||
#include "idlib/math/vector.h"
|
||||
|
||||
class idDeclElectricBolt;
|
||||
class idDeclTable;
|
||||
class idMaterial;
|
||||
class idRenderModelBeam;
|
||||
|
||||
// IDA Local Type ordinal 15618; PDB kind: class.
|
||||
class idElectricBolt
|
||||
{
|
||||
public:
|
||||
const idDeclElectricBolt *eboltDecl;
|
||||
idRenderModelBeam *beamModel;
|
||||
idStaticList<eboltControlNode_t,32> controlNodes;
|
||||
int startTime;
|
||||
int diversity;
|
||||
// Recovered declaration-facing data used by the bolt generator. The decl
|
||||
// system owns the real idDeclElectricBolt and exposes this stable view to
|
||||
// GameLib through GameLib_GetElectricBoltParameters.
|
||||
struct idElectricBoltParameters {
|
||||
const idMaterial* material;
|
||||
bool applyGradient;
|
||||
int revealTime;
|
||||
float startWidth;
|
||||
float endWidth;
|
||||
float maxDeviation;
|
||||
idVec4 color;
|
||||
float brightness;
|
||||
int subdivisions;
|
||||
float branchProbability;
|
||||
int maxBranchLevels;
|
||||
float branchStartWidth;
|
||||
float branchEndWidth;
|
||||
idVec2 branchLength;
|
||||
float maxBranchAngle;
|
||||
int branchSubdivisions;
|
||||
float maxBranchDeviation;
|
||||
const idDeclTable* jitterTable;
|
||||
const idDeclTable* jitterFalloffTable;
|
||||
float jitterDecay;
|
||||
float jitterSpeed;
|
||||
idVec2 jitterLeftMag;
|
||||
idVec2 jitterUpMag;
|
||||
bool useBranchOverride;
|
||||
const idMaterial* branchMaterial;
|
||||
int branchFrames;
|
||||
int branchWidth;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 19740; PDB kind: class.
|
||||
class __declspec(align(8)) idElectricBoltEmitter : public idDynamicEntity
|
||||
{
|
||||
public:
|
||||
// Recovered virtual interface; IDA vtable ordinal 19741.
|
||||
virtual idTypeInfo *GetType();
|
||||
virtual ~idElectricBoltEmitter();
|
||||
virtual idEventArg *CallEvent(idEventArg *result, const idEventDef *, const idEventArg *);
|
||||
virtual bool RespondsTo(const idEventDef *);
|
||||
virtual idEventArg *InternalCallEvent(idEventArg *result, const idEventDef *, const idEventArg *);
|
||||
virtual bool InternalRespondsTo(const idEventDef *);
|
||||
virtual void PostSpawn();
|
||||
virtual void Remove();
|
||||
virtual void DeleteSubEntities();
|
||||
virtual bool Draw(idPlayer *);
|
||||
virtual void JobSync();
|
||||
virtual void Think();
|
||||
virtual void PauseThink();
|
||||
virtual bool ShouldEnterDormancy();
|
||||
virtual bool ShouldLeaveDormancy();
|
||||
virtual void DormantBegin();
|
||||
virtual void DormantEnd(const int);
|
||||
virtual idRenderModelInfo *GetRenderModelInfo();
|
||||
virtual const idRenderModelInfo *GetRenderModelInfo_2();
|
||||
virtual void GetScale(idVec3 *);
|
||||
virtual void SetScale(const idVec3 *);
|
||||
virtual void SetModelByName(const char *);
|
||||
virtual void SetModel(idRenderModel *);
|
||||
virtual const idMaterial *GetCustomMaterial();
|
||||
virtual void SetColor(const idVec4 *);
|
||||
virtual void SetColor_2(const idColor *);
|
||||
virtual void SetColor_3(const idVec3 *);
|
||||
virtual void SetColor_4(float, float, float);
|
||||
virtual void SetColor_5(float, float, float, float);
|
||||
virtual void GetColor(idVec4 *);
|
||||
virtual void GetColor_2(idColor *);
|
||||
virtual void GetColor_3(idVec3 *);
|
||||
virtual void Hide(bool);
|
||||
virtual void Hide_2();
|
||||
virtual void Show();
|
||||
virtual void GetModelTransform(idVec3 *, idMat3 *);
|
||||
virtual void GetSoundTransform(idVec3 *, idMat3 *);
|
||||
virtual void UpdateModelTransform();
|
||||
virtual void UpdateFX();
|
||||
virtual void ProjectOverlay(const idVec3 *, const idVec3 *, float, const char *);
|
||||
virtual idPresentable *AllocPresentable(idRenderModel *);
|
||||
virtual const idComponentTimeLine *GetComponentTimeLine();
|
||||
virtual idComponentTimeLine *GetComponentTimeLine_2();
|
||||
virtual bool UpdateAnimationControllers();
|
||||
virtual void UpdateAttachments();
|
||||
virtual const idAnimStack *GetAnimStack();
|
||||
virtual idAnimStack *GetAnimStack_2();
|
||||
virtual idIndex<short,enum invalidJointIndex_t> *GetJointIndexFromTrace(idIndex<short,enum invalidJointIndex_t> *result, trace_t);
|
||||
virtual awPathResult_t ChangeAnimWebState(const char *, const char *);
|
||||
virtual awPathResult_t ChangeAnimWebState_2(const char *);
|
||||
virtual awPathResult_t ForceAnimWebState(const char *);
|
||||
virtual awPathResult_t ChangeAnimWebStateVia(const char *, const char *, const char *, const char *);
|
||||
virtual awPathResult_t ChangeAnimWebStateVia_2(const char *, const char *);
|
||||
virtual idAnimWebCmdCtx *GetAnimWebCmdCtx();
|
||||
virtual const idAnimWebCmdCtx *GetAnimWebCmdCtx_2();
|
||||
virtual const idAnimator_AF *GetAF();
|
||||
virtual idAnimator_AF *GetAF_2();
|
||||
virtual void PreBind();
|
||||
virtual void PostBind();
|
||||
virtual void PreUnbind();
|
||||
virtual void PostUnbind();
|
||||
virtual const splineLocation_t *GetSplineLocation();
|
||||
virtual void SetAxis(const idMat3 *);
|
||||
virtual bool CanDisablePhysics(const idEntity *);
|
||||
virtual collide_t Collide(const int, trace_t *, const idVec3 *);
|
||||
virtual collide_t Contact(const int, contactInfo_t *);
|
||||
virtual void ApplyImpulse(const int, const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyImpulseFromEntity(const idEntity *, const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyForce(const int, const int, const idVec3 *, const idVec3 *);
|
||||
virtual bool Crush(const int);
|
||||
virtual void ApplyDamage(const int, const int, const idDeclDamage *);
|
||||
virtual void ActivatePhysics(const int);
|
||||
virtual void DeactivatePhysics(const int);
|
||||
virtual void ApplyWaterEffects(const int, const int);
|
||||
virtual void ApplyWaterSplashEffects(const int, const int, surfTypes_t, idPhysicsCallbacks::splashState_t);
|
||||
virtual bool TakesDamage();
|
||||
virtual void DamageFeedback(idEntity *, idEntity *, const idDeclDamage *, float *);
|
||||
virtual void KilledNotification(const idEntity *, const idEntity *, const idDeclDamage *, const float);
|
||||
virtual float Damage(idEntity *, idEntity *, const idDeclDamage *, const float, const idVec3 *, trace_t *);
|
||||
virtual bool CalcDamageImpulse(const idEntity *, const idEntity *, const idDeclDamage *, const float, const idVec3 *, const trace_t *, idVec3 *, idVec3 *);
|
||||
virtual bool IsTargetLockable(const idDeclAmmo *);
|
||||
virtual void AddProjectileLock();
|
||||
virtual void RemoveProjectileLock();
|
||||
virtual const idScriptObject *GetScriptObject();
|
||||
virtual idScriptObject *GetScriptObject_2();
|
||||
virtual bool ShouldConstructScriptObjectAtSpawn();
|
||||
virtual idThread *GetStateThread();
|
||||
virtual int AddThread(const idHandle<int,enum invalidThreadHandle_t,0>);
|
||||
virtual void RemoveThread(const idHandle<int,enum invalidThreadHandle_t,0>);
|
||||
virtual idHandle<int,enum invalidThreadHandle_t,0> *GetThread(idHandle<int,enum invalidThreadHandle_t,0> *result, const int);
|
||||
virtual int NumThreads();
|
||||
virtual int MaxThreads();
|
||||
virtual void ExecuteThread(idThread *);
|
||||
virtual void ResetFSMWaitThreadIfPossible(idThread *);
|
||||
virtual bool HandleGuiEvent(const sysEvent_t *);
|
||||
virtual void ActivateTargets(idEntity *);
|
||||
virtual bool GetRcCarCanTarget();
|
||||
virtual const idBaseHealth *GetHealthComponent();
|
||||
virtual idBaseHealth *GetHealthComponent_2();
|
||||
virtual const idSmartLootComponent *GetSmartLootComponent();
|
||||
virtual idSmartLootComponent *GetSmartLootComponent_2();
|
||||
virtual void Teleport(const idVec3 *, const idAngles *);
|
||||
virtual bool IsPusher();
|
||||
virtual const idList<idEntityPtr<idEntity>,5> *GetTriggerTouchList();
|
||||
virtual idList<idEntityPtr<idEntity>,5> *GetTriggerTouchList_2();
|
||||
virtual void TestFunctionality();
|
||||
virtual float GetUsableDistance();
|
||||
virtual float GetCrosshairIconDistance();
|
||||
virtual usableState_t GetUsableState(const idEntity *, const idFocusTrace *);
|
||||
virtual bool ModifyCrosshairInfo(const idEntity *, const idFocusTrace *, const usableState_t, idCrosshairInfo *);
|
||||
virtual bool IsCrosshairDisabled(const idEntity *, const idFocusTrace *, const usableState_t);
|
||||
virtual bool IsCrosshairSubdued(const idEntity *, const idFocusTrace *, const usableState_t);
|
||||
virtual bool IsEverUsable(const idEntity *);
|
||||
virtual bool IsCurrentlyUsable(const idEntity *);
|
||||
virtual bool Use(idEntity *, const usableState_t);
|
||||
virtual void Dropped(idEntity *, const idDeclInventory *);
|
||||
virtual const idInventoryCollection *GetInventory();
|
||||
virtual idInventoryCollection *GetInventory_2();
|
||||
virtual void InventoryAdded(idInventoryItem *, int);
|
||||
virtual void InventoryRemoved(idInventoryItem *);
|
||||
virtual const idAttachmentCollection *GetAttachments();
|
||||
virtual idAttachmentCollection *GetAttachments_2();
|
||||
virtual void EnableAIEventResponse(const idAIEvent::aiEventClass_t);
|
||||
virtual void DisableAIEventResponse(const idAIEvent::aiEventClass_t);
|
||||
virtual bool CanReceiveAIEvents(const int);
|
||||
virtual bool RespondsToAIEvent(const idAIEvent *);
|
||||
virtual void OnAIEvent(const idAIEvent *);
|
||||
virtual bool IsDead();
|
||||
virtual bool IsDying();
|
||||
virtual idFaction *GetFaction();
|
||||
virtual const idFaction *GetFaction_2();
|
||||
virtual idEntityAuditor *GetAuditor();
|
||||
virtual void GetVisibilityPoint(const visPoint_t, idVec3 *);
|
||||
virtual void GetAimPoint(const aimPoint_t, idVec3 *);
|
||||
virtual void GetEyePos(idVec3 *);
|
||||
virtual bool IsVisible();
|
||||
virtual idDynamicCoverMgr *GetDynamicCoverMgr();
|
||||
virtual const idDynamicCoverMgr *GetDynamicCoverMgr_2();
|
||||
virtual const idAAS2 *GetAAS();
|
||||
virtual void GetViewStateFOV(idVec3 *, unsigned __int8 *, unsigned __int8 *);
|
||||
virtual void GetViewStateFOV_2(idVec3 *, unsigned __int8 *, unsigned __int8 *);
|
||||
virtual int GetNumRepairBotTetherPoints();
|
||||
virtual bool GetRepairBotTetherPoint(const int, const int, idVec3 *);
|
||||
virtual idEntityInterface *CreateEntityInterface(idGame *);
|
||||
virtual void ShowEditingDialog();
|
||||
virtual void UpdateEditingDialog();
|
||||
virtual void UpdateModifiedProperties();
|
||||
virtual inputSettings_t *GetInputSettings(inputSettings_t *result, idPlayer *);
|
||||
virtual bool EvaluateControls(usercmd_t *, usercmd_t *);
|
||||
virtual void CheckForErrors(idList<idStr,5> *);
|
||||
virtual void DebugDrawEntity(const idColor *, int);
|
||||
virtual void ClientThink();
|
||||
virtual void Serialize(idSerializer *);
|
||||
virtual void PostSerializeRead(bool);
|
||||
virtual void OnActivate(idEntity *);
|
||||
virtual void OnMakeActivatable(const bool);
|
||||
virtual void OnNotifyProgressionOwner();
|
||||
|
||||
int minResetTime;
|
||||
int maxResetTime;
|
||||
bool startOff;
|
||||
const idDeclElectricBolt *electricBoltSystem;
|
||||
const idSoundShader *sndPowerDown;
|
||||
const idSoundShader *sndPowerUp;
|
||||
float maxConeAngle;
|
||||
idVec2 length;
|
||||
idEntityPtr<idSplinePath> controlPath;
|
||||
bool loopControlPath;
|
||||
int controlPathGrowTime;
|
||||
idElectricBolt *ebolt;
|
||||
idCurve_Spline<idVec3> *spline;
|
||||
int nextResetTime;
|
||||
struct eboltControlNode_t {
|
||||
idVec3 startPos;
|
||||
idVec3 endPos;
|
||||
};
|
||||
|
||||
struct boltStats_t {
|
||||
int numNodes;
|
||||
int numBranches;
|
||||
float invTotalLength;
|
||||
idVec3 boltStartPos;
|
||||
int boltStartTime;
|
||||
};
|
||||
|
||||
struct segment_t {
|
||||
idVec3 startPos;
|
||||
idVec3 endPos;
|
||||
float lengthFrac;
|
||||
};
|
||||
|
||||
class idElectricBolt {
|
||||
public:
|
||||
idElectricBolt();
|
||||
~idElectricBolt();
|
||||
|
||||
void Init(idRenderModelBeam* beamModel,
|
||||
const idDeclElectricBolt* eboltDecl);
|
||||
void UpdateControlNodes(
|
||||
const idStaticList<eboltControlNode_t, 32>& controlNodes);
|
||||
void StartElectricBolt(int startTime, const idVec3& startPos,
|
||||
const idVec3& endPos, float diversity);
|
||||
void StartElectricBolt(int startTime,
|
||||
const idStaticList<eboltControlNode_t, 32>& controlNodes,
|
||||
float diversity);
|
||||
void StopElectricBolt();
|
||||
void Update(int currentTime);
|
||||
|
||||
const idDeclElectricBolt* eboltDecl;
|
||||
idRenderModelBeam* beamModel;
|
||||
idStaticList<eboltControlNode_t, 32> controlNodes;
|
||||
int startTime;
|
||||
int diversity;
|
||||
};
|
||||
|
||||
static_assert(sizeof(eboltControlNode_t) == 24,
|
||||
"Recovered electric-bolt control-node ABI changed");
|
||||
static_assert(sizeof(boltStats_t) == 28,
|
||||
"Recovered electric-bolt statistics ABI changed");
|
||||
static_assert(sizeof(segment_t) == 28,
|
||||
"Recovered electric-bolt segment ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idElectricBolt) == 800,
|
||||
"Recovered idElectricBolt ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,738 @@
|
||||
#include "gamelib/effects/fxmanager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
int GameLib_GetFXDeclActionCount(const idDeclFX* decl);
|
||||
int GameLib_GetFXDeclChangeId(const idDeclFX* decl);
|
||||
const char* GameLib_GetFXDeclName(const idDeclFX* decl);
|
||||
bool GameLib_GetFXActionParameters(const idDeclFX* decl, int actionIndex,
|
||||
idFXActionParameters& parameters);
|
||||
void GameLib_CreateFXActionResource(idGameLibEffects* effects,
|
||||
idRenderWorld* renderWorld, const idFXActionParameters& parameters,
|
||||
idFXAction& action);
|
||||
void GameLib_StartFXActionResource(idGameLibEffects* effects,
|
||||
const idFXActionParameters& parameters, idFXAction& action,
|
||||
const idVec3& origin, const idMat3& axis, int time);
|
||||
void GameLib_UpdateFXActionResource(idGameLibEffects* effects,
|
||||
const idFXActionParameters& parameters, idFXAction& action,
|
||||
const idVec3& origin, const idMat3& axis, const idVec3& velocity,
|
||||
const idVec4& color, int time, int frameNumber, float fovScale,
|
||||
float depthHack);
|
||||
void GameLib_StopFXActionResource(idGameLibEffects* effects,
|
||||
const idFXActionParameters& parameters, idFXAction& action,
|
||||
int time, bool immediate, bool recycleResources);
|
||||
void GameLib_FreeFXActionResource(idGameLibEffects* effects,
|
||||
const idFXActionParameters& parameters, idFXAction& action);
|
||||
void GameLib_EnumerateFXActionTags(idTreeAnimator* animator,
|
||||
const idDeclFX* decl, int actionIndex, idList<tagData_t, 109>& tags);
|
||||
bool GameLib_GetFXTagVelocity(idTreeAnimator* animator, const tagData_t& tag,
|
||||
int gameMsPerFrame, idVec3& velocity);
|
||||
idVec4 GameLib_GetFXRenderParm(const idDeclRenderParm* parameter);
|
||||
idVec4 GameLib_GetFXTableColor(const idFXSingleAction& action,
|
||||
float fraction);
|
||||
idList<idViewCallbacks*, 109>* GameLib_GetFXViewCallbacks();
|
||||
int GameLib_StartFXSound(idSoundEmitter* emitter, soundChannel_t channel,
|
||||
const idSoundShader* shader);
|
||||
void GameLib_SerializeFXManager(idSerializer& serializer,
|
||||
idFXManager& manager);
|
||||
|
||||
idRenderModelParticle* GameLib_AllocParticleFxModel(idRenderWorld* renderWorld,
|
||||
const idDeclParticle* particleDecl);
|
||||
void GameLib_FreeParticleFxModel(idRenderModelParticle* model);
|
||||
idRenderModel* GameLib_AllocStaticFxModel(idRenderWorld* renderWorld,
|
||||
const char* modelName);
|
||||
void GameLib_FreeStaticFxModel(idRenderModel* model);
|
||||
|
||||
namespace {
|
||||
|
||||
int PointerKey(const void* pointer) {
|
||||
return static_cast<int>(reinterpret_cast<std::uintptr_t>(pointer) >> 4);
|
||||
}
|
||||
|
||||
float RandomRange(idRandom2& random, const idVec2& range) {
|
||||
return range.x + (range.y - range.x) * random.RandomFloat();
|
||||
}
|
||||
|
||||
float Clamp01(const float value) {
|
||||
return (std::max)(0.0f, (std::min)(1.0f, value));
|
||||
}
|
||||
|
||||
void ResetState(fxActionState_t& state) {
|
||||
state.startDelay = 0;
|
||||
state.startTime = -1;
|
||||
state.stopTime = 0;
|
||||
state.hidden = false;
|
||||
state.started = false;
|
||||
state.shouldTrigger = false;
|
||||
state.forceStop = false;
|
||||
state.fadeInStartTime = -1;
|
||||
state.fadeInEndTime = 0;
|
||||
state.fadeOutStartTime = 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
idFXModelRecycler::idFXModelRecycler()
|
||||
: fxPrtModels()
|
||||
, activePrtModelHash(256, 256)
|
||||
, inactivePrtModelHash(256, 256)
|
||||
, fxStaticModels()
|
||||
, activeStaticModelHash(64, 64)
|
||||
, inactiveStaticModelHash(64, 64) {
|
||||
}
|
||||
|
||||
idFXModelRecycler::~idFXModelRecycler() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void idFXModelRecycler::Init() {
|
||||
Shutdown();
|
||||
activePrtModelHash.Clear();
|
||||
inactivePrtModelHash.Clear();
|
||||
activeStaticModelHash.Clear();
|
||||
inactiveStaticModelHash.Clear();
|
||||
}
|
||||
|
||||
void idFXModelRecycler::Shutdown() {
|
||||
for (int index = 0; index < fxPrtModels.Num(); ++index) {
|
||||
if (fxPrtModels[index].pmodel != nullptr) {
|
||||
GameLib_FreeParticleFxModel(fxPrtModels[index].pmodel);
|
||||
}
|
||||
}
|
||||
for (int index = 0; index < fxStaticModels.Num(); ++index) {
|
||||
if (fxStaticModels[index].rmodel != nullptr) {
|
||||
GameLib_FreeStaticFxModel(fxStaticModels[index].rmodel);
|
||||
}
|
||||
}
|
||||
fxPrtModels.Clear();
|
||||
fxStaticModels.Clear();
|
||||
activePrtModelHash.Clear();
|
||||
inactivePrtModelHash.Clear();
|
||||
activeStaticModelHash.Clear();
|
||||
inactiveStaticModelHash.Clear();
|
||||
}
|
||||
|
||||
idRenderModelParticle* idFXModelRecycler::GetParticleFxModel(
|
||||
const idDeclParticle* const particleDecl,
|
||||
idRenderWorld* const renderWorld) {
|
||||
if (particleDecl == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const int key = PointerKey(particleDecl);
|
||||
for (int index = inactivePrtModelHash.First(key); index >= 0;
|
||||
index = inactivePrtModelHash.Next(index)) {
|
||||
if (index < fxPrtModels.Num() &&
|
||||
fxPrtModels[index].pDecl == particleDecl) {
|
||||
inactivePrtModelHash.Remove(key, index);
|
||||
activePrtModelHash.Add(key, index);
|
||||
return fxPrtModels[index].pmodel;
|
||||
}
|
||||
}
|
||||
if (fxPrtModels.Num() >= fxPrtModels.Max()) {
|
||||
return nullptr;
|
||||
}
|
||||
fxPrtModel_t item{};
|
||||
item.pDecl = particleDecl;
|
||||
item.pmodel = GameLib_AllocParticleFxModel(renderWorld, particleDecl);
|
||||
if (item.pmodel == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const int index = fxPrtModels.Append(item);
|
||||
activePrtModelHash.Add(key, index);
|
||||
return item.pmodel;
|
||||
}
|
||||
|
||||
void idFXModelRecycler::RecycleParticleFxModel(
|
||||
const idDeclParticle* const particleDecl,
|
||||
idRenderModelParticle* const model) {
|
||||
if (particleDecl == nullptr || model == nullptr) {
|
||||
return;
|
||||
}
|
||||
const int key = PointerKey(particleDecl);
|
||||
for (int index = activePrtModelHash.First(key); index >= 0;
|
||||
index = activePrtModelHash.Next(index)) {
|
||||
if (index < fxPrtModels.Num() &&
|
||||
fxPrtModels[index].pmodel == model) {
|
||||
activePrtModelHash.Remove(key, index);
|
||||
inactivePrtModelHash.Add(key, index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idRenderModel* idFXModelRecycler::GetStaticFxModel(
|
||||
const idAtomicString& modelName, idRenderWorld* const renderWorld) {
|
||||
if (modelName.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
const int key = inactiveStaticModelHash.GenerateKeyForString(
|
||||
modelName.c_str(), false);
|
||||
for (int index = inactiveStaticModelHash.First(key); index >= 0;
|
||||
index = inactiveStaticModelHash.Next(index)) {
|
||||
if (index < fxStaticModels.Num() &&
|
||||
fxStaticModels[index].modelName == modelName) {
|
||||
inactiveStaticModelHash.Remove(key, index);
|
||||
activeStaticModelHash.Add(key, index);
|
||||
return fxStaticModels[index].rmodel;
|
||||
}
|
||||
}
|
||||
if (fxStaticModels.Num() >= fxStaticModels.Max()) {
|
||||
return nullptr;
|
||||
}
|
||||
fxStaticModel_t item{};
|
||||
item.modelName = modelName;
|
||||
item.rmodel = GameLib_AllocStaticFxModel(renderWorld, modelName.c_str());
|
||||
if (item.rmodel == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const int index = fxStaticModels.Append(item);
|
||||
activeStaticModelHash.Add(key, index);
|
||||
return item.rmodel;
|
||||
}
|
||||
|
||||
void idFXModelRecycler::RecycleStaticFxModel(
|
||||
const idAtomicString& modelName, idRenderModel* const model) {
|
||||
if (modelName.IsEmpty() || model == nullptr) {
|
||||
return;
|
||||
}
|
||||
const int key = activeStaticModelHash.GenerateKeyForString(
|
||||
modelName.c_str(), false);
|
||||
for (int index = activeStaticModelHash.First(key); index >= 0;
|
||||
index = activeStaticModelHash.Next(index)) {
|
||||
if (index < fxStaticModels.Num() &&
|
||||
fxStaticModels[index].rmodel == model) {
|
||||
activeStaticModelHash.Remove(key, index);
|
||||
inactiveStaticModelHash.Add(key, index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idFXAction::idFXAction()
|
||||
: tagIndex(0)
|
||||
, startOrg()
|
||||
, startAxis(1.0f)
|
||||
, rLight(nullptr)
|
||||
, rModel(nullptr)
|
||||
, rParticle(nullptr)
|
||||
, screenPrtHandle(-1)
|
||||
, flareManager()
|
||||
, ribbonManager()
|
||||
, tagData(4)
|
||||
, lastParticleDropPos()
|
||||
, renderParmStartValue(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
, randomAngles(0.0f, 0.0f, 0.0f)
|
||||
, viewCallbacksID(-1) {
|
||||
startOrg.Zero();
|
||||
lastParticleDropPos.Zero();
|
||||
}
|
||||
|
||||
idFXManager::idFXManager()
|
||||
: initialized(false)
|
||||
, fxDecl(nullptr)
|
||||
, gameLibEffects(nullptr)
|
||||
, ta(nullptr)
|
||||
, rw(nullptr)
|
||||
, systemColor(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
, random(0)
|
||||
, soundInfo{nullptr, SND_CHANNEL_ANY}
|
||||
, actions(4)
|
||||
, actionState(4)
|
||||
, remote(false)
|
||||
, allowSurfaceOnlyInViewID(0)
|
||||
, suppressSurfaceInViewID(0)
|
||||
, viewCallbacksID(-1)
|
||||
, declChangeId(-1)
|
||||
, externalRotation(1.0f)
|
||||
, externalPosition()
|
||||
, hasExternalPositionAndRotation(false)
|
||||
, actionBuffer{}
|
||||
, actionBufferPos(0)
|
||||
, serializeActionCount(0) {
|
||||
externalPosition.Zero();
|
||||
}
|
||||
|
||||
idFXManager::~idFXManager() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
idVec4 idFXManager::GetVector(const idDeclRenderParm* const parameter) const {
|
||||
return parameter != nullptr ? GameLib_GetFXRenderParm(parameter)
|
||||
: idVec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
idVec4 idFXManager::GetTableColor(const idFXSingleAction& action,
|
||||
const float fraction) const {
|
||||
return GameLib_GetFXTableColor(action, fraction);
|
||||
}
|
||||
|
||||
bool idFXManager::GetWorldSpaceTagVelocity(const tagData_t& tag,
|
||||
const int gameMsPerFrame, idVec3& velocity) {
|
||||
velocity.Zero();
|
||||
return ta != nullptr && gameMsPerFrame > 0 &&
|
||||
GameLib_GetFXTagVelocity(ta, tag, gameMsPerFrame, velocity);
|
||||
}
|
||||
|
||||
int idFXManager::StartSound(const soundChannel_t channel,
|
||||
const idSoundShader* const shader) {
|
||||
if (soundInfo.emitter == nullptr || shader == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
const soundChannel_t resolved = channel == SND_CHANNEL_ANY
|
||||
? soundInfo.channel : channel;
|
||||
return GameLib_StartFXSound(soundInfo.emitter, resolved, shader);
|
||||
}
|
||||
|
||||
idList<idViewCallbacks*, 109>& idFXManager::GetViewCallbacks() {
|
||||
idList<idViewCallbacks*, 109>* callbacks = GameLib_GetFXViewCallbacks();
|
||||
if (callbacks != nullptr) {
|
||||
return *callbacks;
|
||||
}
|
||||
static idList<idViewCallbacks*, 109> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
const char* idFXManager::GetName() const {
|
||||
return fxDecl != nullptr ? GameLib_GetFXDeclName(fxDecl) : "";
|
||||
}
|
||||
|
||||
bool idFXManager::IsStopped(const int time) const {
|
||||
for (int index = 0; index < actionState.Num(); ++index) {
|
||||
if (time < actionState[index].stopTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void idFXManager::Init(const idDeclFX* const declFX,
|
||||
idRenderWorld* const renderWorld,
|
||||
const fxEmitterSound_t* const emitterSound,
|
||||
idGameLibEffects* const effects, const float diversity,
|
||||
idTreeAnimator* const treeAnimator) {
|
||||
Shutdown();
|
||||
if (declFX == nullptr) {
|
||||
return;
|
||||
}
|
||||
fxDecl = declFX;
|
||||
gameLibEffects = effects;
|
||||
ta = treeAnimator;
|
||||
rw = renderWorld;
|
||||
random.SetSeed(static_cast<unsigned int>(diversity * 65535.0f));
|
||||
if (emitterSound != nullptr) {
|
||||
soundInfo = *emitterSound;
|
||||
}
|
||||
const int count = (std::max)(0, GameLib_GetFXDeclActionCount(fxDecl));
|
||||
actions.SetNum(count);
|
||||
actionState.SetNum(count);
|
||||
declChangeId = GameLib_GetFXDeclChangeId(fxDecl);
|
||||
for (int index = 0; index < count; ++index) {
|
||||
CreateAction(index, rw);
|
||||
}
|
||||
EnumerateTags();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void idFXManager::CreateAction(const int index,
|
||||
idRenderWorld* const renderWorld) {
|
||||
if (index < 0 || index >= actions.Num()) {
|
||||
return;
|
||||
}
|
||||
ResetState(actionState[index]);
|
||||
idFXActionParameters parameters{};
|
||||
if (GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
GameLib_CreateFXActionResource(gameLibEffects, renderWorld,
|
||||
parameters, actions[index]);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::EnumerateTags() {
|
||||
if (ta == nullptr) {
|
||||
return;
|
||||
}
|
||||
for (int index = 0; index < actions.Num(); ++index) {
|
||||
actions[index].tagData.Clear();
|
||||
GameLib_EnumerateFXActionTags(ta, fxDecl, index,
|
||||
actions[index].tagData);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::StartAction(const int index, const idVec3& origin,
|
||||
const idMat3& axis, const int time, const int explicitTagIndex) {
|
||||
if (index < 0 || index >= actions.Num()) {
|
||||
return;
|
||||
}
|
||||
idFXActionParameters parameters{};
|
||||
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
return;
|
||||
}
|
||||
idFXAction& action = actions[index];
|
||||
fxActionState_t& state = actionState[index];
|
||||
action.startOrg = origin;
|
||||
action.startAxis = axis;
|
||||
action.tagIndex = explicitTagIndex >= 0 ? explicitTagIndex : 0;
|
||||
if (explicitTagIndex < 0 && action.tagData.Num() > 1) {
|
||||
action.tagIndex = random.RandomInt(action.tagData.Num());
|
||||
}
|
||||
action.randomAngles = idAngles(
|
||||
RandomRange(random, parameters.randomRotationX),
|
||||
RandomRange(random, parameters.randomRotationY),
|
||||
RandomRange(random, parameters.randomRotationZ));
|
||||
state.startDelay = static_cast<int>(RandomRange(random,
|
||||
parameters.delay) * 1000.0f);
|
||||
state.startTime = time;
|
||||
state.stopTime = time + state.startDelay +
|
||||
static_cast<int>(parameters.duration * 1000.0f);
|
||||
state.fadeInStartTime = time + state.startDelay;
|
||||
state.fadeInEndTime = state.fadeInStartTime +
|
||||
static_cast<int>(parameters.fadeInTime * 1000.0f);
|
||||
state.fadeOutStartTime = state.stopTime -
|
||||
static_cast<int>(parameters.fadeOutTime * 1000.0f);
|
||||
state.hidden = false;
|
||||
state.started = false;
|
||||
state.shouldTrigger = true;
|
||||
state.forceStop = false;
|
||||
}
|
||||
|
||||
int idFXManager::StartActions(const idVec3& origin, const idMat3& axis,
|
||||
const int time, const fxCondition_t startCondition,
|
||||
const fxExtraCondition_t extraCondition, const int explicitTagIndex) {
|
||||
int startedCount = 0;
|
||||
for (int index = 0; index < actions.Num(); ++index) {
|
||||
idFXActionParameters parameters{};
|
||||
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
continue;
|
||||
}
|
||||
if (parameters.startCondition != startCondition) {
|
||||
continue;
|
||||
}
|
||||
if (parameters.extraCondition != FX_EXTRA_COND_NONE &&
|
||||
(static_cast<int>(parameters.extraCondition) &
|
||||
static_cast<int>(extraCondition)) == 0) {
|
||||
continue;
|
||||
}
|
||||
StartAction(index, origin, axis, time, explicitTagIndex);
|
||||
++startedCount;
|
||||
}
|
||||
return startedCount;
|
||||
}
|
||||
|
||||
int idFXManager::InternalStartFX(const fxActionCall_t& actionCall) {
|
||||
if (!initialized) {
|
||||
return 0;
|
||||
}
|
||||
const int result = StartActions(actionCall.org, actionCall.axis,
|
||||
actionCall.time, actionCall.condition, actionCall.extraCondition,
|
||||
actionCall.tagIdx);
|
||||
++actionBufferPos;
|
||||
return result;
|
||||
}
|
||||
|
||||
int idFXManager::StartFX(const idVec3& origin, const idMat3& axis,
|
||||
const int time, const fxCondition_t startCondition,
|
||||
const int explicitTagIndex, const int delay) {
|
||||
if (!initialized) {
|
||||
return 0;
|
||||
}
|
||||
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
|
||||
call.org = origin;
|
||||
call.axis = axis;
|
||||
call.condition = startCondition;
|
||||
call.time = time + delay;
|
||||
call.extraCondition = FX_EXTRA_COND_NONE;
|
||||
call.tagIdx = explicitTagIndex;
|
||||
call.actionType = FXACTION_START;
|
||||
call.immediate = false;
|
||||
call.viewCallbacksID = viewCallbacksID;
|
||||
return InternalStartFX(call);
|
||||
}
|
||||
|
||||
int idFXManager::StartFX(const idVec3& origin, const idMat3& axis,
|
||||
const int time, const fxCondition_t startCondition,
|
||||
const fxExtraCondition_t extraCondition) {
|
||||
if (!initialized) {
|
||||
return 0;
|
||||
}
|
||||
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
|
||||
call.org = origin;
|
||||
call.axis = axis;
|
||||
call.condition = startCondition;
|
||||
call.time = time;
|
||||
call.extraCondition = extraCondition;
|
||||
call.tagIdx = -1;
|
||||
call.actionType = FXACTION_START;
|
||||
call.immediate = false;
|
||||
call.viewCallbacksID = viewCallbacksID;
|
||||
return InternalStartFX(call);
|
||||
}
|
||||
|
||||
int idFXManager::StartFX(const idVec3& origin, const idMat3& axis,
|
||||
const int time, const fxCondition_t startCondition) {
|
||||
return StartFX(origin, axis, time, startCondition, -1, 0);
|
||||
}
|
||||
|
||||
void idFXManager::LocalStartFX(const idVec3& origin, const idMat3& axis,
|
||||
const int time, const fxCondition_t startCondition) {
|
||||
if (initialized) {
|
||||
StartActions(origin, axis, time, startCondition,
|
||||
FX_EXTRA_COND_NONE, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::ApplyFade(const idFXActionParameters& parameters,
|
||||
idFXAction& action, fxActionState_t& state, const int time,
|
||||
const float fraction) {
|
||||
float fade = 1.0f;
|
||||
if (parameters.fadeInTime > 0.0f && time < state.fadeInEndTime) {
|
||||
const int duration = state.fadeInEndTime - state.fadeInStartTime;
|
||||
fade *= duration > 0 ? Clamp01(static_cast<float>(
|
||||
time - state.fadeInStartTime) / duration) : 1.0f;
|
||||
}
|
||||
if (parameters.fadeOutTime > 0.0f && time >= state.fadeOutStartTime) {
|
||||
const int duration = state.stopTime - state.fadeOutStartTime;
|
||||
fade *= duration > 0 ? Clamp01(static_cast<float>(
|
||||
state.stopTime - time) / duration) : 0.0f;
|
||||
}
|
||||
action.renderParmStartValue = idVec4(
|
||||
systemColor.x * fade, systemColor.y * fade,
|
||||
systemColor.z * fade, systemColor.w * fade * Clamp01(fraction));
|
||||
}
|
||||
|
||||
void idFXManager::RestartAction(const int index, const int time) {
|
||||
if (index < 0 || index >= actions.Num()) {
|
||||
return;
|
||||
}
|
||||
const idVec3 origin = actions[index].startOrg;
|
||||
const idMat3 axis = actions[index].startAxis;
|
||||
StopAction(index, time, true, false);
|
||||
StartAction(index, origin, axis, time, actions[index].tagIndex);
|
||||
}
|
||||
|
||||
void idFXManager::StopAction(const int index, const int time,
|
||||
const bool immediate, const bool recycleResources) {
|
||||
if (index < 0 || index >= actions.Num()) {
|
||||
return;
|
||||
}
|
||||
idFXActionParameters parameters{};
|
||||
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
return;
|
||||
}
|
||||
fxActionState_t& state = actionState[index];
|
||||
if (state.startTime < 0) {
|
||||
return;
|
||||
}
|
||||
if (!immediate && !state.forceStop && parameters.fadeOutTime > 0.0f &&
|
||||
parameters.type != FX_SOUND) {
|
||||
state.fadeOutStartTime = time;
|
||||
state.stopTime = time + static_cast<int>(
|
||||
parameters.fadeOutTime * 1000.0f);
|
||||
state.forceStop = true;
|
||||
return;
|
||||
}
|
||||
if (parameters.type == FX_FLARE) {
|
||||
actions[index].flareManager.StopFlare();
|
||||
} else if (parameters.type == FX_RIBBON) {
|
||||
actions[index].ribbonManager.StopRibbon();
|
||||
}
|
||||
GameLib_StopFXActionResource(gameLibEffects, parameters, actions[index],
|
||||
time, immediate, recycleResources);
|
||||
const bool keepHidden = parameters.triggered;
|
||||
ResetState(state);
|
||||
state.hidden = keepHidden;
|
||||
actions[index].lastParticleDropPos.Zero();
|
||||
actions[index].randomAngles = idAngles(0.0f, 0.0f, 0.0f);
|
||||
actions[index].startAxis = idMat3(1.0f);
|
||||
actions[index].startOrg.Zero();
|
||||
}
|
||||
|
||||
void idFXManager::StopActions(const int time,
|
||||
const fxCondition_t stopCondition,
|
||||
const fxExtraCondition_t extraCondition, const bool stopAll,
|
||||
const bool immediate) {
|
||||
for (int index = 0; index < actions.Num(); ++index) {
|
||||
idFXActionParameters parameters{};
|
||||
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
continue;
|
||||
}
|
||||
if (!stopAll && parameters.stopCondition != stopCondition) {
|
||||
continue;
|
||||
}
|
||||
if (!stopAll && parameters.extraCondition != FX_EXTRA_COND_NONE &&
|
||||
(static_cast<int>(parameters.extraCondition) &
|
||||
static_cast<int>(extraCondition)) == 0) {
|
||||
continue;
|
||||
}
|
||||
StopAction(index, time, immediate, true);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::InternalStopFX(const fxActionCall_t& actionCall) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
StopActions(actionCall.time, actionCall.condition,
|
||||
actionCall.extraCondition,
|
||||
actionCall.actionType == FXACTION_STOP_ALL, actionCall.immediate);
|
||||
++actionBufferPos;
|
||||
}
|
||||
|
||||
void idFXManager::StopFX(const int time,
|
||||
const fxCondition_t stopCondition, const bool immediate) {
|
||||
StopFX(time, stopCondition, FX_EXTRA_COND_NONE, immediate);
|
||||
}
|
||||
|
||||
void idFXManager::StopFX(const int time,
|
||||
const fxCondition_t stopCondition,
|
||||
const fxExtraCondition_t extraCondition, const bool immediate) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
|
||||
call.condition = stopCondition;
|
||||
call.time = time;
|
||||
call.extraCondition = extraCondition;
|
||||
call.actionType = FXACTION_STOP;
|
||||
call.immediate = immediate;
|
||||
call.viewCallbacksID = viewCallbacksID;
|
||||
InternalStopFX(call);
|
||||
}
|
||||
|
||||
void idFXManager::LocalStopFX(const int time,
|
||||
const fxCondition_t stopCondition, const bool immediate) {
|
||||
if (initialized) {
|
||||
StopActions(time, stopCondition, FX_EXTRA_COND_NONE, false,
|
||||
immediate);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::StopAllFX(const int time, const bool immediate) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
|
||||
call.condition = FX_NONE;
|
||||
call.time = time;
|
||||
call.extraCondition = FX_EXTRA_COND_NONE;
|
||||
call.actionType = FXACTION_STOP_ALL;
|
||||
call.immediate = immediate;
|
||||
call.viewCallbacksID = viewCallbacksID;
|
||||
InternalStopFX(call);
|
||||
}
|
||||
|
||||
void idFXManager::LocalStopAllFX(const int time, const bool immediate) {
|
||||
if (initialized) {
|
||||
StopActions(time, FX_NONE, FX_EXTRA_COND_NONE, true, immediate);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::UpdateActions(const idVec3& origin, const idMat3& axis,
|
||||
const idVec3& velocity, const int time, const int gameMsPerFrame,
|
||||
const int frameNumber, const float fovScale, const float depthHack) {
|
||||
(void)gameMsPerFrame;
|
||||
for (int index = 0; index < actions.Num(); ++index) {
|
||||
idFXActionParameters parameters{};
|
||||
if (!GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
continue;
|
||||
}
|
||||
fxActionState_t& state = actionState[index];
|
||||
idFXAction& action = actions[index];
|
||||
if (state.startTime < 0 || state.hidden) {
|
||||
continue;
|
||||
}
|
||||
const int actualStart = state.startTime + state.startDelay;
|
||||
if (time < actualStart) {
|
||||
continue;
|
||||
}
|
||||
if (!state.started) {
|
||||
GameLib_StartFXActionResource(gameLibEffects, parameters, action,
|
||||
action.startOrg, action.startAxis, actualStart);
|
||||
if (parameters.type == FX_SOUND) {
|
||||
StartSound(parameters.soundChannel, parameters.sound);
|
||||
}
|
||||
state.started = true;
|
||||
}
|
||||
if (time >= state.stopTime) {
|
||||
if (parameters.looping && !state.forceStop) {
|
||||
RestartAction(index, time + static_cast<int>(
|
||||
parameters.restart * 1000.0f));
|
||||
} else {
|
||||
StopAction(index, time, true, true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const int duration = (std::max)(1, state.stopTime - actualStart);
|
||||
const float fraction = Clamp01(static_cast<float>(time - actualStart) /
|
||||
static_cast<float>(duration));
|
||||
ApplyFade(parameters, action, state, time, fraction);
|
||||
const idVec3 updateOrigin = parameters.trackOrigin ? origin
|
||||
: action.startOrg;
|
||||
const idMat3 updateAxis = parameters.trackOrigin ? axis
|
||||
: action.startAxis;
|
||||
GameLib_UpdateFXActionResource(gameLibEffects, parameters, action,
|
||||
updateOrigin, updateAxis, velocity, action.renderParmStartValue,
|
||||
time, frameNumber, fovScale, depthHack);
|
||||
}
|
||||
}
|
||||
|
||||
void idFXManager::Update(const idVec3& parentOrigin,
|
||||
const idMat3& parentAxis, const idVec3& parentVelocity, const int time,
|
||||
const int gameMsPerFrame, const int frameNumber, const float fovScale,
|
||||
const float depthHack) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
while (serializeActionCount > 0) {
|
||||
--serializeActionCount;
|
||||
fxActionCall_t& call = actionBuffer[actionBufferPos % 8];
|
||||
call.time = time;
|
||||
viewCallbacksID = call.viewCallbacksID;
|
||||
if (call.actionType == FXACTION_START) {
|
||||
InternalStartFX(call);
|
||||
} else {
|
||||
InternalStopFX(call);
|
||||
}
|
||||
}
|
||||
UpdateActions(parentOrigin, parentAxis, parentVelocity, time,
|
||||
gameMsPerFrame, frameNumber, fovScale, depthHack);
|
||||
}
|
||||
|
||||
void idFXManager::ResetTreeAnimator(idTreeAnimator* const treeAnimator) {
|
||||
ta = treeAnimator;
|
||||
EnumerateTags();
|
||||
}
|
||||
|
||||
void idFXManager::Serialize(idSerializer& serializer) {
|
||||
GameLib_SerializeFXManager(serializer, *this);
|
||||
}
|
||||
|
||||
void idFXManager::FreeActions() {
|
||||
for (int index = 0; index < actions.Num(); ++index) {
|
||||
idFXActionParameters parameters{};
|
||||
if (GameLib_GetFXActionParameters(fxDecl, index, parameters)) {
|
||||
GameLib_FreeFXActionResource(gameLibEffects, parameters,
|
||||
actions[index]);
|
||||
}
|
||||
actions[index].tagData.Clear();
|
||||
}
|
||||
actions.Clear();
|
||||
actionState.Clear();
|
||||
}
|
||||
|
||||
void idFXManager::Shutdown() {
|
||||
if (fxDecl != nullptr) {
|
||||
StopActions(0, FX_NONE, FX_EXTRA_COND_NONE, true, true);
|
||||
FreeActions();
|
||||
}
|
||||
initialized = false;
|
||||
fxDecl = nullptr;
|
||||
gameLibEffects = nullptr;
|
||||
ta = nullptr;
|
||||
rw = nullptr;
|
||||
soundInfo.emitter = nullptr;
|
||||
soundInfo.channel = SND_CHANNEL_ANY;
|
||||
declChangeId = -1;
|
||||
actionBufferPos = 0;
|
||||
serializeActionCount = 0;
|
||||
}
|
||||
@@ -1,66 +1,273 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\effects\fxmanager.h
|
||||
// Recovered logical types: 4
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/effects/lensflaremanager.h"
|
||||
#include "gamelib/effects/ribbonmanager.h"
|
||||
#include "idlib/containers/hashindex.h"
|
||||
#include "idlib/containers/list.h"
|
||||
#include "idlib/containers/staticlist.h"
|
||||
#include "idlib/math/random.h"
|
||||
#include "idlib/math/vector.h"
|
||||
#include "idlib/text/atomicstring.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// IDA Local Type ordinal 2791; PDB kind: enum.
|
||||
enum idFXManager::fxActionCallType_t : __int32
|
||||
{
|
||||
FXACTION_START = 0x0,
|
||||
FXACTION_STOP = 0x1,
|
||||
FXACTION_STOP_ALL = 0x2,
|
||||
FXACTION_MAX = 0x3,
|
||||
class idDeclFX;
|
||||
class idDeclParticle;
|
||||
class idDeclRenderParm;
|
||||
class idDeclTable;
|
||||
class idFXSingleAction;
|
||||
class idGameLibEffects;
|
||||
class idMaterial;
|
||||
class idRenderLight;
|
||||
class idRenderModel;
|
||||
class idRenderModelParticle;
|
||||
class idRenderWorld;
|
||||
class idSerializer;
|
||||
class idSoundEmitter;
|
||||
class idSoundShader;
|
||||
class idTreeAnimator;
|
||||
class idViewCallbacks;
|
||||
|
||||
enum fxCondition_t : int {
|
||||
FX_NONE = 0
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14217; PDB kind: struct.
|
||||
struct idFXManager::fxActionCall_t
|
||||
{
|
||||
idVec3 org;
|
||||
idMat3 axis;
|
||||
fxCondition_t condition;
|
||||
int time;
|
||||
fxExtraCondition_t extraCondition;
|
||||
int tagIdx;
|
||||
idFXManager::fxActionCallType_t actionType;
|
||||
bool immediate;
|
||||
int viewCallbacksID;
|
||||
enum fxExtraCondition_t : int {
|
||||
FX_EXTRA_COND_NONE = 0,
|
||||
FX_EXTRA_COND_MAX = 0x10000
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14218; PDB kind: class.
|
||||
class idFXManager
|
||||
{
|
||||
enum soundChannel_t : int {
|
||||
SND_CHANNEL_ANY = 0
|
||||
};
|
||||
|
||||
enum fxActionType_t : int {
|
||||
FX_LIGHT = 0,
|
||||
FX_PARTICLE,
|
||||
FX_DECAL2,
|
||||
FX_MODEL,
|
||||
FX_SOUND,
|
||||
FX_SCREEN_SHAKE,
|
||||
FX_CONTROLLER_SHAKE,
|
||||
FX_ENV_OVERRIDE,
|
||||
FX_ENV_CHANGE,
|
||||
FX_FLARE,
|
||||
FX_RIBBON,
|
||||
FX_OTHER
|
||||
};
|
||||
|
||||
struct tagData_t {
|
||||
idVec3 trans;
|
||||
idQuat rot;
|
||||
std::uint16_t parentJoint;
|
||||
};
|
||||
|
||||
struct fxEmitterSound_t {
|
||||
idSoundEmitter* emitter;
|
||||
soundChannel_t channel;
|
||||
};
|
||||
|
||||
// Stable PC-side view of the fields the recovered state machine reads from
|
||||
// each idFXSingleAction. The declaration system fills this view.
|
||||
struct idFXActionParameters {
|
||||
fxActionType_t type;
|
||||
fxCondition_t startCondition;
|
||||
fxCondition_t stopCondition;
|
||||
fxExtraCondition_t extraCondition;
|
||||
idVec2 delay;
|
||||
float duration;
|
||||
float fadeInTime;
|
||||
float fadeOutTime;
|
||||
float restart;
|
||||
bool looping;
|
||||
bool triggered;
|
||||
bool trackOrigin;
|
||||
bool bindOrigin;
|
||||
bool bindAxis;
|
||||
idVec2 randomRotationX;
|
||||
idVec2 randomRotationY;
|
||||
idVec2 randomRotationZ;
|
||||
const idDeclParticle* particleDecl;
|
||||
idAtomicString modelName;
|
||||
const idSoundShader* sound;
|
||||
soundChannel_t soundChannel;
|
||||
};
|
||||
|
||||
class idFXModelRecycler {
|
||||
public:
|
||||
bool initialized;
|
||||
const idDeclFX *fxDecl;
|
||||
idGameLibEffects *gameLibEffects;
|
||||
idTreeAnimator *ta;
|
||||
idRenderWorld *rw;
|
||||
idVec4 systemColor;
|
||||
idRandom2 random;
|
||||
fxEmitterSound_t soundInfo;
|
||||
idList<idFXAction,109> actions;
|
||||
idList<fxActionState_t,109> actionState;
|
||||
bool remote;
|
||||
int allowSurfaceOnlyInViewID;
|
||||
int suppressSurfaceInViewID;
|
||||
int viewCallbacksID;
|
||||
int declChangeId;
|
||||
idMat3 externalRotation;
|
||||
idVec3 externalPosition;
|
||||
bool hasExternalPositionAndRotation;
|
||||
idFXManager::fxActionCall_t actionBuffer[8];
|
||||
int actionBufferPos;
|
||||
int serializeActionCount;
|
||||
struct fxPrtModel_t {
|
||||
idRenderModelParticle* pmodel;
|
||||
const idDeclParticle* pDecl;
|
||||
};
|
||||
struct fxStaticModel_t {
|
||||
idRenderModel* rmodel;
|
||||
idAtomicString modelName;
|
||||
};
|
||||
|
||||
idFXModelRecycler();
|
||||
~idFXModelRecycler();
|
||||
void Init();
|
||||
void Shutdown();
|
||||
idRenderModelParticle* GetParticleFxModel(
|
||||
const idDeclParticle* particleDecl, idRenderWorld* renderWorld);
|
||||
void RecycleParticleFxModel(const idDeclParticle* particleDecl,
|
||||
idRenderModelParticle* model);
|
||||
idRenderModel* GetStaticFxModel(const idAtomicString& modelName,
|
||||
idRenderWorld* renderWorld);
|
||||
void RecycleStaticFxModel(const idAtomicString& modelName,
|
||||
idRenderModel* model);
|
||||
|
||||
idStaticList<fxPrtModel_t, 256> fxPrtModels;
|
||||
idHashIndex activePrtModelHash;
|
||||
idHashIndex inactivePrtModelHash;
|
||||
idStaticList<fxStaticModel_t, 64> fxStaticModels;
|
||||
idHashIndex activeStaticModelHash;
|
||||
idHashIndex inactiveStaticModelHash;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 23462; PDB kind: struct.
|
||||
struct __declspec(align(4)) idFXManager::UpdateActions::__l79::viewcallbackInfo_t
|
||||
{
|
||||
idVec3 viewOrg;
|
||||
idMat3 viewAxis;
|
||||
float distSQ;
|
||||
bool inRange;
|
||||
struct idFXAction {
|
||||
idFXAction();
|
||||
|
||||
int tagIndex;
|
||||
idVec3 startOrg;
|
||||
idMat3 startAxis;
|
||||
idRenderLight* rLight;
|
||||
idRenderModel* rModel;
|
||||
idRenderModelParticle* rParticle;
|
||||
int screenPrtHandle;
|
||||
idLensFlareManager flareManager;
|
||||
idRibbonManager ribbonManager;
|
||||
idList<tagData_t, 109> tagData;
|
||||
idVec3 lastParticleDropPos;
|
||||
idVec4 renderParmStartValue;
|
||||
idAngles randomAngles;
|
||||
int viewCallbacksID;
|
||||
};
|
||||
|
||||
struct fxActionState_t {
|
||||
int startDelay;
|
||||
int startTime;
|
||||
int stopTime;
|
||||
bool hidden;
|
||||
bool started;
|
||||
bool shouldTrigger;
|
||||
bool forceStop;
|
||||
int fadeInStartTime;
|
||||
int fadeInEndTime;
|
||||
int fadeOutStartTime;
|
||||
};
|
||||
|
||||
class idFXManager {
|
||||
public:
|
||||
enum fxActionCallType_t : int {
|
||||
FXACTION_START = 0,
|
||||
FXACTION_STOP = 1,
|
||||
FXACTION_STOP_ALL = 2,
|
||||
FXACTION_MAX = 3
|
||||
};
|
||||
|
||||
struct fxActionCall_t {
|
||||
idVec3 org;
|
||||
idMat3 axis;
|
||||
fxCondition_t condition;
|
||||
int time;
|
||||
fxExtraCondition_t extraCondition;
|
||||
int tagIdx;
|
||||
fxActionCallType_t actionType;
|
||||
bool immediate;
|
||||
int viewCallbacksID;
|
||||
};
|
||||
|
||||
idFXManager();
|
||||
~idFXManager();
|
||||
|
||||
void Init(const idDeclFX* declFX, idRenderWorld* renderWorld,
|
||||
const fxEmitterSound_t* soundInfo, idGameLibEffects* gameLibEffects,
|
||||
float diversity, idTreeAnimator* treeAnimator);
|
||||
void Shutdown();
|
||||
void Update(const idVec3& parentOrigin, const idMat3& parentAxis,
|
||||
const idVec3& parentVelocity, int time, int gameMsPerFrame,
|
||||
int frameNumber, float fovScale, float depthHack);
|
||||
int StartFX(const idVec3& origin, const idMat3& axis, int time,
|
||||
fxCondition_t startCondition, int explicitTagIndex, int delay);
|
||||
int StartFX(const idVec3& origin, const idMat3& axis, int time,
|
||||
fxCondition_t startCondition, fxExtraCondition_t extraCondition);
|
||||
int StartFX(const idVec3& origin, const idMat3& axis, int time,
|
||||
fxCondition_t startCondition);
|
||||
void LocalStartFX(const idVec3& origin, const idMat3& axis, int time,
|
||||
fxCondition_t startCondition);
|
||||
void StopFX(int time, fxCondition_t stopCondition, bool immediate);
|
||||
void StopFX(int time, fxCondition_t stopCondition,
|
||||
fxExtraCondition_t extraCondition, bool immediate);
|
||||
void LocalStopFX(int time, fxCondition_t stopCondition, bool immediate);
|
||||
void StopAllFX(int time, bool immediate);
|
||||
void LocalStopAllFX(int time, bool immediate);
|
||||
bool IsStopped(int time) const;
|
||||
const char* GetName() const;
|
||||
void ResetTreeAnimator(idTreeAnimator* treeAnimator);
|
||||
void Serialize(idSerializer& serializer);
|
||||
|
||||
bool initialized;
|
||||
const idDeclFX* fxDecl;
|
||||
idGameLibEffects* gameLibEffects;
|
||||
idTreeAnimator* ta;
|
||||
idRenderWorld* rw;
|
||||
idVec4 systemColor;
|
||||
idRandom2 random;
|
||||
fxEmitterSound_t soundInfo;
|
||||
idList<idFXAction, 109> actions;
|
||||
idList<fxActionState_t, 109> actionState;
|
||||
bool remote;
|
||||
int allowSurfaceOnlyInViewID;
|
||||
int suppressSurfaceInViewID;
|
||||
int viewCallbacksID;
|
||||
int declChangeId;
|
||||
idMat3 externalRotation;
|
||||
idVec3 externalPosition;
|
||||
bool hasExternalPositionAndRotation;
|
||||
fxActionCall_t actionBuffer[8];
|
||||
int actionBufferPos;
|
||||
int serializeActionCount;
|
||||
|
||||
private:
|
||||
idVec4 GetVector(const idDeclRenderParm* parameter) const;
|
||||
idVec4 GetTableColor(const idFXSingleAction& action, float fraction) const;
|
||||
bool GetWorldSpaceTagVelocity(const tagData_t& tag,
|
||||
int gameMsPerFrame, idVec3& velocity);
|
||||
int StartSound(soundChannel_t channel, const idSoundShader* shader);
|
||||
idList<idViewCallbacks*, 109>& GetViewCallbacks();
|
||||
void ApplyFade(const idFXActionParameters& parameters,
|
||||
idFXAction& action, fxActionState_t& state, int time, float fraction);
|
||||
void StopAction(int index, int time, bool immediate,
|
||||
bool recycleResources);
|
||||
void RestartAction(int index, int time);
|
||||
void StopActions(int time, fxCondition_t stopCondition,
|
||||
fxExtraCondition_t extraCondition, bool stopAll, bool immediate);
|
||||
void InternalStopFX(const fxActionCall_t& actionCall);
|
||||
void StartAction(int index, const idVec3& origin, const idMat3& axis,
|
||||
int time, int explicitTagIndex);
|
||||
void EnumerateTags();
|
||||
void UpdateActions(const idVec3& origin, const idMat3& axis,
|
||||
const idVec3& velocity, int time, int gameMsPerFrame,
|
||||
int frameNumber, float fovScale, float depthHack);
|
||||
int StartActions(const idVec3& origin, const idMat3& axis, int time,
|
||||
fxCondition_t startCondition, fxExtraCondition_t extraCondition,
|
||||
int explicitTagIndex);
|
||||
void CreateAction(int index, idRenderWorld* renderWorld);
|
||||
void FreeActions();
|
||||
int InternalStartFX(const fxActionCall_t& actionCall);
|
||||
};
|
||||
|
||||
static_assert(sizeof(tagData_t) == 32, "Recovered tagData_t ABI changed");
|
||||
static_assert(sizeof(fxEmitterSound_t) == 8,
|
||||
"Recovered FX emitter sound ABI changed");
|
||||
static_assert(sizeof(fxActionState_t) == 28,
|
||||
"Recovered FX action-state ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idFXAction) == 184,
|
||||
"Recovered idFXAction ABI changed");
|
||||
static_assert(sizeof(idFXManager::fxActionCall_t) == 76,
|
||||
"Recovered FX action-call ABI changed");
|
||||
static_assert(sizeof(idFXManager) == 768,
|
||||
"Recovered idFXManager ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "gamelib/effects/gamelibeffects.h"
|
||||
|
||||
idRenderModelEffects* GameLib_AllocEffectsModel(idRenderWorld* renderWorld);
|
||||
idRenderModelDecal* GameLib_GetDecalModel(idRenderWorld* renderWorld);
|
||||
idRenderModelBeam* GameLib_AllocBeamModel(idRenderWorld* renderWorld);
|
||||
void GameLib_CommitEffectsModel(idRenderModelEffects* model);
|
||||
void GameLib_CommitDecalModel(idRenderModelDecal* model);
|
||||
void GameLib_CommitBeamModel(idRenderModelBeam* model);
|
||||
void GameLib_FreeEffectsModel(idRenderModelEffects* model);
|
||||
void GameLib_FreeBeamModel(idRenderModelBeam* model);
|
||||
void GameLib_UpdateEffectsModel(idRenderModelEffects* model,
|
||||
int currentTime, int gameMsPerFrame);
|
||||
void GameLib_UpdateBeamModel(idRenderModelBeam* model, int currentTime);
|
||||
|
||||
idGameLibEffects::idGameLibEffects()
|
||||
: effectsModel(nullptr)
|
||||
, decalModel(nullptr)
|
||||
, beamModel(nullptr)
|
||||
, effectsModelManager()
|
||||
, deferredDecalManager()
|
||||
, ribbonModelManager()
|
||||
, weaponTraceManager()
|
||||
, fxModelRecycler()
|
||||
, weaponImpactManager()
|
||||
, impactManager()
|
||||
, initialized(false) {
|
||||
}
|
||||
|
||||
idGameLibEffects::~idGameLibEffects() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void idGameLibEffects::Init(idRenderWorld* const renderWorld,
|
||||
idClip* const clip, const float diversity,
|
||||
const int localPlayerIndex) {
|
||||
if (initialized) {
|
||||
Shutdown();
|
||||
}
|
||||
if (renderWorld == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
effectsModel = GameLib_AllocEffectsModel(renderWorld);
|
||||
decalModel = GameLib_GetDecalModel(renderWorld);
|
||||
beamModel = GameLib_AllocBeamModel(renderWorld);
|
||||
if (effectsModel != nullptr) {
|
||||
GameLib_CommitEffectsModel(effectsModel);
|
||||
}
|
||||
if (decalModel != nullptr) {
|
||||
GameLib_CommitDecalModel(decalModel);
|
||||
}
|
||||
if (beamModel != nullptr) {
|
||||
GameLib_CommitBeamModel(beamModel);
|
||||
}
|
||||
|
||||
effectsModelManager.Init();
|
||||
deferredDecalManager.Init(clip, decalModel);
|
||||
ribbonModelManager.Shutdown();
|
||||
weaponTraceManager.Init();
|
||||
fxModelRecycler.Init();
|
||||
weaponImpactManager.Init(&effectsModelManager, diversity, 64,
|
||||
localPlayerIndex);
|
||||
impactManager.Init(&effectsModelManager, diversity, 32,
|
||||
localPlayerIndex);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void idGameLibEffects::Shutdown() {
|
||||
initialized = false;
|
||||
effectsModelManager.Shutdown();
|
||||
deferredDecalManager.Shutdown();
|
||||
ribbonModelManager.Shutdown();
|
||||
weaponTraceManager.Init();
|
||||
fxModelRecycler.Shutdown();
|
||||
weaponImpactManager.Shutdown();
|
||||
impactManager.Shutdown();
|
||||
|
||||
if (effectsModel != nullptr) {
|
||||
GameLib_FreeEffectsModel(effectsModel);
|
||||
effectsModel = nullptr;
|
||||
}
|
||||
if (beamModel != nullptr) {
|
||||
GameLib_FreeBeamModel(beamModel);
|
||||
beamModel = nullptr;
|
||||
}
|
||||
// The decal model is owned by idRenderWorld and is not freed here in the
|
||||
// recovered shutdown path.
|
||||
decalModel = nullptr;
|
||||
}
|
||||
|
||||
bool idGameLibEffects::Update(const int currentTime,
|
||||
const int gameMsPerFrame, const int serverCurrentTime) {
|
||||
if (!initialized) {
|
||||
return false;
|
||||
}
|
||||
deferredDecalManager.Update(currentTime);
|
||||
if (effectsModel != nullptr) {
|
||||
GameLib_UpdateEffectsModel(effectsModel, currentTime, gameMsPerFrame);
|
||||
}
|
||||
if (beamModel != nullptr) {
|
||||
GameLib_UpdateBeamModel(beamModel, currentTime);
|
||||
}
|
||||
weaponTraceManager.Update();
|
||||
const idVec3 origin(0.0f, 0.0f, 0.0f);
|
||||
const idMat3 axis(1.0f);
|
||||
weaponImpactManager.Update(origin, axis, currentTime, serverCurrentTime);
|
||||
impactManager.Update(origin, axis, currentTime, serverCurrentTime);
|
||||
return true;
|
||||
}
|
||||
@@ -1,24 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\effects\gamelibeffects.h
|
||||
// Recovered logical types: 1
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/effects/deferreddecalmanager.h"
|
||||
#include "gamelib/effects/effectsmodelmanager.h"
|
||||
#include "gamelib/effects/fxmanager.h"
|
||||
#include "gamelib/effects/impactmanager.h"
|
||||
#include "gamelib/effects/ribbonmanager.h"
|
||||
#include "gamelib/effects/weapontracemanager.h"
|
||||
|
||||
class idClip;
|
||||
class idRenderModelBeam;
|
||||
class idRenderModelDecal;
|
||||
class idRenderModelEffects;
|
||||
class idRenderWorld;
|
||||
|
||||
// IDA Local Type ordinal 14163; PDB kind: class.
|
||||
class __declspec(align(4)) idGameLibEffects
|
||||
{
|
||||
class alignas(8) idGameLibEffects {
|
||||
public:
|
||||
idRenderModelEffects *effectsModel;
|
||||
idRenderModelDecal *decalModel;
|
||||
idRenderModelBeam *beamModel;
|
||||
idEffectsModelManager effectsModelManager;
|
||||
idDeferredDecalManager deferredDecalManager;
|
||||
idRibbonModelManager ribbonModelManager;
|
||||
idWeaponTraceManager weaponTraceManager;
|
||||
idFXModelRecycler fxModelRecycler;
|
||||
idImpactManager weaponImpactManager;
|
||||
idImpactManager impactManager;
|
||||
bool initialized;
|
||||
idGameLibEffects();
|
||||
~idGameLibEffects();
|
||||
|
||||
void Init(idRenderWorld* renderWorld, idClip* clip, float diversity,
|
||||
int localPlayerIndex);
|
||||
void Shutdown();
|
||||
bool Update(int currentTime, int gameMsPerFrame, int serverCurrentTime);
|
||||
|
||||
idRenderModelEffects* effectsModel;
|
||||
idRenderModelDecal* decalModel;
|
||||
idRenderModelBeam* beamModel;
|
||||
idEffectsModelManager effectsModelManager;
|
||||
idDeferredDecalManager deferredDecalManager;
|
||||
idRibbonModelManager ribbonModelManager;
|
||||
idWeaponTraceManager weaponTraceManager;
|
||||
idFXModelRecycler fxModelRecycler;
|
||||
idImpactManager weaponImpactManager;
|
||||
idImpactManager impactManager;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idFXModelRecycler) == 2720,
|
||||
"Recovered idFXModelRecycler ABI changed");
|
||||
static_assert(sizeof(idGameLibEffects) == 10432,
|
||||
"Recovered idGameLibEffects ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "gamelib/effects/impactmanager.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
const idDeclParticle* GameLib_GetParticleModelDecl(
|
||||
const idRenderModelParticle* model);
|
||||
int GameLib_GetParticleEffectDuration(const idDeclParticle* particle,
|
||||
int numCycles);
|
||||
void GameLib_ConfigureImpactParticleModel(idRenderModelParticle* model,
|
||||
const idDeclParticle* particle, const idVec3& origin,
|
||||
const idMat3& axis, int startTime, float diversity,
|
||||
float distanceSqr, const idColor& color);
|
||||
void GameLib_UpdateImpactParticleTransform(idRenderModelParticle* model,
|
||||
const idVec3& origin, const idMat3& axis);
|
||||
void GameLib_HideImpactParticleModel(idRenderModelParticle* model);
|
||||
void GameLib_SerializeImpactBuffer(idSerializer& serializer,
|
||||
idImpactManager::impactBufferItem_t* buffer, int count,
|
||||
int& bufferPosition);
|
||||
|
||||
idImpactManager::idImpactManager()
|
||||
: impacts(0)
|
||||
, impactBinds(0)
|
||||
, next(0)
|
||||
, random(0)
|
||||
, initialized(false)
|
||||
, effectsModelManager(nullptr)
|
||||
, impactBuffer{}
|
||||
, impactBufferPos(0)
|
||||
, serializeImpactCount(0)
|
||||
, localPlayerIndex(0) {
|
||||
}
|
||||
|
||||
idImpactManager::~idImpactManager() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void idImpactManager::Init(
|
||||
idEffectsModelManager* const effectsModelManager_,
|
||||
const float diversity, const int maxImpacts,
|
||||
const int localPlayerIndex_) {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
effectsModelManager = effectsModelManager_;
|
||||
localPlayerIndex = localPlayerIndex_;
|
||||
next = 0;
|
||||
random.SetSeed(static_cast<unsigned int>(diversity * 65535.0f));
|
||||
impacts.SetNum((std::max)(0, maxImpacts));
|
||||
impactBinds.SetNum(impacts.Num());
|
||||
for (int index = 0; index < impacts.Num(); ++index) {
|
||||
impacts[index] = impactState_t{nullptr, 0, 0};
|
||||
impactBinds[index].bindToParent = false;
|
||||
impactBinds[index].relOrg.Zero();
|
||||
impactBinds[index].relRot = idMat3(1.0f);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void idImpactManager::StopImpacts() {
|
||||
for (int index = 0; index < impacts.Num(); ++index) {
|
||||
impactState_t& impact = impacts[index];
|
||||
if (impact.pmodel != nullptr) {
|
||||
GameLib_HideImpactParticleModel(impact.pmodel);
|
||||
if (effectsModelManager != nullptr) {
|
||||
effectsModelManager->RecycleParticleFxModel(
|
||||
GameLib_GetParticleModelDecl(impact.pmodel),
|
||||
impact.pmodel);
|
||||
}
|
||||
impact.pmodel = nullptr;
|
||||
}
|
||||
impact.startTime = 0;
|
||||
impact.endTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void idImpactManager::Shutdown() {
|
||||
StopImpacts();
|
||||
impacts.Clear();
|
||||
impactBinds.Clear();
|
||||
effectsModelManager = nullptr;
|
||||
impactBufferPos = 0;
|
||||
serializeImpactCount = 0;
|
||||
next = 0;
|
||||
initialized = false;
|
||||
localPlayerIndex = 0;
|
||||
}
|
||||
|
||||
void idImpactManager::UseImpact(const idVec3& origin,
|
||||
const idMat3& axis, const idDeclParticle* const particle,
|
||||
const int startTime, const bool bindToParent,
|
||||
const idVec3& parentOrigin, const idMat3& parentAxis,
|
||||
const float distanceSqr, const int playerIndex,
|
||||
const idColor& color, const int numCycles) {
|
||||
if (!initialized || particle == nullptr || impacts.IsEmpty() ||
|
||||
effectsModelManager == nullptr) {
|
||||
return;
|
||||
}
|
||||
impactState_t& impact = impacts[next];
|
||||
impactBindState_t& bind = impactBinds[next];
|
||||
if (impact.pmodel != nullptr) {
|
||||
GameLib_HideImpactParticleModel(impact.pmodel);
|
||||
effectsModelManager->RecycleParticleFxModel(
|
||||
GameLib_GetParticleModelDecl(impact.pmodel), impact.pmodel);
|
||||
}
|
||||
impact.pmodel =
|
||||
effectsModelManager->GetNextParticleEffectModel(particle);
|
||||
if (impact.pmodel == nullptr) {
|
||||
return;
|
||||
}
|
||||
impact.startTime = startTime;
|
||||
impact.endTime = startTime +
|
||||
GameLib_GetParticleEffectDuration(particle, numCycles) + 1000;
|
||||
bind.bindToParent = bindToParent;
|
||||
if (bindToParent) {
|
||||
const idMat3 inverseParent = parentAxis.Transpose();
|
||||
bind.relOrg = inverseParent * (origin - parentOrigin);
|
||||
bind.relRot = axis * inverseParent;
|
||||
} else {
|
||||
bind.relOrg.Zero();
|
||||
bind.relRot = idMat3(1.0f);
|
||||
}
|
||||
|
||||
impactBufferItem_t& item = impactBuffer[impactBufferPos];
|
||||
item.pos = bindToParent ? bind.relOrg : origin;
|
||||
item.axis = bindToParent ? bind.relRot : axis;
|
||||
item.prt = particle;
|
||||
item.bindToParent = bindToParent;
|
||||
item.playerIndex = playerIndex;
|
||||
item.serverTime = startTime;
|
||||
impactBufferPos = (impactBufferPos + 1) % 16;
|
||||
|
||||
GameLib_ConfigureImpactParticleModel(impact.pmodel, particle,
|
||||
origin, axis, startTime, random.RandomFloat(), distanceSqr, color);
|
||||
next = (next + 1) % impacts.Num();
|
||||
}
|
||||
|
||||
void idImpactManager::Update(const idVec3& parentOrigin,
|
||||
const idMat3& parentAxis, const int localTime, const int serverTime) {
|
||||
while (serializeImpactCount > 0) {
|
||||
const impactBufferItem_t& item = impactBuffer[impactBufferPos];
|
||||
if (serverTime != 0 && item.serverTime > serverTime) {
|
||||
break;
|
||||
}
|
||||
impactBufferPos = (impactBufferPos + 1) % 16;
|
||||
--serializeImpactCount;
|
||||
if (item.prt == nullptr || item.playerIndex == localPlayerIndex) {
|
||||
continue;
|
||||
}
|
||||
const idVec3 origin = item.bindToParent
|
||||
? parentOrigin + parentAxis * item.pos : item.pos;
|
||||
const idMat3 axis = item.bindToParent
|
||||
? parentAxis * item.axis : item.axis;
|
||||
UseImpact(origin, axis, item.prt, localTime, item.bindToParent,
|
||||
parentOrigin, parentAxis, 0.0f, 0,
|
||||
idColor(1.0f, 1.0f, 1.0f, 1.0f), 1);
|
||||
}
|
||||
|
||||
for (int index = 0; index < impacts.Num(); ++index) {
|
||||
impactState_t& impact = impacts[index];
|
||||
if (impact.pmodel == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (impact.endTime != 0 && localTime < impact.endTime) {
|
||||
const impactBindState_t& bind = impactBinds[index];
|
||||
if (bind.bindToParent) {
|
||||
GameLib_UpdateImpactParticleTransform(impact.pmodel,
|
||||
parentOrigin + parentAxis * bind.relOrg,
|
||||
bind.relRot * parentAxis);
|
||||
}
|
||||
} else {
|
||||
GameLib_HideImpactParticleModel(impact.pmodel);
|
||||
if (effectsModelManager != nullptr) {
|
||||
effectsModelManager->RecycleParticleFxModel(
|
||||
GameLib_GetParticleModelDecl(impact.pmodel),
|
||||
impact.pmodel);
|
||||
}
|
||||
impact.pmodel = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void idImpactManager::Serialize(idSerializer& serializer) {
|
||||
const int oldPosition = impactBufferPos;
|
||||
GameLib_SerializeImpactBuffer(serializer, impactBuffer, 16,
|
||||
impactBufferPos);
|
||||
serializeImpactCount = impactBufferPos - oldPosition;
|
||||
if (serializeImpactCount < 0) serializeImpactCount += 16;
|
||||
serializeImpactCount = (std::min)(16, serializeImpactCount);
|
||||
}
|
||||
@@ -1,50 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\effects\impactmanager.h
|
||||
// Recovered logical types: 4
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/effects/effectsmodelmanager.h"
|
||||
#include "idlib/color.h"
|
||||
#include "idlib/containers/list.h"
|
||||
#include "idlib/math/random.h"
|
||||
|
||||
class idDeclParticle;
|
||||
class idRenderModelParticle;
|
||||
class idSerializer;
|
||||
|
||||
// IDA Local Type ordinal 14157; PDB kind: struct.
|
||||
struct idImpactManager::impactState_t
|
||||
{
|
||||
idRenderModelParticle *pmodel;
|
||||
int startTime;
|
||||
int endTime;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14159; PDB kind: struct.
|
||||
struct idImpactManager::impactBindState_t
|
||||
{
|
||||
bool bindToParent;
|
||||
idVec3 relOrg;
|
||||
idMat3 relRot;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14161; PDB kind: struct.
|
||||
struct idImpactManager::impactBufferItem_t
|
||||
{
|
||||
idVec3 pos;
|
||||
idMat3 axis;
|
||||
const idDeclParticle *prt;
|
||||
bool bindToParent;
|
||||
int playerIndex;
|
||||
int serverTime;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14162; PDB kind: class.
|
||||
class idImpactManager
|
||||
{
|
||||
class idImpactManager {
|
||||
public:
|
||||
idList<idImpactManager::impactState_t,5> impacts;
|
||||
idList<idImpactManager::impactBindState_t,5> impactBinds;
|
||||
int next;
|
||||
idRandom2 random;
|
||||
bool initialized;
|
||||
idEffectsModelManager *effectsModelManager;
|
||||
idImpactManager::impactBufferItem_t impactBuffer[16];
|
||||
int impactBufferPos;
|
||||
int serializeImpactCount;
|
||||
int localPlayerIndex;
|
||||
struct impactState_t {
|
||||
idRenderModelParticle* pmodel;
|
||||
int startTime;
|
||||
int endTime;
|
||||
};
|
||||
|
||||
struct impactBindState_t {
|
||||
bool bindToParent;
|
||||
idVec3 relOrg;
|
||||
idMat3 relRot;
|
||||
};
|
||||
|
||||
struct impactBufferItem_t {
|
||||
idVec3 pos;
|
||||
idMat3 axis;
|
||||
const idDeclParticle* prt;
|
||||
bool bindToParent;
|
||||
int playerIndex;
|
||||
int serverTime;
|
||||
};
|
||||
|
||||
idImpactManager();
|
||||
~idImpactManager();
|
||||
|
||||
void Init(idEffectsModelManager* effectsModelManager, float diversity,
|
||||
int maxImpacts, int localPlayerIndex);
|
||||
void Shutdown();
|
||||
void StopImpacts();
|
||||
void UseImpact(const idVec3& origin, const idMat3& axis,
|
||||
const idDeclParticle* particle, int startTime, bool bindToParent,
|
||||
const idVec3& parentOrigin, const idMat3& parentAxis,
|
||||
float distanceSqr, int playerIndex, const idColor& color,
|
||||
int numCycles);
|
||||
void Update(const idVec3& parentOrigin, const idMat3& parentAxis,
|
||||
int localTime, int serverTime);
|
||||
void Serialize(idSerializer& serializer);
|
||||
|
||||
idList<impactState_t, 5> impacts;
|
||||
idList<impactBindState_t, 5> impactBinds;
|
||||
int next;
|
||||
idRandom2 random;
|
||||
bool initialized;
|
||||
idEffectsModelManager* effectsModelManager;
|
||||
impactBufferItem_t impactBuffer[16];
|
||||
int impactBufferPos;
|
||||
int serializeImpactCount;
|
||||
int localPlayerIndex;
|
||||
};
|
||||
|
||||
static_assert(sizeof(idImpactManager::impactState_t) == 12,
|
||||
"Recovered impact state ABI changed");
|
||||
static_assert(sizeof(idImpactManager::impactBindState_t) == 52,
|
||||
"Recovered impact bind ABI changed");
|
||||
static_assert(sizeof(idImpactManager::impactBufferItem_t) == 64,
|
||||
"Recovered impact buffer ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idImpactManager) == 1084,
|
||||
"Recovered idImpactManager ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "gamelib/effects/lasersight.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void GameLib_DrawLaserBeam(idRenderModelBeam* beamModel,
|
||||
const idMaterial* material, const idVec3& start,
|
||||
const idVec3& end, float halfWidth, unsigned char alpha);
|
||||
int GameLib_CreateLaserDecal(idRenderModelDecal* decalModel,
|
||||
const idMaterial* material, int startTime, float size, float depth,
|
||||
bool quad);
|
||||
void GameLib_RemoveLaserDecal(idRenderModelDecal* decalModel, int handle);
|
||||
void GameLib_UpdateLaserDecal(idRenderModelDecal* decalModel, int handle,
|
||||
const idVec3& position, const idMat3& axis, float sizeScale);
|
||||
|
||||
idLaserBeam::idLaserBeam()
|
||||
: material(nullptr)
|
||||
, height(1.0f) {
|
||||
}
|
||||
|
||||
void idLaserBeam::Update(idRenderModelBeam* const beamEffects,
|
||||
const idVec3& startPos, const idVec3& endPos, const float fade) {
|
||||
if (beamEffects == nullptr) {
|
||||
return;
|
||||
}
|
||||
const int alpha = static_cast<int>(fade * 255.9f);
|
||||
GameLib_DrawLaserBeam(beamEffects, material, startPos, endPos,
|
||||
height * 0.5f, static_cast<unsigned char>(
|
||||
(std::max)(0, (std::min)(255, alpha))));
|
||||
}
|
||||
|
||||
idLaserSight::idLaserSight()
|
||||
: initialized(false)
|
||||
, hidden(false)
|
||||
, laserBeam()
|
||||
, laserEndPoint{nullptr, 1.0f, 8.0f, -1, false}
|
||||
, beamEffects(nullptr)
|
||||
, decalEffects(nullptr)
|
||||
, fadeInDuration(1.0f)
|
||||
, fadeOutDuration(1.0f) {
|
||||
}
|
||||
|
||||
idLaserSight::~idLaserSight() {
|
||||
Shutdown();
|
||||
beamEffects = nullptr;
|
||||
decalEffects = nullptr;
|
||||
}
|
||||
|
||||
void idLaserSight::Init(idRenderModelBeam* const beamEffects_,
|
||||
idRenderModelDecal* const decalEffects_,
|
||||
const idMaterial* const laserBeamMtr, const float laserBeamHeight,
|
||||
const idMaterial* const laserPointMtr, const float laserPointSize,
|
||||
const float laserPointDepth, const float fadeIn, const float fadeOut,
|
||||
const bool isQuad) {
|
||||
beamEffects = beamEffects_;
|
||||
decalEffects = decalEffects_;
|
||||
laserBeam.material = laserBeamMtr;
|
||||
laserBeam.height = laserBeamHeight;
|
||||
laserEndPoint.material = laserPointMtr;
|
||||
laserEndPoint.size = laserPointSize;
|
||||
laserEndPoint.depth = laserPointDepth;
|
||||
laserEndPoint.quad = isQuad;
|
||||
laserEndPoint.handle = -1;
|
||||
fadeInDuration = fadeIn;
|
||||
fadeOutDuration = fadeOut;
|
||||
initialized = true;
|
||||
hidden = false;
|
||||
}
|
||||
|
||||
void idLaserSight::Shutdown() {
|
||||
initialized = false;
|
||||
if (decalEffects != nullptr && laserEndPoint.handle != -1) {
|
||||
GameLib_RemoveLaserDecal(decalEffects, laserEndPoint.handle);
|
||||
laserEndPoint.handle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void idLaserSight::Show(const int startTime) {
|
||||
if (!initialized || !hidden) {
|
||||
return;
|
||||
}
|
||||
hidden = false;
|
||||
if (decalEffects != nullptr && laserEndPoint.material != nullptr) {
|
||||
laserEndPoint.handle = GameLib_CreateLaserDecal(decalEffects,
|
||||
laserEndPoint.material, startTime, laserEndPoint.size,
|
||||
laserEndPoint.depth, laserEndPoint.quad);
|
||||
}
|
||||
}
|
||||
|
||||
void idLaserSight::Hide() {
|
||||
if (!initialized || hidden) {
|
||||
return;
|
||||
}
|
||||
hidden = true;
|
||||
if (decalEffects != nullptr && laserEndPoint.handle != -1) {
|
||||
GameLib_RemoveLaserDecal(decalEffects, laserEndPoint.handle);
|
||||
laserEndPoint.handle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void idLaserSight::Update(const idVec3& startPos, const idVec3& endPos,
|
||||
const idMat3& axis, const float sizeScale, const float fade) {
|
||||
if (hidden) {
|
||||
return;
|
||||
}
|
||||
laserBeam.Update(beamEffects, startPos, endPos, fade);
|
||||
if (decalEffects != nullptr && laserEndPoint.handle != -1) {
|
||||
GameLib_UpdateLaserDecal(decalEffects, laserEndPoint.handle,
|
||||
endPos, axis, sizeScale * fade);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\effects\lasersight.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "idlib/math/vector.h"
|
||||
|
||||
class idMaterial;
|
||||
class idRenderModelBeam;
|
||||
class idRenderModelDecal;
|
||||
|
||||
// IDA Local Type ordinal 13817; PDB kind: struct.
|
||||
struct laserSightInfo_t
|
||||
{
|
||||
const idMaterial *laserBeamMtr;
|
||||
const idMaterial *laserDotMtr;
|
||||
float laserBeamHeight;
|
||||
float laserDotSize;
|
||||
float laserDotDepth;
|
||||
float laserDotMinSizeScale;
|
||||
float laserDotMaxSizeScale;
|
||||
bool laserDotQuad;
|
||||
float fadeIn;
|
||||
float fadeOut;
|
||||
struct laserSightInfo_t {
|
||||
const idMaterial* laserBeamMtr;
|
||||
const idMaterial* laserDotMtr;
|
||||
float laserBeamHeight;
|
||||
float laserDotSize;
|
||||
float laserDotDepth;
|
||||
float laserDotMinSizeScale;
|
||||
float laserDotMaxSizeScale;
|
||||
bool laserDotQuad;
|
||||
float fadeIn;
|
||||
float fadeOut;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14739; PDB kind: class.
|
||||
class idLaserSight
|
||||
{
|
||||
class idLaserBeam {
|
||||
public:
|
||||
bool initialized;
|
||||
bool hidden;
|
||||
idLaserBeam laserBeam;
|
||||
idLaserEndPoint laserEndPoint;
|
||||
idRenderModelBeam *beamEffects;
|
||||
idRenderModelDecal *decalEffects;
|
||||
float fadeInDuration;
|
||||
float fadeOutDuration;
|
||||
idLaserBeam();
|
||||
void Update(idRenderModelBeam* beamEffects, const idVec3& startPos,
|
||||
const idVec3& endPos, float fade);
|
||||
|
||||
const idMaterial* material;
|
||||
float height;
|
||||
};
|
||||
|
||||
class alignas(4) idLaserEndPoint {
|
||||
public:
|
||||
const idMaterial* material;
|
||||
float size;
|
||||
float depth;
|
||||
int handle;
|
||||
bool quad;
|
||||
};
|
||||
|
||||
class idLaserSight {
|
||||
public:
|
||||
idLaserSight();
|
||||
~idLaserSight();
|
||||
|
||||
void Init(idRenderModelBeam* beamEffects,
|
||||
idRenderModelDecal* decalEffects, const idMaterial* laserBeamMtr,
|
||||
float laserBeamHeight, const idMaterial* laserPointMtr,
|
||||
float laserPointSize, float laserPointDepth, float fadeIn,
|
||||
float fadeOut, bool isQuad);
|
||||
void Shutdown();
|
||||
void Show(int startTime);
|
||||
void Hide();
|
||||
void Update(const idVec3& startPos, const idVec3& endPos,
|
||||
const idMat3& axis, float sizeScale, float fade);
|
||||
|
||||
bool initialized;
|
||||
bool hidden;
|
||||
idLaserBeam laserBeam;
|
||||
idLaserEndPoint laserEndPoint;
|
||||
idRenderModelBeam* beamEffects;
|
||||
idRenderModelDecal* decalEffects;
|
||||
float fadeInDuration;
|
||||
float fadeOutDuration;
|
||||
};
|
||||
|
||||
static_assert(sizeof(laserSightInfo_t) == 40,
|
||||
"Recovered laserSightInfo_t ABI changed");
|
||||
static_assert(sizeof(idLaserBeam) == 8,
|
||||
"Recovered idLaserBeam ABI changed");
|
||||
static_assert(sizeof(idLaserEndPoint) == 20,
|
||||
"Recovered idLaserEndPoint ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idLaserSight) == 48,
|
||||
"Recovered idLaserSight ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "gamelib/effects/lensflaremanager.h"
|
||||
|
||||
bool GameLib_CreateFlareModels(idRenderWorld* renderWorld,
|
||||
const idDeclFlare* flareDecl, idRenderModelFlare*& flareModel,
|
||||
idRenderModelFlareOcclusionQuad*& occlusionModel);
|
||||
void GameLib_DeleteFlareModel(idRenderModelFlare* flareModel,
|
||||
idRenderModelFlareOcclusionQuad* occlusionModel);
|
||||
void GameLib_ConfigureFlareModels(idRenderModelFlare* flareModel,
|
||||
idRenderModelFlareOcclusionQuad* occlusionModel, float quadScale,
|
||||
bool autosprited, bool sunFlare);
|
||||
void GameLib_UpdateFlareModels(idRenderModelFlare* flareModel,
|
||||
idRenderModelFlareOcclusionQuad* occlusionModel,
|
||||
const idVec3& flareOrigin, const idVec3& occlusionOrigin,
|
||||
const idMat3& axis, float fadeStartRange, float fadeEndRange,
|
||||
const idVec4& color, float coverage, bool hidden);
|
||||
void GameLib_ApplyFlareCoverage(idRenderModelFlare* flareModel,
|
||||
float coverage);
|
||||
void GameLib_ApplyFlareColor(idRenderModelFlare* flareModel,
|
||||
const idVec4& color);
|
||||
|
||||
idLensFlareManager::idLensFlareManager()
|
||||
: flareRenderModel(nullptr)
|
||||
, flareOcclusionQuadModel(nullptr)
|
||||
, sunDirection()
|
||||
, occlusionOffset()
|
||||
, isAutosprited(false)
|
||||
, isInitialized(false) {
|
||||
sunDirection.Zero();
|
||||
occlusionOffset.Zero();
|
||||
}
|
||||
|
||||
idLensFlareManager::~idLensFlareManager() {
|
||||
if (flareRenderModel != nullptr || flareOcclusionQuadModel != nullptr) {
|
||||
GameLib_DeleteFlareModel(flareRenderModel,
|
||||
flareOcclusionQuadModel);
|
||||
}
|
||||
flareRenderModel = nullptr;
|
||||
flareOcclusionQuadModel = nullptr;
|
||||
isInitialized = false;
|
||||
}
|
||||
|
||||
void idLensFlareManager::Init(idRenderWorld* const renderWorld,
|
||||
const idDeclFlare* const flareDecl, const float quadSize,
|
||||
const idVec3& sunDirection_, const idVec3& occlusionOffset_,
|
||||
const bool isAutosprited_) {
|
||||
if (flareDecl == nullptr) {
|
||||
return;
|
||||
}
|
||||
sunDirection = sunDirection_;
|
||||
occlusionOffset = occlusionOffset_;
|
||||
isAutosprited = isAutosprited_;
|
||||
if (!GameLib_CreateFlareModels(renderWorld, flareDecl,
|
||||
flareRenderModel, flareOcclusionQuadModel)) {
|
||||
flareRenderModel = nullptr;
|
||||
flareOcclusionQuadModel = nullptr;
|
||||
return;
|
||||
}
|
||||
const bool sunFlare = sunDirection.LengthSqr() > 0.0f;
|
||||
const float quadScale = quadSize < 8.0f ? 8.0f - quadSize : 0.0f;
|
||||
GameLib_ConfigureFlareModels(flareRenderModel,
|
||||
flareOcclusionQuadModel, quadScale, isAutosprited, sunFlare);
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
void idLensFlareManager::ApplyFade(const float fade) {
|
||||
if (flareRenderModel != nullptr) {
|
||||
GameLib_ApplyFlareCoverage(flareRenderModel, fade);
|
||||
}
|
||||
}
|
||||
|
||||
void idLensFlareManager::ApplyColor(const idVec4& color) {
|
||||
if (flareRenderModel != nullptr) {
|
||||
GameLib_ApplyFlareColor(flareRenderModel, color);
|
||||
}
|
||||
}
|
||||
|
||||
void idLensFlareManager::StartFlare(const idVec3& origin,
|
||||
const idMat3& axis, const idVec4& color, const float fadeStartRange,
|
||||
const float fadeEndRange) {
|
||||
if (!isInitialized || flareRenderModel == nullptr ||
|
||||
flareOcclusionQuadModel == nullptr) {
|
||||
return;
|
||||
}
|
||||
const bool sunFlare = sunDirection.LengthSqr() > 0.0f;
|
||||
const idVec3 flareOrigin = sunFlare ? sunDirection : origin;
|
||||
const idVec3 quadOrigin = sunFlare
|
||||
? sunDirection : origin + occlusionOffset;
|
||||
GameLib_UpdateFlareModels(flareRenderModel, flareOcclusionQuadModel,
|
||||
flareOrigin, quadOrigin, axis, fadeStartRange, fadeEndRange,
|
||||
color, 1.0f, false);
|
||||
}
|
||||
|
||||
void idLensFlareManager::StopFlare() {
|
||||
if (flareRenderModel == nullptr || flareOcclusionQuadModel == nullptr) {
|
||||
return;
|
||||
}
|
||||
GameLib_UpdateFlareModels(flareRenderModel, flareOcclusionQuadModel,
|
||||
idVec3(0.0f, 0.0f, 0.0f), idVec3(0.0f, 0.0f, 0.0f),
|
||||
idMat3(1.0f), 0.0f, 0.0f,
|
||||
idVec4(1.0f, 1.0f, 1.0f, 1.0f), 0.0f, true);
|
||||
}
|
||||
|
||||
void idLensFlareManager::Update(const idVec3& origin,
|
||||
const idMat3& axis, const int time, const bool bindOrigin,
|
||||
const bool bindAxis) {
|
||||
(void)time;
|
||||
if (!isInitialized || flareRenderModel == nullptr ||
|
||||
flareOcclusionQuadModel == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (sunDirection.LengthSqr() == 0.0f && (bindOrigin || bindAxis)) {
|
||||
const idVec3 flareOrigin = bindOrigin ? origin : sunDirection;
|
||||
const idVec3 quadOrigin = flareOrigin + occlusionOffset;
|
||||
GameLib_UpdateFlareModels(flareRenderModel,
|
||||
flareOcclusionQuadModel, flareOrigin, quadOrigin,
|
||||
bindAxis ? axis : idMat3(1.0f), 0.0f, 0.0f,
|
||||
idVec4(1.0f, 1.0f, 1.0f, 1.0f), 1.0f, false);
|
||||
}
|
||||
}
|
||||
@@ -1,204 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\effects\lensflaremanager.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "idlib/math/vector.h"
|
||||
|
||||
class idDeclFlare;
|
||||
class idRenderModelFlare;
|
||||
class idRenderModelFlareOcclusionQuad;
|
||||
class idRenderWorld;
|
||||
|
||||
// IDA Local Type ordinal 14210; PDB kind: class.
|
||||
class __declspec(align(4)) idLensFlareManager
|
||||
{
|
||||
class alignas(4) idLensFlareManager {
|
||||
public:
|
||||
idRenderModelFlare *flareRenderModel;
|
||||
idRenderModelFlareOcclusionQuad *flareOcclusionQuadModel;
|
||||
idVec3 sunDirection;
|
||||
idVec3 occlusionOffset;
|
||||
bool isAutosprited;
|
||||
bool isInitialized;
|
||||
idLensFlareManager();
|
||||
~idLensFlareManager();
|
||||
|
||||
void Init(idRenderWorld* renderWorld, const idDeclFlare* flareDecl,
|
||||
float quadSize, const idVec3& sunDirection,
|
||||
const idVec3& occlusionOffset, bool isAutosprited);
|
||||
void StartFlare(const idVec3& origin, const idMat3& axis,
|
||||
const idVec4& color, float fadeStartRange, float fadeEndRange);
|
||||
void StopFlare();
|
||||
void Update(const idVec3& origin, const idMat3& axis, int time,
|
||||
bool bindOrigin, bool bindAxis);
|
||||
void ApplyFade(float fade);
|
||||
void ApplyColor(const idVec4& color);
|
||||
|
||||
idRenderModelFlare* flareRenderModel;
|
||||
idRenderModelFlareOcclusionQuad* flareOcclusionQuadModel;
|
||||
idVec3 sunDirection;
|
||||
idVec3 occlusionOffset;
|
||||
bool isAutosprited;
|
||||
bool isInitialized;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 19744; PDB kind: class.
|
||||
class __declspec(align(8)) idLensFlare : public idDynamicEntity
|
||||
{
|
||||
public:
|
||||
// Recovered virtual interface; IDA vtable ordinal 19745.
|
||||
virtual idTypeInfo *GetType();
|
||||
virtual ~idLensFlare();
|
||||
virtual idEventArg *CallEvent(idEventArg *result, const idEventDef *, const idEventArg *);
|
||||
virtual bool RespondsTo(const idEventDef *);
|
||||
virtual idEventArg *InternalCallEvent(idEventArg *result, const idEventDef *, const idEventArg *);
|
||||
virtual bool InternalRespondsTo(const idEventDef *);
|
||||
virtual void PostSpawn();
|
||||
virtual void Remove();
|
||||
virtual void DeleteSubEntities();
|
||||
virtual bool Draw(idPlayer *);
|
||||
virtual void JobSync();
|
||||
virtual void Think();
|
||||
virtual void PauseThink();
|
||||
virtual bool ShouldEnterDormancy();
|
||||
virtual bool ShouldLeaveDormancy();
|
||||
virtual void DormantBegin();
|
||||
virtual void DormantEnd(const int);
|
||||
virtual idRenderModelInfo *GetRenderModelInfo();
|
||||
virtual const idRenderModelInfo *GetRenderModelInfo_2();
|
||||
virtual void GetScale(idVec3 *);
|
||||
virtual void SetScale(const idVec3 *);
|
||||
virtual void SetModelByName(const char *);
|
||||
virtual void SetModel(idRenderModel *);
|
||||
virtual const idMaterial *GetCustomMaterial();
|
||||
virtual void SetColor(const idVec4 *);
|
||||
virtual void SetColor_2(const idColor *);
|
||||
virtual void SetColor_3(const idVec3 *);
|
||||
virtual void SetColor_4(float, float, float);
|
||||
virtual void SetColor_5(float, float, float, float);
|
||||
virtual void GetColor(idVec4 *);
|
||||
virtual void GetColor_2(idColor *);
|
||||
virtual void GetColor_3(idVec3 *);
|
||||
virtual void Hide(bool);
|
||||
virtual void Hide_2();
|
||||
virtual void Show();
|
||||
virtual void GetModelTransform(idVec3 *, idMat3 *);
|
||||
virtual void GetSoundTransform(idVec3 *, idMat3 *);
|
||||
virtual void UpdateModelTransform();
|
||||
virtual void UpdateFX();
|
||||
virtual void ProjectOverlay(const idVec3 *, const idVec3 *, float, const char *);
|
||||
virtual idPresentable *AllocPresentable(idRenderModel *);
|
||||
virtual const idComponentTimeLine *GetComponentTimeLine();
|
||||
virtual idComponentTimeLine *GetComponentTimeLine_2();
|
||||
virtual bool UpdateAnimationControllers();
|
||||
virtual void UpdateAttachments();
|
||||
virtual const idAnimStack *GetAnimStack();
|
||||
virtual idAnimStack *GetAnimStack_2();
|
||||
virtual idIndex<short,enum invalidJointIndex_t> *GetJointIndexFromTrace(idIndex<short,enum invalidJointIndex_t> *result, trace_t);
|
||||
virtual awPathResult_t ChangeAnimWebState(const char *, const char *);
|
||||
virtual awPathResult_t ChangeAnimWebState_2(const char *);
|
||||
virtual awPathResult_t ForceAnimWebState(const char *);
|
||||
virtual awPathResult_t ChangeAnimWebStateVia(const char *, const char *, const char *, const char *);
|
||||
virtual awPathResult_t ChangeAnimWebStateVia_2(const char *, const char *);
|
||||
virtual idAnimWebCmdCtx *GetAnimWebCmdCtx();
|
||||
virtual const idAnimWebCmdCtx *GetAnimWebCmdCtx_2();
|
||||
virtual const idAnimator_AF *GetAF();
|
||||
virtual idAnimator_AF *GetAF_2();
|
||||
virtual void PreBind();
|
||||
virtual void PostBind();
|
||||
virtual void PreUnbind();
|
||||
virtual void PostUnbind();
|
||||
virtual const splineLocation_t *GetSplineLocation();
|
||||
virtual void SetAxis(const idMat3 *);
|
||||
virtual bool CanDisablePhysics(const idEntity *);
|
||||
virtual collide_t Collide(const int, trace_t *, const idVec3 *);
|
||||
virtual collide_t Contact(const int, contactInfo_t *);
|
||||
virtual void ApplyImpulse(const int, const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyImpulseFromEntity(const idEntity *, const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyForce(const int, const int, const idVec3 *, const idVec3 *);
|
||||
virtual bool Crush(const int);
|
||||
virtual void ApplyDamage(const int, const int, const idDeclDamage *);
|
||||
virtual void ActivatePhysics(const int);
|
||||
virtual void DeactivatePhysics(const int);
|
||||
virtual void ApplyWaterEffects(const int, const int);
|
||||
virtual void ApplyWaterSplashEffects(const int, const int, surfTypes_t, idPhysicsCallbacks::splashState_t);
|
||||
virtual bool TakesDamage();
|
||||
virtual void DamageFeedback(idEntity *, idEntity *, const idDeclDamage *, float *);
|
||||
virtual void KilledNotification(const idEntity *, const idEntity *, const idDeclDamage *, const float);
|
||||
virtual float Damage(idEntity *, idEntity *, const idDeclDamage *, const float, const idVec3 *, trace_t *);
|
||||
virtual bool CalcDamageImpulse(const idEntity *, const idEntity *, const idDeclDamage *, const float, const idVec3 *, const trace_t *, idVec3 *, idVec3 *);
|
||||
virtual bool IsTargetLockable(const idDeclAmmo *);
|
||||
virtual void AddProjectileLock();
|
||||
virtual void RemoveProjectileLock();
|
||||
virtual const idScriptObject *GetScriptObject();
|
||||
virtual idScriptObject *GetScriptObject_2();
|
||||
virtual bool ShouldConstructScriptObjectAtSpawn();
|
||||
virtual idThread *GetStateThread();
|
||||
virtual int AddThread(const idHandle<int,enum invalidThreadHandle_t,0>);
|
||||
virtual void RemoveThread(const idHandle<int,enum invalidThreadHandle_t,0>);
|
||||
virtual idHandle<int,enum invalidThreadHandle_t,0> *GetThread(idHandle<int,enum invalidThreadHandle_t,0> *result, const int);
|
||||
virtual int NumThreads();
|
||||
virtual int MaxThreads();
|
||||
virtual void ExecuteThread(idThread *);
|
||||
virtual void ResetFSMWaitThreadIfPossible(idThread *);
|
||||
virtual bool HandleGuiEvent(const sysEvent_t *);
|
||||
virtual void ActivateTargets(idEntity *);
|
||||
virtual bool GetRcCarCanTarget();
|
||||
virtual const idBaseHealth *GetHealthComponent();
|
||||
virtual idBaseHealth *GetHealthComponent_2();
|
||||
virtual const idSmartLootComponent *GetSmartLootComponent();
|
||||
virtual idSmartLootComponent *GetSmartLootComponent_2();
|
||||
virtual void Teleport(const idVec3 *, const idAngles *);
|
||||
virtual bool IsPusher();
|
||||
virtual const idList<idEntityPtr<idEntity>,5> *GetTriggerTouchList();
|
||||
virtual idList<idEntityPtr<idEntity>,5> *GetTriggerTouchList_2();
|
||||
virtual void TestFunctionality();
|
||||
virtual float GetUsableDistance();
|
||||
virtual float GetCrosshairIconDistance();
|
||||
virtual usableState_t GetUsableState(const idEntity *, const idFocusTrace *);
|
||||
virtual bool ModifyCrosshairInfo(const idEntity *, const idFocusTrace *, const usableState_t, idCrosshairInfo *);
|
||||
virtual bool IsCrosshairDisabled(const idEntity *, const idFocusTrace *, const usableState_t);
|
||||
virtual bool IsCrosshairSubdued(const idEntity *, const idFocusTrace *, const usableState_t);
|
||||
virtual bool IsEverUsable(const idEntity *);
|
||||
virtual bool IsCurrentlyUsable(const idEntity *);
|
||||
virtual bool Use(idEntity *, const usableState_t);
|
||||
virtual void Dropped(idEntity *, const idDeclInventory *);
|
||||
virtual const idInventoryCollection *GetInventory();
|
||||
virtual idInventoryCollection *GetInventory_2();
|
||||
virtual void InventoryAdded(idInventoryItem *, int);
|
||||
virtual void InventoryRemoved(idInventoryItem *);
|
||||
virtual const idAttachmentCollection *GetAttachments();
|
||||
virtual idAttachmentCollection *GetAttachments_2();
|
||||
virtual void EnableAIEventResponse(const idAIEvent::aiEventClass_t);
|
||||
virtual void DisableAIEventResponse(const idAIEvent::aiEventClass_t);
|
||||
virtual bool CanReceiveAIEvents(const int);
|
||||
virtual bool RespondsToAIEvent(const idAIEvent *);
|
||||
virtual void OnAIEvent(const idAIEvent *);
|
||||
virtual bool IsDead();
|
||||
virtual bool IsDying();
|
||||
virtual idFaction *GetFaction();
|
||||
virtual const idFaction *GetFaction_2();
|
||||
virtual idEntityAuditor *GetAuditor();
|
||||
virtual void GetVisibilityPoint(const visPoint_t, idVec3 *);
|
||||
virtual void GetAimPoint(const aimPoint_t, idVec3 *);
|
||||
virtual void GetEyePos(idVec3 *);
|
||||
virtual bool IsVisible();
|
||||
virtual idDynamicCoverMgr *GetDynamicCoverMgr();
|
||||
virtual const idDynamicCoverMgr *GetDynamicCoverMgr_2();
|
||||
virtual const idAAS2 *GetAAS();
|
||||
virtual void GetViewStateFOV(idVec3 *, unsigned __int8 *, unsigned __int8 *);
|
||||
virtual void GetViewStateFOV_2(idVec3 *, unsigned __int8 *, unsigned __int8 *);
|
||||
virtual int GetNumRepairBotTetherPoints();
|
||||
virtual bool GetRepairBotTetherPoint(const int, const int, idVec3 *);
|
||||
virtual idEntityInterface *CreateEntityInterface(idGame *);
|
||||
virtual void ShowEditingDialog();
|
||||
virtual void UpdateEditingDialog();
|
||||
virtual void UpdateModifiedProperties();
|
||||
virtual inputSettings_t *GetInputSettings(inputSettings_t *result, idPlayer *);
|
||||
virtual bool EvaluateControls(usercmd_t *, usercmd_t *);
|
||||
virtual void CheckForErrors(idList<idStr,5> *);
|
||||
virtual void DebugDrawEntity(const idColor *, int);
|
||||
virtual void ClientThink();
|
||||
virtual void Serialize(idSerializer *);
|
||||
virtual void PostSerializeRead(bool);
|
||||
virtual void OnActivate(idEntity *);
|
||||
virtual void OnMakeActivatable(const bool);
|
||||
virtual void OnNotifyProgressionOwner();
|
||||
|
||||
bool startOff;
|
||||
bool cycleTrigger;
|
||||
const idDeclFlare *declFlare;
|
||||
float quadSize;
|
||||
float fadeStart;
|
||||
float fadeEnd;
|
||||
idVec3 sunDirection;
|
||||
const idSoundShader *sunGlareSnd;
|
||||
const idDeclTable *sunGlareSndVolumeTbl;
|
||||
const idDeclTable *sunGlareSndPitchTbl;
|
||||
const idDeclEnv *sunGlareEnv;
|
||||
int sunGlareEnvFadeOutTime;
|
||||
float sunGlareEnvDotThreshold;
|
||||
const idDeclTable *colorModulateTbl;
|
||||
float modulateTimeScale;
|
||||
idVec3 occlusionQuadOffset;
|
||||
bool autospriteOcclusionQuad;
|
||||
float maxSunGlareScale;
|
||||
bool sunGlareEnvActive;
|
||||
idLensFlareManager flareManager;
|
||||
};
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idLensFlareManager) == 36,
|
||||
"Recovered idLensFlareManager ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "gamelib/effects/ribbonmanager.h"
|
||||
|
||||
idRibbonModelManager::idRibbonModelManager()
|
||||
: ribbonEffects() {
|
||||
}
|
||||
|
||||
idRibbonModelManager::~idRibbonModelManager() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
int idRibbonModelManager::FindRibbonEffect(
|
||||
const idDeclRibbon* const ribbonDecl) const {
|
||||
for (int index = 0; index < ribbonEffects.Num(); ++index) {
|
||||
const ribbonEffects_t& effect = ribbonEffects[index];
|
||||
if (!effect.ribbons.IsEmpty() && effect.ribbons[0] != nullptr &&
|
||||
effect.ribbons[0]->ribbonDecl == ribbonDecl) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void idRibbonModelManager::CreateRibbonEffectModelType(
|
||||
const idDeclRibbon* const ribbonDecl) {
|
||||
if (ribbonDecl == nullptr || FindRibbonEffect(ribbonDecl) >= 0 ||
|
||||
ribbonEffects.Num() >= ribbonEffects.Max()) {
|
||||
return;
|
||||
}
|
||||
ribbonEffects_t* const effect = ribbonEffects.Alloc();
|
||||
if (effect == nullptr) {
|
||||
return;
|
||||
}
|
||||
effect->next = 0;
|
||||
for (int index = 0; index < effect->ribbons.Max(); ++index) {
|
||||
effect->ribbons.Append(new idRibbon(ribbonDecl));
|
||||
}
|
||||
}
|
||||
|
||||
idRibbon* idRibbonModelManager::GetNextRibbonEffectModel(
|
||||
const idDeclRibbon* const ribbonDecl) {
|
||||
const int index = FindRibbonEffect(ribbonDecl);
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
ribbonEffects_t& effect = ribbonEffects[index];
|
||||
if (effect.ribbons.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
idRibbon* const result = effect.ribbons[effect.next];
|
||||
effect.next = (effect.next + 1) % effect.ribbons.Num();
|
||||
return result;
|
||||
}
|
||||
|
||||
void idRibbonModelManager::Shutdown() {
|
||||
for (int effectIndex = 0; effectIndex < ribbonEffects.Num();
|
||||
++effectIndex) {
|
||||
ribbonEffects_t& effect = ribbonEffects[effectIndex];
|
||||
for (int ribbonIndex = 0; ribbonIndex < effect.ribbons.Num();
|
||||
++ribbonIndex) {
|
||||
delete effect.ribbons[ribbonIndex];
|
||||
}
|
||||
effect.ribbons.Clear();
|
||||
effect.next = 0;
|
||||
}
|
||||
ribbonEffects.Clear();
|
||||
}
|
||||
|
||||
idRibbonManager::idRibbonManager()
|
||||
: ribbon(nullptr)
|
||||
, ribbonDecl(nullptr)
|
||||
, beamModel(nullptr)
|
||||
, modelManager(nullptr)
|
||||
, isInitialized(false) {
|
||||
}
|
||||
|
||||
idRibbonManager::~idRibbonManager() {
|
||||
Shutdown();
|
||||
ribbonDecl = nullptr;
|
||||
beamModel = nullptr;
|
||||
modelManager = nullptr;
|
||||
}
|
||||
|
||||
void idRibbonManager::Init(const idDeclRibbon* const ribbonDecl_,
|
||||
idRenderModelBeam* const beamModel_,
|
||||
idRibbonModelManager* const modelManager_) {
|
||||
if (ribbonDecl_ == nullptr || beamModel_ == nullptr ||
|
||||
modelManager_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
ribbonDecl = ribbonDecl_;
|
||||
beamModel = beamModel_;
|
||||
modelManager = modelManager_;
|
||||
modelManager->CreateRibbonEffectModelType(ribbonDecl);
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
void idRibbonManager::Shutdown() {
|
||||
StopRibbon();
|
||||
ribbon = nullptr;
|
||||
isInitialized = false;
|
||||
}
|
||||
|
||||
void idRibbonManager::StartRibbon(const int spawnTime,
|
||||
const idVec3& spawnOrigin) {
|
||||
if (ribbonDecl == nullptr || modelManager == nullptr) {
|
||||
return;
|
||||
}
|
||||
ribbon = modelManager->GetNextRibbonEffectModel(ribbonDecl);
|
||||
if (ribbon != nullptr) {
|
||||
ribbon->StartRibbon(spawnTime, spawnOrigin);
|
||||
}
|
||||
}
|
||||
|
||||
void idRibbonManager::StopRibbon() {
|
||||
if (ribbon != nullptr) {
|
||||
ribbon->StopRibbon();
|
||||
}
|
||||
}
|
||||
|
||||
bool idRibbonManager::UpdateRibbon(const int time, const idVec3& origin,
|
||||
const idMat3& axis, const idVec3& velocity, const idVec4& color,
|
||||
const idVec3& translate) {
|
||||
if (ribbon == nullptr) {
|
||||
return false;
|
||||
}
|
||||
ribbon->RemoveOldNodes(time);
|
||||
ribbon->UpdatePosition(time, origin, axis, velocity, color);
|
||||
ribbon->UpdateGeometry(time, beamModel, axis, translate);
|
||||
return ribbon->ribbonState != RIBBON_INACTIVE;
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
#include "gamelib/physics/afbody.h"
|
||||
|
||||
#include "gamelib/physics/clipmodel.h"
|
||||
#include "idlib/lib_print.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
void GameLib_SerializeAFBody(idSerializer* serializer, idAFBody& body);
|
||||
|
||||
namespace {
|
||||
|
||||
void ZeroState(AFBodyPState_t& state) {
|
||||
state.worldOrigin.Zero();
|
||||
state.worldAxis = idMat3(1.0f);
|
||||
state.atRestOrigin.Zero();
|
||||
state.atRestAxis = idMat3(1.0f);
|
||||
std::memset(state.spatialVelocity.p, 0, sizeof(state.spatialVelocity.p));
|
||||
std::memset(state.externalForce.p, 0, sizeof(state.externalForce.p));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
idAFBody::idAFBody()
|
||||
: name()
|
||||
, clipModel(nullptr)
|
||||
, children(4)
|
||||
, constraints(4)
|
||||
, motionQuery{0}
|
||||
, inverseWorldSpatialInertia()
|
||||
, I()
|
||||
, invI()
|
||||
, J()
|
||||
, s()
|
||||
, totalForce()
|
||||
, auxForce()
|
||||
, acceleration() {
|
||||
Init();
|
||||
}
|
||||
|
||||
idAFBody::idAFBody(const char* const bodyName,
|
||||
idClipModel* const model, const float density)
|
||||
: idAFBody() {
|
||||
name.Set(bodyName != nullptr ? bodyName : "noname");
|
||||
SetClipModel(model);
|
||||
SetDensity(density, idMat3(1.0f));
|
||||
}
|
||||
|
||||
idAFBody::~idAFBody() {
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Delete();
|
||||
clipModel = nullptr;
|
||||
}
|
||||
children.Clear();
|
||||
constraints.Clear();
|
||||
response = nullptr;
|
||||
responseIndex = nullptr;
|
||||
}
|
||||
|
||||
void idAFBody::Init() {
|
||||
name.Set("noname");
|
||||
clipModel = nullptr;
|
||||
clipMask = 0;
|
||||
linearFrictionWater = -1.0f;
|
||||
angularFrictionWater = -1.0f;
|
||||
linearFriction = -1.0f;
|
||||
angularFriction = -1.0f;
|
||||
contactFriction = -1.0f;
|
||||
bouncyness = -1.0f;
|
||||
frictionDir.Zero();
|
||||
contactMotorDir.Zero();
|
||||
contactMotorVelocity = 0.0f;
|
||||
contactMotorForce = 0.0f;
|
||||
mass = 1.0f;
|
||||
invMass = 1.0f;
|
||||
centerOfMass.Zero();
|
||||
inertiaTensor = idMat3(1.0f);
|
||||
inverseInertiaTensor = idMat3(1.0f);
|
||||
parent = nullptr;
|
||||
primaryConstraint = nullptr;
|
||||
tree = nullptr;
|
||||
std::memset(&fl, 0, sizeof(fl));
|
||||
fl.isZero = 1;
|
||||
fl.selfCollision = 1;
|
||||
ZeroState(current);
|
||||
saved = current;
|
||||
inverseWorldSpatialInertia.Zero(6, 6);
|
||||
I.Zero(6, 6);
|
||||
invI.Zero(6, 6);
|
||||
J.Zero(6, 6);
|
||||
s.Zero();
|
||||
totalForce.Zero();
|
||||
auxForce.Zero();
|
||||
acceleration.Zero();
|
||||
response = nullptr;
|
||||
responseIndex = nullptr;
|
||||
numResponses = 0;
|
||||
maxAuxiliaryIndex = 0;
|
||||
maxSubTreeAuxiliaryIndex = 0;
|
||||
}
|
||||
|
||||
void idAFBody::SetClipModel(idClipModel* const model) {
|
||||
if (clipModel != nullptr && clipModel != model) {
|
||||
clipModel->Delete();
|
||||
}
|
||||
clipModel = model;
|
||||
}
|
||||
|
||||
void idAFBody::SetBouncyness(const float bounce) {
|
||||
if (bounce < 0.0f || bounce > 1.0f) {
|
||||
idLibPrint::Warning("idAFBody::SetBouncyness: %.1f out of range",
|
||||
bounce);
|
||||
return;
|
||||
}
|
||||
bouncyness = bounce;
|
||||
}
|
||||
|
||||
void idAFBody::SetFriction(const float linear, const float angular,
|
||||
const float contact) {
|
||||
if (linear < 0.0f || linear > 1.0f || angular < 0.0f ||
|
||||
angular > 1.0f || contact < 0.0f) {
|
||||
idLibPrint::Warning("idAFBody::SetFriction: invalid coefficients");
|
||||
return;
|
||||
}
|
||||
linearFriction = linear;
|
||||
angularFriction = angular;
|
||||
contactFriction = contact;
|
||||
linearFrictionWater = (std::min)(1.0f,
|
||||
(std::max)(0.0f, linear * 1.2f));
|
||||
angularFrictionWater = (std::min)(1.0f,
|
||||
(std::max)(0.0f, angular * 1.2f));
|
||||
}
|
||||
|
||||
void idAFBody::SetDensity(const float density,
|
||||
const idMat3& inertiaScale) {
|
||||
if (clipModel == nullptr) return;
|
||||
clipModel->GetMassProperties(density, mass, centerOfMass,
|
||||
inertiaTensor);
|
||||
if (mass <= 0.0f) {
|
||||
idLibPrint::Warning("idAFBody::SetDensity: invalid mass for '%s'",
|
||||
name.c_str());
|
||||
mass = 1.0f;
|
||||
centerOfMass.Zero();
|
||||
inertiaTensor = idMat3(1.0f);
|
||||
}
|
||||
invMass = 1.0f / mass;
|
||||
inertiaTensor *= inertiaScale;
|
||||
inverseInertiaTensor = inertiaTensor;
|
||||
if (!inverseInertiaTensor.InverseSelf()) {
|
||||
inverseInertiaTensor = idMat3(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void idAFBody::SetFrictionDirection(const idVec3& direction) {
|
||||
frictionDir = clipModel != nullptr
|
||||
? clipModel->GetAxis().Transpose() * direction : direction;
|
||||
fl.useFrictionDir = 1;
|
||||
}
|
||||
|
||||
bool idAFBody::GetFrictionDirection(idVec3& direction) const {
|
||||
if (!fl.useFrictionDir) return false;
|
||||
direction = clipModel != nullptr
|
||||
? clipModel->GetAxis() * frictionDir : frictionDir;
|
||||
return true;
|
||||
}
|
||||
|
||||
void idAFBody::SetContactMotorDirection(const idVec3& direction) {
|
||||
contactMotorDir = clipModel != nullptr
|
||||
? clipModel->GetAxis().Transpose() * direction : direction;
|
||||
fl.useContactMotorDir = 1;
|
||||
}
|
||||
|
||||
bool idAFBody::GetContactMotorDirection(idVec3& direction) const {
|
||||
if (!fl.useContactMotorDir) return false;
|
||||
direction = clipModel != nullptr
|
||||
? clipModel->GetAxis() * contactMotorDir : contactMotorDir;
|
||||
return true;
|
||||
}
|
||||
|
||||
idVec3 idAFBody::GetPointVelocity(const idVec3& point) const {
|
||||
const idVec3 linear(current.spatialVelocity[0],
|
||||
current.spatialVelocity[1], current.spatialVelocity[2]);
|
||||
const idVec3 angular(current.spatialVelocity[3],
|
||||
current.spatialVelocity[4], current.spatialVelocity[5]);
|
||||
const idVec3 origin = clipModel != nullptr
|
||||
? clipModel->GetOrigin() : current.worldOrigin;
|
||||
return linear + angular.Cross(point - origin);
|
||||
}
|
||||
|
||||
void idAFBody::AddForce(const idVec3& point, const idVec3& force) {
|
||||
current.externalForce[0] += force.x;
|
||||
current.externalForce[1] += force.y;
|
||||
current.externalForce[2] += force.z;
|
||||
const idVec3 origin = clipModel != nullptr
|
||||
? clipModel->GetOrigin() : current.worldOrigin;
|
||||
const idVec3 torque = (point - origin).Cross(force);
|
||||
current.externalForce[3] += torque.x;
|
||||
current.externalForce[4] += torque.y;
|
||||
current.externalForce[5] += torque.z;
|
||||
}
|
||||
|
||||
void idAFBody::Serialize(idSerializer* const serializer) {
|
||||
if (serializer != nullptr) GameLib_SerializeAFBody(serializer, *this);
|
||||
}
|
||||
@@ -1,70 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\afbody.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "cm/jobs/collisionquery.h"
|
||||
#include "idlib/containers/list.h"
|
||||
#include "idlib/math/spatialmat.h"
|
||||
#include "idlib/text/atomicstring.h"
|
||||
|
||||
#ifndef ID_CLIP_QUERY_DEFINED
|
||||
#define ID_CLIP_QUERY_DEFINED
|
||||
struct idClipQuery { std::uint64_t index; };
|
||||
#endif
|
||||
|
||||
// IDA Local Type ordinal 14602; PDB kind: class.
|
||||
class idAFBody
|
||||
{
|
||||
class idAFConstraint;
|
||||
class idAFTree;
|
||||
class idClipModel;
|
||||
class idSerializer;
|
||||
|
||||
struct AFBodyPState_t {
|
||||
idVec3 worldOrigin;
|
||||
idMat3 worldAxis;
|
||||
idVec3 atRestOrigin;
|
||||
idMat3 atRestAxis;
|
||||
idVec6 spatialVelocity;
|
||||
idVec6 externalForce;
|
||||
};
|
||||
|
||||
class alignas(16) idAFBody {
|
||||
public:
|
||||
// Recovered virtual interface; IDA vtable ordinal 14603.
|
||||
virtual ~idAFBody();
|
||||
virtual void Serialize(idSerializer *);
|
||||
struct afBodyFlags_t {
|
||||
std::uint8_t clearClipMaskInSolid : 1;
|
||||
std::uint8_t noSyncCollide : 1;
|
||||
std::uint8_t isZero : 1;
|
||||
std::uint8_t useContactMotorDir : 1;
|
||||
std::uint8_t useFrictionDir : 1;
|
||||
std::uint8_t spatialInertiaSparse : 1;
|
||||
std::uint8_t selfCollision : 1;
|
||||
std::uint8_t clipMaskSet : 1;
|
||||
};
|
||||
|
||||
__declspec(align(16)) idAtomicString name;
|
||||
idClipModel *clipModel;
|
||||
int clipMask;
|
||||
float linearFrictionWater;
|
||||
float angularFrictionWater;
|
||||
float linearFriction;
|
||||
float angularFriction;
|
||||
float contactFriction;
|
||||
float bouncyness;
|
||||
idVec3 frictionDir;
|
||||
idVec3 contactMotorDir;
|
||||
float contactMotorVelocity;
|
||||
float contactMotorForce;
|
||||
float mass;
|
||||
float invMass;
|
||||
idVec3 centerOfMass;
|
||||
idMat3 inertiaTensor;
|
||||
idMat3 inverseInertiaTensor;
|
||||
idAFBody *parent;
|
||||
idList<idAFBody *,71> children;
|
||||
idAFConstraint *primaryConstraint;
|
||||
idList<idAFConstraint *,71> constraints;
|
||||
idAFTree *tree;
|
||||
idAFBody::afBodyFlags_t fl;
|
||||
AFBodyPState_t current;
|
||||
AFBodyPState_t saved;
|
||||
idClipQuery motionQuery;
|
||||
idSpatialMat inverseWorldSpatialInertia;
|
||||
idSpatialMat I;
|
||||
idSpatialMat invI;
|
||||
idSpatialMat J;
|
||||
idStaticSpatialVec s;
|
||||
idStaticSpatialVec totalForce;
|
||||
idStaticSpatialVec auxForce;
|
||||
idStaticSpatialVec acceleration;
|
||||
float *response;
|
||||
int *responseIndex;
|
||||
int numResponses;
|
||||
int maxAuxiliaryIndex;
|
||||
int maxSubTreeAuxiliaryIndex;
|
||||
idAFBody();
|
||||
idAFBody(const char* name, idClipModel* clipModel, float density);
|
||||
virtual ~idAFBody();
|
||||
virtual void Serialize(idSerializer* serializer);
|
||||
|
||||
void Init();
|
||||
void SetClipModel(idClipModel* model);
|
||||
void SetBouncyness(float bounce);
|
||||
void SetFriction(float linear, float angular, float contact);
|
||||
void SetDensity(float density, const idMat3& inertiaScale);
|
||||
void SetFrictionDirection(const idVec3& direction);
|
||||
bool GetFrictionDirection(idVec3& direction) const;
|
||||
void SetContactMotorDirection(const idVec3& direction);
|
||||
bool GetContactMotorDirection(idVec3& direction) const;
|
||||
idVec3 GetPointVelocity(const idVec3& point) const;
|
||||
void AddForce(const idVec3& point, const idVec3& force);
|
||||
|
||||
alignas(16) idAtomicString name;
|
||||
idClipModel* clipModel;
|
||||
int clipMask;
|
||||
float linearFrictionWater;
|
||||
float angularFrictionWater;
|
||||
float linearFriction;
|
||||
float angularFriction;
|
||||
float contactFriction;
|
||||
float bouncyness;
|
||||
idVec3 frictionDir;
|
||||
idVec3 contactMotorDir;
|
||||
float contactMotorVelocity;
|
||||
float contactMotorForce;
|
||||
float mass;
|
||||
float invMass;
|
||||
idVec3 centerOfMass;
|
||||
idMat3 inertiaTensor;
|
||||
idMat3 inverseInertiaTensor;
|
||||
idAFBody* parent;
|
||||
idList<idAFBody*, 71> children;
|
||||
idAFConstraint* primaryConstraint;
|
||||
idList<idAFConstraint*, 71> constraints;
|
||||
idAFTree* tree;
|
||||
afBodyFlags_t fl;
|
||||
AFBodyPState_t current;
|
||||
AFBodyPState_t saved;
|
||||
idClipQuery motionQuery;
|
||||
idSpatialMat inverseWorldSpatialInertia;
|
||||
idSpatialMat I;
|
||||
idSpatialMat invI;
|
||||
idSpatialMat J;
|
||||
idStaticSpatialVec s;
|
||||
idStaticSpatialVec totalForce;
|
||||
idStaticSpatialVec auxForce;
|
||||
idStaticSpatialVec acceleration;
|
||||
float* response;
|
||||
int* responseIndex;
|
||||
int numResponses;
|
||||
int maxAuxiliaryIndex;
|
||||
int maxSubTreeAuxiliaryIndex;
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 14607; PDB kind: struct.
|
||||
struct idAFBody::afBodyFlags_t
|
||||
{
|
||||
__int8 clearClipMaskInSolid : 1;
|
||||
__int8 noSyncCollide : 1;
|
||||
__int8 isZero : 1;
|
||||
__int8 useContactMotorDir : 1;
|
||||
__int8 useFrictionDir : 1;
|
||||
__int8 spatialInertiaSparse : 1;
|
||||
__int8 selfCollision : 1;
|
||||
__int8 clipMaskSet : 1;
|
||||
};
|
||||
static_assert(sizeof(AFBodyPState_t) == 144,
|
||||
"Recovered articulated-body state ABI changed");
|
||||
static_assert(sizeof(idAFBody::afBodyFlags_t) == 1,
|
||||
"Recovered articulated-body flags ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idAFBody) == 816,
|
||||
"Recovered idAFBody ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "gamelib/physics/aftree.h"
|
||||
|
||||
#include "gamelib/physics/afbody.h"
|
||||
#include "gamelib/physics/clipmodel.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void GameLib_FactorAFConstraintTree(const idAFTree& tree);
|
||||
void GameLib_SolveAFConstraintTree(const idAFTree& tree,
|
||||
int auxiliaryIndex);
|
||||
void GameLib_CalculateAFConstraintResponse(const idAFTree& tree,
|
||||
const idAFConstraint* constraint, int row, int auxiliaryIndex);
|
||||
void GameLib_AccumulateAFConstraintForces(const idAFTree& tree,
|
||||
float timeStep);
|
||||
void GameLib_DrawAFBodyLink(const idVec3& parentOrigin,
|
||||
const idVec3& childOrigin, const idVec4& color);
|
||||
|
||||
idAFTree::idAFTree()
|
||||
: sortedBodies(4) {
|
||||
}
|
||||
|
||||
void idAFTree::SortBodies_r(idList<idAFBody*, 71>& sortedList,
|
||||
idAFBody* const body) {
|
||||
if (body == nullptr) return;
|
||||
sortedList.Append(body);
|
||||
body->tree = this;
|
||||
for (int index = 0; index < body->children.Num(); ++index) {
|
||||
idAFBody* const child = body->children[index];
|
||||
if (child != nullptr) {
|
||||
child->parent = body;
|
||||
SortBodies_r(sortedList, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void idAFTree::SortBodies() {
|
||||
idList<idAFBody*, 71> original = sortedBodies;
|
||||
idList<idAFBody*, 71> ordered(4);
|
||||
for (int index = 0; index < original.Num(); ++index) {
|
||||
idAFBody* const body = original[index];
|
||||
if (body != nullptr && body->parent == nullptr) {
|
||||
SortBodies_r(ordered, body);
|
||||
}
|
||||
}
|
||||
// A malformed or partially deserialized graph may have no root. Preserve
|
||||
// every body once instead of silently dropping it.
|
||||
for (int index = 0; index < original.Num(); ++index) {
|
||||
idAFBody* const body = original[index];
|
||||
bool found = false;
|
||||
for (int sorted = 0; sorted < ordered.Num(); ++sorted)
|
||||
if (ordered[sorted] == body) { found = true; break; }
|
||||
if (!found && body != nullptr) ordered.Append(body);
|
||||
}
|
||||
sortedBodies = ordered;
|
||||
}
|
||||
|
||||
void idAFTree::SetMaxSubTreeAuxiliaryIndex() {
|
||||
for (int index = sortedBodies.Num() - 1; index >= 0; --index) {
|
||||
idAFBody* const body = sortedBodies[index];
|
||||
if (body == nullptr) continue;
|
||||
body->maxSubTreeAuxiliaryIndex = body->maxAuxiliaryIndex;
|
||||
for (int childIndex = 0; childIndex < body->children.Num();
|
||||
++childIndex) {
|
||||
const idAFBody* const child = body->children[childIndex];
|
||||
if (child != nullptr) {
|
||||
body->maxSubTreeAuxiliaryIndex = (std::max)(
|
||||
body->maxSubTreeAuxiliaryIndex,
|
||||
child->maxSubTreeAuxiliaryIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void idAFTree::Factor() const {
|
||||
GameLib_FactorAFConstraintTree(*this);
|
||||
}
|
||||
|
||||
void idAFTree::Solve(const int auxiliaryIndex) const {
|
||||
GameLib_SolveAFConstraintTree(*this, auxiliaryIndex);
|
||||
}
|
||||
|
||||
void idAFTree::Response(const idAFConstraint* const constraint,
|
||||
const int row, const int auxiliaryIndex) const {
|
||||
if (constraint != nullptr) {
|
||||
GameLib_CalculateAFConstraintResponse(*this, constraint, row,
|
||||
auxiliaryIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void idAFTree::CalculateForces(const float timeStep) const {
|
||||
if (timeStep <= 0.0f) return;
|
||||
for (int index = 0; index < sortedBodies.Num(); ++index) {
|
||||
idAFBody* const body = sortedBodies[index];
|
||||
if (body == nullptr) continue;
|
||||
for (int component = 0; component < 6; ++component) {
|
||||
body->totalForce[component] =
|
||||
body->current.externalForce[component] +
|
||||
body->auxForce[component];
|
||||
}
|
||||
body->inverseWorldSpatialInertia.Multiply(body->acceleration,
|
||||
body->totalForce);
|
||||
const float inverseTimeStep = 1.0f / timeStep;
|
||||
for (int component = 0; component < 6; ++component) {
|
||||
body->acceleration[component] +=
|
||||
body->current.spatialVelocity[component] * inverseTimeStep;
|
||||
body->s[component] = 0.0f;
|
||||
}
|
||||
body->fl.isZero = 1;
|
||||
}
|
||||
GameLib_AccumulateAFConstraintForces(*this, timeStep);
|
||||
}
|
||||
|
||||
void idAFTree::DebugDraw(const idVec4& color) const {
|
||||
for (int index = 1; index < sortedBodies.Num(); ++index) {
|
||||
const idAFBody* const body = sortedBodies[index];
|
||||
if (body == nullptr || body->parent == nullptr ||
|
||||
body->clipModel == nullptr || body->parent->clipModel == nullptr) {
|
||||
continue;
|
||||
}
|
||||
GameLib_DrawAFBodyLink(body->parent->clipModel->GetOrigin(),
|
||||
body->clipModel->GetOrigin(), color);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\aftree.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "idlib/containers/list.h"
|
||||
#include "idlib/math/vector.h"
|
||||
|
||||
class idAFBody;
|
||||
class idAFConstraint;
|
||||
|
||||
// IDA Local Type ordinal 14606; PDB kind: class.
|
||||
class idAFTree
|
||||
{
|
||||
class idAFTree {
|
||||
public:
|
||||
idList<idAFBody *,71> sortedBodies;
|
||||
idAFTree();
|
||||
|
||||
void SortBodies();
|
||||
void SetMaxSubTreeAuxiliaryIndex();
|
||||
void Factor() const;
|
||||
void Solve(int auxiliaryIndex) const;
|
||||
void Response(const idAFConstraint* constraint, int row,
|
||||
int auxiliaryIndex) const;
|
||||
void CalculateForces(float timeStep) const;
|
||||
void DebugDraw(const idVec4& color) const;
|
||||
|
||||
idList<idAFBody*, 71> sortedBodies;
|
||||
|
||||
private:
|
||||
void SortBodies_r(idList<idAFBody*, 71>& sortedList,
|
||||
idAFBody* body);
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 33695; PDB kind: typedef.
|
||||
typedef void (__fastcall *Free_t)(void *);
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idAFTree) == 16,
|
||||
"Recovered idAFTree ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "gamelib/physics/buoyancy.h"
|
||||
|
||||
#include "gamelib/physics/physics.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
struct idBuoyancySample {
|
||||
idVec3 position;
|
||||
float weight;
|
||||
};
|
||||
|
||||
int GameLib_GetBuoyancySamples(const idClipModel* clipModel,
|
||||
idBuoyancySample* samples, int maxSamples);
|
||||
void GameLib_TransformBuoyancySample(const idClipModel* clipModel,
|
||||
const idVec3& localPosition, idVec3& worldPosition);
|
||||
int GameLib_EvaluateBuoyantBodies(idClip* clip, idPhysics* physics,
|
||||
int clipMask, surfTypes_t surfaceOverride, idBuoyancyResult* results,
|
||||
int maxResults);
|
||||
void GameLib_ApplyWaterDamage(const idDeclDamage* damage,
|
||||
idPhysics* physics, int bodyId, float waterLevel);
|
||||
|
||||
idBuoyancy::idBuoyancy()
|
||||
: buoyantClipModels() {
|
||||
}
|
||||
|
||||
void idBuoyancy::CalculateBuoyancyWeights(
|
||||
const int* const polytopeNumPlanes,
|
||||
const idPlane* const polytopePlanes, const int numPolytopes,
|
||||
const idClipModel* const clipModel, float* const weights) {
|
||||
if (weights == nullptr || numPolytopes <= 0) {
|
||||
return;
|
||||
}
|
||||
for (int polytope = 0; polytope < numPolytopes; ++polytope) {
|
||||
weights[polytope] = 0.0f;
|
||||
}
|
||||
if (polytopeNumPlanes == nullptr || polytopePlanes == nullptr ||
|
||||
clipModel == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
idBuoyancySample samples[64]{};
|
||||
const int sampleCount = (std::max)(0, (std::min)(64,
|
||||
GameLib_GetBuoyancySamples(clipModel, samples, 64)));
|
||||
int firstPlane = 0;
|
||||
for (int polytope = 0; polytope < numPolytopes; ++polytope) {
|
||||
const int planeCount = (std::max)(0,
|
||||
polytopeNumPlanes[polytope]);
|
||||
for (int sampleIndex = 0; sampleIndex < sampleCount;
|
||||
++sampleIndex) {
|
||||
idVec3 worldPosition;
|
||||
GameLib_TransformBuoyancySample(clipModel,
|
||||
samples[sampleIndex].position, worldPosition);
|
||||
bool inside = true;
|
||||
for (int planeIndex = 0; planeIndex < planeCount;
|
||||
++planeIndex) {
|
||||
const idPlane& plane = polytopePlanes[
|
||||
firstPlane + planeIndex];
|
||||
if (plane.Distance(worldPosition) > 0.0f) {
|
||||
inside = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inside) {
|
||||
weights[polytope] += samples[sampleIndex].weight;
|
||||
}
|
||||
}
|
||||
firstPlane += planeCount;
|
||||
}
|
||||
}
|
||||
|
||||
void idBuoyancy::ApplyBuoyancy(idClip* const clip,
|
||||
idPhysics* const physics, const float timeStep,
|
||||
const idDeclDamage* const waterDamage, const idVec3& waterCurrent,
|
||||
const float waterDensity, const float waterViscosity,
|
||||
const int clipMask, const surfTypes_t surfaceOverride) {
|
||||
buoyantClipModels.Clear();
|
||||
if (clip == nullptr || physics == nullptr || timeStep <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
idBuoyancyResult results[128]{};
|
||||
const int resultCount = (std::max)(0, (std::min)(128,
|
||||
GameLib_EvaluateBuoyantBodies(clip, physics, clipMask,
|
||||
surfaceOverride, results, 128)));
|
||||
float maximumWaterLevel = 0.0f;
|
||||
for (int index = 0; index < resultCount; ++index) {
|
||||
const idBuoyancyResult& result = results[index];
|
||||
if (result.displacedVolume <= 0.0f) {
|
||||
continue;
|
||||
}
|
||||
buoyantClipModel_t body{};
|
||||
body.physicsId = physics->GetPhysicsId();
|
||||
body.bodyId = result.bodyId;
|
||||
buoyantClipModels.Append(body);
|
||||
|
||||
const idVec3 gravity = *physics->GetGravity();
|
||||
const idVec3 buoyancyForce = gravity *
|
||||
(-waterDensity * result.displacedVolume);
|
||||
const idVec3 relativeVelocity = waterCurrent -
|
||||
result.linearVelocity;
|
||||
const idVec3 dragForce = relativeVelocity *
|
||||
(waterViscosity * result.displacedVolume);
|
||||
const idVec3 totalForce = buoyancyForce + dragForce;
|
||||
physics->ApplyForce(result.bodyId, &result.centerOfBuoyancy,
|
||||
&totalForce);
|
||||
maximumWaterLevel = (std::max)(maximumWaterLevel,
|
||||
result.waterLevel);
|
||||
if (waterDamage != nullptr && result.waterLevel > 0.0f) {
|
||||
GameLib_ApplyWaterDamage(waterDamage, physics, result.bodyId,
|
||||
result.waterLevel);
|
||||
}
|
||||
}
|
||||
physics->SetWaterLevel(maximumWaterLevel, -1);
|
||||
physics->SetWaterViscosity(waterViscosity, -1);
|
||||
}
|
||||
@@ -1,14 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\buoyancy.h
|
||||
// Recovered logical types: 1
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "idlib/containers/staticlist.h"
|
||||
#include "idlib/math/plane.h"
|
||||
#include "idlib/math/vector.h"
|
||||
|
||||
class idClip;
|
||||
class idClipModel;
|
||||
class idDeclDamage;
|
||||
class idPhysics;
|
||||
enum surfTypes_t : int;
|
||||
|
||||
// IDA Local Type ordinal 18845; PDB kind: class.
|
||||
class idBuoyancy
|
||||
{
|
||||
public:
|
||||
idStaticList<buoyantClipModel_t,128> buoyantClipModels;
|
||||
struct buoyantClipModel_t {
|
||||
int physicsId;
|
||||
int bodyId;
|
||||
};
|
||||
|
||||
struct idBuoyancyResult {
|
||||
int bodyId;
|
||||
idVec3 centerOfBuoyancy;
|
||||
idVec3 linearVelocity;
|
||||
float displacedVolume;
|
||||
float waterLevel;
|
||||
};
|
||||
|
||||
class idBuoyancy {
|
||||
public:
|
||||
idBuoyancy();
|
||||
|
||||
void CalculateBuoyancyWeights(const int* polytopeNumPlanes,
|
||||
const idPlane* polytopePlanes, int numPolytopes,
|
||||
const idClipModel* clipModel, float* weights);
|
||||
void ApplyBuoyancy(idClip* clip, idPhysics* physics, float timeStep,
|
||||
const idDeclDamage* waterDamage, const idVec3& waterCurrent,
|
||||
float waterDensity, float waterViscosity, int clipMask,
|
||||
surfTypes_t surfaceOverride);
|
||||
|
||||
idStaticList<buoyantClipModel_t, 128> buoyantClipModels;
|
||||
};
|
||||
|
||||
static_assert(sizeof(buoyantClipModel_t) == 8,
|
||||
"Recovered buoyant clip-model ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idBuoyancy) == 1040,
|
||||
"Recovered idBuoyancy ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -159,6 +159,8 @@ private:
|
||||
static idPhysics* hash[1024];
|
||||
static int currentPhysicsId;
|
||||
|
||||
protected:
|
||||
|
||||
alignas(8) physicsType_t type;
|
||||
int physicsId;
|
||||
int entityNumber;
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#include "gamelib/physics/physics_actor.h"
|
||||
|
||||
#include "gamelib/physics/clip.h"
|
||||
#include "gamelib/physics/clipmodel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
int GameLib_GetPhysicsCurrentTime(const idPhysics* physics);
|
||||
|
||||
namespace {
|
||||
|
||||
const idBounds kActorZeroBounds{{idVec3(0.0f, 0.0f, 0.0f),
|
||||
idVec3(0.0f, 0.0f, 0.0f)}};
|
||||
const idVec3 kActorZeroOrigin(0.0f, 0.0f, 0.0f);
|
||||
const idMat3 kActorIdentityAxis(1.0f);
|
||||
|
||||
int ClampClipIndex(const int id) {
|
||||
return id >= 0 && id < idPhysics_Actor::ACTORCLIP_MAX ? id : 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
idPhysics_Actor::idPhysics_Actor()
|
||||
: idPhysics_DynamicBase()
|
||||
, clipModels{nullptr, nullptr}
|
||||
, clipMasks{0, 0}
|
||||
, clipModelAxis(1.0f)
|
||||
, mass(100.0f)
|
||||
, invMass(0.01f)
|
||||
, hasMaster(false)
|
||||
, masterYaw(0.0f)
|
||||
, masterDeltaYaw(0.0f)
|
||||
, wasHistoryInitialized(false)
|
||||
, lastHistorySaveTime(0)
|
||||
, originHistory{}
|
||||
, yawHistory{} {
|
||||
}
|
||||
|
||||
idPhysics_Actor::~idPhysics_Actor() {
|
||||
UnlinkClip();
|
||||
clipModels[0] = nullptr;
|
||||
clipModels[1] = nullptr;
|
||||
}
|
||||
|
||||
void idPhysics_Actor::SetClipModel(idClipModel* const model,
|
||||
const float density, const int id, const bool freeOld) {
|
||||
const int index = ClampClipIndex(id);
|
||||
if (clipModels[index] != nullptr && clipModels[index] != model &&
|
||||
freeOld) {
|
||||
clipModels[index]->Delete();
|
||||
}
|
||||
clipModels[index] = model;
|
||||
if (model != nullptr) {
|
||||
if (density > 0.0f && index == ACTORCLIP_DEFAULT) {
|
||||
float modelMass = 0.0f;
|
||||
idVec3 center;
|
||||
idMat3 inertia;
|
||||
model->GetMassProperties(density, modelMass, center, inertia);
|
||||
if (modelMass > 0.0f) SetMass(modelMass, index);
|
||||
}
|
||||
model->Link(GetEntityNumber(), GetEntityNumber(), index,
|
||||
model->GetOrigin(), clipModelAxis);
|
||||
}
|
||||
}
|
||||
|
||||
idClipModel* idPhysics_Actor::GetClipModel(const int id) {
|
||||
return clipModels[ClampClipIndex(id)];
|
||||
}
|
||||
|
||||
int idPhysics_Actor::GetNumClipModels() {
|
||||
return (clipModels[0] != nullptr ? 1 : 0) +
|
||||
(clipModels[1] != nullptr ? 1 : 0);
|
||||
}
|
||||
|
||||
void idPhysics_Actor::SetMass(const float newMass, const int id) {
|
||||
(void)id;
|
||||
mass = (std::max)(1.0e-6f, newMass);
|
||||
invMass = 1.0f / mass;
|
||||
}
|
||||
float idPhysics_Actor::GetMass(int) { return mass; }
|
||||
|
||||
void idPhysics_Actor::SetContents(const int contents, const int id) {
|
||||
idClipModel* const model = clipModels[ClampClipIndex(id)];
|
||||
if (model != nullptr) model->SetContents(contents);
|
||||
}
|
||||
int idPhysics_Actor::GetContents(const int id) {
|
||||
idClipModel* const model = clipModels[ClampClipIndex(id)];
|
||||
return model != nullptr ? model->GetContents() : 0;
|
||||
}
|
||||
void idPhysics_Actor::SetClipMask(const int mask, const int id) {
|
||||
clipMasks[ClampClipIndex(id)] = mask;
|
||||
if (id <= 0) idPhysics_DynamicBase::SetClipMask(mask, id);
|
||||
}
|
||||
int idPhysics_Actor::GetClipMask(const int id) {
|
||||
return clipMasks[ClampClipIndex(id)];
|
||||
}
|
||||
const idBounds* idPhysics_Actor::GetBounds(const int id) {
|
||||
idClipModel* const model = clipModels[ClampClipIndex(id)];
|
||||
return model != nullptr ? &model->GetBounds() : &kActorZeroBounds;
|
||||
}
|
||||
const idBounds* idPhysics_Actor::GetAbsBounds(const int id) {
|
||||
idClipModel* const model = clipModels[ClampClipIndex(id)];
|
||||
return model != nullptr ? &model->GetAbsBounds() : &kActorZeroBounds;
|
||||
}
|
||||
const idVec3* idPhysics_Actor::GetOrigin(const int id) {
|
||||
idClipModel* const model = clipModels[ClampClipIndex(id)];
|
||||
return model != nullptr ? &model->GetOrigin() : &kActorZeroOrigin;
|
||||
}
|
||||
const idMat3* idPhysics_Actor::GetAxis(const int id) {
|
||||
idClipModel* const model = clipModels[ClampClipIndex(id)];
|
||||
return model != nullptr ? &model->GetAxis() : &kActorIdentityAxis;
|
||||
}
|
||||
|
||||
void idPhysics_Actor::SetGravity(const idVec3* const gravity) {
|
||||
idPhysics_DynamicBase::SetGravity(gravity);
|
||||
SetClipModelAxis();
|
||||
}
|
||||
|
||||
bool idPhysics_Actor::IsPushable(int) { return false; }
|
||||
|
||||
void idPhysics_Actor::DisableClip() {
|
||||
DisableClip(ACTORCLIP_DEFAULT);
|
||||
DisableClip(ACTORCLIP_PLAYER);
|
||||
}
|
||||
void idPhysics_Actor::EnableClip() {
|
||||
EnableClip(ACTORCLIP_DEFAULT);
|
||||
EnableClip(ACTORCLIP_PLAYER);
|
||||
}
|
||||
void idPhysics_Actor::DisableClip(const actorClipModel_t type_) {
|
||||
if (clipModels[type_] != nullptr) clipModels[type_]->Disable();
|
||||
}
|
||||
void idPhysics_Actor::EnableClip(const actorClipModel_t type_) {
|
||||
if (clipModels[type_] != nullptr) clipModels[type_]->Enable();
|
||||
}
|
||||
void idPhysics_Actor::UnlinkClip() {
|
||||
for (idClipModel* model : clipModels)
|
||||
if (model != nullptr) model->Unlink();
|
||||
}
|
||||
void idPhysics_Actor::LinkClip() {
|
||||
LinkClip(*GetOrigin(0), clipModelAxis);
|
||||
}
|
||||
void idPhysics_Actor::LinkClip(const idVec3& origin,
|
||||
const idMat3& axis) {
|
||||
for (int index = 0; index < ACTORCLIP_MAX; ++index) {
|
||||
if (clipModels[index] != nullptr) {
|
||||
clipModels[index]->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
index, origin, axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void idPhysics_Actor::SetClipModelAxis() {
|
||||
idVec3 down = gravityNormal;
|
||||
if (down.NormalizeFast() == 0.0f) {
|
||||
clipModelAxis = idMat3(1.0f);
|
||||
return;
|
||||
}
|
||||
idVec3 right = std::fabs(down.z) < 0.7f
|
||||
? down.Cross(idVec3(0.0f, 0.0f, 1.0f))
|
||||
: down.Cross(idVec3(0.0f, 1.0f, 0.0f));
|
||||
right.NormalizeFast();
|
||||
idVec3 forward = right.Cross(down);
|
||||
forward.NormalizeFast();
|
||||
clipModelAxis[0] = forward;
|
||||
clipModelAxis[1] = right;
|
||||
clipModelAxis[2] = -down;
|
||||
}
|
||||
|
||||
bool idPhysics_Actor::EvaluateContacts() {
|
||||
ClearContacts();
|
||||
for (idClipModel* model : clipModels)
|
||||
if (model != nullptr) AddGroundContacts(model, 12 - contacts.Num());
|
||||
return contacts.Num() > 0;
|
||||
}
|
||||
|
||||
void idPhysics_Actor::ClipTranslation(trace_t* const results,
|
||||
const idVec3* const translation, const idClipModel* const model) {
|
||||
idPhysics_DynamicBase::ClipTranslation(results, translation,
|
||||
model != nullptr ? model : clipModels[0]);
|
||||
}
|
||||
|
||||
void idPhysics_Actor::ClipRotation(trace_t* const results,
|
||||
const idRotation* const rotation, const idClipModel* const model) {
|
||||
if (results == nullptr) return;
|
||||
const idClipModel* moving = model != nullptr ? model : clipModels[0];
|
||||
if (clip == nullptr || moving == nullptr || rotation == nullptr) {
|
||||
std::memset(results, 0, sizeof(*results));
|
||||
results->fraction = 1.0f;
|
||||
return;
|
||||
}
|
||||
clip->Rotation(results, moving->GetOrigin(), *rotation, moving,
|
||||
moving->GetAxis(), clipMasks[0], GetEntityNumber(), false,
|
||||
"idPhysics_Actor::ClipRotation");
|
||||
}
|
||||
|
||||
int idPhysics_Actor::ClipContents(const idClipModel* const model,
|
||||
const int id) {
|
||||
idClipModel* const self = clipModels[ClampClipIndex(id)];
|
||||
if (clip == nullptr || model == nullptr || self == nullptr) return 0;
|
||||
trace_t result{};
|
||||
clip->ContentsModel(result, self->GetOrigin(), self, self->GetAxis(),
|
||||
clipMasks[ClampClipIndex(id)], model->GetOrigin(), model,
|
||||
model->GetAxis());
|
||||
return result.c.contentFlags;
|
||||
}
|
||||
|
||||
float idPhysics_Actor::GetMasterDeltaYaw() const { return masterDeltaYaw; }
|
||||
|
||||
void idPhysics_Actor::RememberHistorySample() {
|
||||
const int time = GameLib_GetPhysicsCurrentTime(this);
|
||||
const idVec3 currentOrigin = *const_cast<idPhysics_Actor*>(this)->GetOrigin(0);
|
||||
if (!wasHistoryInitialized) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
originHistory[i] = currentOrigin;
|
||||
yawHistory[i] = masterYaw;
|
||||
}
|
||||
wasHistoryInitialized = true;
|
||||
} else {
|
||||
for (int i = 15; i > 0; --i) {
|
||||
originHistory[i] = originHistory[i - 1];
|
||||
yawHistory[i] = yawHistory[i - 1];
|
||||
}
|
||||
originHistory[0] = currentOrigin;
|
||||
yawHistory[0] = masterYaw;
|
||||
}
|
||||
lastHistorySaveTime = time;
|
||||
}
|
||||
|
||||
idVec3 idPhysics_Actor::GetOriginHistory(const int millisecondsAgo) const {
|
||||
if (!wasHistoryInitialized) return kActorZeroOrigin;
|
||||
const int sample = (std::max)(0, (std::min)(15,
|
||||
(millisecondsAgo + 7) / 16));
|
||||
return originHistory[sample];
|
||||
}
|
||||
|
||||
idVec3 idPhysics_Actor::GetVelocityHistory(const int millisecondsAgo) const {
|
||||
if (!wasHistoryInitialized) return kActorZeroOrigin;
|
||||
const int sample = (std::max)(1, (std::min)(15,
|
||||
(millisecondsAgo + 7) / 16));
|
||||
return (originHistory[0] - originHistory[sample]) *
|
||||
(1000.0f / static_cast<float>(sample * 16));
|
||||
}
|
||||
@@ -1,115 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_actor.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/physics/physics_dynamicbase.h"
|
||||
#include "idlib/math/rotation.h"
|
||||
|
||||
|
||||
// IDA Local Type ordinal 2021; PDB kind: enum.
|
||||
enum idPhysics_Actor::actorClipModel_t : __int32
|
||||
{
|
||||
ACTORCLIP_DEFAULT = 0x0,
|
||||
ACTORCLIP_PLAYER = 0x1,
|
||||
ACTORCLIP_MAX = 0x2,
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 15362; PDB kind: class.
|
||||
class idPhysics_Actor : public idPhysics_DynamicBase
|
||||
{
|
||||
class idPhysics_Actor : public idPhysics_DynamicBase {
|
||||
public:
|
||||
// Recovered virtual interface; IDA vtable ordinal 15363.
|
||||
virtual ~idPhysics_Actor();
|
||||
virtual void SetClipModel(idClipModel *, float, int, bool);
|
||||
virtual idClipModel *GetClipModel(int);
|
||||
virtual int GetNumClipModels();
|
||||
virtual void SetMass(float, int);
|
||||
virtual float GetMass(int);
|
||||
virtual void SetContents(int, int);
|
||||
virtual int GetContents(int);
|
||||
virtual void SetClipMask(int, int);
|
||||
virtual int GetClipMask(int);
|
||||
virtual const idBounds *GetBounds(int);
|
||||
virtual const idBounds *GetAbsBounds(int);
|
||||
virtual void SetOrigin(const idVec3 *, int);
|
||||
virtual void SetAxis(const idMat3 *, int);
|
||||
virtual void Translate(const idVec3 *, int);
|
||||
virtual void Rotate(const idRotation *, int);
|
||||
virtual const idVec3 *GetOrigin(int);
|
||||
virtual const idMat3 *GetAxis(int);
|
||||
virtual const idVec3 *GetLocalOrigin(int);
|
||||
virtual const idMat3 *GetLocalAxis(int);
|
||||
virtual void SetLinearVelocity(const idVec3 *, int);
|
||||
virtual void SetAngularVelocity(const idVec3 *, int);
|
||||
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
|
||||
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
|
||||
virtual void SetGravity(const idVec3 *);
|
||||
virtual const idVec3 *GetGravity();
|
||||
virtual const idVec3 *GetGravityNormal();
|
||||
virtual void SetWaterLevel(float, int);
|
||||
virtual float GetWaterLevel(int);
|
||||
virtual void SetWaterViscosity(float, int);
|
||||
virtual float GetWaterViscosity(int);
|
||||
virtual void SetWaterEntNum(int);
|
||||
virtual int GetWaterEntNum();
|
||||
virtual void SetWaterSurfaceWrldHeight(float);
|
||||
virtual float GetWaterSurfaceWrldHeight();
|
||||
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
|
||||
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
|
||||
virtual void Activate();
|
||||
virtual void PutToRest();
|
||||
virtual bool IsAtRest();
|
||||
virtual bool IsPushable(int);
|
||||
virtual void SaveState();
|
||||
virtual void RestoreState();
|
||||
virtual bool Evaluate(int, int);
|
||||
virtual void UpdateTime(int);
|
||||
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
|
||||
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
|
||||
virtual int ClipContents(const idClipModel *, int);
|
||||
virtual void DisableClip();
|
||||
virtual void EnableClip();
|
||||
virtual void UnlinkClip();
|
||||
virtual void LinkClip();
|
||||
virtual bool EvaluateContacts();
|
||||
virtual int GetNumContacts();
|
||||
virtual const contactInfo_t *GetContact(int);
|
||||
virtual void ClearContacts();
|
||||
virtual void AddContactPhysics(idPhysics *);
|
||||
virtual void RemoveContactPhysics(idPhysics *);
|
||||
virtual int GetNumContactPhysics();
|
||||
virtual idPhysics *GetContactPhysics(int);
|
||||
virtual void ActivateContactPhysics();
|
||||
virtual bool HasGroundContacts();
|
||||
virtual bool IsGroundEntity(int);
|
||||
virtual bool IsGroundClipModel(int, int);
|
||||
virtual void SetPushed(int);
|
||||
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
|
||||
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
|
||||
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
|
||||
virtual void SetLocalOrigin(const idVec3 *, int);
|
||||
virtual void SetLocalAxis(const idMat3 *, int);
|
||||
virtual int GetBlockingEntityNum();
|
||||
virtual int GetLinearEndTime();
|
||||
virtual int GetAngularEndTime();
|
||||
virtual bool IsInNonResidentCollisionArea(bool);
|
||||
virtual bool IsOutsideWorld();
|
||||
virtual const idMat3 *GetGravityAxis();
|
||||
virtual void DisableClip_2(const idPhysics_Actor::actorClipModel_t);
|
||||
virtual void EnableClip_2(const idPhysics_Actor::actorClipModel_t);
|
||||
virtual void LinkClip_2(const idVec3 *, const idMat3 *);
|
||||
enum actorClipModel_t : int {
|
||||
ACTORCLIP_DEFAULT = 0,
|
||||
ACTORCLIP_PLAYER = 1,
|
||||
ACTORCLIP_MAX = 2
|
||||
};
|
||||
|
||||
idClipModel *clipModels[2];
|
||||
int clipMasks[2];
|
||||
idMat3 clipModelAxis;
|
||||
float mass;
|
||||
float invMass;
|
||||
bool hasMaster;
|
||||
float masterYaw;
|
||||
float masterDeltaYaw;
|
||||
bool wasHistoryInitialized;
|
||||
int lastHistorySaveTime;
|
||||
idVec3 originHistory[16];
|
||||
float yawHistory[16];
|
||||
idPhysics_Actor();
|
||||
~idPhysics_Actor() override;
|
||||
|
||||
void SetClipModel(idClipModel*, float, int, bool) override;
|
||||
idClipModel* GetClipModel(int) override;
|
||||
int GetNumClipModels() override;
|
||||
void SetMass(float, int) override;
|
||||
float GetMass(int) override;
|
||||
void SetContents(int, int) override;
|
||||
int GetContents(int) override;
|
||||
void SetClipMask(int, int) override;
|
||||
int GetClipMask(int) override;
|
||||
const idBounds* GetBounds(int) override;
|
||||
const idBounds* GetAbsBounds(int) override;
|
||||
const idVec3* GetOrigin(int) override;
|
||||
const idMat3* GetAxis(int) override;
|
||||
void SetGravity(const idVec3*) override;
|
||||
bool IsPushable(int) override;
|
||||
void ClipTranslation(trace_t*, const idVec3*,
|
||||
const idClipModel*) override;
|
||||
void ClipRotation(trace_t*, const idRotation*,
|
||||
const idClipModel*) override;
|
||||
int ClipContents(const idClipModel*, int) override;
|
||||
void DisableClip() override;
|
||||
void EnableClip() override;
|
||||
void UnlinkClip() override;
|
||||
void LinkClip() override;
|
||||
bool EvaluateContacts() override;
|
||||
|
||||
void DisableClip(actorClipModel_t clipType);
|
||||
void EnableClip(actorClipModel_t clipType);
|
||||
void LinkClip(const idVec3& origin, const idMat3& axis);
|
||||
void SetClipModelAxis();
|
||||
float GetMasterDeltaYaw() const;
|
||||
void RememberHistorySample();
|
||||
idVec3 GetOriginHistory(int millisecondsAgo) const;
|
||||
idVec3 GetVelocityHistory(int millisecondsAgo) const;
|
||||
|
||||
idClipModel* clipModels[ACTORCLIP_MAX];
|
||||
int clipMasks[ACTORCLIP_MAX];
|
||||
idMat3 clipModelAxis;
|
||||
float mass;
|
||||
float invMass;
|
||||
bool hasMaster;
|
||||
float masterYaw;
|
||||
float masterDeltaYaw;
|
||||
bool wasHistoryInitialized;
|
||||
int lastHistorySaveTime;
|
||||
idVec3 originHistory[16];
|
||||
float yawHistory[16];
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idPhysics_Actor) == 456,
|
||||
"Recovered idPhysics_Actor ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
#include "gamelib/physics/physics_dynamicbase.h"
|
||||
|
||||
#include "gamelib/physics/clip.h"
|
||||
#include "gamelib/physics/clipmodel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
void GameLib_ActivateContactPhysics(idPhysics* physics);
|
||||
void GameLib_DrawPhysicsVelocity(const idVec3& origin,
|
||||
const idVec3& linearVelocity, const idVec3& angularVelocity,
|
||||
float angularScale);
|
||||
|
||||
idPhysics_DynamicBase::idPhysics_DynamicBase()
|
||||
: idPhysics()
|
||||
, clipMask(0)
|
||||
, gravityVector(0.0f, 0.0f, -1066.0f)
|
||||
, gravityNormal(0.0f, 0.0f, -1.0f)
|
||||
, contacts(4)
|
||||
, contactPhysicsIds(4)
|
||||
, waterLevel(0.0f)
|
||||
, waterViscosity(0.0f) {
|
||||
}
|
||||
|
||||
idPhysics_DynamicBase::~idPhysics_DynamicBase() {
|
||||
contacts.Clear();
|
||||
contactPhysicsIds.Clear();
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::SetClipMask(const int mask, const int id) {
|
||||
(void)id;
|
||||
clipMask = mask;
|
||||
}
|
||||
|
||||
const idBounds* idPhysics_DynamicBase::GetAbsBounds(const int id) {
|
||||
const idClipModel* const model = GetClipModel(id);
|
||||
if (model != nullptr) {
|
||||
return &model->GetAbsBounds();
|
||||
}
|
||||
static const idBounds empty{{idVec3(0.0f, 0.0f, 0.0f),
|
||||
idVec3(0.0f, 0.0f, 0.0f)}};
|
||||
return ∅
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::ClipTranslation(trace_t* const results,
|
||||
const idVec3* const translation, const idClipModel* const model) {
|
||||
if (results == nullptr) {
|
||||
return;
|
||||
}
|
||||
const idClipModel* const clipModel = model != nullptr
|
||||
? model : GetClipModel(0);
|
||||
if (clip == nullptr || clipModel == nullptr || translation == nullptr) {
|
||||
std::memset(results, 0, sizeof(*results));
|
||||
results->fraction = 1.0f;
|
||||
return;
|
||||
}
|
||||
const idVec3& start = clipModel->GetOrigin();
|
||||
clip->Translation(results, start, start + *translation, clipModel,
|
||||
clipModel->GetAxis(), clipMask, GetEntityNumber(), false,
|
||||
"idPhysics_DynamicBase::ClipTranslation");
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::SetGravity(const idVec3* const gravity) {
|
||||
if (gravity == nullptr) {
|
||||
return;
|
||||
}
|
||||
gravityVector = *gravity;
|
||||
gravityNormal = gravityVector;
|
||||
if (gravityNormal.NormalizeFast() == 0.0f) {
|
||||
gravityNormal.Zero();
|
||||
}
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::SetWaterLevel(const float level, const int id) {
|
||||
(void)id;
|
||||
waterLevel = (std::max)(0.0f, (std::min)(1.0f, level));
|
||||
}
|
||||
|
||||
float idPhysics_DynamicBase::GetWaterLevel(const int id) {
|
||||
(void)id;
|
||||
return waterLevel;
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::SetWaterViscosity(const float viscosity,
|
||||
const int id) {
|
||||
(void)id;
|
||||
waterViscosity = (std::max)(0.0f, viscosity);
|
||||
}
|
||||
|
||||
float idPhysics_DynamicBase::GetWaterViscosity(const int id) {
|
||||
(void)id;
|
||||
return waterViscosity;
|
||||
}
|
||||
|
||||
const contactInfo_t* idPhysics_DynamicBase::GetContact(const int index) {
|
||||
return index >= 0 && index < contacts.Num() ? &contacts[index] : nullptr;
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::ClearContacts() {
|
||||
for (int index = 0; index < contacts.Num(); ++index) {
|
||||
idPhysics* const other = idPhysics::GetPhysicsForId(
|
||||
contacts[index].physicsId);
|
||||
if (other != nullptr && other != this) {
|
||||
other->RemoveContactPhysics(this);
|
||||
}
|
||||
}
|
||||
contacts.Clear();
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::AddContactPhysics(idPhysics* const physics) {
|
||||
if (physics == nullptr || physics == this) {
|
||||
return;
|
||||
}
|
||||
const int id = physics->GetPhysicsId();
|
||||
for (int index = 0; index < contactPhysicsIds.Num(); ++index) {
|
||||
if (contactPhysicsIds[index] == id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
contactPhysicsIds.Append(id);
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::RemoveContactPhysics(idPhysics* const physics) {
|
||||
if (physics == nullptr) {
|
||||
return;
|
||||
}
|
||||
const int id = physics->GetPhysicsId();
|
||||
for (int index = contactPhysicsIds.Num() - 1; index >= 0; --index) {
|
||||
if (contactPhysicsIds[index] == id) {
|
||||
contactPhysicsIds.RemoveIndexFast(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idPhysics* idPhysics_DynamicBase::GetContactPhysics(const int index) {
|
||||
if (index < 0 || index >= contactPhysicsIds.Num()) {
|
||||
return nullptr;
|
||||
}
|
||||
return idPhysics::GetPhysicsForId(contactPhysicsIds[index]);
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::ActivateContactPhysics() {
|
||||
for (int index = contactPhysicsIds.Num() - 1; index >= 0; --index) {
|
||||
idPhysics* const physics = idPhysics::GetPhysicsForId(
|
||||
contactPhysicsIds[index]);
|
||||
if (physics == nullptr) {
|
||||
contactPhysicsIds.RemoveIndexFast(index);
|
||||
continue;
|
||||
}
|
||||
GameLib_ActivateContactPhysics(physics);
|
||||
}
|
||||
}
|
||||
|
||||
bool idPhysics_DynamicBase::HasGroundContacts() {
|
||||
for (int index = 0; index < contacts.Num(); ++index) {
|
||||
if (contacts[index].normal.Dot(-gravityNormal) > 0.0f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool idPhysics_DynamicBase::IsGroundEntity(const int entityNumber_) {
|
||||
for (int index = 0; index < contacts.Num(); ++index) {
|
||||
if (contacts[index].entityNum == entityNumber_ &&
|
||||
contacts[index].normal.Dot(gravityNormal) < -0.1f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool idPhysics_DynamicBase::IsGroundClipModel(const int entityNumber_,
|
||||
const int bodyId) {
|
||||
for (int index = 0; index < contacts.Num(); ++index) {
|
||||
if (contacts[index].entityNum == entityNumber_ &&
|
||||
contacts[index].bodyId == bodyId &&
|
||||
contacts[index].normal.Dot(gravityNormal) < -0.98480773f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::AddContactPhysicsForContacts() {
|
||||
for (int index = 0; index < contacts.Num(); ++index) {
|
||||
idPhysics* const physics = idPhysics::GetPhysicsForId(
|
||||
contacts[index].physicsId);
|
||||
if (physics != nullptr && physics != this) {
|
||||
physics->AddContactPhysics(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::AddGroundContacts(const idClipModel* const model,
|
||||
const int maxContacts) {
|
||||
if (clip == nullptr || model == nullptr || maxContacts <= 0) {
|
||||
return;
|
||||
}
|
||||
contactsResult_t results{};
|
||||
clip->Contacts(&results, model->GetOrigin(), gravityNormal, 0.25f,
|
||||
model, model->GetAxis(), clipMask, GetEntityNumber(),
|
||||
"idPhysics_DynamicBase::AddGroundContacts");
|
||||
const int count = (std::min)(results.numContacts, maxContacts);
|
||||
for (int index = 0; index < count; ++index) {
|
||||
contacts.Append(results.contacts[index]);
|
||||
UpdateCollisionResidency(results.contacts[index]);
|
||||
}
|
||||
AddContactPhysicsForContacts();
|
||||
}
|
||||
|
||||
bool idPhysics_DynamicBase::IsOutsideWorld() {
|
||||
if (clip == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const idBounds& world = clip->GetWorldBounds();
|
||||
const idBounds* const object = GetAbsBounds(-1);
|
||||
return (*object)[1].x < world[0].x - 1024.0f ||
|
||||
(*object)[1].y < world[0].y - 1024.0f ||
|
||||
(*object)[1].z < world[0].z - 1024.0f ||
|
||||
(*object)[0].x > world[1].x + 1024.0f ||
|
||||
(*object)[0].y > world[1].y + 1024.0f ||
|
||||
(*object)[0].z > world[1].z + 1024.0f;
|
||||
}
|
||||
|
||||
void idPhysics_DynamicBase::DrawVelocity(const int id,
|
||||
const float linearScale, const float angularScale) const {
|
||||
idVec3 linear;
|
||||
idVec3 angular;
|
||||
const_cast<idPhysics_DynamicBase*>(this)->GetLinearVelocity(&linear, id);
|
||||
const_cast<idPhysics_DynamicBase*>(this)->GetAngularVelocity(&angular, id);
|
||||
linear = linear * linearScale;
|
||||
const idVec3* const origin =
|
||||
const_cast<idPhysics_DynamicBase*>(this)->GetOrigin(id);
|
||||
if (origin != nullptr) {
|
||||
GameLib_DrawPhysicsVelocity(*origin, linear, angular, angularScale);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_dynamicbase.h
|
||||
// Recovered logical types: 1
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/physics/physics.h"
|
||||
#include "idlib/bv/bounds.h"
|
||||
#include "idlib/containers/list.h"
|
||||
|
||||
|
||||
// IDA Local Type ordinal 14609; PDB kind: class.
|
||||
class __declspec(align(8)) idPhysics_DynamicBase : public idPhysics
|
||||
{
|
||||
class alignas(8) idPhysics_DynamicBase : public idPhysics {
|
||||
public:
|
||||
// Recovered virtual interface; IDA vtable ordinal 14612.
|
||||
virtual ~idPhysics_DynamicBase();
|
||||
virtual void SetClipModel(idClipModel *, float, int, bool);
|
||||
virtual idClipModel *GetClipModel(int);
|
||||
virtual int GetNumClipModels();
|
||||
virtual void SetMass(float, int);
|
||||
virtual float GetMass(int);
|
||||
virtual void SetContents(int, int);
|
||||
virtual int GetContents(int);
|
||||
virtual void SetClipMask(int, int);
|
||||
virtual int GetClipMask(int);
|
||||
virtual const idBounds *GetBounds(int);
|
||||
virtual const idBounds *GetAbsBounds(int);
|
||||
virtual void SetOrigin(const idVec3 *, int);
|
||||
virtual void SetAxis(const idMat3 *, int);
|
||||
virtual void Translate(const idVec3 *, int);
|
||||
virtual void Rotate(const idRotation *, int);
|
||||
virtual const idVec3 *GetOrigin(int);
|
||||
virtual const idMat3 *GetAxis(int);
|
||||
virtual const idVec3 *GetLocalOrigin(int);
|
||||
virtual const idMat3 *GetLocalAxis(int);
|
||||
virtual void SetLinearVelocity(const idVec3 *, int);
|
||||
virtual void SetAngularVelocity(const idVec3 *, int);
|
||||
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
|
||||
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
|
||||
virtual void SetGravity(const idVec3 *);
|
||||
virtual const idVec3 *GetGravity();
|
||||
virtual const idVec3 *GetGravityNormal();
|
||||
virtual void SetWaterLevel(float, int);
|
||||
virtual float GetWaterLevel(int);
|
||||
virtual void SetWaterViscosity(float, int);
|
||||
virtual float GetWaterViscosity(int);
|
||||
virtual void SetWaterEntNum(int);
|
||||
virtual int GetWaterEntNum();
|
||||
virtual void SetWaterSurfaceWrldHeight(float);
|
||||
virtual float GetWaterSurfaceWrldHeight();
|
||||
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
|
||||
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
|
||||
virtual void Activate();
|
||||
virtual void PutToRest();
|
||||
virtual bool IsAtRest();
|
||||
virtual bool IsPushable(int);
|
||||
virtual void SaveState();
|
||||
virtual void RestoreState();
|
||||
virtual bool Evaluate(int, int);
|
||||
virtual void UpdateTime(int);
|
||||
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
|
||||
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
|
||||
virtual int ClipContents(const idClipModel *, int);
|
||||
virtual void DisableClip();
|
||||
virtual void EnableClip();
|
||||
virtual void UnlinkClip();
|
||||
virtual void LinkClip();
|
||||
virtual bool EvaluateContacts();
|
||||
virtual int GetNumContacts();
|
||||
virtual const contactInfo_t *GetContact(int);
|
||||
virtual void ClearContacts();
|
||||
virtual void AddContactPhysics(idPhysics *);
|
||||
virtual void RemoveContactPhysics(idPhysics *);
|
||||
virtual int GetNumContactPhysics();
|
||||
virtual idPhysics *GetContactPhysics(int);
|
||||
virtual void ActivateContactPhysics();
|
||||
virtual bool HasGroundContacts();
|
||||
virtual bool IsGroundEntity(int);
|
||||
virtual bool IsGroundClipModel(int, int);
|
||||
virtual void SetPushed(int);
|
||||
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
|
||||
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
|
||||
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
|
||||
virtual void SetLocalOrigin(const idVec3 *, int);
|
||||
virtual void SetLocalAxis(const idMat3 *, int);
|
||||
virtual int GetBlockingEntityNum();
|
||||
virtual int GetLinearEndTime();
|
||||
virtual int GetAngularEndTime();
|
||||
virtual bool IsInNonResidentCollisionArea(bool);
|
||||
virtual bool IsOutsideWorld();
|
||||
idPhysics_DynamicBase();
|
||||
~idPhysics_DynamicBase() override;
|
||||
|
||||
int clipMask;
|
||||
idVec3 gravityVector;
|
||||
idVec3 gravityNormal;
|
||||
idList<contactInfo_t,77> contacts;
|
||||
idList<int,77> contactPhysicsIds;
|
||||
float waterLevel;
|
||||
float waterViscosity;
|
||||
void SetClipMask(int mask, int id) override;
|
||||
int GetClipMask(int id) override { (void)id; return clipMask; }
|
||||
const idBounds* GetAbsBounds(int id) override;
|
||||
void ClipTranslation(trace_t* results, const idVec3* translation,
|
||||
const idClipModel* model) override;
|
||||
void SetGravity(const idVec3* gravity) override;
|
||||
const idVec3* GetGravity() override { return &gravityVector; }
|
||||
const idVec3* GetGravityNormal() override { return &gravityNormal; }
|
||||
void SetWaterLevel(float level, int id) override;
|
||||
float GetWaterLevel(int id) override;
|
||||
void SetWaterViscosity(float viscosity, int id) override;
|
||||
float GetWaterViscosity(int id) override;
|
||||
int GetNumContacts() override { return contacts.Num(); }
|
||||
const contactInfo_t* GetContact(int index) override;
|
||||
void ClearContacts() override;
|
||||
void AddContactPhysics(idPhysics* physics) override;
|
||||
void RemoveContactPhysics(idPhysics* physics) override;
|
||||
int GetNumContactPhysics() override { return contactPhysicsIds.Num(); }
|
||||
idPhysics* GetContactPhysics(int index) override;
|
||||
void ActivateContactPhysics() override;
|
||||
bool HasGroundContacts() override;
|
||||
bool IsGroundEntity(int entityNumber) override;
|
||||
bool IsGroundClipModel(int entityNumber, int bodyId) override;
|
||||
bool IsOutsideWorld();
|
||||
|
||||
protected:
|
||||
void AddContactPhysicsForContacts();
|
||||
void AddGroundContacts(const idClipModel* model, int maxContacts);
|
||||
void DrawVelocity(int id, float linearScale, float angularScale) const;
|
||||
|
||||
int clipMask;
|
||||
idVec3 gravityVector;
|
||||
idVec3 gravityNormal;
|
||||
idList<contactInfo_t, 77> contacts;
|
||||
idList<int, 77> contactPhysicsIds;
|
||||
float waterLevel;
|
||||
float waterViscosity;
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idPhysics_DynamicBase) == 120,
|
||||
"Recovered idPhysics_DynamicBase ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
#include "gamelib/physics/physics_static.h"
|
||||
|
||||
#include "gamelib/physics/clip.h"
|
||||
#include "gamelib/physics/clipmodel.h"
|
||||
#include "idlib/math/rotation.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
|
||||
idVec3& origin, idMat3& axis);
|
||||
void GameLib_ActivateContactPhysics(idPhysics* physics);
|
||||
|
||||
namespace {
|
||||
|
||||
const idVec3 kZeroVector(0.0f, 0.0f, 0.0f);
|
||||
const idVec3 kDownVector(0.0f, 0.0f, -1.0f);
|
||||
const idMat3 kIdentityAxis(1.0f);
|
||||
const idBounds kZeroBounds{{idVec3(0.0f, 0.0f, 0.0f),
|
||||
idVec3(0.0f, 0.0f, 0.0f)}};
|
||||
|
||||
} // namespace
|
||||
|
||||
idPhysics_Static::idPhysics_Static()
|
||||
: idPhysics()
|
||||
, clipModel(nullptr)
|
||||
, contactPhysicsIds(4)
|
||||
, isOrientated(0)
|
||||
, hasMaster(0)
|
||||
, reservedFlags(0)
|
||||
, current{} {
|
||||
type = PHYSICS_STATIC;
|
||||
current.worldOrigin.Zero();
|
||||
current.worldAxis = idMat3(1.0f);
|
||||
current.localOrigin.Zero();
|
||||
current.localAxis = idMat3(1.0f);
|
||||
}
|
||||
|
||||
idPhysics_Static::~idPhysics_Static() {
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Unlink();
|
||||
}
|
||||
clipModel = nullptr;
|
||||
}
|
||||
|
||||
void idPhysics_Static::SetClipModel(idClipModel* const model,
|
||||
const float density, const int id, const bool freeOld) {
|
||||
(void)density;
|
||||
if (clipModel != nullptr && clipModel != model && freeOld) {
|
||||
clipModel->Delete();
|
||||
}
|
||||
clipModel = model;
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Link(GetEntityNumber(), GetEntityNumber(), id,
|
||||
current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
}
|
||||
|
||||
idClipModel* idPhysics_Static::GetClipModel(const int id) {
|
||||
(void)id;
|
||||
return clipModel;
|
||||
}
|
||||
|
||||
int idPhysics_Static::GetNumClipModels() { return clipModel != nullptr; }
|
||||
void idPhysics_Static::SetMass(float, int) {}
|
||||
float idPhysics_Static::GetMass(int) { return 0.0f; }
|
||||
|
||||
void idPhysics_Static::SetContents(const int contents, const int id) {
|
||||
(void)id;
|
||||
if (clipModel != nullptr) clipModel->SetContents(contents);
|
||||
}
|
||||
int idPhysics_Static::GetContents(const int id) {
|
||||
(void)id;
|
||||
return clipModel != nullptr ? clipModel->GetContents() : 0;
|
||||
}
|
||||
void idPhysics_Static::SetClipMask(int, int) {}
|
||||
int idPhysics_Static::GetClipMask(int) { return 0; }
|
||||
|
||||
const idBounds* idPhysics_Static::GetBounds(const int id) {
|
||||
(void)id;
|
||||
return clipModel != nullptr ? &clipModel->GetBounds() : &kZeroBounds;
|
||||
}
|
||||
|
||||
const idBounds* idPhysics_Static::GetAbsBounds(const int id) {
|
||||
(void)id;
|
||||
if (clipModel != nullptr) return &clipModel->GetAbsBounds();
|
||||
static idBounds pointBounds;
|
||||
pointBounds[0] = current.worldOrigin;
|
||||
pointBounds[1] = current.worldOrigin;
|
||||
return &pointBounds;
|
||||
}
|
||||
|
||||
void idPhysics_Static::SetOrigin(const idVec3* const origin, const int id) {
|
||||
(void)id;
|
||||
if (origin == nullptr) return;
|
||||
current.worldOrigin = *origin;
|
||||
if (!hasMaster) current.localOrigin = *origin;
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
}
|
||||
|
||||
void idPhysics_Static::SetAxis(const idMat3* const axis, const int id) {
|
||||
(void)id;
|
||||
if (axis == nullptr) return;
|
||||
current.worldAxis = *axis;
|
||||
if (!hasMaster || !isOrientated) current.localAxis = *axis;
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
}
|
||||
|
||||
void idPhysics_Static::Translate(const idVec3* const translation,
|
||||
const int id) {
|
||||
(void)id;
|
||||
if (translation == nullptr) return;
|
||||
current.worldOrigin = current.worldOrigin + *translation;
|
||||
current.localOrigin = current.localOrigin + *translation;
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
}
|
||||
|
||||
void idPhysics_Static::Rotate(const idRotation* const rotation,
|
||||
const int id) {
|
||||
(void)id;
|
||||
if (rotation == nullptr) return;
|
||||
current.worldOrigin = *rotation * current.worldOrigin;
|
||||
current.worldAxis *= rotation->ToMat3();
|
||||
current.localAxis *= rotation->ToMat3();
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
}
|
||||
|
||||
const idVec3* idPhysics_Static::GetOrigin(int) { return ¤t.worldOrigin; }
|
||||
const idMat3* idPhysics_Static::GetAxis(int) { return ¤t.worldAxis; }
|
||||
const idVec3* idPhysics_Static::GetLocalOrigin(int) { return ¤t.localOrigin; }
|
||||
const idMat3* idPhysics_Static::GetLocalAxis(int) { return ¤t.localAxis; }
|
||||
void idPhysics_Static::SetLinearVelocity(const idVec3*, int) {}
|
||||
void idPhysics_Static::SetAngularVelocity(const idVec3*, int) {}
|
||||
idVec3* idPhysics_Static::GetLinearVelocity(idVec3* result, int) {
|
||||
if (result != nullptr) result->Zero();
|
||||
return result;
|
||||
}
|
||||
idVec3* idPhysics_Static::GetAngularVelocity(idVec3* result, int) {
|
||||
if (result != nullptr) result->Zero();
|
||||
return result;
|
||||
}
|
||||
void idPhysics_Static::SetGravity(const idVec3*) {}
|
||||
const idVec3* idPhysics_Static::GetGravity() { return &kZeroVector; }
|
||||
const idVec3* idPhysics_Static::GetGravityNormal() { return &kDownVector; }
|
||||
void idPhysics_Static::SetWaterLevel(float, int) {}
|
||||
float idPhysics_Static::GetWaterLevel(int) { return 0.0f; }
|
||||
void idPhysics_Static::SetWaterViscosity(float, int) {}
|
||||
float idPhysics_Static::GetWaterViscosity(int) { return 0.0f; }
|
||||
void idPhysics_Static::SetWaterEntNum(int) {}
|
||||
int idPhysics_Static::GetWaterEntNum() { return -1; }
|
||||
void idPhysics_Static::SetWaterSurfaceWrldHeight(float) {}
|
||||
float idPhysics_Static::GetWaterSurfaceWrldHeight() { return 0.0f; }
|
||||
|
||||
void idPhysics_Static::GetImpactInfo(int, const idVec3*,
|
||||
impactInfo_t* const info) {
|
||||
if (info != nullptr) info->Zero();
|
||||
}
|
||||
void idPhysics_Static::ApplyImpulse(int, const idVec3*, const idVec3*) {}
|
||||
void idPhysics_Static::ApplyForce(int, const idVec3*, const idVec3*) {}
|
||||
void idPhysics_Static::Activate() {}
|
||||
void idPhysics_Static::PutToRest() {}
|
||||
bool idPhysics_Static::IsAtRest() { return true; }
|
||||
bool idPhysics_Static::IsPushable(int) { return false; }
|
||||
void idPhysics_Static::SaveState() {}
|
||||
void idPhysics_Static::RestoreState() {}
|
||||
|
||||
bool idPhysics_Static::Evaluate(int, int) {
|
||||
if (!hasMaster || callbacks == nullptr) return false;
|
||||
idVec3 masterOrigin;
|
||||
idMat3 masterAxis;
|
||||
if (!GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
|
||||
masterAxis)) return false;
|
||||
const idVec3 oldOrigin = current.worldOrigin;
|
||||
const idMat3 oldAxis = current.worldAxis;
|
||||
current.worldOrigin = masterOrigin + masterAxis * current.localOrigin;
|
||||
current.worldAxis = isOrientated
|
||||
? current.localAxis * masterAxis : current.localAxis;
|
||||
if (clipModel != nullptr) {
|
||||
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
return (current.worldOrigin - oldOrigin).LengthSqr() > 0.0f ||
|
||||
(current.worldAxis[0] - oldAxis[0]).LengthSqr() > 0.0f ||
|
||||
(current.worldAxis[1] - oldAxis[1]).LengthSqr() > 0.0f ||
|
||||
(current.worldAxis[2] - oldAxis[2]).LengthSqr() > 0.0f;
|
||||
}
|
||||
|
||||
void idPhysics_Static::UpdateTime(int) {}
|
||||
|
||||
void idPhysics_Static::ClipTranslation(trace_t* const results,
|
||||
const idVec3* const translation, const idClipModel* const model) {
|
||||
if (results == nullptr) return;
|
||||
const idClipModel* moving = model != nullptr ? model : clipModel;
|
||||
if (clip == nullptr || moving == nullptr || translation == nullptr) {
|
||||
std::memset(results, 0, sizeof(*results));
|
||||
results->fraction = 1.0f;
|
||||
return;
|
||||
}
|
||||
clip->Translation(results, current.worldOrigin,
|
||||
current.worldOrigin + *translation, moving, current.worldAxis, 0,
|
||||
GetEntityNumber(), false, "idPhysics_Static::ClipTranslation");
|
||||
}
|
||||
|
||||
void idPhysics_Static::ClipRotation(trace_t* const results,
|
||||
const idRotation* const rotation, const idClipModel* const model) {
|
||||
if (results == nullptr) return;
|
||||
const idClipModel* moving = model != nullptr ? model : clipModel;
|
||||
if (clip == nullptr || moving == nullptr || rotation == nullptr) {
|
||||
std::memset(results, 0, sizeof(*results));
|
||||
results->fraction = 1.0f;
|
||||
return;
|
||||
}
|
||||
clip->Rotation(results, current.worldOrigin, *rotation, moving,
|
||||
current.worldAxis, 0, GetEntityNumber(), false,
|
||||
"idPhysics_Static::ClipRotation");
|
||||
}
|
||||
|
||||
int idPhysics_Static::ClipContents(const idClipModel* const model, int) {
|
||||
if (clip == nullptr || model == nullptr) return 0;
|
||||
trace_t result{};
|
||||
clip->Contents(&result, current.worldOrigin, model, current.worldAxis,
|
||||
0, GetEntityNumber(), "idPhysics_Static::ClipContents");
|
||||
return result.c.contentFlags;
|
||||
}
|
||||
|
||||
void idPhysics_Static::DisableClip() { if (clipModel) clipModel->Disable(); }
|
||||
void idPhysics_Static::EnableClip() { if (clipModel) clipModel->Enable(); }
|
||||
void idPhysics_Static::UnlinkClip() { if (clipModel) clipModel->Unlink(); }
|
||||
void idPhysics_Static::LinkClip() {
|
||||
if (clipModel) clipModel->Link(GetEntityNumber(), GetEntityNumber(),
|
||||
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
|
||||
}
|
||||
bool idPhysics_Static::EvaluateContacts() { return false; }
|
||||
int idPhysics_Static::GetNumContacts() { return 0; }
|
||||
const contactInfo_t* idPhysics_Static::GetContact(int) { return nullptr; }
|
||||
void idPhysics_Static::ClearContacts() {}
|
||||
|
||||
void idPhysics_Static::AddContactPhysics(idPhysics* const physics) {
|
||||
if (physics == nullptr || physics == this) return;
|
||||
const int physicsId = physics->GetPhysicsId();
|
||||
for (int i = 0; i < contactPhysicsIds.Num(); ++i)
|
||||
if (contactPhysicsIds[i] == physicsId) return;
|
||||
contactPhysicsIds.Append(physicsId);
|
||||
}
|
||||
void idPhysics_Static::RemoveContactPhysics(idPhysics* const physics) {
|
||||
if (physics == nullptr) return;
|
||||
for (int i = contactPhysicsIds.Num() - 1; i >= 0; --i)
|
||||
if (contactPhysicsIds[i] == physics->GetPhysicsId())
|
||||
contactPhysicsIds.RemoveIndexFast(i);
|
||||
}
|
||||
int idPhysics_Static::GetNumContactPhysics() { return contactPhysicsIds.Num(); }
|
||||
idPhysics* idPhysics_Static::GetContactPhysics(const int index) {
|
||||
return index >= 0 && index < contactPhysicsIds.Num()
|
||||
? idPhysics::GetPhysicsForId(contactPhysicsIds[index]) : nullptr;
|
||||
}
|
||||
void idPhysics_Static::ActivateContactPhysics() {
|
||||
for (int i = contactPhysicsIds.Num() - 1; i >= 0; --i) {
|
||||
idPhysics* physics = idPhysics::GetPhysicsForId(contactPhysicsIds[i]);
|
||||
if (physics) GameLib_ActivateContactPhysics(physics);
|
||||
else contactPhysicsIds.RemoveIndexFast(i);
|
||||
}
|
||||
}
|
||||
bool idPhysics_Static::HasGroundContacts() { return false; }
|
||||
bool idPhysics_Static::IsGroundEntity(int) { return false; }
|
||||
bool idPhysics_Static::IsGroundClipModel(int, int) { return false; }
|
||||
void idPhysics_Static::SetPushed(int) {}
|
||||
idVec3* idPhysics_Static::GetPushedLinearVelocity(idVec3* result, int) {
|
||||
if (result) result->Zero(); return result;
|
||||
}
|
||||
idVec3* idPhysics_Static::GetPushedAngularVelocity(idVec3* result, int) {
|
||||
if (result) result->Zero(); return result;
|
||||
}
|
||||
|
||||
void idPhysics_Static::SetMaster(const bool orientated,
|
||||
const idVec3* const masterOrigin, const idMat3* const masterAxis,
|
||||
const bindFlags_t flags) {
|
||||
(void)flags;
|
||||
if (masterOrigin != nullptr && masterAxis != nullptr) {
|
||||
const idMat3 inverse = masterAxis->Transpose();
|
||||
current.localOrigin = inverse *
|
||||
(current.worldOrigin - *masterOrigin);
|
||||
current.localAxis = orientated
|
||||
? current.worldAxis * inverse : current.worldAxis;
|
||||
hasMaster = 1;
|
||||
isOrientated = orientated ? 1 : 0;
|
||||
} else {
|
||||
current.localOrigin = current.worldOrigin;
|
||||
current.localAxis = current.worldAxis;
|
||||
hasMaster = 0;
|
||||
isOrientated = 0;
|
||||
}
|
||||
}
|
||||
void idPhysics_Static::SetLocalOrigin(const idVec3* origin, int id) {
|
||||
if (origin) { current.localOrigin = *origin; Evaluate(0, 0); }
|
||||
(void)id;
|
||||
}
|
||||
void idPhysics_Static::SetLocalAxis(const idMat3* axis, int id) {
|
||||
if (axis) { current.localAxis = *axis; Evaluate(0, 0); }
|
||||
(void)id;
|
||||
}
|
||||
int idPhysics_Static::GetBlockingEntityNum() { return 0x1FFF; }
|
||||
int idPhysics_Static::GetLinearEndTime() { return 0; }
|
||||
int idPhysics_Static::GetAngularEndTime() { return 0; }
|
||||
@@ -1,96 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_static.h
|
||||
// Recovered logical types: 1
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/physics/physics.h"
|
||||
#include "idlib/bv/bounds.h"
|
||||
#include "idlib/containers/list.h"
|
||||
|
||||
|
||||
// IDA Local Type ordinal 15178; PDB kind: class.
|
||||
class idPhysics_Static : public idPhysics
|
||||
{
|
||||
public:
|
||||
// Recovered virtual interface; IDA vtable ordinal 15179.
|
||||
virtual ~idPhysics_Static();
|
||||
virtual void SetClipModel(idClipModel *, float, int, bool);
|
||||
virtual idClipModel *GetClipModel(int);
|
||||
virtual int GetNumClipModels();
|
||||
virtual void SetMass(float, int);
|
||||
virtual float GetMass(int);
|
||||
virtual void SetContents(int, int);
|
||||
virtual int GetContents(int);
|
||||
virtual void SetClipMask(int, int);
|
||||
virtual int GetClipMask(int);
|
||||
virtual const idBounds *GetBounds(int);
|
||||
virtual const idBounds *GetAbsBounds(int);
|
||||
virtual void SetOrigin(const idVec3 *, int);
|
||||
virtual void SetAxis(const idMat3 *, int);
|
||||
virtual void Translate(const idVec3 *, int);
|
||||
virtual void Rotate(const idRotation *, int);
|
||||
virtual const idVec3 *GetOrigin(int);
|
||||
virtual const idMat3 *GetAxis(int);
|
||||
virtual const idVec3 *GetLocalOrigin(int);
|
||||
virtual const idMat3 *GetLocalAxis(int);
|
||||
virtual void SetLinearVelocity(const idVec3 *, int);
|
||||
virtual void SetAngularVelocity(const idVec3 *, int);
|
||||
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
|
||||
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
|
||||
virtual void SetGravity(const idVec3 *);
|
||||
virtual const idVec3 *GetGravity();
|
||||
virtual const idVec3 *GetGravityNormal();
|
||||
virtual void SetWaterLevel(float, int);
|
||||
virtual float GetWaterLevel(int);
|
||||
virtual void SetWaterViscosity(float, int);
|
||||
virtual float GetWaterViscosity(int);
|
||||
virtual void SetWaterEntNum(int);
|
||||
virtual int GetWaterEntNum();
|
||||
virtual void SetWaterSurfaceWrldHeight(float);
|
||||
virtual float GetWaterSurfaceWrldHeight();
|
||||
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
|
||||
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
|
||||
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
|
||||
virtual void Activate();
|
||||
virtual void PutToRest();
|
||||
virtual bool IsAtRest();
|
||||
virtual bool IsPushable(int);
|
||||
virtual void SaveState();
|
||||
virtual void RestoreState();
|
||||
virtual bool Evaluate(int, int);
|
||||
virtual void UpdateTime(int);
|
||||
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
|
||||
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
|
||||
virtual int ClipContents(const idClipModel *, int);
|
||||
virtual void DisableClip();
|
||||
virtual void EnableClip();
|
||||
virtual void UnlinkClip();
|
||||
virtual void LinkClip();
|
||||
virtual bool EvaluateContacts();
|
||||
virtual int GetNumContacts();
|
||||
virtual const contactInfo_t *GetContact(int);
|
||||
virtual void ClearContacts();
|
||||
virtual void AddContactPhysics(idPhysics *);
|
||||
virtual void RemoveContactPhysics(idPhysics *);
|
||||
virtual int GetNumContactPhysics();
|
||||
virtual idPhysics *GetContactPhysics(int);
|
||||
virtual void ActivateContactPhysics();
|
||||
virtual bool HasGroundContacts();
|
||||
virtual bool IsGroundEntity(int);
|
||||
virtual bool IsGroundClipModel(int, int);
|
||||
virtual void SetPushed(int);
|
||||
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
|
||||
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
|
||||
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
|
||||
virtual void SetLocalOrigin(const idVec3 *, int);
|
||||
virtual void SetLocalAxis(const idMat3 *, int);
|
||||
virtual int GetBlockingEntityNum();
|
||||
virtual int GetLinearEndTime();
|
||||
virtual int GetAngularEndTime();
|
||||
virtual bool IsInNonResidentCollisionArea(bool);
|
||||
|
||||
idClipModel *clipModel;
|
||||
idList<int,77> contactPhysicsIds;
|
||||
unsigned __int8 : 6;
|
||||
__int8 isOrientated : 1;
|
||||
__int8 hasMaster : 1;
|
||||
staticPState_t current;
|
||||
struct staticPState_t {
|
||||
idVec3 worldOrigin;
|
||||
idMat3 worldAxis;
|
||||
idVec3 localOrigin;
|
||||
idMat3 localAxis;
|
||||
};
|
||||
|
||||
class idPhysics_Static : public idPhysics {
|
||||
public:
|
||||
idPhysics_Static();
|
||||
~idPhysics_Static() override;
|
||||
|
||||
void SetClipModel(idClipModel*, float, int, bool) override;
|
||||
idClipModel* GetClipModel(int) override;
|
||||
int GetNumClipModels() override;
|
||||
void SetMass(float, int) override;
|
||||
float GetMass(int) override;
|
||||
void SetContents(int, int) override;
|
||||
int GetContents(int) override;
|
||||
void SetClipMask(int, int) override;
|
||||
int GetClipMask(int) override;
|
||||
const idBounds* GetBounds(int) override;
|
||||
const idBounds* GetAbsBounds(int) override;
|
||||
void SetOrigin(const idVec3*, int) override;
|
||||
void SetAxis(const idMat3*, int) override;
|
||||
void Translate(const idVec3*, int) override;
|
||||
void Rotate(const idRotation*, int) override;
|
||||
const idVec3* GetOrigin(int) override;
|
||||
const idMat3* GetAxis(int) override;
|
||||
const idVec3* GetLocalOrigin(int) override;
|
||||
const idMat3* GetLocalAxis(int) override;
|
||||
void SetLinearVelocity(const idVec3*, int) override;
|
||||
void SetAngularVelocity(const idVec3*, int) override;
|
||||
idVec3* GetLinearVelocity(idVec3*, int) override;
|
||||
idVec3* GetAngularVelocity(idVec3*, int) override;
|
||||
void SetGravity(const idVec3*) override;
|
||||
const idVec3* GetGravity() override;
|
||||
const idVec3* GetGravityNormal() override;
|
||||
void SetWaterLevel(float, int) override;
|
||||
float GetWaterLevel(int) override;
|
||||
void SetWaterViscosity(float, int) override;
|
||||
float GetWaterViscosity(int) override;
|
||||
void SetWaterEntNum(int) override;
|
||||
int GetWaterEntNum() override;
|
||||
void SetWaterSurfaceWrldHeight(float) override;
|
||||
float GetWaterSurfaceWrldHeight() override;
|
||||
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
|
||||
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
|
||||
void ApplyForce(int, const idVec3*, const idVec3*) override;
|
||||
void Activate() override;
|
||||
void PutToRest() override;
|
||||
bool IsAtRest() override;
|
||||
bool IsPushable(int) override;
|
||||
void SaveState() override;
|
||||
void RestoreState() override;
|
||||
bool Evaluate(int, int) override;
|
||||
void UpdateTime(int) override;
|
||||
void ClipTranslation(trace_t*, const idVec3*,
|
||||
const idClipModel*) override;
|
||||
void ClipRotation(trace_t*, const idRotation*,
|
||||
const idClipModel*) override;
|
||||
int ClipContents(const idClipModel*, int) override;
|
||||
void DisableClip() override;
|
||||
void EnableClip() override;
|
||||
void UnlinkClip() override;
|
||||
void LinkClip() override;
|
||||
bool EvaluateContacts() override;
|
||||
int GetNumContacts() override;
|
||||
const contactInfo_t* GetContact(int) override;
|
||||
void ClearContacts() override;
|
||||
void AddContactPhysics(idPhysics*) override;
|
||||
void RemoveContactPhysics(idPhysics*) override;
|
||||
int GetNumContactPhysics() override;
|
||||
idPhysics* GetContactPhysics(int) override;
|
||||
void ActivateContactPhysics() override;
|
||||
bool HasGroundContacts() override;
|
||||
bool IsGroundEntity(int) override;
|
||||
bool IsGroundClipModel(int, int) override;
|
||||
void SetPushed(int) override;
|
||||
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
|
||||
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
|
||||
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
|
||||
void SetLocalOrigin(const idVec3*, int) override;
|
||||
void SetLocalAxis(const idMat3*, int) override;
|
||||
int GetBlockingEntityNum() override;
|
||||
int GetLinearEndTime() override;
|
||||
int GetAngularEndTime() override;
|
||||
|
||||
idClipModel* clipModel;
|
||||
idList<int, 77> contactPhysicsIds;
|
||||
std::uint8_t isOrientated : 1;
|
||||
std::uint8_t hasMaster : 1;
|
||||
std::uint8_t reservedFlags : 6;
|
||||
staticPState_t current;
|
||||
};
|
||||
|
||||
static_assert(sizeof(staticPState_t) == 96,
|
||||
"Recovered static physics-state ABI changed");
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idPhysics_Static) == 168,
|
||||
"Recovered idPhysics_Static ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
#include "gamelib/physics/push.h"
|
||||
|
||||
#include "gamelib/physics/clipmodel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
int GameLib_GetPushPhysicsObjects(idClip* clip, const idBounds& bounds,
|
||||
idPhysics** objects, int maxObjects);
|
||||
bool GameLib_GetPushSweepBounds(idPhysics* pusher,
|
||||
const idVec3& oldOrigin, const idVec3& newOrigin,
|
||||
const idMat3& oldAxis, const idMat3& newAxis, idBounds& bounds);
|
||||
idRotation GameLib_GetPushRotation(const idVec3& origin,
|
||||
const idMat3& oldAxis, const idMat3& newAxis);
|
||||
bool GameLib_RotatePushObjectToAxial(idPhysics* physics,
|
||||
const idVec3& rotationPoint, const idClipModel* clipModel);
|
||||
|
||||
namespace {
|
||||
|
||||
void ClearTrace(trace_t& trace, const idVec3& end,
|
||||
const idMat3& endAxis) {
|
||||
std::memset(&trace, 0, sizeof(trace));
|
||||
trace.fraction = 1.0f;
|
||||
trace.endpos = end;
|
||||
trace.endAxis = endAxis;
|
||||
trace.c.entityNum = 0x1FFF;
|
||||
trace.c.physicsId = -1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
idPush::idPush(idClip* const clip_)
|
||||
: clip(clip_)
|
||||
, pushed(4) {
|
||||
}
|
||||
|
||||
void idPush::Init(idClip* const clip_) { clip = clip_; }
|
||||
|
||||
void idPush::InitSavingPushedPhysicsObjectState() { pushed.Clear(); }
|
||||
|
||||
void idPush::SavePhysicsObjectState(idPhysics* const physics) {
|
||||
if (physics == nullptr) return;
|
||||
for (int index = 0; index < pushed.Num(); ++index)
|
||||
if (pushed[index] == physics) return;
|
||||
physics->SaveState();
|
||||
pushed.Append(physics);
|
||||
}
|
||||
|
||||
void idPush::RestorePushedPhysicsObjectState() {
|
||||
for (int index = 0; index < pushed.Num(); ++index)
|
||||
if (pushed[index] != nullptr) pushed[index]->RestoreState();
|
||||
}
|
||||
|
||||
void idPush::SetPushedOnPushedPhysicsObjects(const int deltaTime) {
|
||||
for (int index = 0; index < pushed.Num(); ++index)
|
||||
if (pushed[index] != nullptr) pushed[index]->SetPushed(deltaTime);
|
||||
}
|
||||
|
||||
void idPush::ClipPhysicsObjectRotation(trace_t& trace,
|
||||
idPhysics* const physics, const idClipModel* const clipModel,
|
||||
idClipModel* const skip, const idRotation& rotation) {
|
||||
if (skip != nullptr) skip->Disable();
|
||||
physics->ClipRotation(&trace, &rotation, clipModel);
|
||||
if (skip != nullptr) skip->Enable();
|
||||
}
|
||||
|
||||
void idPush::ClipPhysicsObjectTranslation(trace_t& trace,
|
||||
idPhysics* const physics, const idClipModel* const clipModel,
|
||||
idClipModel* const skip, const idVec3& translation) {
|
||||
if (skip != nullptr) skip->Disable();
|
||||
physics->ClipTranslation(&trace, &translation, clipModel);
|
||||
if (skip != nullptr) skip->Enable();
|
||||
}
|
||||
|
||||
bool idPush::CanPushPhysicsObject(idPhysics* const physics,
|
||||
const int flags, idPhysics* const pusher) {
|
||||
if (physics == nullptr || pusher == nullptr || physics == pusher) {
|
||||
return false;
|
||||
}
|
||||
const int pusherContents = pusher->GetContents(-1);
|
||||
if (!physics->IsPushable(pusherContents) ||
|
||||
(physics->GetClipMask(-1) & pusherContents) == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((flags & 4) != 0 && physics->GetType() != PHYSICS_RIGIDBODY) {
|
||||
return false;
|
||||
}
|
||||
if ((flags & 8) != 0 &&
|
||||
pusher->IsGroundEntity(physics->GetEntityNumber())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int idPush::GetPhysicsObjectsTouchingBounds(idPhysics** const objects,
|
||||
const idBounds& bounds, const int flags, idPhysics* const pusher) {
|
||||
if (clip == nullptr || objects == nullptr) return 0;
|
||||
idPhysics* candidates[256]{};
|
||||
const int count = (std::max)(0, (std::min)(256,
|
||||
GameLib_GetPushPhysicsObjects(clip, bounds, candidates, 256)));
|
||||
int accepted = 0;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
if (!CanPushPhysicsObject(candidates[index], flags, pusher)) continue;
|
||||
bool duplicate = false;
|
||||
for (int check = 0; check < accepted; ++check)
|
||||
if (objects[check] == candidates[index]) duplicate = true;
|
||||
if (!duplicate) objects[accepted++] = candidates[index];
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
bool idPush::RotatePhysicsObjectToAxial(idPhysics* const physics,
|
||||
const idVec3& rotationPoint, const idClipModel* const clipModel) {
|
||||
return physics != nullptr && GameLib_RotatePushObjectToAxial(
|
||||
physics, rotationPoint, clipModel);
|
||||
}
|
||||
|
||||
idPush::pushResult_t idPush::RecursiveTryTranslatePushPhysicsObject(
|
||||
trace_t& results, trace_t& trace, idPhysics* const pusher,
|
||||
const int flags, const idVec3& translation, float& mass) {
|
||||
idPhysics* const blocking = idPhysics::GetPhysicsForId(trace.c.physicsId);
|
||||
if (!CanPushPhysicsObject(blocking, flags & ~8, pusher)) {
|
||||
results = trace;
|
||||
return PUSH_BLOCKED;
|
||||
}
|
||||
const pushResult_t result = TryTranslatePushPhysicsObject(results,
|
||||
blocking, pusher->GetClipModel(0), flags, *blocking->GetOrigin(0),
|
||||
translation, mass);
|
||||
if (result == PUSH_OK) {
|
||||
pusher->ClipTranslation(&trace, &translation,
|
||||
pusher->GetClipModel(0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
idPush::pushResult_t idPush::TryTranslatePushPhysicsObject(
|
||||
trace_t& results, idPhysics* const check,
|
||||
idClipModel* const pusherModel, const int flags,
|
||||
const idVec3& oldOrigin, const idVec3& translation, float& mass) {
|
||||
if (check == nullptr) return PUSH_BLOCKED;
|
||||
trace_t trace{};
|
||||
ClipPhysicsObjectTranslation(trace, check, pusherModel,
|
||||
pusherModel, translation);
|
||||
if (trace.fraction < 1.0f) {
|
||||
const pushResult_t recursive = RecursiveTryTranslatePushPhysicsObject(
|
||||
results, trace, check, flags, translation, mass);
|
||||
if (recursive != PUSH_OK) return recursive;
|
||||
}
|
||||
SavePhysicsObjectState(check);
|
||||
check->Translate(&translation, -1);
|
||||
mass += check->GetMass(-1);
|
||||
ClearTrace(results, oldOrigin + translation, *check->GetAxis(0));
|
||||
return PUSH_OK;
|
||||
}
|
||||
|
||||
idPush::pushResult_t idPush::RecursiveTryRotatePushPhysicsObject(
|
||||
trace_t& results, trace_t& trace, idPhysics* const pusher,
|
||||
const int flags, const idRotation& rotation, float& mass) {
|
||||
idPhysics* const blocking = idPhysics::GetPhysicsForId(trace.c.physicsId);
|
||||
if (!CanPushPhysicsObject(blocking, flags & ~8, pusher)) {
|
||||
results = trace;
|
||||
return PUSH_BLOCKED;
|
||||
}
|
||||
return TryRotatePushPhysicsObject(results, blocking,
|
||||
pusher->GetClipModel(0), flags, rotation.GetOrigin(),
|
||||
*blocking->GetAxis(0), rotation, mass);
|
||||
}
|
||||
|
||||
idPush::pushResult_t idPush::TryRotatePushPhysicsObject(trace_t& results,
|
||||
idPhysics* const check, idClipModel* const pusherModel,
|
||||
const int flags, const idVec3& rotationPoint, const idMat3& oldAxis,
|
||||
const idRotation& rotation, float& mass) {
|
||||
if (check == nullptr) return PUSH_BLOCKED;
|
||||
trace_t trace{};
|
||||
ClipPhysicsObjectRotation(trace, check, pusherModel, pusherModel,
|
||||
rotation);
|
||||
if (trace.fraction < 1.0f) {
|
||||
const pushResult_t recursive = RecursiveTryRotatePushPhysicsObject(
|
||||
results, trace, check, flags, rotation, mass);
|
||||
if (recursive != PUSH_OK) return recursive;
|
||||
}
|
||||
SavePhysicsObjectState(check);
|
||||
check->Rotate(&rotation, -1);
|
||||
if ((flags & 2) != 0 && !RotatePhysicsObjectToAxial(check,
|
||||
rotationPoint, pusherModel)) {
|
||||
check->RestoreState();
|
||||
return PUSH_BLOCKED;
|
||||
}
|
||||
mass += check->GetMass(-1);
|
||||
ClearTrace(results, *check->GetOrigin(0), oldAxis * rotation.ToMat3());
|
||||
return PUSH_OK;
|
||||
}
|
||||
|
||||
float idPush::ClipTranslationalPush(trace_t& results,
|
||||
idPhysics* const pusher, const int flags, const idVec3& newOrigin,
|
||||
const idVec3& translation) {
|
||||
idBounds sweep;
|
||||
if (!GameLib_GetPushSweepBounds(pusher,
|
||||
newOrigin - translation, newOrigin, *pusher->GetAxis(0),
|
||||
*pusher->GetAxis(0), sweep)) return 0.0f;
|
||||
idPhysics* objects[256]{};
|
||||
const int count = GetPhysicsObjectsTouchingBounds(objects, sweep,
|
||||
flags, pusher);
|
||||
float mass = 0.0f;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
if (TryTranslatePushPhysicsObject(results, objects[index],
|
||||
pusher->GetClipModel(0), flags, *objects[index]->GetOrigin(0),
|
||||
translation, mass) != PUSH_OK) return mass;
|
||||
}
|
||||
return mass;
|
||||
}
|
||||
|
||||
float idPush::ClipRotationalPush(trace_t& results,
|
||||
idPhysics* const pusher, const int flags, const idMat3& newAxis,
|
||||
const idRotation& rotation) {
|
||||
idBounds sweep;
|
||||
const idVec3 origin = *pusher->GetOrigin(0);
|
||||
if (!GameLib_GetPushSweepBounds(pusher, origin, origin,
|
||||
*pusher->GetAxis(0), newAxis, sweep)) return 0.0f;
|
||||
idPhysics* objects[256]{};
|
||||
const int count = GetPhysicsObjectsTouchingBounds(objects, sweep,
|
||||
flags, pusher);
|
||||
float mass = 0.0f;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
if (TryRotatePushPhysicsObject(results, objects[index],
|
||||
pusher->GetClipModel(0), flags, origin,
|
||||
*objects[index]->GetAxis(0), rotation, mass) != PUSH_OK)
|
||||
return mass;
|
||||
}
|
||||
return mass;
|
||||
}
|
||||
|
||||
float idPush::ClipPush(trace_t& results, idPhysics* const pusher,
|
||||
const int flags, const idVec3& oldOrigin, const idMat3& oldAxis,
|
||||
idVec3& newOrigin, idMat3& newAxis) {
|
||||
ClearTrace(results, newOrigin, newAxis);
|
||||
if (pusher == nullptr) return 0.0f;
|
||||
InitSavingPushedPhysicsObjectState();
|
||||
float totalMass = 0.0f;
|
||||
const idVec3 translation = newOrigin - oldOrigin;
|
||||
if (translation.LengthSqr() > 0.0f) {
|
||||
totalMass += ClipTranslationalPush(results, pusher, flags,
|
||||
newOrigin, translation);
|
||||
if (results.fraction < 1.0f) {
|
||||
RestorePushedPhysicsObjectState();
|
||||
newOrigin = oldOrigin;
|
||||
newAxis = oldAxis;
|
||||
return totalMass;
|
||||
}
|
||||
}
|
||||
const idRotation rotation = GameLib_GetPushRotation(newOrigin,
|
||||
oldAxis, newAxis);
|
||||
if (rotation.GetAngle() != 0.0f) {
|
||||
totalMass += ClipRotationalPush(results, pusher, flags,
|
||||
newAxis, rotation);
|
||||
if (results.fraction < 1.0f) {
|
||||
RestorePushedPhysicsObjectState();
|
||||
newOrigin = oldOrigin;
|
||||
newAxis = oldAxis;
|
||||
}
|
||||
}
|
||||
return totalMass;
|
||||
}
|
||||
@@ -1,18 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
|
||||
// Original PDB header: w:\tech5\engine\gamelib\physics\push.h
|
||||
// Recovered logical types: 2
|
||||
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
|
||||
#include "gamelib/physics/physics.h"
|
||||
#include "idlib/bv/bounds.h"
|
||||
#include "idlib/containers/list.h"
|
||||
#include "idlib/math/rotation.h"
|
||||
|
||||
|
||||
// IDA Local Type ordinal 14173; PDB kind: class.
|
||||
class idPush
|
||||
{
|
||||
class idPush {
|
||||
public:
|
||||
idClip *clip;
|
||||
idList<idPhysics *,77> pushed;
|
||||
enum pushResult_t : int {
|
||||
PUSH_OK = 0,
|
||||
PUSH_BLOCKED = 1,
|
||||
PUSH_CRUSHED = 2
|
||||
};
|
||||
|
||||
explicit idPush(idClip* clip = nullptr);
|
||||
void Init(idClip* clip);
|
||||
void InitSavingPushedPhysicsObjectState();
|
||||
void SavePhysicsObjectState(idPhysics* physics);
|
||||
void RestorePushedPhysicsObjectState();
|
||||
void SetPushedOnPushedPhysicsObjects(int deltaTime);
|
||||
float ClipPush(trace_t& results, idPhysics* pusher, int flags,
|
||||
const idVec3& oldOrigin, const idMat3& oldAxis,
|
||||
idVec3& newOrigin, idMat3& newAxis);
|
||||
|
||||
idClip* clip;
|
||||
idList<idPhysics*, 77> pushed;
|
||||
|
||||
private:
|
||||
void ClipPhysicsObjectRotation(trace_t& trace, idPhysics* physics,
|
||||
const idClipModel* clipModel, idClipModel* skip,
|
||||
const idRotation& rotation);
|
||||
void ClipPhysicsObjectTranslation(trace_t& trace, idPhysics* physics,
|
||||
const idClipModel* clipModel, idClipModel* skip,
|
||||
const idVec3& translation);
|
||||
bool CanPushPhysicsObject(idPhysics* physics, int flags,
|
||||
idPhysics* pusher);
|
||||
int GetPhysicsObjectsTouchingBounds(idPhysics** physicsObjects,
|
||||
const idBounds& bounds, int flags, idPhysics* pusher);
|
||||
bool RotatePhysicsObjectToAxial(idPhysics* physics,
|
||||
const idVec3& rotationPoint, const idClipModel* clipModel);
|
||||
pushResult_t RecursiveTryTranslatePushPhysicsObject(trace_t& results,
|
||||
trace_t& trace, idPhysics* pusher, int flags,
|
||||
const idVec3& translation, float& mass);
|
||||
pushResult_t RecursiveTryRotatePushPhysicsObject(trace_t& results,
|
||||
trace_t& trace, idPhysics* pusher, int flags,
|
||||
const idRotation& rotation, float& mass);
|
||||
pushResult_t TryTranslatePushPhysicsObject(trace_t& results,
|
||||
idPhysics* check, idClipModel* pusherModel, int flags,
|
||||
const idVec3& oldOrigin, const idVec3& translation, float& mass);
|
||||
pushResult_t TryRotatePushPhysicsObject(trace_t& results,
|
||||
idPhysics* check, idClipModel* pusherModel, int flags,
|
||||
const idVec3& rotationPoint, const idMat3& oldAxis,
|
||||
const idRotation& rotation, float& mass);
|
||||
float ClipTranslationalPush(trace_t& results, idPhysics* pusher,
|
||||
int flags, const idVec3& newOrigin, const idVec3& translation);
|
||||
float ClipRotationalPush(trace_t& results, idPhysics* pusher,
|
||||
int flags, const idMat3& newAxis, const idRotation& rotation);
|
||||
};
|
||||
|
||||
// IDA Local Type ordinal 29474; PDB kind: typedef.
|
||||
typedef unsigned __int16 ush;
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
static_assert(sizeof(idPush) == 20, "Recovered idPush ABI changed");
|
||||
#endif
|
||||
|
||||
@@ -148,6 +148,35 @@ private:
|
||||
float* p;
|
||||
};
|
||||
|
||||
// Fixed six-component spatial vector embedded by articulated-figure bodies
|
||||
// and constraints. Tungsten keeps an eight-float, 16-byte-aligned backing
|
||||
// slab so VMX loads can safely read both halves of the six-vector.
|
||||
class alignas(16) idStaticSpatialVec : public idSpatialVec {
|
||||
public:
|
||||
idStaticSpatialVec()
|
||||
: idSpatialVec()
|
||||
, data{} {
|
||||
SetData(6, data);
|
||||
}
|
||||
|
||||
idStaticSpatialVec(const idStaticSpatialVec& other)
|
||||
: idStaticSpatialVec() {
|
||||
for (int index = 0; index < 6; ++index) data[index] = other.data[index];
|
||||
}
|
||||
|
||||
idStaticSpatialVec& operator=(const idStaticSpatialVec& other) {
|
||||
if (this != &other) {
|
||||
for (int index = 0; index < 6; ++index)
|
||||
data[index] = other.data[index];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
alignas(16) float data[8];
|
||||
};
|
||||
|
||||
#if INTPTR_MAX == INT32_MAX
|
||||
static_assert(sizeof(idSpatialVec) == 8, "Recovered idSpatialVec ABI changed");
|
||||
static_assert(sizeof(idStaticSpatialVec) == 48,
|
||||
"Recovered idStaticSpatialVec ABI changed");
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user