mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-12 07:34:36 +00:00
Sprite line clipping by subsector
This commit is contained in:
parent
fc16f6bbbc
commit
71350f2c17
4 changed files with 118 additions and 75 deletions
|
@ -62,9 +62,8 @@ void RenderPolyPortal::Render(int portalDepth)
|
||||||
|
|
||||||
void RenderPolyPortal::ClearBuffers()
|
void RenderPolyPortal::ClearBuffers()
|
||||||
{
|
{
|
||||||
SectorSpriteRanges.clear();
|
SeenSectors.clear();
|
||||||
SectorSpriteRanges.resize(numsectors);
|
SubsectorDepths.clear();
|
||||||
SortedSprites.clear();
|
|
||||||
TranslucentObjects.clear();
|
TranslucentObjects.clear();
|
||||||
SectorPortals.clear();
|
SectorPortals.clear();
|
||||||
LinePortals.clear();
|
LinePortals.clear();
|
||||||
|
@ -117,35 +116,61 @@ void RenderPolyPortal::RenderSubsector(subsector_t *sub)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpriteRange sprites = GetSpritesForSector(sub->sector);
|
SeenSectors.insert(sub->sector);
|
||||||
for (int i = 0; i < sprites.Count; i++)
|
SubsectorDepths[sub] = subsectorDepth;
|
||||||
{
|
|
||||||
AActor *thing = SortedSprites[sprites.Start + i].Thing;
|
|
||||||
TranslucentObjects.push_back({ thing, sub, subsectorDepth });
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslucentObjects.insert(TranslucentObjects.end(), SubsectorTranslucentWalls.begin(), SubsectorTranslucentWalls.end());
|
|
||||||
SubsectorTranslucentWalls.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SpriteRange RenderPolyPortal::GetSpritesForSector(sector_t *sector)
|
void RenderPolyPortal::RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right)
|
||||||
{
|
{
|
||||||
if ((int)SectorSpriteRanges.size() < sector->sectornum || sector->sectornum < 0)
|
if (numnodes == 0)
|
||||||
return SpriteRange();
|
RenderSprite(thing, sortDistance, left, right, 0.0, 1.0, subsectors);
|
||||||
|
else
|
||||||
|
RenderSprite(thing, sortDistance, left, right, 0.0, 1.0, nodes + numnodes - 1); // The head node is the last node output.
|
||||||
|
}
|
||||||
|
|
||||||
auto &range = SectorSpriteRanges[sector->sectornum];
|
void RenderPolyPortal::RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node)
|
||||||
if (range.Start == -1)
|
{
|
||||||
|
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||||
{
|
{
|
||||||
range.Start = (int)SortedSprites.size();
|
node_t *bsp = (node_t *)node;
|
||||||
range.Count = 0;
|
|
||||||
for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext)
|
DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y));
|
||||||
|
DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx));
|
||||||
|
double planeD = planeNormal | planePos;
|
||||||
|
|
||||||
|
int sideLeft = (left | planeNormal) > planeD;
|
||||||
|
int sideRight = (right | planeNormal) > planeD;
|
||||||
|
|
||||||
|
if (sideLeft != sideRight)
|
||||||
{
|
{
|
||||||
SortedSprites.push_back({ thing, (thing->Pos() - ViewPos).LengthSquared() });
|
double dotLeft = planeNormal | left;
|
||||||
range.Count++;
|
double dotRight = planeNormal | right;
|
||||||
|
double t = (planeD - dotLeft) / (dotRight - dotLeft);
|
||||||
|
|
||||||
|
DVector2 mid = left * (1.0 - t) + right * t;
|
||||||
|
double tmid = t1 * (1.0 - t) + t2 * t;
|
||||||
|
|
||||||
|
if (sideLeft == 0)
|
||||||
|
{
|
||||||
|
RenderSprite(thing, sortDistance, mid, right, tmid, t2, bsp->children[sideRight]);
|
||||||
|
right = mid;
|
||||||
|
t2 = tmid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RenderSprite(thing, sortDistance, left, mid, t1, tmid, bsp->children[sideLeft]);
|
||||||
|
left = mid;
|
||||||
|
t1 = tmid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::stable_sort(SortedSprites.begin() + range.Start, SortedSprites.begin() + range.Start + range.Count);
|
node = bsp->children[sideLeft];
|
||||||
}
|
}
|
||||||
return range;
|
|
||||||
|
subsector_t *sub = (subsector_t *)((BYTE *)node - 1);
|
||||||
|
|
||||||
|
auto it = SubsectorDepths.find(sub);
|
||||||
|
if (it != SubsectorDepths.end())
|
||||||
|
TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, (float)t1, (float)t2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
|
void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
|
||||||
|
@ -178,12 +203,12 @@ void RenderPolyPortal::RenderLine(subsector_t *sub, seg_t *line, sector_t *front
|
||||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||||
if (!fakeFloor->model) continue;
|
if (!fakeFloor->model) continue;
|
||||||
RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, fakeFloor, SubsectorTranslucentWalls);
|
RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, fakeFloor, TranslucentObjects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render wall, and update culling info if its an occlusion blocker
|
// Render wall, and update culling info if its an occlusion blocker
|
||||||
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, SubsectorTranslucentWalls, LinePortals))
|
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals))
|
||||||
{
|
{
|
||||||
if (hasSegmentRange)
|
if (hasSegmentRange)
|
||||||
Cull.MarkSegmentCulled(sx1, sx2);
|
Cull.MarkSegmentCulled(sx1, sx2);
|
||||||
|
@ -287,6 +312,20 @@ void RenderPolyPortal::RenderTranslucent(int portalDepth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (sector_t *sector : SeenSectors)
|
||||||
|
{
|
||||||
|
for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext)
|
||||||
|
{
|
||||||
|
DVector2 left, right;
|
||||||
|
if (!RenderPolySprite::GetLine(thing, left, right))
|
||||||
|
continue;
|
||||||
|
double distanceSquared = (thing->Pos() - ViewPos).LengthSquared();
|
||||||
|
RenderSprite(thing, distanceSquared, left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end());
|
||||||
|
|
||||||
for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it)
|
for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it)
|
||||||
{
|
{
|
||||||
auto &obj = *it;
|
auto &obj = *it;
|
||||||
|
|
|
@ -38,40 +38,31 @@
|
||||||
#include "r_poly_particle.h"
|
#include "r_poly_particle.h"
|
||||||
#include "r_poly_plane.h"
|
#include "r_poly_plane.h"
|
||||||
#include "r_poly_cull.h"
|
#include "r_poly_cull.h"
|
||||||
|
#include <set>
|
||||||
// Used for sorting things by distance to the camera
|
#include <unordered_map>
|
||||||
class PolySortedSprite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PolySortedSprite(AActor *thing, double distanceSquared) : Thing(thing), DistanceSquared(distanceSquared) { }
|
|
||||||
bool operator<(const PolySortedSprite &other) const { return DistanceSquared < other.DistanceSquared; }
|
|
||||||
|
|
||||||
AActor *Thing;
|
|
||||||
double DistanceSquared;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PolyTranslucentObject
|
class PolyTranslucentObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PolyTranslucentObject(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth) : particle(particle), sub(sub), subsectorDepth(subsectorDepth) { }
|
PolyTranslucentObject(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth) : particle(particle), sub(sub), subsectorDepth(subsectorDepth) { }
|
||||||
PolyTranslucentObject(AActor *thing, subsector_t *sub, uint32_t subsectorDepth) : thing(thing), sub(sub), subsectorDepth(subsectorDepth) { }
|
PolyTranslucentObject(AActor *thing, subsector_t *sub, uint32_t subsectorDepth, double dist, float t1, float t2) : thing(thing), sub(sub), subsectorDepth(subsectorDepth), DistanceSquared(dist), SpriteLeft(t1), SpriteRight(t2) { }
|
||||||
PolyTranslucentObject(RenderPolyWall wall) : wall(wall) { }
|
PolyTranslucentObject(RenderPolyWall wall) : wall(wall) { }
|
||||||
|
|
||||||
|
bool operator<(const PolyTranslucentObject &other) const
|
||||||
|
{
|
||||||
|
return subsectorDepth != other.subsectorDepth ? subsectorDepth < other.subsectorDepth : DistanceSquared < other.DistanceSquared;
|
||||||
|
}
|
||||||
|
|
||||||
particle_t *particle = nullptr;
|
particle_t *particle = nullptr;
|
||||||
AActor *thing = nullptr;
|
AActor *thing = nullptr;
|
||||||
subsector_t *sub = nullptr;
|
subsector_t *sub = nullptr;
|
||||||
uint32_t subsectorDepth = 0;
|
|
||||||
|
|
||||||
RenderPolyWall wall;
|
RenderPolyWall wall;
|
||||||
};
|
|
||||||
|
uint32_t subsectorDepth = 0;
|
||||||
class SpriteRange
|
double DistanceSquared = 1.e6;
|
||||||
{
|
|
||||||
public:
|
float SpriteLeft = 0.0f, SpriteRight = 1.0f;
|
||||||
SpriteRange() = default;
|
|
||||||
SpriteRange(int start, int count) : Start(start), Count(count) { }
|
|
||||||
int Start = -1;
|
|
||||||
int Count = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PolyDrawSectorPortal;
|
class PolyDrawSectorPortal;
|
||||||
|
@ -95,18 +86,17 @@ private:
|
||||||
void RenderSectors();
|
void RenderSectors();
|
||||||
void RenderSubsector(subsector_t *sub);
|
void RenderSubsector(subsector_t *sub);
|
||||||
void RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
|
void RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
|
||||||
|
void RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right);
|
||||||
SpriteRange GetSpritesForSector(sector_t *sector);
|
void RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
|
||||||
|
|
||||||
TriMatrix WorldToClip;
|
TriMatrix WorldToClip;
|
||||||
Vec4f PortalPlane;
|
Vec4f PortalPlane;
|
||||||
uint32_t StencilValue = 0;
|
uint32_t StencilValue = 0;
|
||||||
PolyCull Cull;
|
PolyCull Cull;
|
||||||
uint32_t NextSubsectorDepth = 0;
|
uint32_t NextSubsectorDepth = 0;
|
||||||
std::vector<SpriteRange> SectorSpriteRanges;
|
std::set<sector_t *> SeenSectors;
|
||||||
std::vector<PolySortedSprite> SortedSprites;
|
std::unordered_map<subsector_t *, uint32_t> SubsectorDepths;
|
||||||
std::vector<PolyTranslucentObject> TranslucentObjects;
|
std::vector<PolyTranslucentObject> TranslucentObjects;
|
||||||
std::vector<PolyTranslucentObject> SubsectorTranslucentWalls;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
|
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
|
||||||
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
|
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
|
||||||
|
|
|
@ -32,11 +32,43 @@
|
||||||
EXTERN_CVAR(Float, transsouls)
|
EXTERN_CVAR(Float, transsouls)
|
||||||
EXTERN_CVAR(Int, r_drawfuzz)
|
EXTERN_CVAR(Int, r_drawfuzz)
|
||||||
|
|
||||||
void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
|
bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
|
||||||
{
|
{
|
||||||
if (IsThingCulled(thing))
|
if (IsThingCulled(thing))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
|
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
|
||||||
|
|
||||||
|
bool flipTextureX = false;
|
||||||
|
FTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||||
|
if (tex == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DVector2 spriteScale = thing->Scale;
|
||||||
|
double thingxscalemul = spriteScale.X / tex->Scale.X;
|
||||||
|
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
|
||||||
|
|
||||||
|
if (flipTextureX)
|
||||||
|
pos.X -= (tex->GetWidth() - tex->LeftOffset) * thingxscalemul;
|
||||||
|
else
|
||||||
|
pos.X -= tex->LeftOffset * thingxscalemul;
|
||||||
|
|
||||||
|
double spriteHalfWidth = thingxscalemul * tex->GetWidth() * 0.5;
|
||||||
|
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||||
|
|
||||||
|
pos.X += spriteHalfWidth;
|
||||||
|
|
||||||
|
left = DVector2(pos.X - ViewSin * spriteHalfWidth, pos.Y + ViewCos * spriteHalfWidth);
|
||||||
|
right = DVector2(pos.X + ViewSin * spriteHalfWidth, pos.Y - ViewCos * spriteHalfWidth);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
|
||||||
|
{
|
||||||
|
DVector2 points[2];
|
||||||
|
if (!GetLine(thing, points[0], points[1]))
|
||||||
|
return;
|
||||||
|
|
||||||
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
|
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
|
||||||
pos.Z += thing->GetBobOffset(r_TicFracF);
|
pos.Z += thing->GetBobOffset(r_TicFracF);
|
||||||
|
|
||||||
|
@ -44,6 +76,7 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla
|
||||||
FTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
FTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||||
if (tex == nullptr)
|
if (tex == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DVector2 spriteScale = thing->Scale;
|
DVector2 spriteScale = thing->Scale;
|
||||||
double thingxscalemul = spriteScale.X / tex->Scale.X;
|
double thingxscalemul = spriteScale.X / tex->Scale.X;
|
||||||
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
|
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
|
||||||
|
@ -61,26 +94,6 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const Vec4f &clipPla
|
||||||
|
|
||||||
pos.X += spriteHalfWidth;
|
pos.X += spriteHalfWidth;
|
||||||
|
|
||||||
DVector2 points[2] =
|
|
||||||
{
|
|
||||||
{ pos.X - ViewSin * spriteHalfWidth, pos.Y + ViewCos * spriteHalfWidth },
|
|
||||||
{ pos.X + ViewSin * spriteHalfWidth, pos.Y - ViewCos * spriteHalfWidth }
|
|
||||||
};
|
|
||||||
|
|
||||||
// Is this sprite inside? (To do: clip the points)
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
|
||||||
{
|
|
||||||
seg_t *line = &sub->firstline[i];
|
|
||||||
double nx = line->v1->fY() - line->v2->fY();
|
|
||||||
double ny = line->v2->fX() - line->v1->fX();
|
|
||||||
double d = -(line->v1->fX() * nx + line->v1->fY() * ny);
|
|
||||||
if (pos.X * nx + pos.Y * ny + d > 0.0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//double depth = 1.0;
|
//double depth = 1.0;
|
||||||
//visstyle_t visstyle = GetSpriteVisStyle(thing, depth);
|
//visstyle_t visstyle = GetSpriteVisStyle(thing, depth);
|
||||||
// Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
|
// Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
|
||||||
|
|
|
@ -31,6 +31,7 @@ class RenderPolySprite
|
||||||
public:
|
public:
|
||||||
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, 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 GetLine(AActor *thing, DVector2 &left, DVector2 &right);
|
||||||
static bool IsThingCulled(AActor *thing);
|
static bool IsThingCulled(AActor *thing);
|
||||||
static FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX);
|
static FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue