diff --git a/source/core/gamestruct.h b/source/core/gamestruct.h index fac4003c2..fa5c76eee 100644 --- a/source/core/gamestruct.h +++ b/source/core/gamestruct.h @@ -103,6 +103,7 @@ struct GameInterface virtual int chaseCamY(binangle ang) { return 0; } virtual int chaseCamZ(fixedhoriz horiz) { return 0; } virtual void processSprites(int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) = 0; + virtual void UpdateCameras(double smoothratio) {} virtual FString statFPS() { diff --git a/source/core/rendering/hw_entrypoint.cpp b/source/core/rendering/hw_entrypoint.cpp index ee1996035..08c0248ea 100644 --- a/source/core/rendering/hw_entrypoint.cpp +++ b/source/core/rendering/hw_entrypoint.cpp @@ -49,6 +49,7 @@ #include "hw_drawinfo.h" #include "gamecvars.h" #include "render.h" +#include "gamestruct.h" EXTERN_CVAR(Bool, cl_capfps) @@ -269,6 +270,8 @@ static void CheckTimer(FRenderState &state, uint64_t ShaderStartTime) } +void animatecamsprite(double s); + void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, lookangle rollang) { checkRotatedWalls(); @@ -280,28 +283,30 @@ void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sect if (sect >= 0) sectnum = sect; if (sectnum < 0) return; - auto RenderState = screen->RenderState(); - RenderState->SetVertexBuffer(screen->mVertexData); - screen->mVertexData->Reset(); - - FRenderViewpoint r_viewpoint = SetupViewpoint(playersprite, position, sectnum, angle, horizon, rollang); iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; - checkBenchActive(); // reset statistics counters ResetProfilingData(); // Get this before everything else + FRenderViewpoint r_viewpoint = SetupViewpoint(playersprite, position, sectnum, angle, horizon, rollang); if (cl_capfps) r_viewpoint.TicFrac = 1.; else r_viewpoint.TicFrac = I_GetTimeFrac(); screen->mLights->Clear(); screen->mViewpoints->Clear(); + screen->mVertexData->Reset(); // Shader start time does not need to be handled per level. Just use the one from the camera to render from. + auto RenderState = screen->RenderState(); CheckTimer(*RenderState, 0/*ShaderStartTime*/); + // prepare all camera textures that have been used in the last frame. + gi->UpdateCameras(r_viewpoint.TicFrac); + + RenderState->SetVertexBuffer(screen->mVertexData); + // now render the main view float fovratio; float ratio = ActiveRatio(windowxy2.x - windowxy1.x + 1, windowxy2.y - windowxy1.y + 1); @@ -316,7 +321,26 @@ void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sect screen->ImageTransitionScene(true); // Only relevant for Vulkan. - RenderViewpoint(r_viewpoint, nullptr, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, false, false); + RenderViewpoint(r_viewpoint, nullptr, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true); + All.Unclock(); +} + +void render_camtex(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, lookangle rollang, FGameTexture* camtex, IntRect& rect, double smoothratio) +{ + int16_t sect = sectnum; + updatesector(position.x, position.y, §); + if (sect >= 0) sectnum = sect; + if (sectnum < 0) return; + + screen->RenderState()->SetVertexBuffer(screen->mVertexData); + + // now render the main view + float ratio = camtex->GetDisplayWidth() / camtex->GetDisplayHeight(); + + FRenderViewpoint r_viewpoint = SetupViewpoint(playersprite, position, sectnum, angle, horizon, rollang); + if (cl_capfps) r_viewpoint.TicFrac = smoothratio; + + RenderViewpoint(r_viewpoint, &rect, r_viewpoint.FieldOfView.Degrees, ratio, ratio, false, false); All.Unclock(); } diff --git a/source/core/rendering/render.h b/source/core/rendering/render.h index 89eb28477..ad4fb56f9 100644 --- a/source/core/rendering/render.h +++ b/source/core/rendering/render.h @@ -2,8 +2,10 @@ #include "build.h" class FSerializer; +struct IntRect; void render_drawrooms(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, lookangle rollang); +void render_camtex(spritetype* playersprite, const vec3_t& position, int sectnum, binangle angle, fixedhoriz horizon, lookangle rollang, FGameTexture* camtex, IntRect& rect, double smoothratio); struct PortalDesc { diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h index 9c697f5ab..368aafb60 100644 --- a/source/games/duke/src/duke3d.h +++ b/source/games/duke/src/duke3d.h @@ -66,6 +66,7 @@ struct GameInterface : public ::GameInterface int chaseCamY(binangle ang) { return -ang.bsin(-4); } int chaseCamZ(fixedhoriz horiz) { return horiz.asq16() >> 9; } void processSprites(int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) override; + void UpdateCameras(double smoothratio) override; }; diff --git a/source/games/duke/src/render.cpp b/source/games/duke/src/render.cpp index 5012cd064..b6905b1f6 100644 --- a/source/games/duke/src/render.cpp +++ b/source/games/duke/src/render.cpp @@ -92,7 +92,7 @@ void renderView(spritetype* playersprite, int sectnum, int x, int y, int z, bina // //--------------------------------------------------------------------------- -void animatecamsprite(double smoothratio) +void GameInterface::UpdateCameras(double smoothratio) { const int VIEWSCREEN_ACTIVE_DISTANCE = 8192; @@ -126,7 +126,7 @@ void animatecamsprite(double smoothratio) } else { - render_drawrooms(camera, camera->pos, camera->sectnum, ang, buildhoriz(camera->shade), buildlook(0)); + render_camtex(camera, camera->pos, camera->sectnum, ang, buildhoriz(camera->shade), buildlook(0), tex, rect, smoothratio); } display_mirror = 0; }); @@ -259,7 +259,7 @@ void displayrooms(int snum, double smoothratio) DoInterpolations(smoothratio / 65536.); setgamepalette(BASEPAL); - animatecamsprite(smoothratio); + if (!testnewrenderer) gi->UpdateCameras(smoothratio); // Only Polymost does this here. The new renderer calls this internally. if (ud.cameraactor) { diff --git a/source/games/sw/src/draw.cpp b/source/games/sw/src/draw.cpp index 9b81bc1b5..0b8ee5ca1 100644 --- a/source/games/sw/src/draw.cpp +++ b/source/games/sw/src/draw.cpp @@ -1555,7 +1555,8 @@ drawscreen(PLAYERp pp, double smoothratio) if (automapMode != am_full)// && !ScreenSavePic) { // Cameras must be done before the main loop. - JS_DrawCameras(pp, tx, ty, tz); + if (!testnewrenderer) JS_DrawCameras(pp, tx, ty, tz, smoothratio); + else JS_CameraParms(pp, tx, ty, tz); } if (!testnewrenderer) diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h index 6c477ac2a..7cf22c150 100644 --- a/source/games/sw/src/game.h +++ b/source/games/sw/src/game.h @@ -2249,6 +2249,7 @@ struct GameInterface : ::GameInterface int chaseCamY(binangle ang) { return -ang.bsin(-3); } int chaseCamZ(fixedhoriz horiz) { return horiz.asq16() >> 8; } void processSprites(int viewx, int viewy, int viewz, binangle viewang, double smoothRatio) override; + void UpdateCameras(double smoothratio) override; GameStats getStats() override; diff --git a/source/games/sw/src/jsector.cpp b/source/games/sw/src/jsector.cpp index 309f1e2a4..533ead8a2 100644 --- a/source/games/sw/src/jsector.cpp +++ b/source/games/sw/src/jsector.cpp @@ -464,7 +464,7 @@ void JS_InitMirrors(void) // Draw a 3d screen to a specific tile ///////////////////////////////////////////////////// void drawroomstotile(int daposx, int daposy, int daposz, - binangle ang, fixedhoriz horiz, short dacursectnum, short tilenume) + binangle ang, fixedhoriz horiz, short dacursectnum, short tilenume, double smoothratio) { TileFiles.MakeCanvas(tilenume, tileWidth(tilenume), tileHeight(tilenume)); @@ -481,7 +481,7 @@ void drawroomstotile(int daposx, int daposy, int daposz, } else { - render_drawrooms(nullptr, { daposx, daposy, daposz }, dacursectnum, ang, horiz, buildlook(0)); + render_camtex(nullptr, { daposx, daposy, daposz }, dacursectnum, ang, horiz, buildlook(0), tileGetTexture(tilenume), rect, smoothratio); } }); @@ -540,7 +540,7 @@ short camplayerview = 1; // Don't show yourself! // Hack job alert! // Mirrors and cameras are maintained in the same data structure, but for hardware rendering they cannot be interleaved. // So this function replicates JS_DrawMirrors to only process the camera textures but not change any global state. -void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz) +void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz, double smoothratio) { int j, cnt; int dist; @@ -721,11 +721,11 @@ void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz) if (TEST_BOOL11(sp) && numplayers > 1) { - drawroomstotile(cp->posx, cp->posy, cp->posz, cp->angle.ang, cp->horizon.horiz, cp->cursectnum, mirror[cnt].campic); + drawroomstotile(cp->posx, cp->posy, cp->posz, cp->angle.ang, cp->horizon.horiz, cp->cursectnum, mirror[cnt].campic, smoothratio); } else { - drawroomstotile(sp->x, sp->y, sp->z, buildang(SP_TAG5(sp)), buildhoriz(camhoriz), sp->sectnum, mirror[cnt].campic); + drawroomstotile(sp->x, sp->y, sp->z, buildang(SP_TAG5(sp)), buildhoriz(camhoriz), sp->sectnum, mirror[cnt].campic, smoothratio); } } } @@ -735,6 +735,25 @@ void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz) } } +// Workaround until the camera code can be refactored to process all camera textures that were visible last frame. +// Need to stash the parameters for later use. This is only used to find the nearest camera. +static PLAYERp cam_pp; +static int cam_tx, cam_ty, cam_tz; + +void JS_CameraParms(PLAYERp pp, int tx, int ty, int tz) +{ + cam_pp = pp; + cam_tx = tx; + cam_ty = ty; + cam_tz = tz; +} + +void GameInterface::UpdateCameras(double smoothratio) +{ + JS_DrawCameras(cam_pp, cam_tx, cam_ty, cam_tz, smoothratio); +} + + void DoAutoSize(tspriteptr_t tspr) { diff --git a/source/games/sw/src/jsector.h b/source/games/sw/src/jsector.h index c7a0ec571..da97e9d91 100644 --- a/source/games/sw/src/jsector.h +++ b/source/games/sw/src/jsector.h @@ -70,7 +70,8 @@ extern bool mirrorinview; extern short NormalVisibility; void JAnalyzeSprites(tspriteptr_t tspr); -void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz); +void JS_DrawCameras(PLAYERp pp, int tx, int ty, int tz, double smoothratio); +void JS_CameraParms(PLAYERp pp, int tx, int ty, int tz); void JS_DrawMirrors(PLAYERp pp,int tx,int ty,int tz,fixed_t tpq16ang,fixed_t tpq16horiz); void JS_InitMirrors(void); void JS_InitLockouts(void);