This commit is contained in:
Christoph Oelckers 2018-12-28 23:14:22 +01:00
commit 3559f7dffb
22 changed files with 599 additions and 602 deletions

View file

@ -801,7 +801,7 @@ static inline bool isFakePain(AActor *target, AActor *inflictor, int damage)
}
// [MC] Completely ripped out of DamageMobj to make it less messy.
static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags)
static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, int originaldamage)
{
bool justhit = false;
int painchance = 0;
@ -827,7 +827,7 @@ static void ReactToDamage(AActor *target, AActor *inflictor, AActor *source, int
// Are we attempting to cause pain?
if (!noPain)
{
fakedPain = (isFakePain(target, inflictor, damage));
fakedPain = (isFakePain(target, inflictor, originaldamage));
forcedPain = (MustForcePain(target, inflictor));
}
@ -1456,7 +1456,7 @@ static int DoDamageMobj(AActor *target, AActor *inflictor, AActor *source, int d
bool needevent = true;
int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle, needevent);
if (realdamage >= 0) //Keep this check separated. Mods relying upon negative numbers may break otherwise.
ReactToDamage(target, inflictor, source, realdamage, mod, flags);
ReactToDamage(target, inflictor, source, realdamage, mod, flags, damage);
if (realdamage > 0 && needevent)
{

View file

@ -54,19 +54,20 @@
namespace swrenderer
{
void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, int lightlevel, bool foggy, float lightleft, float lightstep, FDynamicColormap *basecolormap)
void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight)
{
// This is essentially the same as R_MapVisPlane but with an extra step
// to create new horizontal spans whenever the light changes enough that
// we need to use a new colormap.
int wallshade = LightVisibility::LightLevelToShade(lightlevel, foggy, thread->Viewport.get());
float light = lightleft + lightstep*(x2 - x1 - 1);
int wallshade = LightVisibility::LightLevelToShade(wallLight.GetLightLevel(), wallLight.GetFoggy(), thread->Viewport.get());
int x = x2 - 1;
int t2 = uclip[x];
int b2 = dclip[x];
float light = wallLight.GetLightPos(x);
int rcolormap = GETPALOOKUP(light, wallshade);
int lcolormap;
FDynamicColormap *basecolormap = wallLight.GetBaseColormap();
uint8_t *basecolormapdata = basecolormap->Maps;
if (b2 > t2)
@ -75,7 +76,7 @@ namespace swrenderer
}
drawerargs.SetBaseColormap(basecolormap);
drawerargs.SetLight(light, lightlevel, foggy, thread->Viewport.get());
drawerargs.SetLight(light, wallLight.GetLightLevel(), wallLight.GetFoggy(), thread->Viewport.get());
uint8_t *fake_dc_colormap = basecolormap->Maps + (GETPALOOKUP(light, wallshade) << COLORMAPSHIFT);
@ -86,7 +87,7 @@ namespace swrenderer
const int xr = x + 1;
int stop;
light -= lightstep;
light -= wallLight.GetLightStep();
lcolormap = GETPALOOKUP(light, wallshade);
if (lcolormap != rcolormap)
{

View file

@ -31,7 +31,7 @@ namespace swrenderer
class RenderFogBoundary
{
public:
void Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, int lightlevel, bool foggy, float lightleft, float lightstep, FDynamicColormap *basecolormap);
void Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight);
private:
void RenderSection(RenderThread *thread, int y, int y2, int x1);

View file

@ -71,15 +71,13 @@ namespace swrenderer
Thread = thread;
}
void SWRenderLine::Render(seg_t *line, subsector_t *subsector, sector_t *sector, sector_t *fakebacksector, VisiblePlane *linefloorplane, VisiblePlane *lineceilingplane, bool infog, FDynamicColormap *colormap, Fake3DOpaque opaque3dfloor)
void SWRenderLine::Render(seg_t *line, subsector_t *subsector, sector_t *sector, sector_t *fakebacksector, VisiblePlane *linefloorplane, VisiblePlane *lineceilingplane, Fake3DOpaque opaque3dfloor)
{
mSubsector = subsector;
mFrontSector = sector;
mBackSector = fakebacksector;
mFloorPlane = linefloorplane;
mCeilingPlane = lineceilingplane;
foggy = infog;
basecolormap = colormap;
mLineSegment = line;
m3DFloor = opaque3dfloor;
@ -314,7 +312,7 @@ namespace swrenderer
if (!rw_prepped)
{
rw_prepped = true;
SetWallVariables(true);
SetWallVariables();
}
side_t *sidedef = mLineSegment->sidedef;
@ -326,26 +324,15 @@ namespace swrenderer
// 3D floors code abuses the line render code to update plane clipping
// lists but doesn't actually draw anything.
bool onlyUpdatePlaneClip = (m3DFloor.type != Fake3DOpaque::Normal);
if (!onlyUpdatePlaneClip)
if (m3DFloor.type == Fake3DOpaque::Normal)
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->cy = WallC.tleft.Y;
draw_segment->cdx = WallC.tright.X - WallC.tleft.X;
draw_segment->cdy = WallC.tright.Y - WallC.tleft.Y;
draw_segment->WallC = WallC;
draw_segment->tmapvals = WallT;
draw_segment->siz1 = 1 / WallC.sz1;
draw_segment->siz2 = 1 / WallC.sz2;
draw_segment->x1 = start;
draw_segment->x2 = stop;
draw_segment->curline = mLineSegment;
draw_segment->foggy = foggy;
draw_segment->SubsectorDepth = Thread->OpaquePass->GetSubsectorDepth(mSubsector->Index());
bool markportal = ShouldMarkPortal();
@ -400,29 +387,30 @@ namespace swrenderer
}
}
if (!onlyUpdatePlaneClip && r_3dfloors)
if (m3DFloor.type == Fake3DOpaque::Normal)
{
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 (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 (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 (!onlyUpdatePlaneClip)
// allocate space for masked texture tables, if needed
// [RH] Don't just allocate the space; fill it in too.
if ((sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) &&
@ -452,8 +440,8 @@ namespace swrenderer
lwal = draw_segment->maskedtexturecol;
swal = draw_segment->swall;
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
FSoftwareTexture *pic = tex && tex->isValid()? tex->GetSoftwareTexture() : nullptr;
double yscale = (pic? pic->GetScale().Y : 1.0) * sidedef->GetTextureYScale(side_t::mid);
FSoftwareTexture *pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
double yscale = (pic ? pic->GetScale().Y : 1.0) * sidedef->GetTextureYScale(side_t::mid);
fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid));
if (pic && pic->useWorldPanning())
@ -490,27 +478,16 @@ namespace swrenderer
draw_segment->iscalestep = 0;
}
}
draw_segment->light = rw_lightleft + rw_lightstep * (start - WallC.sx1);
draw_segment->lightstep = rw_lightstep;
// Masked mMiddlePart.Textures should get the light level from the sector they reference,
// not from the current subsector, which is what the current lightlevel value
// comes from. We make an exeption for polyobjects, however, since their "home"
// sector should be whichever one they move into.
if (mLineSegment->sidedef->Flags & WALLF_POLYOBJ)
{
draw_segment->lightlevel = lightlevel;
}
else
{
draw_segment->lightlevel = mLineSegment->sidedef->GetLightLevel(foggy, mLineSegment->frontsector->lightlevel);
}
draw_segment->light = mLight.GetLightPos(start);
draw_segment->lightstep = mLight.GetLightStep();
if (draw_segment->bFogBoundary || draw_segment->maskedtexturecol != nullptr)
{
Thread->DrawSegments->PushTranslucent(draw_segment);
}
}
}
}
ClipSegmentTopBottom(start, stop);
@ -552,7 +529,7 @@ namespace swrenderer
// [ZZ] Only if not an active mirror
if (!markportal)
{
RenderDecal::RenderDecals(Thread, mLineSegment->sidedef, draw_segment, lightlevel, rw_lightleft, rw_lightstep, mLineSegment, WallC, foggy, basecolormap, walltop.ScreenY, wallbottom.ScreenY, false);
RenderDecal::RenderDecals(Thread, mLineSegment->sidedef, draw_segment, mLineSegment, mLight, walltop.ScreenY, wallbottom.ScreenY, false);
}
if (markportal)
@ -700,7 +677,7 @@ namespace swrenderer
}
}
void SWRenderLine::SetWallVariables(bool needlights)
void SWRenderLine::SetWallVariables()
{
RenderPortal *renderportal = Thread->Portal.get();
@ -775,8 +752,13 @@ namespace swrenderer
bool segtextured = ftex != NULL || mTopPart.Texture != NULL || mBottomPart.Texture != NULL;
if (m3DFloor.type == Fake3DOpaque::Normal)
{
mLight.SetColormap(mFrontSector, mLineSegment);
}
// calculate light table
if (needlights && (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector))))
if (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector)))
{
lwallscale =
ftex ? ((midtex? midtex->GetScale().X : 1.0) * sidedef->GetTextureXScale(side_t::mid)) :
@ -786,18 +768,7 @@ namespace swrenderer
walltexcoords.Project(Thread->Viewport.get(), sidedef->TexelLength * lwallscale, WallC.sx1, WallC.sx2, WallT);
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() == nullptr && cameraLight->FixedLightLevel() < 0)
{
lightlevel = mLineSegment->sidedef->GetLightLevel(foggy, mFrontSector->lightlevel);
rw_lightleft = float(Thread->Light->WallVis(WallC.sz1, foggy));
rw_lightstep = float((Thread->Light->WallVis(WallC.sz2, foggy) - rw_lightleft) / (WallC.sx2 - WallC.sx1));
}
else
{
rw_lightleft = 1;
rw_lightstep = 0;
}
mLight.SetLightLeft(Thread, WallC);
}
}
@ -1164,10 +1135,8 @@ namespace swrenderer
offset = -offset;
}
float rw_light = rw_lightleft + rw_lightstep * (x1 - WallC.sx1);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallupper.ScreenY, mTopPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, false, OPAQUE, lightlevel, offset, rw_light, rw_lightstep, GetLightList(), foggy, basecolormap);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallupper.ScreenY, mTopPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, false, OPAQUE, offset, mLight, GetLightList());
}
void SWRenderLine::RenderMiddleTexture(int x1, int x2)
@ -1197,10 +1166,8 @@ namespace swrenderer
offset = -offset;
}
float rw_light = rw_lightleft + rw_lightstep * (x1 - WallC.sx1);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallbottom.ScreenY, mMiddlePart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, lightlevel, offset, rw_light, rw_lightstep, GetLightList(), foggy, basecolormap);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallbottom.ScreenY, mMiddlePart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, offset, mLight, GetLightList());
}
void SWRenderLine::RenderBottomTexture(int x1, int x2)
@ -1231,10 +1198,8 @@ namespace swrenderer
offset = -offset;
}
float rw_light = rw_lightleft + rw_lightstep * (x1 - WallC.sx1);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walllower.ScreenY, wallbottom.ScreenY, mBottomPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, lightlevel, offset, rw_light, rw_lightstep, GetLightList(), foggy, basecolormap);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walllower.ScreenY, wallbottom.ScreenY, mBottomPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, false, OPAQUE, offset, mLight, GetLightList());
}
FLightNode *SWRenderLine::GetLightList()

View file

@ -72,13 +72,13 @@ namespace swrenderer
{
public:
SWRenderLine(RenderThread *thread);
void Render(seg_t *line, subsector_t *subsector, sector_t *sector, sector_t *fakebacksector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, bool foggy, FDynamicColormap *basecolormap, Fake3DOpaque fake3DOpaque);
void Render(seg_t *line, subsector_t *subsector, sector_t *sector, sector_t *fakebacksector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, Fake3DOpaque fake3DOpaque);
RenderThread *Thread = nullptr;
private:
bool RenderWallSegment(int x1, int x2) override;
void SetWallVariables(bool needlights);
void SetWallVariables();
void SetTopTexture();
void SetMiddleTexture();
void SetBottomTexture();
@ -128,16 +128,11 @@ namespace swrenderer
FWallCoords WallC;
FWallTmapVals WallT;
bool foggy;
FDynamicColormap *basecolormap;
// Wall segment variables:
bool rw_prepped;
int lightlevel;
float rw_lightstep;
float rw_lightleft;
ProjectedWallLight mLight;
double lwallscale;

View file

@ -80,12 +80,8 @@ namespace swrenderer
sector_t tempsec;
const sector_t *sec = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
FDynamicColormap *basecolormap = GetColorTable(sec->Colormap, sec->SpecialColors[sector_t::walltop]); // [RH] Set basecolormap
bool foggy = ds->foggy;
int lightlevel = ds->lightlevel;
rw_lightstep = ds->lightstep;
rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
mLight.SetColormap(sec, curline);
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
Clip3DFloors *clip3d = Thread->Clip3D.get();
@ -94,10 +90,7 @@ namespace swrenderer
{
if (clipTop <= frontsector->e->XFloor.lightlist[i].plane.Zat0())
{
lightlist_t *lit = &frontsector->e->XFloor.lightlist[i];
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag
lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr);
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
break;
}
}
@ -107,7 +100,7 @@ namespace swrenderer
SpriteDrawerArgs columndrawerargs;
ColormapLight cmlight;
cmlight.SetColormap(Thread, MINZ, lightlevel, foggy, basecolormap, false, false, false, false, false);
cmlight.SetColormap(Thread, MINZ, mLight.GetLightLevel(), mLight.GetFoggy(), mLight.GetBaseColormap(), false, false, false, false, false);
bool visible = columndrawerargs.SetStyle(viewport, LegacyRenderStyles[additive ? STYLE_Add : STYLE_Translucent], alpha, 0, 0, cmlight);
if (!visible && !ds->bFogBoundary && !ds->Has3DFloorWalls())
{
@ -123,7 +116,7 @@ namespace swrenderer
const short *mceilingclip = ds->sprtopclip - ds->x1;
RenderFogBoundary renderfog;
renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, lightlevel, ds->foggy, rw_light, rw_lightstep, basecolormap);
renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, mLight);
if (ds->maskedtexturecol == nullptr)
renderwall = false;
@ -134,7 +127,7 @@ namespace swrenderer
}
if (renderwall)
notrelevant = RenderWall(ds, x1, x2, basecolormap, columndrawerargs, visible, lightlevel, foggy);
notrelevant = RenderWall(ds, x1, x2, columndrawerargs, visible);
if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls())
{
@ -147,7 +140,7 @@ namespace swrenderer
}
}
bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2, FDynamicColormap *basecolormap, SpriteDrawerArgs &columndrawerargs, bool visible, int lightlevel, bool foggy)
bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2, SpriteDrawerArgs &columndrawerargs, bool visible)
{
auto renderstyle = DefaultRenderStyle();
auto viewport = Thread->Viewport.get();
@ -226,12 +219,12 @@ namespace swrenderer
}
// [RH] Don't bother drawing segs that are completely offscreen
if (viewport->globaldclip * ds->sz1 < -textop && viewport->globaldclip * ds->sz2 < -textop)
if (viewport->globaldclip * ds->WallC.sz1 < -textop && viewport->globaldclip * ds->WallC.sz2 < -textop)
{ // Texture top is below the bottom of the screen
return false;
}
if (viewport->globaluclip * ds->sz1 > texheight - textop && viewport->globaluclip * ds->sz2 > texheight - textop)
if (viewport->globaluclip * ds->WallC.sz1 > texheight - textop && viewport->globaluclip * ds->WallC.sz2 > texheight - textop)
{ // Texture bottom is above the top of the screen
return false;
}
@ -245,10 +238,10 @@ namespace swrenderer
return true;
}
WallC.sz1 = ds->sz1;
WallC.sz2 = ds->sz2;
WallC.sx1 = ds->sx1;
WallC.sx2 = ds->sx2;
WallC.sz1 = ds->WallC.sz1;
WallC.sz2 = ds->WallC.sz2;
WallC.sx1 = ds->WallC.sx1;
WallC.sx2 = ds->WallC.sx2;
// Unclipped vanilla Doom range for the wall. Relies on ceiling/floor clip to clamp the wall in range.
double ceilZ = textop;
@ -317,10 +310,11 @@ namespace swrenderer
if (visible)
{
Thread->PrepareTexture(tex, renderstyle);
float lightpos = mLight.GetLightPos(x1);
for (int x = x1; x < x2; ++x)
{
if (needslight)
columndrawerargs.SetLight(rw_light, lightlevel, foggy, Thread->Viewport.get());
columndrawerargs.SetLight(lightpos, mLight.GetLightLevel(), mLight.GetFoggy(), Thread->Viewport.get());
fixed_t iscale = xs_Fix<16>::ToFix(MaskedSWall[x] * MaskedScaleY);
double sprtopscreen;
@ -331,7 +325,7 @@ namespace swrenderer
columndrawerargs.DrawMaskedColumn(Thread, x, iscale, tex, maskedtexturecol[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, renderstyle);
rw_light += rw_lightstep;
lightpos += mLight.GetLightStep();
spryscale += rw_scalestep;
}
}
@ -351,10 +345,10 @@ namespace swrenderer
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z) * MaskedScaleY + rowoffset;
}
WallC.sz1 = ds->sz1;
WallC.sz2 = ds->sz2;
WallC.sx1 = ds->sx1;
WallC.sx2 = ds->sx2;
WallC.sz1 = ds->WallC.sz1;
WallC.sz2 = ds->WallC.sz2;
WallC.sx1 = ds->WallC.sx1;
WallC.sx2 = ds->WallC.sx2;
if (clip3d->CurrentSkybox)
{ // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor
@ -399,14 +393,14 @@ namespace swrenderer
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(frontsector, curline, WallC, rw_pic, x1, x2, mceilingclip, mfloorclip, texturemid, MaskedSWall, maskedtexturecol, ds->yscale, top, bot, true, additive, alpha, lightlevel, rw_offset, rw_light, rw_lightstep, nullptr, ds->foggy, basecolormap);
renderWallpart.Render(frontsector, curline, WallC, rw_pic, x1, x2, mceilingclip, mfloorclip, texturemid, MaskedSWall, maskedtexturecol, ds->yscale, top, bot, true, additive, alpha, rw_offset, mLight, nullptr);
}
return false;
}
// kg3D - render one fake wall
void RenderDrawSegment::RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, int lightlevel, FDynamicColormap *basecolormap, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
void RenderDrawSegment::RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
{
int i;
double xscale;
@ -416,8 +410,7 @@ namespace swrenderer
if (Alpha <= 0)
return;
rw_lightstep = ds->lightstep;
rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
const short *mfloorclip = ds->sprbottomclip - ds->x1;
const short *mceilingclip = ds->sprtopclip - ds->x1;
@ -469,14 +462,7 @@ namespace swrenderer
texturemid += rowoffset;
}
WallC.sz1 = ds->sz1;
WallC.sz2 = ds->sz2;
WallC.sx1 = ds->sx1;
WallC.sx2 = ds->sx2;
WallC.tleft.X = ds->cx;
WallC.tleft.Y = ds->cy;
WallC.tright.X = ds->cx + ds->cdx;
WallC.tright.Y = ds->cy + ds->cdy;
WallC = ds->WallC;
WallT = ds->tmapvals;
Clip3DFloors *clip3d = Thread->Clip3D.get();
@ -495,15 +481,15 @@ namespace swrenderer
}
ProjectedWallTexcoords walltexcoords;
walltexcoords.ProjectPos(Thread->Viewport.get(), curline->sidedef->TexelLength*xscale, ds->sx1, ds->sx2, WallT);
walltexcoords.ProjectPos(Thread->Viewport.get(), curline->sidedef->TexelLength*xscale, ds->WallC.sx1, ds->WallC.sx2, WallT);
double top, bot;
GetMaskedWallTopBottom(ds, top, bot);
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(frontsector, curline, WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, texturemid, MaskedSWall, walltexcoords.UPos, yscale, top, bot, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha, lightlevel, rw_offset, rw_light, rw_lightstep, nullptr, ds->foggy, basecolormap);
renderWallpart.Render(frontsector, curline, WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, texturemid, MaskedSWall, walltexcoords.UPos, yscale, top, bot, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha, rw_offset, mLight, nullptr);
RenderDecal::RenderDecals(Thread, curline->sidedef, ds, lightlevel, rw_light, rw_lightstep, curline, WallC, ds->foggy, basecolormap, wallupper.ScreenY, walllower.ScreenY, true);
RenderDecal::RenderDecals(Thread, curline->sidedef, ds, curline, mLight, wallupper.ScreenY, walllower.ScreenY, true);
}
// kg3D - walls of fake floors
@ -695,46 +681,42 @@ namespace swrenderer
}
rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr;
}
// correct colors now
FDynamicColormap *basecolormap = nullptr;
int lightlevel = ds->lightlevel;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0)
{
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
{
lightlist_t *lit = &backsector->e->XFloor.lightlist[j];
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
//bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag
lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr);
break;
}
}
}
else
{
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
{
lightlist_t *lit = &frontsector->e->XFloor.lightlist[j];
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
//bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag
lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr);
break;
}
}
}
}
if (basecolormap == nullptr) basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
if (rw_pic && !swimmable_found)
{
RenderFakeWall(ds, x1, x2, fover ? fover : rover, lightlevel, basecolormap, clipTop, clipBottom, rw_pic);
// correct colors now
lightlist_t *lit = nullptr;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0)
{
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &backsector->e->XFloor.lightlist[j];
break;
}
}
}
else
{
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &frontsector->e->XFloor.lightlist[j];
break;
}
}
}
}
//mLight.lightlevel = ds->lightlevel;
mLight.SetColormap(frontsector, curline, lit);
RenderFakeWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
}
break;
}
@ -882,46 +864,41 @@ namespace swrenderer
}
rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr;
}
// correct colors now
FDynamicColormap *basecolormap = nullptr;
int lightlevel = ds->lightlevel;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0)
{
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
{
lightlist_t *lit = &backsector->e->XFloor.lightlist[j];
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag
lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr);
break;
}
}
}
else
{
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
{
lightlist_t *lit = &frontsector->e->XFloor.lightlist[j];
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag
lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr);
break;
}
}
}
}
if (basecolormap == nullptr) basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
if (rw_pic && !swimmable_found)
{
RenderFakeWall(ds, x1, x2, fover ? fover : rover, lightlevel, basecolormap, clipTop, clipBottom, rw_pic);
// correct colors now
lightlist_t *lit = nullptr;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedLightLevel() < 0)
{
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &backsector->e->XFloor.lightlist[j];
break;
}
}
}
else
{
for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
{
lit = &frontsector->e->XFloor.lightlist[j];
break;
}
}
}
}
//mLight.lightlevel = ds->lightlevel;
mLight.SetColormap(frontsector, curline, lit);
RenderFakeWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
}
break;
}

View file

@ -37,9 +37,9 @@ namespace swrenderer
RenderThread *Thread = nullptr;
private:
bool RenderWall(DrawSegment *ds, int x1, int x2, FDynamicColormap *basecolormap, SpriteDrawerArgs &columndrawerargs, bool visible, int lightlevel, bool foggy);
bool RenderWall(DrawSegment *ds, int x1, int x2, SpriteDrawerArgs &columndrawerargs, bool visible);
void ClipMidtex(int x1, int x2);
void RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, int lightlevel, FDynamicColormap *basecolormap, double clipTop, double clipBottom, FSoftwareTexture *rw_pic);
void RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic);
void RenderFakeWallRange(DrawSegment *ds, int x1, int x2);
void GetMaskedWallTopBottom(DrawSegment *ds, double &top, double &bot);
@ -52,8 +52,8 @@ namespace swrenderer
FWallCoords WallC;
FWallTmapVals WallT;
float rw_light = 0.0f;
float rw_lightstep = 0.0f;
ProjectedWallLight mLight;
fixed_t rw_offset = 0;
ProjectedWallLine wallupper;

View file

@ -54,284 +54,7 @@
namespace swrenderer
{
WallSampler::WallSampler(RenderViewport *viewport, int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FSoftwareTexture *texture)
{
xoffset += FLOAT2FIXED(xmagnitude * 0.5);
xoffset *= texture->GetPhysicalScale();
if (!viewport->RenderTarget->IsBgra())
{
height = texture->GetPhysicalHeight();
int uv_fracbits = 32 - texture->GetHeightBits();
if (uv_fracbits != 32)
{
uv_max = height << uv_fracbits;
// Find start uv in [0-base_height[ range.
// Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range.
double uv_stepd = swal * yrepeat;
double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / texture->GetHeight();
v = v - floor(v);
v *= height;
v *= (1 << uv_fracbits);
uv_pos = (uint32_t)(int64_t)v;
uv_step = xs_ToFixed(uv_fracbits, uv_stepd * texture->GetPhysicalScale());
if (uv_step == 0) // To prevent divide by zero elsewhere
uv_step = 1;
}
else
{ // Hack for one pixel tall textures
uv_pos = 0;
uv_step = 0;
uv_max = 1;
}
int col = xoffset >> FRACBITS;
// If the texture's width isn't a power of 2, then we need to make it a
// positive offset for proper clamping.
int width;
if (col < 0 && (width = texture->GetPhysicalWidth()) != (1 << texture->GetWidthBits()))
{
col = width + (col % width);
}
source = texture->GetColumn(DefaultRenderStyle(), col, nullptr);
source2 = nullptr;
texturefracx = 0;
}
else
{
// Normalize to 0-1 range:
double uv_stepd = swal * yrepeat;
double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / texture->GetHeight();
v = v - floor(v);
double v_step = uv_stepd / texture->GetHeight();
if (std::isnan(v) || std::isnan(v_step)) // this should never happen, but it apparently does..
{
uv_stepd = 0.0;
v = 0.0;
v_step = 0.0;
}
// Convert to uint32_t:
uv_pos = (uint32_t)(int64_t)(v * 0x100000000LL);
uv_step = (uint32_t)(int64_t)(v_step * 0x100000000LL);
uv_max = 0;
// Texture mipmap and filter selection:
double ymagnitude = fabs(uv_stepd);
double magnitude = MAX(ymagnitude, xmagnitude);
double min_lod = -1000.0;
double lod = MAX(log2(magnitude) + r_lod_bias, min_lod);
bool magnifying = lod < 0.0f;
int mipmap_offset = 0;
int mip_width = texture->GetPhysicalWidth();
int mip_height = texture->GetPhysicalHeight();
if (r_mipmap && texture->Mipmapped() && mip_width > 1 && mip_height > 1)
{
uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width);
int level = (int)lod;
while (level > 0 && mip_width > 1 && mip_height > 1)
{
mipmap_offset += mip_width * mip_height;
level--;
mip_width = MAX(mip_width >> 1, 1);
mip_height = MAX(mip_height >> 1, 1);
}
xoffset = (xpos >> FRACBITS) * mip_width;
}
const uint32_t *pixels = texture->GetPixelsBgra() + mipmap_offset;
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
if (filter_nearest)
{
int tx = (xoffset >> FRACBITS) % mip_width;
if (tx < 0)
tx += mip_width;
source = (uint8_t*)(pixels + tx * mip_height);
source2 = nullptr;
height = mip_height;
texturefracx = 0;
}
else
{
xoffset -= FRACUNIT / 2;
int tx0 = (xoffset >> FRACBITS) % mip_width;
if (tx0 < 0)
tx0 += mip_width;
int tx1 = (tx0 + 1) % mip_width;
source = (uint8_t*)(pixels + tx0 * mip_height);
source2 = (uint8_t*)(pixels + tx1 * mip_height);
height = mip_height;
texturefracx = (xoffset >> (FRACBITS - 4)) & 15;
}
}
}
// Draw a column with support for non-power-of-two ranges
void RenderWallPart::Draw1Column(int x, int y1, int y2, WallSampler &sampler)
{
// Find column position in view space
float w1 = 1.0f / WallC.sz1;
float w2 = 1.0f / WallC.sz2;
float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1);
float wcol = w1 * (1.0f - t) + w2 * t;
float zcol = 1.0f / wcol;
float zbufferdepth = 1.0f / (zcol / Thread->Viewport->viewwindow.FocalTangent);
if (r_dynlights && light_list)
{
auto viewport = Thread->Viewport.get();
int tx = x;
bool mirror = !!(Thread->Portal->MirrorFlags & RF_XFLIP);
if (mirror)
tx = viewwidth - tx - 1;
drawerargs.dc_viewpos.X = (float)((tx + 0.5 - viewport->CenterX) / viewport->CenterX * zcol);
drawerargs.dc_viewpos.Y = zcol;
drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol);
drawerargs.dc_viewpos_step.Z = (float)(-zcol / viewport->InvZtoScale);
// Calculate max lights that can touch column so we can allocate memory for the list
int max_lights = 0;
FLightNode *cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
max_lights++;
cur_node = cur_node->nextLight;
}
drawerargs.dc_num_lights = 0;
drawerargs.dc_lights = Thread->FrameMemory->AllocMemory<DrawerLight>(max_lights);
// Setup lights for column
cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
{
double lightX = cur_node->lightsource->X() - Thread->Viewport->viewpoint.Pos.X;
double lightY = cur_node->lightsource->Y() - Thread->Viewport->viewpoint.Pos.Y;
double lightZ = cur_node->lightsource->Z() - Thread->Viewport->viewpoint.Pos.Z;
float lx = (float)(lightX * Thread->Viewport->viewpoint.Sin - lightY * Thread->Viewport->viewpoint.Cos) - drawerargs.dc_viewpos.X;
float ly = (float)(lightX * Thread->Viewport->viewpoint.TanCos + lightY * Thread->Viewport->viewpoint.TanSin) - drawerargs.dc_viewpos.Y;
float lz = (float)lightZ;
// Precalculate the constant part of the dot here so the drawer doesn't have to.
bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0;
float lconstant = lx * lx + ly * ly;
float nlconstant = is_point_light ? lx * drawerargs.dc_normal.X + ly * drawerargs.dc_normal.Y : 0.0f;
// Include light only if it touches this column
float radius = cur_node->lightsource->GetRadius();
if (radius * radius >= lconstant && nlconstant >= 0.0f)
{
uint32_t red = cur_node->lightsource->GetRed();
uint32_t green = cur_node->lightsource->GetGreen();
uint32_t blue = cur_node->lightsource->GetBlue();
auto &light = drawerargs.dc_lights[drawerargs.dc_num_lights++];
light.x = lconstant;
light.y = nlconstant;
light.z = lz;
light.radius = 256.0f / cur_node->lightsource->GetRadius();
light.color = (red << 16) | (green << 8) | blue;
}
}
cur_node = cur_node->nextLight;
}
}
else
{
drawerargs.dc_num_lights = 0;
}
if (Thread->Viewport->RenderTarget->IsBgra())
{
int count = y2 - y1;
drawerargs.SetTexture(sampler.source, sampler.source2, sampler.height);
drawerargs.SetTextureUPos(sampler.texturefracx);
drawerargs.SetDest(Thread->Viewport.get(), x, y1);
drawerargs.SetCount(count);
drawerargs.SetTextureVStep(sampler.uv_step);
drawerargs.SetTextureVPos(sampler.uv_pos);
drawerargs.DrawColumn(Thread);
if (r_modelscene)
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
uint64_t step64 = sampler.uv_step;
uint64_t pos64 = sampler.uv_pos;
sampler.uv_pos = (uint32_t)(pos64 + step64 * count);
}
else
{
if (sampler.uv_max == 0 || sampler.uv_step == 0) // power of two
{
int count = y2 - y1;
drawerargs.SetTexture(sampler.source, sampler.source2, sampler.height);
drawerargs.SetTextureUPos(sampler.texturefracx);
drawerargs.SetDest(Thread->Viewport.get(), x, y1);
drawerargs.SetCount(count);
drawerargs.SetTextureVStep(sampler.uv_step);
drawerargs.SetTextureVPos(sampler.uv_pos);
drawerargs.DrawColumn(Thread);
if (r_modelscene)
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
uint64_t step64 = sampler.uv_step;
uint64_t pos64 = sampler.uv_pos;
sampler.uv_pos = (uint32_t)(pos64 + step64 * count);
}
else
{
uint32_t uv_pos = sampler.uv_pos;
uint32_t left = y2 - y1;
int y = y1;
while (left > 0)
{
uint32_t available = sampler.uv_max - uv_pos;
uint32_t next_uv_wrap = available / sampler.uv_step;
if (available % sampler.uv_step != 0)
next_uv_wrap++;
uint32_t count = MIN(left, next_uv_wrap);
drawerargs.SetTexture(sampler.source, sampler.source2, sampler.height);
drawerargs.SetTextureUPos(sampler.texturefracx);
drawerargs.SetDest(Thread->Viewport.get(), x, y);
drawerargs.SetCount(count);
drawerargs.SetTextureVStep(sampler.uv_step);
drawerargs.SetTextureVPos(uv_pos);
drawerargs.DrawColumn(Thread);
if (r_modelscene)
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
y += count;
left -= count;
uv_pos += sampler.uv_step * count;
if (uv_pos >= sampler.uv_max)
uv_pos -= sampler.uv_max;
}
sampler.uv_pos = uv_pos;
}
}
}
void RenderWallPart::ProcessWallWorker(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal)
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal)
{
if (rw_pic == nullptr)
return;
@ -344,54 +67,347 @@ namespace swrenderer
texturemid = 0;
}
WallDrawerArgs drawerargs;
drawerargs.SetTextureFracBits(Thread->Viewport->RenderTarget->IsBgra() ? FRACBITS : fracbits);
// Textures that aren't masked can use the faster opaque drawer
if (!rw_pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive)
{
drawerargs.SetStyle(true, false, OPAQUE, basecolormap);
drawerargs.SetStyle(true, false, OPAQUE, mLight.GetBaseColormap());
}
else
{
drawerargs.SetStyle(mask, additive, alpha, basecolormap);
drawerargs.SetStyle(mask, additive, alpha, mLight.GetBaseColormap());
}
CameraLight *cameraLight = CameraLight::Instance();
bool fixed = (cameraLight->FixedColormap() != NULL || cameraLight->FixedLightLevel() >= 0);
RenderViewport *viewport = Thread->Viewport.get();
float dx = WallC.tright.X - WallC.tleft.X;
float dy = WallC.tright.Y - WallC.tleft.Y;
float length = sqrt(dx * dx + dy * dy);
drawerargs.dc_normal.X = dy / length;
drawerargs.dc_normal.Y = -dx / length;
drawerargs.dc_normal.Z = 0.0f;
CameraLight *cameraLight = CameraLight::Instance();
bool fixed = (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0);
bool haslights = r_dynlights && light_list;
if (haslights)
{
float dx = WallC.tright.X - WallC.tleft.X;
float dy = WallC.tright.Y - WallC.tleft.Y;
float length = sqrt(dx * dx + dy * dy);
drawerargs.dc_normal.X = dy / length;
drawerargs.dc_normal.Y = -dx / length;
drawerargs.dc_normal.Z = 0.0f;
}
double xmagnitude = 1.0;
float curlight = light;
for (int x = x1; x < x2; x++, curlight += lightstep)
float curlight = mLight.GetLightPos(x1);
float lightstep = mLight.GetLightStep();
if (viewport->RenderTarget->IsBgra())
{
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 <= y1)
continue;
for (int x = x1; x < x2; x++, curlight += lightstep)
{
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 <= y1)
continue;
if (!fixed)
drawerargs.SetLight(curlight, lightlevel, foggy, Thread->Viewport.get());
if (!fixed)
drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x]));
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x]));
WallSampler sampler(Thread->Viewport.get(), y1, texturemid, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic);
Draw1Column(x, y1, y2, sampler);
fixed_t xxoffset = (lwal[x] + xoffset + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale();
// Normalize to 0-1 range:
double uv_stepd = swal[x] * yrepeat;
double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight();
v = v - floor(v);
double v_step = uv_stepd / rw_pic->GetHeight();
if (std::isnan(v) || std::isnan(v_step)) // this should never happen, but it apparently does..
{
uv_stepd = 0.0;
v = 0.0;
v_step = 0.0;
}
// Convert to uint32_t:
uint32_t uv_pos = (uint32_t)(int64_t)(v * 0x100000000LL);
uint32_t uv_step = (uint32_t)(int64_t)(v_step * 0x100000000LL);
// Texture mipmap and filter selection:
double ymagnitude = fabs(uv_stepd);
double magnitude = MAX(ymagnitude, xmagnitude);
double min_lod = -1000.0;
double lod = MAX(log2(magnitude) + r_lod_bias, min_lod);
bool magnifying = lod < 0.0f;
int mipmap_offset = 0;
int mip_width = rw_pic->GetPhysicalWidth();
int mip_height = rw_pic->GetPhysicalHeight();
if (r_mipmap && rw_pic->Mipmapped() && mip_width > 1 && mip_height > 1)
{
uint32_t xpos = (uint32_t)((((uint64_t)xxoffset) << FRACBITS) / mip_width);
int level = (int)lod;
while (level > 0 && mip_width > 1 && mip_height > 1)
{
mipmap_offset += mip_width * mip_height;
level--;
mip_width = MAX(mip_width >> 1, 1);
mip_height = MAX(mip_height >> 1, 1);
}
xxoffset = (xpos >> FRACBITS) * mip_width;
}
const uint32_t *pixels = rw_pic->GetPixelsBgra() + mipmap_offset;
const uint8_t *source;
const uint8_t *source2;
uint32_t texturefracx;
uint32_t height;
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
if (filter_nearest)
{
int tx = (xxoffset >> FRACBITS) % mip_width;
if (tx < 0)
tx += mip_width;
source = (uint8_t*)(pixels + tx * mip_height);
source2 = nullptr;
height = mip_height;
texturefracx = 0;
}
else
{
xxoffset -= FRACUNIT / 2;
int tx0 = (xxoffset >> FRACBITS) % mip_width;
if (tx0 < 0)
tx0 += mip_width;
int tx1 = (tx0 + 1) % mip_width;
source = (uint8_t*)(pixels + tx0 * mip_height);
source2 = (uint8_t*)(pixels + tx1 * mip_height);
height = mip_height;
texturefracx = (xxoffset >> (FRACBITS - 4)) & 15;
}
drawerargs.SetTexture(source, source2, height);
if (haslights)
SetLights(drawerargs, x, y1);
else
drawerargs.dc_num_lights = 0;
drawerargs.SetTextureUPos(texturefracx);
drawerargs.SetTextureVStep(uv_step);
int count = y2 - y1;
drawerargs.SetDest(viewport, x, y1);
drawerargs.SetCount(count);
drawerargs.SetTextureVPos(uv_pos);
drawerargs.DrawColumn(Thread);
}
}
else
{
uint32_t height = rw_pic->GetPhysicalHeight();
uint32_t uv_max;
int uv_fracbits = 32 - rw_pic->GetHeightBits();
if (uv_fracbits != 32)
uv_max = height << uv_fracbits;
for (int x = x1; x < x2; x++, curlight += lightstep)
{
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 <= y1)
continue;
if (!fixed)
drawerargs.SetLight(curlight, mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x]));
uint32_t uv_pos;
uint32_t uv_step;
fixed_t xxoffset = (lwal[x] + xoffset + FLOAT2FIXED(xmagnitude * 0.5)) * rw_pic->GetPhysicalScale();
if (uv_fracbits != 32)
{
// Find start uv in [0-base_height[ range.
// Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range.
double uv_stepd = swal[x] * yrepeat;
double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / rw_pic->GetHeight();
v = v - floor(v);
v *= height;
v *= (1 << uv_fracbits);
uv_pos = (uint32_t)(int64_t)v;
uv_step = xs_ToFixed(uv_fracbits, uv_stepd * rw_pic->GetPhysicalScale());
if (uv_step == 0) // To prevent divide by zero elsewhere
uv_step = 1;
}
else
{ // Hack for one pixel tall textures
uv_pos = 0;
uv_step = 0;
uv_max = 1;
}
int col = xxoffset >> FRACBITS;
// If the texture's width isn't a power of 2, then we need to make it a
// positive offset for proper clamping.
int width;
if (col < 0 && (width = rw_pic->GetPhysicalWidth()) != (1 << rw_pic->GetWidthBits()))
{
col = width + (col % width);
}
drawerargs.SetTexture(rw_pic->GetColumn(DefaultRenderStyle(), col, nullptr), nullptr, height);
if (haslights)
SetLights(drawerargs, x, y1);
else
drawerargs.dc_num_lights = 0;
drawerargs.SetTextureVStep(uv_step);
if (uv_max == 0 || uv_step == 0) // power of two
{
int count = y2 - y1;
drawerargs.SetDest(viewport, x, y1);
drawerargs.SetCount(count);
drawerargs.SetTextureVPos(uv_pos);
drawerargs.DrawColumn(Thread);
}
else
{
uint32_t left = y2 - y1;
int y = y1;
while (left > 0)
{
uint32_t available = uv_max - uv_pos;
uint32_t next_uv_wrap = available / uv_step;
if (available % uv_step != 0)
next_uv_wrap++;
uint32_t count = MIN(left, next_uv_wrap);
drawerargs.SetDest(viewport, x, y);
drawerargs.SetCount(count);
drawerargs.SetTextureVPos(uv_pos);
drawerargs.DrawColumn(Thread);
y += count;
left -= count;
uv_pos += uv_step * count;
if (uv_pos >= uv_max)
uv_pos -= uv_max;
}
}
}
}
if (Thread->MainThread)
NetUpdate();
if (r_modelscene)
{
for (int x = x1; x < x2; x++)
{
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 > y1)
{
int count = y2 - y1;
float w1 = 1.0f / WallC.sz1;
float w2 = 1.0f / WallC.sz2;
float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1);
float wcol = w1 * (1.0f - t) + w2 * t;
float zcol = 1.0f / wcol;
float zbufferdepth = 1.0f / (zcol / viewport->viewwindow.FocalTangent);
drawerargs.SetDest(viewport, x, y1);
drawerargs.SetCount(count);
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
}
}
}
}
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal)
void RenderWallPart::SetLights(WallDrawerArgs &drawerargs, int x, int y1)
{
ProcessWallWorker(uwal, dwal, texturemid, swal, lwal);
bool mirror = !!(Thread->Portal->MirrorFlags & RF_XFLIP);
int tx = x;
if (mirror)
tx = viewwidth - tx - 1;
RenderViewport *viewport = Thread->Viewport.get();
// Find column position in view space
float w1 = 1.0f / WallC.sz1;
float w2 = 1.0f / WallC.sz2;
float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1);
float wcol = w1 * (1.0f - t) + w2 * t;
float zcol = 1.0f / wcol;
drawerargs.dc_viewpos.X = (float)((tx + 0.5 - viewport->CenterX) / viewport->CenterX * zcol);
drawerargs.dc_viewpos.Y = zcol;
drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol);
drawerargs.dc_viewpos_step.Z = (float)(-zcol / viewport->InvZtoScale);
// Calculate max lights that can touch column so we can allocate memory for the list
int max_lights = 0;
FLightNode *cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
max_lights++;
cur_node = cur_node->nextLight;
}
drawerargs.dc_num_lights = 0;
drawerargs.dc_lights = Thread->FrameMemory->AllocMemory<DrawerLight>(max_lights);
// Setup lights for column
cur_node = light_list;
while (cur_node)
{
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
{
double lightX = cur_node->lightsource->X() - viewport->viewpoint.Pos.X;
double lightY = cur_node->lightsource->Y() - viewport->viewpoint.Pos.Y;
double lightZ = cur_node->lightsource->Z() - viewport->viewpoint.Pos.Z;
float lx = (float)(lightX * viewport->viewpoint.Sin - lightY * viewport->viewpoint.Cos) - drawerargs.dc_viewpos.X;
float ly = (float)(lightX * viewport->viewpoint.TanCos + lightY * viewport->viewpoint.TanSin) - drawerargs.dc_viewpos.Y;
float lz = (float)lightZ;
// Precalculate the constant part of the dot here so the drawer doesn't have to.
bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0;
float lconstant = lx * lx + ly * ly;
float nlconstant = is_point_light ? lx * drawerargs.dc_normal.X + ly * drawerargs.dc_normal.Y : 0.0f;
// Include light only if it touches this column
float radius = cur_node->lightsource->GetRadius();
if (radius * radius >= lconstant && nlconstant >= 0.0f)
{
uint32_t red = cur_node->lightsource->GetRed();
uint32_t green = cur_node->lightsource->GetGreen();
uint32_t blue = cur_node->lightsource->GetBlue();
auto &light = drawerargs.dc_lights[drawerargs.dc_num_lights++];
light.x = lconstant;
light.y = nlconstant;
light.z = lz;
light.radius = 256.0f / cur_node->lightsource->GetRadius();
light.color = (red << 16) | (green << 8) | blue;
}
}
cur_node = cur_node->nextLight;
}
}
void RenderWallPart::ProcessStripedWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal)
@ -423,9 +439,7 @@ namespace swrenderer
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
lightlist_t *lit = &frontsector->e->XFloor.lightlist[i];
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
lightlevel = curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL);
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
}
ProcessNormalWall(up, dwal, texturemid, swal, lwal);
@ -516,7 +530,7 @@ namespace swrenderer
}
}
void RenderWallPart::Render(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, double texturemid, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, bool additive, fixed_t alpha, int lightlevel, fixed_t xoffset, float light, float lightstep, FLightNode *light_list, bool foggy, FDynamicColormap *basecolormap)
void RenderWallPart::Render(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, double texturemid, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, bool additive, fixed_t alpha, fixed_t xoffset, const ProjectedWallLight &light, FLightNode *light_list)
{
this->x1 = x1;
this->x2 = x2;
@ -524,18 +538,17 @@ namespace swrenderer
this->curline = curline;
this->WallC = WallC;
this->yrepeat = yscale;
this->lightlevel = lightlevel;
this->mLight = light;
this->xoffset = xoffset;
this->light = light;
this->lightstep = lightstep;
this->foggy = foggy;
this->basecolormap = basecolormap;
this->light_list = light_list;
this->rw_pic = pic;
this->mask = mask;
this->additive = additive;
this->alpha = alpha;
if (Thread->MainThread)
NetUpdate();
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
if (rw_pic->GetHeight() != 1 << rw_pic->GetHeightBits())

View file

@ -63,13 +63,9 @@ namespace swrenderer
bool mask,
bool additive,
fixed_t alpha,
int lightlevel,
fixed_t xoffset,
float light,
float lightstep,
FLightNode *light_list,
bool foggy,
FDynamicColormap *basecolormap);
const ProjectedWallLight &light,
FLightNode *light_list);
RenderThread *Thread = nullptr;
@ -78,8 +74,7 @@ namespace swrenderer
void ProcessWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal);
void ProcessStripedWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal);
void ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal);
void ProcessWallWorker(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal);
void Draw1Column(int x, int y1, int y2, WallSampler &sampler);
void SetLights(WallDrawerArgs &drawerargs, int x, int y1);
int x1 = 0;
int x2 = 0;
@ -88,33 +83,13 @@ namespace swrenderer
seg_t *curline = nullptr;
FWallCoords WallC;
ProjectedWallLight mLight;
double yrepeat = 0.0;
int lightlevel = 0;
fixed_t xoffset = 0;
float light = 0.0f;
float lightstep = 0.0f;
bool foggy = false;
FDynamicColormap *basecolormap = nullptr;
FLightNode *light_list = nullptr;
bool mask = false;
bool additive = false;
fixed_t alpha = 0;
WallDrawerArgs drawerargs;
};
struct WallSampler
{
WallSampler() { }
WallSampler(RenderViewport *viewport, int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FSoftwareTexture *texture);
uint32_t uv_pos;
uint32_t uv_step;
uint32_t uv_max;
const uint8_t *source;
const uint8_t *source2;
uint32_t texturefracx;
uint32_t height;
};
}

View file

@ -241,4 +241,43 @@ namespace swrenderer
}
}
}
/////////////////////////////////////////////////////////////////////////
void ProjectedWallLight::SetLightLeft(RenderThread *thread, const FWallCoords &wallc)
{
x1 = wallc.sx1;
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() == nullptr && cameraLight->FixedLightLevel() < 0)
{
lightleft = float(thread->Light->WallVis(wallc.sz1, foggy));
lightstep = float((thread->Light->WallVis(wallc.sz2, foggy) - lightleft) / (wallc.sx2 - wallc.sx1));
}
else
{
lightleft = 1;
lightstep = 0;
}
}
void ProjectedWallLight::SetColormap(const sector_t *frontsector, seg_t *lineseg, lightlist_t *lit)
{
if (!lit)
{
basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
foggy = level.fadeto || frontsector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE);
if (!(lineseg->sidedef->Flags & WALLF_POLYOBJ))
lightlevel = lineseg->sidedef->GetLightLevel(foggy, frontsector->lightlevel);
else
lightlevel = frontsector->GetLightLevel();
}
else
{
basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]);
foggy = level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE);
lightlevel = lineseg->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != nullptr);
}
}
}

View file

@ -56,4 +56,29 @@ namespace swrenderer
void Project(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT);
void ProjectPos(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT);
};
class ProjectedWallLight
{
public:
int GetLightLevel() const { return lightlevel; }
bool GetFoggy() const { return foggy; }
FDynamicColormap *GetBaseColormap() const { return basecolormap; }
float GetLightPos(int x) const { return lightleft + lightstep * (x - x1); }
float GetLightStep() const { return lightstep; }
void SetColormap(const sector_t *frontsector, seg_t *lineseg, lightlist_t *lit = nullptr);
void SetLightLeft(float left, float step, int startx) { lightleft = left; lightstep = step; x1 = startx; }
void SetLightLeft(RenderThread *thread, const FWallCoords &wallc);
private:
int lightlevel;
bool foggy;
FDynamicColormap *basecolormap;
int x1;
float lightleft;
float lightstep;
};
}

View file

@ -451,7 +451,7 @@ namespace swrenderer
}
// kg3D - add fake segs, never rendered
void RenderOpaquePass::FakeDrawLoop(subsector_t *sub, sector_t *frontsector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, bool foggy, FDynamicColormap *basecolormap, Fake3DOpaque opaque3dfloor)
void RenderOpaquePass::FakeDrawLoop(subsector_t *sub, sector_t *frontsector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, Fake3DOpaque opaque3dfloor)
{
int count;
seg_t* line;
@ -463,7 +463,7 @@ namespace swrenderer
{
if ((line->sidedef) && !(line->sidedef->Flags & WALLF_POLYOBJ))
{
renderline.Render(line, InSubsector, frontsector, nullptr, floorplane, ceilingplane, foggy, basecolormap, opaque3dfloor);
renderline.Render(line, InSubsector, frontsector, nullptr, floorplane, ceilingplane, opaque3dfloor);
}
line++;
}
@ -622,8 +622,6 @@ namespace swrenderer
DVector2 viewpointPos = Thread->Viewport->viewpoint.Pos.XY();
basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
seg_t *line = sub->firstline;
int count = sub->numlines;
while (count--)
@ -637,8 +635,8 @@ namespace swrenderer
}
else if (!outersubsector || line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ))
{
Add3DFloorLine(line, frontsector, basecolormap, foggy);
renderline.Render(line, InSubsector, frontsector, nullptr, floorplane, ceilingplane, foggy, basecolormap, Fake3DOpaque::Normal); // now real
Add3DFloorLine(line, frontsector);
renderline.Render(line, InSubsector, frontsector, nullptr, floorplane, ceilingplane, Fake3DOpaque::Normal); // now real
}
line++;
}
@ -648,7 +646,7 @@ namespace swrenderer
}
}
void RenderOpaquePass::Add3DFloorLine(seg_t *line, sector_t *frontsector, FDynamicColormap *basecolormap, bool foggy)
void RenderOpaquePass::Add3DFloorLine(seg_t *line, sector_t *frontsector)
{
// kg3D - fake planes bounding calculation
if (r_3dfloors && line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())
@ -669,7 +667,7 @@ namespace swrenderer
clip3d->fakeFloor->validcount = validcount;
clip3d->NewClip();
}
renderline.Render(line, InSubsector, frontsector, &tempsec, nullptr, nullptr, foggy, basecolormap, opaque3dfloor); // fake
renderline.Render(line, InSubsector, frontsector, &tempsec, nullptr, nullptr, opaque3dfloor); // fake
}
clip3d->fakeFloor = nullptr;
}
@ -744,7 +742,7 @@ namespace swrenderer
floorplane3d->AddLights(Thread, sub->section->lighthead);
FakeDrawLoop(sub, &tempsec, floorplane3d, nullptr, foggy, basecolormap, Fake3DOpaque::FakeFloor);
FakeDrawLoop(sub, &tempsec, floorplane3d, nullptr, Fake3DOpaque::FakeFloor);
}
}
// and now ceilings
@ -812,7 +810,7 @@ namespace swrenderer
ceilingplane3d->AddLights(Thread, sub->section->lighthead);
FakeDrawLoop(sub, &tempsec, nullptr, ceilingplane3d, foggy, basecolormap, Fake3DOpaque::FakeCeiling);
FakeDrawLoop(sub, &tempsec, nullptr, ceilingplane3d, Fake3DOpaque::FakeCeiling);
}
}
clip3d->fakeFloor = nullptr;

View file

@ -86,8 +86,8 @@ namespace swrenderer
void AddPolyobjs(subsector_t *sub);
void Add3DFloorPlanes(subsector_t *sub, sector_t *frontsector, FDynamicColormap *basecolormap, bool foggy, int adjusted_ceilinglightlevel, int adjusted_floorlightlevel);
void FakeDrawLoop(subsector_t *sub, sector_t *frontsector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, bool foggy, FDynamicColormap *basecolormap, Fake3DOpaque opaque3dfloor);
void Add3DFloorLine(seg_t *line, sector_t *frontsector, FDynamicColormap *basecolormap, bool foggy);
void FakeDrawLoop(subsector_t *sub, sector_t *frontsector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, Fake3DOpaque opaque3dfloor);
void Add3DFloorLine(seg_t *line, sector_t *frontsector);
void AddSprites(sector_t *sec, int lightlevel, WaterFakeSide fakeside, bool foggy, FDynamicColormap *basecolormap);
bool IsPotentiallyVisible(AActor *thing);

View file

@ -206,10 +206,8 @@ namespace swrenderer
// Create a drawseg to clip sprites to the sky plane
DrawSegment *draw_segment = Thread->FrameMemory->NewObject<DrawSegment>();
draw_segment->CurrentPortalUniq = CurrentPortalUniq;
draw_segment->siz1 = INT_MAX;
draw_segment->siz2 = INT_MAX;
draw_segment->sz1 = 0;
draw_segment->sz2 = 0;
draw_segment->WallC.sz1 = 0;
draw_segment->WallC.sz2 = 0;
draw_segment->x1 = pl->left;
draw_segment->x2 = pl->right;
draw_segment->silhouette = SIL_BOTH;
@ -219,7 +217,6 @@ namespace swrenderer
draw_segment->swall = nullptr;
draw_segment->bFogBoundary = false;
draw_segment->curline = nullptr;
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));
drawseglist->Push(draw_segment);

View file

@ -107,18 +107,18 @@ namespace swrenderer
group.EndIndex = MIN(index + groupSize, SegmentsCount());
group.x1 = ds->x1;
group.x2 = ds->x2;
group.neardepth = MIN(ds->sz1, ds->sz2);
group.fardepth = MAX(ds->sz1, ds->sz2);
group.neardepth = MIN(ds->WallC.sz1, ds->WallC.sz2);
group.fardepth = MAX(ds->WallC.sz1, ds->WallC.sz2);
for (unsigned int groupIndex = group.BeginIndex + 1; groupIndex < group.EndIndex; groupIndex++)
{
ds = Segment(groupIndex);
group.x1 = MIN(group.x1, ds->x1);
group.x2 = MAX(group.x2, ds->x2);
group.neardepth = MIN(group.neardepth, ds->sz1);
group.neardepth = MIN(group.neardepth, ds->sz2);
group.fardepth = MAX(ds->sz1, group.fardepth);
group.fardepth = MAX(ds->sz2, group.fardepth);
group.neardepth = MIN(group.neardepth, ds->WallC.sz1);
group.neardepth = MIN(group.neardepth, ds->WallC.sz2);
group.fardepth = MAX(ds->WallC.sz1, group.fardepth);
group.fardepth = MAX(ds->WallC.sz2, group.fardepth);
}
for (int x = group.x1; x < group.x2; x++)

View file

@ -31,15 +31,10 @@ namespace swrenderer
float light, lightstep;
float iscale, iscalestep;
short x1, x2; // Same as sx1 and sx2, but clipped to the drawseg
short sx1, sx2; // left, right of parent seg on screen
float sz1, sz2; // z for left, right of parent seg on screen
float siz1, siz2; // 1/z for left, right of parent seg on screen
float cx, cy, cdx, cdy;
FWallCoords WallC;
float yscale;
uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both
bool bFogBoundary = false;
int lightlevel = 0;
bool foggy = false;
// Pointers to lists for sprite clipping, all three adjusted so [x1] is first value.
short *sprtopclip = nullptr;

View file

@ -57,15 +57,15 @@ EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
void RenderDecal::RenderDecals(RenderThread *thread, side_t *sidedef, DrawSegment *draw_segment, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass)
void RenderDecal::RenderDecals(RenderThread *thread, side_t *sidedef, DrawSegment *draw_segment, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass)
{
for (DBaseDecal *decal = sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
{
Render(thread, sidedef, decal, draw_segment, lightlevel, lightleft, lightstep, curline, wallC, foggy, basecolormap, walltop, wallbottom, drawsegPass);
Render(thread, sidedef, decal, draw_segment, curline, light, walltop, wallbottom, drawsegPass);
}
}
void RenderDecal::Render(RenderThread *thread, side_t *wall, DBaseDecal *decal, DrawSegment *clipper, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &savecoord, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass)
void RenderDecal::Render(RenderThread *thread, side_t *wall, DBaseDecal *decal, DrawSegment *clipper, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass)
{
DVector2 decal_left, decal_right, decal_pos;
int x1, x2;
@ -75,7 +75,6 @@ namespace swrenderer
int needrepeat = 0;
sector_t *back;
FDynamicColormap *usecolormap;
float light = 0;
const short *mfloorclip;
const short *mceilingclip;
@ -257,7 +256,7 @@ namespace swrenderer
}
// Prepare lighting
usecolormap = basecolormap;
usecolormap = light.GetBaseColormap();
// Decals that are added to the scene must fade to black.
if (decal->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0)
@ -265,7 +264,7 @@ namespace swrenderer
usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
}
light = lightleft + (x1 - savecoord.sx1) * lightstep;
float lightpos = light.GetLightPos(x1);
cameraLight = CameraLight::Instance();
@ -288,7 +287,7 @@ namespace swrenderer
int x = x1;
ColormapLight cmlight;
cmlight.SetColormap(thread, MINZ, lightlevel, foggy, usecolormap, decal->RenderFlags & RF_FULLBRIGHT, false, false, false, false);
cmlight.SetColormap(thread, MINZ, light.GetLightLevel(), light.GetFoggy(), usecolormap, decal->RenderFlags & RF_FULLBRIGHT, false, false, false, false);
SpriteDrawerArgs drawerargs;
bool visible = drawerargs.SetStyle(thread->Viewport.get(), decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor, cmlight);
@ -301,10 +300,10 @@ namespace swrenderer
{
if (calclighting)
{ // calculate lighting
drawerargs.SetLight(light, lightlevel, foggy, thread->Viewport.get());
drawerargs.SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get());
}
DrawColumn(thread, drawerargs, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle);
light += lightstep;
lightpos += light.GetLightStep();
x++;
}
}

View file

@ -12,10 +12,10 @@ namespace swrenderer
class RenderDecal
{
public:
static void RenderDecals(RenderThread *thread, side_t *wall, DrawSegment *draw_segment, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass);
static void RenderDecals(RenderThread *thread, side_t *wall, DrawSegment *draw_segment, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass);
private:
static void Render(RenderThread *thread, side_t *wall, DBaseDecal *first, DrawSegment *clipper, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass);
static void Render(RenderThread *thread, side_t *wall, DBaseDecal *first, DrawSegment *clipper, seg_t *curline, const ProjectedWallLight &light, const short *walltop, const short *wallbottom, bool drawsegPass);
static void DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FSoftwareTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style);
};
}

View file

@ -291,7 +291,9 @@ namespace swrenderer
{
continue;
}
if ((ds->siz2 - ds->siz1) * ((x2 + x1) / 2 - ds->sx1) / (ds->sx2 - ds->sx1) + ds->siz1 < idepth)
float siz1 = 1 / ds->WallC.sz1;
float siz2 = 1 / ds->WallC.sz2;
if ((siz2 - siz1) * ((x2 + x1) / 2 - ds->WallC.sx1) / (ds->WallC.sx2 - ds->WallC.sx1) + siz1 < idepth)
{
// [ZZ] only draw stuff that's inside the same portal as the particle, other portals will care for themselves
if (ds->CurrentPortalUniq == CurrentPortalUniq)

View file

@ -340,8 +340,8 @@ namespace swrenderer
continue;
}
float neardepth = MIN(ds->sz1, ds->sz2);
float fardepth = MAX(ds->sz1, ds->sz2);
float neardepth = MIN(ds->WallC.sz1, ds->WallC.sz2);
float fardepth = MAX(ds->WallC.sz1, ds->WallC.sz2);
// Check if sprite is in front of draw seg:
if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) &&
@ -414,8 +414,8 @@ namespace swrenderer
int r1 = MAX<int>(ds->x1, x1);
int r2 = MIN<int>(ds->x2, x2);
float neardepth = MIN(ds->sz1, ds->sz2);
float fardepth = MAX(ds->sz1, ds->sz2);
float neardepth = MIN(ds->WallC.sz1, ds->WallC.sz2);
float fardepth = MAX(ds->WallC.sz1, ds->WallC.sz2);
// Check if sprite is in front of draw seg:
if ((!spr->IsWallSprite() && neardepth > spr->depth) || ((spr->IsWallSprite() || fardepth > spr->depth) &&

View file

@ -48,16 +48,16 @@ const char *GetVersionString();
#ifdef GIT_DESCRIPTION
#define VERSIONSTR GIT_DESCRIPTION
#else
#define VERSIONSTR "3.7pre"
#define VERSIONSTR "3.8pre"
#endif
// The version as seen in the Windows resource
#define RC_FILEVERSION 3,6,9999,0
#define RC_PRODUCTVERSION 3,6,9999,0
#define RC_FILEVERSION 3,7,9999,0
#define RC_PRODUCTVERSION 3,7,9999,0
#define RC_PRODUCTVERSION2 VERSIONSTR
// These are for content versioning.
#define VER_MAJOR 3
#define VER_MINOR 7
#define VER_MINOR 8
#define VER_REVISION 0
// Version identifier for network games.

View file

@ -146,6 +146,12 @@ class LevelCompatibility native play
SetLineActivation(959, SPAC_Cross);
SetLineSpecial(960, Floor_RaiseToNearest, 16, 32);
SetLineActivation(960, SPAC_Cross);
// Dropping into the holes themselves raises sectors
for(int i=0; i<9; i++)
{
SetLineSpecial(999+i, Floor_RaiseToNearest, 16, 32);
SetLineActivation(999+i, SPAC_Cross);
}
break;
}
@ -179,6 +185,7 @@ class LevelCompatibility native play
}
case 'A53AE580A4AF2B5D0B0893F86914781E': // TNT: Evilution map31
case '55192065F7FAA7D161767145DA008293': // TNT Anthology/GOG MAP31
{
// The famous missing yellow key...
SetThingFlags(470, 2016);
@ -234,6 +241,15 @@ class LevelCompatibility native play
break;
}
case 'ECA0559E85EFFB6966ECB8DE01E3A35B': // Plutonia Experiment MAP16
{
// Have it so that the slime pit at the end of the level can
// actually kill the player.
SetSectorSpecial(95, 768);
SetSectorSpecial(96, 768);
break;
}
case '9D84B423D8FD28553DDE23B55F97CF4A': // Plutonia Experiment MAP25
{
// Missing texture at level exit.