Added gamelib physics and effects.

This commit is contained in:
Justin Marshall
2026-08-09 04:29:27 -07:00
parent 1d0c9d6657
commit 47c4709db7
29 changed files with 4171 additions and 917 deletions
@@ -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);
}
+89 -190
View File
@@ -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
+738
View File
@@ -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;
}
+261 -54
View File
@@ -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;
}
+38 -18
View File
@@ -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);
}
+66 -44
View File
@@ -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);
}
}
+68 -28
View File
@@ -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);
}
}
+30 -197
View File
@@ -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;
}
+204
View File
@@ -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);
}
+98 -62
View File
@@ -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
+123
View File
@@ -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);
}
}
+25 -10
View File
@@ -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
+116
View File
@@ -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);
}
+41 -9
View File
@@ -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
+2
View File
@@ -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));
}
+63 -109
View File
@@ -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 &empty;
}
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 &current.worldOrigin; }
const idMat3* idPhysics_Static::GetAxis(int) { return &current.worldAxis; }
const idVec3* idPhysics_Static::GetLocalOrigin(int) { return &current.localOrigin; }
const idMat3* idPhysics_Static::GetLocalAxis(int) { return &current.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; }
+104 -92
View File
@@ -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
+263
View File
@@ -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;
}
+57 -12
View File
@@ -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
+29
View File
@@ -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