From 35b485183a1e10de9dfe41fbc80eef74a90613ac Mon Sep 17 00:00:00 2001 From: SSNTails Date: Tue, 11 Jun 2024 18:32:22 +0000 Subject: [PATCH 1/2] Chasecam during demo playback --- p_camera.c | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++++ p_camera.h | 31 ++++ 2 files changed, 466 insertions(+) create mode 100644 p_camera.c create mode 100644 p_camera.h diff --git a/p_camera.c b/p_camera.c new file mode 100644 index 0000000000..45118d455c --- /dev/null +++ b/p_camera.c @@ -0,0 +1,435 @@ +#include "p_camera.h" + +#ifdef USECAMERA +camera_t camera, camera2; +//#define NOCLIPCAMERA + +static boolean PIT_CameraCheckLine(line_t *ld, pmovework_t *mw) +{ + fixed_t opentop, openbottom, lowfloor; + sector_t *front, *back; + + // The moving thing's destination positoin will cross the given line. + // If this should not be allowed, return false. + if(ld->sidenum[1] == -1) + return false; // one-sided line + + if(ld->flags & ML_BLOCKING) + return false; // explicitly blocking everything + + front = LD_FRONTSECTOR(ld); + back = LD_BACKSECTOR(ld); + + if(front->ceilingheight == front->floorheight || + back->ceilingheight == back->floorheight) + { + mw->blockline = ld; + return false; // probably a closed door + } + + if(front->ceilingheight < back->ceilingheight) + opentop = front->ceilingheight; + else + opentop = back->ceilingheight; + + if(front->floorheight > back->floorheight) + { + openbottom = front->floorheight; + lowfloor = back->floorheight; + } + else + { + openbottom = back->floorheight; + lowfloor = front->floorheight; + } + + // adjust floor/ceiling heights + if(opentop < mw->tmceilingz) + mw->tmceilingz = opentop; + if(openbottom >mw->tmfloorz) + mw->tmfloorz = openbottom; + if(lowfloor < mw->tmdropoffz) + mw->tmdropoffz = lowfloor; + + return true; +} + +static boolean PM_CameraCrossCheck(line_t *ld, pmovework_t *mw) +{ + if(PM_BoxCrossLine(ld, mw)) + { + if(!PIT_CameraCheckLine(ld, mw)) + return false; + } + return true; +} + +static boolean PM_CameraCheckPosition(pmovework_t *mw) +{ + int xl, xh, yl, yh, bx, by; + mobj_t *tmthing = mw->tmthing; + VINT *lvalidcount; + + mw->tmflags = tmthing->flags; + + mw->tmbbox[BOXTOP ] = mw->tmy + tmthing->radius; + mw->tmbbox[BOXBOTTOM] = mw->tmy - tmthing->radius; + mw->tmbbox[BOXRIGHT ] = mw->tmx + tmthing->radius; + mw->tmbbox[BOXLEFT ] = mw->tmx - tmthing->radius; + + mw->newsubsec = R_PointInSubsector(mw->tmx, mw->tmy); + + // the base floor/ceiling is from the subsector that contains the point. + // Any contacted lines the step closer together will adjust them. + mw->tmfloorz = mw->tmdropoffz = mw->newsubsec->sector->floorheight; + mw->tmceilingz = mw->newsubsec->sector->ceilingheight; + + I_GetThreadLocalVar(DOOMTLS_VALIDCOUNT, lvalidcount); + *lvalidcount = *lvalidcount + 1; + if (*lvalidcount == 0) + *lvalidcount = 1; + + mw->blockline = NULL; + mw->numspechit = 0; + + if(mw->tmflags & MF_NOCLIP) // thing has no clipping? + return true; + + // check lines + xl = mw->tmbbox[BOXLEFT ] - bmaporgx; + xh = mw->tmbbox[BOXRIGHT ] - bmaporgx; + yl = mw->tmbbox[BOXBOTTOM] - bmaporgy; + yh = mw->tmbbox[BOXTOP ] - bmaporgy; + + if(xl < 0) + xl = 0; + if(yl < 0) + yl = 0; + if(yh < 0 || xh < 0) + return true; + + xl = (unsigned)xl >> MAPBLOCKSHIFT; + xh = (unsigned)xh >> MAPBLOCKSHIFT; + yl = (unsigned)yl >> MAPBLOCKSHIFT; + yh = (unsigned)yh >> MAPBLOCKSHIFT; + + if(xh >= bmapwidth) + xh = bmapwidth - 1; + if(yh >= bmapheight) + yh = bmapheight - 1; + + for(bx = xl; bx <= xh; bx++) + { + for(by = yl; by <= yh; by++) + { + if(!P_BlockLinesIterator(bx, by, (blocklinesiter_t)PM_CameraCrossCheck, mw)) + return false; + } + } + + return true; +} + +static boolean P_CameraTryMove2(ptrymove_t *tm, boolean checkposonly) +{ + pmovework_t mw; + boolean trymove2; // result from P_CameraTryMove2 + mobj_t *tmthing = tm->tmthing; + + mw.tmx = tm->tmx; + mw.tmy = tm->tmy; + mw.tmthing = tm->tmthing; + mw.spechit = &tm->spechit[0]; + + trymove2 = PM_CameraCheckPosition(&mw); + + tm->floatok = false; + tm->blockline = mw.blockline; + tm->tmfloorz = mw.tmfloorz; + tm->tmceilingz = mw.tmceilingz; + tm->tmdropoffz = mw.tmdropoffz; + + if(checkposonly) + return trymove2; + + if(!trymove2) + return false; + + if(!(tmthing->flags & MF_NOCLIP)) + { + if(mw.tmceilingz - mw.tmfloorz < tmthing->height) + return false; // doesn't fit + tm->floatok = true; + if(mw.tmceilingz - tmthing->z < tmthing->height) + return false; // mobj must lower itself to fit + if(mw.tmfloorz - tmthing->z > 24*FRACUNIT) + return false; // too big a step up + if(!(tmthing->flags & (MF_DROPOFF|MF_FLOAT)) && mw.tmfloorz - mw.tmdropoffz > 24*FRACUNIT) + return false; // don't stand over a dropoff + } + + // the move is ok, so link the thing into its new position. + tmthing->floorz = mw.tmfloorz; + tmthing->ceilingz = mw.tmceilingz; + tmthing->x = mw.tmx; + tmthing->y = mw.tmy; + + return true; +} + +static boolean P_CameraTryMove (ptrymove_t *tm, mobj_t *thing, fixed_t x, fixed_t y) +{ + tm->tmthing = thing; + tm->tmx = x; + tm->tmy = y; + return P_CameraTryMove2 (tm, false); +} + +// +// Try to slide the player against walls by finding the closest move available. +// +static void P_CameraSlideMove(pslidemove_t *sm) +{ + int i; + fixed_t dx, dy, rx, ry; + fixed_t frac, slide; + pslidework_t sw; + mobj_t *slidething = sm->slidething; + + dx = slidething->momx; + dy = slidething->momy; + sw.slidex = slidething->x; + sw.slidey = slidething->y; + sw.slidething = slidething; + sw.numspechit = 0; + sw.spechit = &sm->spechit[0]; + + // perform a maximum of three bumps + for(i = 0; i < 3; i++) + { + frac = P_CompletableFrac(&sw, dx, dy); + if(frac != FRACUNIT) + frac -= 0x1000; + if(frac < 0) + frac = 0; + + rx = FixedMul(frac, dx); + ry = FixedMul(frac, dy); + + sw.slidex += rx; + sw.slidey += ry; + + // made it the entire way + if(frac == FRACUNIT) + { + slidething->momx = dx; + slidething->momy = dy; +// SL_CheckSpecialLines(&sw); // Camera doesn't trip lines + sm->slidex = sw.slidex; + sm->slidey = sw.slidey; + return; + } + + // project the remaining move along the line that blocked movement + dx -= rx; + dy -= ry; + dx = FixedMul(dx, sw.blocknvx); + dy = FixedMul(dy, sw.blocknvy); + slide = dx + dy; + + dx = FixedMul(slide, sw.blocknvx); + dy = FixedMul(slide, sw.blocknvy); + } + + // some hideous situation has happened that won't let the camera slide + sm->slidex = slidething->x; + sm->slidey = slidething->y; + sm->slidething->momx = slidething->momy = 0; +} + +static void P_ResetCamera(player_t *player, camera_t *thiscam) +{ + thiscam->x = player->mo->x; + thiscam->y = player->mo->y; + thiscam->z = player->mo->z + VIEWHEIGHT; +} + +// Process the mobj-ish required functions of the camera +static void P_CameraThinker(player_t *player, camera_t *thiscam) +{ +#ifdef NOCLIPCAMERA + thiscam->x += thiscam->momx; + thiscam->y += thiscam->momy; + thiscam->z += thiscam->momz; + return; +#else + // P_CameraXYMovement() + if (thiscam->momx || thiscam->momy) + { + fixed_t momx, momy; + pslidemove_t sm; + ptrymove_t tm; + + momx = vblsinframe*(thiscam->momx>>2); + momy = vblsinframe*(thiscam->momy>>2); + + mobj_t mo; // Our temporary dummy to pretend we are a mobj + mo.flags = MF_SOLID|MF_FLOAT; + mo.x = thiscam->x; + mo.y = thiscam->y; + mo.z = thiscam->z; + mo.floorz = thiscam->floorz; + mo.ceilingz = thiscam->ceilingz; + mo.momx = thiscam->momx; + mo.momy = thiscam->momy; + mo.momz = thiscam->momz; + mo.radius = CAM_RADIUS; + mo.height = CAM_HEIGHT; + sm.slidething = &mo; + + P_CameraSlideMove(&sm); + + if (sm.slidex == mo.x && sm.slidey == mo.y) + goto camstairstep; + + if (P_CameraTryMove(&tm, &mo, sm.slidex, sm.slidey)) + goto camwrapup; + +camstairstep: + // something fucked up in slidemove, so stairstep + if (P_CameraTryMove(&tm, &mo, mo.x, mo.y + momy)) + { + mo.momx = 0; + mo.momy = momy; + goto camwrapup; + } + + if (P_CameraTryMove(&tm, &mo, mo.x + momx, mo.y)) + { + mo.momx = momx; + mo.momy = 0; + goto camwrapup; + } + + mo.momx = mo.momy = 0; + +camwrapup: + thiscam->x = mo.x; + thiscam->y = mo.y; + thiscam->z = mo.z; + thiscam->floorz = mo.floorz; + thiscam->ceilingz = mo.ceilingz; + thiscam->momx = mo.momx; + thiscam->momy = mo.momy; + thiscam->momz = mo.momz; + } + + // P_CameraZMovement() + if (thiscam->momz) + { + thiscam->z += thiscam->momz; + + // Don't go below the floor + if (thiscam->z <= thiscam->floorz) + { + thiscam->z = thiscam->floorz; + if (thiscam->z > player->viewz + CAM_HEIGHT + (16 << FRACBITS)) + { + // Camera got stuck above the player + P_ResetCamera(player, thiscam); + } + } + + // Don't go above the ceiling + if (thiscam->z + CAM_HEIGHT > thiscam->ceilingz) + { + if (thiscam->momz > 0) + thiscam->momz = 0; + + thiscam->z = thiscam->ceilingz - CAM_HEIGHT; + + if (thiscam->z + CAM_HEIGHT < player->mo->z - player->mo->height) + { + // Camera got stuck below the player + P_ResetCamera(player, thiscam); + } + } + } + + if (thiscam->ceilingz - thiscam->z < CAM_HEIGHT && thiscam->ceilingz >= thiscam->z) + { + thiscam->ceilingz = thiscam->z + CAM_HEIGHT; + thiscam->floorz = thiscam->z; + } +#endif +} + +void P_MoveChaseCamera(player_t *player, camera_t *thiscam) +{ + angle_t angle = 0; + angle_t focusangle = 0; + fixed_t x, y, z, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; + fixed_t dist; + mobj_t *mo; + subsector_t *newsubsec; + + mo = player->mo; +// const fixed_t radius = CAM_RADIUS; + const fixed_t height = CAM_HEIGHT; + + angle = focusangle = mo->angle; + + P_CameraThinker(player, thiscam); + + camspeed = FRACUNIT / 4; + camdist = CAM_DIST; + camheight = 20 << FRACBITS; + + if (P_AproxDistance(thiscam->x - mo->x, thiscam->y - mo->y) > camdist * 2) + { + // Camera is stuck, and the player has gone over twice as far away from it, so let's reset + P_ResetCamera(player, thiscam); + } + + dist = camdist; + + // If dead, camera is twice as close + if (player->health <= 0) + dist >>= 1; + + // Destination XY + x = mo->x - FixedMul(finecosine((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); + y = mo->y - FixedMul(finesine((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); + + pviewheight = VIEWHEIGHT; + + z = mo->z + pviewheight + camheight; + + // Look at halfway between the camera and player. Is the ceiling lower? Then the camera should try to move down to fit under it + newsubsec = R_PointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); + + { + // camera fit? + if (newsubsec->sector->ceilingheight != newsubsec->sector->floorheight // Don't try to fit in sectors with equal floor and ceiling heights + && newsubsec->sector->ceilingheight - height < z) + z = newsubsec->sector->ceilingheight - height-(11<z < thiscam->floorz) + thiscam->z = thiscam->floorz; + + // The camera actually focuses 64 units ahead of where the player is. + // This is more aesthetically pleasing. + dist = 64 << FRACBITS; + viewpointx = mo->x + FixedMul(finecosine((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); + viewpointy = mo->y + FixedMul(finesine((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); + + thiscam->angle = R_PointToAngle2(thiscam->x, thiscam->y, viewpointx, viewpointy); + + // Set the mom vector, cut by the camera speed, as it tries to move to the destination position + thiscam->momx = FixedMul(x - thiscam->x, camspeed); + thiscam->momy = FixedMul(y - thiscam->y, camspeed); + thiscam->momz = FixedMul(z - thiscam->z, camspeed); +} + +#endif \ No newline at end of file diff --git a/p_camera.h b/p_camera.h new file mode 100644 index 0000000000..52e78adca8 --- /dev/null +++ b/p_camera.h @@ -0,0 +1,31 @@ +#ifndef __P_CAMERA_H__ +#define __P_CAMERA_H__ + +#include "doomdef.h" +#include "p_local.h" + +#ifdef USECAMERA +typedef struct camera_s +{ + // Info for drawing: position. + fixed_t x, y, z; + + angle_t angle; // orientation + angle_t aiming; // up/down (future) + + struct subsector_s *subsector; + fixed_t floorz, ceilingz; + + // Momentums used to update position + fixed_t momx, momy, momz; +} camera_t; + +#define CAM_HEIGHT (16< Date: Tue, 11 Jun 2024 18:52:18 +0000 Subject: [PATCH 2/2] Chasecam during demo playback --- Makefile | 3 ++- p_camera.c | 5 +--- p_camera.h | 5 +--- p_local.h | 40 +++++++++++++++++++++++++++ p_move.c | 24 +---------------- p_slide.c | 79 ++++++++++++++++++++++++++++++++++++++++++------------ p_user.c | 13 +++++++++ r_main.c | 28 +++++++++++++++---- r_phase3.c | 3 +++ r_phase8.c | 3 +++ wadbase.s | 2 +- 11 files changed, 150 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 37013a3233..b1b07813f9 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ OBJS = \ d_main.o \ g_game.o \ info.o \ + p_camera.o \ p_ceilng.o \ p_doors.o \ p_enemy.o \ @@ -115,7 +116,7 @@ m68k.bin: $(TARGET).32x: $(TARGET).elf $(OBJC) -O binary $< temp2.bin - $(DD) if=temp2.bin of=temp.bin bs=180K conv=sync + $(DD) if=temp2.bin of=temp.bin bs=196K conv=sync rm -f temp3.bin cat temp.bin $(WAD) >>temp3.bin $(DD) if=temp3.bin of=$@ bs=512K conv=sync diff --git a/p_camera.c b/p_camera.c index 45118d455c..fe248c05db 100644 --- a/p_camera.c +++ b/p_camera.c @@ -1,7 +1,6 @@ #include "p_camera.h" -#ifdef USECAMERA -camera_t camera, camera2; +camera_t camera; //#define NOCLIPCAMERA static boolean PIT_CameraCheckLine(line_t *ld, pmovework_t *mw) @@ -431,5 +430,3 @@ void P_MoveChaseCamera(player_t *player, camera_t *thiscam) thiscam->momy = FixedMul(y - thiscam->y, camspeed); thiscam->momz = FixedMul(z - thiscam->z, camspeed); } - -#endif \ No newline at end of file diff --git a/p_camera.h b/p_camera.h index 52e78adca8..0b90ad3867 100644 --- a/p_camera.h +++ b/p_camera.h @@ -4,7 +4,6 @@ #include "doomdef.h" #include "p_local.h" -#ifdef USECAMERA typedef struct camera_s { // Info for drawing: position. @@ -24,8 +23,6 @@ typedef struct camera_s #define CAM_RADIUS (20<numspechit = sw.numspechit; } +// +// Try to slide the player against walls by finding the closest move available. +// +void P_CameraSlideMove(pslidemove_t *sm) +{ + int i; + fixed_t dx, dy, rx, ry; + fixed_t frac, slide; + pslidework_t sw; + mobj_t *slidething = sm->slidething; + + dx = slidething->momx; + dy = slidething->momy; + sw.slidex = slidething->x; + sw.slidey = slidething->y; + sw.slidething = slidething; + sw.numspechit = 0; + sw.spechit = &sm->spechit[0]; + + // perform a maximum of three bumps + for (i = 0; i < 3; i++) + { + frac = P_CompletableFrac(&sw, dx, dy); + if (frac != FRACUNIT) + frac -= 0x1000; + if (frac < 0) + frac = 0; + + rx = FixedMul(frac, dx); + ry = FixedMul(frac, dy); + + sw.slidex += rx; + sw.slidey += ry; + + // made it the entire way + if (frac == FRACUNIT) + { + slidething->momx = dx; + slidething->momy = dy; + // SL_CheckSpecialLines(&sw); // Camera doesn't trip lines + sm->slidex = sw.slidex; + sm->slidey = sw.slidey; + return; + } + + // project the remaining move along the line that blocked movement + dx -= rx; + dy -= ry; + dx = FixedMul(dx, sw.blocknvx); + dy = FixedMul(dy, sw.blocknvy); + slide = dx + dy; + + dx = FixedMul(slide, sw.blocknvx); + dy = FixedMul(slide, sw.blocknvy); + } + + // some hideous situation has happened that won't let the camera slide + sm->slidex = slidething->x; + sm->slidey = slidething->y; + sm->slidething->momx = slidething->momy = 0; +} + // EOF diff --git a/p_user.c b/p_user.c index 358e525720..b7b87001dd 100644 --- a/p_user.c +++ b/p_user.c @@ -3,6 +3,7 @@ #include "doomdef.h" #include "p_local.h" #include "st_main.h" +#include "p_camera.h" fixed_t forwardmove[2] = {0x40000, 0x60000}; @@ -606,6 +607,11 @@ ticphase = 21; if (player->playerstate == PST_DEAD) { + if (demoplayback) + { + if (player == &players[consoleplayer]) + P_MoveChaseCamera(player, &camera); + } P_DeathThink (player); return; } @@ -619,6 +625,13 @@ ticphase = 22; else P_MovePlayer (player); P_CalcHeight (player); + + if (demoplayback) + { + if (player == &players[consoleplayer]) + P_MoveChaseCamera(player, &camera); + } + if (player->mo->subsector->sector->special) P_PlayerInSpecialSector (player); diff --git a/r_main.c b/r_main.c index 58e93f74a6..1a887b9d72 100644 --- a/r_main.c +++ b/r_main.c @@ -2,6 +2,7 @@ #include "doomdef.h" #include "r_local.h" +#include "p_camera.h" #ifdef MARS #include "mars.h" #include "marshw.h" @@ -503,17 +504,34 @@ static void R_Setup (int displayplayer, visplane_t *visplanes_, player = &players[displayplayer]; + if (demoplayback) + { + const camera_t *thiscam = NULL; + + if (displayplayer == consoleplayer) + thiscam = &camera; + + vd.viewx = thiscam->x; + vd.viewy = thiscam->y; + vd.viewz = thiscam->z; + vd.viewangle = thiscam->angle; + vd.lightlevel = thiscam->subsector->sector->lightlevel; + } + else + { + vd.viewx = player->mo->x; + vd.viewy = player->mo->y; + vd.viewz = player->viewz; + vd.viewangle = player->mo->angle; + vd.lightlevel = player->mo->subsector->sector->lightlevel; + } + vd.viewplayer = player; - vd.viewx = player->mo->x; - vd.viewy = player->mo->y; - vd.viewz = player->viewz; - vd.viewangle = player->mo->angle; vd.viewsin = finesine(vd.viewangle>>ANGLETOFINESHIFT); vd.viewcos = finecosine(vd.viewangle>>ANGLETOFINESHIFT); vd.displayplayer = displayplayer; - vd.lightlevel = player->mo->subsector->sector->lightlevel; vd.fixedcolormap = 0; vd.clipangle = xtoviewangle[0]<state]; sprdef = &sprites[state->sprite]; sprframe = &spriteframes[sprdef->firstframe + (state->frame & FF_FRAMEMASK)]; diff --git a/r_phase8.c b/r_phase8.c index e16103fafa..c82a372de3 100644 --- a/r_phase8.c +++ b/r_phase8.c @@ -468,6 +468,9 @@ static void R_DrawPSprites(int sprscreenhalf) I_SetThreadLocalVar(DOOMTLS_COLORMAP, dc_colormaps); + if (demoplayback) + return; // No psprites in camera view + // draw psprites for (spr = vd.lastsprite_p; spr < vd.vissprite_p; spr++) { diff --git a/wadbase.s b/wadbase.s index 6871e8ca92..ad176dd854 100644 --- a/wadbase.s +++ b/wadbase.s @@ -4,5 +4,5 @@ .global _wadBase _wadBase: - .long 0x202D000 + .long 0x2031000