diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index bc66955fc..9b5c58abb 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5120,6 +5120,8 @@ static void HWR_ProjectSprite(mobj_t *thing) spriteyscale = FIXED_TO_FLOAT(interp.spriteyscale); // transform the origin point + if (thing->type == MT_OVERLAY) // Handle overlays + R_ThingOffsetOverlay(thing, &interp.x, &interp.y); tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx; tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy; @@ -5439,6 +5441,8 @@ static void HWR_ProjectSprite(mobj_t *thing) // calculate tz for tracer, same way it is calculated for this sprite // transform the origin point + if (thing->tracer->type == MT_OVERLAY) // Handle overlays + R_ThingOffsetOverlay(thing->tracer, &tracer_interp.x, &tracer_interp.y); tr_x = FIXED_TO_FLOAT(tracer_interp.x) - gl_viewx; tr_y = FIXED_TO_FLOAT(tracer_interp.y) - gl_viewy; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 87881be8d..5e6eb5d11 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1580,6 +1580,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #undef INTERPOLERATION_LIMIT #endif + if (spr->mobj->type == MT_OVERLAY) // Handle overlays + R_ThingOffsetOverlay(spr->mobj, &interp.x, &interp.y); //Hurdler: it seems there is still a small problem with mobj angle p.x = FIXED_TO_FLOAT(interp.x); p.y = FIXED_TO_FLOAT(interp.y)+md2->offset; diff --git a/src/p_mobj.c b/src/p_mobj.c index 686f08478..d2d0d8d72 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6764,15 +6764,33 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield) P_SetScale(thing, FixedMul(thing->target->scale, thing->target->player->shieldscale)); thing->destscale = thing->scale; + thing->old_scale = FixedMul(thing->target->old_scale, thing->target->player->shieldscale); + +#define NewMH(mobj) mobj->height // Ugly mobj-height and player-height defines, for the sake of prettier code +#define NewPH(player) P_GetPlayerHeight(player) +#define OldMH(mobj) FixedMul(mobj->height, FixedDiv(mobj->old_scale, mobj->scale)) +#define OldPH(player) FixedMul(player->height, player->mo->old_scale) P_UnsetThingPosition(thing); thing->x = thing->target->x; thing->y = thing->target->y; + thing->old_x = thing->target->old_x; + thing->old_y = thing->target->old_y; if (thing->eflags & MFE_VERTICALFLIP) - thing->z = thing->target->z + (thing->target->height - thing->height + FixedDiv(P_GetPlayerHeight(thing->target->player) - thing->target->height, 3*FRACUNIT)) - FixedMul(2*FRACUNIT, thing->target->scale); + { + thing->z = thing->target->z + NewMH(thing->target) - NewMH(thing) + ((NewPH(thing->target->player) - NewMH(thing->target)) / 3) - (thing->target->scale * 2); + thing->old_z = thing->target->old_z + OldMH(thing->target) - OldMH(thing) + ((OldPH(thing->target->player) - OldMH(thing->target)) / 3) - (thing->target->old_scale * 2); + } else - thing->z = thing->target->z - (FixedDiv(P_GetPlayerHeight(thing->target->player) - thing->target->height, 3*FRACUNIT)) + FixedMul(2*FRACUNIT, thing->target->scale); + { + thing->z = thing->target->z - ((NewPH(thing->target->player) - NewMH(thing->target)) / 3) + (thing->target->scale * 2); + thing->old_z = thing->target->old_z - ((OldPH(thing->target->player) - OldMH(thing->target)) / 3) + (thing->target->old_scale * 2); + } P_SetThingPosition(thing); P_CheckPosition(thing, thing->x, thing->y); +#undef NewMH +#undef NewPH +#undef OldMH +#undef OldPH if (P_MobjWasRemoved(thing)) return false; @@ -6838,10 +6856,11 @@ void P_RunOverlays(void) { // run overlays mobj_t *mo, *next = NULL; - fixed_t destx,desty,zoffs; for (mo = overlaycap; mo; mo = next) { + fixed_t zoffs; + I_Assert(!P_MobjWasRemoved(mo)); // grab next in chain, then unset the chain target @@ -6857,31 +6876,11 @@ void P_RunOverlays(void) continue; } - if (!splitscreen /*&& rendermode != render_soft*/) - { - angle_t viewingangle; - - if (players[displayplayer].awayviewtics && players[displayplayer].awayviewmobj != NULL && !P_MobjWasRemoved(players[displayplayer].awayviewmobj)) - viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); - else if (!camera.chase && players[displayplayer].mo) - viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); - else - viewingangle = R_PointToAngle2(mo->target->x, mo->target->y, camera.x, camera.y); - - if (!(mo->state->frame & FF_ANIMATE) && mo->state->var1) - viewingangle += ANGLE_180; - destx = mo->target->x + P_ReturnThrustX(mo->target, viewingangle, FixedMul(FRACUNIT/4, mo->scale)); - desty = mo->target->y + P_ReturnThrustY(mo->target, viewingangle, FixedMul(FRACUNIT/4, mo->scale)); - } - else - { - destx = mo->target->x; - desty = mo->target->y; - } - mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP); mo->scale = mo->destscale = mo->target->scale; + mo->old_scale = mo->target->old_scale; mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir; + mo->old_angle = (mo->target->player ? mo->target->player->old_drawangle : mo->target->old_angle) + mo->movedir; if (!(mo->state->frame & FF_ANIMATE)) zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale); @@ -6891,15 +6890,26 @@ void P_RunOverlays(void) zoffs = 0; P_UnsetThingPosition(mo); - mo->x = destx; - mo->y = desty; + mo->x = mo->target->x; + mo->y = mo->target->y; + mo->old_x = mo->target->old_x; + mo->old_y = mo->target->old_y; mo->radius = mo->target->radius; mo->height = mo->target->height; if (mo->eflags & MFE_VERTICALFLIP) - mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs; + { + mo->z = mo->target->z + mo->target->height - mo->height - zoffs; + if (mo->scale == mo->old_scale) + mo->old_z = mo->target->old_z + mo->target->height - mo->height - zoffs; + else // Interpolate height scale changes - mo and mo->target have the same scales here, so don't interpolate them individually + mo->old_z = mo->target->old_z + FixedMul(mo->target->height - mo->height, FixedDiv(mo->old_scale, mo->scale)) - zoffs; + } else - mo->z = mo->target->z + zoffs; - if (mo->state->var1) + { + mo->z = mo->target->z + zoffs; + mo->old_z = mo->target->old_z + zoffs; + } + if (!(mo->state->frame & FF_ANIMATE) && mo->state->var1) P_SetUnderlayPosition(mo); else P_SetThingPosition(mo); diff --git a/src/r_things.c b/src/r_things.c index 6e334990b..c1c2de875 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1649,6 +1649,8 @@ static void R_ProjectSprite(mobj_t *thing) this_scale = interp.scale; // transform the origin point + if (thing->type == MT_OVERLAY) // Handle overlays + R_ThingOffsetOverlay(thing, &interp.x, &interp.y); tr_x = interp.x - viewx; tr_y = interp.y - viewy; @@ -1987,6 +1989,8 @@ static void R_ProjectSprite(mobj_t *thing) R_InterpolateMobjState(thing, FRACUNIT, &tracer_interp); } + if (thing->type == MT_OVERLAY) // Handle overlays + R_ThingOffsetOverlay(thing, &tracer_interp.x, &tracer_interp.y); tr_x = (tracer_interp.x + sort_x) - viewx; tr_y = (tracer_interp.y + sort_y) - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); @@ -3521,6 +3525,50 @@ boolean R_ThingIsFullDark(mobj_t *thing) return ((thing->frame & FF_BRIGHTMASK) == FF_FULLDARK || (thing->renderflags & RF_BRIGHTMASK) == RF_FULLDARK); } +// Offsets MT_OVERLAY towards the camera at render-time - Works in splitscreen! +// The &x and &y arguments should be pre-interpolated, and will be modified +void R_ThingOffsetOverlay(mobj_t *thing, fixed_t *x, fixed_t *y) +{ + mobj_t *mobj = thing; + INT16 offset = 0; // Offset towards or away from the camera, and how much + fixed_t offsetscale = thing->scale; // Occasionally needs to be interpolated + angle_t viewingangle; + UINT8 looplimit = 255; // Prevent infinite loops - A chain of 255 connected overlays is enough for any sane use case + +#ifdef PARANOIA + if (P_MobjWasRemoved(mobj) || !x || !y) + I_Error("R_ThingOffsetOverlay: thing, x, or y is invalid"); +#endif + + do // Get the overlay's offset + { + // Does the overlay use FF_ANIMATE? If not, if var1 is non-zero, it's an underlay instead of an overlay + if (!(mobj->state->frame & FF_ANIMATE) && mobj->state->var1) + offset += 1; // Underlay below the target, away from the camera + else + offset -= 1; // Overlay on top of the target, towards the camera + + looplimit -= 1; + mobj = mobj->target; + } while (!P_MobjWasRemoved(mobj) && mobj->type == MT_OVERLAY && looplimit > 0); // Handle overlays following other overlays + + // Does the offset scale need to be interpolated? + if (thing->scale != thing->old_scale && R_UsingFrameInterpolation() && !paused) + { + interpmobjstate_t interp = {0}; + R_InterpolateMobjState(thing, rendertimefrac, &interp); + offsetscale = interp.scale; + } + + + // Get the angle from the camera to the X and Y coordinates + viewingangle = R_PointToAngle(*x, *y); + + // Finally, offset the X and Y coordinates towards or away from the camera + *x += P_ReturnThrustX(thing, viewingangle, FixedMul(offset * (FRACUNIT/4), offsetscale)); + *y += P_ReturnThrustY(thing, viewingangle, FixedMul(offset * (FRACUNIT/4), offsetscale)); +} + // // R_DrawMasked // diff --git a/src/r_things.h b/src/r_things.h index e11005363..9988d81bc 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -88,6 +88,8 @@ boolean R_ThingIsFullBright (mobj_t *thing); boolean R_ThingIsSemiBright (mobj_t *thing); boolean R_ThingIsFullDark (mobj_t *thing); +void R_ThingOffsetOverlay (mobj_t *thing, fixed_t *outx, fixed_t *outy); + // -------------- // MASKED DRAWING // --------------