diff --git a/Core/Libraries/Source/WWVegas/WW3D2/hanim.h b/Core/Libraries/Source/WWVegas/WW3D2/hanim.h index 6565263988..34df969829 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/hanim.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/hanim.h @@ -95,11 +95,7 @@ class HAnimClass : public RefCountClass, public HashableClass virtual float Get_Frame_Rate() = 0; virtual float Get_Total_Time() = 0; -// virtual Vector3 Get_Translation(int pividx,float frame) = 0; -// virtual Quaternion Get_Orientation(int pividx,float frame) = 0; // Jani: Changed to pass in reference of destination to avoid copying - virtual void Get_Translation(int pividx,float frame) {} // todo: remove - virtual void Get_Orientation(int pividx,float frame) {} // todo: remove virtual void Get_Translation(Vector3& translation, int pividx,float frame) const = 0; virtual void Get_Orientation(Quaternion& orientation, int pividx,float frame) const = 0; virtual void Get_Transform(Matrix3D&, int pividx, float frame) const = 0; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h index fe21ef1787..5924046fff 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h @@ -93,8 +93,6 @@ class HCompressedAnimClass : public HAnimClass float Get_Total_Time() { return (float)NumFrames / FrameRate; } int Get_Flavor() { return Flavor; } -// Vector3 Get_Translation(int pividx,float frame); -// Quaternion Get_Orientation(int pividx,float frame); void Get_Translation(Vector3& translation, int pividx,float frame) const; void Get_Orientation(Quaternion& orientation, int pividx,float frame) const; void Get_Transform(Matrix3D& transform, int pividx,float frame) const; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp b/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp index 0a8d11c999..db808dc948 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp @@ -62,6 +62,7 @@ #include "wwmemlog.h" #include "hrawanim.h" #include "motchan.h" +#include "ww3d.h" /*********************************************************************************************** * HTreeClass::HTreeClass -- constructor * @@ -606,8 +607,16 @@ void HTreeClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float fra /*Customized version of the above which excludes interpolation and assumes HRawAnimClass For use by 'Generals' -MW*/ -void HTreeClass::Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame) +void HTreeClass::Anim_Update_Without_Interpolation(const Matrix3D & root,HRawAnimClass * motion,float frame) { + if (WW3D::Get_Sync_Frame_Time() == 0 && (int)motion->Get_Frame_Rate() == WWSyncPerSecond) + { + // TheSuperHackers @tweak Keep the animation frame step in sync with the ww3d frame step if they can align. + // @todo This needs improving if the WWSyncPerSecond is changed or the animation frame rates can be larger. + static_assert(WWSyncPerSecond == 30, "This is currently catered to a 30 fps sync"); + return; + } + PivotClass *pivot,*endpivot,*lastAnimPivot; Pivot[0].Transform = root; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/htree.h b/Core/Libraries/Source/WWVegas/WW3D2/htree.h index f0fe2c563c..01e993061f 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/htree.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/htree.h @@ -100,7 +100,7 @@ class HTreeClass : public W3DMPO void Anim_Update( const Matrix3D & root, HAnimClass * motion, float frame); - void Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame); + void Anim_Update_Without_Interpolation(const Matrix3D & root,HRawAnimClass * motion,float frame); void Blend_Update( const Matrix3D & root, HAnimClass * motion0, diff --git a/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp b/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp index 9795b38909..f5fc0417a2 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp @@ -1146,13 +1146,9 @@ void RingRenderObjClass::animate() InnerScaleChannel.Get_Key_Count () > 0 || OuterScaleChannel.Get_Key_Count () > 0) { - // - // Convert from milliseconds to seconds and normalize the time - // if (AnimDuration > 0) { - float frametime = WW3D::Get_Frame_Time(); - frametime = (frametime * 0.001F) / AnimDuration; - anim_time += frametime; + float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + anim_time += frametime / AnimDuration; } else { anim_time = 1.0F; } diff --git a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp index 16ccba9f86..dd97d4a050 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp @@ -78,7 +78,6 @@ SegLineRendererClass::SegLineRendererClass(void) : NoiseAmplitude(0.0f), MergeAbortFactor(1.5f), TextureTileFactor(1.0f), - LastUsedSyncTime(WW3D::Get_Sync_Time()), CurrentUVOffset(0.0f,0.0f), UVOffsetDeltaPerMS(0.0f, 0.0f), Bits(DEFAULT_BITS), @@ -98,7 +97,6 @@ SegLineRendererClass::SegLineRendererClass(const SegLineRendererClass & that) : NoiseAmplitude(0.0f), MergeAbortFactor(1.5f), TextureTileFactor(1.0f), - LastUsedSyncTime(that.LastUsedSyncTime), CurrentUVOffset(0.0f,0.0f), UVOffsetDeltaPerMS(0.0f, 0.0f), Bits(DEFAULT_BITS), @@ -120,7 +118,6 @@ SegLineRendererClass & SegLineRendererClass::operator = (const SegLineRendererCl NoiseAmplitude = that.NoiseAmplitude; MergeAbortFactor = that.MergeAbortFactor; TextureTileFactor = that.TextureTileFactor; - LastUsedSyncTime = that.LastUsedSyncTime; CurrentUVOffset = that.CurrentUVOffset; UVOffsetDeltaPerMS = that.UVOffsetDeltaPerMS; Bits = that.Bits; @@ -201,7 +198,6 @@ void SegLineRendererClass::Set_Texture_Tile_Factor(float factor) void SegLineRendererClass::Reset_Line(void) { - LastUsedSyncTime = WW3D::Get_Sync_Time(); CurrentUVOffset.Set(0.0f,0.0f); } @@ -227,9 +223,8 @@ void SegLineRendererClass::Render /* ** Handle texture UV offset animation (done once for entire line). */ - unsigned int delta = WW3D::Get_Sync_Time() - LastUsedSyncTime; - float del = (float)delta; - Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * del; + // TheSuperHackers @tweak The render update is now decoupled from the logic step. + Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * WW3D::Get_Logic_Frame_Time_Milliseconds(); // ensure offsets are in [0, 1] range: uv_offset.X = uv_offset.X - floorf(uv_offset.X); @@ -237,7 +232,6 @@ void SegLineRendererClass::Render // Update state CurrentUVOffset = uv_offset; - LastUsedSyncTime = WW3D::Get_Sync_Time(); // Used later TextureMapMode map_mode = Get_Texture_Mapping_Mode(); diff --git a/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp b/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp index fa3e5c4ed3..bd3514e747 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp @@ -1104,13 +1104,9 @@ void SphereRenderObjClass::animate (void) ScaleChannel.Get_Key_Count () > 0 || VectorChannel.Get_Key_Count () > 0) { - // - // Convert from milliseconds to seconds and normalize the time - // if (AnimDuration > 0) { - float frametime = WW3D::Get_Frame_Time(); - frametime = (frametime * 0.001F) / AnimDuration; - anim_time += frametime; + float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + anim_time += frametime / AnimDuration; } else { anim_time = 1.0F; } diff --git a/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h b/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h index a2a2248ecc..329324ca51 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h +++ b/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h @@ -26,6 +26,12 @@ #define ARRAY_SIZE(x) int(sizeof(x)/sizeof(x[0])) #endif +enum +{ + // TheSuperHackers @info The original WWSync was 33 ms, ~30 fps, integer. + // Changing this will require tweaking all Drawable code that concerns the ww3d time step, including locomotion physics. + WWSyncPerSecond = 30 +}; #if defined(_MSC_VER) && _MSC_VER < 1300 typedef unsigned MemValueType; diff --git a/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h b/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h index d7acdd7b4e..eb25d597db 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h +++ b/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h @@ -18,8 +18,11 @@ #pragma once -// The WW3D Sync time. This was originally 33 ms, ~30 fps, integer. -// Changing or removing this will require tweaking all Drawable code that concerns logic time step, including locomotion physics. -#ifndef MSEC_PER_WWSYNC_FRAME -#define MSEC_PER_WWSYNC_FRAME (33) +// Enable translation and rotation interpolation for raw animation (HRawAnimClass) updates. +// This was intentionally disabled in the retail version, but likely not fully thought through. +// Interpolation is certainly desired for animations that move and rotate meshes, but may not be +// desired for animations that teleport meshes from one location to another, such as blinking lights. +// @todo Implement a new flag per animation file to opt-out of interpolation. +#ifndef WW3D_ENABLE_RAW_ANIM_INTERPOLATION +#define WW3D_ENABLE_RAW_ANIM_INTERPOLATION (1) #endif diff --git a/Core/Tools/W3DView/GraphicView.cpp b/Core/Tools/W3DView/GraphicView.cpp index ccf5bbfca5..185c4465c6 100644 --- a/Core/Tools/W3DView/GraphicView.cpp +++ b/Core/Tools/W3DView/GraphicView.cpp @@ -546,7 +546,7 @@ CGraphicView::RepaintView // // Let the audio class think // - WWAudioClass::Get_Instance ()->On_Frame_Update (WW3D::Get_Frame_Time()); + WWAudioClass::Get_Instance ()->On_Frame_Update (WW3D::Get_Logic_Frame_Time_Milliseconds()); // // Update the count of particles and polys in the status bar diff --git a/Generals/Code/GameEngine/Include/Common/GameCommon.h b/Generals/Code/GameEngine/Include/Common/GameCommon.h index 87813783e1..e83eea3bb3 100644 --- a/Generals/Code/GameEngine/Include/Common/GameCommon.h +++ b/Generals/Code/GameEngine/Include/Common/GameCommon.h @@ -66,7 +66,7 @@ enum { BaseFps = 30, // The historic base frame rate for this game. This value must never change. - LOGICFRAMES_PER_SECOND = 30, + LOGICFRAMES_PER_SECOND = WWSyncPerSecond, MSEC_PER_SECOND = 1000 }; const Real LOGICFRAMES_PER_MSEC_REAL = (((Real)LOGICFRAMES_PER_SECOND) / ((Real)MSEC_PER_SECOND)); diff --git a/Generals/Code/GameEngine/Include/GameClient/Drawable.h b/Generals/Code/GameEngine/Include/GameClient/Drawable.h index 8807b3930e..750f76fcf8 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Drawable.h +++ b/Generals/Code/GameEngine/Include/GameClient/Drawable.h @@ -168,7 +168,7 @@ class TintEnvelope : public MemoryPoolObject, public Snapshot TintEnvelope(void); void update(void); ///< does all the work void play(const RGBColor *peak, - UnsignedInt atackFrames = DEF_ATTACK_FRAMES, + UnsignedInt attackFrames = DEF_ATTACK_FRAMES, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt sustainAtPeak = DEF_SUSTAIN_FRAMES ); // ask MLorenzen void sustain(void) { m_envState = ENVELOPE_STATE_SUSTAIN; } @@ -231,7 +231,6 @@ enum DrawableStatus CPP_11(: DrawableStatusBits) DRAWABLE_STATUS_NONE = 0x00000000, ///< no status DRAWABLE_STATUS_DRAWS_IN_MIRROR = 0x00000001, ///< drawable can reflect DRAWABLE_STATUS_SHADOWS = 0x00000002, ///< use setShadowsEnabled() access method - DRAWABLE_STATUS_TINT_COLOR_LOCKED = 0x00000004, ///< drawable tint color is "locked" and won't fade to normal DRAWABLE_STATUS_NO_STATE_PARTICLES = 0x00000008, ///< do *not* auto-create particle systems based on model condition DRAWABLE_STATUS_NO_SAVE = 0x00000010, ///< do *not* save this drawable (UI fluff only). ignored (error, actually) if attached to an object @@ -372,7 +371,7 @@ class Drawable : public Thing, Bool getDrawsInMirror() const { return BitIsSet(m_status, DRAWABLE_STATUS_DRAWS_IN_MIRROR) || isKindOf(KINDOF_CAN_CAST_REFLECTIONS); } - void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = FALSE ); ///< flash a drawable in the color specified for a short time + void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = 0 ); ///< flash a drawable in the color specified for a short time void colorTint( const RGBColor *color ); ///< tint this drawable the color specified void setTintEnvelope( const RGBColor *color, Real attack, Real decay ); ///< how to transition color void flashAsSelected( const RGBColor *color = NULL ); ///< drawable takes care of the details if you spec no color diff --git a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h index 6b9815a411..512e0ee5a1 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -133,6 +133,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Real getHeight( void ); ///< Returns the height of the world Bool isInGameLogicUpdate( void ) const { return m_isInUpdate; } + Bool hasUpdated() const { return m_hasUpdated; } ///< Returns true if the logic frame has advanced in the current client/render update UnsignedInt getFrame( void ); ///< Returns the current simulation frame number UnsignedInt getCRC( Int mode = CRC_CACHED, AsciiString deepCRCFileName = AsciiString::TheEmptyString ); ///< Returns the CRC @@ -301,6 +302,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Bool m_loadingScene; Bool m_isInUpdate; + Bool m_hasUpdated; Int m_rankPointsToAddAtGameStart; diff --git a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp index c2b324641c..58a1419c12 100644 --- a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp @@ -255,7 +255,7 @@ GameEngine::GameEngine( void ) // initialize to non garbage values m_maxFPS = BaseFps; m_logicTimeScaleFPS = LOGICFRAMES_PER_SECOND; - m_updateTime = 0.0f; + m_updateTime = 1.0f / BaseFps; // initialized to something to avoid division by zero on first use m_logicTimeAccumulator = 0.0f; m_quitting = FALSE; m_isActive = FALSE; diff --git a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp index 9891fb0f89..891bd99470 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -922,9 +922,6 @@ void Drawable::colorFlash( const RGBColor* color, UnsignedInt decayFrames, Unsig white.setFromInt(0xffffffff); m_colorTintEnvelope->play( &white ); } - - // make sure the tint color is unlocked so we "fade back down" to normal - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); } // ------------------------------------------------------------------------------------------------ @@ -935,11 +932,7 @@ void Drawable::colorTint( const RGBColor* color ) if( color ) { // set the color via color flash - colorFlash( color, 0, 0, TRUE ); - - // lock the tint color so the flash never "fades back down" - setDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - + colorFlash( color, 0, 0, ~0u ); } else { @@ -948,10 +941,6 @@ void Drawable::colorTint( const RGBColor* color ) // remove the tint applied to the object m_colorTintEnvelope->rest(); - - // set the tint as unlocked so we can flash and stuff again - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - } } @@ -1264,7 +1253,7 @@ void Drawable::applyPhysicsXform(Matrix3D* mtx) { // TheSuperHackers @tweak Update the physics transform on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() != 0) + if (WW3D::Get_Sync_Frame_Time() != 0) { calcPhysicsXform(*m_physicsXform); } @@ -4756,11 +4745,11 @@ TintEnvelope::TintEnvelope(void) const Real FADE_RATE_EPSILON = (0.001f); //------------------------------------------------------------------------------------------------- -void TintEnvelope::play(const RGBColor *peak, UnsignedInt atackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) +void TintEnvelope::play(const RGBColor *peak, UnsignedInt attackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) { setPeakColor( peak ); - setAttackFrames( atackFrames ); + setAttackFrames( attackFrames ); setDecayFrames( decayFrames ); m_envState = ENVELOPE_STATE_ATTACK; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp index 3bfdc41b17..328d1dfdbe 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp @@ -147,7 +147,7 @@ UpdateSleepTime EMPUpdate::update( void ) { RGBColor end = data->m_endColor; saturateRGB( end, 5 ); - dr->colorFlash( &end, 9999, m_tintEnvFadeFrames, TRUE ); + dr->colorFlash( &end, 0, m_tintEnvFadeFrames, ~0u ); doDisableAttack(); } diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 1f01c04aa4..92bf469c28 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -226,6 +226,7 @@ GameLogic::GameLogic( void ) // m_frame = 0; + m_hasUpdated = FALSE; m_frameObjectsChangedTriggerAreas = 0; m_width = 0; m_height = 0; @@ -256,6 +257,7 @@ GameLogic::GameLogic( void ) void GameLogic::setDefaults( Bool saveGame ) { m_frame = 0; + m_hasUpdated = FALSE; m_width = DEFAULT_WORLD_WIDTH; m_height = DEFAULT_WORLD_HEIGHT; m_objList = NULL; @@ -1020,6 +1022,7 @@ void GameLogic::startNewGame( Bool saveGame ) // reset the frame counter m_frame = 0; + m_hasUpdated = FALSE; #ifdef DEBUG_CRC // TheSuperHackers @info helmutbuhler 04/09/2025 @@ -3327,6 +3330,7 @@ void GameLogic::update( void ) if (!m_startNewGame) { m_frame++; + m_hasUpdated = TRUE; } } @@ -3334,6 +3338,8 @@ void GameLogic::update( void ) // ------------------------------------------------------------------------------------------------ void GameLogic::preUpdate() { + m_hasUpdated = FALSE; + if (m_pauseFrame == m_frame && m_pauseFrame != 0) { m_pauseFrame = 0; diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h index 5be5f6fc74..52cc395bc6 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h @@ -180,7 +180,6 @@ class HeightMapRenderObjClass : public RenderObjClass, public DX8_CleanupHook void renderTerrainPass(CameraClass *pCamera); ///< renders additional terrain pass. W3DShroud *getShroud() {return m_shroud;} - void renderExtraBlendTiles(void); ///< render 3-way blend tiles that have blend of 3 textures. void updateShorelineTiles(Int minX, Int minY, Int maxX, Int maxY, WorldHeightMap *pMap); ///
m_useCloudMap; + const Bool doCloud = useCloud(); + + if (doCloud) + { + // TheSuperHackers @tweak Updates the cloud movement before applying it to the world. + // Is now decoupled from logic step. + W3DShaderManager::updateCloud(); + } Matrix3D tm(Transform); #if 0 // There is some weirdness sometimes with the dx8 static buffers. @@ -3906,10 +3913,6 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } - st=W3DShaderManager::ST_TERRAIN_BASE; //set default shader //set correct shader based on current settings @@ -4454,10 +4457,7 @@ void HeightMapRenderObjClass::renderExtraBlendTiles(void) W3DShaderManager::ShaderTypes st = W3DShaderManager::ST_ROAD_BASE; - Bool doCloud = TheGlobalData->m_useCloudMap; - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } + const Bool doCloud = useCloud(); if (TheGlobalData->m_useLightMap && doCloud) { @@ -4486,3 +4486,9 @@ void HeightMapRenderObjClass::renderExtraBlendTiles(void) } } } + +//============================================================================= +Bool HeightMapRenderObjClass::useCloud() +{ + return TheGlobalData->m_useCloudMap && TheGlobalData->m_timeOfDay != TIME_OF_DAY_NIGHT; +} diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 0f1306bcb8..c839a8e988 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1731,7 +1731,10 @@ void W3DDisplay::draw( void ) } } - WW3D::Add_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + + // TheSuperHackers @info This binds the WW3D update to the logic update. + WW3D::Sync(TheGameLogic->hasUpdated()); static Int now; now=timeGetTime(); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 2c9d8a26d5..a219e4912d 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1248,12 +1248,14 @@ class TerrainShader2Stage : public W3DShaderInterface public: float m_xSlidePerSecond ; ///< How far the clouds move per second. float m_ySlidePerSecond ; ///< How far the clouds move per second. - int m_curTick; float m_xOffset; float m_yOffset; + virtual Int set(Int pass); /// 1) m_xOffset -= 1; + while (m_yOffset > 1) m_yOffset -= 1; + while (m_xOffset < -1) m_xOffset += 1; + while (m_yOffset < -1) m_yOffset += 1; +} + void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curViewInverse, Bool doUpdate) { #define STRETCH_FACTOR ((float)(1/(63.0*MAP_XY_FACTOR/2))) /* covers 63/2 tiles */ @@ -1340,26 +1352,6 @@ void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curVie *destMatrix = *curViewInverse * scale; D3DXMATRIX offset; - - Int delta = m_curTick; - m_curTick = WW3D::Get_Sync_Time();//::GetTickCount(); - delta = m_curTick-delta; - m_xOffset += m_xSlidePerSecond*delta/1000; - m_yOffset += m_ySlidePerSecond*delta/1000; - - - //m_xOffset += m_xSlidePerSecond*delta/500; - //m_yOffset += m_ySlidePerSecond*delta/500; - - - //m_yOffset = sinf( (float)m_curTick * 0.0001f ); - //m_xOffset = cosf( (float)m_curTick * 0.0001f ); - - if (m_xOffset > 1) m_xOffset -= 1; - if (m_yOffset > 1) m_yOffset -= 1; - if (m_xOffset < -1) m_xOffset += 1; - if (m_yOffset < -1) m_yOffset += 1; - D3DXMatrixTranslation(&offset, m_xOffset, m_yOffset,0); *destMatrix *= offset; } @@ -2447,6 +2439,12 @@ void W3DShaderManager::shutdown(void) } } +//============================================================================= +void W3DShaderManager::updateCloud() +{ + terrainShader2Stage.updateCloud(); +} + // W3DShaderManager::getShaderPasses ======================================================= /** Return number of renderig passes required in perform the desired shader on current hardware. App will need to re-render the polygons this many times to complete the diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index f2d8d959ce..4cf15ff829 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -89,7 +89,6 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -145,7 +144,6 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -205,7 +203,6 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl ModeAnim.Motion = NULL; ModeAnim.Frame = 0.0f; ModeAnim.PrevFrame = 0.0f; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0 = NULL; @@ -289,12 +286,6 @@ void Animatable3DObjClass::Render(RenderInfoClass & rinfo) return; } - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid() || Are_Sub_Object_Transforms_Dirty()) { Update_Sub_Object_Transforms(); } @@ -316,12 +307,6 @@ void Animatable3DObjClass::Special_Render(SpecialRenderInfoClass & rinfo) { if (HTree == NULL) return; - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid()) { Update_Sub_Object_Transforms(); } @@ -476,7 +461,6 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m ModeAnim.Motion = motion; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = frame; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added @@ -777,7 +761,7 @@ void Animatable3DObjClass::Control_Bone(int bindex,const Matrix3D & objtm,bool w void Animatable3DObjClass::Update_Sub_Object_Transforms(void) { /* - ** The RenderObj impementation will cause our 'container' + ** The RenderObj implementation will cause our 'container' ** to update if we are not valid yet */ CompositeRenderObjClass::Update_Sub_Object_Transforms(); @@ -949,27 +933,30 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const // Compute the current frame based on elapsed time. // if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) { - float sync_time_diff = WW3D::Get_Sync_Time() - ModeAnim.LastSyncTime; - float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * sync_time_diff * 0.001f; + // TheSuperHackers @tweak The animation render update is now decoupled from the logic step. + const float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + const float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * frametime; frame += delta; // // Wrap the frame // + const int numFrames = ModeAnim.Motion->Get_Num_Frames() - 1; + switch (ModeAnim.AnimMode) { case ANIM_MODE_ONCE: - if (frame >= ModeAnim.Motion->Get_Num_Frames() - 1) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + if (frame >= numFrames) { + frame = numFrames; } break; case ANIM_MODE_LOOP: - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame -= ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame = 0; + if ( frame >= numFrames ) { + frame -= numFrames; + // If it is still too far out, reset + if ( frame >= numFrames ) { + frame = 0; + } } break; case ANIM_MODE_ONCE_BACKWARDS: //play animation one time but backwards @@ -979,22 +966,22 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const break; case ANIM_MODE_LOOP_BACKWARDS: //play animation backwards in a loop if ( frame < 0 ) { - frame += ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame < 0 ) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + frame += numFrames; + // If it is still too far out, reset + if ( frame < 0 ) { + frame = numFrames; + } } break; case ANIM_MODE_LOOP_PINGPONG: if (ModeAnim.animDirection >= 1.0f) { //playing forwards, reverse direction - if (frame >= (ModeAnim.Motion->Get_Num_Frames() - 1)) + if (frame >= numFrames) { //step backwards in animation by excess time - frame = (ModeAnim.Motion->Get_Num_Frames() - 1)*2 - frame; + frame = numFrames * 2 - frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) - frame = (ModeAnim.Motion->Get_Num_Frames() - 1); + if ( frame >= numFrames - 1 ) + frame = numFrames; direction = ModeAnim.animDirection * -1.0f; } } @@ -1004,7 +991,7 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const { //step forwards in animation by excess time frame = -frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) + if ( frame >= numFrames ) frame = 0; direction = ModeAnim.animDirection * -1.0f; } @@ -1043,19 +1030,11 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // // Update the frame number and sync time // - float oldprev = ModeAnim.PrevFrame; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); - if (ModeAnim.Frame == ModeAnim.PrevFrame) { - // This function was somehow called twice per frame. - // Since ModeAnim.Frame hasn't changed, reset the ModeAnim.PrevFrame. - // If you don't do this sounds won't be triggered properly because Frame and PrevFrame will be the same. - ModeAnim.PrevFrame = oldprev; - } // - // Force the heirarchy to be recalculated + // Force the hierarchy to be recalculated // Set_Hierarchy_Valid (false); } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index cd5a745d84..b93b1bc775 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -190,7 +190,6 @@ class Animatable3DObjClass : public CompositeRenderObjClass float Frame; float PrevFrame; int AnimMode; - mutable int LastSyncTime; float animDirection; float frameRateMultiplier; // 020607 srj -- added } ModeAnim; @@ -262,9 +261,11 @@ inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * ** Apply motion to the base pose */ if ((motion) && (HTree)) { - if (ModeAnim.Motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) - HTree->Anim_Update(Transform,(HRawAnimClass*)ModeAnim.Motion,ModeAnim.Frame); +#if !WW3D_ENABLE_RAW_ANIM_INTERPOLATION + if (motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) + HTree->Anim_Update_Without_Interpolation(root,(HRawAnimClass*)motion,frame); else +#endif HTree->Anim_Update(root,motion,frame); } Set_Hierarchy_Valid(true); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp index 5b27bdaf4a..9e4a933d95 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp @@ -940,8 +940,7 @@ void DazzleRenderObjClass::Render(RenderInfoClass & rinfo) const DazzleTypeClass* params=types[type]; params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,current_distance); - unsigned time_ms=WW3D::Get_Frame_Time(); - if (time_ms==0) time_ms=1; + float time_ms=WW3D::Get_Logic_Frame_Time_Milliseconds(); float weight=pow(params->ic.history_weight,time_ms); if (dazzle_intensity>0.0f) { @@ -1012,9 +1011,6 @@ void DazzleRenderObjClass::Render_Dazzle(CameraClass* camera) screen_x_scale=h/w; } -// unsigned time_ms=WW3D::Get_Frame_Time(); -// if (time_ms==0) time_ms=1; - float halo_scale_x=types[type]->ic.halo_scale_x; float halo_scale_y=types[type]->ic.halo_scale_y; float dazzle_scale_x=types[type]->ic.dazzle_scale_x; @@ -1481,9 +1477,6 @@ void DazzleLayerClass::Render(CameraClass* camera) camera->Apply(); - unsigned time_ms=WW3D::Get_Frame_Time(); - if (time_ms==0) time_ms=1; - DX8Wrapper::Set_Material(NULL); for (unsigned type=0;type max_intensity_delta) { Intensity += max_intensity_delta; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index cadd4fb4bf..0acd23d847 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -165,6 +165,7 @@ const char* DAZZLE_INI_FILENAME="DAZZLE.INI"; ** ***********************************************************************************/ +float WW3D::LogicFrameTimeMs = 1000.0f / WWSyncPerSecond; // initialized to something to avoid division by zero on first use float WW3D::FractionalSyncMs = 0.0f; unsigned int WW3D::SyncTime = 0; unsigned int WW3D::PreviousSyncTime = 0; @@ -1168,21 +1169,10 @@ unsigned int WW3D::Get_Last_Frame_Vertex_Count(void) return Debug_Statistics::Get_DX8_Vertices(); } -void WW3D::Add_Frame_Time(float milliseconds) +void WW3D::Update_Logic_Frame_Time(float milliseconds) { + LogicFrameTimeMs = milliseconds; FractionalSyncMs += milliseconds; - unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; - -#if MSEC_PER_WWSYNC_FRAME - if (integralSyncMs < MSEC_PER_WWSYNC_FRAME) - { - Sync(SyncTime); - return; - } -#endif - - FractionalSyncMs -= integralSyncMs; - Sync(SyncTime + integralSyncMs); } @@ -1198,12 +1188,17 @@ void WW3D::Add_Frame_Time(float milliseconds) * HISTORY: * * 3/24/98 GTH : Created. * *=============================================================================================*/ -void WW3D::Sync(unsigned int sync_time) +void WW3D::Sync(bool step) { PreviousSyncTime = SyncTime; - SyncTime = sync_time; -} + if (step) + { + unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; + FractionalSyncMs -= integralSyncMs; + SyncTime += integralSyncMs; + } +} /*********************************************************************************************** * WW3D::Set_Ext_Swap_Interval -- Sets the swap interval the device should aim sync for. * diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index 9c544db816..4cb8c5bf9b 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -162,18 +162,20 @@ class WW3D static void Flip_To_Primary(void); - // TheSuperHackers @info Call this function to accumulate fractional render time. - // It will then call Sync with a new time on its own once an appropriate amount of time has passed. - static void Add_Frame_Time(float milliseconds); + // TheSuperHackers @info Add amount of milliseconds that the simulation has advanced in this render frame. + // This can be a fraction of a logic step. + static void Update_Logic_Frame_Time(float milliseconds); /* ** Timing ** By calling the Sync function, the application can move the ww3d library time forward. This ** will control things like animated uv-offset mappers and render object animations. */ - static void Sync( unsigned int sync_time ); + static void Sync(bool step); static unsigned int Get_Sync_Time(void) { return SyncTime; } - static unsigned int Get_Frame_Time(void) { return SyncTime - PreviousSyncTime; } - static unsigned int Get_Frame_Count(void) { return FrameCount; } + static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } + static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } + static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; } + static unsigned int Get_Frame_Count(void) { return FrameCount; } static unsigned int Get_Last_Frame_Poly_Count(void); static unsigned int Get_Last_Frame_Vertex_Count(void); @@ -323,19 +325,23 @@ class WW3D static void Allocate_Debug_Resources(void); static void Release_Debug_Resources(void); + // Logic frame time, in milliseconds + static float LogicFrameTimeMs; + + // Accumulated synchronized frame time in milliseconds static float FractionalSyncMs; // Timing info: - // The absolute synchronized frame time (in milliseconds) supplied by the - // application at the start of every frame. Note that wraparound cases - // etc. need to be considered. - static unsigned int SyncTime; - - // The previously set absolute sync time - this is used to get the interval between - // the most recently set sync time and the previous one. Assuming the - // application sets sync time at the start of every frame, this represents - // the frame interval. - static unsigned int PreviousSyncTime; + // The absolute synchronized frame time (in milliseconds) supplied by the + // application at the start of every frame. Note that wraparound cases + // etc. need to be considered. + static unsigned int SyncTime; + + // The previously set absolute sync time - this is used to get the interval between + // the most recently set sync time and the previous one. Assuming the + // application sets sync time at the start of every frame, this represents + // the frame interval. + static unsigned int PreviousSyncTime; static float PixelCenterX; static float PixelCenterY; diff --git a/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h b/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h index d7acdd7b4e..eb25d597db 100644 --- a/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h +++ b/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h @@ -18,8 +18,11 @@ #pragma once -// The WW3D Sync time. This was originally 33 ms, ~30 fps, integer. -// Changing or removing this will require tweaking all Drawable code that concerns logic time step, including locomotion physics. -#ifndef MSEC_PER_WWSYNC_FRAME -#define MSEC_PER_WWSYNC_FRAME (33) +// Enable translation and rotation interpolation for raw animation (HRawAnimClass) updates. +// This was intentionally disabled in the retail version, but likely not fully thought through. +// Interpolation is certainly desired for animations that move and rotate meshes, but may not be +// desired for animations that teleport meshes from one location to another, such as blinking lights. +// @todo Implement a new flag per animation file to opt-out of interpolation. +#ifndef WW3D_ENABLE_RAW_ANIM_INTERPOLATION +#define WW3D_ENABLE_RAW_ANIM_INTERPOLATION (1) #endif diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h b/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h index 723ab57d2b..2ce08a130f 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h @@ -72,7 +72,7 @@ enum { BaseFps = 30, // The historic base frame rate for this game. This value must never change. - LOGICFRAMES_PER_SECOND = 30, + LOGICFRAMES_PER_SECOND = WWSyncPerSecond, MSEC_PER_SECOND = 1000 }; const Real LOGICFRAMES_PER_MSEC_REAL = (((Real)LOGICFRAMES_PER_SECOND) / ((Real)MSEC_PER_SECOND)); diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h index 868a189584..7f320bd409 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h @@ -171,7 +171,7 @@ class TintEnvelope : public MemoryPoolObject, public Snapshot TintEnvelope(void); void update(void); ///< does all the work void play(const RGBColor *peak, - UnsignedInt atackFrames = DEF_ATTACK_FRAMES, + UnsignedInt attackFrames = DEF_ATTACK_FRAMES, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt sustainAtPeak = DEF_SUSTAIN_FRAMES ); // ask MLorenzen void sustain(void) { m_envState = ENVELOPE_STATE_SUSTAIN; } @@ -234,7 +234,6 @@ enum DrawableStatus CPP_11(: DrawableStatusBits) DRAWABLE_STATUS_NONE = 0x00000000, ///< no status DRAWABLE_STATUS_DRAWS_IN_MIRROR = 0x00000001, ///< drawable can reflect DRAWABLE_STATUS_SHADOWS = 0x00000002, ///< use setShadowsEnabled() access method - DRAWABLE_STATUS_TINT_COLOR_LOCKED = 0x00000004, ///< drawable tint color is "locked" and won't fade to normal DRAWABLE_STATUS_NO_STATE_PARTICLES = 0x00000008, ///< do *not* auto-create particle systems based on model condition DRAWABLE_STATUS_NO_SAVE = 0x00000010, ///< do *not* save this drawable (UI fluff only). ignored (error, actually) if attached to an object @@ -388,7 +387,7 @@ class Drawable : public Thing, Bool getDrawsInMirror() const { return BitIsSet(m_status, DRAWABLE_STATUS_DRAWS_IN_MIRROR) || isKindOf(KINDOF_CAN_CAST_REFLECTIONS); } - void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = FALSE ); ///< flash a drawable in the color specified for a short time + void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = 0 ); ///< flash a drawable in the color specified for a short time void colorTint( const RGBColor *color ); ///< tint this drawable the color specified void setTintEnvelope( const RGBColor *color, Real attack, Real decay ); ///< how to transition color void flashAsSelected( const RGBColor *color = NULL ); ///< drawable takes care of the details if you spec no color diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h index 285847aad9..5931e710fd 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -138,6 +138,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Real getHeight( void ); ///< Returns the height of the world Bool isInGameLogicUpdate( void ) const { return m_isInUpdate; } + Bool hasUpdated() const { return m_hasUpdated; } ///< Returns true if the logic frame has advanced in the current client/render update UnsignedInt getFrame( void ); ///< Returns the current simulation frame number UnsignedInt getCRC( Int mode = CRC_CACHED, AsciiString deepCRCFileName = AsciiString::TheEmptyString ); ///< Returns the CRC @@ -324,6 +325,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Bool m_clearingGameData; Bool m_isInUpdate; + Bool m_hasUpdated; Int m_rankPointsToAddAtGameStart; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index c7f30f53eb..02d786b4e5 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -253,7 +253,7 @@ GameEngine::GameEngine( void ) // initialize to non garbage values m_maxFPS = BaseFps; m_logicTimeScaleFPS = LOGICFRAMES_PER_SECOND; - m_updateTime = 0.0f; + m_updateTime = 1.0f / BaseFps; // initialized to something to avoid division by zero on first use m_logicTimeAccumulator = 0.0f; m_quitting = FALSE; m_isActive = FALSE; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 328440a0ea..dce9e2c412 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -971,9 +971,6 @@ void Drawable::colorFlash( const RGBColor* color, UnsignedInt decayFrames, Unsig white.setFromInt(0xffffffff); m_colorTintEnvelope->play( &white ); } - - // make sure the tint color is unlocked so we "fade back down" to normal - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); } // ------------------------------------------------------------------------------------------------ @@ -984,11 +981,7 @@ void Drawable::colorTint( const RGBColor* color ) if( color ) { // set the color via color flash - colorFlash( color, 0, 0, TRUE ); - - // lock the tint color so the flash never "fades back down" - setDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - + colorFlash( color, 0, 0, ~0u ); } else { @@ -997,10 +990,6 @@ void Drawable::colorTint( const RGBColor* color ) // remove the tint applied to the object m_colorTintEnvelope->rest(); - - // set the tint as unlocked so we can flash and stuff again - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - } } @@ -1392,7 +1381,7 @@ void Drawable::applyPhysicsXform(Matrix3D* mtx) { // TheSuperHackers @tweak Update the physics transform on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() != 0) + if (WW3D::Get_Sync_Frame_Time() != 0) { calcPhysicsXform(*m_physicsXform); } @@ -5513,11 +5502,11 @@ TintEnvelope::TintEnvelope(void) const Real FADE_RATE_EPSILON = (0.001f); //------------------------------------------------------------------------------------------------- -void TintEnvelope::play(const RGBColor *peak, UnsignedInt atackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) +void TintEnvelope::play(const RGBColor *peak, UnsignedInt attackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) { setPeakColor( peak ); - setAttackFrames( atackFrames ); + setAttackFrames( attackFrames ); setDecayFrames( decayFrames ); m_envState = ENVELOPE_STATE_ATTACK; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp index 8d754fa1b0..63e7fdb9e4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp @@ -149,7 +149,7 @@ UpdateSleepTime EMPUpdate::update( void ) { RGBColor end = data->m_endColor; saturateRGB( end, 5 ); - dr->colorFlash( &end, 9999, m_tintEnvFadeFrames, TRUE ); + dr->colorFlash( &end, 0, m_tintEnvFadeFrames, ~0u ); doDisableAttack(); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 540731886d..7cdcc3eabb 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -237,6 +237,7 @@ GameLogic::GameLogic( void ) // m_frame = 0; + m_hasUpdated = FALSE; m_frameObjectsChangedTriggerAreas = 0; m_width = 0; m_height = 0; @@ -271,6 +272,7 @@ GameLogic::GameLogic( void ) void GameLogic::setDefaults( Bool loadingSaveGame ) { m_frame = 0; + m_hasUpdated = FALSE; m_width = DEFAULT_WORLD_WIDTH; m_height = DEFAULT_WORLD_HEIGHT; m_objList = NULL; @@ -1157,6 +1159,7 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) // reset the frame counter m_frame = 0; + m_hasUpdated = FALSE; #ifdef DEBUG_CRC // TheSuperHackers @info helmutbuhler 04/09/2025 @@ -3863,6 +3866,7 @@ void GameLogic::update( void ) if (!m_startNewGame) { m_frame++; + m_hasUpdated = TRUE; } } @@ -3870,6 +3874,8 @@ void GameLogic::update( void ) // ------------------------------------------------------------------------------------------------ void GameLogic::preUpdate() { + m_hasUpdated = FALSE; + if (m_pauseFrame == m_frame && m_pauseFrame != 0) { m_pauseFrame = 0; diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h index 7e439de2da..60165711af 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h @@ -328,6 +328,8 @@ class BaseHeightMapRenderObjClass : public RenderObjClass, public DX8_CleanupHoo void initDestAlphaLUT(void); ///m_useCloudMap && TheGlobalData->m_timeOfDay != TIME_OF_DAY_NIGHT; +} diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp index eb59745dd9..56af0e77ca 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp @@ -310,9 +310,11 @@ void W3DTankDraw::onRenderObjRecreated(void) //------------------------------------------------------------------------------------------------- void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) { + W3DModelDraw::doDrawModule(transformMtx); + // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real DEBRIS_THRESHOLD = 0.00001f; @@ -405,8 +407,6 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) } } } - - W3DModelDraw::doDrawModule(transformMtx); } // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp index 94b43a54b7..83945bf5f3 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp @@ -517,7 +517,7 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx) // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real ACCEL_THRESHOLD = 0.01f; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp index 12a52f8da1..49625d6628 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp @@ -395,7 +395,7 @@ void W3DTruckDraw::doDrawModule(const Matrix3D* transformMtx) // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real ACCEL_THRESHOLD = 0.01f; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp index 07a36aad45..553e62db20 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp @@ -459,7 +459,14 @@ void FlatHeightMapRenderObjClass::Render(RenderInfoClass & rinfo) Int devicePasses; W3DShaderManager::ShaderTypes st; - Bool doCloud = TheGlobalData->m_useCloudMap; + const Bool doCloud = useCloud(); + + if (doCloud) + { + // TheSuperHackers @tweak Updates the cloud movement before applying it to the world. + // Is now decoupled from logic step. + W3DShaderManager::updateCloud(); + } Matrix3D tm(Transform); // If there are trees, tell them to draw at the transparent time to draw. @@ -494,10 +501,6 @@ void FlatHeightMapRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } - st=W3DShaderManager::ST_FLAT_TERRAIN_BASE; //set default shader //set correct shader based on current settings diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp index 7891e46bdc..6b7dbd25a8 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp @@ -1912,7 +1912,14 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) Int i,j,devicePasses; W3DShaderManager::ShaderTypes st; - Bool doCloud = TheGlobalData->m_useCloudMap; + const Bool doCloud = useCloud(); + + if (doCloud) + { + // TheSuperHackers @tweak Updates the cloud movement before applying it to the world. + // Is now decoupled from logic step. + W3DShaderManager::updateCloud(); + } Matrix3D tm(Transform); #if 0 // There is some weirdness sometimes with the dx8 static buffers. @@ -2003,10 +2010,6 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } - st=W3DShaderManager::ST_TERRAIN_BASE; //set default shader //set correct shader based on current settings @@ -2415,10 +2418,7 @@ void HeightMapRenderObjClass::renderExtraBlendTiles(void) W3DShaderManager::ShaderTypes st = W3DShaderManager::ST_ROAD_BASE; - Bool doCloud = TheGlobalData->m_useCloudMap; - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } + const Bool doCloud = useCloud(); if (TheGlobalData->m_useLightMap && doCloud) { diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index cadeda7209..3b7fd684fd 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1812,7 +1812,10 @@ void W3DDisplay::draw( void ) } } - WW3D::Add_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + + // TheSuperHackers @info This binds the WW3D update to the logic update. + WW3D::Sync(TheGameLogic->hasUpdated()); static Int now; now=timeGetTime(); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index b487858291..a3df459813 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1482,12 +1482,14 @@ class TerrainShader2Stage : public W3DShaderInterface public: float m_xSlidePerSecond ; ///< How far the clouds move per second. float m_ySlidePerSecond ; ///< How far the clouds move per second. - int m_curTick; float m_xOffset; float m_yOffset; + virtual Int set(Int pass); /// 1) m_xOffset -= 1; + while (m_yOffset > 1) m_yOffset -= 1; + while (m_xOffset < -1) m_xOffset += 1; + while (m_yOffset < -1) m_yOffset += 1; +} + void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curViewInverse, Bool doUpdate) { #define STRETCH_FACTOR ((float)(1/(63.0*MAP_XY_FACTOR/2))) /* covers 63/2 tiles */ @@ -1605,26 +1617,6 @@ void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curVie *destMatrix = *curViewInverse * scale; D3DXMATRIX offset; - - Int delta = m_curTick; - m_curTick = WW3D::Get_Sync_Time();//::GetTickCount(); - delta = m_curTick-delta; - m_xOffset += m_xSlidePerSecond*delta/1000; - m_yOffset += m_ySlidePerSecond*delta/1000; - - - //m_xOffset += m_xSlidePerSecond*delta/500; - //m_yOffset += m_ySlidePerSecond*delta/500; - - - //m_yOffset = sinf( (float)m_curTick * 0.0001f ); - //m_xOffset = cosf( (float)m_curTick * 0.0001f ); - - while (m_xOffset > 1) m_xOffset -= 1; - while (m_yOffset > 1) m_yOffset -= 1; - while (m_xOffset < -1) m_xOffset += 1; - while (m_yOffset < -1) m_yOffset += 1; - D3DXMatrixTranslation(&offset, m_xOffset, m_yOffset,0); *destMatrix *= offset; } @@ -2704,6 +2696,12 @@ void W3DShaderManager::shutdown(void) } +//============================================================================= +void W3DShaderManager::updateCloud() +{ + terrainShader2Stage.updateCloud(); +} + // W3DShaderManager::getShaderPasses ======================================================= /** Return number of renderig passes required in perform the desired shader on current hardware. App will need to re-render the polygons this many times to complete the diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp index cf40de7c79..bed66d1c65 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp @@ -156,8 +156,8 @@ void W3DSnowManager::reset( void ) void W3DSnowManager::update(void) { - - m_time += WW3D::Get_Frame_Time() / 1000.0f; + // TheSuperHackers @tweak The snow render update is now decoupled from the logic step. + m_time += WW3D::Get_Logic_Frame_Time_Seconds(); //find current time offset, adjusting for overflow m_time=fmod(m_time,m_fullTimePeriod); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index 551cb69957..15e089a0ba 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -89,7 +89,6 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -145,7 +144,6 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -205,7 +203,6 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl ModeAnim.Motion = NULL; ModeAnim.Frame = 0.0f; ModeAnim.PrevFrame = 0.0f; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0 = NULL; @@ -289,12 +286,6 @@ void Animatable3DObjClass::Render(RenderInfoClass & rinfo) return; } - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid() || Are_Sub_Object_Transforms_Dirty()) { Update_Sub_Object_Transforms(); } @@ -316,12 +307,6 @@ void Animatable3DObjClass::Special_Render(SpecialRenderInfoClass & rinfo) { if (HTree == NULL) return; - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid()) { Update_Sub_Object_Transforms(); } @@ -476,7 +461,6 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m ModeAnim.Motion = motion; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = frame; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added @@ -776,7 +760,7 @@ void Animatable3DObjClass::Control_Bone(int bindex,const Matrix3D & objtm,bool w void Animatable3DObjClass::Update_Sub_Object_Transforms(void) { /* - ** The RenderObj impementation will cause our 'container' + ** The RenderObj implementation will cause our 'container' ** to update if we are not valid yet */ CompositeRenderObjClass::Update_Sub_Object_Transforms(); @@ -957,27 +941,30 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const // Compute the current frame based on elapsed time. // if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) { - float sync_time_diff = WW3D::Get_Sync_Time() - ModeAnim.LastSyncTime; - float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * sync_time_diff * 0.001f; + // TheSuperHackers @tweak The animation render update is now decoupled from the logic step. + const float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + const float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * frametime; frame += delta; // // Wrap the frame // + const int numFrames = ModeAnim.Motion->Get_Num_Frames() - 1; + switch (ModeAnim.AnimMode) { case ANIM_MODE_ONCE: - if (frame >= ModeAnim.Motion->Get_Num_Frames() - 1) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + if (frame >= numFrames) { + frame = numFrames; } break; case ANIM_MODE_LOOP: - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame -= ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame = 0; + if ( frame >= numFrames ) { + frame -= numFrames; + // If it is still too far out, reset + if ( frame >= numFrames ) { + frame = 0; + } } break; case ANIM_MODE_ONCE_BACKWARDS: //play animation one time but backwards @@ -987,22 +974,22 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const break; case ANIM_MODE_LOOP_BACKWARDS: //play animation backwards in a loop if ( frame < 0 ) { - frame += ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame < 0 ) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + frame += numFrames; + // If it is still too far out, reset + if ( frame < 0 ) { + frame = numFrames; + } } break; case ANIM_MODE_LOOP_PINGPONG: if (ModeAnim.animDirection >= 1.0f) { //playing forwards, reverse direction - if (frame >= (ModeAnim.Motion->Get_Num_Frames() - 1)) + if (frame >= numFrames) { //step backwards in animation by excess time - frame = (ModeAnim.Motion->Get_Num_Frames() - 1)*2 - frame; + frame = numFrames * 2 - frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) - frame = (ModeAnim.Motion->Get_Num_Frames() - 1); + if ( frame >= numFrames - 1 ) + frame = numFrames; direction = ModeAnim.animDirection * -1.0f; } } @@ -1012,7 +999,7 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const { //step forwards in animation by excess time frame = -frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) + if ( frame >= numFrames ) frame = 0; direction = ModeAnim.animDirection * -1.0f; } @@ -1051,19 +1038,11 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // // Update the frame number and sync time // - float oldprev = ModeAnim.PrevFrame; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); - if (ModeAnim.Frame == ModeAnim.PrevFrame) { - // This function was somehow called twice per frame. - // Since ModeAnim.Frame hasn't changed, reset the ModeAnim.PrevFrame. - // If you don't do this sounds won't be triggered properly because Frame and PrevFrame will be the same. - ModeAnim.PrevFrame = oldprev; - } // - // Force the heirarchy to be recalculated + // Force the hierarchy to be recalculated // Set_Hierarchy_Valid (false); } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index a671b5b1af..437480caf1 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -190,7 +190,6 @@ class Animatable3DObjClass : public CompositeRenderObjClass float Frame; float PrevFrame; int AnimMode; - mutable int LastSyncTime; float animDirection; float frameRateMultiplier; // 020607 srj -- added } ModeAnim; @@ -262,9 +261,11 @@ inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * ** Apply motion to the base pose */ if ((motion) && (HTree)) { - if (ModeAnim.Motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) - HTree->Anim_Update(Transform,(HRawAnimClass*)ModeAnim.Motion,ModeAnim.Frame); +#if !WW3D_ENABLE_RAW_ANIM_INTERPOLATION + if (motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) + HTree->Anim_Update_Without_Interpolation(root,(HRawAnimClass*)motion,frame); else +#endif HTree->Anim_Update(root,motion,frame); } Set_Hierarchy_Valid(true); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp index 1b19381d44..d609985123 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp @@ -975,8 +975,7 @@ void DazzleRenderObjClass::Render(RenderInfoClass & rinfo) const DazzleTypeClass* params=types[type]; params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,dir,current_distance); - unsigned time_ms=WW3D::Get_Frame_Time(); - if (time_ms==0) time_ms=1; + float time_ms=WW3D::Get_Logic_Frame_Time_Milliseconds(); float weight=pow(params->ic.history_weight,time_ms); if (dazzle_intensity>0.0f) { @@ -1048,9 +1047,6 @@ void DazzleRenderObjClass::Render_Dazzle(CameraClass* camera) screen_x_scale=h/w; } -// unsigned time_ms=WW3D::Get_Frame_Time(); -// if (time_ms==0) time_ms=1; - // Do NOT scale halo by current scale // because it uses screen parallel primitives // and if it's too big it will be visible until @@ -1587,9 +1583,6 @@ void DazzleLayerClass::Render(CameraClass* camera) camera->Apply(); - unsigned time_ms=WW3D::Get_Frame_Time(); - if (time_ms==0) time_ms=1; - DX8Wrapper::Set_Material(NULL); for (unsigned type=0;type max_intensity_delta) { Intensity += max_intensity_delta; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 14aa8203cd..c27bd87134 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -166,6 +166,7 @@ const char* DAZZLE_INI_FILENAME="DAZZLE.INI"; ** ***********************************************************************************/ +float WW3D::LogicFrameTimeMs = 1000.0f / WWSyncPerSecond; // initialized to something to avoid division by zero on first use float WW3D::FractionalSyncMs = 0.0f; unsigned int WW3D::SyncTime = 0; unsigned int WW3D::PreviousSyncTime = 0; @@ -1163,21 +1164,10 @@ unsigned int WW3D::Get_Last_Frame_Vertex_Count(void) return Debug_Statistics::Get_DX8_Vertices(); } -void WW3D::Add_Frame_Time(float milliseconds) +void WW3D::Update_Logic_Frame_Time(float milliseconds) { + LogicFrameTimeMs = milliseconds; FractionalSyncMs += milliseconds; - unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; - -#if MSEC_PER_WWSYNC_FRAME - if (integralSyncMs < MSEC_PER_WWSYNC_FRAME) - { - Sync(SyncTime); - return; - } -#endif - - FractionalSyncMs -= integralSyncMs; - Sync(SyncTime + integralSyncMs); } @@ -1193,12 +1183,17 @@ void WW3D::Add_Frame_Time(float milliseconds) * HISTORY: * * 3/24/98 GTH : Created. * *=============================================================================================*/ -void WW3D::Sync(unsigned int sync_time) +void WW3D::Sync(bool step) { PreviousSyncTime = SyncTime; - SyncTime = sync_time; -} + if (step) + { + unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; + FractionalSyncMs -= integralSyncMs; + SyncTime += integralSyncMs; + } +} /*********************************************************************************************** * WW3D::Set_Ext_Swap_Interval -- Sets the swap interval the device should aim sync for. * diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index af2261961e..0057dbf989 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -162,18 +162,20 @@ class WW3D static void Flip_To_Primary(void); - // TheSuperHackers @info Call this function to accumulate fractional render time. - // It will then call Sync with a new time on its own once an appropriate amount of time has passed. - static void Add_Frame_Time(float milliseconds); + // TheSuperHackers @info Add amount of milliseconds that the simulation has advanced in this render frame. + // This can be a fraction of a logic step. + static void Update_Logic_Frame_Time(float milliseconds); /* ** Timing ** By calling the Sync function, the application can move the ww3d library time forward. This ** will control things like animated uv-offset mappers and render object animations. */ - static void Sync( unsigned int sync_time ); + static void Sync(bool step); static unsigned int Get_Sync_Time(void) { return SyncTime; } - static unsigned int Get_Frame_Time(void) { return SyncTime - PreviousSyncTime; } - static unsigned int Get_Frame_Count(void) { return FrameCount; } + static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } + static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } + static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; } + static unsigned int Get_Frame_Count(void) { return FrameCount; } static unsigned int Get_Last_Frame_Poly_Count(void); static unsigned int Get_Last_Frame_Vertex_Count(void); @@ -323,19 +325,23 @@ class WW3D static void Allocate_Debug_Resources(void); static void Release_Debug_Resources(void); + // Logic frame time, in milliseconds + static float LogicFrameTimeMs; + + // Accumulated synchronized frame time in milliseconds static float FractionalSyncMs; // Timing info: - // The absolute synchronized frame time (in milliseconds) supplied by the - // application at the start of every frame. Note that wraparound cases - // etc. need to be considered. - static unsigned int SyncTime; - - // The previously set absolute sync time - this is used to get the interval between - // the most recently set sync time and the previous one. Assuming the - // application sets sync time at the start of every frame, this represents - // the frame interval. - static unsigned int PreviousSyncTime; + // The absolute synchronized frame time (in milliseconds) supplied by the + // application at the start of every frame. Note that wraparound cases + // etc. need to be considered. + static unsigned int SyncTime; + + // The previously set absolute sync time - this is used to get the interval between + // the most recently set sync time and the previous one. Assuming the + // application sets sync time at the start of every frame, this represents + // the frame interval. + static unsigned int PreviousSyncTime; static float PixelCenterX; static float PixelCenterY;