Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,11 @@ class W3DModelDraw : public DrawModule, public ObjectDrawInterface
Bool m_hideHeadlights;
Bool m_pauseAnimation;
Int m_animationMode;
Real m_prevTurretAngle[MAX_TURRETS];
Real m_currTurretAngle[MAX_TURRETS];
Real m_prevTurretPitch[MAX_TURRETS];
Real m_currTurretPitch[MAX_TURRETS];
UnsignedInt m_lastTurretSampledFrame;

void adjustAnimation(const ModelConditionInfo* prevState, Real prevAnimFraction);
Real getCurrentAnimFraction() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,11 @@
#include "Common/GameState.h"
#include "Common/GlobalData.h"
#include "Common/PerfTimer.h"
#include "Common/RandomValue.h"
#include "Common/ThingTemplate.h"
#include "Common/GameLOD.h"
#include "Common/Xfer.h"
#include "Common/GameEngine.h"
#include "Common/FramePacer.h"
#include "Common/GameUtility.h"
#include "GameClient/Drawable.h"
#include "GameClient/FXList.h"
#include "GameClient/Shadow.h"
Expand Down Expand Up @@ -1740,6 +1741,14 @@ W3DModelDraw::W3DModelDraw(Thing *thing, const ModuleData* moduleData) : DrawMod
{
m_weaponRecoilInfoVec[i].clear();
}
m_lastTurretSampledFrame = 0;
for (i = 0; i < MAX_TURRETS; ++i)
{
m_prevTurretAngle[i] = 0.0f;
m_currTurretAngle[i] = 0.0f;
m_prevTurretPitch[i] = 0.0f;
m_currTurretPitch[i] = 0.0f;
}
m_needRecalcBoneParticleSystems = false;
m_fullyObscuredByShroud = false;

Expand Down Expand Up @@ -2422,28 +2431,62 @@ void W3DModelDraw::handleClientTurretPositioning()
if (!m_curState || !(m_curState->m_validStuff & ModelConditionInfo::TURRETS_VALID))
return;

const Object* obj = getDrawable() ? getDrawable()->getObject() : nullptr;
const AIUpdateInterface* ai = obj ? obj->getAIUpdateInterface() : nullptr;
UnsignedInt currentLogicFrame = TheGameLogic ? TheGameLogic->getFrame() : 0;

if (currentLogicFrame != m_lastTurretSampledFrame)
{
for (int tslot = 0; tslot < MAX_TURRETS; ++tslot)
{
Real rawAngle = 0.0f;
Real rawPitch = 0.0f;
if (ai)
{
ai->getTurretRotAndPitch((WhichTurretType)tslot, &rawAngle, &rawPitch);
}

if (m_lastTurretSampledFrame > 0 && currentLogicFrame == m_lastTurretSampledFrame + 1)
{
m_prevTurretAngle[tslot] = m_currTurretAngle[tslot];
m_currTurretAngle[tslot] = rawAngle;

m_prevTurretPitch[tslot] = m_currTurretPitch[tslot];
m_currTurretPitch[tslot] = rawPitch;
}
else
{
m_prevTurretAngle[tslot] = rawAngle;
m_currTurretAngle[tslot] = rawAngle;

m_prevTurretPitch[tslot] = rawPitch;
m_currTurretPitch[tslot] = rawPitch;
}
}
m_lastTurretSampledFrame = currentLogicFrame;
}

Real alpha = (TheGameEngine && TheFramePacer) ? TheGameEngine->getLogicTimeAccumulator() * TheFramePacer->getActualLogicTimeScaleFps() : 0.0f;
Real clampAlpha = (alpha > 1.0f) ? 1.0f : ((alpha < 0.0f) ? 0.0f : alpha);

for (int tslot = 0; tslot < MAX_TURRETS; ++tslot)
{
const ModelConditionInfo::TurretInfo& tur = m_curState->m_turrets[tslot];
Real turretAngle = 0;
Real turretPitch = 0;
if (tur.m_turretAngleBone || tur.m_turretPitchBone)
{
const Object *obj = getDrawable()->getObject();
if (obj)
{
const AIUpdateInterface* ai = obj->getAIUpdateInterface();
if (ai)
ai->getTurretRotAndPitch((WhichTurretType)tslot, &turretAngle, &turretPitch);
}
Real angleDelta = stdAngleDiff(m_currTurretAngle[tslot], m_prevTurretAngle[tslot]);
Real interpTurretAngle = m_prevTurretAngle[tslot] + angleDelta * clampAlpha;

Real pitchDelta = m_currTurretPitch[tslot] - m_prevTurretPitch[tslot];
Real interpTurretPitch = m_prevTurretPitch[tslot] + pitchDelta * clampAlpha;

// do turret, if any
if (tur.m_turretAngleBone != 0)
{
if (m_curState)
turretAngle += tur.m_turretArtAngle;
interpTurretAngle += tur.m_turretArtAngle;
Matrix3D turretXfrm(1);
turretXfrm.Rotate_Z(turretAngle);
turretXfrm.Rotate_Z(interpTurretAngle);
if (m_renderObject)
{
m_renderObject->Capture_Bone( tur.m_turretAngleBone );
Expand All @@ -2455,9 +2498,9 @@ void W3DModelDraw::handleClientTurretPositioning()
if (tur.m_turretPitchBone != 0)
{
if (m_curState)
turretPitch += tur.m_turretArtPitch;
interpTurretPitch += tur.m_turretArtPitch;
Matrix3D turretPitchXfrm(1);
turretPitchXfrm.Rotate_Y(-turretPitch);
turretPitchXfrm.Rotate_Y(-interpTurretPitch);
if (m_renderObject)
{
m_renderObject->Capture_Bone( tur.m_turretPitchBone );
Expand Down
3 changes: 3 additions & 0 deletions Generals/Code/GameEngine/Include/Common/GameEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ class GameEngine : public SubsystemInterface

Bool m_quitting; ///< true when we need to quit the game
Bool m_isActive; ///< app has OS focus.

public:
Real getLogicTimeAccumulator() const { return m_logicTimeAccumulator; }
};

inline void GameEngine::setQuitting( Bool quitting ) { m_quitting = quitting; }
Expand Down
3 changes: 3 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/GameEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ class GameEngine : public SubsystemInterface

Bool m_quitting; ///< true when we need to quit the game
Bool m_isActive; ///< app has OS focus.

public:
Real getLogicTimeAccumulator() const { return m_logicTimeAccumulator; }
};

inline void GameEngine::setQuitting( Bool quitting ) { m_quitting = quitting; }
Expand Down
10 changes: 10 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class DrawModule;
class ClientUpdateModule;
class View;
class Locomotor;
class ProjectileUpdateInterface;
class Anim2D;
class Shadow;
class ModuleInfo;
Expand Down Expand Up @@ -652,6 +653,7 @@ class Drawable : public Thing,
private:

const Locomotor* getLocomotor() const;
void applySubFrameExtrapolation();

// note, these are lazily allocated!
TintEnvelope* m_selectionFlashEnvelope; ///< used for selection flash, works WITH m_colorTintEnvelope
Expand Down Expand Up @@ -711,6 +713,7 @@ class Drawable : public Thing,

Matrix3D m_instance; ///< The instance matrix that holds the initial/default position & orientation
Real m_instanceScale; ///< the uniform scale factor applied to the instance matrix before it is sent to W3D.
Matrix3D m_visualExtrapolationMtx; ///< Decoupled visual glide matrix

DrawableInfo m_drawableInfo; ///< structure pointed to by W3D render objects so they know which drawable they belong to.

Expand All @@ -730,11 +733,18 @@ class Drawable : public Thing,
Bool m_hiddenByStealth; ///< drawable is hidden due to stealth
Bool m_instanceIsIdentity; ///< If true, instance matrix can be skipped
Bool m_drawableFullyObscuredByShroud; ///<drawable is hidden by shroud/fog
Bool m_useExtrapolation; ///< True if currently gliding
Matrix3D m_prevLogicMtx; ///< Matrix recorded at logic frame N-1
Matrix3D m_currLogicMtx; ///< Matrix recorded at logic frame N
UnsignedInt m_lastSampledLogicFrame; ///< Last sampled logic frame tick
Bool m_hasInterpolationData; ///< True if valid prev & curr matrices exist
Bool m_ambientSoundEnabled;
Bool m_ambientSoundEnabledFromScript;

Bool m_receivesDynamicLights;

private:

#ifdef DIRTY_CONDITION_FLAGS
Bool m_isModelDirty; ///< if true, must call replaceModelConditionState() before drawing or accessing drawmodule info
#endif
Expand Down
85 changes: 85 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "Common/DrawModule.h"
#include "Common/FramePacer.h"
#include "Common/GameAudio.h"
#include "Common/GameEngine.h"
#include "Common/GameLOD.h"
#include "Common/GameState.h"
#include "Common/GameUtility.h"
Expand All @@ -61,6 +62,7 @@
#include "GameLogic/Module/StealthUpdate.h"
#include "GameLogic/Module/StickyBombUpdate.h"
#include "GameLogic/Module/BattlePlanUpdate.h"
#include "GameLogic/Module/UpdateModule.h"
#include "GameLogic/ScriptEngine.h"
#include "GameLogic/Weapon.h"

Expand Down Expand Up @@ -408,6 +410,12 @@ Drawable::Drawable( const ThingTemplate *thingTemplate, DrawableStatusBits statu
//Real scaleFuzziness = thingTemplate->getInstanceScaleFuzziness();
//Real fuzzyScale = ( 1.0f + GameClientRandomValueReal( -scaleFuzziness, scaleFuzziness ));
m_instanceScale = thingTemplate->getAssetScale();// * fuzzyScale;
m_useExtrapolation = FALSE;
m_visualExtrapolationMtx.Make_Identity();
m_prevLogicMtx.Make_Identity();
m_currLogicMtx.Make_Identity();
m_lastSampledLogicFrame = 0;
m_hasInterpolationData = FALSE;

// initially not bound to an object
m_object = nullptr;
Expand Down Expand Up @@ -1145,6 +1153,8 @@ void Drawable::updateDrawable()
UnsignedInt now = TheGameLogic->getFrame();
Object *obj = getObject();

applySubFrameExtrapolation();

{
for (ClientUpdateModule** cu = getClientUpdateModules(); cu && *cu; ++cu)
{
Expand Down Expand Up @@ -4244,6 +4254,11 @@ void Drawable::setInstanceMatrix( const Matrix3D *instance )
//-------------------------------------------------------------------------------------------------
const Matrix3D *Drawable::getTransformMatrix() const
{
if (m_useExtrapolation)
{
return &m_visualExtrapolationMtx;
}

const Object *obj = getObject();

if (obj)
Expand Down Expand Up @@ -5639,3 +5654,73 @@ void TintEnvelope::loadPostProcess()

}

void Drawable::applySubFrameExtrapolation()
{
Object* obj = getObject();
if (!obj || !TheGameLogic)
{
m_useExtrapolation = FALSE;
return;
}

UnsignedInt currentLogicFrame = TheGameLogic->getFrame();

if (currentLogicFrame != m_lastSampledLogicFrame)
{
const Matrix3D& currentMtx = *obj->getTransformMatrix();

if (m_lastSampledLogicFrame > 0 && currentLogicFrame == m_lastSampledLogicFrame + 1)
{
m_prevLogicMtx = m_currLogicMtx;
m_currLogicMtx = currentMtx;

Vector3 deltaPos = m_currLogicMtx.Get_Translation() - m_prevLogicMtx.Get_Translation();
if (deltaPos.Length2() > 40000.0f) // >200 units threshold for teleportation
{
m_prevLogicMtx = m_currLogicMtx;
m_hasInterpolationData = FALSE;
}
else
{
m_hasInterpolationData = TRUE;
}
}
else
{
m_prevLogicMtx = currentMtx;
m_currLogicMtx = currentMtx;
m_hasInterpolationData = FALSE;
}

m_lastSampledLogicFrame = currentLogicFrame;
}

Real alpha = TheGameEngine->getLogicTimeAccumulator() * TheFramePacer->getActualLogicTimeScaleFps();

if (m_hasInterpolationData && alpha >= 0.0f)
{
Real clampAlpha = (alpha > 1.0f) ? 1.0f : alpha;

Vector3 prevPos = m_prevLogicMtx.Get_Translation();
Vector3 currPos = m_currLogicMtx.Get_Translation();
Vector3 interpPos = prevPos + (currPos - prevPos) * clampAlpha;

Real prevAngle = m_prevLogicMtx.Get_Z_Rotation();
Real currAngle = m_currLogicMtx.Get_Z_Rotation();
Real angleDelta = stdAngleDiff(currAngle, prevAngle);

m_visualExtrapolationMtx = m_prevLogicMtx;

if (fabs(angleDelta) > 0.001f && fabs(angleDelta) < 3.0f)
{
m_visualExtrapolationMtx.In_Place_Pre_Rotate_Z(angleDelta * clampAlpha);
}

m_visualExtrapolationMtx.Set_Translation(interpPos);
m_useExtrapolation = TRUE;
}
else
{
m_useExtrapolation = FALSE;
}
}
Loading