From d98dd3e2dd3b101082cb6162ecd1678ccc6be524 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 12 Sep 2025 11:50:24 -0400 Subject: [PATCH] Add variables that bake 3D offsets into a sprite https://git.do.srb2.org/KartKrew/RingRacers/-/merge_requests/63 --- src/acs/call-funcs.cpp | 12 +++++ src/deh_tables.c | 1 + src/hardware/hw_main.c | 37 +++++++++++++- src/hardware/hw_md2.c | 107 +++++++++++++++++++++++++++++++++++++++-- src/k_kart.c | 7 +++ src/lua_mobjlib.c | 48 ++++++++++++++++++ src/p_local.h | 1 + src/p_mobj.c | 13 +++++ src/p_mobj.h | 2 + src/p_saveg.c | 28 ++++++++++- src/p_user.c | 9 ++++ src/r_patch.h | 5 ++ src/r_patchrotation.c | 96 +++++++++++++++++++++++++++++++++++- src/r_things.cpp | 39 ++++++++++++++- src/r_things.h | 2 + 15 files changed, 398 insertions(+), 9 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 417346faf..01e3f34c5 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -4310,6 +4310,12 @@ enum THING_PROP_HNEXT, THING_PROP_HPREV, THING_PROP_ITNEXT, + THING_PROP_BAKEDXOFFSET, + THING_PROP_BAKEDYOFFSET, + THING_PROP_BAKEDZOFFSET, + THING_PROP_BAKEDXPIVOT, + THING_PROP_BAKEDYPIVOT, + THING_PROP_BAKEDZPIVOT, THING_PROP__MAX }; @@ -4479,6 +4485,12 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A PROP_MOBJ(THING_PROP_HNEXT, hnext) PROP_MOBJ(THING_PROP_HPREV, hprev) PROP_MOBJ(THING_PROP_ITNEXT, itnext) + PROP_INT(THING_PROP_BAKEDXOFFSET, bakexoff) + PROP_INT(THING_PROP_BAKEDYOFFSET, bakeyoff) + PROP_INT(THING_PROP_BAKEDZOFFSET, bakezoff) + PROP_INT(THING_PROP_BAKEDXPIVOT, bakexpiv) + PROP_INT(THING_PROP_BAKEDYPIVOT, bakeypiv) + PROP_INT(THING_PROP_BAKEDZPIVOT, bakezpiv) default: { CONS_Alert(CONS_WARNING, "GetThingProperty type %d out of range (expected 0 - %d).\n", property, THING_PROP__MAX-1); diff --git a/src/deh_tables.c b/src/deh_tables.c index c0701085f..73d87d268 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1087,6 +1087,7 @@ struct int_const_s const INT_CONST[] = { {"OV_DONT3DOFFSET", OV_DONT3DOFFSET}, {"OV_DONTXYSCALE", OV_DONTXYSCALE}, {"OV_DONTROLL", OV_DONTROLL}, + {"OV_DONTBAKEOFFSET", OV_DONTBAKEOFFSET}, // Player state (playerstate_t) {"PST_LIVE",PST_LIVE}, // Playing or camping. diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 25fc10243..e76545f4e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4712,6 +4712,7 @@ static void HWR_ProjectSprite(mobj_t *thing) patch_t *rotsprite = NULL; INT32 rollangle = 0; angle_t spriterotangle = 0; + vector2_t visoffs; #endif // uncapped/interpolation @@ -4877,12 +4878,28 @@ static void HWR_ProjectSprite(mobj_t *thing) flip = 0; } } + + // initialize and rotate pitch/roll vector + visoffs.x = 0; + visoffs.y = 0; + + const fixed_t visoffymul = (vflip ? -FRACUNIT : FRACUNIT); + + if (R_ThingIsUsingBakedOffsets(thing)) + { + R_RotateSpriteOffsetsByPitchRoll(thing, + vflip, hflip, &visoffs); + } #endif if (thing->renderflags & RF_ABSOLUTEOFFSETS) { spr_offset = interp.spritexoffset; +#ifdef ROTSPRITE + spr_topoffset = (interp.spriteyoffset + FixedDiv((visoffs.y * visoffymul), mapobjectscale)); +#else spr_topoffset = interp.spriteyoffset; +#endif } else { @@ -4892,7 +4909,12 @@ static void HWR_ProjectSprite(mobj_t *thing) flipoffset = -1; spr_offset += interp.spritexoffset * flipoffset; +#ifdef ROTSPRITE + spr_topoffset += (interp.spriteyoffset + FixedDiv((visoffs.y * visoffymul), + mapobjectscale)) * flipoffset; +#else spr_topoffset += interp.spriteyoffset * flipoffset; +#endif } if (papersprite) @@ -4943,17 +4965,28 @@ static void HWR_ProjectSprite(mobj_t *thing) } else { +#ifdef ROTSPRITE + if (visoffs.x) + { + visoffs.x = (FixedDiv((visoffs.x * FRACUNIT), mapobjectscale)); + } +#endif if (flip) { - x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); +#ifdef ROTSPRITE + spr_offset -= visoffs.x; +#endif + x1 = (FIXED_TO_FLOAT((spr_width - spr_offset)) * this_xscale); x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); } else { +#ifdef ROTSPRITE + spr_offset += visoffs.x; +#endif x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); } - // test if too close /* if (papersprite) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 91c6c9d27..2c55669f6 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1685,18 +1685,27 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.angley = FIXED_TO_FLOAT(anglef); } + angle_t pitchR, rollR, fixedAngY; + // drift frame unrotation hack... if (modeltype == MODELTYPE_OLDPLAYER && (spr2 == SPR2_DRRN || spr2 == SPR2_DRLN)) p.angley += spr2 == SPR2_DRRN ? 45.0f : -45.0f; + pitchR = 0; + rollR = 0; + fixedAngY = 0; + { fixed_t anglef = AngleFixed(R_SpriteRotationAngle(spr->mobj, NULL, &interp)); p.rollangle = 0.0f; + // make fixedAngY a disguised fixed_t first + fixedAngY = FLOAT_TO_FIXED(p.angley); + if (anglef) { - fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know + fixed_t camAngleDiff = AngleFixed(viewangle) - (fixed_t)(fixedAngY); // dumb reconversion back, I know anglef *= flip ? -1 : 1; // Adjust for flipping @@ -1708,9 +1717,19 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2); // rotation axes relative to camera - p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); - p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); + pitchR = FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT); + rollR = FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT); + + p.rollx = FIXED_TO_FLOAT((fixed_t)rollR); + p.rollz = FIXED_TO_FLOAT((fixed_t)pitchR); + + // convert to angles + pitchR = FixedAngle((fixed_t)pitchR); + rollR = FixedAngle((fixed_t)rollR); } + + // make this a proper angle now + fixedAngY = FixedAngle(fixedAngY); } p.anglez = FIXED_TO_FLOAT(AngleFixed(R_InterpolateAngle(spr->mobj->old_pitch, spr->mobj->pitch))); @@ -1744,6 +1763,88 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.y += ox * gl_viewcos; p.z += oy; + if (R_ThingIsUsingBakedOffsets(spr->mobj)) + { + // visoffset stuff + float xx, xy, yx, yy; + float zx, zy, zz; + float xpiv, ypiv, zpiv; + fixed_t zh; + fixed_t xoffs, yoffs; + + // xoffs = (cos(xoff) + sin(yoff)) + xoffs = + FixedMul(spr->mobj->bakeyoff, -FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)) + + FixedMul(spr->mobj->bakexoff, FINESINE(fixedAngY >> ANGLETOFINESHIFT)); + + // yoffs = (-sin(xoff) + cos(yoff)) + yoffs = + FixedMul(spr->mobj->bakeyoff, -FINESINE(fixedAngY >> ANGLETOFINESHIFT)) + + FixedMul(spr->mobj->bakexoff, FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)); + + const fixed_t hflipmul = hflip ? -FRACUNIT : FRACUNIT; + + xpiv = FIXED_TO_FLOAT( + FixedMul( + FixedMul(spr->mobj->bakeypiv, + -FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)) + + FixedMul(spr->mobj->bakexpiv, + FINESINE(fixedAngY >> ANGLETOFINESHIFT)), + hflipmul)); + ypiv = FIXED_TO_FLOAT( + FixedMul( + FixedMul(spr->mobj->bakeypiv, + -FINESINE(fixedAngY >> ANGLETOFINESHIFT)) + + FixedMul(spr->mobj->bakexpiv, + FINECOSINE(fixedAngY >> ANGLETOFINESHIFT)), + hflipmul)); + zpiv = FIXED_TO_FLOAT(spr->mobj->bakezpiv * ((flip) ? -1 : 1)); + + pitchR = ((pitchR + spr->mobj->pitch) * ((flip) ? -1 : 1)); + rollR = ((rollR + spr->mobj->roll) * ((flip) ? -1 : 1)); + + // x offset + xx = FIXED_TO_FLOAT(FixedMul(FixedMul( + FixedMul(xoffs,spr->mobj->spritexscale), + hflipmul), + FINECOSINE(pitchR >> ANGLETOFINESHIFT) + )); + xy = FIXED_TO_FLOAT(FixedMul(FixedMul( + FixedMul(xoffs,spr->mobj->spritexscale), + hflipmul), + -FINESINE(pitchR >> ANGLETOFINESHIFT) + )); + + // y offset + yx = FIXED_TO_FLOAT(FixedMul(FixedMul( + FixedMul(yoffs,spr->mobj->spritexscale), + hflipmul), + FINECOSINE(rollR >> ANGLETOFINESHIFT) + )); + + yy = FIXED_TO_FLOAT(FixedMul(FixedMul( + FixedMul(yoffs,spr->mobj->spritexscale), + hflipmul), + -FINESINE(rollR >> ANGLETOFINESHIFT) + )); + + // z offset + zh = FixedMul(FixedMul(spr->mobj->bakezoff,spr->mobj->spriteyscale), + FINECOSINE(rollR >> ANGLETOFINESHIFT)); + + zz = FIXED_TO_FLOAT(FixedMul(zh, + FINECOSINE(pitchR >> ANGLETOFINESHIFT))); + zx = FIXED_TO_FLOAT(FixedMul(zh, + FINESINE(pitchR >> ANGLETOFINESHIFT))); + zy = FIXED_TO_FLOAT(FixedMul(zh, + FINESINE(rollR >> ANGLETOFINESHIFT))); + + // do these namings even make sense at this point? + p.x += xx + zx + xpiv; + p.z += (xy + yy + zz * (flip ? -1 : 1)) + zpiv; + p.y += yx + zy + ypiv; + } + HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf); } } diff --git a/src/k_kart.c b/src/k_kart.c index 1a2b3fcc1..5e8876980 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6477,6 +6477,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->spritexoffset = 0; player->mo->spriteyoffset = 0; + player->mo->bakexoff = 0; + player->mo->bakeyoff = 0; + player->mo->bakezoff = 0; + player->mo->bakexpiv = 0; + player->mo->bakeypiv = 0; + player->mo->bakezpiv = 0; + player->cameraOffset = 0; if (player->loop.radius) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 233534da8..0eaeb2bc2 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -103,6 +103,12 @@ enum mobj_e { mobj_sprxoff, mobj_spryoff, mobj_sprzoff, + mobj_bakexoff, + mobj_bakeyoff, + mobj_bakezoff, + mobj_bakexpiv, + mobj_bakeypiv, + mobj_bakezpiv, mobj_terrain, mobj_dispoffset, mobj_tid, @@ -192,6 +198,12 @@ static const char *const mobj_opt[] = { "sprxoff", "spryoff", "sprzoff", + "bakexoff", + "bakeyoff", + "bakezoff", + "bakexpiv", + "bakeypiv", + "bakezpiv", "terrain", "dispoffset", "tid", @@ -542,6 +554,24 @@ static int mobj_get(lua_State *L) case mobj_sprzoff: lua_pushfixed(L, mo->sprzoff); break; + case mobj_bakexoff: + lua_pushfixed(L, mo->bakexoff); + break; + case mobj_bakeyoff: + lua_pushfixed(L, mo->bakeyoff); + break; + case mobj_bakezoff: + lua_pushfixed(L, mo->bakezoff); + break; + case mobj_bakexpiv: + lua_pushfixed(L, mo->bakexpiv); + break; + case mobj_bakeypiv: + lua_pushfixed(L, mo->bakeypiv); + break; + case mobj_bakezpiv: + lua_pushfixed(L, mo->bakezpiv); + break; case mobj_terrain: LUA_PushUserdata(L, mo->terrain, META_TERRAIN); break; @@ -982,6 +1012,24 @@ static int mobj_set(lua_State *L) case mobj_sprzoff: mo->sprzoff = luaL_checkfixed(L, 3); break; + case mobj_bakexoff: + mo->bakexoff = luaL_checkfixed(L, 3); + break; + case mobj_bakeyoff: + mo->bakeyoff = luaL_checkfixed(L, 3); + break; + case mobj_bakezoff: + mo->bakezoff = luaL_checkfixed(L, 3); + break; + case mobj_bakexpiv: + mo->bakexpiv = luaL_checkfixed(L, 3); + break; + case mobj_bakeypiv: + mo->bakeypiv = luaL_checkfixed(L, 3); + break; + case mobj_bakezpiv: + mo->bakezpiv = luaL_checkfixed(L, 3); + break; case mobj_terrain: mo->terrain = *((terrain_t **)luaL_checkudata(L, 3, META_TERRAIN)); break; diff --git a/src/p_local.h b/src/p_local.h index 109d87c2f..de6c9a980 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -321,6 +321,7 @@ void P_RunOverlays(void); #define OV_DONT3DOFFSET 1<<1 #define OV_DONTXYSCALE 1<<2 #define OV_DONTROLL 1<<3 +#define OV_DONTBAKEOFFSET 1<<4 void P_HandleMinecartSegments(mobj_t *mobj); void P_MobjThinker(mobj_t *mobj); diff --git a/src/p_mobj.c b/src/p_mobj.c index c3dc90558..f2a90c10f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6740,6 +6740,19 @@ void P_RunOverlays(void) mo->roll = mo->target->roll; } + if (!(mo->threshold & OV_DONTBAKEOFFSET)) + { + // offsets + mo->bakexoff = mo->target->bakexoff; + mo->bakeyoff = mo->target->bakeyoff; + mo->bakezoff = mo->target->bakezoff; + // pivots + mo->bakexpiv = mo->target->bakexpiv; + mo->bakeypiv = mo->target->bakeypiv; + mo->bakezpiv = mo->target->bakezpiv; + } + + if ((mo->flags & MF_DONTENCOREMAP) != (mo->target->flags & MF_DONTENCOREMAP)) mo->flags ^= MF_DONTENCOREMAP; diff --git a/src/p_mobj.h b/src/p_mobj.h index c042a6994..c514eb966 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -421,6 +421,8 @@ struct mobj_t UINT8 shadowcolor; // Palette index to use for rendering the shadow fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision + fixed_t bakexoff, bakeyoff, bakezoff; // BAKED sprite offsets. Simulates visuals in real space, and rotates along the object's sprite + fixed_t bakexpiv, bakeypiv, bakezpiv; // Pivot points for baked offsets. These are *not* rotated with a sprite terrain_t *terrain; // Terrain definition of the floor this object last hit. NULL when in the air. mobj_t *terrainOverlay; // Overlay sprite object for terrain diff --git a/src/p_saveg.c b/src/p_saveg.c index 579dc798a..6b71e40fd 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2071,7 +2071,7 @@ typedef enum { MD3_GRAVITY = 1, MD3_MISCCAP = 1<<1, - + MD3_BAKEDOFFSET = 1<<2, } mobj_diff3_t; typedef enum @@ -2383,6 +2383,9 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 diff3 |= MD3_GRAVITY; if (mobj == misccap) diff3 |= MD3_MISCCAP; + if (mobj->bakexoff || mobj->bakeyoff || mobj->bakezoff || mobj->bakexpiv || + mobj->bakeypiv || mobj->bakezpiv) + diff3 |= MD3_BAKEDOFFSET; if (diff3 != 0) diff2 |= MD2_MORE; @@ -2658,6 +2661,15 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 { WRITEFIXED(save->p, mobj->gravity); } + if (diff3 & MD3_BAKEDOFFSET) + { + WRITEFIXED(save->p, mobj->bakexoff); + WRITEFIXED(save->p, mobj->bakeyoff); + WRITEFIXED(save->p, mobj->bakezoff); + WRITEFIXED(save->p, mobj->bakexpiv); + WRITEFIXED(save->p, mobj->bakeypiv); + WRITEFIXED(save->p, mobj->bakezpiv); + } WRITEUINT32(save->p, mobj->mobjnum); } @@ -3914,6 +3926,20 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) { mobj->gravity = FRACUNIT; } + if (diff3 & MD3_BAKEDOFFSET) + { + mobj->bakexoff = READFIXED(save->p); + mobj->bakeyoff = READFIXED(save->p); + mobj->bakezoff = READFIXED(save->p); + mobj->bakexpiv = READFIXED(save->p); + mobj->bakeypiv = READFIXED(save->p); + mobj->bakezpiv = READFIXED(save->p); + } + else + { + mobj->bakexoff = mobj->bakeyoff = mobj->bakezoff = 0; + mobj->bakexpiv = mobj->bakeypiv = mobj->bakezpiv = 0; + } // Reset some non-synch values mobj->sloperoll = 0; diff --git a/src/p_user.c b/src/p_user.c index e78d6cb69..eb24e8f75 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1219,6 +1219,15 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->sprxoff = mobj->sprxoff; ghost->spryoff = mobj->spryoff; ghost->sprzoff = mobj->sprzoff; + + // baked offsets + ghost->bakexoff = mobj->bakexoff; + ghost->bakeyoff = mobj->bakeyoff; + ghost->bakezoff = mobj->bakezoff; + ghost->bakexpiv = mobj->bakexpiv; + ghost->bakeypiv = mobj->bakeypiv; + ghost->bakezpiv = mobj->bakezpiv; + ghost->rollangle = mobj->rollangle; ghost->spritexscale = mobj->spritexscale; diff --git a/src/r_patch.h b/src/r_patch.h index 84718c253..89f3c27c2 100644 --- a/src/r_patch.h +++ b/src/r_patch.h @@ -50,6 +50,11 @@ boolean R_IsOverlayingInvinciblePlayer(mobj_t* mobj); angle_t R_GetPitchRollAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstate_t *interp); angle_t R_ModelRotationAngle(mobj_t *mobj, player_t *viewPlayer); angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstate_t *interp); +vector2_t* R_RotateSpriteOffsetsByPitchRoll( + mobj_t* mobj, + boolean vflip, + boolean hflip, + vector2_t* out); #endif #ifdef __cplusplus diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index b83797537..dcd74088a 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -26,8 +26,8 @@ fixed_t rollsinang[ROTANGLES]; angle_t R_GetPitchRollAngle(mobj_t *mobj, player_t *viewPlayer, interpmobjstate_t *interp) { angle_t viewingAngle, rollOrPitch; - angle_t sloperoll = interp->slopepitch; - angle_t slopepitch = interp->sloperoll; + angle_t sloperoll = !interp ? 0 : interp->slopepitch; + angle_t slopepitch = !interp ? 0 : interp->sloperoll; fixed_t pitchMul, rollMul; if (mobj->player) @@ -131,6 +131,98 @@ INT32 R_GetRollAngle(angle_t rollangle) return ra; } +#define VISROTMUL (ANG1 * ROTANGDIFF) + +vector2_t* R_RotateSpriteOffsetsByPitchRoll( + mobj_t* mobj, + boolean vflip, + boolean hflip, + vector2_t* out) +{ + fixed_t rotcos, rotsin, finx, finy; + vector2_t xvec, yvec; + + // input offsets + fixed_t xoffs, yoffs, xpiv, ypiv; + + // final offsets + INT16 visx, visy, visz; + INT16 vxpiv, vypiv; + + // visual rotation + angle_t visrollang; + + // camera angle + angle_t viewingAngle = R_PointToAngle(mobj->x, mobj->y); + + // rotate ourselves entirely by the sprite's own rotation angle + angle_t visrot = R_SpriteRotationAngle(mobj, NULL, NULL); + + // xoffs = (-cos(xoff) + sin(yoff)) + xoffs = + FixedMul(mobj->bakeyoff, -FINECOSINE(mobj->angle >> ANGLETOFINESHIFT)) + + FixedMul(mobj->bakexoff, FINESINE(mobj->angle >> ANGLETOFINESHIFT)); + xpiv = + FixedMul(mobj->bakeypiv, -FINECOSINE(mobj->angle >> ANGLETOFINESHIFT)) + + FixedMul(mobj->bakexpiv, FINESINE(mobj->angle >> ANGLETOFINESHIFT)); + + // yoffs = (-sin(yoff) + cos(xoff)) + yoffs = + FixedMul(mobj->bakeyoff, -FINESINE(mobj->angle >> ANGLETOFINESHIFT)) + + FixedMul(mobj->bakexoff, FINECOSINE(mobj->angle >> ANGLETOFINESHIFT)); + ypiv = + FixedMul(mobj->bakeypiv, -FINESINE(mobj->angle >> ANGLETOFINESHIFT)) + + FixedMul(mobj->bakexpiv, FINECOSINE(mobj->angle >> ANGLETOFINESHIFT)); + + visrollang = (R_GetRollAngle(visrot) * VISROTMUL) * (hflip ? -1 : 1); + + // get pitch and roll multipliers, mainly used to align the + // viewpoint with the camera + fixed_t pitchMul = -FINESINE(viewingAngle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(viewingAngle >> ANGLETOFINESHIFT); + + // get visual positions + visz = visy = visx = 0; + visz = (INT16)(-(mobj->bakezoff / FRACUNIT)); + visx = (INT16)(FixedMul((yoffs / FRACUNIT), rollMul)); + visy = (INT16)(FixedMul((xoffs / FRACUNIT), pitchMul)); + + vxpiv = (INT16)(FixedMul((ypiv / FRACUNIT), rollMul)); + vypiv = (INT16)(FixedMul((xpiv / FRACUNIT), pitchMul)); + + // rotate by rollangle + finx = (visx + visy); + finy = -visz; + + rotcos = FINECOSINE(visrollang >> ANGLETOFINESHIFT); + rotsin = FINESINE(visrollang >> ANGLETOFINESHIFT); + + xvec.x = FixedMul(finx, rotcos); + xvec.y = FixedMul(finx, -rotsin); + + yvec.x = FixedMul(finy, rotsin); + yvec.y = FixedMul(finy, -rotcos); + + // set finalized offsets + out->x = (fixed_t)(xvec.x + yvec.x + vxpiv + vypiv); + out->y = (fixed_t)(xvec.y - yvec.y) + (mobj->bakezpiv / FRACUNIT); + + // flip based on vflip and hflip + // flip the view angle if we're horizontally flipped + if (hflip) + { + out->x *= -1; + } + + if (vflip) + { + out->y *= -1; + } + return out; +} + +#undef VISROTMUL + patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip) { rotsprite_t *rotsprite = patch->rotated; diff --git a/src/r_things.cpp b/src/r_things.cpp index 73cea1693..fcd0f4c7a 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -854,6 +854,12 @@ boolean R_ThingIsFlashing(mobj_t *thing) baddie_is_flashing(thing); } +boolean R_ThingIsUsingBakedOffsets(mobj_t* thing) +{ + return ((thing->bakexoff) || (thing->bakeyoff) || (thing->bakezoff) || + (thing->bakexpiv) || (thing->bakeypiv) || (thing->bakezpiv)); +} + UINT8 *R_GetSpriteTranslation(vissprite_t *vis) { if (!(vis->cut & SC_PRECIP) && @@ -1734,6 +1740,7 @@ static void R_ProjectSprite(mobj_t *thing) patch_t *rotsprite = NULL; INT32 rollangle = 0; angle_t spriterotangle = 0; + vector2_t visoffs; #endif // uncapped/interpolation @@ -1923,10 +1930,28 @@ static void R_ProjectSprite(mobj_t *thing) if (spritexscale < 1 || spriteyscale < 1) return; +#ifdef ROTSPRITE + // initialize and rotate pitch/roll vector + visoffs.x = 0; + visoffs.y = 0; + + const fixed_t visoffymul = (vflip ? -FRACUNIT : FRACUNIT); + + if (R_ThingIsUsingBakedOffsets(thing)) + { + R_RotateSpriteOffsetsByPitchRoll(thing, + vflip, hflip, &visoffs); + } +#endif + if (thing->renderflags & RF_ABSOLUTEOFFSETS) { spr_offset = interp.spritexoffset; +#ifdef ROTSPRITE + spr_topoffset = (interp.spriteyoffset + FixedDiv((visoffs.y * visoffymul), mapobjectscale)); +#else spr_topoffset = interp.spriteyoffset; +#endif } else { @@ -1935,8 +1960,13 @@ static void R_ProjectSprite(mobj_t *thing) if ((thing->renderflags & RF_FLIPOFFSETS) && flip) flipoffset = -1; - spr_offset += interp.spritexoffset * flipoffset; + spr_offset += (interp.spritexoffset) * flipoffset; +#ifdef ROTSPRITE + spr_topoffset += (interp.spriteyoffset + FixedDiv((visoffs.y * visoffymul), + mapobjectscale)) * flipoffset; +#else spr_topoffset += interp.spriteyoffset * flipoffset; +#endif } if (flip) @@ -1944,6 +1974,13 @@ static void R_ProjectSprite(mobj_t *thing) else offset = -spr_offset; +#ifdef ROTSPRITE + if (visoffs.x) + { + offset -= FixedDiv((visoffs.x * FRACUNIT), mapobjectscale); + } +#endif + offset = FixedMul(offset, FixedMul(spritexscale, this_scale)); offset2 = FixedMul(spr_width, FixedMul(spritexscale, this_scale)); diff --git a/src/r_things.h b/src/r_things.h index d99e264cf..c85b2c63d 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -95,6 +95,8 @@ boolean R_ThingIsFullDark (mobj_t *thing); boolean R_ThingIsFlashing(mobj_t *thing); +boolean R_ThingIsUsingBakedOffsets(mobj_t *thing); + INT32 R_ThingLightLevel(mobj_t *thing); // --------------