diff --git a/src/p_map.c b/src/p_map.c index 1f02123d5..fe67ad49c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -103,7 +103,7 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorrover = tmfloorrover; thing->ceilingrover = tmceilingrover; - P_ResetInterpolationState(thing); + P_ResetMobjInterpolationState(thing); return true; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 57af599cf..6b413bcd5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -42,6 +42,77 @@ actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; +static mobj_t **interpolated_mobjs = NULL; +static size_t interpolated_mobjs_len = 0; +static size_t interpolated_mobjs_capacity = 0; + +// NOTE: This will NOT check that the mobj has already been added, for perf +// reasons. +static void AddInterpolatedMobj(mobj_t *mobj) +{ + if (interpolated_mobjs_len >= interpolated_mobjs_capacity) + { + if (interpolated_mobjs_capacity == 0) + { + interpolated_mobjs_capacity = 256; + } + else + { + interpolated_mobjs_capacity *= 2; + } + + interpolated_mobjs = Z_ReallocAlign( + interpolated_mobjs, + sizeof(mobj_t *) * interpolated_mobjs_capacity, + PU_LEVEL, + NULL, + 64 + ); + } + + interpolated_mobjs[interpolated_mobjs_len] = mobj; + interpolated_mobjs_len += 1; +} + +static void RemoveInterpolatedMobj(mobj_t *mobj) +{ + size_t i; + + if (interpolated_mobjs_len == 0) return; + + for (i = 0; i < interpolated_mobjs_len - 1; i++) + { + if (interpolated_mobjs[i] == mobj) + { + interpolated_mobjs[i] = interpolated_mobjs[ + interpolated_mobjs_len - 1 + ]; + interpolated_mobjs_len -= 1; + return; + } + } +} + +void P_InitMobjInterpolators(void) +{ + // apparently it's not acceptable to free something already unallocated + // Z_Free(interpolated_mobjs); + interpolated_mobjs = NULL; + interpolated_mobjs_len = 0; + interpolated_mobjs_capacity = 0; +} + +void P_UpdateMobjInterpolators(void) +{ + size_t i; + for (i = 0; i < interpolated_mobjs_len; i++) + { + mobj_t *mobj = interpolated_mobjs[i]; + if (!P_MobjWasRemoved(mobj)) + P_ResetMobjInterpolationState(mobj); + } +} + void P_InitCachedActions(void) { actioncachehead.prev = actioncachehead.next = &actioncachehead; @@ -893,11 +964,11 @@ void P_EmeraldManager(void) } // -// P_ResetInterpolationState +// P_ResetMobjInterpolationState // // Reset the rendering interpolation state of the mobj. // -void P_ResetInterpolationState(mobj_t *mobj) +void P_ResetMobjInterpolationState(mobj_t *mobj) { mobj->old_x = mobj->x; mobj->old_y = mobj->y; @@ -913,11 +984,11 @@ void P_ResetInterpolationState(mobj_t *mobj) } // -// P_ResetPrecipitationInterpolationState +// P_ResetPrecipitationMobjInterpolationState // // Reset the rendering interpolation state of the precipmobj. // -void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj) +void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) { mobj->old_x = mobj->x; mobj->old_y = mobj->y; @@ -4059,7 +4130,7 @@ void P_NullPrecipThinker(precipmobj_t *mobj) void P_SnowThinker(precipmobj_t *mobj) { - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4067,13 +4138,13 @@ void P_SnowThinker(precipmobj_t *mobj) if ((mobj->z += mobj->momz) <= mobj->floorz) { mobj->z = mobj->ceilingz; - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); } } void P_RainThinker(precipmobj_t *mobj) { - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4094,7 +4165,7 @@ void P_RainThinker(precipmobj_t *mobj) return; mobj->z = mobj->ceilingz; - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); P_SetPrecipMobjState(mobj, S_RAIN1); return; @@ -10072,8 +10143,6 @@ void P_MobjThinker(mobj_t *mobj) I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - P_ResetInterpolationState(mobj); - if (mobj->flags & MF_NOTHINK) return; @@ -10939,7 +11008,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP)) P_CheckGravity(mobj, false); - P_ResetInterpolationState(mobj); + AddInterpolatedMobj(mobj); return mobj; } @@ -10988,7 +11057,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype || mobj->subsector->sector->floorpic == skyflatnum) mobj->precipflags |= PCF_PIT; - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); return mobj; } @@ -11109,6 +11178,8 @@ void P_RemoveMobj(mobj_t *mobj) memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); #endif + RemoveInterpolatedMobj(mobj); + // free block if (!mobj->thinker.next) { // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through! diff --git a/src/p_mobj.h b/src/p_mobj.h index 371dc49dc..455954ca3 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -503,8 +503,12 @@ void P_RingZMovement(mobj_t *mo); boolean P_SceneryZMovement(mobj_t *mo); void P_PlayerZMovement(mobj_t *mo); void P_EmeraldManager(void); -void P_ResetInterpolationState(mobj_t *mobj); -void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj); + +// Initialize internal mobj interpolator list (e.g. during level loading) +void P_InitMobjInterpolators(void); +void P_UpdateMobjInterpolators(void); +void P_ResetMobjInterpolationState(mobj_t *mobj); +void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj); extern INT32 modulothing; diff --git a/src/p_setup.c b/src/p_setup.c index 65e7b5886..063c1b975 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4376,6 +4376,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_InitializeLevelInterpolators(); P_InitThinkers(); + P_InitMobjInterpolators(); P_InitCachedActions(); if (!fromnetsave && savedata.lives > 0) diff --git a/src/p_tick.c b/src/p_tick.c index e244de1c6..7773dec55 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -642,6 +642,8 @@ void P_Ticker(boolean run) if (run) { + P_UpdateMobjInterpolators(); + if (demorecording) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); if (demoplayback)