diff --git a/src/r_poly.cpp b/src/r_poly.cpp index a823d94f7..978e0a1f4 100644 --- a/src/r_poly.cpp +++ b/src/r_poly.cpp @@ -47,6 +47,10 @@ void RenderPolyBsp::Render() SolidSegments.push_back({ -0x7fff, 0 }); SolidSegments.push_back({ viewwidth, 0x7fff }); + SectorSpriteRanges.clear(); + SectorSpriteRanges.resize(numsectors); + SortedSprites.clear(); + // Perspective correct: float ratio = WidescreenRatio; float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio; @@ -174,8 +178,10 @@ void RenderPolyBsp::RenderSubsector(subsector_t *sub) PolyTriangleDrawer::draw(uniforms, vertices, sub->numlines, TriangleDrawMode::Fan, true, 0, viewwidth, 0, viewheight, ceiltex); } - for (AActor *thing = sub->sector->thinglist; thing != nullptr; thing = thing->snext) + SpriteRange sprites = GetSpritesForSector(sub->sector); + for (int i = 0; i < sprites.Count; i++) { + AActor *thing = SortedSprites[sprites.Start + i].Thing; if ((thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) AddWallSprite(thing, sub); else @@ -183,6 +189,26 @@ void RenderPolyBsp::RenderSubsector(subsector_t *sub) } } +SpriteRange RenderPolyBsp::GetSpritesForSector(sector_t *sector) +{ + if (SectorSpriteRanges.size() < sector->sectornum || sector->sectornum < 0) + return SpriteRange(); + + auto &range = SectorSpriteRanges[sector->sectornum]; + if (range.Start == -1) + { + range.Start = (int)SortedSprites.size(); + range.Count = 0; + for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext) + { + SortedSprites.push_back({ thing, (thing->Pos() - ViewPos).LengthSquared() }); + range.Count++; + } + std::stable_sort(SortedSprites.begin() + range.Start, SortedSprites.begin() + range.Start + range.Count); + } + return range; +} + void RenderPolyBsp::AddLine(seg_t *line, sector_t *frontsector) { // Reject lines not facing viewer diff --git a/src/r_poly.h b/src/r_poly.h index 6248e02f7..7e26f8ce6 100644 --- a/src/r_poly.h +++ b/src/r_poly.h @@ -49,6 +49,26 @@ public: FDynamicColormap *Colormap = nullptr; }; +// Used for sorting things by distance to the camera +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 SpriteRange +{ +public: + SpriteRange() = default; + SpriteRange(int start, int count) : Start(start), Count(count) { } + int Start = -1; + int Count = 0; +}; + // Renders a GL BSP tree in a scene class RenderPolyBsp { @@ -67,6 +87,7 @@ private: bool IsThingCulled(AActor *thing); visstyle_t GetSpriteVisStyle(AActor *thing, double z); FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX); + SpriteRange GetSpritesForSector(sector_t *sector); void RenderPlayerSprites(); void RenderPlayerSprite(DPSprite *sprite, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac); @@ -85,6 +106,9 @@ private: std::vector PvsSectors; TriMatrix worldToClip; + std::vector SectorSpriteRanges; + std::vector SortedSprites; + std::vector ScreenSprites; const int BaseXCenter = 160;