diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index 5c3d2c124..d0eaa86d5 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -319,16 +319,22 @@ namespace swrenderer side_t *sidedef = mLineSegment->sidedef; RenderPortal *renderportal = Thread->Portal.get(); + Clip3DFloors *clip3d = Thread->Clip3D.get(); DrawSegment *draw_segment = Thread->FrameMemory->NewObject(); - Thread->DrawSegments->Push(draw_segment); + + // 3D floors code abuses the line render code to update plane clipping + // lists but doesn't actually draw anything. + bool onlyUpdatePlaneClip = (clip3d->fake3D & FAKE3D_FAKEMASK) ? true : false; + if (!onlyUpdatePlaneClip) + Thread->DrawSegments->Push(draw_segment); draw_segment->CurrentPortalUniq = renderportal->CurrentPortalUniq; draw_segment->sx1 = WallC.sx1; draw_segment->sx2 = WallC.sx2; draw_segment->sz1 = WallC.sz1; draw_segment->sz2 = WallC.sz2; - draw_segment->cx = WallC.tleft.X;; + draw_segment->cx = WallC.tleft.X; draw_segment->cy = WallC.tleft.Y; draw_segment->cdx = WallC.tright.X - WallC.tleft.X; draw_segment->cdy = WallC.tright.Y - WallC.tleft.Y; @@ -338,20 +344,8 @@ namespace swrenderer draw_segment->x1 = start; draw_segment->x2 = stop; draw_segment->curline = mLineSegment; - draw_segment->bFogBoundary = false; - draw_segment->bFakeBoundary = false; draw_segment->foggy = foggy; - Clip3DFloors *clip3d = Thread->Clip3D.get(); - if (clip3d->fake3D & FAKE3D_FAKEMASK) draw_segment->fake = 1; - else draw_segment->fake = 0; - - draw_segment->sprtopclip = nullptr; - draw_segment->sprbottomclip = nullptr; - draw_segment->maskedtexturecol = nullptr; - draw_segment->bkup = nullptr; - draw_segment->swall = nullptr; - bool markportal = ShouldMarkPortal(); if (markportal) @@ -369,8 +363,6 @@ namespace swrenderer else { // two sided line - draw_segment->silhouette = 0; - if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0) { @@ -406,29 +398,32 @@ namespace swrenderer } } - if (!draw_segment->fake && r_3dfloors && mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) { - for (i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) { - F3DFloor *rover = mBackSector->e->XFloor.ffloors[i]; - if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) { - draw_segment->bFakeBoundary |= 1; - break; + if (!onlyUpdatePlaneClip && r_3dfloors) + { + if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) { + for (i = 0; i < (int)mBackSector->e->XFloor.ffloors.Size(); i++) { + F3DFloor *rover = mBackSector->e->XFloor.ffloors[i]; + if (rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) { + draw_segment->SetHas3DFloorBackSectorWalls(); + break; + } + } + } + if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) { + for (i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) { + F3DFloor *rover = mFrontSector->e->XFloor.ffloors[i]; + if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) { + draw_segment->SetHas3DFloorFrontSectorWalls(); + break; + } } } } - if (!draw_segment->fake && r_3dfloors && mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) { - for (i = 0; i < (int)mFrontSector->e->XFloor.ffloors.Size(); i++) { - F3DFloor *rover = mFrontSector->e->XFloor.ffloors[i]; - if (rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) { - draw_segment->bFakeBoundary |= 2; - break; - } - } - } - // kg3D - no for fakes - if (!draw_segment->fake) + + if (!onlyUpdatePlaneClip) // allocate space for masked texture tables, if needed // [RH] Don't just allocate the space; fill it in too. - if ((TexMan(sidedef->GetTexture(side_t::mid), true)->UseType != FTexture::TEX_Null || draw_segment->bFakeBoundary || IsFogBoundary(mFrontSector, mBackSector)) && + if ((TexMan(sidedef->GetTexture(side_t::mid), true)->UseType != FTexture::TEX_Null || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) && (mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) && (mFloorClipped != ProjectedWallCull::OutsideAbove || !sidedef->GetTexture(side_t::bottom).isValid()) && (WallC.sz1 >= TOO_CLOSE_Z && WallC.sz2 >= TOO_CLOSE_Z)) @@ -444,10 +439,10 @@ namespace swrenderer memcpy(draw_segment->bkup, &Thread->OpaquePass->ceilingclip[start], sizeof(short)*(stop - start)); draw_segment->bFogBoundary = IsFogBoundary(mFrontSector, mBackSector); - if (sidedef->GetTexture(side_t::mid).isValid() || draw_segment->bFakeBoundary) + if (sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls()) { if (sidedef->GetTexture(side_t::mid).isValid()) - draw_segment->bFakeBoundary |= 4; // it is also mid texture + draw_segment->SetHas3DFloorMidTexture(); draw_segment->maskedtexturecol = Thread->FrameMemory->AllocMemory(stop - start); draw_segment->swall = Thread->FrameMemory->AllocMemory(stop - start); @@ -510,7 +505,7 @@ namespace swrenderer if (draw_segment->bFogBoundary || draw_segment->maskedtexturecol != nullptr) { - Thread->DrawSegments->PushInteresting(draw_segment); + Thread->DrawSegments->PushTranslucent(draw_segment); } } } diff --git a/src/swrenderer/line/r_renderdrawsegment.cpp b/src/swrenderer/line/r_renderdrawsegment.cpp index 47fa2fb76..89c73455c 100644 --- a/src/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/swrenderer/line/r_renderdrawsegment.cpp @@ -79,7 +79,7 @@ namespace swrenderer FDynamicColormap *patchstylecolormap = nullptr; bool visible = columndrawerargs.SetStyle(viewport, LegacyRenderStyles[additive ? STYLE_Add : STYLE_Translucent], alpha, 0, 0, patchstylecolormap); - if (!visible && !ds->bFogBoundary && !ds->bFakeBoundary) + if (!visible && !ds->bFogBoundary && !ds->Has3DFloorWalls()) { return; } @@ -139,7 +139,7 @@ namespace swrenderer if (ds->maskedtexturecol == nullptr) renderwall = false; } - else if ((ds->bFakeBoundary && !(ds->bFakeBoundary & 4)) || !visible) + else if ((ds->Has3DFloorWalls() && !ds->Has3DFloorMidTexture()) || !visible) { renderwall = false; } @@ -147,7 +147,7 @@ namespace swrenderer if (renderwall) notrelevant = RenderWall(ds, x1, x2, walldrawerargs, columndrawerargs, visible, basecolormap, wallshade, wrap); - if (ds->bFakeBoundary & 3) + if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls()) { RenderFakeWallRange(ds, x1, x2, wallshade); } @@ -540,7 +540,7 @@ namespace swrenderer { return; } - if ((ds->bFakeBoundary & 3) == 2) + if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls()) { sector_t *sec = backsector; backsector = frontsector; @@ -709,7 +709,7 @@ namespace swrenderer CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedLightLevel() < 0) { - if ((ds->bFakeBoundary & 3) == 2) + if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls()) { for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--) { @@ -888,7 +888,7 @@ namespace swrenderer CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedLightLevel() < 0) { - if ((ds->bFakeBoundary & 3) == 2) + if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls()) { for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--) { diff --git a/src/swrenderer/r_renderthread.cpp b/src/swrenderer/r_renderthread.cpp index fa20da456..bb2816a94 100644 --- a/src/swrenderer/r_renderthread.cpp +++ b/src/swrenderer/r_renderthread.cpp @@ -103,23 +103,28 @@ namespace swrenderer // calls to GetPixels for this to work. static std::mutex loadmutex; - loadmutex.lock(); - try + + std::unique_lock lock(loadmutex); + + texture->GetPixels(); + const FTexture::Span *spans; + texture->GetColumn(0, &spans); + if (Viewport->RenderTarget->IsBgra()) { - texture->GetPixels(); - const FTexture::Span *spans; - texture->GetColumn(0, &spans); - if (Viewport->RenderTarget->IsBgra()) - { - texture->GetPixelsBgra(); - texture->GetColumnBgra(0, &spans); - } - loadmutex.unlock(); + texture->GetPixelsBgra(); + texture->GetColumnBgra(0, &spans); } - catch (...) + } + + void RenderThread::PreparePolyObject(subsector_t *sub) + { + static std::mutex polyobjmutex; + + std::unique_lock lock(polyobjmutex); + + if (sub->BSP == nullptr || sub->BSP->bDirty) { - loadmutex.unlock(); - throw; + sub->BuildPolyBSP(); } } } diff --git a/src/swrenderer/r_renderthread.h b/src/swrenderer/r_renderthread.h index 3a439421c..6bc23bba5 100644 --- a/src/swrenderer/r_renderthread.h +++ b/src/swrenderer/r_renderthread.h @@ -83,6 +83,9 @@ namespace swrenderer // Make sure texture can accessed safely void PrepareTexture(FTexture *texture); + + // Setup poly object in a threadsafe manner + void PreparePolyObject(subsector_t *sub); private: std::unique_ptr tc_drawers; diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index bebb9580f..1dbd7cc9f 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -404,10 +404,8 @@ namespace swrenderer void RenderOpaquePass::AddPolyobjs(subsector_t *sub) { - if (sub->BSP == nullptr || sub->BSP->bDirty) - { - sub->BuildPolyBSP(); - } + Thread->PreparePolyObject(sub); + if (sub->BSP->Nodes.Size() == 0) { RenderSubsector(&sub->BSP->Subsectors[0]); diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index 9e9a347a4..6c585d13a 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -217,7 +217,6 @@ namespace swrenderer draw_segment->swall = nullptr; draw_segment->bFogBoundary = false; draw_segment->curline = nullptr; - draw_segment->fake = 0; draw_segment->foggy = false; memcpy(draw_segment->sprbottomclip, floorclip + pl->left, (pl->right - pl->left) * sizeof(short)); memcpy(draw_segment->sprtopclip, ceilingclip + pl->left, (pl->right - pl->left) * sizeof(short)); @@ -528,8 +527,8 @@ namespace swrenderer void RenderPortal::SetMainPortal() { - WindowLeft = 0; - WindowRight = viewwidth; + WindowLeft = Thread->X1; + WindowRight = Thread->X2; MirrorFlags = 0; CurrentPortal = nullptr; CurrentPortalUniq = 0; diff --git a/src/swrenderer/scene/r_translucent_pass.cpp b/src/swrenderer/scene/r_translucent_pass.cpp index b395e0b6d..e08486ef9 100644 --- a/src/swrenderer/scene/r_translucent_pass.cpp +++ b/src/swrenderer/scene/r_translucent_pass.cpp @@ -136,37 +136,11 @@ namespace swrenderer RenderPortal *renderportal = Thread->Portal.get(); DrawSegmentList *drawseglist = Thread->DrawSegments.get(); - int numGroups = drawseglist->SegmentGroups.Size(); - for (int j = 0; j < numGroups; j++) - drawseglist->SegmentGroups[j].GroupDrawn = false; - auto &sortedSprites = Thread->SpriteList->SortedSprites; for (int i = sortedSprites.Size(); i > 0; i--) { VisibleSprite *sprite = sortedSprites[i - 1]; - // Draw the draw segments known to be behind us now. - for (int j = numGroups; j > 0; j--) - { - auto &group = drawseglist->SegmentGroups[j - 1]; - if (!group.GroupDrawn && group.neardepth > sprite->DrawSegDepth()) - { - for (unsigned int index = group.BeginIndex; index != group.EndIndex; index++) - { - DrawSegment *ds = drawseglist->Segment(index); - - if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq) continue; - if (ds->fake) continue; - if (ds->maskedtexturecol != nullptr || ds->bFogBoundary) - { - RenderDrawSegment renderer(Thread); - renderer.Render(ds, ds->x1, ds->x2); - } - } - group.GroupDrawn = true; - } - } - if (sprite->IsCurrentPortalUniq(renderportal->CurrentPortalUniq)) { sprite->Render(Thread); @@ -187,8 +161,6 @@ namespace swrenderer // [ZZ] the same as above if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq) continue; - // kg3D - no fake segs - if (ds->fake) continue; if (ds->maskedtexturecol != nullptr || ds->bFogBoundary) { RenderDrawSegment renderer(Thread); diff --git a/src/swrenderer/segments/r_drawsegment.cpp b/src/swrenderer/segments/r_drawsegment.cpp index 6d8d50707..76b13df97 100644 --- a/src/swrenderer/segments/r_drawsegment.cpp +++ b/src/swrenderer/segments/r_drawsegment.cpp @@ -63,15 +63,15 @@ namespace swrenderer StartIndices.Clear(); StartIndices.Push(0); - InterestingSegments.Clear(); - StartInterestingIndices.Clear(); - StartInterestingIndices.Push(0); + TranslucentSegments.Clear(); + StartTranslucentIndices.Clear(); + StartTranslucentIndices.Push(0); } void DrawSegmentList::PushPortal() { StartIndices.Push(Segments.Size()); - StartInterestingIndices.Push(InterestingSegments.Size()); + StartTranslucentIndices.Push(TranslucentSegments.Size()); } void DrawSegmentList::PopPortal() @@ -79,8 +79,8 @@ namespace swrenderer Segments.Resize(StartIndices.Last()); StartIndices.Pop(); - InterestingSegments.Resize(StartInterestingIndices.Last()); - StartInterestingIndices.Pop(); + TranslucentSegments.Resize(StartTranslucentIndices.Last()); + StartTranslucentIndices.Pop(); } void DrawSegmentList::Push(DrawSegment *segment) @@ -88,9 +88,9 @@ namespace swrenderer Segments.Push(segment); } - void DrawSegmentList::PushInteresting(DrawSegment *segment) + void DrawSegmentList::PushTranslucent(DrawSegment *segment) { - InterestingSegments.Push(segment); + TranslucentSegments.Push(segment); } void DrawSegmentList::BuildSegmentGroups() @@ -131,9 +131,6 @@ namespace swrenderer { ds = Segment(groupIndex); - // kg3D - no clipping on fake segs - if (ds->fake) continue; - if (ds->silhouette & SIL_BOTTOM) { short *clip1 = clipbottom + ds->x1; diff --git a/src/swrenderer/segments/r_drawsegment.h b/src/swrenderer/segments/r_drawsegment.h index 2c6fcdaa7..c29b3a67a 100644 --- a/src/swrenderer/segments/r_drawsegment.h +++ b/src/swrenderer/segments/r_drawsegment.h @@ -36,23 +36,33 @@ namespace swrenderer float siz1, siz2; // 1/z for left, right of parent seg on screen float cx, cy, cdx, cdy; float yscale; - uint8_t silhouette; // 0=none, 1=bottom, 2=top, 3=both - uint8_t bFogBoundary; - uint8_t bFakeBoundary; // for fake walls - int shade; - bool foggy; + uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both + bool bFogBoundary = false; + int shade = 0; + bool foggy = false; // Pointers to lists for sprite clipping, all three adjusted so [x1] is first value. - short *sprtopclip; - short *sprbottomclip; - fixed_t *maskedtexturecol; - float *swall; - short *bkup; // sprtopclip backup, for mid and fake textures + short *sprtopclip = nullptr; + short *sprbottomclip = nullptr; + fixed_t *maskedtexturecol = nullptr; + float *swall = nullptr; + short *bkup = nullptr; // sprtopclip backup, for mid and fake textures FWallTmapVals tmapvals; - int fake; // ident fake drawseg, don't draw and clip sprites backups - int CurrentPortalUniq; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. + int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping. + + bool Has3DFloorWalls() const { return b3DFloorBoundary != 0; } + bool Has3DFloorFrontSectorWalls() const { return (b3DFloorBoundary & 2) == 2; } + bool Has3DFloorBackSectorWalls() const { return (b3DFloorBoundary & 1) == 1; } + bool Has3DFloorMidTexture() const { return (b3DFloorBoundary & 4) == 4; } + + void SetHas3DFloorFrontSectorWalls() { b3DFloorBoundary |= 2; } + void SetHas3DFloorBackSectorWalls() { b3DFloorBoundary |= 1; } + void SetHas3DFloorMidTexture() { b3DFloorBoundary |= 4; } + + private: + uint8_t b3DFloorBoundary = 0; // 1=backsector, 2=frontsector, 4=midtexture }; struct DrawSegmentGroup @@ -63,7 +73,6 @@ namespace swrenderer short *sprbottomclip; unsigned int BeginIndex; unsigned int EndIndex; - bool GroupDrawn; }; class DrawSegmentList @@ -76,14 +85,14 @@ namespace swrenderer unsigned int SegmentsCount() const { return Segments.Size() - StartIndices.Last(); } DrawSegment *Segment(unsigned int index) const { return Segments[Segments.Size() - 1 - index]; } - unsigned int InterestingSegmentsCount() const { return InterestingSegments.Size() - StartInterestingIndices.Last(); } - DrawSegment *InterestingSegment(unsigned int index) const { return InterestingSegments[InterestingSegments.Size() - 1 - index]; } + unsigned int TranslucentSegmentsCount() const { return TranslucentSegments.Size() - StartTranslucentIndices.Last(); } + DrawSegment *TranslucentSegment(unsigned int index) const { return TranslucentSegments[TranslucentSegments.Size() - 1 - index]; } void Clear(); void PushPortal(); void PopPortal(); void Push(DrawSegment *segment); - void PushInteresting(DrawSegment *segment); + void PushTranslucent(DrawSegment *segment); void BuildSegmentGroups(); @@ -93,8 +102,8 @@ namespace swrenderer TArray Segments; TArray StartIndices; - TArray InterestingSegments; // drawsegs that have something drawn on them - TArray StartInterestingIndices; + TArray TranslucentSegments; // drawsegs that have something drawn on them + TArray StartTranslucentIndices; // For building segment groups short cliptop[MAXWIDTH]; diff --git a/src/swrenderer/things/r_particle.cpp b/src/swrenderer/things/r_particle.cpp index fee9a39c0..33d2a6d09 100644 --- a/src/swrenderer/things/r_particle.cpp +++ b/src/swrenderer/things/r_particle.cpp @@ -275,12 +275,10 @@ namespace swrenderer // Draw any masked textures behind this particle so that when the // particle is drawn, it will be in front of them. DrawSegmentList *segmentlist = thread->DrawSegments.get(); - for (unsigned int index = 0; index != segmentlist->InterestingSegmentsCount(); index++) + for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) { - DrawSegment *ds = segmentlist->InterestingSegment(index); + DrawSegment *ds = segmentlist->TranslucentSegment(index); - // kg3D - no fake segs - if (ds->fake) continue; if (ds->x1 >= x2 || ds->x2 <= x1) { continue; diff --git a/src/swrenderer/things/r_visiblesprite.cpp b/src/swrenderer/things/r_visiblesprite.cpp index f7ae8547b..e9ddec275 100644 --- a/src/swrenderer/things/r_visiblesprite.cpp +++ b/src/swrenderer/things/r_visiblesprite.cpp @@ -58,7 +58,6 @@ namespace swrenderer int i; int x1, x2; - int r1, r2; short topclip, botclip; short *clip1, *clip2; FSWColormap *colormap = spr->Light.BaseColormap; @@ -85,10 +84,6 @@ namespace swrenderer if (x1 >= x2) return; - // Reject sprites outside the slice rendered by the thread - if (x2 < thread->X1 || x1 > thread->X2) - return; - // [RH] Sprites split behind a one-sided line can also be discarded. if (spr->sector == nullptr) return; @@ -293,16 +288,48 @@ namespace swrenderer // The first drawseg that is closer than the sprite is the clip seg. DrawSegmentList *segmentlist = thread->DrawSegments.get(); + RenderPortal *renderportal = thread->Portal.get(); + + // Render draw segments behind sprite + for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++) + { + DrawSegment *ds = segmentlist->TranslucentSegment(index); + + if (ds->x1 >= x2 || ds->x2 <= x1) + { + continue; + } + + float neardepth = MIN(ds->sz1, ds->sz2); + float fardepth = MAX(ds->sz1, ds->sz2); + + // Check if sprite is in front of draw seg: + if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) && + (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - + (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) + { + if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq) + { + int r1 = MAX(ds->x1, x1); + int r2 = MIN(ds->x2, x2); + + RenderDrawSegment renderer(thread); + renderer.Render(ds, r1, r2); + } + } + } + for (unsigned int groupIndex = 0; groupIndex < segmentlist->SegmentGroups.Size(); groupIndex++) { auto &group = segmentlist->SegmentGroups[groupIndex]; + if (group.x1 >= x2 || group.x2 <= x1 || group.neardepth > spr->depth) continue; if (group.fardepth < spr->depth) { - r1 = MAX(group.x1, x1); - r2 = MIN(group.x2, x2); + int r1 = MAX(group.x1, x1); + int r2 = MIN(group.x2, x2); // Clip bottom clip1 = clipbot + r1; @@ -330,13 +357,10 @@ namespace swrenderer } else { - //for (unsigned int index = segmentlist->BeginIndex(); index != segmentlist->EndIndex(); index++) for (unsigned int index = group.BeginIndex; index != group.EndIndex; index++) { DrawSegment *ds = segmentlist->Segment(index); - // kg3D - no clipping on fake segs - if (ds->fake) continue; // determine if the drawseg obscures the sprite if (ds->x1 >= x2 || ds->x2 <= x1 || (!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == nullptr && @@ -346,41 +370,18 @@ namespace swrenderer continue; } - r1 = MAX(ds->x1, x1); - r2 = MIN(ds->x2, x2); + int r1 = MAX(ds->x1, x1); + int r2 = MIN(ds->x2, x2); - float neardepth, fardepth; - if (!spr->IsWallSprite()) - { - if (ds->sz1 < ds->sz2) - { - neardepth = ds->sz1, fardepth = ds->sz2; - } - else - { - neardepth = ds->sz2, fardepth = ds->sz1; - } - } - else - { - // GCC complained about this case, is there something missing here? - fardepth = neardepth = 0; - } + float neardepth = MIN(ds->sz1, ds->sz2); + float fardepth = MAX(ds->sz1, ds->sz2); // Check if sprite is in front of draw seg: if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) && (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) { - RenderPortal *renderportal = thread->Portal.get(); - - // seg is behind sprite, so draw the mid texture if it has one - if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq && (ds->maskedtexturecol != nullptr || ds->bFogBoundary)) - { - RenderDrawSegment renderer(thread); - renderer.Render(ds, r1, r2); - } - + // seg is behind sprite continue; } diff --git a/src/swrenderer/things/r_visiblespritelist.cpp b/src/swrenderer/things/r_visiblespritelist.cpp index 7161507dd..ef91e6bed 100644 --- a/src/swrenderer/things/r_visiblespritelist.cpp +++ b/src/swrenderer/things/r_visiblespritelist.cpp @@ -41,7 +41,6 @@ namespace swrenderer Sprites.Clear(); StartIndices.Clear(); SortedSprites.Clear(); - DrewAVoxel = false; } void VisibleSpriteList::PushPortal() @@ -55,17 +54,13 @@ namespace swrenderer StartIndices.Pop(); } - void VisibleSpriteList::Push(VisibleSprite *sprite, bool isVoxel) + void VisibleSpriteList::Push(VisibleSprite *sprite) { Sprites.Push(sprite); - if (isVoxel) - DrewAVoxel = true; } void VisibleSpriteList::Sort() { - bool compare2d = DrewAVoxel; - unsigned int first = StartIndices.Size() == 0 ? 0 : StartIndices.Last(); unsigned int count = Sprites.Size() - first; @@ -88,25 +83,9 @@ namespace swrenderer SortedSprites[i] = Sprites[first + count - i - 1]; } - if (compare2d) + std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool { - // This is an alternate version, for when one or more voxel is in view. - // It does a 2D distance test based on whichever one is furthest from - // the viewpoint. - - std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool - { - return a->SortDist2D() < b->SortDist2D(); - }); - } - else - { - // This is the standard version, which does a simple test based on depth. - - std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool - { - return a->SortDist() > b->SortDist(); - }); - } + return a->SortDist() > b->SortDist(); + }); } } diff --git a/src/swrenderer/things/r_visiblespritelist.h b/src/swrenderer/things/r_visiblespritelist.h index 30d27cc67..52ee1772c 100644 --- a/src/swrenderer/things/r_visiblespritelist.h +++ b/src/swrenderer/things/r_visiblespritelist.h @@ -11,7 +11,7 @@ namespace swrenderer void Clear(); void PushPortal(); void PopPortal(); - void Push(VisibleSprite *sprite, bool isVoxel = false); + void Push(VisibleSprite *sprite); void Sort(); TArray SortedSprites; @@ -19,6 +19,5 @@ namespace swrenderer private: TArray Sprites; TArray StartIndices; - bool DrewAVoxel = false; }; } diff --git a/src/swrenderer/things/r_voxel.cpp b/src/swrenderer/things/r_voxel.cpp index fe626dd2f..f32452399 100644 --- a/src/swrenderer/things/r_voxel.cpp +++ b/src/swrenderer/things/r_voxel.cpp @@ -124,7 +124,7 @@ namespace swrenderer vis->yscale = (float)yscale; vis->x1 = renderportal->WindowLeft; vis->x2 = renderportal->WindowRight; - vis->idepth = 1 / MINZ; + vis->idepth = float(1 / tz); vis->floorclip = thing->Floorclip; pos.Z -= thing->Floorclip; @@ -189,7 +189,19 @@ namespace swrenderer vis->Light.SetColormap(thread->Light->SpriteGlobVis(foggy) / MAX(tz, MINZ), spriteshade, basecolormap, fullbright, invertcolormap, fadeToBlack); - thread->SpriteList->Push(vis, true); + // Fake a voxel drawing to find its extents.. + SpriteDrawerArgs drawerargs; + drawerargs.SetLight(vis->Light.BaseColormap, 0, vis->Light.ColormapNum << FRACBITS); + basecolormap = (FDynamicColormap*)vis->Light.BaseColormap; + bool visible = drawerargs.SetStyle(thread->Viewport.get(), vis->RenderStyle, vis->Alpha, vis->Translation, vis->FillColor, basecolormap); + if (!visible) + return; + int flags = vis->bInMirror ? (DVF_MIRRORED | DVF_FIND_X1X2) : DVF_FIND_X1X2; + vis->DrawVoxel(thread, drawerargs, vis->pa.vpos, vis->pa.vang, vis->gpos, vis->Angle, vis->xscale, FLOAT2FIXED(vis->yscale), vis->voxel, nullptr, nullptr, 0, 0, flags); + if (vis->x1 >= vis->x2) + return; + + thread->SpriteList->Push(vis); } void RenderVoxel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ) @@ -379,8 +391,13 @@ namespace swrenderer bool useSlabDataBgra = !drawerargs.DrawerNeedsPalInput() && viewport->RenderTarget->IsBgra(); + int coverageX1 = this->x2; + int coverageX2 = this->x1; + const int maxoutblocks = 100; - VoxelBlock *outblocks = thread->FrameMemory->AllocMemory(maxoutblocks); + VoxelBlock *outblocks = nullptr; + if ((flags & DVF_FIND_X1X2) == 0) + outblocks = thread->FrameMemory->AllocMemory(maxoutblocks); int nextoutblock = 0; for (cnt = 0; cnt < 8; cnt++) @@ -457,10 +474,7 @@ namespace swrenderer if (voxptr >= voxend) continue; lx = xs_RoundToInt(nx * centerxwide_f / (ny + y1)) + viewport->viewwindow.centerx; - if (lx < 0) lx = 0; rx = xs_RoundToInt((nx + nxoff) * centerxwide_f / (ny + y2)) + viewport->viewwindow.centerx; - if (rx > viewwidth) rx = viewwidth; - if (rx <= lx) continue; if (flags & DVF_MIRRORED) { @@ -469,6 +483,17 @@ namespace swrenderer rx = t; } + if (lx < this->x1) lx = this->x1; + if (rx > this->x2) rx = this->x2; + if (rx <= lx) continue; + + if (flags & DVF_FIND_X1X2) + { + coverageX1 = MIN(coverageX1, lx); + coverageX2 = MAX(coverageX2, rx); + continue; + } + fixed_t l1 = xs_RoundToInt(centerxwidebig_f / (ny - yoff)); fixed_t l2 = xs_RoundToInt(centerxwidebig_f / (ny + yoff)); for (; voxptr < voxend; voxptr = (kvxslab_t *)((uint8_t *)voxptr + voxptr->zleng + 3)) @@ -594,7 +619,7 @@ namespace swrenderer if (nextoutblock == maxoutblocks) { - drawerargs.DrawVoxelBlocks(thread, outblocks, nextoutblock); + drawerargs.DrawVoxelBlocks(thread, outblocks, maxoutblocks); outblocks = thread->FrameMemory->AllocMemory(maxoutblocks); nextoutblock = 0; } @@ -645,9 +670,17 @@ namespace swrenderer } } - if (nextoutblock != 0) + if (flags & DVF_FIND_X1X2) { - drawerargs.DrawVoxelBlocks(thread, outblocks, nextoutblock); + this->x1 = coverageX1; + this->x2 = coverageX2; + } + else + { + if (nextoutblock != 0) + { + drawerargs.DrawVoxelBlocks(thread, outblocks, nextoutblock); + } } } diff --git a/src/swrenderer/things/r_voxel.h b/src/swrenderer/things/r_voxel.h index a97ee5196..bef22d480 100644 --- a/src/swrenderer/things/r_voxel.h +++ b/src/swrenderer/things/r_voxel.h @@ -73,6 +73,12 @@ namespace swrenderer FAngle vang = { 0.0f }; // view angle }; + struct VoxelBlockEntry + { + VoxelBlock *block; + VoxelBlockEntry *next; + }; + posang pa; DAngle Angle = { 0.0 }; fixed_t xscale = 0; @@ -82,7 +88,7 @@ namespace swrenderer uint32_t Translation = 0; uint32_t FillColor = 0; - enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2, DVF_MIRRORED = 4 }; + enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2, DVF_MIRRORED = 4, DVF_FIND_X1X2 = 8 }; static kvxslab_t *GetSlabStart(const FVoxelMipLevel &mip, int x, int y); static kvxslab_t *GetSlabEnd(const FVoxelMipLevel &mip, int x, int y);