dhewm / dhewm3

dhewm 3 main repository
https://dhewm3.org/
GNU General Public License v3.0
1.74k stars 341 forks source link

Smooth movement on refresh rates above 60Hz? #230

Open dezo2 opened 5 years ago

dezo2 commented 5 years ago

Recently I found a simple tool named Quake 4 Tweaker, which allows Q4 to run smoothly on monitors with refresh rate above 60. https://community.pcgamingwiki.com/files/file/1009-quake-4-tweaker/ I think it does that by hacking into the global game timing slowing it down to the selected monitor refresh rate / target FPS. The more target FPS is selected, the slower the game movement/animation is, so it simply compensates for the game speed up above 60Hz when using uncapped framerate (com_fixedTic 1). The result is perfectly smooth gameplay with correct timing on higher refresh rates. Is it possible to implement something like this into the dhewm3 code? I tried the "experimental" com_fixedTic -1 but for me it behaves the same as com_fixedTic 0, so on the higher refresh rates (100, 120, 144) the movement is just a stuttery mess capped to 63Hz.

dezo2 commented 5 years ago

After some source code digging I think that all it takes is a little change in UsercmdGen.h: const int USERCMD_HZ = 120; //60 Compiling the source code will produce new base.dll - replace it in the dhewm3 installation and then use autoexec.cfg with: seta com_fixedTic "1" seta r_swapInterval "1" seta r_finish "1" ;optional to reduce input lag That should lock dhewm3 movement to smooth 120FPS just like in bfg edition. Cutscenes timing will be still a little off (that would need multiples of 62.5Hz refresh rate), but thats a minor problem compared to 60FPS judder on 120Hz refresh rate. I will test it some more, but so far it seems to be working OK.

KillPixelGames commented 5 years ago

This would be amazing. Playing Doom3 at 60hz is brutal. IMO, the 120hz of the BFG edition is its only saving grace.

I really hope this gets implemented in dhewm3 :D

buvk commented 5 years ago

Could you share the dll? I'm having issues compiling the source in mysys. Is it possible to go higher? E.g. 240hz

dezo2 commented 5 years ago

I am not that familiar with the sources, but I think Daniel should be able to create a cvar for this. Even if it should require restart of the engine, it will be better than hardcoded value. I didn't play with this since march, but I can share the 120Hz dll here for version 1.5.0, if you want to try it. It should work with any other frequency, but I tried only 120Hz as I have currently 120Hz monitor. Just make sure your autoexec.cfg is set as above. The dll is compiled using VS2017 and latest stable version 1.5.0 of sources.

base.zip

buvk commented 5 years ago

Hmm, I am definitely having some issues with this. The game speed often jumps to double the speed.

dezo2 commented 5 years ago

That cvar com_fixedTic "1" is a hack to remove the 62.5 framerate cap. It must be substituted using VSync. To get smooth gameplay, some criteria must be met:

DanielGibson commented 5 years ago

Ok, just to write something here: ;) The problem is, this kind of change is dangerous - you never know if that 60Hz assumption is hardcoded somewhere without using that USERCMD_HZ constant, which can cause subtle bugs - and I don't own a 120Hz display myself to test it.

(and if I understand correctly, @buvk's problem is not the framerate but that the game itself, i.e. animations or shooting or whatever, runs twice as fast as it should?)

dezo2 commented 5 years ago

I remember going trough almost half the game before posting it here, heavy shooting included and didn't encounter any speedups or slowdowns. No problems with fast GPU, but with slower one there might be some. I know the hack does not compensate for framerates below refresh rate, so engine speed slowdowns are inevitable. But the speedups are new for me...

buvk commented 5 years ago

My monitor is 240hz, and I removed 120hz via CRU due to DSR favoring lower refresh rates in some games.

I'd be happy to help test whatever I can here. I plan to play through the entire game, so if there are issues, there's a good chance I'll spot them.

dezo2 commented 5 years ago

Well, that's the problem. Display refresh rate must be the same as framerate, otherwise this hack will not work. In your case VSync is trying to hold the framerate at 240, not 120, hence the 2x speedups. But sometimes it falls down do 120 and then you see normal speed. You can try 120fps framelimiter or I can try to compile 240Hz dll for you, but if your GPU is not able to hold stable 240FPS, there is really no point - you would see slowdowns instead.

buvk commented 5 years ago

I actually tried limiting framerate via rtss; was still encountering weird issues.

My rig should be able to handle 240fps no problem, so if you can compile a new dll, I can test that and let you know the outcome.

dezo2 commented 5 years ago

There you go: base240.zip It moves at half speed on my 120Hz display, so on 240Hz it should run at normal speed with that above mentioned autoexec.cfg settings.

buvk commented 5 years ago

Well I guess my rig isn't good enough, or else the game/engine itself has issues sustaining higher framerates. I often saw framerate drop to around 120ish. My GPU usage remained low, so I don't think it's that (I have a 2080).

I'll play around with the 120hz dll some more.

On Thu., Jun. 13, 2019, 10:44 a.m. dezo2, notifications@github.com wrote:

There you go: base240.zip https://github.com/dhewm/dhewm3/files/3287402/base240.zip It moves at half speed on my 120Hz display, so on 240Hz it should run at normal speed with that above mentioned autoexec.cfg settings.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dhewm/dhewm3/issues/230?email_source=notifications&email_token=AAULDRZI6AEJQCM3PJOSFGTP2KBRVA5CNFSM4G3LTU6KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXUP45Q#issuecomment-501808758, or mute the thread https://github.com/notifications/unsubscribe-auth/AAULDR5FDELUAG6IUMMJNKLP2KBRVANCNFSM4G3LTU6A .

DanielGibson commented 5 years ago

can't you run your display at 120hz somehow? like, configure the refreshrate in windows or the GPU driver to 120hz?

dezo2 commented 5 years ago

That sucks. It may actually be CPU this time as the engine obviously isn't created for multicores and single core processing has its limits (as in the original Crysis 1 game).

DanielGibson commented 5 years ago

Yeah, multiple cores were not a thing in desktop PCs in 2004, so it's very single-threaded. (Some servers or workstations had multiple sockets for multiple CPUs, but that wasn't relevant in the gaming market)

Also, 240hz is just brutal: instead of 16.7ms per frame it's only 4ms per frame - that's not easy to achieve! I also seriously doubt anything beyond 120Hz really makes sense/a visible difference. (Many people say the same thing about more than 60Hz, but AFAIK most people can indeed see/feel the difference between 60 and 120)

dezo2 commented 5 years ago

I am glad I didn't go higher than 120Hz with my monitor, because the CPU/GPU demands are also doubled. That said, the difference between 60Hz and 100+Hz is VERY noticeable, even for an old fart like me. The smoothness reminds me of the good old CRT times, I really like it.

KillPixelGames commented 5 years ago

So, I tested this a few days ago (first time ever modifying or compiling code. yay me), some observations:

-ticrate MUST match the display refresh and you MUST use com_fixedtic 1 -120 and 144hz both present subtle issues, mostly with physics and animation -to truly be double, the game would need to run at 125hz, but since this hack relies on a fixedtic and no display (that I know of) runs at 125hz you will also have some desync issues. -a minor issue, but if you use com_fixedtic 1 and your fps falls below the ticrate, the entire game will slow (that said, always use com_fixedtic 1 on any version of doom/quake/prey if you can - it eliminates the 1 sec sync which causes a stutter and the overall feel is quite smoother).

The BFG edition manages to avoid all of this and run the game on a tic independent from the display refresh, even with com_fixedtic 1 and a display above 120hz.

EDIT: the Quake4 tweaker mentioned above WORKS LIKE A CHARM on quake4 - no issues whatsoever.

dezo2 commented 5 years ago

Yeah, the com_fixedTick hack + VSync is quite old, I think I used it all the time in old id tech games, because that 1sec stutter pissed me off. Cutscenes sound is out of sync because of the hack, but everything else seems to be mostly OK. Much better than with the stutter. With today PCs, the slowdowns are second to none, as the game is not that demanding. I really like to know they logic back then, why they have to use the internal tick at 62.5Hz? Why such stupid value? It is present even in their prerendered movies in game resources and looks pathetic. Nevertheless, it is possible to create custom resolution with 125Hz refresh rate, at least on nVidia cards in their control panel. I think every 144+Hz panel should be able to display that.

DanielGibson commented 5 years ago

why do you think it's 62.5, the constant (USERCMD_HZ) is 60?

EDIT: oh, is it because 1000/60 == 16 (in integers) and 1000/62.5 == 16 as well, even without any type-dependent rounding?

dezo2 commented 5 years ago

You might be onto something. I don't know the egine inside out, but it seems that the physics and sound are synchronized to 62.5Hz. That is the value I see in RivaTuner overlay with com_fixedTic 0 and disabled VSync. So not exactly the 60FPS, but this dreaded 62.5. The renderer also seems to repeat a frame every second even when used with 60Hz VSync to synchronize everything to that value.

KillPixelGames commented 5 years ago

You'll also notice that the vanilla game is capped at 62.5 (the OSD reads 62/63).

dezo2 commented 5 years ago

const int USERCMD_HZ = 60 // 60 frames per second const int USERCMD_MSEC = 1000 / USERCMD_HZ; So why they are using integer dividing here? For performance reasons? The second constant should be float and everything that depends on it it should be also calculated in floats. Strange.

DanielGibson commented 5 years ago

it's a constant so there is no difference in performance in the divide itself; I don't know why they're using int and not float there. Note that this is another problem for 120hz (or even more): while 16ms as an int constant seems to work well enough, the higher the Hz (and thus the lower the USERCMD_MSEC frametime), the more the inaccuracy of ints in milliseconds will hurt us. Using either a float or microseconds there should work better; but TBH I'm not sure I dare to make such a deep change - I imagine that this would require switching to float/microsecond in lots of places, possibly including the network protocol. And it might require lots of changes in the gamecode as well, which again would affect mods (=> make them harder to port and break the mod DLL interface; though just chaning USERCMD_HZ to another value or making it configurable at runtime would also break the DLL interface) :-/

KillPixelGames commented 5 years ago

https://github.com/RobertBeckebans/RBDOOM-3-BFG/commit/72f986077b4abb523b6b3ac6232bbaf62a0bbc8f

not sure if anything useful can be gleaned from this.

DanielGibson commented 5 years ago

RobertBeckebans/RBDOOM-3-BFG@72f9860

not sure if anything useful can be gleaned from this.

Not really, at least not from that commit itself - as you see USERCMD_HZ is apparently unused in the BFG code, so the change didn't matter. One could try to figure out what changes they did to the gamecode to make it work without it and see if our gamecode could be adjusted in the same way - but again, that might make porting mods harder :-/

KillPixelGames commented 5 years ago

The Quake4 tweaker mentioned earlier works flawlessly in my experience - unfortunately I can't find any sources for it.

https://methanhydrat.wordpress.com/2018/02/13/quake-4-tweaker/

DanielGibson commented 5 years ago

I sent the Quake 4 Tweaker author a message on the blog you linked, hopefully they'll tell me how it was done in Q4, maybe the same works for Doom3 (unless Q4 already eliminated USERCMD_HZ and it was just a cvar or sth.. we'll see).

Methanhydrat commented 5 years ago

Hi there, I am the author of the Quake 4 Tweaker mod.

I am afraid the solution I used for Quake 4 is not applicable to Doom 3. You are all on the right track and already discovered the USERCMD_HZ and USERCMD_MSEC constants. As far as I know, this would be the way to go to adjust the frame rate limit.

The version of id Tech 4 that Quake 4 uses is more advanced than what was released for Doom 3; which makes sense considering it came out a few years later. In that game, the above constants were merged into two additional functions in idCommonLocal, which I called GetUserCmdHz and GetUserCmdMsec, because they basically return computed values for the aforementioned constants.

These functions are called every frame from the engine and seem to be used throughout the code to calculate the corresponding timings. This makes it possible to adjust everything on the fly. The mod hooks these functions and adjusts their returns according to the FPS limit that was configured by the user.

Unfortunately, neither the Doom 3 nor the Doom 3 BFG code features this implementation. The latter uses a different mechanism than the original, but it is still not the same as what can be seen in Quake 4. This also makes sense, because, as far as I know, the BFG edition was developed from the original source code, with some backported featured from id Tech 5.

Now, I think your best bet is to adjust the constants and by hand just try to fix every additional problem that occurs. It might also be helpful to take a deeper look at how the problem was tackled in the BFG edition and maybe get some inspiration for how to do it.

I think it is unfortunate that some of these awesome shooters are hard or impossible to fix for high frame rates, since these types of games benefit immensely from it. What pains me most in this regard, is the original Prey, which is a game that I love, but which uses an even older version of id Tech 4. Contrary to Doom 3, where we have the source code and thus a fair chance to change it, that one most likely will never be fixed.

DanielGibson commented 5 years ago

Hey @Methanhydrat, thanks a lot for the insight! :)

A pity this won't work for Doom3; I kinda feared this (because patching it in Doom3 would probably have been next to impossible, as that constant will be used as a constant by the compiler, not some kind of variable that could be modified by a hack), but was hoping there's a trick to it..

I guess we should indeed look at D3BFG then. I wonder if it would be sufficient to just simulate the game (incl. animations) every 2. (for 120/144hz) or 4. (for 240Hz) frame and only update the viewport (based on the players input) in the others so input (hopefully) still feels smooth - but TBH I never looked closely at how Doom3 does all this, as so far it has just worked the way it is..

Regarding Prey: The game code (SDK) is available, so maybe it would be possible to combine some binary-hacks in the executable with an adapted game DLL? Alternatively one could try to port the Prey SDK to dhewm3, though that wouldn't really conform to the licenses (GPL and SDK license are incompatible, that's why I only support Doom3 mods that have (re-)released their source under GPL) - but OTOH if prey game DLLs turned up that just by dumb luck turned out to work with dhewm3 (possibly modified to implement missing engine features) there's nothing anyone could do about it? ;) Then again, 3DRealms still exists in some form, maybe they could even release the source properly? No idea if they have all the needed rights, but might be worth asking them?

Methanhydrat commented 5 years ago

I had a similar idea and actually already spent a considerable amount of time trying to marry the SDK sources of Prey with the Doom 3 code, in the hopes to have something that could then be could used to create some kind of source port, including a FPS fix.

Setting aside the licensing issues, at first glance this seems like a very promising approach. The SDK contains almost everything of the game, except for the engine and the Doom 3 source contains the engine that was used for the game. The problem is, that Human Head actually made quite a few modifications to the engine that are not part of the SDK. You can see this by examining the engine headers that are included in it.

I think it would still be doable for a diligent person to fill in the missing parts, since it seems like 95% of the code needed is there. However, the required effort is in the end hard to assess, because there could have been additional adjustments made to the engine, that are not visible by only examining the SDK.

A proper re-release of the source code would of course be awesome. In theory, it should also be possible to release the entire source code now, provided they would integrate the Prey changes in a separate fork of the Doom 3 release, which was not yet available when the SDK came out.

However, I am kind of skeptical that this is ever going to happen. Since 3D Realms is now part of Interceptor, I don't think they have any control over the license anymore. As far as I know, the rights to the Prey franchise were purchased by Bethesda. And since they have a new franchise using the Prey name, I highly doubt they are interested in re-releasing source code for a game, which they didn't even bother to keep digitally purchasable anymore.

But I would of course be thrilled, if someone could make that possible.

dezo2 commented 5 years ago

Regarding the 1sec stutter - going through the sources again, I just realized that the UsercmdGen.h is shared between all the projects (dhewm3, base, dx3p). So when someone wants to play it without the hack (com_fixedTic ="0" as default) at 120FPS or more, recompiled dhemw3 is also needed for the altered USERCMD_HZ/MSEC to take effect everywhere. Then there should be no engine slowdowns/speedups or audio desync, but instead the stupid stutter comming from integer rounding. And at higher refresh rates it will stutter even more, as Daniel mentioned.

From the code it seems that they based the entire timing on integer miliseconds (physics, sound, rendering, netcode) and synchronized everything to the (inaccurate) integer frametime value: 60Hz refresh -> 16ms instead of 16.66666ms frametime 120Hz refresh -> 8ms instead of 8.33333ms frametime and so on. This creates the stutter and without changing all affected functions/structures into floats it cannot be as smooth as other engines. Why they made it like this is beyond me...

EDIT: And of course thx to Methanhydrat for the explanation of his Quake 4 tool. I was wondering why there aren't similar tools for other id Tech4 games.

buvk commented 5 years ago

@dezo2 with the base120 dll, would it be better to cap framerate at 120 or 125fps with a g/freesync monitor?

dezo2 commented 5 years ago

Try 125 as it gives exactly 8ms frametime without remainder. In theory this should solve all the desync problems with the hack or any stutter without it.

buvk commented 5 years ago

Played for about an hour or so this morning with fps capped at 125, and with gsync on. It is glorious.

buvk commented 5 years ago

Well, found a crash when using the 120 base dll. When closing the crane in Alpha Labs Sector 3, the game crashes to console. Here is the error:

script/map_alphalabs3_crane.script : map_alphalabs3::crane_cmd_pickup script/map_alphalabs3_crane.script : map_alphalabs3::crane_cmd_pickup script/map_alphalabs3_crane.script : map_alphalabs3::crane_update_loop

----- Game Map Shutdown ----- idRenderWorld::FreeLightDef: handle 73 is NULL WARNING: idClipModel::FreeTraceModel: tried to free uncached trace model ******************** ERROR: script/map_alphalabs3_crane.script(214): Thread 'map_alphalabs3::crane_update_loop': Tried to bind an object to itself.
dezo2 commented 5 years ago

Sorry to hear that. I am afraid that this is the maximum we can squeeze out of this engine in its current state. I had no crashes so far, but that doesn't mean it will be 100% stable. At least we have found where and how to alter the hardcoded limits, so somebody with more skills and time than me can look into it.

KillPixelGames commented 4 years ago

@Methanhydrat Thank you for shedding some light on the issue! I do hope some day that high, smooth framerates come to Doom3. On that note, I'm installing Wolf:TNO and RAGE since I've discovered your idtech5 tweaker :D

@buvk I was unable to replicate this crash using the 120base.dll, has it only happened to you once?

buvk commented 4 years ago

I was able to replicate it several times. I played through the entire game and encountered about 6 places that crashed.

On Wed., Jul. 10, 2019, 10:57 a.m. KillPixelGames, notifications@github.com wrote:

@Methanhydrat https://github.com/Methanhydrat Thank you for shedding some light on the issue! I do hope some day that high, smooth framerates come to Doom3. On that note, I'm installing Wolf:TNO and RAGE since I've discovered your idtech5 tweaker :D

@buvk https://github.com/buvk I was unable to replicate this crash using the 120base.dll, has it only happened to you once?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dhewm/dhewm3/issues/230?email_source=notifications&email_token=AAULDR4TQ2SYYU77FV6QB63P6YPJHA5CNFSM4G3LTU6KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZUICUY#issuecomment-510165331, or mute the thread https://github.com/notifications/unsubscribe-auth/AAULDRYU7FR4MP73CTPFHLTP6YPJHANCNFSM4G3LTU6A .

Winghelm commented 4 years ago

I'm using redux mod, base120 DLL with framecap @ 125 FPS in NVCP on a G-Sync enabled display, everything works like a charm and looks pretty cool (@ DSR-4K resolution), haven't spotted any problems beyond occasional errors in Alpha Labs, but it's great that they don't happen again if I reload.

Sol1vaN commented 3 years ago

As far as I know, the rights to the Prey franchise were purchased by Bethesda. And since they have a new franchise using the Prey name, I highly doubt they are interested in re-releasing source code for a game, which they didn't even bother to keep digitally purchasable anymore.

Well, right now there's more dangerous because Bethesda was purchased by Microsoft on Mar 9, 2021: https://www.theverge.com/2021/3/9/22319124/microsoft-bethesda-acquisition-complete-finalized

So, I can't see clearly the future of releasing the source codes from Prey, Doom 4, etc.

Is very sad to see this :(

DanielGibson commented 3 years ago

If anything, Microsoft buying Bethesda makes source releases more likely.

I still think it's very unlikely that Prey will be open sourced.

Sol1vaN commented 3 years ago

If anything, Microsoft buying Bethesda makes source releases more likely.

I still think it's very unlikely that Prey will be open sourced.

Really? I've never seen a source code release from Microsoft, I mean: Halo 1, Halo 2, Gear of Wars, etc. Do you really still think that's possible Microsoft will release a source code ?

Well, Prey source code is hard to release, I don't know why, maybe the same reason from GtSoftware from Blood 1 (they lost the source code) jaja.

DanielGibson commented 3 years ago

They have been open source friendly in general in the last few years, open source for example .net core.

They also released the source code of Allegiance and MechCommander2.

Sol1vaN commented 3 years ago

They have been open source friendly in general in the last few years, open source for example .net core.

They also released the source code of Allegiance and MechCommander2.

Good to know this! I hope they continue with the same intention.

StonkD0 commented 1 year ago

Well, found a crash when using the 120 base dll. When closing the crane in Alpha Labs Sector 3, the game crashes to console. Here is the error:

script/map_alphalabs3_crane.script : map_alphalabs3::crane_cmd_pickup script/map_alphalabs3_crane.script : map_alphalabs3::crane_cmd_pickup script/map_alphalabs3_crane.script : map_alphalabs3::crane_update_loop ----- Game Map Shutdown ----- idRenderWorld::FreeLightDef: handle 73 is NULL WARNING: idClipModel::FreeTraceModel: tried to free uncached trace model

ERROR: script/map_alphalabs3_crane.script(214): Thread 'map_alphalabs3::crane_update_loop': Tried to bind an object to itself.

i know this thread is old but i really wanted to play doom in 120hz and fortunatly i could fix the crash in alpha labs 3 by editing the crane script file and changing "$crane.setFingerAngle( 20 )" under "close the claw and bind" from 20 to 5. Hopefully i could help someone with this post :)

Terepin commented 8 months ago

I am not that familiar with the sources, but I think Daniel should be able to create a cvar for this. Even if it should require restart of the engine, it will be better than hardcoded value. I didn't play with this since march, but I can share the 120Hz dll here for version 1.5.0, if you want to try it. It should work with any other frequency, but I tried only 120Hz as I have currently 120Hz monitor. Just make sure your autoexec.cfg is set as above. The dll is compiled using VS2017 and latest stable version 1.5.0 of sources.

base.zip

I just want to thank you for this! I managed to play the whole game from start to finish without a single crash. Unfortunately, this doesn't work in RoE. Does anyone knows how to make it work in the expansion as well?

ViperAcidZX commented 8 months ago

I am not that familiar with the sources, but I think Daniel should be able to create a cvar for this. Even if it should require restart of the engine, it will be better than hardcoded value. I didn't play with this since march, but I can share the 120Hz dll here for version 1.5.0, if you want to try it. It should work with any other frequency, but I tried only 120Hz as I have currently 120Hz monitor. Just make sure your autoexec.cfg is set as above. The dll is compiled using VS2017 and latest stable version 1.5.0 of sources. base.zip

I just want to thank you for this! I managed to play the whole game from start to finish without a single crash. Unfortunately, this doesn't work in RoE. Does anyone knows how to make it work in the expansion as well?

I'm hoping for support with the fan port of BFG Edition's The Lost Mission into Doom 3 (2004) as well.

IanHead commented 8 months ago

The original Doom games have a internal tic rate of 35 Hz and modern source ports provide the smooth movement by interpolating the positions of objects for each rendered frame between tics.

I wonder if this could be applied to Doom 3 as well, even if one just started with the basics like camera orientation I.e. with this basic implementation, characters and entities still might move around at 60 frames per second max, but you can turn your head as smoothly as your monitor and GPU can put out.

Without knowing a thing about how the code actually looks for Doom 3 this seems like a more elegant solution than changing the tic rate directly, and more future-proof as well for when we're running 480 Hz monitors or whatever in ten years' time.

IanHead commented 8 months ago

Further thoughts (feel free to hide this if I'm getting off-base):

GZDoom tackles this by applying the interpolation in p_tick.cpp and it runs code via r_interpolate.cpp on each object that is supposed to lerp between tics, to update their positions before rendering. This results in the tic rate staying the same, but with objects moving smoothly between those tics, and with the trade-off of 1 tic of latency.

The basic idea is a bit like this (I think)...

For each new tic:

Get ScreenRefreshRateHz e.g. 320 Get TicRateHz e.g. 60

Set LerpedPositionsElapsed = 0

Get ObjectPositionNextTic e.g. 10 Get ObjectPositionCurrentTic e.g. 5

Set PositionsBetweenTics = ScreenRefreshRateHz / TicRateHz e.g. 320 / 60 = 5.333333333 Set LerpedMovementPerRefresh = (ObjectPositionCurrentTic - ObjectPositionNextTic) / PositionsBetweenTics e.g. (10-5) / 5.333333333 = 0.9375

For new each frame draw:

Increment the object position by LerpedMovementPerRefresh and increment LerpedPositionsElapsed by 1, then send the resulting scene for rendering.

Repeat until LerpedPositionsElapsed >= PositionsBetweenTics.

I'm struggling a bit to see though where exactly such logic would fit in dhewm3... I'm guessing somewhere in framework/Common.cpp, in void idCommonLocal::Frame...?

Also, d3xp's game_local.cpp manipulates USERCMD_MSEC to do its slowmo stuff with the Artifact. So maybe some of the work is already done in there (void idGameLocal::ComputeSlowMsec()).