From b74a9965b8f1e678f04c52fc8747cc98e6df6cf8 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 5 Jun 2018 19:36:57 +0200 Subject: [PATCH] - draw models in mirrors and portals at the right location in the software renderer --- src/swrenderer/scene/r_portal.cpp | 7 +++++++ src/swrenderer/scene/r_scene.cpp | 8 ++++++++ src/swrenderer/things/r_model.cpp | 25 ++++++++++++++++++------- src/swrenderer/things/r_model.h | 6 +++++- src/swrenderer/viewport/r_viewport.cpp | 4 ++++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index 46e6e8357..323480c32 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -173,6 +173,7 @@ namespace swrenderer Thread->Viewport->viewpoint.sector = port->mDestination; assert(Thread->Viewport->viewpoint.sector != nullptr); R_SetViewAngle(Thread->Viewport->viewpoint, Thread->Viewport->viewwindow); + Thread->Viewport->SetupPolyViewport(Thread); Thread->OpaquePass->ClearSeenSprites(); Thread->Clip3D->ClearFakeFloors(); @@ -239,6 +240,7 @@ namespace swrenderer // Masked textures and planes need the view coordinates restored for proper positioning. viewposStack.Pop(Thread->Viewport->viewpoint.Pos); + Thread->Viewport->SetupPolyViewport(Thread); Thread->TranslucentPass->Render(); VisiblePlane *pl = nullptr; // quiet, GCC! @@ -259,6 +261,7 @@ namespace swrenderer Thread->Viewport->viewpoint.extralight = savedextralight; Thread->Viewport->viewpoint.Angles = savedangles; R_SetViewAngle(Thread->Viewport->viewpoint, Thread->Viewport->viewwindow); + Thread->Viewport->SetupPolyViewport(Thread); CurrentPortalInSkybox = false; Thread->Clip3D->LeaveSkybox(); @@ -426,6 +429,8 @@ namespace swrenderer else MirrorFlags |= RF_XFLIP; } + Thread->Viewport->SetupPolyViewport(Thread); + // some portals have height differences, account for this here Thread->Clip3D->EnterSkybox(); // push 3D floor height map CurrentPortalInSkybox = false; // first portal in a skybox should set this variable to false for proper clipping in skyboxes. @@ -478,6 +483,8 @@ namespace swrenderer viewpoint.Pos = startpos; viewpoint.Path[0] = savedpath[0]; viewpoint.Path[1] = savedpath[1]; + + viewport->SetupPolyViewport(Thread); } #if 0 diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index d51eef63a..bf6653568 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -159,6 +159,8 @@ namespace swrenderer if (r_models) MainThread()->Viewport->SetupPolyViewport(MainThread()); + FRenderViewpoint origviewpoint = MainThread()->Viewport->viewpoint; + ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags; // Never draw the player unless in chasecam mode if (!MainThread()->Viewport->viewpoint.showviewer) @@ -167,6 +169,12 @@ namespace swrenderer } RenderThreadSlices(); + + // Mirrors fail to restore the original viewpoint -- we need it for the HUD weapon to draw correctly. + MainThread()->Viewport->viewpoint = origviewpoint; + if (r_models) + MainThread()->Viewport->SetupPolyViewport(MainThread()); + RenderPSprites(); MainThread()->Viewport->viewpoint.camera->renderflags = savedflags; diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp index d3eac67e0..831fc09f8 100644 --- a/src/swrenderer/things/r_model.cpp +++ b/src/swrenderer/things/r_model.cpp @@ -47,12 +47,22 @@ namespace swrenderer if (tz < MINZ) return; - // too far off the side? double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos; + + // Flip for mirrors + if (thread->Portal->MirrorFlags & RF_XFLIP) + { + tx = viewwidth - tx - 1; + } + + // too far off the side? if (fabs(tx / 64) > fabs(tz)) return; RenderModel *vis = thread->FrameMemory->NewObject(x, y, z, smf, actor, float(1 / tz)); + vis->CurrentPortalUniq = thread->Portal->CurrentPortalUniq; + vis->WorldToClip = thread->Viewport->WorldToClip; + vis->MirrorWorldToClip = !!(thread->Portal->MirrorFlags & RF_XFLIP); thread->SpriteList->Push(vis); } @@ -64,7 +74,7 @@ namespace swrenderer void RenderModel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) { - SWModelRenderer renderer(thread, clip3DFloor); + SWModelRenderer renderer(thread, clip3DFloor, &WorldToClip, MirrorWorldToClip); renderer.RenderModel(x, y, z, smf, actor); } @@ -72,13 +82,14 @@ namespace swrenderer void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy) { - SWModelRenderer renderer(thread, Fake3DTranslucent()); + SWModelRenderer renderer(thread, Fake3DTranslucent(), &thread->Viewport->WorldToClip, false); renderer.RenderHUDModel(psp, ofsx, ofsy); } ///////////////////////////////////////////////////////////////////////////// - SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor) : Thread(thread), Clip3DFloor(clip3DFloor) + SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip) + : Thread(thread), Clip3DFloor(clip3DFloor), WorldToClip(worldToClip), MirrorWorldToClip(mirrorWorldToClip) { } @@ -123,7 +134,7 @@ namespace swrenderer if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES)) PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true); - PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !mirrored); + PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip)); } void SWModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf) @@ -194,7 +205,7 @@ namespace swrenderer if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal]) PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true); - PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, mirrored); + PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip)); } void SWModelRenderer::EndDrawHUDModel(AActor *actor) @@ -225,7 +236,7 @@ namespace swrenderer swapYZ.Matrix[2 + 1 * 4] = 1.0f; swapYZ.Matrix[3 + 3 * 4] = 1.0f; - PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject(Thread->Viewport->WorldToClip * swapYZ * ObjectToWorld)); + PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject((*WorldToClip) * swapYZ * ObjectToWorld)); } void SWModelRenderer::DrawArrays(int start, int count) diff --git a/src/swrenderer/things/r_model.h b/src/swrenderer/things/r_model.h index ee6608358..2c08c95c1 100644 --- a/src/swrenderer/things/r_model.h +++ b/src/swrenderer/things/r_model.h @@ -47,12 +47,14 @@ namespace swrenderer float x, y, z; FSpriteModelFrame *smf; AActor *actor; + Mat4f WorldToClip; + bool MirrorWorldToClip; }; class SWModelRenderer : public FModelRenderer { public: - SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor); + SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip); ModelRendererType GetType() const override { return SWModelRendererType; } @@ -81,6 +83,8 @@ namespace swrenderer unsigned int *IndexBuffer = nullptr; TriVertex *VertexBuffer = nullptr; float InterpolationFactor = 0.0; + Mat4f *WorldToClip = nullptr; + bool MirrorWorldToClip = false; }; class SWModelVertexBuffer : public IModelVertexBuffer diff --git a/src/swrenderer/viewport/r_viewport.cpp b/src/swrenderer/viewport/r_viewport.cpp index 57994d899..e3cfc1548 100644 --- a/src/swrenderer/viewport/r_viewport.cpp +++ b/src/swrenderer/viewport/r_viewport.cpp @@ -62,6 +62,10 @@ namespace swrenderer void RenderViewport::SetupPolyViewport(RenderThread *thread) { WorldToView = SoftwareWorldToView(viewpoint); + + if (thread->Portal->MirrorFlags & RF_XFLIP) + WorldToView = Mat4f::Scale(-1.0f, 1.0f, 1.0f) * WorldToView; + ViewToClip = SoftwareViewToClip(); WorldToClip = ViewToClip * WorldToView; }