From c37ce1fdbc57bb788ce7e2f950edc4a444cd58ed Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 26 Nov 2016 10:49:29 +0100 Subject: [PATCH] Add plane clipping to the triangle drawer --- src/r_compiler/llvmdrawers.h | 20 ---------- src/r_poly.cpp | 2 +- src/r_poly_cull.cpp | 2 +- src/r_poly_decal.cpp | 7 ++-- src/r_poly_decal.h | 6 ++- src/r_poly_particle.cpp | 3 +- src/r_poly_particle.h | 4 +- src/r_poly_plane.cpp | 16 ++++---- src/r_poly_plane.h | 7 ++-- src/r_poly_portal.cpp | 21 +++++----- src/r_poly_sky.cpp | 1 + src/r_poly_sprite.cpp | 4 +- src/r_poly_sprite.h | 4 +- src/r_poly_triangle.cpp | 74 ++++++++++++++++++++---------------- src/r_poly_triangle.h | 41 ++++++++++++++++++-- src/r_poly_wall.cpp | 19 ++++----- src/r_poly_wall.h | 7 ++-- src/r_poly_wallsprite.cpp | 3 +- src/r_poly_wallsprite.h | 4 +- 19 files changed, 146 insertions(+), 99 deletions(-) diff --git a/src/r_compiler/llvmdrawers.h b/src/r_compiler/llvmdrawers.h index 4ce3a3a03..c5eb96f4c 100644 --- a/src/r_compiler/llvmdrawers.h +++ b/src/r_compiler/llvmdrawers.h @@ -191,26 +191,6 @@ struct TriVertex float varying[NumVarying]; }; -struct TriMatrix -{ - static TriMatrix null(); - static TriMatrix identity(); - static TriMatrix translate(float x, float y, float z); - static TriMatrix scale(float x, float y, float z); - static TriMatrix rotate(float angle, float x, float y, float z); - static TriMatrix swapYZ(); - static TriMatrix perspective(float fovy, float aspect, float near, float far); - static TriMatrix frustum(float left, float right, float bottom, float top, float near, float far); - - static TriMatrix worldToView(); // Software renderer world to view space transform - static TriMatrix viewToClip(); // Software renderer shearing projection - - TriVertex operator*(TriVertex v) const; - TriMatrix operator*(const TriMatrix &m) const; - - float matrix[16]; -}; - struct TriUniforms { uint32_t light; diff --git a/src/r_poly.cpp b/src/r_poly.cpp index b262ca01d..186077806 100644 --- a/src/r_poly.cpp +++ b/src/r_poly.cpp @@ -44,7 +44,7 @@ void RenderPolyScene::Render() ClearBuffers(); SetSceneViewport(); SetupPerspectiveMatrix(); - MainPortal.SetViewpoint(WorldToClip, Vec4f(0.0f), GetNextStencilValue()); + MainPortal.SetViewpoint(WorldToClip, Vec4f(0.0f, 0.0f, 0.0f, 1.0f), GetNextStencilValue()); MainPortal.Render(0); Skydome.Render(WorldToClip); MainPortal.RenderTranslucent(0); diff --git a/src/r_poly_cull.cpp b/src/r_poly_cull.cpp index 37ddf9103..9ee71c28a 100644 --- a/src/r_poly_cull.cpp +++ b/src/r_poly_cull.cpp @@ -177,7 +177,7 @@ bool PolyCull::CheckBBox(float *bspcoord) // Skip if its in front of the portal: - if (PortalClipPlane != Vec4f(0.0f) && IntersectionTest::plane_aabb(PortalClipPlane, aabb) == IntersectionTest::outside) + if (IntersectionTest::plane_aabb(PortalClipPlane, aabb) == IntersectionTest::outside) return false; // Occlusion test using solid segments: diff --git a/src/r_poly_decal.cpp b/src/r_poly_decal.cpp index ded64a095..9d47c014a 100644 --- a/src/r_poly_decal.cpp +++ b/src/r_poly_decal.cpp @@ -29,7 +29,7 @@ #include "r_poly.h" #include "a_sharedglobal.h" -void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue) +void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const Vec4f &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue) { if (line->linedef == nullptr && line->sidedef == nullptr) return; @@ -37,11 +37,11 @@ void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const seg_t for (DBaseDecal *decal = line->sidedef->AttachedDecals; decal != nullptr; decal = decal->WallNext) { RenderPolyDecal render; - render.Render(worldToClip, decal, line, subsectorDepth, stencilValue); + render.Render(worldToClip, clipPlane, decal, line, subsectorDepth, stencilValue); } } -void RenderPolyDecal::Render(const TriMatrix &worldToClip, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue) +void RenderPolyDecal::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue) { if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid()) return; @@ -166,5 +166,6 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, DBaseDecal *decal, co args.stenciltestvalue = stencilValue; args.stencilwritevalue = stencilValue; //mode = R_SetPatchStyle (decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector, TriBlendMode::Shaded); } diff --git a/src/r_poly_decal.h b/src/r_poly_decal.h index c836a0cd7..068887d90 100644 --- a/src/r_poly_decal.h +++ b/src/r_poly_decal.h @@ -24,11 +24,13 @@ #include "r_poly_triangle.h" +class Vec4f; + class RenderPolyDecal { public: - static void RenderWallDecals(const TriMatrix &worldToClip, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue); + static void RenderWallDecals(const TriMatrix &worldToClip, const Vec4f &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue); private: - void Render(const TriMatrix &worldToClip, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue); }; diff --git a/src/r_poly_particle.cpp b/src/r_poly_particle.cpp index 8151d4888..73e1819d4 100644 --- a/src/r_poly_particle.cpp +++ b/src/r_poly_particle.cpp @@ -28,7 +28,7 @@ #include "r_poly_particle.h" #include "r_poly.h" -void RenderPolyParticle::Render(const TriMatrix &worldToClip, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) +void RenderPolyParticle::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) { DVector3 pos = particle->Pos; double psize = particle->size / 8.0; @@ -104,5 +104,6 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, particle_t *partic args.stenciltestvalue = stencilValue; args.stencilwritevalue = stencilValue; args.SetColormap(sub->sector->ColorMap); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); PolyTriangleDrawer::draw(args, TriDrawVariant::FillSubsector, TriBlendMode::AlphaBlend); } diff --git a/src/r_poly_particle.h b/src/r_poly_particle.h index 3fbb2d2ab..fd581fa83 100644 --- a/src/r_poly_particle.h +++ b/src/r_poly_particle.h @@ -25,8 +25,10 @@ #include "r_poly_triangle.h" #include "p_effect.h" +class Vec4f; + class RenderPolyParticle { public: - void Render(const TriMatrix &worldToClip, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); }; diff --git a/src/r_poly_plane.cpp b/src/r_poly_plane.cpp index 8d4067be0..76ede6960 100644 --- a/src/r_poly_plane.cpp +++ b/src/r_poly_plane.cpp @@ -32,7 +32,7 @@ EXTERN_CVAR(Int, r_3dfloors) -void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) +void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals) { RenderPolyPlane plane; @@ -58,7 +58,7 @@ void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, subsector_t *su double fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->centerspot); if (fakeHeight < ViewPos.Z && fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot)) { - plane.Render3DFloor(worldToClip, sub, subsectorDepth, stencilValue, false, fakeFloor); + plane.Render3DFloor(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, false, fakeFloor); } } @@ -79,16 +79,16 @@ void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, subsector_t *su double fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot); if (fakeHeight > ViewPos.Z && fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot)) { - plane.Render3DFloor(worldToClip, sub, subsectorDepth, stencilValue, true, fakeFloor); + plane.Render3DFloor(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, true, fakeFloor); } } } - plane.Render(worldToClip, sub, subsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals); - plane.Render(worldToClip, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals); + plane.Render(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals); + plane.Render(worldToClip, clipPlane, sub, subsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals); } -void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor) +void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor) { FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture; FTexture *tex = TexMan(picnum); @@ -140,11 +140,12 @@ void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, subsector_t *s args.stencilwritevalue = stencilValue + 1; args.SetTexture(tex); args.SetColormap(sub->sector->ColorMap); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); PolyTriangleDrawer::draw(args, TriDrawVariant::DrawNormal, TriBlendMode::Copy); PolyTriangleDrawer::draw(args, TriDrawVariant::Stencil, TriBlendMode::Copy); } -void RenderPolyPlane::Render(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) +void RenderPolyPlane::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals) { FSectorPortal *portal = sub->sector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor); PolyDrawSectorPortal *polyportal = nullptr; @@ -251,6 +252,7 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, subsector_t *sub, uin args.stenciltestvalue = stencilValue; args.stencilwritevalue = stencilValue + 1; args.SetColormap(frontsector->ColorMap); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); if (!isSky) { diff --git a/src/r_poly_plane.h b/src/r_poly_plane.h index 6e418bf50..3006ce86b 100644 --- a/src/r_poly_plane.h +++ b/src/r_poly_plane.h @@ -25,14 +25,15 @@ #include "r_poly_triangle.h" class PolyDrawSectorPortal; +class Vec4f; class RenderPolyPlane { public: - static void RenderPlanes(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); + static void RenderPlanes(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector> §orPortals); private: - void Render3DFloor(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor); - void Render(const TriMatrix &worldToClip, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); + void Render3DFloor(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); TriVertex PlaneVertex(vertex_t *v1, double height); }; diff --git a/src/r_poly_portal.cpp b/src/r_poly_portal.cpp index 757285d77..3257afc70 100644 --- a/src/r_poly_portal.cpp +++ b/src/r_poly_portal.cpp @@ -94,7 +94,7 @@ void RenderPolyPortal::RenderSubsector(subsector_t *sub) if (sub->sector->CenterFloor() != sub->sector->CenterCeiling()) { - RenderPolyPlane::RenderPlanes(WorldToClip, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); + RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, sub, subsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals); } for (uint32_t i = 0; i < sub->numlines; i++) @@ -178,12 +178,12 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front if (!(fakeFloor->flags & FF_EXISTS)) continue; if (!(fakeFloor->flags & FF_RENDERPLANES)) continue; if (!fakeFloor->model) continue; - RenderPolyWall::Render3DFloorLine(WorldToClip, line, frontsector, subsectorDepth, StencilValue, fakeFloor, SubsectorTranslucentWalls); + RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, fakeFloor, SubsectorTranslucentWalls); } } // Render wall, and update culling info if its an occlusion blocker - if (RenderPolyWall::RenderLine(WorldToClip, line, frontsector, subsectorDepth, StencilValue, SubsectorTranslucentWalls, LinePortals)) + if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, SubsectorTranslucentWalls, LinePortals)) { if (hasSegmentRange) Cull.MarkSegmentCulled(sx1, sx2); @@ -208,6 +208,7 @@ void RenderPolyPortal::RenderPortals(int portalDepth) args.uniforms.color = 0; args.uniforms.light = 256; args.uniforms.flags = TriUniforms::fixed_light; + args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w); for (auto &portal : SectorPortals) { @@ -253,6 +254,7 @@ void RenderPolyPortal::RenderTranslucent(int portalDepth) args.mode = TriangleDrawMode::Fan; args.stenciltestvalue = portal->StencilValue + 1; args.stencilwritevalue = StencilValue; + args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w); for (const auto &verts : portal->Shape) { args.vinput = verts.Vertices; @@ -273,6 +275,7 @@ void RenderPolyPortal::RenderTranslucent(int portalDepth) args.mode = TriangleDrawMode::Fan; args.stenciltestvalue = portal->StencilValue + 1; args.stencilwritevalue = StencilValue; + args.SetClipPlane(PortalPlane.x, PortalPlane.y, PortalPlane.z, PortalPlane.w); for (const auto &verts : portal->Shape) { args.vinput = verts.Vertices; @@ -290,21 +293,21 @@ void RenderPolyPortal::RenderTranslucent(int portalDepth) if (obj.particle) { RenderPolyParticle spr; - spr.Render(WorldToClip, obj.particle, obj.sub, obj.subsectorDepth, StencilValue + 1); + spr.Render(WorldToClip, PortalPlane, obj.particle, obj.sub, obj.subsectorDepth, StencilValue + 1); } else if (!obj.thing) { - obj.wall.Render(WorldToClip); + obj.wall.Render(WorldToClip, PortalPlane); } else if ((obj.thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { RenderPolyWallSprite wallspr; - wallspr.Render(WorldToClip, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1); + wallspr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1); } else { RenderPolySprite spr; - spr.Render(WorldToClip, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1); + spr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1); } } } @@ -341,7 +344,7 @@ void PolyDrawSectorPortal::Render(int portalDepth) TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z); TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; - RenderPortal.SetViewpoint(worldToClip, Vec4f(0.0f), StencilValue); + RenderPortal.SetViewpoint(worldToClip, Vec4f(0.0f, 0.0f, 0.0f, 1.0f), StencilValue); RenderPortal.Render(portalDepth); RestoreGlobals(); @@ -445,7 +448,7 @@ void PolyDrawLinePortal::Render(int portalDepth) DVector2 planePos = Portal->mDestination->v1->fPos(); DVector2 planeNormal = (Portal->mDestination->v2->fPos() - Portal->mDestination->v1->fPos()).Rotated90CW(); planeNormal.MakeUnit(); - double planeD = -(planeNormal | (planePos + planeNormal * 5.0)); + double planeD = -(planeNormal | (planePos + planeNormal * 0.001)); Vec4f portalPlane((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD); RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue); diff --git a/src/r_poly_sky.cpp b/src/r_poly_sky.cpp index 97f8203fa..c0a219c79 100644 --- a/src/r_poly_sky.cpp +++ b/src/r_poly_sky.cpp @@ -61,6 +61,7 @@ void PolySkyDome::Render(const TriMatrix &worldToClip) args.stencilwritevalue = 255; args.SetTexture(frontskytex); args.SetColormap(&NormalLight); + args.SetClipPlane(0.0f, 0.0f, 0.0f, 0.0f); RenderCapColorRow(args, frontskytex, 0, false); RenderCapColorRow(args, frontskytex, rc, true); diff --git a/src/r_poly_sprite.cpp b/src/r_poly_sprite.cpp index 0bacd6eb2..edb46c460 100644 --- a/src/r_poly_sprite.cpp +++ b/src/r_poly_sprite.cpp @@ -27,11 +27,12 @@ #include "r_data/r_translate.h" #include "r_poly_sprite.h" #include "r_poly.h" +#include "r_poly_intersection.h" EXTERN_CVAR(Float, transsouls) EXTERN_CVAR(Int, r_drawfuzz) -void RenderPolySprite::Render(const TriMatrix &worldToClip, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) +void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) { if (IsThingCulled(thing)) return; @@ -138,6 +139,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, AActor *thing, subse args.stencilwritevalue = stencilValue; args.SetTexture(tex, thing->Translation); args.SetColormap(sub->sector->ColorMap); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); TriBlendMode blendmode; diff --git a/src/r_poly_sprite.h b/src/r_poly_sprite.h index e23d0d09d..04b0fcb94 100644 --- a/src/r_poly_sprite.h +++ b/src/r_poly_sprite.h @@ -24,10 +24,12 @@ #include "r_poly_triangle.h" +class Vec4f; + class RenderPolySprite { public: - void Render(const TriMatrix &worldToClip, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); static bool IsThingCulled(AActor *thing); static FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX); diff --git a/src/r_poly_triangle.cpp b/src/r_poly_triangle.cpp index 298c5f024..f08d060e8 100644 --- a/src/r_poly_triangle.cpp +++ b/src/r_poly_triangle.cpp @@ -119,34 +119,34 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, TriDrawVarian const TriVertex *vinput = drawargs.vinput; int vcount = drawargs.vcount; - TriVertex vert[3]; + ShadedTriVertex vert[3]; if (drawargs.mode == TriangleDrawMode::Normal) { for (int i = 0; i < vcount / 3; i++) { for (int j = 0; j < 3; j++) - vert[j] = shade_vertex(*drawargs.objectToClip, *(vinput++)); + vert[j] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); draw_shaded_triangle(vert, ccw, &args, thread, drawfunc); } } else if (drawargs.mode == TriangleDrawMode::Fan) { - vert[0] = shade_vertex(*drawargs.objectToClip, *(vinput++)); - vert[1] = shade_vertex(*drawargs.objectToClip, *(vinput++)); + vert[0] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); + vert[1] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); for (int i = 2; i < vcount; i++) { - vert[2] = shade_vertex(*drawargs.objectToClip, *(vinput++)); + vert[2] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); draw_shaded_triangle(vert, ccw, &args, thread, drawfunc); vert[1] = vert[2]; } } else // TriangleDrawMode::Strip { - vert[0] = shade_vertex(*drawargs.objectToClip, *(vinput++)); - vert[1] = shade_vertex(*drawargs.objectToClip, *(vinput++)); + vert[0] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); + vert[1] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); for (int i = 2; i < vcount; i++) { - vert[2] = shade_vertex(*drawargs.objectToClip, *(vinput++)); + vert[2] = shade_vertex(*drawargs.objectToClip, drawargs.clipPlane, *(vinput++)); draw_shaded_triangle(vert, ccw, &args, thread, drawfunc); vert[0] = vert[1]; vert[1] = vert[2]; @@ -155,13 +155,18 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, TriDrawVarian } } -TriVertex PolyTriangleDrawer::shade_vertex(const TriMatrix &objectToClip, TriVertex v) +ShadedTriVertex PolyTriangleDrawer::shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v) { // Apply transform to get clip coordinates: - return objectToClip * v; + ShadedTriVertex sv = objectToClip * v; + + // Calculate gl_ClipDistance[0] + sv.clipDistance0 = v.x * clipPlane[0] + v.y * clipPlane[1] + v.z * clipPlane[2] + v.w * clipPlane[3]; + + return sv; } -void PolyTriangleDrawer::draw_shaded_triangle(const TriVertex *vert, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread, void(*drawfunc)(const TriDrawTriangleArgs *, WorkerThreadData *)) +void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread, void(*drawfunc)(const TriDrawTriangleArgs *, WorkerThreadData *)) { // Cull, clip and generate additional vertices as needed TriVertex clippedvert[max_additional_vertices]; @@ -225,7 +230,7 @@ bool PolyTriangleDrawer::cullhalfspace(float clipdistance1, float clipdistance2, return false; } -void PolyTriangleDrawer::clipedge(const TriVertex *verts, TriVertex *clippedvert, int &numclipvert) +void PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippedvert, int &numclipvert) { // Clip and cull so that the following is true for all vertices: // -v.w <= v.x <= v.w @@ -243,16 +248,18 @@ void PolyTriangleDrawer::clipedge(const TriVertex *verts, TriVertex *clippedvert } // halfspace clip distances - float clipdistance[6 * 3]; + static const int numclipdistances = 7; + float clipdistance[numclipdistances * 3]; for (int i = 0; i < 3; i++) { const auto &v = verts[i]; - clipdistance[i * 6 + 0] = v.x + v.w; - clipdistance[i * 6 + 1] = v.w - v.x; - clipdistance[i * 6 + 2] = v.y + v.w; - clipdistance[i * 6 + 3] = v.w - v.y; - clipdistance[i * 6 + 4] = v.z + v.w; - clipdistance[i * 6 + 5] = v.w - v.z; + clipdistance[i * numclipdistances + 0] = v.x + v.w; + clipdistance[i * numclipdistances + 1] = v.w - v.x; + clipdistance[i * numclipdistances + 2] = v.y + v.w; + clipdistance[i * numclipdistances + 3] = v.w - v.y; + clipdistance[i * numclipdistances + 4] = v.z + v.w; + clipdistance[i * numclipdistances + 5] = v.w - v.z; + clipdistance[i * numclipdistances + 6] = v.clipDistance0; } // Clip against each halfspace @@ -260,7 +267,7 @@ void PolyTriangleDrawer::clipedge(const TriVertex *verts, TriVertex *clippedvert float *output = weights + max_additional_vertices * 3; int inputverts = 3; int outputverts = 0; - for (int p = 0; p < 6; p++) + for (int p = 0; p < numclipdistances; p++) { // Clip each edge outputverts = 0; @@ -268,14 +275,14 @@ void PolyTriangleDrawer::clipedge(const TriVertex *verts, TriVertex *clippedvert { int j = (i + 1) % inputverts; float clipdistance1 = - clipdistance[0 * 6 + p] * input[i * 3 + 0] + - clipdistance[1 * 6 + p] * input[i * 3 + 1] + - clipdistance[2 * 6 + p] * input[i * 3 + 2]; + clipdistance[0 * numclipdistances + p] * input[i * 3 + 0] + + clipdistance[1 * numclipdistances + p] * input[i * 3 + 1] + + clipdistance[2 * numclipdistances + p] * input[i * 3 + 2]; float clipdistance2 = - clipdistance[0 * 6 + p] * input[j * 3 + 0] + - clipdistance[1 * 6 + p] * input[j * 3 + 1] + - clipdistance[2 * 6 + p] * input[j * 3 + 2]; + clipdistance[0 * numclipdistances + p] * input[j * 3 + 0] + + clipdistance[1 * numclipdistances + p] * input[j * 3 + 1] + + clipdistance[2 * numclipdistances + p] * input[j * 3 + 2]; float t1, t2; if (!cullhalfspace(clipdistance1, clipdistance2, t1, t2) && outputverts + 1 < max_additional_vertices) @@ -512,17 +519,20 @@ TriMatrix TriMatrix::operator*(const TriMatrix &mult) const return result; } -TriVertex TriMatrix::operator*(TriVertex v) const +ShadedTriVertex TriMatrix::operator*(TriVertex v) const { float vx = matrix[0 * 4 + 0] * v.x + matrix[1 * 4 + 0] * v.y + matrix[2 * 4 + 0] * v.z + matrix[3 * 4 + 0] * v.w; float vy = matrix[0 * 4 + 1] * v.x + matrix[1 * 4 + 1] * v.y + matrix[2 * 4 + 1] * v.z + matrix[3 * 4 + 1] * v.w; float vz = matrix[0 * 4 + 2] * v.x + matrix[1 * 4 + 2] * v.y + matrix[2 * 4 + 2] * v.z + matrix[3 * 4 + 2] * v.w; float vw = matrix[0 * 4 + 3] * v.x + matrix[1 * 4 + 3] * v.y + matrix[2 * 4 + 3] * v.z + matrix[3 * 4 + 3] * v.w; - v.x = vx; - v.y = vy; - v.z = vz; - v.w = vw; - return v; + ShadedTriVertex sv; + sv.x = vx; + sv.y = vy; + sv.z = vz; + sv.w = vw; + for (int i = 0; i < TriVertex::NumVarying; i++) + sv.varying[i] = v.varying[i]; + return sv; } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/r_poly_triangle.h b/src/r_poly_triangle.h index 8fef11e99..270dda894 100644 --- a/src/r_poly_triangle.h +++ b/src/r_poly_triangle.h @@ -38,6 +38,7 @@ enum class TriangleDrawMode }; struct TriDrawTriangleArgs; +struct TriMatrix; class PolyDrawArgs { @@ -55,6 +56,15 @@ public: uint8_t stenciltestvalue = 0; uint8_t stencilwritevalue = 0; const uint8_t *colormaps = nullptr; + float clipPlane[4]; + + void SetClipPlane(float a, float b, float c, float d) + { + clipPlane[0] = a; + clipPlane[1] = b; + clipPlane[2] = c; + clipPlane[3] = d; + } void SetTexture(FTexture *texture) { @@ -118,6 +128,31 @@ public: } }; +struct ShadedTriVertex : public TriVertex +{ + float clipDistance0; +}; + +struct TriMatrix +{ + static TriMatrix null(); + static TriMatrix identity(); + static TriMatrix translate(float x, float y, float z); + static TriMatrix scale(float x, float y, float z); + static TriMatrix rotate(float angle, float x, float y, float z); + static TriMatrix swapYZ(); + static TriMatrix perspective(float fovy, float aspect, float near, float far); + static TriMatrix frustum(float left, float right, float bottom, float top, float near, float far); + + static TriMatrix worldToView(); // Software renderer world to view space transform + static TriMatrix viewToClip(); // Software renderer shearing projection + + ShadedTriVertex operator*(TriVertex v) const; + TriMatrix operator*(const TriMatrix &m) const; + + float matrix[16]; +}; + class PolyTriangleDrawer { public: @@ -125,11 +160,11 @@ public: static void draw(const PolyDrawArgs &args, TriDrawVariant variant, TriBlendMode blendmode); private: - static TriVertex shade_vertex(const TriMatrix &objectToClip, TriVertex v); + static ShadedTriVertex shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v); static void draw_arrays(const PolyDrawArgs &args, TriDrawVariant variant, TriBlendMode blendmode, WorkerThreadData *thread); - static void draw_shaded_triangle(const TriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread, void(*drawfunc)(const TriDrawTriangleArgs *, WorkerThreadData *)); + static void draw_shaded_triangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread, void(*drawfunc)(const TriDrawTriangleArgs *, WorkerThreadData *)); static bool cullhalfspace(float clipdistance1, float clipdistance2, float &t1, float &t2); - static void clipedge(const TriVertex *verts, TriVertex *clippedvert, int &numclipvert); + static void clipedge(const ShadedTriVertex *verts, TriVertex *clippedvert, int &numclipvert); static int viewport_x, viewport_y, viewport_width, viewport_height, dest_pitch, dest_width, dest_height; static bool dest_bgra; diff --git a/src/r_poly_wall.cpp b/src/r_poly_wall.cpp index 6e09faa8a..cd4d32077 100644 --- a/src/r_poly_wall.cpp +++ b/src/r_poly_wall.cpp @@ -35,7 +35,7 @@ EXTERN_CVAR(Bool, r_drawmirrors) -bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals) +bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals) { PolyDrawLinePortal *polyportal = nullptr; if (line->backsector == nullptr && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors)) @@ -85,7 +85,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, secto wall.UnpeggedCeil = frontceilz1; wall.Texpart = side_t::mid; wall.Polyportal = polyportal; - wall.Render(worldToClip); + wall.Render(worldToClip, clipPlane); return true; } } @@ -120,7 +120,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, secto wall.BottomZ = topfloorz1; wall.UnpeggedCeil = topceilz1; wall.Texpart = side_t::top; - wall.Render(worldToClip); + wall.Render(worldToClip, clipPlane); } if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef) @@ -130,7 +130,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, secto wall.BottomZ = bottomfloorz2; wall.UnpeggedCeil = topceilz1; wall.Texpart = side_t::bottom; - wall.Render(worldToClip); + wall.Render(worldToClip, clipPlane); } if (line->sidedef) @@ -149,14 +149,14 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, seg_t *line, secto if (polyportal) { wall.Polyportal = polyportal; - wall.Render(worldToClip); + wall.Render(worldToClip, clipPlane); } } } return polyportal != nullptr; } -void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput) +void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput) { double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1); double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1); @@ -176,7 +176,7 @@ void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, seg_t *line wall.BottomZ = frontfloorz1; wall.UnpeggedCeil = frontceilz1; wall.Texpart = side_t::mid; - wall.Render(worldToClip); + wall.Render(worldToClip, clipPlane); } void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2) @@ -189,7 +189,7 @@ void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ce this->floor2 = floor2; } -void RenderPolyWall::Render(const TriMatrix &worldToClip) +void RenderPolyWall::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane) { FTexture *tex = GetTexture(); if (!tex && !Polyportal) @@ -253,6 +253,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip) if (tex) args.SetTexture(tex); args.SetColormap(Line->frontsector->ColorMap); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); if (Polyportal) { @@ -275,7 +276,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip) PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector, TriBlendMode::Add); } - RenderPolyDecal::RenderWallDecals(worldToClip, LineSeg, SubsectorDepth, StencilValue); + RenderPolyDecal::RenderWallDecals(worldToClip, clipPlane, LineSeg, SubsectorDepth, StencilValue); } void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2) diff --git a/src/r_poly_wall.h b/src/r_poly_wall.h index d1196df9f..bcecd5a05 100644 --- a/src/r_poly_wall.h +++ b/src/r_poly_wall.h @@ -26,15 +26,16 @@ class PolyTranslucentObject; class PolyDrawLinePortal; +class Vec4f; class RenderPolyWall { public: - static bool RenderLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); - static void Render3DFloorLine(const TriMatrix &worldToClip, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput); + static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector &translucentWallsOutput, std::vector> &linePortals); + static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector &translucentWallsOutput); void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2); - void Render(const TriMatrix &worldToClip); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane); DVector2 v1; DVector2 v2; diff --git a/src/r_poly_wallsprite.cpp b/src/r_poly_wallsprite.cpp index c8e0abcc4..351e24e36 100644 --- a/src/r_poly_wallsprite.cpp +++ b/src/r_poly_wallsprite.cpp @@ -28,7 +28,7 @@ #include "r_poly_wallsprite.h" #include "r_poly.h" -void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) +void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) { if (RenderPolySprite::IsThingCulled(thing)) return; @@ -120,5 +120,6 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, AActor *thing, s args.stencilwritevalue = stencilValue; args.SetTexture(tex); args.SetColormap(sub->sector->ColorMap); + args.SetClipPlane(clipPlane.x, clipPlane.y, clipPlane.z, clipPlane.w); PolyTriangleDrawer::draw(args, TriDrawVariant::DrawSubsector, TriBlendMode::AlphaBlend); } diff --git a/src/r_poly_wallsprite.h b/src/r_poly_wallsprite.h index 2942d6994..51cf28de6 100644 --- a/src/r_poly_wallsprite.h +++ b/src/r_poly_wallsprite.h @@ -24,8 +24,10 @@ #include "r_poly_triangle.h" +class Vec4f; + class RenderPolyWallSprite { public: - void Render(const TriMatrix &worldToClip, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); + void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue); };