This commit is contained in:
Rachael Alexanderson 2017-07-02 16:36:46 -04:00
commit 6a402c28d8
15 changed files with 194 additions and 200 deletions

View file

@ -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<DrawSegment>();
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<fixed_t>(stop - start);
draw_segment->swall = Thread->FrameMemory->AllocMemory<float>(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);
}
}
}

View file

@ -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--)
{

View file

@ -103,23 +103,28 @@ namespace swrenderer
// calls to GetPixels for this to work.
static std::mutex loadmutex;
loadmutex.lock();
try
std::unique_lock<std::mutex> 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<std::mutex> lock(polyobjmutex);
if (sub->BSP == nullptr || sub->BSP->bDirty)
{
loadmutex.unlock();
throw;
sub->BuildPolyBSP();
}
}
}

View file

@ -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<SWTruecolorDrawers> tc_drawers;

View file

@ -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]);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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<DrawSegment *> Segments;
TArray<unsigned int> StartIndices;
TArray<DrawSegment *> InterestingSegments; // drawsegs that have something drawn on them
TArray<unsigned int> StartInterestingIndices;
TArray<DrawSegment *> TranslucentSegments; // drawsegs that have something drawn on them
TArray<unsigned int> StartTranslucentIndices;
// For building segment groups
short cliptop[MAXWIDTH];

View file

@ -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;

View file

@ -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<int>(ds->x1, x1);
int r2 = MIN<int>(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<int>(group.x1, x1);
r2 = MIN<int>(group.x2, x2);
int r1 = MAX<int>(group.x1, x1);
int r2 = MIN<int>(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<int>(ds->x1, x1);
r2 = MIN<int>(ds->x2, x2);
int r1 = MAX<int>(ds->x1, x1);
int r2 = MIN<int>(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;
}

View file

@ -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();
});
}
}

View file

@ -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<VisibleSprite *> SortedSprites;
@ -19,6 +19,5 @@ namespace swrenderer
private:
TArray<VisibleSprite *> Sprites;
TArray<unsigned int> StartIndices;
bool DrewAVoxel = false;
};
}

View file

@ -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<VoxelBlock>(maxoutblocks);
VoxelBlock *outblocks = nullptr;
if ((flags & DVF_FIND_X1X2) == 0)
outblocks = thread->FrameMemory->AllocMemory<VoxelBlock>(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<VoxelBlock>(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);
}
}
}

View file

@ -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);