Merge remote-tracking branch 'origin/master' into polybackend

This commit is contained in:
Magnus Norddahl 2019-12-01 20:09:19 +01:00
commit 4a25c9f69b
658 changed files with 75029 additions and 68704 deletions

View file

@ -37,92 +37,137 @@ EXTERN_CVAR(Float, transsouls)
IMPLEMENT_CLASS(DShape2DTransform, false, false)
DEFINE_ACTION_FUNCTION(DShape2DTransform, Clear)
static void Shape2DTransform_Clear(DShape2DTransform* self)
{
self->transform.Identity();
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Clear, Shape2DTransform_Clear)
{
PARAM_SELF_PROLOGUE(DShape2DTransform);
self->transform.Identity();
Shape2DTransform_Clear(self);
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2DTransform, Rotate)
static void Shape2DTransform_Rotate(DShape2DTransform* self, double angle)
{
self->transform = DMatrix3x3::Rotate2D(DEG2RAD(angle)) * self->transform;
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Rotate, Shape2DTransform_Rotate)
{
PARAM_SELF_PROLOGUE(DShape2DTransform);
PARAM_FLOAT(angle);
self->transform = DMatrix3x3::Rotate2D(DEG2RAD(angle)) * self->transform;
Shape2DTransform_Rotate(self, angle);
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2DTransform, Scale)
static void Shape2DTransform_Scale(DShape2DTransform* self, double x, double y)
{
PARAM_SELF_PROLOGUE(DShape2DTransform);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
self->transform = DMatrix3x3::Scale2D(DVector2(x, y)) * self->transform;
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2DTransform, Translate)
DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Scale, Shape2DTransform_Scale)
{
PARAM_SELF_PROLOGUE(DShape2DTransform);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
Shape2DTransform_Scale(self, x, y);
return 0;
}
static void Shape2DTransform_Translate(DShape2DTransform* self, double x, double y)
{
self->transform = DMatrix3x3::Translate2D(DVector2(x, y)) * self->transform;
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Translate, Shape2DTransform_Translate)
{
PARAM_SELF_PROLOGUE(DShape2DTransform);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
Shape2DTransform_Translate(self, x, y);
return 0;
}
IMPLEMENT_CLASS(DShape2D, false, false)
DEFINE_ACTION_FUNCTION(DShape2D, SetTransform)
static void Shape2D_SetTransform(DShape2D* self, DShape2DTransform *transform)
{
self->transform = transform->transform;
self->dirty = true;
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, SetTransform, Shape2D_SetTransform)
{
PARAM_SELF_PROLOGUE(DShape2D);
PARAM_OBJECT(transform, DShape2DTransform);
self->transform = transform->transform;
self->dirty = true;
Shape2D_SetTransform(self, transform);
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2D, Clear)
static void Shape2D_Clear(DShape2D* self, int which)
{
PARAM_SELF_PROLOGUE(DShape2D);
PARAM_INT(which);
if ( which&C_Verts )
if (which & C_Verts)
{
self->mVertices.Clear();
self->dirty = true;
}
if ( which&C_Coords ) self->mCoords.Clear();
if ( which&C_Indices ) self->mIndices.Clear();
if (which & C_Coords) self->mCoords.Clear();
if (which & C_Indices) self->mIndices.Clear();
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear)
{
PARAM_SELF_PROLOGUE(DShape2D);
PARAM_INT(which);
Shape2D_Clear(self, which);
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2D, PushVertex)
static void Shape2D_PushVertex(DShape2D* self, double x, double y)
{
self->mVertices.Push(DVector2(x, y));
self->dirty = true;
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex)
{
PARAM_SELF_PROLOGUE(DShape2D);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
self->mVertices.Push(DVector2(x,y));
self->dirty = true;
Shape2D_PushVertex(self, x, y);
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2D, PushCoord)
static void Shape2D_PushCoord(DShape2D* self, double u, double v)
{
self->mCoords.Push(DVector2(u, v));
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord)
{
PARAM_SELF_PROLOGUE(DShape2D);
PARAM_FLOAT(u);
PARAM_FLOAT(v);
self->mCoords.Push(DVector2(u,v));
Shape2D_PushCoord(self, u, v);
return 0;
}
DEFINE_ACTION_FUNCTION(DShape2D, PushTriangle)
static void Shape2D_PushTriangle(DShape2D* self, int a, int b, int c)
{
self->mIndices.Push(a);
self->mIndices.Push(b);
self->mIndices.Push(c);
}
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle)
{
PARAM_SELF_PROLOGUE(DShape2D);
PARAM_INT(a);
PARAM_INT(b);
PARAM_INT(c);
self->mIndices.Push(a);
self->mIndices.Push(b);
self->mIndices.Push(c);
Shape2D_PushTriangle(self, a, b, c);
return 0;
}

View file

@ -1132,7 +1132,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawLine)
PARAM_INT(color);
PARAM_INT(alpha);
if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
screen->DrawLine(x0, y0, x1, y1, -1, color, alpha);
screen->DrawLine(x0, y0, x1, y1, -1, color | MAKEARGB(255, 0, 0, 0), alpha);
return 0;
}

View file

@ -104,14 +104,10 @@ void InitSkyMap(FLevelLocals *Level)
// of the texture is at the top of the screen when looking fully up.
skyheight = skytex1->GetDisplayHeight();
if (skyheight >= 128 && skyheight < 200)
{
Level->skystretch = (r_skymode == 1
&& skyheight >= 128
&& Level->IsFreelookAllowed()
&& !(Level->flags & LEVEL_FORCETILEDSKY)) ? 1 : 0;
}
else Level->skystretch = false;
Level->skystretch = (r_skymode == 1
&& skyheight >= 128 && skyheight <= 256
&& Level->IsFreelookAllowed()
&& !(Level->flags & LEVEL_FORCETILEDSKY)) ? 1 : 0;
}
void R_InitSkyMap()

View file

@ -64,7 +64,6 @@
#include "actorinlines.h"
#include "g_game.h"
#include "i_system.h"
#include "atterm.h"
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -154,7 +153,6 @@ DAngle viewpitch;
DEFINE_GLOBAL(LocalViewPitch);
// CODE --------------------------------------------------------------------
static void R_Shutdown ();
//==========================================================================
//
@ -380,8 +378,6 @@ FRenderer *CreateSWRenderer();
void R_Init ()
{
atterm (R_Shutdown);
StartScreen->Progress();
R_InitTranslationTables ();
R_SetViewSize (screenblocks);
@ -400,12 +396,10 @@ void R_Init ()
//
//==========================================================================
static void R_Shutdown ()
void R_Shutdown ()
{
if (SWRenderer != nullptr) delete SWRenderer;
SWRenderer = nullptr;
R_DeinitTranslationTables();
R_DeinitColormaps ();
}
//==========================================================================

View file

@ -51,6 +51,7 @@
#include "r_draw_pal.h"
#include "r_thread.h"
#include "swrenderer/scene/r_light.h"
#include "playsim/a_dynlight.h"
#include "polyrenderer/drawers/poly_triangle.h"
CVAR(Bool, r_dynlights, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
@ -217,34 +218,347 @@ namespace swrenderer
}
}
class DepthColumnCommand : public DrawerCommand
/////////////////////////////////////////////////////////////////////////
DrawWallCommand::DrawWallCommand(const WallDrawerArgs& args) : wallargs(args)
{
public:
DepthColumnCommand(const WallDrawerArgs &args, float idepth) : idepth(1.0f / idepth)
}
void DrawWallCommand::Execute(DrawerThread* thread)
{
if (!thread->columndrawer)
thread->columndrawer = std::make_shared<WallColumnDrawerArgs>();
WallColumnDrawerArgs& drawerargs = *thread->columndrawer.get();
drawerargs.wallargs = &wallargs;
bool fixed = wallargs.fixedlight;
bool haslights = r_dynlights && wallargs.lightlist;
if (haslights)
{
auto rendertarget = args.Viewport()->RenderTarget;
if (rendertarget->IsBgra())
{
uint32_t *destorg = (uint32_t*)rendertarget->GetPixels();
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
uint32_t *dest = (uint32_t*)args.Dest();
int offset = (int)(ptrdiff_t)(dest - destorg);
x = offset % rendertarget->GetPitch();
y = offset / rendertarget->GetPitch();
}
else
{
uint8_t *destorg = rendertarget->GetPixels();
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
uint8_t *dest = (uint8_t*)args.Dest();
int offset = (int)(ptrdiff_t)(dest - destorg);
x = offset % rendertarget->GetPitch();
y = offset / rendertarget->GetPitch();
}
count = args.Count();
float dx = wallargs.WallC.tright.X - wallargs.WallC.tleft.X;
float dy = wallargs.WallC.tright.Y - wallargs.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;
}
DepthColumnCommand(const SkyDrawerArgs &args, float idepth) : idepth(1.0f / idepth)
drawerargs.SetTextureFracBits(wallargs.fracbits);
float curlight = wallargs.lightpos;
float lightstep = wallargs.lightstep;
int shade = wallargs.mShade;
float upos = wallargs.texcoords.upos, ustepX = wallargs.texcoords.ustepX, ustepY = wallargs.texcoords.ustepY;
float vpos = wallargs.texcoords.vpos, vstepX = wallargs.texcoords.vstepX, vstepY = wallargs.texcoords.vstepY;
float wpos = wallargs.texcoords.wpos, wstepX = wallargs.texcoords.wstepX, wstepY = wallargs.texcoords.wstepY;
float startX = wallargs.texcoords.startX;
int x1 = wallargs.x1;
int x2 = wallargs.x2;
upos += ustepX * (x1 + 0.5f - startX);
vpos += vstepX * (x1 + 0.5f - startX);
wpos += wstepX * (x1 + 0.5f - startX);
float centerY = wallargs.CenterY;
centerY -= 0.5f;
auto uwal = wallargs.uwal;
auto dwal = wallargs.dwal;
for (int x = x1; x < x2; x++)
{
int y1 = uwal[x];
int y2 = dwal[x];
if (y2 > y1)
{
if (!fixed) drawerargs.SetLight(curlight, shade);
if (haslights)
SetLights(drawerargs, x, y1);
else
drawerargs.dc_num_lights = 0;
float dy = (y1 - centerY);
float u = upos + ustepY * dy;
float v = vpos + vstepY * dy;
float w = wpos + wstepY * dy;
float scaleU = ustepX;
float scaleV = vstepY;
w = 1.0f / w;
u *= w;
v *= w;
scaleU *= w;
scaleV *= w;
uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL);
uint32_t texelY = (uint32_t)(int64_t)((v - std::floor(v)) * 0x1'0000'0000LL);
uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL);
uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL);
if (wallargs.fracbits != 32)
DrawWallColumn8(thread, drawerargs, x, y1, y2, texelX, texelY, texelStepY);
else
DrawWallColumn32(thread, drawerargs, x, y1, y2, texelX, texelY, texelStepX, texelStepY);
}
upos += ustepX;
vpos += vstepX;
wpos += wstepX;
curlight += lightstep;
}
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 / wallargs.WallC.sz1;
float w2 = 1.0f / wallargs.WallC.sz2;
float t = (x - wallargs.WallC.sx1 + 0.5f) / (wallargs.WallC.sx2 - wallargs.WallC.sx1);
float wcol = w1 * (1.0f - t) + w2 * t;
float zcol = 1.0f / wcol;
float zbufferdepth = 1.0f / (zcol / wallargs.FocalTangent);
drawerargs.SetDest(x, y1);
drawerargs.SetCount(count);
DrawDepthColumn(thread, drawerargs, zbufferdepth);
}
}
}
}
void DrawWallCommand::DrawWallColumn32(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY)
{
int texwidth = wallargs.texwidth;
int texheight = wallargs.texheight;
double xmagnitude = fabs(static_cast<int32_t>(texelStepX)* (1.0 / 0x1'0000'0000LL));
double ymagnitude = fabs(static_cast<int32_t>(texelStepY)* (1.0 / 0x1'0000'0000LL));
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 = texwidth;
int mip_height = texheight;
if (wallargs.mipmapped && mip_width > 1 && mip_height > 1)
{
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);
}
}
const uint32_t* pixels = static_cast<const uint32_t*>(wallargs.texpixels) + mipmap_offset;
fixed_t xxoffset = (texelX >> 16)* mip_width;
const uint8_t* source;
const uint8_t* source2;
uint32_t texturefracx;
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
if (filter_nearest)
{
int tx = (xxoffset >> FRACBITS) % mip_width;
source = (uint8_t*)(pixels + tx * mip_height);
source2 = nullptr;
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);
texturefracx = (xxoffset >> (FRACBITS - 4)) & 15;
}
int count = y2 - y1;
drawerargs.SetDest(x, y1);
drawerargs.SetCount(count);
drawerargs.SetTexture(source, source2, mip_height);
drawerargs.SetTextureUPos(texturefracx);
drawerargs.SetTextureVPos(texelY);
drawerargs.SetTextureVStep(texelStepY);
DrawColumn(thread, drawerargs);
}
void DrawWallCommand::DrawWallColumn8(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY)
{
int texwidth = wallargs.texwidth;
int texheight = wallargs.texheight;
int fracbits = wallargs.fracbits;
uint32_t uv_max = texheight << fracbits;
const uint8_t* pixels = static_cast<const uint8_t*>(wallargs.texpixels) + (((texelX >> 16)* texwidth) >> 16)* texheight;
texelY = (static_cast<uint64_t>(texelY)* texheight) >> (32 - fracbits);
texelStepY = (static_cast<uint64_t>(texelStepY)* texheight) >> (32 - fracbits);
drawerargs.SetTexture(pixels, nullptr, texheight);
drawerargs.SetTextureVStep(texelStepY);
if (uv_max == 0 || texelStepY == 0) // power of two
{
int count = y2 - y1;
drawerargs.SetDest(x, y1);
drawerargs.SetCount(count);
drawerargs.SetTextureVPos(texelY);
DrawColumn(thread, drawerargs);
}
else
{
uint32_t left = y2 - y1;
int y = y1;
while (left > 0)
{
uint32_t available = uv_max - texelY;
uint32_t next_uv_wrap = available / texelStepY;
if (available % texelStepY != 0)
next_uv_wrap++;
uint32_t count = MIN(left, next_uv_wrap);
drawerargs.SetDest(x, y);
drawerargs.SetCount(count);
drawerargs.SetTextureVPos(texelY);
DrawColumn(thread, drawerargs);
y += count;
left -= count;
texelY += texelStepY * count;
if (texelY >= uv_max)
texelY -= uv_max;
}
}
}
void DrawWallCommand::DrawDepthColumn(DrawerThread* thread, const WallColumnDrawerArgs& args, float idepth)
{
int x, y, count;
auto rendertarget = args.Viewport()->RenderTarget;
if (rendertarget->IsBgra())
{
uint32_t* destorg = (uint32_t*)rendertarget->GetPixels();
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
uint32_t* dest = (uint32_t*)args.Dest();
int offset = (int)(ptrdiff_t)(dest - destorg);
x = offset % rendertarget->GetPitch();
y = offset / rendertarget->GetPitch();
}
else
{
uint8_t* destorg = rendertarget->GetPixels();
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
uint8_t* dest = (uint8_t*)args.Dest();
int offset = (int)(ptrdiff_t)(dest - destorg);
x = offset % rendertarget->GetPitch();
y = offset / rendertarget->GetPitch();
}
count = args.Count();
auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil;
int pitch = zbuffer->Width();
float* values = zbuffer->DepthValues() + y * pitch + x;
int cnt = count;
values = thread->dest_for_thread(y, pitch, values);
cnt = thread->count_for_thread(y, cnt);
pitch *= thread->num_cores;
float depth = idepth;
for (int i = 0; i < cnt; i++)
{
*values = depth;
values += pitch;
}
}
void DrawWallCommand::SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1)
{
bool mirror = !!(wallargs.PortalMirrorFlags & RF_XFLIP);
int tx = x;
if (mirror)
tx = viewwidth - tx - 1;
// Find column position in view space
float w1 = 1.0f / wallargs.WallC.sz1;
float w2 = 1.0f / wallargs.WallC.sz2;
float t = (x - wallargs.WallC.sx1 + 0.5f) / (wallargs.WallC.sx2 - wallargs.WallC.sx1);
float wcol = w1 * (1.0f - t) + w2 * t;
float zcol = 1.0f / wcol;
drawerargs.dc_viewpos.X = (float)((tx + 0.5 - wallargs.CenterX) / wallargs.CenterX * zcol);
drawerargs.dc_viewpos.Y = zcol;
drawerargs.dc_viewpos.Z = (float)((wallargs.CenterY - y1 - 0.5) / wallargs.InvZtoScale * zcol);
drawerargs.dc_viewpos_step.Z = (float)(-zcol / wallargs.InvZtoScale);
drawerargs.dc_num_lights = 0;
// Setup lights for column
FLightNode* cur_node = drawerargs.LightList();
while (cur_node)
{
if (cur_node->lightsource->IsActive())
{
double lightX = cur_node->lightsource->X() - wallargs.ViewpointPos.X;
double lightY = cur_node->lightsource->Y() - wallargs.ViewpointPos.Y;
double lightZ = cur_node->lightsource->Z() - wallargs.ViewpointPos.Z;
float lx = (float)(lightX * wallargs.Sin - lightY * wallargs.Cos) - drawerargs.dc_viewpos.X;
float ly = (float)(lightX * wallargs.TanCos + lightY * wallargs.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->IsAttenuated();
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;
if (drawerargs.dc_num_lights == WallColumnDrawerArgs::MAX_DRAWER_LIGHTS)
break;
}
}
cur_node = cur_node->nextLight;
}
}
/////////////////////////////////////////////////////////////////////////
class DepthSkyColumnCommand : public DrawerCommand
{
public:
DepthSkyColumnCommand(const SkyDrawerArgs &args, float idepth) : idepth(idepth)
{
auto rendertarget = args.Viewport()->RenderTarget;
if (rendertarget->IsBgra())
@ -319,7 +633,7 @@ namespace swrenderer
if (idepth1 == idepth2)
{
float depth = 1.0f / idepth1;
float depth = idepth1;
#ifdef DEPTH_DEBUG
uint32_t gray = clamp<int32_t>((int32_t)(1.0f / depth / 4.0f), 0, 255);
uint32_t color = MAKEARGB(255, gray, gray, gray);
@ -344,7 +658,7 @@ namespace swrenderer
dest[x] = color;
#endif
values[x] = 1.0f / depth;
values[x] = depth;
depth += step;
}
}
@ -360,12 +674,7 @@ namespace swrenderer
void SWPixelFormatDrawers::DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth)
{
Queue->Push<DepthColumnCommand>(args, idepth);
}
void SWPixelFormatDrawers::DrawDepthWallColumn(const WallDrawerArgs &args, float idepth)
{
Queue->Push<DepthColumnCommand>(args, idepth);
Queue->Push<DepthSkyColumnCommand>(args, idepth);
}
void SWPixelFormatDrawers::DrawDepthSpan(const SpanDrawerArgs &args, float idepth1, float idepth2)

View file

@ -57,12 +57,12 @@ namespace swrenderer
public:
SWPixelFormatDrawers(DrawerCommandQueuePtr queue) : Queue(queue) { }
virtual ~SWPixelFormatDrawers() { }
virtual void DrawWallColumn(const WallDrawerArgs &args) = 0;
virtual void DrawWallMaskedColumn(const WallDrawerArgs &args) = 0;
virtual void DrawWallAddColumn(const WallDrawerArgs &args) = 0;
virtual void DrawWallAddClampColumn(const WallDrawerArgs &args) = 0;
virtual void DrawWallSubClampColumn(const WallDrawerArgs &args) = 0;
virtual void DrawWallRevSubClampColumn(const WallDrawerArgs &args) = 0;
virtual void DrawWall(const WallDrawerArgs &args) = 0;
virtual void DrawWallMasked(const WallDrawerArgs &args) = 0;
virtual void DrawWallAdd(const WallDrawerArgs &args) = 0;
virtual void DrawWallAddClamp(const WallDrawerArgs &args) = 0;
virtual void DrawWallSubClamp(const WallDrawerArgs &args) = 0;
virtual void DrawWallRevSubClamp(const WallDrawerArgs &args) = 0;
virtual void DrawSingleSkyColumn(const SkyDrawerArgs &args) = 0;
virtual void DrawDoubleSkyColumn(const SkyDrawerArgs &args) = 0;
virtual void DrawColumn(const SpriteDrawerArgs &args) = 0;
@ -96,7 +96,6 @@ namespace swrenderer
virtual void DrawFogBoundaryLine(const SpanDrawerArgs &args) = 0;
void DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth);
void DrawDepthWallColumn(const WallDrawerArgs &args, float idepth);
void DrawDepthSpan(const SpanDrawerArgs &args, float idepth1, float idepth2);
DrawerCommandQueuePtr Queue;

View file

@ -93,10 +93,6 @@ EXTERN_CVAR(Int, gl_particles_style)
namespace swrenderer
{
PalWall1Command::PalWall1Command(const WallDrawerArgs &args) : args(args)
{
}
uint8_t PalWall1Command::AddLights(const DrawerLight *lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material)
{
uint32_t lit_r = 0;
@ -150,7 +146,7 @@ namespace swrenderer
return RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)];
}
void DrawWall1PalCommand::Execute(DrawerThread *thread)
void DrawWall1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args)
{
uint32_t fracstep = args.TextureVStep();
uint32_t frac = args.TextureVPos();
@ -160,7 +156,7 @@ namespace swrenderer
uint8_t *dest = args.Dest();
int bits = args.TextureFracBits();
int pitch = args.Viewport()->RenderTarget->GetPitch();
DrawerLight *dynlights = args.dc_lights;
const DrawerLight *dynlights = args.dc_lights;
int num_dynlights = args.dc_num_lights;
float viewpos_z = args.dc_viewpos.Z;
float step_viewpos_z = args.dc_viewpos_step.Z;
@ -201,7 +197,7 @@ namespace swrenderer
}
}
void DrawWallMasked1PalCommand::Execute(DrawerThread *thread)
void DrawWallMasked1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args)
{
uint32_t fracstep = args.TextureVStep();
uint32_t frac = args.TextureVPos();
@ -211,7 +207,7 @@ namespace swrenderer
uint8_t *dest = args.Dest();
int bits = args.TextureFracBits();
int pitch = args.Viewport()->RenderTarget->GetPitch();
DrawerLight *dynlights = args.dc_lights;
const DrawerLight *dynlights = args.dc_lights;
int num_dynlights = args.dc_num_lights;
float viewpos_z = args.dc_viewpos.Z;
float step_viewpos_z = args.dc_viewpos_step.Z;
@ -260,7 +256,7 @@ namespace swrenderer
}
}
void DrawWallAdd1PalCommand::Execute(DrawerThread *thread)
void DrawWallAdd1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args)
{
uint32_t fracstep = args.TextureVStep();
uint32_t frac = args.TextureVPos();
@ -322,7 +318,7 @@ namespace swrenderer
}
}
void DrawWallAddClamp1PalCommand::Execute(DrawerThread *thread)
void DrawWallAddClamp1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args)
{
uint32_t fracstep = args.TextureVStep();
uint32_t frac = args.TextureVPos();
@ -332,7 +328,7 @@ namespace swrenderer
uint8_t *dest = args.Dest();
int bits = args.TextureFracBits();
int pitch = args.Viewport()->RenderTarget->GetPitch();
DrawerLight *dynlights = args.dc_lights;
const DrawerLight *dynlights = args.dc_lights;
int num_dynlights = args.dc_num_lights;
float viewpos_z = args.dc_viewpos.Z;
float step_viewpos_z = args.dc_viewpos_step.Z;
@ -396,7 +392,7 @@ namespace swrenderer
}
}
void DrawWallSubClamp1PalCommand::Execute(DrawerThread *thread)
void DrawWallSubClamp1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args)
{
uint32_t fracstep = args.TextureVStep();
uint32_t frac = args.TextureVPos();
@ -406,7 +402,7 @@ namespace swrenderer
uint8_t *dest = args.Dest();
int bits = args.TextureFracBits();
int pitch = args.Viewport()->RenderTarget->GetPitch();
DrawerLight *dynlights = args.dc_lights;
const DrawerLight *dynlights = args.dc_lights;
int num_dynlights = args.dc_num_lights;
float viewpos_z = args.dc_viewpos.Z;
float step_viewpos_z = args.dc_viewpos_step.Z;
@ -469,7 +465,7 @@ namespace swrenderer
}
}
void DrawWallRevSubClamp1PalCommand::Execute(DrawerThread *thread)
void DrawWallRevSubClamp1PalCommand::DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args)
{
uint32_t fracstep = args.TextureVStep();
uint32_t frac = args.TextureVPos();
@ -479,7 +475,7 @@ namespace swrenderer
uint8_t *dest = args.Dest();
int bits = args.TextureFracBits();
int pitch = args.Viewport()->RenderTarget->GetPitch();
DrawerLight *dynlights = args.dc_lights;
const DrawerLight *dynlights = args.dc_lights;
int num_dynlights = args.dc_num_lights;
float viewpos_z = args.dc_viewpos.Z;
float step_viewpos_z = args.dc_viewpos_step.Z;

View file

@ -8,26 +8,138 @@
#include "swrenderer/viewport/r_spandrawer.h"
#include "swrenderer/viewport/r_walldrawer.h"
#include "swrenderer/viewport/r_spritedrawer.h"
#include "swrenderer/r_swcolormaps.h"
struct FSWColormap;
namespace swrenderer
{
class PalWall1Command : public DrawerCommand
class WallColumnDrawerArgs
{
public:
PalWall1Command(const WallDrawerArgs &args);
void SetDest(int x, int y)
{
dc_dest = Viewport()->GetDest(x, y);
dc_dest_y = y;
}
void SetCount(int count) { dc_count = count; }
void SetTexture(const uint8_t* pixels, const uint8_t* pixels2, int height)
{
dc_source = pixels;
dc_source2 = pixels2;
dc_textureheight = height;
}
void SetTextureFracBits(int bits) { dc_wall_fracbits = bits; }
void SetTextureUPos(uint32_t pos) { dc_texturefracx = pos; }
void SetTextureVPos(fixed_t pos) { dc_texturefrac = pos; }
void SetTextureVStep(fixed_t step) { dc_iscale = step; }
void SetLight(float light, int shade) { mLight = light; mShade = shade; }
uint8_t* Dest() const { return dc_dest; }
int DestY() const { return dc_dest_y; }
int Count() const { return dc_count; }
uint32_t* SrcBlend() const { return wallargs->SrcBlend(); }
uint32_t* DestBlend() const { return wallargs->DestBlend(); }
fixed_t SrcAlpha() const { return wallargs->SrcAlpha(); }
fixed_t DestAlpha() const { return wallargs->DestAlpha(); }
uint32_t TextureUPos() const { return dc_texturefracx; }
fixed_t TextureVPos() const { return dc_texturefrac; }
fixed_t TextureVStep() const { return dc_iscale; }
const uint8_t* TexturePixels() const { return dc_source; }
const uint8_t* TexturePixels2() const { return dc_source2; }
uint32_t TextureHeight() const { return dc_textureheight; }
int TextureFracBits() const { return dc_wall_fracbits; }
FVector3 dc_normal = { 0,0,0 };
FVector3 dc_viewpos = { 0,0,0 };
FVector3 dc_viewpos_step = { 0,0,0 };
enum { MAX_DRAWER_LIGHTS = 16 };
DrawerLight dc_lights[MAX_DRAWER_LIGHTS];
int dc_num_lights = 0;
RenderViewport* Viewport() const { return wallargs->Viewport(); }
uint8_t* Colormap(RenderViewport* viewport) const
{
auto basecolormap = wallargs->BaseColormap();
if (basecolormap)
{
if (viewport->RenderTarget->IsBgra())
return basecolormap->Maps;
else
return basecolormap->Maps + (GETPALOOKUP(mLight, mShade) << COLORMAPSHIFT);
}
else
{
return wallargs->TranslationMap();
}
}
uint8_t* TranslationMap() const { return wallargs->TranslationMap(); }
ShadeConstants ColormapConstants() const { return wallargs->ColormapConstants(); }
fixed_t Light() const { return LIGHTSCALE(mLight, mShade); }
FLightNode* LightList() const { return wallargs->lightlist; }
const WallDrawerArgs* wallargs;
private:
uint8_t* dc_dest = nullptr;
int dc_dest_y = 0;
int dc_count = 0;
fixed_t dc_iscale = 0;
fixed_t dc_texturefrac = 0;
uint32_t dc_texturefracx = 0;
uint32_t dc_textureheight = 0;
const uint8_t* dc_source = nullptr;
const uint8_t* dc_source2 = nullptr;
int dc_wall_fracbits = 0;
float mLight = 0.0f;
int mShade = 0;
};
class DrawWallCommand : public DrawerCommand
{
public:
DrawWallCommand(const WallDrawerArgs& args);
void Execute(DrawerThread* thread) override;
protected:
virtual void DrawColumn(DrawerThread* thread, const WallColumnDrawerArgs& args) = 0;
private:
void DrawWallColumn32(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepX, uint32_t texelStepY);
void DrawWallColumn8(DrawerThread* thread, WallColumnDrawerArgs& drawerargs, int x, int y1, int y2, uint32_t texelX, uint32_t texelY, uint32_t texelStepY);
void DrawDepthColumn(DrawerThread* thread, const WallColumnDrawerArgs& args, float idepth);
void SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1);
WallDrawerArgs wallargs;
};
class PalWall1Command : public DrawWallCommand
{
public:
PalWall1Command(const WallDrawerArgs &args) : DrawWallCommand(args) { }
protected:
inline static uint8_t AddLights(const DrawerLight *lights, int num_lights, float viewpos_z, uint8_t fg, uint8_t material);
WallDrawerArgs args;
};
class DrawWall1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void Execute(DrawerThread *thread) override; };
class DrawWallMasked1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void Execute(DrawerThread *thread) override; };
class DrawWallAdd1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void Execute(DrawerThread *thread) override; };
class DrawWallAddClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void Execute(DrawerThread *thread) override; };
class DrawWallSubClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void Execute(DrawerThread *thread) override; };
class DrawWallRevSubClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void Execute(DrawerThread *thread) override; };
class DrawWall1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; };
class DrawWallMasked1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; };
class DrawWallAdd1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; };
class DrawWallAddClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; };
class DrawWallSubClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; };
class DrawWallRevSubClamp1PalCommand : public PalWall1Command { public: using PalWall1Command::PalWall1Command; void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override; };
class PalSkyCommand : public DrawerCommand
{
@ -230,20 +342,20 @@ namespace swrenderer
public:
using SWPixelFormatDrawers::SWPixelFormatDrawers;
void DrawWallColumn(const WallDrawerArgs &args) override { Queue->Push<DrawWall1PalCommand>(args); }
void DrawWallMaskedColumn(const WallDrawerArgs &args) override { Queue->Push<DrawWallMasked1PalCommand>(args); }
void DrawWall(const WallDrawerArgs &args) override { Queue->Push<DrawWall1PalCommand>(args); }
void DrawWallMasked(const WallDrawerArgs &args) override { Queue->Push<DrawWallMasked1PalCommand>(args); }
void DrawWallAddColumn(const WallDrawerArgs &args) override
void DrawWallAdd(const WallDrawerArgs &args) override
{
if (args.dc_num_lights == 0)
if (!args.lightlist)
Queue->Push<DrawWallAdd1PalCommand>(args);
else
Queue->Push<DrawWallAddClamp1PalCommand>(args);
}
void DrawWallAddClampColumn(const WallDrawerArgs &args) override { Queue->Push<DrawWallAddClamp1PalCommand>(args); }
void DrawWallSubClampColumn(const WallDrawerArgs &args) override { Queue->Push<DrawWallSubClamp1PalCommand>(args); }
void DrawWallRevSubClampColumn(const WallDrawerArgs &args) override { Queue->Push<DrawWallRevSubClamp1PalCommand>(args); }
void DrawWallAddClamp(const WallDrawerArgs &args) override { Queue->Push<DrawWallAddClamp1PalCommand>(args); }
void DrawWallSubClamp(const WallDrawerArgs &args) override { Queue->Push<DrawWallSubClamp1PalCommand>(args); }
void DrawWallRevSubClamp(const WallDrawerArgs &args) override { Queue->Push<DrawWallRevSubClamp1PalCommand>(args); }
void DrawSingleSkyColumn(const SkyDrawerArgs &args) override { Queue->Push<DrawSingleSky1PalCommand>(args); }
void DrawDoubleSkyColumn(const SkyDrawerArgs &args) override { Queue->Push<DrawDoubleSky1PalCommand>(args); }
void DrawColumn(const SpriteDrawerArgs &args) override { Queue->Push<DrawColumnPalCommand>(args); }

View file

@ -80,32 +80,32 @@ CVAR(Float, r_lod_bias, -1.5, 0); // To do: add CVAR_ARCHIVE | CVAR_GLOBALCONFIG
namespace swrenderer
{
void SWTruecolorDrawers::DrawWallColumn(const WallDrawerArgs &args)
void SWTruecolorDrawers::DrawWall(const WallDrawerArgs &args)
{
Queue->Push<DrawWall32Command>(args);
}
void SWTruecolorDrawers::DrawWallMaskedColumn(const WallDrawerArgs &args)
void SWTruecolorDrawers::DrawWallMasked(const WallDrawerArgs &args)
{
Queue->Push<DrawWallMasked32Command>(args);
}
void SWTruecolorDrawers::DrawWallAddColumn(const WallDrawerArgs &args)
void SWTruecolorDrawers::DrawWallAdd(const WallDrawerArgs &args)
{
Queue->Push<DrawWallAddClamp32Command>(args);
}
void SWTruecolorDrawers::DrawWallAddClampColumn(const WallDrawerArgs &args)
void SWTruecolorDrawers::DrawWallAddClamp(const WallDrawerArgs &args)
{
Queue->Push<DrawWallAddClamp32Command>(args);
}
void SWTruecolorDrawers::DrawWallSubClampColumn(const WallDrawerArgs &args)
void SWTruecolorDrawers::DrawWallSubClamp(const WallDrawerArgs &args)
{
Queue->Push<DrawWallSubClamp32Command>(args);
}
void SWTruecolorDrawers::DrawWallRevSubClampColumn(const WallDrawerArgs &args)
void SWTruecolorDrawers::DrawWallRevSubClamp(const WallDrawerArgs &args)
{
Queue->Push<DrawWallRevSubClamp32Command>(args);
}

View file

@ -244,12 +244,12 @@ namespace swrenderer
public:
using SWPixelFormatDrawers::SWPixelFormatDrawers;
void DrawWallColumn(const WallDrawerArgs &args) override;
void DrawWallMaskedColumn(const WallDrawerArgs &args) override;
void DrawWallAddColumn(const WallDrawerArgs &args) override;
void DrawWallAddClampColumn(const WallDrawerArgs &args) override;
void DrawWallSubClampColumn(const WallDrawerArgs &args) override;
void DrawWallRevSubClampColumn(const WallDrawerArgs &args) override;
void DrawWall(const WallDrawerArgs &args) override;
void DrawWallMasked(const WallDrawerArgs &args) override;
void DrawWallAdd(const WallDrawerArgs &args) override;
void DrawWallAddClamp(const WallDrawerArgs &args) override;
void DrawWallSubClamp(const WallDrawerArgs &args) override;
void DrawWallRevSubClamp(const WallDrawerArgs &args) override;
void DrawSingleSkyColumn(const SkyDrawerArgs &args) override;
void DrawDoubleSkyColumn(const SkyDrawerArgs &args) override;
void DrawColumn(const SpriteDrawerArgs &args) override;

View file

@ -22,6 +22,7 @@
#pragma once
#include "swrenderer/drawers/r_draw_pal.h"
#include "swrenderer/drawers/r_draw_rgba.h"
#include "swrenderer/viewport/r_walldrawer.h"
@ -46,15 +47,12 @@ namespace swrenderer
}
template<typename BlendT>
class DrawWall32T : public DrawerCommand
class DrawWall32T : public DrawWallCommand
{
protected:
WallDrawerArgs args;
public:
DrawWall32T(const WallDrawerArgs &drawerargs) : args(drawerargs) { }
DrawWall32T(const WallDrawerArgs &drawerargs) : DrawWallCommand(drawerargs) { }
void Execute(DrawerThread *thread) override
void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override
{
using namespace DrawWall32TModes;
@ -64,21 +62,21 @@ namespace swrenderer
if (shade_constants.simple_shade)
{
if (is_nearest_filter)
Loop<SimpleShade, NearestFilter>(thread, shade_constants);
Loop<SimpleShade, NearestFilter>(thread, args, shade_constants);
else
Loop<SimpleShade, LinearFilter>(thread, shade_constants);
Loop<SimpleShade, LinearFilter>(thread, args, shade_constants);
}
else
{
if (is_nearest_filter)
Loop<AdvancedShade, NearestFilter>(thread, shade_constants);
Loop<AdvancedShade, NearestFilter>(thread, args, shade_constants);
else
Loop<AdvancedShade, LinearFilter>(thread, shade_constants);
Loop<AdvancedShade, LinearFilter>(thread, args, shade_constants);
}
}
template<typename ShadeModeT, typename FilterModeT>
FORCEINLINE void Loop(DrawerThread *thread, ShadeConstants shade_constants)
FORCEINLINE void Loop(DrawerThread *thread, const WallColumnDrawerArgs& args, ShadeConstants shade_constants)
{
using namespace DrawWall32TModes;

View file

@ -22,6 +22,7 @@
#pragma once
#include "swrenderer/drawers/r_draw_pal.h"
#include "swrenderer/drawers/r_draw_rgba.h"
#include "swrenderer/viewport/r_walldrawer.h"
@ -46,15 +47,12 @@ namespace swrenderer
}
template<typename BlendT>
class DrawWall32T : public DrawerCommand
class DrawWall32T : public DrawWallCommand
{
protected:
WallDrawerArgs args;
public:
DrawWall32T(const WallDrawerArgs &drawerargs) : args(drawerargs) { }
DrawWall32T(const WallDrawerArgs &drawerargs) : DrawWallCommand(drawerargs) { }
void Execute(DrawerThread *thread) override
void DrawColumn(DrawerThread *thread, const WallColumnDrawerArgs& args) override
{
using namespace DrawWall32TModes;
@ -64,21 +62,21 @@ namespace swrenderer
if (shade_constants.simple_shade)
{
if (is_nearest_filter)
Loop<SimpleShade, NearestFilter>(thread, shade_constants);
Loop<SimpleShade, NearestFilter>(thread, args, shade_constants);
else
Loop<SimpleShade, LinearFilter>(thread, shade_constants);
Loop<SimpleShade, LinearFilter>(thread, args, shade_constants);
}
else
{
if (is_nearest_filter)
Loop<AdvancedShade, NearestFilter>(thread, shade_constants);
Loop<AdvancedShade, NearestFilter>(thread, args, shade_constants);
else
Loop<AdvancedShade, LinearFilter>(thread, shade_constants);
Loop<AdvancedShade, LinearFilter>(thread, args, shade_constants);
}
}
template<typename ShadeModeT, typename FilterModeT>
FORCEINLINE void VECTORCALL Loop(DrawerThread *thread, ShadeConstants shade_constants)
FORCEINLINE void VECTORCALL Loop(DrawerThread *thread, const WallColumnDrawerArgs& args, ShadeConstants shade_constants)
{
using namespace DrawWall32TModes;

View file

@ -34,6 +34,8 @@ EXTERN_CVAR(Int, r_multithreaded)
class PolyTriangleThreadData;
namespace swrenderer { class WallColumnDrawerArgs; }
// Worker data for each thread executing drawer commands
class DrawerThread
{
@ -61,6 +63,7 @@ public:
const uint8_t *tiltlighting[MAXWIDTH];
std::shared_ptr<PolyTriangleThreadData> poly;
std::shared_ptr<swrenderer::WallColumnDrawerArgs> columndrawer;
size_t debug_draw_pos = 0;

View file

@ -81,7 +81,7 @@ namespace swrenderer
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
return;
if (WallC.Init(Thread, pt1, pt2, 32.0 / (1 << 12)))
if (WallC.Init(Thread, pt1, pt2, line))
return;
RenderPortal *renderportal = Thread->Portal.get();

View file

@ -54,7 +54,7 @@
namespace swrenderer
{
void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, const ProjectedWallLight &wallLight)
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

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, const ProjectedWallLight &wallLight);
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

@ -62,7 +62,6 @@
CVAR(Bool, r_fogboundary, true, 0)
CVAR(Bool, r_drawmirrors, true, 0)
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
@ -88,7 +87,7 @@ namespace swrenderer
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
return;
if (WallC.Init(Thread, pt1, pt2, 32.0 / (1 << 12)))
if (WallC.Init(Thread, pt1, pt2, line))
return;
RenderPortal *renderportal = Thread->Portal.get();
@ -109,22 +108,6 @@ namespace swrenderer
if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && P_ClipLineToPortal(line->linedef, renderportal->CurrentPortal->dst, Thread->Viewport->viewpoint.Pos))
return;
vertex_t *v1 = line->linedef->v1;
vertex_t *v2 = line->linedef->v2;
if ((v1 == line->v1 && v2 == line->v2) || (v2 == line->v1 && v1 == line->v2))
{ // The seg is the entire wall.
WallT.InitFromWallCoords(Thread, &WallC);
}
else
{ // The seg is only part of the wall.
if (line->linedef->sidedef[0] != line->sidedef)
{
swapvalues(v1, v2);
}
WallT.InitFromLine(Thread, v1->fPos() - Thread->Viewport->viewpoint.Pos, v2->fPos() - Thread->Viewport->viewpoint.Pos);
}
mFrontCeilingZ1 = mFrontSector->ceilingplane.ZatPoint(line->v1);
mFrontFloorZ1 = mFrontSector->floorplane.ZatPoint(line->v1);
mFrontCeilingZ2 = mFrontSector->ceilingplane.ZatPoint(line->v2);
@ -301,14 +284,6 @@ namespace swrenderer
// A wall segment will be drawn between start and stop pixels (inclusive).
bool SWRenderLine::RenderWallSegment(int start, int stop)
{
int i;
bool maskedtexture = false;
#ifdef RANGECHECK
if (start >= viewwidth || start >= stop)
I_Error("Bad R_StoreWallRange: %i to %i", start, stop);
#endif
if (!rw_prepped)
{
rw_prepped = true;
@ -327,41 +302,38 @@ namespace swrenderer
if (m3DFloor.type == Fake3DOpaque::Normal)
Thread->DrawSegments->Push(draw_segment);
draw_segment->CurrentPortalUniq = renderportal->CurrentPortalUniq;
draw_segment->drawsegclip.CurrentPortalUniq = renderportal->CurrentPortalUniq;
draw_segment->WallC = WallC;
draw_segment->tmapvals = WallT;
draw_segment->x1 = start;
draw_segment->x2 = stop;
draw_segment->curline = mLineSegment;
draw_segment->SubsectorDepth = Thread->OpaquePass->GetSubsectorDepth(mSubsector->Index());
draw_segment->drawsegclip.SubsectorDepth = Thread->OpaquePass->GetSubsectorDepth(mSubsector->Index());
bool markportal = ShouldMarkPortal();
if (markportal)
{
draw_segment->silhouette = SIL_BOTH;
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip);
draw_segment->drawsegclip.silhouette = SIL_BOTH;
}
else if (mBackSector == NULL)
else if (!mBackSector)
{
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(stop - start);
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(stop - start);
fillshort(draw_segment->sprtopclip, stop - start, viewheight);
memset(draw_segment->sprbottomclip, -1, (stop - start) * sizeof(short));
draw_segment->silhouette = SIL_BOTH;
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1);
draw_segment->drawsegclip.silhouette = SIL_BOTH;
}
else
{
// two sided line
if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 ||
mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
if (mFrontFloorZ1 > mBackFloorZ1 || mFrontFloorZ2 > mBackFloorZ2 || mBackSector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
{
draw_segment->silhouette = SIL_BOTTOM;
draw_segment->drawsegclip.silhouette = SIL_BOTTOM;
}
if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 ||
mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
if (mFrontCeilingZ1 < mBackCeilingZ1 || mFrontCeilingZ2 < mBackCeilingZ2 || mBackSector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) < 0)
{
draw_segment->silhouette |= SIL_TOP;
draw_segment->drawsegclip.silhouette |= SIL_TOP;
}
// killough 1/17/98: this test is required if the fix
@ -372,118 +344,63 @@ namespace swrenderer
//
// killough 4/7/98: make doorclosed external variable
if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2))
{
if (mDoorClosed || (mBackCeilingZ1 <= mFrontFloorZ1 && mBackCeilingZ2 <= mFrontFloorZ2))
{
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(stop - start);
memset(draw_segment->sprbottomclip, -1, (stop - start) * sizeof(short));
draw_segment->silhouette |= SIL_BOTTOM;
}
if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2))
{ // killough 1/17/98, 2/8/98
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(stop - start);
fillshort(draw_segment->sprtopclip, stop - start, viewheight);
draw_segment->silhouette |= SIL_TOP;
}
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, -1);
draw_segment->drawsegclip.silhouette |= SIL_BOTTOM;
}
if (mDoorClosed || (mBackFloorZ1 >= mFrontCeilingZ1 && mBackFloorZ2 >= mFrontCeilingZ2))
{
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, viewheight);
draw_segment->drawsegclip.silhouette |= SIL_TOP;
}
if (m3DFloor.type == Fake3DOpaque::Normal)
{
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;
}
}
}
}
// 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)) &&
(mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) &&
if ((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))
{
float *swal;
fixed_t *lwal;
int i;
maskedtexture = true;
// kg3D - backup for mid and fake walls
draw_segment->bkup = Thread->FrameMemory->AllocMemory<short>(stop - start);
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->Has3DFloorWalls())
if (r_3dfloors)
{
if (sidedef->GetTexture(side_t::mid).isValid())
draw_segment->SetHas3DFloorMidTexture();
draw_segment->maskedtexturecol = Thread->FrameMemory->AllocMemory<fixed_t>(stop - start);
draw_segment->swall = Thread->FrameMemory->AllocMemory<float>(stop - start);
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);
fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid));
if (pic && pic->useWorldPanning(sidedef->GetLevel()))
{
xoffset = xs_RoundToInt(xoffset * lwallscale);
if (mBackSector->e && mBackSector->e->XFloor.ffloors.Size()) {
for (int 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;
}
}
}
for (i = start; i < stop; i++)
{
*lwal++ = walltexcoords.UPos[i] + xoffset;
*swal++ = walltexcoords.VStep[i];
}
double istart = draw_segment->swall[0] * yscale;
double iend = *(swal - 1) * yscale;
#if 0
///This was for avoiding overflow when using fixed point. It might not be needed anymore.
const double mini = 3 / 65536.0;
if (istart < mini && istart >= 0) istart = mini;
if (istart > -mini && istart < 0) istart = -mini;
if (iend < mini && iend >= 0) iend = mini;
if (iend > -mini && iend < 0) iend = -mini;
#endif
istart = 1 / istart;
iend = 1 / iend;
draw_segment->yscale = (float)yscale;
draw_segment->iscale = (float)istart;
if (stop - start > 1)
{
draw_segment->iscalestep = float((iend - istart) / (stop - start - 1));
}
else
{
draw_segment->iscalestep = 0;
if (mFrontSector->e && mFrontSector->e->XFloor.ffloors.Size()) {
for (int 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;
}
}
}
}
draw_segment->light = mLight.GetLightPos(start);
draw_segment->lightstep = mLight.GetLightStep();
if (IsFogBoundary(mFrontSector, mBackSector))
draw_segment->SetHasFogBoundary();
if (draw_segment->bFogBoundary || draw_segment->maskedtexturecol != nullptr)
if (mLineSegment->linedef->alpha > 0.0f && sidedef->GetTexture(side_t::mid).isValid())
{
FTexture* tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
FSoftwareTexture* pic = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
if (pic)
{
draw_segment->SetHasTranslucentMidTexture();
draw_segment->texcoords.ProjectTranslucent(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, pic);
draw_segment->drawsegclip.silhouette |= SIL_TOP | SIL_BOTTOM;
}
}
if (draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls())
{
draw_segment->drawsegclip.SetBackupClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
Thread->DrawSegments->PushTranslucent(draw_segment);
}
}
@ -503,22 +420,16 @@ namespace swrenderer
MarkOpaquePassClip(start, stop);
// save sprite clipping info
if (((draw_segment->silhouette & SIL_TOP) || maskedtexture) && draw_segment->sprtopclip == nullptr)
bool needcliplists = draw_segment->HasFogBoundary() || draw_segment->HasTranslucentMidTexture() || draw_segment->Has3DFloorWalls();
if (((draw_segment->drawsegclip.silhouette & SIL_TOP) || needcliplists) && !draw_segment->drawsegclip.sprtopclip)
{
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(stop - start);
memcpy(draw_segment->sprtopclip, &Thread->OpaquePass->ceilingclip[start], sizeof(short)*(stop - start));
draw_segment->drawsegclip.SetTopClip(Thread, start, stop, Thread->OpaquePass->ceilingclip);
}
if (((draw_segment->silhouette & SIL_BOTTOM) || maskedtexture) && draw_segment->sprbottomclip == nullptr)
if (((draw_segment->drawsegclip.silhouette & SIL_BOTTOM) || needcliplists) && !draw_segment->drawsegclip.sprbottomclip)
{
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(stop - start);
memcpy(draw_segment->sprbottomclip, &Thread->OpaquePass->floorclip[start], sizeof(short)*(stop - start));
}
if (maskedtexture && mLineSegment->sidedef->GetTexture(side_t::mid).isValid())
{
draw_segment->silhouette |= SIL_TOP | SIL_BOTTOM;
draw_segment->drawsegclip.SetBottomClip(Thread, start, stop, Thread->OpaquePass->floorclip);
}
RenderMiddleTexture(start, stop);
@ -529,12 +440,12 @@ namespace swrenderer
// [ZZ] Only if not an active mirror
if (!markportal)
{
RenderDecal::RenderDecals(Thread, mLineSegment->sidedef, draw_segment, mLineSegment, mLight, walltop.ScreenY, wallbottom.ScreenY, false);
RenderDecal::RenderDecals(Thread, draw_segment, mLineSegment, mFrontSector, walltop.ScreenY, wallbottom.ScreenY, false);
}
if (markportal)
{
Thread->Portal->AddLinePortal(mLineSegment->linedef, draw_segment->x1, draw_segment->x2, draw_segment->sprtopclip, draw_segment->sprbottomclip);
Thread->Portal->AddLinePortal(mLineSegment->linedef, draw_segment->x1, draw_segment->x2, draw_segment->drawsegclip.sprtopclip, draw_segment->drawsegclip.sprbottomclip);
}
return true;
@ -720,9 +631,7 @@ namespace swrenderer
markfloor = ShouldMarkFloor();
markceiling = ShouldMarkCeiling();
SetTopTexture();
SetMiddleTexture();
SetBottomTexture();
SetTextures();
if (mBackSector && !(sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)))
{
@ -746,215 +655,67 @@ namespace swrenderer
}
}
}
}
FTexture *ftex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
FSoftwareTexture *midtex = ftex && ftex->isValid() ? ftex->GetSoftwareTexture() : nullptr;
void SWRenderLine::SetTextures()
{
mTopTexture = nullptr;
mMiddleTexture = nullptr;
mBottomTexture = nullptr;
bool segtextured = ftex != NULL || mTopPart.Texture != NULL || mBottomPart.Texture != NULL;
side_t* sidedef = mLineSegment->sidedef;
line_t* linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (m3DFloor.type == Fake3DOpaque::Normal)
if (!mBackSector)
{
mLight.SetColormap(mFrontSector, mLineSegment);
SetMiddleTexture();
}
// calculate light table
if (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector)))
else
{
lwallscale =
ftex ? ((midtex? midtex->GetScale().X : 1.0) * sidedef->GetTextureXScale(side_t::mid)) :
mTopPart.Texture ? (mTopPart.Texture->GetScale().X * sidedef->GetTextureXScale(side_t::top)) :
mBottomPart.Texture ? (mBottomPart.Texture->GetScale().X * sidedef->GetTextureXScale(side_t::bottom)) :
1.;
walltexcoords.Project(Thread->Viewport.get(), sidedef->TexelLength * lwallscale, WallC.sx1, WallC.sx2, WallT);
mLight.SetLightLeft(Thread, WallC);
if (mFrontCeilingZ1 > mBackCeilingZ1 || mFrontCeilingZ2 > mBackCeilingZ2) SetTopTexture();
if (mFrontFloorZ1 < mBackFloorZ1 || mFrontFloorZ2 < mBackFloorZ2) SetBottomTexture();
}
}
void SWRenderLine::SetTopTexture()
{
mTopPart.Texture = nullptr;
if (!(mFrontCeilingZ1 > mBackCeilingZ1 || mFrontCeilingZ2 > mBackCeilingZ2)) return;
side_t *sidedef = mLineSegment->sidedef;
line_t *linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (!mBackSector) return;
// No top texture for skyhack lines
if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum) return;
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true);
mTopPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
if (mTopPart.Texture == nullptr) return;
if (!tex || !tex->isValid()) return;
mTopPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::top));
double rowoffset = sidedef->GetTextureYOffset(side_t::top);
mTopPart.TextureScaleU = sidedef->GetTextureXScale(side_t::top);
mTopPart.TextureScaleV = sidedef->GetTextureYScale(side_t::top);
double yrepeat = mTopPart.Texture->GetScale().Y * mTopPart.TextureScaleV;
if (yrepeat >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGTOP)
{ // top of texture at top
mTopPart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
if (rowoffset < 0 && mTopPart.Texture != NULL)
{
rowoffset += mTopPart.Texture->GetHeight();
}
}
else
{ // bottom of texture at bottom
mTopPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mTopPart.Texture->GetHeight();
}
}
else
{ // upside down
rowoffset = -rowoffset;
if (linedef->flags & ML_DONTPEGTOP)
{ // bottom of texture at top
mTopPart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mTopPart.Texture->GetHeight();
}
else
{ // top of texture at bottom
mTopPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
}
if (mTopPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
mTopPart.TextureMid += rowoffset * yrepeat;
}
else
{
mTopPart.TextureMid += rowoffset;
}
mTopTexture = tex->GetSoftwareTexture();
}
void SWRenderLine::SetMiddleTexture()
{
mMiddlePart.Texture = nullptr;
side_t *sidedef = mLineSegment->sidedef;
line_t *linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (mBackSector) return;
// [RH] Horizon lines do not need to be textured
if (linedef->isVisualPortal()) return;
if (linedef->special == Line_Horizon) return;
auto tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true);
mMiddlePart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
if (mMiddlePart.Texture == nullptr) return;
mMiddlePart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid));
double rowoffset = sidedef->GetTextureYOffset(side_t::mid);
mMiddlePart.TextureScaleU = sidedef->GetTextureXScale(side_t::mid);
mMiddlePart.TextureScaleV = sidedef->GetTextureYScale(side_t::mid);
double yrepeat = mMiddlePart.Texture->GetScale().Y * mMiddlePart.TextureScaleV;
if (yrepeat >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mMiddlePart.Texture->GetHeight();
}
else
{ // top of texture at top
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
if (rowoffset < 0 && mMiddlePart.Texture != NULL)
{
rowoffset += mMiddlePart.Texture->GetHeight();
}
}
}
else
{ // upside down
rowoffset = -rowoffset;
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
else
{ // bottom of texture at top
mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mMiddlePart.Texture->GetHeight();
}
}
if (mMiddlePart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
mMiddlePart.TextureMid += rowoffset * yrepeat;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
mMiddlePart.TextureMid += rowoffset;
}
if (!tex || !tex->isValid()) return;
mMiddleTexture = tex->GetSoftwareTexture();
}
void SWRenderLine::SetBottomTexture()
{
mBottomPart.Texture = nullptr;
if (!(mFrontFloorZ1 < mBackFloorZ1 || mFrontFloorZ2 < mBackFloorZ2)) return;
side_t *sidedef = mLineSegment->sidedef;
line_t *linedef = mLineSegment->linedef;
if (sidedef == linedef->sidedef[0] && (linedef->special == Line_Mirror && r_drawmirrors)) return;
if (!mBackSector) return;
double frontlowertop = mFrontSector->GetPlaneTexZ(sector_t::ceiling);
if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum)
{
// Putting sky ceilings on the front and back of a line alters the way unpegged
// positioning works.
frontlowertop = mBackSector->GetPlaneTexZ(sector_t::ceiling);
}
FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::bottom), true);
mBottomPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
if (!mBottomPart.Texture) return;
if (!tex || !tex->isValid()) return;
mBottomPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::bottom));
double rowoffset = sidedef->GetTextureYOffset(side_t::bottom);
mBottomPart.TextureScaleU = sidedef->GetTextureXScale(side_t::bottom);
mBottomPart.TextureScaleV = sidedef->GetTextureYScale(side_t::bottom);
double yrepeat = mBottomPart.Texture->GetScale().Y * mBottomPart.TextureScaleV;
if (yrepeat >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
mBottomPart.TextureMid = (frontlowertop - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
else
{ // top of texture at top
mBottomPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
if (rowoffset < 0 && mBottomPart.Texture != NULL)
{
rowoffset += mBottomPart.Texture->GetHeight();
}
}
}
else
{ // upside down
rowoffset = -rowoffset;
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
mBottomPart.TextureMid = (frontlowertop - Thread->Viewport->viewpoint.Pos.Z) * yrepeat;
}
else
{ // bottom of texture at top
mBottomPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mBottomPart.Texture->GetHeight();
}
}
if (mBottomPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
mBottomPart.TextureMid += rowoffset * yrepeat;
}
else
{
mBottomPart.TextureMid += rowoffset;
}
mBottomTexture = tex->GetSoftwareTexture();
}
bool SWRenderLine::IsFogBoundary(sector_t *front, sector_t *back) const
@ -1072,14 +833,14 @@ namespace swrenderer
auto ceilingclip = Thread->OpaquePass->ceilingclip;
auto floorclip = Thread->OpaquePass->floorclip;
if (mMiddlePart.Texture) // one sided line
if (mMiddleTexture) // one sided line
{
fillshort(ceilingclip + x1, x2 - x1, viewheight);
fillshort(floorclip + x1, x2 - x1, 0xffff);
}
else
{ // two sided line
if (mTopPart.Texture != nullptr)
if (mTopTexture != nullptr)
{ // top wall
for (int x = x1; x < x2; ++x)
{
@ -1092,7 +853,7 @@ namespace swrenderer
memcpy(ceilingclip + x1, walltop.ScreenY + x1, (x2 - x1) * sizeof(short));
}
if (mBottomPart.Texture != nullptr)
if (mBottomTexture != nullptr)
{ // bottom wall
for (int x = x1; x < x2; ++x)
{
@ -1109,227 +870,39 @@ namespace swrenderer
void SWRenderLine::RenderTopTexture(int x1, int x2)
{
if (mMiddlePart.Texture) return;
if (!mTopPart.Texture) return;
if (mMiddleTexture) return;
if (!mTopTexture) return;
if (!viewactive) return;
auto rw_pic = mTopPart.Texture;
double xscale = rw_pic->GetScale().X * mTopPart.TextureScaleU;
double yscale = rw_pic->GetScale().Y * mTopPart.TextureScaleV;
if (xscale != lwallscale)
{
walltexcoords.ProjectPos(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT);
lwallscale = xscale;
}
fixed_t offset;
if (mTopPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
offset = xs_RoundToInt(mTopPart.TextureOffsetU * xscale);
}
else
{
offset = mTopPart.TextureOffsetU;
}
if (xscale < 0)
{
offset = -offset;
}
ProjectedWallTexcoords texcoords;
texcoords.ProjectTop(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, mTopTexture);
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, offset, mLight, GetLightList());
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mTopTexture, x1, x2, walltop.ScreenY, wallupper.ScreenY, texcoords, false, false, OPAQUE);
}
void SWRenderLine::RenderMiddleTexture(int x1, int x2)
{
if (!mMiddlePart.Texture) return;
if (!mMiddleTexture) return;
if (!viewactive) return;
auto rw_pic = mMiddlePart.Texture;
double xscale = rw_pic->GetScale().X * mMiddlePart.TextureScaleU;
double yscale = rw_pic->GetScale().Y * mMiddlePart.TextureScaleV;
if (xscale != lwallscale)
{
walltexcoords.ProjectPos(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT);
lwallscale = xscale;
}
fixed_t offset;
if (mMiddlePart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
offset = xs_RoundToInt(mMiddlePart.TextureOffsetU * xscale);
}
else
{
offset = mMiddlePart.TextureOffsetU;
}
if (xscale < 0)
{
offset = -offset;
}
ProjectedWallTexcoords texcoords;
texcoords.ProjectMid(Thread->Viewport.get(), mFrontSector, mLineSegment, WallC, mMiddleTexture);
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, offset, mLight, GetLightList());
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mMiddleTexture, x1, x2, walltop.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE);
}
void SWRenderLine::RenderBottomTexture(int x1, int x2)
{
if (mMiddlePart.Texture) return;
if (!mBottomPart.Texture) return;
if (mMiddleTexture) return;
if (!mBottomTexture) return;
if (!viewactive) return;
auto rw_pic = mBottomPart.Texture;
double xscale = rw_pic->GetScale().X * mBottomPart.TextureScaleU;
double yscale = rw_pic->GetScale().Y * mBottomPart.TextureScaleV;
if (xscale != lwallscale)
{
walltexcoords.ProjectPos(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT);
lwallscale = xscale;
}
fixed_t offset;
if (mBottomPart.Texture->useWorldPanning(mLineSegment->GetLevel()))
{
offset = xs_RoundToInt(mBottomPart.TextureOffsetU * xscale);
}
else
{
offset = mBottomPart.TextureOffsetU;
}
if (xscale < 0)
{
offset = -offset;
}
ProjectedWallTexcoords texcoords;
texcoords.ProjectBottom(Thread->Viewport.get(), mFrontSector, mBackSector, mLineSegment, WallC, mBottomTexture);
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, offset, mLight, GetLightList());
}
FLightNode *SWRenderLine::GetLightList()
{
CameraLight *cameraLight = CameraLight::Instance();
if ((cameraLight->FixedLightLevel() >= 0) || cameraLight->FixedColormap())
return nullptr; // [SP] Don't draw dynlights if invul/lightamp active
else if (mLineSegment && mLineSegment->sidedef)
return mLineSegment->sidedef->lighthead;
else
return nullptr;
}
////////////////////////////////////////////////////////////////////////////
// Transform and clip coordinates. Returns true if it was clipped away
bool FWallCoords::Init(RenderThread *thread, const DVector2 &pt1, const DVector2 &pt2, double too_close)
{
auto viewport = thread->Viewport.get();
RenderPortal *renderportal = thread->Portal.get();
tleft.X = float(pt1.X * viewport->viewpoint.Sin - pt1.Y * viewport->viewpoint.Cos);
tright.X = float(pt2.X * viewport->viewpoint.Sin - pt2.Y * viewport->viewpoint.Cos);
tleft.Y = float(pt1.X * viewport->viewpoint.TanCos + pt1.Y * viewport->viewpoint.TanSin);
tright.Y = float(pt2.X * viewport->viewpoint.TanCos + pt2.Y * viewport->viewpoint.TanSin);
if (renderportal->MirrorFlags & RF_XFLIP)
{
float t = -tleft.X;
tleft.X = -tright.X;
tright.X = t;
swapvalues(tleft.Y, tright.Y);
}
float fsx1, fsz1, fsx2, fsz2;
if (tleft.X >= -tleft.Y)
{
if (tleft.X > tleft.Y) return true; // left edge is off the right side
if (tleft.Y == 0) return true;
fsx1 = viewport->CenterX + tleft.X * viewport->CenterX / tleft.Y;
fsz1 = tleft.Y;
}
else
{
if (tright.X < -tright.Y) return true; // wall is off the left side
float den = tleft.X - tright.X - tright.Y + tleft.Y;
if (den == 0) return true;
fsx1 = 0;
fsz1 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X + tleft.Y) / den;
}
if (fsz1 < too_close)
return true;
if (tright.X <= tright.Y)
{
if (tright.X < -tright.Y) return true; // right edge is off the left side
if (tright.Y == 0) return true;
fsx2 = viewport->CenterX + tright.X * viewport->CenterX / tright.Y;
fsz2 = tright.Y;
}
else
{
if (tleft.X > tleft.Y) return true; // wall is off the right side
float den = tright.Y - tleft.Y - tright.X + tleft.X;
if (den == 0) return true;
fsx2 = viewwidth;
fsz2 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X - tleft.Y) / den;
}
if (fsz2 < too_close)
return true;
sx1 = xs_RoundToInt(fsx1);
sx2 = xs_RoundToInt(fsx2);
float delta = fsx2 - fsx1;
float t1 = (sx1 + 0.5f - fsx1) / delta;
float t2 = (sx2 + 0.5f - fsx1) / delta;
float invZ1 = 1.0f / fsz1;
float invZ2 = 1.0f / fsz2;
sz1 = 1.0f / (invZ1 * (1.0f - t1) + invZ2 * t1);
sz2 = 1.0f / (invZ1 * (1.0f - t2) + invZ2 * t2);
return sx2 <= sx1;
}
/////////////////////////////////////////////////////////////////////////
void FWallTmapVals::InitFromWallCoords(RenderThread *thread, const FWallCoords *wallc)
{
const FVector2 *left = &wallc->tleft;
const FVector2 *right = &wallc->tright;
RenderPortal *renderportal = thread->Portal.get();
if (renderportal->MirrorFlags & RF_XFLIP)
{
swapvalues(left, right);
}
UoverZorg = left->X * thread->Viewport->CenterX;
UoverZstep = -left->Y;
InvZorg = (left->X - right->X) * thread->Viewport->CenterX;
InvZstep = right->Y - left->Y;
}
void FWallTmapVals::InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right)
{
// Coordinates should have already had viewx,viewy subtracted
auto viewport = thread->Viewport.get();
double fullx1 = left.X * viewport->viewpoint.Sin - left.Y * viewport->viewpoint.Cos;
double fullx2 = right.X * viewport->viewpoint.Sin - right.Y * viewport->viewpoint.Cos;
double fully1 = left.X * viewport->viewpoint.TanCos + left.Y * viewport->viewpoint.TanSin;
double fully2 = right.X * viewport->viewpoint.TanCos + right.Y * viewport->viewpoint.TanSin;
RenderPortal *renderportal = thread->Portal.get();
if (renderportal->MirrorFlags & RF_XFLIP)
{
fullx1 = -fullx1;
fullx2 = -fullx2;
}
UoverZorg = float(fullx1 * viewport->CenterX);
UoverZstep = float(-fully1);
InvZorg = float((fullx1 - fullx2) * viewport->CenterX);
InvZstep = float(fully2 - fully1);
renderWallpart.Render(mFrontSector, mLineSegment, WallC, mBottomTexture, x1, x2, walllower.ScreenY, wallbottom.ScreenY, texcoords, false, false, OPAQUE);
}
}

View file

@ -39,35 +39,6 @@ namespace swrenderer
class RenderThread;
struct VisiblePlane;
struct FWallCoords
{
FVector2 tleft; // coords at left of wall in view space rx1,ry1
FVector2 tright; // coords at right of wall in view space rx2,ry2
float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2
short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2
bool Init(RenderThread *thread, const DVector2 &pt1, const DVector2 &pt2, double too_close);
};
struct FWallTmapVals
{
float UoverZorg, UoverZstep;
float InvZorg, InvZstep;
void InitFromWallCoords(RenderThread *thread, const FWallCoords *wallc);
void InitFromLine(RenderThread *thread, const DVector2 &left, const DVector2 &right);
};
struct WallPartTexture
{
fixed_t TextureOffsetU;
double TextureMid;
double TextureScaleU;
double TextureScaleV;
FSoftwareTexture *Texture;
};
class SWRenderLine : VisibleSegmentRenderer
{
public:
@ -79,6 +50,7 @@ namespace swrenderer
private:
bool RenderWallSegment(int x1, int x2) override;
void SetWallVariables();
void SetTextures();
void SetTopTexture();
void SetMiddleTexture();
void SetBottomTexture();
@ -91,8 +63,6 @@ namespace swrenderer
void RenderMiddleTexture(int x1, int x2);
void RenderBottomTexture(int x1, int x2);
FLightNode *GetLightList();
bool IsFogBoundary(sector_t *front, sector_t *back) const;
bool SkyboxCompare(sector_t *frontsector, sector_t *backsector) const;
@ -126,22 +96,17 @@ namespace swrenderer
bool mDoorClosed;
FWallCoords WallC;
FWallTmapVals WallT;
// Wall segment variables:
bool rw_prepped;
ProjectedWallLight mLight;
double lwallscale;
bool markfloor; // False if the back side is the same plane.
bool markceiling;
WallPartTexture mTopPart;
WallPartTexture mMiddlePart;
WallPartTexture mBottomPart;
FSoftwareTexture* mTopTexture;
FSoftwareTexture* mMiddleTexture;
FSoftwareTexture* mBottomTexture;
ProjectedWallCull mCeilingClipped;
ProjectedWallCull mFloorClipped;
@ -150,7 +115,6 @@ namespace swrenderer
ProjectedWallLine wallbottom;
ProjectedWallLine wallupper;
ProjectedWallLine walllower;
ProjectedWallTexcoords walltexcoords;
sector_t tempsec; // killough 3/8/98: ceiling/water hack
};

View file

@ -54,8 +54,6 @@
#include "swrenderer/viewport/r_viewport.h"
#include "swrenderer/viewport/r_spritedrawer.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
RenderDrawSegment::RenderDrawSegment(RenderThread *thread)
@ -73,79 +71,25 @@ namespace swrenderer
frontsector = curline->frontsector;
backsector = curline->backsector;
// killough 4/13/98: get correct lightlevel for 2s normal textures
sector_t tempsec;
const sector_t *sec = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
if (ds->HasFogBoundary())
RenderFog(ds, x1, x2);
mLight.SetColormap(sec, curline);
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
if (ds->HasTranslucentMidTexture())
RenderWall(ds, x1, x2);
Clip3DFloors *clip3d = Thread->Clip3D.get();
if (ds->Has3DFloorWalls())
Render3DFloorWallRange(ds, x1, x2);
double clipTop = m3DFloor.clipTop ? m3DFloor.sclipTop : sec->ceilingplane.ZatPoint(Thread->Viewport->viewpoint.Pos);
for (int i = frontsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
{
if (clipTop <= frontsector->e->XFloor.lightlist[i].plane.Zat0())
{
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
break;
}
}
float alpha = (float)MIN(curline->linedef->alpha, 1.);
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
SpriteDrawerArgs columndrawerargs;
ColormapLight cmlight;
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())
{
return;
}
// [RH] Draw fog partition
bool renderwall = true;
bool notrelevant = false;
if (ds->bFogBoundary)
{
const short *mfloorclip = ds->sprbottomclip - ds->x1;
const short *mceilingclip = ds->sprtopclip - ds->x1;
RenderFogBoundary renderfog;
renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, mLight);
if (ds->maskedtexturecol == nullptr)
renderwall = false;
}
else if ((ds->Has3DFloorWalls() && !ds->Has3DFloorMidTexture()) || !visible)
{
renderwall = false;
}
if (renderwall)
notrelevant = RenderWall(ds, x1, x2, columndrawerargs, visible);
if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls())
{
RenderFakeWallRange(ds, x1, x2);
}
if (!notrelevant)
{
ds->sprclipped = true;
fillshort(ds->sprtopclip - ds->x1 + x1, x2 - x1, viewheight);
}
if (ds->HasFogBoundary() || ds->HasTranslucentMidTexture() || ds->Has3DFloorWalls())
ds->drawsegclip.SetRangeDrawn(x1, x2);
}
bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2, SpriteDrawerArgs &columndrawerargs, bool visible)
void RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2)
{
auto renderstyle = DefaultRenderStyle();
auto viewport = Thread->Viewport.get();
Clip3DFloors *clip3d = Thread->Clip3D.get();
if (curline->sidedef->GetTexture(side_t::mid).isNull())
return false;
FTexture *ttex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::mid), true);
if (curline->GetLevel()->i_compatflags & COMPATF_MASKEDMIDTEX)
{
@ -153,96 +97,24 @@ namespace swrenderer
}
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
const short *mfloorclip = ds->sprbottomclip - ds->x1;
const short *mceilingclip = ds->sprtopclip - ds->x1;
float *MaskedSWall = ds->swall - ds->x1;
float MaskedScaleY = ds->yscale;
fixed_t *maskedtexturecol = ds->maskedtexturecol - ds->x1;
double spryscale = ds->iscale + ds->iscalestep * (x1 - ds->x1);
float rw_scalestep = ds->iscalestep;
// find positioning
double texheight = tex->GetScaledHeightDouble();
double texheightscale = fabs(curline->sidedef->GetTextureYScale(side_t::mid));
if (texheightscale != 1)
{
texheight = texheight / texheightscale;
}
double texturemid;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
{
texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
}
else
{
texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
}
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
const short *mfloorclip = ds->drawsegclip.sprbottomclip;
const short *mceilingclip = ds->drawsegclip.sprtopclip;
bool wrap = (curline->linedef->flags & ML_WRAP_MIDTEX) || (curline->sidedef->Flags & WALLF_WRAP_MIDTEX);
if (!wrap)
{ // Texture does not wrap vertically.
double textop;
bool sprflipvert = false;
double ceilZ, floorZ;
GetNoWrapMidTextureZ(ds, tex, ceilZ, floorZ);
if (MaskedScaleY < 0)
{
MaskedScaleY = -MaskedScaleY;
sprflipvert = true;
}
if (tex->useWorldPanning(curline->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid += rowoffset - Thread->Viewport->viewpoint.Pos.Z;
textop = texturemid;
texturemid *= MaskedScaleY;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
textop = texturemid + rowoffset / MaskedScaleY - Thread->Viewport->viewpoint.Pos.Z;
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z) * MaskedScaleY + rowoffset;
}
if (sprflipvert)
{
MaskedScaleY = -MaskedScaleY;
texturemid -= tex->GetHeight() << FRACBITS;
}
// Texture top is below the bottom of the screen
if (viewport->globaldclip * ds->WallC.sz1 < -ceilZ && viewport->globaldclip * ds->WallC.sz2 < -ceilZ) return;
// [RH] Don't bother drawing segs that are completely offscreen
if (viewport->globaldclip * ds->WallC.sz1 < -textop && viewport->globaldclip * ds->WallC.sz2 < -textop)
{ // Texture top is below the bottom of the screen
return false;
}
// Texture bottom is above the top of the screen
if (viewport->globaluclip * ds->WallC.sz1 > -floorZ && viewport->globaluclip * ds->WallC.sz2 > -floorZ) return;
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;
}
if (m3DFloor.clipBottom && textop < m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z)
{
return true;
}
if (m3DFloor.clipTop && textop - texheight > m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z)
{
return true;
}
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;
double floorZ = textop - texheight;
if (m3DFloor.clipBottom && ceilZ < m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z) return;
if (m3DFloor.clipTop && floorZ > m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z) return;
// The 3D Floors implementation destroys the ceiling clip when doing its height passes..
if (m3DFloor.clipTop || m3DFloor.clipBottom)
@ -271,19 +143,11 @@ namespace swrenderer
floorZ = MAX(floorZ, clipZ);
}
wallupper.Project(Thread->Viewport.get(), ceilZ, &WallC);
walllower.Project(Thread->Viewport.get(), floorZ, &WallC);
wallupper.Project(Thread->Viewport.get(), ceilZ, &ds->WallC);
walllower.Project(Thread->Viewport.get(), floorZ, &ds->WallC);
for (int i = x1; i < x2; i++)
{
if (wallupper.ScreenY[i] < mceilingclip[i])
wallupper.ScreenY[i] = mceilingclip[i];
}
for (int i = x1; i < x2; i++)
{
if (walllower.ScreenY[i] > mfloorclip[i])
walllower.ScreenY[i] = mfloorclip[i];
}
wallupper.ClipTop(x1, x2, ds->drawsegclip);
walllower.ClipBottom(x1, x2, ds->drawsegclip);
if (clip3d->CurrentSkybox)
{ // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor
@ -293,59 +157,15 @@ namespace swrenderer
(curline->sidedef->Flags & WALLF_CLIP_MIDTEX) ||
(curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX))
{
ClipMidtex(x1, x2);
ClipMidtex(ds, x1, x2);
}
}
mfloorclip = walllower.ScreenY;
mceilingclip = wallupper.ScreenY;
auto cameraLight = CameraLight::Instance();
bool needslight = (cameraLight->FixedColormap() == nullptr && cameraLight->FixedLightLevel() < 0);
// draw the columns one at a time
if (visible)
{
Thread->PrepareTexture(tex, renderstyle);
float lightpos = mLight.GetLightPos(x1);
for (int x = x1; x < x2; ++x)
{
if (needslight)
columndrawerargs.SetLight(lightpos, mLight.GetLightLevel(), mLight.GetFoggy(), Thread->Viewport.get());
fixed_t iscale = xs_Fix<16>::ToFix(MaskedSWall[x] * MaskedScaleY);
double sprtopscreen;
if (sprflipvert)
sprtopscreen = viewport->CenterY + texturemid * spryscale;
else
sprtopscreen = viewport->CenterY - texturemid * spryscale;
columndrawerargs.DrawMaskedColumn(Thread, x, iscale, tex, maskedtexturecol[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, renderstyle);
lightpos += mLight.GetLightStep();
spryscale += rw_scalestep;
}
}
}
else
{ // Texture does wrap vertically.
if (tex->useWorldPanning(curline->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z + rowoffset) * MaskedScaleY;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
texturemid = (texturemid - Thread->Viewport->viewpoint.Pos.Z) * MaskedScaleY + rowoffset;
}
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
@ -355,142 +175,58 @@ namespace swrenderer
(curline->sidedef->Flags & WALLF_CLIP_MIDTEX) ||
(curline->GetLevel()->ib_compatflags & BCOMPATF_CLIPMIDTEX))
{
ClipMidtex(x1, x2);
ClipMidtex(ds, x1, x2);
}
}
if (m3DFloor.clipTop)
{
wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &WallC);
for (int i = x1; i < x2; i++)
{
if (wallupper.ScreenY[i] < mceilingclip[i])
wallupper.ScreenY[i] = mceilingclip[i];
}
wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
wallupper.ClipTop(x1, x2, ds->drawsegclip);
mceilingclip = wallupper.ScreenY;
}
if (m3DFloor.clipBottom)
{
walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &WallC);
for (int i = x1; i < x2; i++)
{
if (walllower.ScreenY[i] > mfloorclip[i])
walllower.ScreenY[i] = mfloorclip[i];
}
walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
walllower.ClipBottom(x1, x2, ds->drawsegclip);
mfloorclip = walllower.ScreenY;
}
rw_offset = 0;
FSoftwareTexture *rw_pic = tex;
double top, bot;
GetMaskedWallTopBottom(ds, top, bot);
float alpha = FLOAT2FIXED((float)MIN(curline->linedef->alpha, 1.));
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, rw_offset, mLight, nullptr);
}
return false;
sector_t tempsec;
const sector_t* lightsector = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
fixed_t alpha = FLOAT2FIXED((float)MIN(curline->linedef->alpha, 1.));
bool additive = (curline->linedef->flags & ML_ADDTRANS) != 0;
RenderWallPart renderWallpart(Thread);
renderWallpart.Render(lightsector, curline, ds->WallC, tex, x1, x2, mceilingclip, mfloorclip, ds->texcoords, true, additive, alpha);
}
// kg3D - render one fake wall
void RenderDrawSegment::RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
void RenderDrawSegment::Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic)
{
int i;
double xscale;
double yscale;
fixed_t Alpha = Scale(rover->alpha, OPAQUE, 255);
if (Alpha <= 0)
return;
mLight.SetLightLeft(ds->light, ds->lightstep, ds->x1);
sector_t* lightsector = (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls()) ? backsector : frontsector;
const short *mfloorclip = ds->sprbottomclip - ds->x1;
const short *mceilingclip = ds->sprtopclip - ds->x1;
wallupper.Project(Thread->Viewport.get(), clipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
walllower.Project(Thread->Viewport.get(), clipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
//double spryscale = ds->iscale + ds->iscalestep * (x1 - ds->x1);
float *MaskedSWall = ds->swall - ds->x1;
// find positioning
side_t *scaledside;
side_t::ETexpart scaledpart;
if (rover->flags & FF_UPPERTEXTURE)
{
scaledside = curline->sidedef;
scaledpart = side_t::top;
}
else if (rover->flags & FF_LOWERTEXTURE)
{
scaledside = curline->sidedef;
scaledpart = side_t::bottom;
}
else
{
scaledside = rover->master->sidedef[0];
scaledpart = side_t::mid;
}
xscale = rw_pic->GetScale().X * scaledside->GetTextureXScale(scaledpart);
yscale = rw_pic->GetScale().Y * scaledside->GetTextureYScale(scaledpart);
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid);
double planez = rover->model->GetPlaneTexZ(sector_t::ceiling);
rw_offset = FLOAT2FIXED(curline->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid));
if (rowoffset < 0)
{
rowoffset += rw_pic->GetHeight();
}
double texturemid = (planez - Thread->Viewport->viewpoint.Pos.Z) * yscale;
if (rw_pic->useWorldPanning(curline->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid = texturemid + rowoffset * yscale;
rw_offset = xs_RoundToInt(rw_offset * xscale);
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
texturemid += rowoffset;
}
WallC = ds->WallC;
WallT = ds->tmapvals;
Clip3DFloors *clip3d = Thread->Clip3D.get();
wallupper.Project(Thread->Viewport.get(), clipTop - Thread->Viewport->viewpoint.Pos.Z, &WallC);
walllower.Project(Thread->Viewport.get(), clipBottom - Thread->Viewport->viewpoint.Pos.Z, &WallC);
for (i = x1; i < x2; i++)
{
if (wallupper.ScreenY[i] < mceilingclip[i])
wallupper.ScreenY[i] = mceilingclip[i];
}
for (i = x1; i < x2; i++)
{
if (walllower.ScreenY[i] > mfloorclip[i])
walllower.ScreenY[i] = mfloorclip[i];
}
wallupper.ClipTop(x1, x2, ds->drawsegclip);
walllower.ClipBottom(x1, x2, ds->drawsegclip);
ProjectedWallTexcoords walltexcoords;
walltexcoords.ProjectPos(Thread->Viewport.get(), curline->sidedef->TexelLength*xscale, ds->WallC.sx1, ds->WallC.sx2, WallT);
double top, bot;
GetMaskedWallTopBottom(ds, top, bot);
walltexcoords.Project3DFloor(Thread->Viewport.get(), rover, curline, ds->WallC, rw_pic);
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, rw_offset, mLight, nullptr);
renderWallpart.Render(lightsector, curline, ds->WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, walltexcoords, true, (rover->flags & FF_ADDITIVETRANS) != 0, Alpha);
RenderDecal::RenderDecals(Thread, curline->sidedef, ds, curline, mLight, wallupper.ScreenY, walllower.ScreenY, true);
RenderDecal::RenderDecals(Thread, ds, curline, lightsector, wallupper.ScreenY, walllower.ScreenY, true);
}
// kg3D - walls of fake floors
void RenderDrawSegment::RenderFakeWallRange(DrawSegment *ds, int x1, int x2)
void RenderDrawSegment::Render3DFloorWallRange(DrawSegment *ds, int x1, int x2)
{
int i, j;
F3DFloor *rover, *fover = nullptr;
@ -503,16 +239,11 @@ namespace swrenderer
frontsector = curline->frontsector;
backsector = curline->backsector;
if (backsector == nullptr)
{
if (!backsector)
return;
}
if (ds->Has3DFloorFrontSectorWalls() && !ds->Has3DFloorBackSectorWalls())
{
sector_t *sec = backsector;
backsector = frontsector;
frontsector = sec;
}
std::swap(frontsector, backsector);
floorHeight = backsector->CenterFloor();
ceilingHeight = backsector->CenterCeiling();
@ -681,39 +412,7 @@ namespace swrenderer
if (rw_pic && !swimmable_found)
{
// 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);
Render3DFloorWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
}
break;
}
@ -864,58 +563,57 @@ namespace swrenderer
if (rw_pic && !swimmable_found)
{
// 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);
Render3DFloorWall(ds, x1, x2, fover ? fover : rover, clipTop, clipBottom, rw_pic);
}
break;
}
}
}
void RenderDrawSegment::RenderFog(DrawSegment* ds, int x1, int x2)
{
const short* mfloorclip = ds->drawsegclip.sprbottomclip;
const short* mceilingclip = ds->drawsegclip.sprtopclip;
if (m3DFloor.clipTop)
{
wallupper.Project(Thread->Viewport.get(), m3DFloor.sclipTop - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
wallupper.ClipTop(x1, x2, ds->drawsegclip);
mceilingclip = wallupper.ScreenY;
}
if (m3DFloor.clipBottom)
{
walllower.Project(Thread->Viewport.get(), m3DFloor.sclipBottom - Thread->Viewport->viewpoint.Pos.Z, &ds->WallC);
walllower.ClipBottom(x1, x2, ds->drawsegclip);
mfloorclip = walllower.ScreenY;
}
sector_t tempsec;
const sector_t* lightsector = Thread->OpaquePass->FakeFlat(frontsector, &tempsec, nullptr, nullptr, nullptr, 0, 0, 0, 0);
ProjectedWallLight walllight;
walllight.SetColormap(lightsector, curline);
walllight.SetLightLeft(Thread, ds->WallC);
RenderFogBoundary renderfog;
renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, walllight);
}
// Clip a midtexture to the floor and ceiling of the sector in front of it.
void RenderDrawSegment::ClipMidtex(int x1, int x2)
void RenderDrawSegment::ClipMidtex(DrawSegment* ds, int x1, int x2)
{
ProjectedWallLine most;
RenderPortal *renderportal = Thread->Portal.get();
most.Project(Thread->Viewport.get(), curline->frontsector->ceilingplane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
most.Project(Thread->Viewport.get(), curline->frontsector->ceilingplane, &ds->WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
for (int i = x1; i < x2; ++i)
{
if (wallupper.ScreenY[i] < most.ScreenY[i])
wallupper.ScreenY[i] = most.ScreenY[i];
}
most.Project(Thread->Viewport.get(), curline->frontsector->floorplane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
most.Project(Thread->Viewport.get(), curline->frontsector->floorplane, &ds->WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
for (int i = x1; i < x2; ++i)
{
if (walllower.ScreenY[i] > most.ScreenY[i])
@ -941,4 +639,22 @@ namespace swrenderer
bot = MAX(bot, m3DFloor.sclipBottom);
}
}
void RenderDrawSegment::GetNoWrapMidTextureZ(DrawSegment* ds, FSoftwareTexture* tex, double& ceilZ, double& floorZ)
{
double texheight = tex->GetScaledHeightDouble() / fabs(curline->sidedef->GetTextureYScale(side_t::mid));
double texturemid;
if (curline->linedef->flags & ML_DONTPEGBOTTOM)
texturemid = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
else
texturemid = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
if (tex->useWorldPanning(curline->GetLevel()))
rowoffset /= fabs(tex->GetScale().Y * curline->sidedef->GetTextureYScale(side_t::mid));
double textop = texturemid + rowoffset - Thread->Viewport->viewpoint.Pos.Z;
// Unclipped vanilla Doom range for the wall. Relies on ceiling/floor clip to clamp the wall in range.
ceilZ = textop;
floorZ = textop - texheight;
}
}

View file

@ -37,10 +37,12 @@ namespace swrenderer
RenderThread *Thread = nullptr;
private:
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, double clipTop, double clipBottom, FSoftwareTexture *rw_pic);
void RenderFakeWallRange(DrawSegment *ds, int x1, int x2);
void RenderWall(DrawSegment *ds, int x1, int x2);
void Render3DFloorWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, double clipTop, double clipBottom, FSoftwareTexture *rw_pic);
void Render3DFloorWallRange(DrawSegment *ds, int x1, int x2);
void RenderFog(DrawSegment* ds, int x1, int x2);
void ClipMidtex(DrawSegment* ds, int x1, int x2);
void GetNoWrapMidTextureZ(DrawSegment* ds, FSoftwareTexture* tex, double& ceilZ, double& floorZ);
void GetMaskedWallTopBottom(DrawSegment *ds, double &top, double &bot);
sector_t *frontsector = nullptr;
@ -49,13 +51,6 @@ namespace swrenderer
seg_t *curline = nullptr;
Fake3DTranslucent m3DFloor;
FWallCoords WallC;
FWallTmapVals WallT;
ProjectedWallLight mLight;
fixed_t rw_offset = 0;
ProjectedWallLine wallupper;
ProjectedWallLine walllower;
};

View file

@ -54,24 +54,81 @@
namespace swrenderer
{
void RenderWallPart::ProcessNormalWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal)
RenderWallPart::RenderWallPart(RenderThread* thread)
{
if (rw_pic == nullptr)
Thread = thread;
}
void RenderWallPart::Render(const sector_t* lightsector, seg_t* curline, const FWallCoords& WallC, FSoftwareTexture* pic, int x1, int x2, const short* walltop, const short* wallbottom, const ProjectedWallTexcoords& texcoords, bool mask, bool additive, fixed_t alpha)
{
if (pic == nullptr)
return;
int fracbits = 32 - rw_pic->GetHeightBits();
if (fracbits == 32)
{ // Hack for one pixel tall textures
fracbits = 0;
yrepeat = 0;
texturemid = 0;
this->x1 = x1;
this->x2 = x2;
this->lightsector = lightsector;
this->curline = curline;
this->WallC = WallC;
this->pic = pic;
this->mask = mask;
this->additive = additive;
this->alpha = alpha;
light_list = GetLightList();
mLight.SetColormap(lightsector, curline);
mLight.SetLightLeft(Thread, WallC);
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
CameraLight* cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0 || !(lightsector->e && lightsector->e->XFloor.lightlist.Size()))
{
ProcessNormalWall(walltop, wallbottom, texcoords);
}
else
{
ProcessStripedWall(walltop, wallbottom, texcoords);
}
}
void RenderWallPart::ProcessStripedWall(const short* uwal, const short* dwal, const ProjectedWallTexcoords& texcoords)
{
RenderPortal* renderportal = Thread->Portal.get();
ProjectedWallLine most1, most2, most3;
const short* up = uwal;
short* down = most1.ScreenY;
for (unsigned int i = 0; i < lightsector->e->XFloor.lightlist.Size(); i++)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), lightsector->e->XFloor.lightlist[i].plane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
if (j != ProjectedWallCull::OutsideAbove)
{
for (int j = x1; j < x2; ++j)
{
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
}
ProcessNormalWall(up, down, texcoords);
up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
mLight.SetColormap(lightsector, curline, &lightsector->e->XFloor.lightlist[i]);
}
ProcessNormalWall(up, dwal, texcoords);
}
void RenderWallPart::ProcessNormalWall(const short* uwal, const short* dwal, const ProjectedWallTexcoords& texcoords)
{
CameraLight* cameraLight = CameraLight::Instance();
RenderViewport* viewport = Thread->Viewport.get();
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)
if (!pic->GetTexture()->isMasked() && mask && alpha >= OPAQUE && !additive)
{
drawerargs.SetStyle(true, false, OPAQUE, mLight.GetBaseColormap());
}
@ -80,486 +137,65 @@ namespace swrenderer
drawerargs.SetStyle(mask, additive, alpha, mLight.GetBaseColormap());
}
RenderViewport *viewport = Thread->Viewport.get();
int count = x2 - x1;
short* data = Thread->FrameMemory->AllocMemory<short>(count << 1);
CameraLight *cameraLight = CameraLight::Instance();
bool fixed = (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0);
drawerargs.x1 = x1;
drawerargs.x2 = x2;
drawerargs.uwal = data - x1;
drawerargs.dwal = data + count - x1; // to avoid calling AllocMemory twice
memcpy(drawerargs.uwal + x1, uwal + x1, sizeof(short) * count);
memcpy(drawerargs.dwal + x1, dwal + x1, sizeof(short) * count);
drawerargs.WallC = WallC;
drawerargs.texcoords = texcoords;
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 = mLight.GetLightPos(x1);
float lightstep = mLight.GetLightStep();
drawerargs.lightpos = mLight.GetLightPos(x1);
drawerargs.lightstep = mLight.GetLightStep();
drawerargs.mShade = LightVisibility::LightLevelToShade(mLight.GetLightLevel(), mLight.GetFoggy(), viewport);
drawerargs.lightlist = light_list;
drawerargs.texwidth = pic->GetPhysicalWidth();
drawerargs.texheight = pic->GetPhysicalHeight();
if (viewport->RenderTarget->IsBgra())
{
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]));
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);
}
drawerargs.texpixels = pic->GetPixelsBgra();
drawerargs.fracbits = 32;
drawerargs.mipmapped = r_mipmap && pic->Mipmapped();
}
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;
}
}
}
drawerargs.texpixels = pic->GetPixels(DefaultRenderStyle());
int fracbits = 32 - pic->GetHeightBits();
if (fracbits == 32) fracbits = 0; // One pixel tall textures
drawerargs.fracbits = fracbits;
drawerargs.mipmapped = false;
}
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;
// This data really should be its own command as it rarely changes
drawerargs.SetDest(viewport);
drawerargs.CenterX = Thread->Viewport->CenterX;
drawerargs.CenterY = Thread->Viewport->CenterY;
drawerargs.FocalTangent = Thread->Viewport->viewwindow.FocalTangent;
drawerargs.InvZtoScale = Thread->Viewport->InvZtoScale;
drawerargs.ViewpointPos = { (float)Thread->Viewport->viewpoint.Pos.X, (float)Thread->Viewport->viewpoint.Pos.Y, (float)Thread->Viewport->viewpoint.Pos.Z };
drawerargs.Sin = Thread->Viewport->viewpoint.Sin;
drawerargs.Cos = Thread->Viewport->viewpoint.Cos;
drawerargs.TanCos = Thread->Viewport->viewpoint.TanCos;
drawerargs.TanSin = Thread->Viewport->viewpoint.TanSin;
drawerargs.PortalMirrorFlags = Thread->Portal->MirrorFlags;
drawerargs.fixedlight = (cameraLight->FixedColormap() || cameraLight->FixedLightLevel() >= 0);
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);
}
}
}
drawerargs.DrawWall(Thread);
}
void RenderWallPart::SetLights(WallDrawerArgs &drawerargs, int x, int y1)
FLightNode* RenderWallPart::GetLightList()
{
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->IsActive())
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->IsActive())
{
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->IsAttenuated();
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)
{
ProjectedWallLine most1, most2, most3;
const short *up;
short *down;
up = uwal;
down = most1.ScreenY;
assert(WallC.sx1 <= x1);
assert(WallC.sx2 >= x2);
RenderPortal *renderportal = Thread->Portal.get();
// kg3D - fake floors instead of zdoom light list
for (unsigned int i = 0; i < frontsector->e->XFloor.lightlist.Size(); i++)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), frontsector->e->XFloor.lightlist[i].plane, &WallC, curline, renderportal->MirrorFlags & RF_XFLIP);
if (j != ProjectedWallCull::OutsideAbove)
{
for (int j = x1; j < x2; ++j)
{
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
}
ProcessNormalWall(up, down, texturemid, swal, lwal);
up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
mLight.SetColormap(frontsector, curline, &frontsector->e->XFloor.lightlist[i]);
}
ProcessNormalWall(up, dwal, texturemid, swal, lwal);
}
void RenderWallPart::ProcessWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal)
{
CameraLight *cameraLight = CameraLight::Instance();
if (cameraLight->FixedColormap() != NULL || cameraLight->FixedLightLevel() >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
{
ProcessNormalWall(uwal, dwal, texturemid, swal, lwal);
}
CameraLight* cameraLight = CameraLight::Instance();
if ((cameraLight->FixedLightLevel() >= 0) || cameraLight->FixedColormap())
return nullptr; // [SP] Don't draw dynlights if invul/lightamp active
else if (curline && curline->sidedef)
return curline->sidedef->lighthead;
else
{
ProcessStripedWall(uwal, dwal, texturemid, swal, lwal);
}
}
//=============================================================================
//
// ProcessWallNP2
//
// This is a wrapper around ProcessWall that helps it tile textures whose heights
// are not powers of 2. It divides the wall into texture-sized strips and calls
// ProcessNormalWall for each of those. Since only one repetition of the texture fits
// in each strip, ProcessWall will not tile.
//
//=============================================================================
void RenderWallPart::ProcessWallNP2(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal, double top, double bot)
{
ProjectedWallLine most1, most2, most3;
double texheight = rw_pic->GetHeight();
double partition;
double scaledtexheight = texheight / yrepeat;
if (yrepeat >= 0)
{ // normal orientation: draw strips from top to bottom
partition = top - fmod(top - texturemid / yrepeat - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight);
if (partition == top)
{
partition -= scaledtexheight;
}
const short *up = uwal;
short *down = most1.ScreenY;
texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + texheight;
while (partition > bot)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC);
if (j != ProjectedWallCull::OutsideAbove)
{
for (int j = x1; j < x2; ++j)
{
down[j] = clamp(most3.ScreenY[j], up[j], dwal[j]);
}
ProcessWall(up, down, texturemid, swal, lwal);
up = down;
down = (down == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
partition -= scaledtexheight;
texturemid -= texheight;
}
ProcessWall(up, dwal, texturemid, swal, lwal);
}
else
{ // upside down: draw strips from bottom to top
partition = bot - fmod(bot - texturemid / yrepeat - Thread->Viewport->viewpoint.Pos.Z, scaledtexheight);
short *up = most1.ScreenY;
const short *down = dwal;
texturemid = (partition - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + texheight;
while (partition < top)
{
ProjectedWallCull j = most3.Project(Thread->Viewport.get(), partition - Thread->Viewport->viewpoint.Pos.Z, &WallC);
if (j != ProjectedWallCull::OutsideBelow)
{
for (int j = x1; j < x2; ++j)
{
up[j] = clamp(most3.ScreenY[j], uwal[j], down[j]);
}
ProcessWall(up, down, texturemid, swal, lwal);
down = up;
up = (up == most1.ScreenY) ? most2.ScreenY : most1.ScreenY;
}
partition -= scaledtexheight;
texturemid -= texheight;
}
ProcessWall(uwal, down, texturemid, swal, lwal);
}
}
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;
this->frontsector = frontsector;
this->curline = curline;
this->WallC = WallC;
this->yrepeat = yscale;
this->mLight = light;
this->xoffset = xoffset;
this->light_list = light_list;
this->rw_pic = pic;
this->mask = mask;
this->additive = additive;
this->alpha = alpha;
Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here.
if (rw_pic->GetHeight() != 1 << rw_pic->GetHeightBits())
{
ProcessWallNP2(walltop, wallbottom, texturemid, swall, lwall, top, bottom);
}
else
{
ProcessWall(walltop, wallbottom, texturemid, swall, lwall);
}
}
RenderWallPart::RenderWallPart(RenderThread *thread)
{
Thread = thread;
return nullptr;
}
}

View file

@ -46,47 +46,35 @@ namespace swrenderer
RenderWallPart(RenderThread *thread);
void Render(
sector_t *frontsector,
const sector_t *lightsector,
seg_t *curline,
const FWallCoords &WallC,
FSoftwareTexture *rw_pic,
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,
const ProjectedWallTexcoords &texcoords,
bool mask,
bool additive,
fixed_t alpha,
fixed_t xoffset,
const ProjectedWallLight &light,
FLightNode *light_list);
RenderThread *Thread = nullptr;
fixed_t alpha);
private:
void ProcessWallNP2(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal, double top, double bot);
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 SetLights(WallDrawerArgs &drawerargs, int x, int y1);
void ProcessStripedWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
void ProcessNormalWall(const short *uwal, const short *dwal, const ProjectedWallTexcoords& texcoords);
FLightNode* GetLightList();
RenderThread* Thread = nullptr;
int x1 = 0;
int x2 = 0;
FSoftwareTexture *rw_pic = nullptr;
sector_t *frontsector = nullptr;
FSoftwareTexture *pic = nullptr;
const sector_t *lightsector = nullptr;
seg_t *curline = nullptr;
FWallCoords WallC;
ProjectedWallLight mLight;
double yrepeat = 0.0;
fixed_t xoffset = 0;
FLightNode *light_list = nullptr;
bool mask = false;
bool additive = false;

View file

@ -48,6 +48,107 @@
namespace swrenderer
{
// Transform and clip coordinates. Returns true if it was clipped away
bool FWallCoords::Init(RenderThread* thread, const DVector2& pt1, const DVector2& pt2, seg_t* lineseg)
{
auto viewport = thread->Viewport.get();
RenderPortal* renderportal = thread->Portal.get();
tleft.X = float(pt1.X * viewport->viewpoint.Sin - pt1.Y * viewport->viewpoint.Cos);
tright.X = float(pt2.X * viewport->viewpoint.Sin - pt2.Y * viewport->viewpoint.Cos);
tleft.Y = float(pt1.X * viewport->viewpoint.TanCos + pt1.Y * viewport->viewpoint.TanSin);
tright.Y = float(pt2.X * viewport->viewpoint.TanCos + pt2.Y * viewport->viewpoint.TanSin);
if (renderportal->MirrorFlags & RF_XFLIP)
{
float t = -tleft.X;
tleft.X = -tright.X;
tright.X = t;
swapvalues(tleft.Y, tright.Y);
}
float fsx1, fsz1, fsx2, fsz2;
if (tleft.X >= -tleft.Y)
{
if (tleft.X > tleft.Y) return true; // left edge is off the right side
if (tleft.Y == 0) return true;
fsx1 = viewport->CenterX + tleft.X * viewport->CenterX / tleft.Y;
fsz1 = tleft.Y;
tx1 = 0.0f;
}
else
{
if (tright.X < -tright.Y) return true; // wall is off the left side
float den = tleft.X - tright.X - tright.Y + tleft.Y;
if (den == 0) return true;
fsx1 = 0;
tx1 = (tleft.X + tleft.Y) / den;
fsz1 = tleft.Y + (tright.Y - tleft.Y) * tx1;
}
if (fsz1 < TOO_CLOSE_Z)
return true;
if (tright.X <= tright.Y)
{
if (tright.X < -tright.Y) return true; // right edge is off the left side
if (tright.Y == 0) return true;
fsx2 = viewport->CenterX + tright.X * viewport->CenterX / tright.Y;
fsz2 = tright.Y;
tx2 = 1.0f;
}
else
{
if (tleft.X > tleft.Y) return true; // wall is off the right side
float den = tright.Y - tleft.Y - tright.X + tleft.X;
if (den == 0) return true;
fsx2 = viewwidth;
tx2 = (tleft.X - tleft.Y) / den;
fsz2 = tleft.Y + (tright.Y - tleft.Y) * tx2;
}
if (fsz2 < TOO_CLOSE_Z)
return true;
sx1 = xs_RoundToInt(fsx1);
sx2 = xs_RoundToInt(fsx2);
float delta = fsx2 - fsx1;
float t1 = (sx1 + 0.5f - fsx1) / delta;
float t2 = (sx2 + 0.5f - fsx1) / delta;
float invZ1 = 1.0f / fsz1;
float invZ2 = 1.0f / fsz2;
sz1 = 1.0f / (invZ1 * (1.0f - t1) + invZ2 * t1);
sz2 = 1.0f / (invZ1 * (1.0f - t2) + invZ2 * t2);
if (sx2 <= sx1)
return true;
if (lineseg && lineseg->linedef)
{
line_t* line = lineseg->linedef;
if (fabs(line->delta.X) > fabs(line->delta.Y))
{
t1 = (lineseg->v1->fX() - line->v1->fX()) / line->delta.X;
t2 = (lineseg->v2->fX() - line->v1->fX()) / line->delta.X;
}
else
{
t1 = (lineseg->v1->fY() - line->v1->fY()) / line->delta.Y;
t2 = (lineseg->v2->fY() - line->v1->fY()) / line->delta.Y;
}
tx1 = t1 + tx1 * (t2 - t1);
tx2 = t1 + tx2 * (t2 - t1);
}
return false;
}
////////////////////////////////////////////////////////////////////////////
ProjectedWallCull ProjectedWallLine::Project(RenderViewport *viewport, double z, const FWallCoords *wallc)
{
return Project(viewport, z, z, wallc);
@ -168,84 +269,385 @@ namespace swrenderer
}
}
/////////////////////////////////////////////////////////////////////////
void ProjectedWallTexcoords::Project(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT)
void ProjectedWallLine::ClipTop(int x1, int x2, const DrawSegmentClipInfo& clip)
{
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - viewport->CenterX);
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - viewport->CenterX);
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float xrepeat = (float)fabs(walxrepeat);
float depthScale = (float)(WallT.InvZstep * viewport->WallTMapScale2);
float depthOrg = (float)(-WallT.UoverZstep * viewport->WallTMapScale2);
if (walxrepeat < 0.0)
for (int i = x1; i < x2; i++)
{
for (int x = x1; x < x2; x++)
{
float u = uOverZ / invZ;
UPos[x] = (fixed_t)((xrepeat - u * xrepeat) * FRACUNIT);
VStep[x] = depthOrg + u * depthScale;
uOverZ += uGradient;
invZ += zGradient;
}
}
else
{
for (int x = x1; x < x2; x++)
{
float u = uOverZ / invZ;
UPos[x] = (fixed_t)(u * xrepeat * FRACUNIT);
VStep[x] = depthOrg + u * depthScale;
uOverZ += uGradient;
invZ += zGradient;
}
ScreenY[i] = std::max(ScreenY[i], clip.sprtopclip[i]);
}
}
void ProjectedWallTexcoords::ProjectPos(RenderViewport *viewport, double walxrepeat, int x1, int x2, const FWallTmapVals &WallT)
void ProjectedWallLine::ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip)
{
float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - viewport->CenterX);
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - viewport->CenterX);
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float xrepeat = (float)fabs(walxrepeat);
if (walxrepeat < 0.0f)
for (int i = x1; i < x2; i++)
{
for (int x = x1; x < x2; x++)
ScreenY[i] = std::min(ScreenY[i], clip.sprbottomclip[i]);
}
}
/////////////////////////////////////////////////////////////////////////
void ProjectedWallTexcoords::ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
float yscale = GetYScale(sidedef, pic, side_t::top);
double cameraZ = viewport->viewpoint.Pos.Z;
double texturemid;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGTOP)
{ // top of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale;
}
else
{ // bottom of texture at bottom
texturemid = (backsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale + pic->GetHeight();
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGTOP)
{ // bottom of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale + pic->GetHeight();
}
else
{ // top of texture at bottom
texturemid = (backsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale;
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::top);
fixed_t xoffset = GetXOffset(lineseg, pic, side_t::top);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::top), WallC, pic, xoffset, texturemid, yscale, false);
}
void ProjectedWallTexcoords::ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
float yscale = GetYScale(sidedef, pic, side_t::mid);
double cameraZ = viewport->viewpoint.Pos.Z;
double texturemid;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
texturemid = (frontsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale + pic->GetHeight();
}
else
{ // top of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale;
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
texturemid = (frontsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale;
}
else
{ // bottom of texture at top
texturemid = (frontsector->GetPlaneTexZ(sector_t::ceiling) - cameraZ) * yscale + pic->GetHeight();
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::mid);
fixed_t xoffset = GetXOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), WallC, pic, xoffset, texturemid, yscale, false);
}
void ProjectedWallTexcoords::ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
side_t* sidedef = lineseg->sidedef;
line_t* linedef = lineseg->linedef;
double frontlowertop = frontsector->GetPlaneTexZ(sector_t::ceiling);
if (frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum)
{
// Putting sky ceilings on the front and back of a line alters the way unpegged
// positioning works.
frontlowertop = backsector->GetPlaneTexZ(sector_t::ceiling);
}
float yscale = GetYScale(sidedef, pic, side_t::bottom);
double cameraZ = viewport->viewpoint.Pos.Z;
double texturemid;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
texturemid = (frontlowertop - cameraZ) * yscale;
}
else
{ // top of texture at top
texturemid = (backsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale;
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
texturemid = (frontlowertop - cameraZ) * yscale;
}
else
{ // bottom of texture at top
texturemid = (backsector->GetPlaneTexZ(sector_t::floor) - cameraZ) * yscale + pic->GetHeight();
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::bottom);
fixed_t xoffset = GetXOffset(lineseg, pic, side_t::bottom);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::bottom), WallC, pic, xoffset, texturemid, yscale, false);
}
void ProjectedWallTexcoords::ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
line_t* linedef = lineseg->linedef;
side_t* sidedef = lineseg->sidedef;
float yscale = GetYScale(sidedef, pic, side_t::mid);
double cameraZ = viewport->viewpoint.Pos.Z;
double texZFloor = MAX(frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor));
double texZCeiling = MIN(frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
double texturemid;
if (yscale >= 0)
{ // normal orientation
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // bottom of texture at bottom
texturemid = (texZFloor - cameraZ) * yscale + pic->GetHeight();
}
else
{ // top of texture at top
texturemid = (texZCeiling - cameraZ) * yscale;
}
}
else
{ // upside down
if (linedef->flags & ML_DONTPEGBOTTOM)
{ // top of texture at bottom
texturemid = (texZFloor - cameraZ) * yscale;
}
else
{ // bottom of texture at top
texturemid = (texZCeiling - cameraZ) * yscale + pic->GetHeight();
}
}
texturemid += GetRowOffset(lineseg, pic, side_t::mid);
fixed_t xoffset = GetXOffset(lineseg, pic, side_t::mid);
Project(viewport, sidedef->TexelLength * GetXScale(sidedef, pic, side_t::mid), WallC, pic, xoffset, texturemid, yscale, false);
}
void ProjectedWallTexcoords::Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic)
{
// find positioning
side_t* scaledside;
side_t::ETexpart scaledpart;
if (rover->flags & FF_UPPERTEXTURE)
{
scaledside = lineseg->sidedef;
scaledpart = side_t::top;
}
else if (rover->flags & FF_LOWERTEXTURE)
{
scaledside = lineseg->sidedef;
scaledpart = side_t::bottom;
}
else
{
scaledside = rover->master->sidedef[0];
scaledpart = side_t::mid;
}
double xscale = pic->GetScale().X * scaledside->GetTextureXScale(scaledpart);
float yscale = pic->GetScale().Y * scaledside->GetTextureYScale(scaledpart);
double rowoffset = lineseg->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid);
double planez = rover->model->GetPlaneTexZ(sector_t::ceiling);
fixed_t xoffset = FLOAT2FIXED(lineseg->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid));
if (rowoffset < 0)
{
rowoffset += pic->GetHeight();
}
double texturemid = (planez - viewport->viewpoint.Pos.Z) * yscale;
if (pic->useWorldPanning(lineseg->GetLevel()))
{
// rowoffset is added before the multiply so that the masked texture will
// still be positioned in world units rather than texels.
texturemid = texturemid + rowoffset * yscale;
xoffset = xs_RoundToInt(xoffset * xscale);
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
texturemid += rowoffset;
}
Project(viewport, lineseg->sidedef->TexelLength * xscale, WallC, pic, xoffset, texturemid, yscale, false);
}
void ProjectedWallTexcoords::Project(RenderViewport *viewport, double walxrepeat, const FWallCoords& WallC, FSoftwareTexture* pic, fixed_t xoffset, double texturemid, float yscale, bool flipx)
{
float texwidth = pic->GetWidth();
float texheight = pic->GetHeight();
float texU1 = FIXED2FLOAT(xoffset) / texwidth;
float texU2 = texU1 + walxrepeat / texwidth;
if (walxrepeat < 0.0)
{
texU1 += 1.0f;
texU2 += 1.0f;
}
if (flipx)
{
texU1 = 1.0f - texU1;
texU2 = 1.0f - texU2;
}
float texV = texturemid / texheight;
// Set up some fake vertices as that makes it easier to calculate the gradients using code already known to work.
Vertex v1;
v1.x = WallC.sx1 + 0.5f;// WallC.tleft.X;
v1.y = 0.0f;
v1.w = WallC.sz1;//WallC.tleft.Y;
Vertex v2;
v2.x = WallC.sx2 + 0.5f;// WallC.tright.X;
v2.y = 0.0f;
v2.w = WallC.sz2;// WallC.tright.Y;
v1.u = texU1 * (1.0f - WallC.tx1) + texU2 * WallC.tx1;
v2.u = texU1 * (1.0f - WallC.tx2) + texU2 * WallC.tx2;
v1.v = texV;
v2.v = texV;
Vertex v3;
v3.x = v1.x;
v3.y = v1.y - 100.0f;
v3.w = v1.w;
v3.u = v1.u;
v3.v = v1.v + yscale * 100.0f / texheight;
// Project to screen space
v1.w = 1.0f / v1.w;
v2.w = 1.0f / v2.w;
v3.w = 1.0f / v3.w;
v1.y = viewport->CenterY - v1.y * v1.w * viewport->InvZtoScale;
v2.y = viewport->CenterY - v2.y * v2.w * viewport->InvZtoScale;
v3.y = viewport->CenterY - v3.y * v3.w * viewport->InvZtoScale;
// Calculate gradients
float bottomX = (v2.x - v3.x) * (v1.y - v3.y) - (v1.x - v3.x) * (v2.y - v3.y);
float bottomY = (v1.x - v3.x) * (v2.y - v3.y) - (v2.x - v3.x) * (v1.y - v3.y);
wstepX = FindGradientX(bottomX, 1.0f, 1.0f, 1.0f, v1, v2, v3);
ustepX = FindGradientX(bottomX, v1.u, v2.u, v3.u, v1, v2, v3);
vstepX = FindGradientX(bottomX, v1.v, v2.v, v3.v, v1, v2, v3);
wstepY = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f, v1, v2, v3);
ustepY = FindGradientY(bottomY, v1.u, v2.u, v3.u, v1, v2, v3);
vstepY = FindGradientY(bottomY, v1.v, v2.v, v3.v, v1, v2, v3);
startX = v1.x;
upos = v1.u * v1.w;
vpos = v1.v * v1.w;
wpos = v1.w;
}
double ProjectedWallTexcoords::GetRowOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
double yrepeat = GetYScale(lineseg->sidedef, tex, texpart);
double rowoffset = lineseg->sidedef->GetTextureYOffset(texpart);
if (yrepeat >= 0)
{
// check if top of texture at top:
bool top_at_top =
(texpart == side_t::top && (lineseg->linedef->flags & ML_DONTPEGTOP)) ||
(texpart != side_t::top && !(lineseg->linedef->flags & ML_DONTPEGBOTTOM));
if (rowoffset < 0 && top_at_top)
{
float u = uOverZ / invZ * xrepeat - xrepeat;
UPos[x] = (fixed_t)(u * FRACUNIT);
uOverZ += uGradient;
invZ += zGradient;
rowoffset += tex->GetHeight();
}
}
else
{
for (int x = x1; x < x2; x++)
{
float u = uOverZ / invZ * xrepeat;
UPos[x] = (fixed_t)(u * FRACUNIT);
uOverZ += uGradient;
invZ += zGradient;
}
rowoffset = -rowoffset;
}
if (tex->useWorldPanning(lineseg->GetLevel()))
{
return rowoffset * yrepeat;
}
else
{
// rowoffset is added outside the multiply so that it positions the texture
// by texels instead of world units.
return rowoffset;
}
}
fixed_t ProjectedWallTexcoords::GetXOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
fixed_t TextureOffsetU = FLOAT2FIXED(lineseg->sidedef->GetTextureXOffset(texpart));
double xscale = GetXScale(lineseg->sidedef, tex, texpart);
fixed_t xoffset;
if (tex->useWorldPanning(lineseg->GetLevel()))
{
xoffset = xs_RoundToInt(TextureOffsetU * xscale);
}
else
{
xoffset = TextureOffsetU;
}
if (xscale < 0)
{
xoffset = -xoffset;
}
return xoffset;
}
double ProjectedWallTexcoords::GetXScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
double TextureScaleU = sidedef->GetTextureXScale(texpart);
return tex->GetScale().X * TextureScaleU;
}
double ProjectedWallTexcoords::GetYScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart)
{
double TextureScaleV = sidedef->GetTextureYScale(texpart);
return tex->GetScale().Y * TextureScaleV;
}
/////////////////////////////////////////////////////////////////////////
void ProjectedWallLight::SetLightLeft(RenderThread *thread, const FWallCoords &wallc)
{
spritelight = false;
x1 = wallc.sx1;
CameraLight *cameraLight = CameraLight::Instance();

View file

@ -27,8 +27,20 @@
namespace swrenderer
{
struct FWallCoords;
struct FWallTmapVals;
struct DrawSegmentClipInfo;
struct FWallCoords
{
FVector2 tleft; // coords at left of wall in view space rx1,ry1
FVector2 tright; // coords at right of wall in view space rx2,ry2
float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2
short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2
float tx1, tx2; // texture coordinate fractions
bool Init(RenderThread* thread, const DVector2& pt1, const DVector2& pt2, seg_t* lineseg = nullptr);
};
enum class ProjectedWallCull
{
@ -45,16 +57,55 @@ namespace swrenderer
ProjectedWallCull Project(RenderViewport *viewport, double z1, double z2, const FWallCoords *wallc);
ProjectedWallCull Project(RenderViewport *viewport, const secplane_t &plane, const FWallCoords *wallc, seg_t *line, bool xflip);
ProjectedWallCull Project(RenderViewport *viewport, double z, const FWallCoords *wallc);
void ClipTop(int x1, int x2, const DrawSegmentClipInfo& clip);
void ClipBottom(int x1, int x2, const DrawSegmentClipInfo& clip);
};
class ProjectedWallTexcoords
{
public:
float VStep[MAXWIDTH]; // swall
fixed_t UPos[MAXWIDTH]; // lwall
void ProjectTop(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
void ProjectMid(RenderViewport* viewport, sector_t* frontsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
void ProjectBottom(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
void ProjectTranslucent(RenderViewport* viewport, sector_t* frontsector, sector_t* backsector, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
void Project3DFloor(RenderViewport* viewport, F3DFloor* rover, seg_t* lineseg, const FWallCoords& WallC, FSoftwareTexture* pic);
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);
// Gradients
float upos, ustepX, ustepY;
float vpos, vstepX, vstepY;
float wpos, wstepX, wstepY;
float startX;
private:
void Project(RenderViewport* viewport, double walxrepeat, const FWallCoords& WallC, FSoftwareTexture* pic, fixed_t xoffset, double texturemid, float yscale, bool flipx);
static fixed_t GetXOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart);
static double GetRowOffset(seg_t* lineseg, FSoftwareTexture* tex, side_t::ETexpart texpart);
static double GetXScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart);
static double GetYScale(side_t* sidedef, FSoftwareTexture* tex, side_t::ETexpart texpart);
struct Vertex
{
float x, y, w;
float u, v;
};
float FindGradientX(float bottomX, float c0, float c1, float c2, const Vertex& v1, const Vertex& v2, const Vertex& v3)
{
c0 *= v1.w;
c1 *= v2.w;
c2 *= v3.w;
return ((c1 - c2) * (v1.y - v3.y) - (c0 - c2) * (v2.y - v3.y)) / bottomX;
}
float FindGradientY(float bottomY, float c0, float c1, float c2, const Vertex& v1, const Vertex& v2, const Vertex& v3)
{
c0 *= v1.w;
c1 *= v2.w;
c2 *= v3.w;
return ((c1 - c2) * (v1.x - v3.x) - (c0 - c2) * (v2.x - v3.x)) / bottomY;
}
};
class ProjectedWallLight
@ -66,16 +117,17 @@ namespace swrenderer
float GetLightPos(int x) const { return lightleft + lightstep * (x - x1); }
float GetLightStep() const { return lightstep; }
bool IsSpriteLight() const { return spritelight; }
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);
void SetSpriteLight() { lightleft = 0.0f; lightstep = 0.0f; spritelight = true; }
private:
int lightlevel;
bool foggy;
FDynamicColormap *basecolormap;
bool spritelight;
int x1;
float lightleft;

View file

@ -56,6 +56,7 @@
CVAR(Bool, r_linearsky, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
EXTERN_CVAR(Int, r_skymode)
EXTERN_CVAR(Bool, cl_oldfreelooklimit)
namespace swrenderer
{
@ -82,11 +83,12 @@ namespace swrenderer
FSoftwareTexture *sskytex2 = skytex2->GetSoftwareTexture();
skytexturemid = 0;
int skyheight = skytex1->GetDisplayHeight();
skyoffset = cl_oldfreelooklimit? 0 : skyheight == 256? 166 : skyheight >= 240? 150 : skyheight >= 200? 110 : 138;
if (skyheight >= 128 && skyheight < 200)
{
skytexturemid = -28;
}
else if (skyheight > 200)
else if (skyheight >= 200)
{
skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? skytex1->GetSkyOffset() : 0);
}
@ -102,9 +104,9 @@ namespace swrenderer
if (Level->skystretch)
{
skyscale *= (double)SKYSTRETCH_HEIGHT / skyheight;
skyiscale *= skyheight / (float)SKYSTRETCH_HEIGHT;
skytexturemid *= skyheight / (double)SKYSTRETCH_HEIGHT;
skyscale *= (double)(SKYSTRETCH_HEIGHT + skyoffset) / skyheight;
skyiscale *= skyheight / (float)(SKYSTRETCH_HEIGHT + skyoffset);
skytexturemid *= skyheight / (double)(SKYSTRETCH_HEIGHT + skyoffset);
}
// The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees,
@ -204,7 +206,7 @@ namespace swrenderer
frontcyl = MAX(frontskytex->GetWidth(), frontxscale);
if (Level->skystretch)
{
skymid = skymid * frontskytex->GetScaledHeightDouble() / SKYSTRETCH_HEIGHT;
skymid = skymid * frontskytex->GetScaledHeightDouble() / (SKYSTRETCH_HEIGHT + skyoffset);
}
}
}
@ -274,7 +276,7 @@ namespace swrenderer
void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2)
{
if (1 << frontskytex->GetHeightBits() == frontskytex->GetPhysicalHeight())
if (1 << frontskytex->GetHeightBits() >= frontskytex->GetPhysicalHeight())
{
double texturemid = skymid * frontskytex->GetScale().Y + frontskytex->GetHeight();
DrawSkyColumnStripe(start_x, y1, y2, frontskytex->GetScale().Y, texturemid, frontskytex->GetScale().Y);

View file

@ -55,6 +55,7 @@ namespace swrenderer
fixed_t backcyl = 0;
double skymid = 0.0;
angle_t skyangle = 0;
int skyoffset = 0;
SkyDrawerArgs drawerargs;
};

View file

@ -37,6 +37,7 @@
#include "po_man.h"
#include "r_data/colormaps.h"
#include "r_memory.h"
#include <stdlib.h>
void *RenderMemory::AllocBytes(int size)
{
@ -73,3 +74,42 @@ void RenderMemory::Clear()
FreeBlocks.push_back(std::move(block));
}
}
static void* Aligned_Alloc(size_t alignment, size_t size)
{
void* ptr;
#if defined _MSC_VER
ptr = _aligned_malloc(size, alignment);
if (!ptr)
throw std::bad_alloc();
#else
// posix_memalign required alignment to be a min of sizeof(void *)
if (alignment < sizeof(void*))
alignment = sizeof(void*);
if (posix_memalign((void**)&ptr, alignment, size))
throw std::bad_alloc();
#endif
return ptr;
}
static void Aligned_Free(void* ptr)
{
if (ptr)
{
#if defined _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
}
RenderMemory::MemoryBlock::MemoryBlock() : Data(static_cast<uint8_t*>(Aligned_Alloc(16, BlockSize))), Position(0)
{
}
RenderMemory::MemoryBlock::~MemoryBlock()
{
Aligned_Free(Data);
}

View file

@ -29,8 +29,8 @@ private:
struct MemoryBlock
{
MemoryBlock() : Data(new uint8_t[BlockSize]), Position(0) { }
~MemoryBlock() { delete[] Data; }
MemoryBlock();
~MemoryBlock();
MemoryBlock(const MemoryBlock &) = delete;
MemoryBlock &operator=(const MemoryBlock &) = delete;

View file

@ -55,7 +55,6 @@
#include "templates.h"
#include "r_utility.h"
#include "swrenderer/r_renderer.h"
#include "atterm.h"
#include <atomic>
FDynamicColormap NormalLight;
@ -452,7 +451,7 @@ static void InitBoomColormaps ()
//
//==========================================================================
static void DeinitSWColorMaps()
void DeinitSWColorMaps()
{
FreeSpecialLights();
if (realcolormaps.Maps != nullptr)
@ -475,8 +474,6 @@ static void DeinitSWColorMaps()
void InitSWColorMaps()
{
DeinitSWColorMaps();
atterm(DeinitSWColorMaps);
InitBoomColormaps();
NormalLight.Color = PalEntry (255, 255, 255);
NormalLight.Fade = 0;

View file

@ -30,6 +30,7 @@ extern FDynamicColormap FullNormalLight;
extern bool NormalLightHasFixedLights;
extern TArray<FSWColormap> SpecialSWColormaps;
void DeinitSWColorMaps();
void InitSWColorMaps();
FDynamicColormap *GetSpecialLights (PalEntry lightcolor, PalEntry fadecolor, int desaturate);
void SetDefaultColormap (const char *name);

View file

@ -205,7 +205,10 @@ namespace swrenderer
int shade = LightVisibility::LightLevelToShade(lightlevel, foggy, thread->Viewport.get());
if (psprite)
{
visibility = 0;
shade -= 24 * FRACUNIT;
}
BaseColormap = basecolormap;
ColormapNum = GETPALOOKUP(visibility, shade);

View file

@ -35,10 +35,10 @@ namespace swrenderer
class RenderThread;
struct VisiblePlane;
// The 3072 below is just an arbitrary value picked to avoid
// The 32 below is just an arbitrary value picked to avoid
// drawing lines the player is too close to that would overflow
// the texture calculations.
#define TOO_CLOSE_Z (3072.0 / (1<<12))
#define TOO_CLOSE_Z (32.0 / (1 << 12))
enum class WaterFakeSide
{

View file

@ -206,20 +206,15 @@ 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->drawsegclip.CurrentPortalUniq = CurrentPortalUniq;
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;
draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(pl->right - pl->left);
draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(pl->right - pl->left);
draw_segment->maskedtexturecol = nullptr;
draw_segment->swall = nullptr;
draw_segment->bFogBoundary = false;
draw_segment->drawsegclip.silhouette = SIL_BOTH;
draw_segment->drawsegclip.SetTopClip(Thread, pl->left, pl->right, ceilingclip);
draw_segment->drawsegclip.SetBottomClip(Thread, pl->left, pl->right, floorclip);
draw_segment->curline = nullptr;
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);
Thread->OpaquePass->RenderScene(Thread->Viewport->Level());

View file

@ -114,7 +114,7 @@ namespace swrenderer
for (DrawSegment *seg : portaldrawsegs)
{
// ignore segs from other portals
if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq)
if (seg->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq)
continue;
// (all checks that are already done in R_CollectPortals have been removed for performance reasons.)
@ -154,20 +154,16 @@ namespace swrenderer
DrawSegment *ds = drawseglist->Segment(index);
// [ZZ] the same as above
if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq)
if (ds->drawsegclip.CurrentPortalUniq != renderportal->CurrentPortalUniq)
continue;
if (ds->maskedtexturecol || ds->bFogBoundary)
if (ds->HasTranslucentMidTexture() || ds->Has3DFloorWalls() || ds->HasFogBoundary())
{
RenderDrawSegment renderer(Thread);
renderer.Render(ds, ds->x1, ds->x2, clip3DFloor);
if (renew && ds->bFogBoundary) // don't draw fogboundary again
ds->bFogBoundary = false;
if (renew && ds->sprclipped)
{
memcpy(ds->sprtopclip, ds->bkup, (ds->x2 - ds->x1) * sizeof(short));
ds->sprclipped = false;
}
if (renew)
ds->drawsegclip.SetRangeUndrawn(ds->x1, ds->x2);
}
}
}

View file

@ -131,10 +131,10 @@ namespace swrenderer
{
ds = Segment(groupIndex);
if (ds->silhouette & SIL_BOTTOM)
if (ds->drawsegclip.silhouette & SIL_BOTTOM)
{
short *clip1 = clipbottom + ds->x1;
const short *clip2 = ds->sprbottomclip;
const short *clip2 = ds->drawsegclip.sprbottomclip + ds->x1;
int i = ds->x2 - ds->x1;
do
{
@ -145,10 +145,10 @@ namespace swrenderer
} while (--i);
}
if (ds->silhouette & SIL_TOP)
if (ds->drawsegclip.silhouette & SIL_TOP)
{
short *clip1 = cliptop + ds->x1;
const short *clip2 = ds->sprtopclip;
const short *clip2 = ds->drawsegclip.sprtopclip + ds->x1;
int i = ds->x2 - ds->x1;
do
{
@ -168,4 +168,58 @@ namespace swrenderer
SegmentGroups.Push(group);
}
}
/////////////////////////////////////////////////////////////////////////
void DrawSegmentClipInfo::SetTopClip(RenderThread* thread, int x1, int x2, const short* ceilingclip)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
memcpy(clip, ceilingclip + x1, (x2 - x1) * sizeof(short));
sprtopclip = clip - x1;
}
void DrawSegmentClipInfo::SetTopClip(RenderThread* thread, int x1, int x2, short value)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
for (int i = 0; i < x2 - x1; i++)
clip[i] = value;
sprtopclip = clip - x1;
}
void DrawSegmentClipInfo::SetBottomClip(RenderThread* thread, int x1, int x2, const short* floorclip)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
memcpy(clip, floorclip + x1, (x2 - x1) * sizeof(short));
sprbottomclip = clip - x1;
}
void DrawSegmentClipInfo::SetBottomClip(RenderThread* thread, int x1, int x2, short value)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
for (int i = 0; i < x2 - x1; i++)
clip[i] = value;
sprbottomclip = clip - x1;
}
void DrawSegmentClipInfo::SetBackupClip(RenderThread* thread, int x1, int x2, const short* ceilingclip)
{
short* clip = thread->FrameMemory->AllocMemory<short>(x2 - x1);
memcpy(clip, ceilingclip + x1, (x2 - x1) * sizeof(short));
bkup = clip - x1;
}
void DrawSegmentClipInfo::SetRangeDrawn(int x1, int x2)
{
sprclipped = true;
fillshort(const_cast<short*>(sprtopclip) + x1, x2 - x1, viewheight);
}
void DrawSegmentClipInfo::SetRangeUndrawn(int x1, int x2)
{
if (sprclipped)
{
sprclipped = false;
memcpy(const_cast<short*>(sprtopclip) + x1, bkup + x1, (x2 - x1) * sizeof(short));
}
}
}

View file

@ -25,42 +25,52 @@
namespace swrenderer
{
struct DrawSegmentClipInfo
{
void SetTopClip(RenderThread* thread, int x1, int x2, const short* ceilingclip);
void SetTopClip(RenderThread* thread, int x1, int x2, short value);
void SetBottomClip(RenderThread* thread, int x1, int x2, const short* floorclip);
void SetBottomClip(RenderThread* thread, int x1, int x2, short value);
void SetBackupClip(RenderThread* thread, int x1, int x2, const short* ceilingclip);
void SetRangeDrawn(int x1, int x2);
void SetRangeUndrawn(int x1, int x2);
uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both
int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping.
int SubsectorDepth;
// Pointers to lists for sprite clipping, all three adjusted so [x1] is first value.
const short* sprtopclip = nullptr;
const short* sprbottomclip = nullptr;
private:
bool sprclipped = false; // True if draw segment was used for clipping sprites
const short* bkup = nullptr;
};
struct DrawSegment
{
seg_t *curline;
float light, lightstep;
float iscale, iscalestep;
short x1, x2; // Same as sx1 and sx2, but clipped to the drawseg
short x1, x2;
FWallCoords WallC;
float yscale;
uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both
bool bFogBoundary = false;
ProjectedWallTexcoords texcoords;
// Pointers to lists for sprite clipping, all three adjusted so [x1] is first value.
short *sprtopclip = nullptr;
short *sprbottomclip = nullptr;
fixed_t *maskedtexturecol = nullptr;
float *swall = nullptr;
short *bkup = nullptr; // sprtopclip backup, for mid and fake textures
bool sprclipped = false; // True if draw segment was used for clipping sprites
FWallTmapVals tmapvals;
int CurrentPortalUniq = 0; // [ZZ] to identify the portal that this drawseg is in. used for sprite clipping.
DrawSegmentClipInfo drawsegclip;
int SubsectorDepth;
bool HasFogBoundary() const { return (flags & 8) != 0; }
bool Has3DFloorWalls() const { return (flags & 3) != 0; }
bool Has3DFloorFrontSectorWalls() const { return (flags & 2) != 0; }
bool Has3DFloorBackSectorWalls() const { return (flags & 1) != 0; }
bool HasTranslucentMidTexture() const { return (flags & 4) != 0; }
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; }
void SetHasFogBoundary() { flags |= 8; }
void SetHas3DFloorFrontSectorWalls() { flags |= 2; }
void SetHas3DFloorBackSectorWalls() { flags |= 1; }
void SetHasTranslucentMidTexture() { flags |= 4; }
private:
uint8_t b3DFloorBoundary = 0; // 1=backsector, 2=frontsector, 4=midtexture
int flags = 0; // 1=backsector, 2=frontsector, 4=midtexture, 8=fogboundary
};
struct DrawSegmentGroup

View file

@ -52,8 +52,8 @@ namespace swrenderer
ceilingclip = thread->FrameMemory->AllocMemory<short>(len);
floorclip = thread->FrameMemory->AllocMemory<short>(len);
memcpy(ceilingclip, topclip, len * sizeof(short));
memcpy(floorclip, bottomclip, len * sizeof(short));
memcpy(ceilingclip, topclip + x1, len * sizeof(short));
memcpy(floorclip, bottomclip + x1, len * sizeof(short));
for (int i = 0; i < x2 - x1; i++)
{

View file

@ -68,7 +68,7 @@ FSoftwareTexture::FSoftwareTexture(FTexture *tex)
auto info = tex->CreateTexBuffer(0, CTF_CheckOnly| mBufferFlags);
mPhysicalWidth = info.mWidth;
mPhysicalHeight = info.mHeight;
mPhysicalScale = mPhysicalWidth / tex->Width;
mPhysicalScale = tex->Width > 0? mPhysicalWidth / tex->Width : mPhysicalWidth;
CalcBitSize();
}

View file

@ -164,6 +164,7 @@ public:
const uint32_t *GetPixelsBgra() override;
const uint8_t *GetPixels(int style) override;
bool CheckModified (int which) override;
void GenerateBgraMipmapsFast();
private:

View file

@ -40,6 +40,8 @@
#include "warpbuffer.h"
#include "v_video.h"
EXTERN_CVAR(Int, gl_texture_hqresizemult)
EXTERN_CVAR(Int, gl_texture_hqresizemode)
FWarpTexture::FWarpTexture (FTexture *source, int warptype)
: FSoftwareTexture (source)
@ -57,11 +59,17 @@ bool FWarpTexture::CheckModified (int style)
const uint32_t *FWarpTexture::GetPixelsBgra()
{
uint64_t time = screen->FrameTime;
uint64_t resizeMult = gl_texture_hqresizemult;
if (time != GenTime[2])
{
if (gl_texture_hqresizemode == 0 || gl_texture_hqresizemult < 1)
resizeMult = 1;
auto otherpix = FSoftwareTexture::GetPixelsBgra();
WarpedPixelsRgba.Resize(GetWidth() * GetHeight());
WarpBuffer(WarpedPixelsRgba.Data(), otherpix, GetWidth(), GetHeight(), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped);
WarpedPixelsRgba.Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult * 4 / 3 + 1));
WarpBuffer(WarpedPixelsRgba.Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped);
GenerateBgraMipmapsFast();
FreeAllSpans();
GenTime[2] = time;
}
@ -72,11 +80,16 @@ const uint32_t *FWarpTexture::GetPixelsBgra()
const uint8_t *FWarpTexture::GetPixels(int index)
{
uint64_t time = screen->FrameTime;
uint64_t resizeMult = gl_texture_hqresizemult;
if (time != GenTime[index])
{
if (gl_texture_hqresizemode == 0 || gl_texture_hqresizemult < 1)
resizeMult = 1;
const uint8_t *otherpix = FSoftwareTexture::GetPixels(index);
WarpedPixels[index].Resize(GetWidth() * GetHeight());
WarpBuffer(WarpedPixels[index].Data(), otherpix, GetWidth(), GetHeight(), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped);
WarpedPixels[index].Resize(unsigned(GetWidth() * GetHeight() * resizeMult * resizeMult));
WarpBuffer(WarpedPixels[index].Data(), otherpix, int(GetWidth() * resizeMult), int(GetHeight() * resizeMult), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped);
FreeAllSpans();
GenTime[index] = time;
}
@ -104,3 +117,44 @@ int FWarpTexture::NextPo2 (int v)
v |= v >> 16;
return ++v;
}
void FWarpTexture::GenerateBgraMipmapsFast()
{
uint32_t *src = WarpedPixelsRgba.Data();
uint32_t *dest = src + GetPhysicalWidth() * GetPhysicalHeight();
int levels = MipmapLevels();
for (int i = 1; i < levels; i++)
{
int srcw = MAX(GetPhysicalWidth() >> (i - 1), 1);
int srch = MAX(GetPhysicalHeight() >> (i - 1), 1);
int w = MAX(GetPhysicalWidth() >> i, 1);
int h = MAX(GetPhysicalHeight() >> i, 1);
for (int x = 0; x < w; x++)
{
int sx0 = x * 2;
int sx1 = MIN((x + 1) * 2, srcw - 1);
for (int y = 0; y < h; y++)
{
int sy0 = y * 2;
int sy1 = MIN((y + 1) * 2, srch - 1);
uint32_t src00 = src[sy0 + sx0 * srch];
uint32_t src01 = src[sy1 + sx0 * srch];
uint32_t src10 = src[sy0 + sx1 * srch];
uint32_t src11 = src[sy1 + sx1 * srch];
uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4;
uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4;
uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4;
uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4;
dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue;
}
}
src = dest;
dest += w * h;
}
}

View file

@ -53,24 +53,20 @@
#include "swrenderer/r_memory.h"
#include "swrenderer/r_renderthread.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
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)
void RenderDecal::RenderDecals(RenderThread *thread, DrawSegment *draw_segment, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass)
{
for (DBaseDecal *decal = sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
{
Render(thread, sidedef, decal, draw_segment, curline, light, walltop, wallbottom, drawsegPass);
Render(thread, decal, draw_segment, curline, lightsector, walltop, wallbottom, 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)
void RenderDecal::Render(RenderThread *thread, DBaseDecal *decal, DrawSegment *clipper, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass)
{
DVector2 decal_left, decal_right, decal_pos;
int x1, x2;
double yscale;
uint8_t flipx;
double zpos;
int needrepeat = 0;
sector_t *back;
@ -127,7 +123,6 @@ namespace swrenderer
}
FTexture *tex = TexMan.GetPalettedTexture(decal->PicNum, true);
flipx = (uint8_t)(decal->RenderFlags & RF_XFLIP);
if (tex == NULL || !tex->isValid())
{
@ -145,20 +140,16 @@ namespace swrenderer
edge_left *= decal->ScaleX;
double dcx, dcy;
decal->GetXY(wall, dcx, dcy);
decal->GetXY(curline->sidedef, dcx, dcy);
decal_pos = { dcx, dcy };
DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit();
float maskedScaleY;
decal_left = decal_pos - edge_left * angvec - thread->Viewport->viewpoint.Pos;
decal_right = decal_pos + edge_right * angvec - thread->Viewport->viewpoint.Pos;
CameraLight *cameraLight;
double texturemid;
FWallCoords WallC;
if (WallC.Init(thread, decal_left, decal_right, TOO_CLOSE_Z))
if (WallC.Init(thread, decal_left, decal_right))
return;
x1 = WallC.sx1;
@ -167,9 +158,6 @@ namespace swrenderer
if (x1 >= clipper->x2 || x2 <= clipper->x1)
return;
FWallTmapVals WallT;
WallT.InitFromWallCoords(thread, &WallC);
if (drawsegPass)
{
uint32_t clipMode = decal->RenderFlags & RF_CLIPMASK;
@ -230,9 +218,6 @@ namespace swrenderer
}
}
yscale = decal->ScaleY;
texturemid = WallSpriteTile->GetTopOffset(0) + (zpos - thread->Viewport->viewpoint.Pos.Z) / yscale;
// Clip sprite to drawseg
x1 = MAX<int>(clipper->x1, x1);
x2 = MIN<int>(clipper->x2, x2);
@ -241,21 +226,10 @@ namespace swrenderer
return;
}
ProjectedWallTexcoords walltexcoords;
walltexcoords.Project(thread->Viewport.get(), WallSpriteTile->GetWidth(), x1, x2, WallT);
if (flipx)
{
int i;
int right = (WallSpriteTile->GetWidth() << FRACBITS) - 1;
for (i = x1; i < x2; i++)
{
walltexcoords.UPos[i] = right - walltexcoords.UPos[i];
}
}
// Prepare lighting
ProjectedWallLight light;
light.SetColormap(lightsector, curline);
light.SetLightLeft(thread, WallC);
usecolormap = light.GetBaseColormap();
// Decals that are added to the scene must fade to black.
@ -264,48 +238,19 @@ namespace swrenderer
usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
}
float lightpos = light.GetLightPos(x1);
cameraLight = CameraLight::Instance();
// Draw it
bool sprflipvert;
if (decal->RenderFlags & RF_YFLIP)
{
sprflipvert = true;
yscale = -yscale;
texturemid -= WallSpriteTile->GetHeight();
}
else
{
sprflipvert = false;
}
maskedScaleY = float(1 / yscale);
do
{
int x = x1;
ColormapLight cmlight;
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);
bool calclighting = cameraLight->FixedLightLevel() < 0 && !cameraLight->FixedColormap();
if (visible)
{
thread->PrepareTexture(WallSpriteTile, decal->RenderStyle);
while (x < x2)
{
if (calclighting)
{ // calculate lighting
drawerargs.SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get());
}
DrawColumn(thread, drawerargs, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle);
lightpos += light.GetLightStep();
x++;
}
drawerargs.DrawMasked(thread, zpos + WallSpriteTile->GetTopOffset(0) * decal->ScaleY, decal->ScaleY, decal->RenderFlags & RF_XFLIP, decal->RenderFlags & RF_YFLIP, WallC, light, WallSpriteTile, mfloorclip, mceilingclip, decal->RenderStyle);
}
// If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will
@ -315,19 +260,4 @@ namespace swrenderer
mfloorclip = wallbottom;
} while (needrepeat--);
}
void RenderDecal::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)
{
auto viewport = thread->Viewport.get();
float iscale = walltexcoords.VStep[x] * maskedScaleY;
double spryscale = 1 / iscale;
double sprtopscreen;
if (sprflipvert)
sprtopscreen = viewport->CenterY + texturemid * spryscale;
else
sprtopscreen = viewport->CenterY - texturemid * spryscale;
drawerargs.DrawMaskedColumn(thread, x, FLOAT2FIXED(iscale), WallSpriteTile, walltexcoords.UPos[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, style);
}
}

View file

@ -12,10 +12,9 @@ namespace swrenderer
class RenderDecal
{
public:
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);
static void RenderDecals(RenderThread *thread, DrawSegment *draw_segment, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass);
private:
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);
static void Render(RenderThread *thread, DBaseDecal *first, DrawSegment *clipper, seg_t *curline, const sector_t* lightsector, const short *walltop, const short *wallbottom, bool drawsegPass);
};
}

View file

@ -298,7 +298,7 @@ namespace swrenderer
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)
if (ds->drawsegclip.CurrentPortalUniq == CurrentPortalUniq)
{
RenderDrawSegment renderer(thread);
renderer.Render(ds, MAX<int>(ds->x1, x1), MIN<int>(ds->x2, x2), clip3DFloor);

View file

@ -70,6 +70,8 @@ EXTERN_CVAR(Bool, r_drawplayersprites)
EXTERN_CVAR(Bool, r_deathcamera)
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
CVAR(Bool, r_noaccel, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
namespace swrenderer
{
RenderPlayerSprites::RenderPlayerSprites(RenderThread *thread)
@ -325,7 +327,7 @@ namespace swrenderer
if (vis.x1 > x1)
vis.startfrac += vis.xiscale*(vis.x1 - x1);
noaccel = false;
noaccel = r_noaccel;
FDynamicColormap *colormap_to_use = nullptr;
if (pspr->GetID() < PSP_TARGETCENTER)
{
@ -489,46 +491,23 @@ namespace swrenderer
void NoAccelPlayerSprite::Render(RenderThread *thread)
{
if (xscale == 0 || fabs(yscale) < (1.0f / 32000.0f))
{ // scaled to 0; can't see
return;
}
SpriteDrawerArgs drawerargs;
bool visible = drawerargs.SetStyle(thread->Viewport.get(), RenderStyle, Alpha, Translation, FillColor, Light);
if (!visible)
return;
double spryscale = yscale;
bool sprflipvert = false;
fixed_t iscale = FLOAT2FIXED(1 / yscale);
auto viewport = thread->Viewport.get();
double sprtopscreen;
double centerY = viewheight / 2;
double y1, y2;
if (renderflags & RF_YFLIP)
{
sprflipvert = true;
spryscale = -spryscale;
iscale = -iscale;
sprtopscreen = viewport->CenterY + (texturemid - pic->GetHeight()) * spryscale;
y1 = centerY + (texturemid - pic->GetHeight()) * (-yscale);
y2 = y1 + pic->GetHeight() * (-yscale);
}
else
{
sprflipvert = false;
sprtopscreen = viewport->CenterY - texturemid * spryscale;
}
// clip to screen bounds
short *mfloorclip = screenheightarray;
short *mceilingclip = zeroarray;
fixed_t frac = startfrac;
thread->PrepareTexture(pic, RenderStyle);
for (int x = x1; x < x2; x++)
{
drawerargs.DrawMaskedColumn(thread, x, iscale, pic, frac + xiscale / 2, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, RenderStyle, false);
frac += xiscale;
y1 = centerY - texturemid * yscale;
y2 = y1 + pic->GetHeight() * yscale;
}
drawerargs.DrawMasked2D(thread, x1, x2, y1, y2, pic, RenderStyle);
}
}

View file

@ -67,7 +67,6 @@
#include "a_dynlight.h"
#include "r_data/r_vanillatrans.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
EXTERN_CVAR(Bool, gl_light_sprites)
namespace swrenderer
@ -75,32 +74,20 @@ namespace swrenderer
void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ttex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap)
{
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
// transform the origin point
double tr_x = pos.X - thread->Viewport->viewpoint.Pos.X;
double tr_y = pos.Y - thread->Viewport->viewpoint.Pos.Y;
double tz = tr_x * thread->Viewport->viewpoint.TanCos + tr_y * thread->Viewport->viewpoint.TanSin;
auto viewport = thread->Viewport.get();
// thing is behind view plane?
if (tz < MINZ)
const double thingxscalemul = spriteScale.X / tex->GetScale().X;
// Calculate billboard line for the sprite
DVector2 dir = { viewport->viewpoint.Sin, -viewport->viewpoint.Cos };
DVector2 pt1 = pos.XY() - viewport->viewpoint.Pos.XY() - dir * (((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul);
DVector2 pt2 = pt1 + dir * (tex->GetWidth() * thingxscalemul);
FWallCoords wallc;
if (wallc.Init(thread, pt1, pt2))
return;
double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos;
// [RH] Flip for mirrors
RenderPortal *renderportal = thread->Portal.get();
if (renderportal->MirrorFlags & RF_XFLIP)
{
tx = -tx;
}
//tx2 = tx >> 4;
// too far off the side?
if (fabs(tx / 64) > fabs(tz))
{
return;
}
// [RH] Added scaling
int scaled_to = tex->GetScaledTopOffsetSW();
int scaled_bo = scaled_to - tex->GetScaledHeight();
@ -134,86 +121,41 @@ namespace swrenderer
}
}
auto viewport = thread->Viewport.get();
double xscale = viewport->CenterX / tz;
// [RH] Reject sprites that are off the top or bottom of the screen
if (viewport->globaluclip * tz > viewport->viewpoint.Pos.Z - gzb || viewport->globaldclip * tz < viewport->viewpoint.Pos.Z - gzt)
{
return;
}
// [RH] Flip for mirrors
auto renderportal = thread->Portal.get();
renderflags ^= renderportal->MirrorFlags & RF_XFLIP;
// [SP] SpriteFlip
if (thing->renderflags & RF_SPRITEFLIP)
renderflags ^= RF_XFLIP;
// calculate edges of the shape
const double thingxscalemul = spriteScale.X / tex->GetScale().X;
tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul;
double dtx1 = tx * xscale;
int x1 = viewport->viewwindow.centerx + xs_RoundToInt(dtx1);
// off the right side?
if (x1 >= renderportal->WindowRight)
return;
tx += tex->GetWidth() * thingxscalemul;
int x2 = viewport->viewwindow.centerx + xs_RoundToInt(tx * xscale);
// off the left side or too small?
if ((x2 < renderportal->WindowLeft || x2 <= x1))
return;
xscale = spriteScale.X * xscale / tex->GetScale().X;
fixed_t iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases
double yscale = spriteScale.Y / tex->GetScale().Y;
// store information in a vissprite
RenderSprite *vis = thread->FrameMemory->NewObject<RenderSprite>();
vis->wallc = wallc;
vis->SpriteScale = yscale;
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
vis->xscale = FLOAT2FIXED(xscale);
vis->yscale = float(viewport->InvZtoScale * yscale / tz);
vis->idepth = float(1 / tz);
vis->yscale = float(viewport->InvZtoScale * yscale / wallc.sz1);
vis->idepth = float(1 / wallc.sz1);
vis->floorclip = thing->Floorclip / yscale;
vis->texturemid = tex->GetTopOffsetSW() - (viewport->viewpoint.Pos.Z - pos.Z + thing->Floorclip) / yscale;
vis->x1 = x1 < renderportal->WindowLeft ? renderportal->WindowLeft : x1;
vis->x2 = x2 > renderportal->WindowRight ? renderportal->WindowRight : x2;
//vis->Angle = thing->Angles.Yaw;
if (renderflags & RF_XFLIP)
{
vis->startfrac = (tex->GetWidth() << FRACBITS) - 1;
vis->xiscale = -iscale;
}
else
{
vis->startfrac = 0;
vis->xiscale = iscale;
}
vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - viewport->viewwindow.centerx + 0.5 - dtx1));
// killough 3/27/98: save sector for special clipping later
vis->x1 = wallc.sx1 < renderportal->WindowLeft ? renderportal->WindowLeft : wallc.sx1;
vis->x2 = wallc.sx2 > renderportal->WindowRight ? renderportal->WindowRight : wallc.sx2;
vis->heightsec = heightsec;
vis->sector = thing->Sector;
vis->section = thing->section;
vis->depth = (float)tz;
vis->depth = (float)wallc.sz1;
vis->gpos = { (float)pos.X, (float)pos.Y, (float)pos.Z };
vis->gzb = (float)gzb; // [RH] use gzb, not thing->z
vis->gzt = (float)gzt; // killough 3/27/98
vis->gzb = (float)gzb;
vis->gzt = (float)gzt;
vis->deltax = float(pos.X - viewport->viewpoint.Pos.X);
vis->deltay = float(pos.Y - viewport->viewpoint.Pos.Y);
vis->renderflags = renderflags;
if (thing->flags5 & MF5_BRIGHT)
vis->renderflags |= RF_FULLBRIGHT; // kg3D
vis->renderflags |= RF_FULLBRIGHT;
vis->RenderStyle = thing->RenderStyle;
if (r_UseVanillaTransparency)
{
@ -226,11 +168,7 @@ namespace swrenderer
vis->Alpha = float(thing->Alpha);
vis->fakefloor = fakefloor;
vis->fakeceiling = fakeceiling;
//vis->bInMirror = renderportal->MirrorFlags & RF_XFLIP;
//vis->bSplitSprite = false;
vis->pic = tex;
vis->foggy = foggy;
// The software renderer cannot invert the source without inverting the overlay
@ -300,74 +238,36 @@ namespace swrenderer
vis->dynlightcolor = 0;
}
vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false);
vis->Light.SetColormap(thread, wallc.sz1, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false);
thread->SpriteList->Push(vis);
}
void RenderSprite::Render(RenderThread *thread, short *mfloorclip, short *mceilingclip, int, int, Fake3DTranslucent)
{
auto vis = this;
fixed_t frac;
FSoftwareTexture *tex;
int x2;
fixed_t xiscale;
double spryscale, sprtopscreen;
bool sprflipvert;
if (vis->xscale == 0 || fabs(vis->yscale) < (1.0f / 32000.0f))
{ // scaled to 0; can't see
return;
}
SpriteDrawerArgs drawerargs;
drawerargs.SetDynamicLight(dynlightcolor);
bool visible = drawerargs.SetStyle(thread->Viewport.get(), vis->RenderStyle, vis->Alpha, vis->Translation, vis->FillColor, vis->Light);
bool visible = drawerargs.SetStyle(thread->Viewport.get(), RenderStyle, Alpha, Translation, FillColor, Light);
if (visible)
{
tex = vis->pic;
spryscale = vis->yscale;
sprflipvert = false;
fixed_t iscale = FLOAT2FIXED(1 / vis->yscale);
frac = vis->startfrac;
xiscale = vis->xiscale;
double texturemid = vis->texturemid;
auto viewport = thread->Viewport.get();
if (vis->renderflags & RF_YFLIP)
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
short portalfloorclip[MAXWIDTH];
int x2 = wallc.sx2;
for (int x = wallc.sx1; x < x2; x++)
{
sprflipvert = true;
spryscale = -spryscale;
iscale = -iscale;
texturemid -= vis->pic->GetHeight();
sprtopscreen = viewport->CenterY + texturemid * spryscale;
}
else
{
sprflipvert = false;
sprtopscreen = viewport->CenterY - texturemid * spryscale;
if (translucentPass->ClipSpriteColumnWithPortals(x, this))
portalfloorclip[x] = mceilingclip[x];
else
portalfloorclip[x] = mfloorclip[x];
}
int x = vis->x1;
x2 = vis->x2;
thread->PrepareTexture(pic, RenderStyle);
if (x < x2)
{
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
ProjectedWallLight mlight;
mlight.SetSpriteLight();
thread->PrepareTexture(tex, vis->RenderStyle);
while (x < x2)
{
if (!translucentPass->ClipSpriteColumnWithPortals(x, vis))
drawerargs.DrawMaskedColumn(thread, x, iscale, tex, frac, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, vis->RenderStyle, false);
x++;
frac += xiscale;
}
}
drawerargs.SetBaseColormap(Light.BaseColormap);
drawerargs.DrawMasked(thread, gzt - floorclip, SpriteScale, renderflags & RF_XFLIP, renderflags & RF_YFLIP, wallc, mlight, pic, portalfloorclip, mceilingclip, RenderStyle);
}
}
}

View file

@ -13,9 +13,8 @@ namespace swrenderer
void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override;
private:
fixed_t xscale = 0;
fixed_t startfrac = 0; // horizontal position of x1
fixed_t xiscale = 0; // negative if flipped
FWallCoords wallc;
double SpriteScale;
uint32_t Translation = 0;
uint32_t FillColor = 0;

View file

@ -59,7 +59,7 @@ namespace swrenderer
for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++)
{
DrawSegment *ds = segmentlist->TranslucentSegment(index);
if (ds->SubsectorDepth >= SubsectorDepth && ds->CurrentPortalUniq == renderportal->CurrentPortalUniq)
if (ds->drawsegclip.SubsectorDepth >= SubsectorDepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
{
int r1 = MAX<int>(ds->x1, 0);
int r2 = MIN<int>(ds->x2, viewwidth - 1);
@ -321,7 +321,7 @@ namespace swrenderer
for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++)
{
DrawSegment *ds = segmentlist->TranslucentSegment(index);
if (ds->SubsectorDepth >= subsectordepth && ds->CurrentPortalUniq == renderportal->CurrentPortalUniq)
if (ds->drawsegclip.SubsectorDepth >= subsectordepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
{
int r1 = MAX<int>(ds->x1, 0);
int r2 = MIN<int>(ds->x2, viewwidth - 1);
@ -350,7 +350,7 @@ namespace swrenderer
(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)
if (ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
{
int r1 = MAX<int>(ds->x1, x1);
int r2 = MIN<int>(ds->x2, x2);
@ -405,9 +405,7 @@ namespace swrenderer
DrawSegment *ds = segmentlist->Segment(index);
// determine if the drawseg obscures the sprite
if (ds->x1 >= x2 || ds->x2 <= x1 ||
(!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == nullptr &&
!ds->bFogBoundary))
if (ds->x1 >= x2 || ds->x2 <= x1 || (!(ds->drawsegclip.silhouette & SIL_BOTH) && !ds->Has3DFloorWalls() && !ds->HasTranslucentMidTexture() && !ds->HasFogBoundary()))
{
// does not cover sprite
continue;
@ -433,10 +431,10 @@ namespace swrenderer
// [RH] Optimized further (at least for VC++;
// other compilers should be at least as good as before)
if (ds->silhouette & SIL_BOTTOM) //bottom sil
if (ds->drawsegclip.silhouette & SIL_BOTTOM) //bottom sil
{
short *clip1 = clipbot + r1;
const short *clip2 = ds->sprbottomclip + r1 - ds->x1;
const short *clip2 = ds->drawsegclip.sprbottomclip + r1;
int i = r2 - r1;
do
{
@ -447,10 +445,10 @@ namespace swrenderer
} while (--i);
}
if (ds->silhouette & SIL_TOP) // top sil
if (ds->drawsegclip.silhouette & SIL_TOP) // top sil
{
short *clip1 = cliptop + r1;
const short *clip2 = ds->sprtopclip + r1 - ds->x1;
const short *clip2 = ds->drawsegclip.sprtopclip + r1;
int i = r2 - r1;
do
{

View file

@ -67,8 +67,6 @@
#include "swrenderer/r_memory.h"
#include "swrenderer/r_renderthread.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
namespace swrenderer
{
void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ppic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap)
@ -96,7 +94,7 @@ namespace swrenderer
right.Y = left.Y + x2 * angsin;
// Is it off-screen?
if (wallc.Init(thread, left, right, TOO_CLOSE_Z))
if (wallc.Init(thread, left, right))
return;
RenderPortal *renderportal = thread->Portal.get();
@ -141,7 +139,19 @@ namespace swrenderer
vis->wallc = wallc;
vis->foggy = foggy;
vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, false, false, false, false, false);
if (vis->RenderStyle == LegacyRenderStyles[STYLE_Add] && basecolormap->Fade != 0)
{
basecolormap = GetSpecialLights(basecolormap->Color, 0, basecolormap->Desaturate);
}
bool fullbright = !vis->foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
bool invertcolormap = (vis->RenderStyle.Flags & STYLEF_InvertOverlay) != 0;
if (vis->RenderStyle.Flags & STYLEF_InvertSource)
invertcolormap = !invertcolormap;
bool fadeToBlack = (vis->RenderStyle.Flags & STYLEF_FadeToBlack) != 0;
vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false);
thread->SpriteList->Push(vis);
}
@ -150,33 +160,11 @@ namespace swrenderer
{
auto spr = this;
int x1, x2;
double iyscale;
bool sprflipvert;
x1 = MAX<int>(spr->x1, spr->wallc.sx1);
x2 = MIN<int>(spr->x2, spr->wallc.sx2);
int x1 = MAX<int>(spr->x1, spr->wallc.sx1);
int x2 = MIN<int>(spr->x2, spr->wallc.sx2);
if (x1 >= x2)
return;
FWallTmapVals WallT;
WallT.InitFromWallCoords(thread, &spr->wallc);
ProjectedWallTexcoords walltexcoords;
walltexcoords.Project(thread->Viewport.get(), spr->pic->GetWidth() << FRACBITS, x1, x2, WallT);
iyscale = 1 / spr->yscale;
double texturemid = (spr->gzt - thread->Viewport->viewpoint.Pos.Z) * iyscale;
if (spr->renderflags & RF_XFLIP)
{
int right = (spr->pic->GetWidth() << FRACBITS) - 1;
for (int i = x1; i < x2; i++)
{
walltexcoords.UPos[i] = right - walltexcoords.UPos[i];
}
}
// Prepare lighting
// Decals that are added to the scene must fade to black.
@ -192,57 +180,25 @@ namespace swrenderer
if (!visible)
return;
float lightleft = float(thread->Light->WallVis(spr->wallc.sz1, foggy));
float lightstep = float((thread->Light->WallVis(spr->wallc.sz2, foggy) - lightleft) / (spr->wallc.sx2 - spr->wallc.sx1));
float light = lightleft + (x1 - spr->wallc.sx1) * lightstep;
CameraLight *cameraLight = CameraLight::Instance();
bool calclighting = cameraLight->FixedLightLevel() < 0 && !cameraLight->FixedColormap();
ProjectedWallLight mlight;
mlight.SetLightLeft(thread, wallc);
// Draw it
auto WallSpriteTile = spr->pic;
if (spr->renderflags & RF_YFLIP)
{
sprflipvert = true;
iyscale = -iyscale;
texturemid -= spr->pic->GetHeight();
}
else
{
sprflipvert = false;
}
float maskedScaleY = (float)iyscale;
int x = x1;
RenderTranslucentPass *translucentPass = thread->TranslucentPass.get();
thread->PrepareTexture(WallSpriteTile, spr->RenderStyle);
while (x < x2)
RenderTranslucentPass* translucentPass = thread->TranslucentPass.get();
short floorclip[MAXWIDTH];
for (int x = x1; x < x2; x++)
{
if (calclighting)
{
drawerargs.SetLight(light, spr->sector->lightlevel, spr->foggy, thread->Viewport.get());
}
if (!translucentPass->ClipSpriteColumnWithPortals(x, spr))
DrawColumn(thread, drawerargs, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, spr->RenderStyle);
light += lightstep;
x++;
if (translucentPass->ClipSpriteColumnWithPortals(x, spr))
floorclip[x] = mceilingclip[x];
else
floorclip[x] = mfloorclip[x];
}
}
void RenderWallSprite::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)
{
auto viewport = thread->Viewport.get();
float iscale = walltexcoords.VStep[x] * maskedScaleY;
double spryscale = 1 / iscale;
double sprtopscreen;
if (sprflipvert)
sprtopscreen = viewport->CenterY + texturemid * spryscale;
else
sprtopscreen = viewport->CenterY - texturemid * spryscale;
drawerargs.DrawMaskedColumn(thread, x, FLOAT2FIXED(iscale), WallSpriteTile, walltexcoords.UPos[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, style);
drawerargs.SetBaseColormap(spr->Light.BaseColormap);
drawerargs.DrawMasked(thread, spr->gzt, spr->yscale, spr->renderflags & RF_XFLIP, spr->renderflags & RF_YFLIP, spr->wallc, mlight, WallSpriteTile, floorclip, mceilingclip, spr->RenderStyle);
}
}

View file

@ -17,8 +17,6 @@ namespace swrenderer
void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override;
private:
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);
FWallCoords wallc;
uint32_t Translation = 0;
uint32_t FillColor = 0;

View file

@ -38,6 +38,7 @@ namespace swrenderer
uint8_t *Colormap(RenderViewport *viewport) const;
uint8_t *TranslationMap() const { return mTranslation; }
FSWColormap* BaseColormap() const { return mBaseColormap; }
ShadeConstants ColormapConstants() const;
fixed_t Light() const { return LIGHTSCALE(mLight, mShade); }

View file

@ -43,206 +43,246 @@ namespace swrenderer
colfunc = &SWPixelFormatDrawers::DrawColumn;
}
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked)
void SpriteDrawerArgs::DrawMasked(RenderThread* thread, double topZ, double scale, bool flipX, bool flipY, const FWallCoords& WallC, const ProjectedWallLight& light, FSoftwareTexture* tex, const short* mfloorclip, const short* mceilingclip, FRenderStyle style)
{
if (x < thread->X1 || x >= thread->X2)
return;
col *= tex->GetPhysicalScale();
iscale *= tex->GetPhysicalScale();
spryscale /= tex->GetPhysicalScale();
auto viewport = thread->Viewport.get();
auto cameraLight = CameraLight::Instance();
// Handle the linear filtered version in a different function to reduce chances of merge conflicts from zdoom.
if (viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input) // To do: add support to R_DrawColumnHoriz_rgba
bool calclighting = cameraLight->FixedLightLevel() < 0 && !cameraLight->FixedColormap() && !light.IsSpriteLight();
float wpos = 1.0f / WallC.sz1;
float wstepX = (1.0f / WallC.sz2 - wpos) / (WallC.sx2 - WallC.sx1);
float upos, ustepX;
if (flipX)
{
DrawMaskedColumnBgra(thread, x, iscale, tex, col, spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip, unmasked);
return;
upos = (1.0f - WallC.tx1) / WallC.sz1;
ustepX = ((1.0f - WallC.tx2) / WallC.sz2 - upos) / (WallC.sx2 - WallC.sx1);
}
else
{
upos = WallC.tx1 / WallC.sz1;
ustepX = (WallC.tx2 / WallC.sz2 - upos) / (WallC.sx2 - WallC.sx1);
}
float iscale = 1.0f / scale;
if (flipY)
iscale = -iscale;
float vstepY = iscale / WallC.sz1 / (viewport->InvZtoScale / WallC.sz1);
wpos += wstepX * 0.5f;
upos += ustepX * 0.5f;
int x1 = WallC.sx1;
int x2 = WallC.sx2;
float centerY = thread->Viewport->CenterY;
topZ -= thread->Viewport->viewpoint.Pos.Z;
if (flipY)
topZ -= tex->GetHeight() * scale;
int texwidth = tex->GetPhysicalWidth();
int texheight = tex->GetPhysicalHeight();
float lightpos = light.GetLightPos(x1);
float lightstep = light.GetLightStep();
dc_viewport = viewport;
dc_x = x;
dc_iscale = iscale;
dc_textureheight = tex->GetPhysicalHeight();
dc_textureheight = texheight;
const FSoftwareTextureSpan *span;
const uint8_t *column;
if (viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input)
column = (const uint8_t *)tex->GetColumnBgra(col >> FRACBITS, &span);
else
column = tex->GetColumn(style, col >> FRACBITS, &span);
bool bgra = viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input;
FSoftwareTextureSpan unmaskedSpan[2];
if (unmasked)
for (int x = x1; x < x2; x++)
{
span = unmaskedSpan;
unmaskedSpan[0].TopOffset = 0;
unmaskedSpan[0].Length = tex->GetPhysicalHeight();
unmaskedSpan[1].TopOffset = 0;
unmaskedSpan[1].Length = 0;
}
int pixelsize = viewport->RenderTarget->IsBgra() ? 4 : 1;
while (span->Length != 0)
{
const int length = span->Length;
const int top = span->TopOffset;
// calculate unclipped screen coordinates for post
dc_yl = (int)(sprtopscreen + spryscale * top + 0.5);
dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1;
if (sprflipvert)
if (calclighting)
{
swapvalues(dc_yl, dc_yh);
SetLight(lightpos, light.GetLightLevel(), light.GetFoggy(), thread->Viewport.get());
}
if (dc_yh >= mfloorclip[dc_x])
{
dc_yh = mfloorclip[dc_x] - 1;
}
if (dc_yl < mceilingclip[dc_x])
{
dc_yl = mceilingclip[dc_x];
}
float w = 1.0f / wpos;
float y1 = centerY - topZ * wpos * viewport->InvZtoScale;
float u = upos * w;
float scaleU = ustepX * w;
float scaleV = vstepY * w;
if (dc_yl <= dc_yh)
{
dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5 - sprtopscreen) / spryscale);
dc_source = column;
dc_source2 = nullptr;
SetDest(viewport, dc_x, dc_yl);
dc_count = dc_yh - dc_yl + 1;
uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL);
uint32_t texelStepX = (uint32_t)(int64_t)(scaleU * 0x1'0000'0000LL);
uint32_t texelStepY = (uint32_t)(int64_t)(scaleV * 0x1'0000'0000LL);
fixed_t maxfrac = ((top + length) << FRACBITS) - 1;
dc_texturefrac = MAX(dc_texturefrac, 0);
dc_texturefrac = MIN(dc_texturefrac, maxfrac);
if (dc_iscale > 0)
dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale);
else if (dc_iscale < 0)
dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale));
DrawMaskedColumn(thread, x, y1, mceilingclip[x], mfloorclip[x], texelX, texelStepX, texelStepY, scaleV, flipY, tex, texwidth, texheight, bgra, style);
(thread->Drawers(dc_viewport)->*colfunc)(*this);
}
span++;
upos += ustepX;
wpos += wstepX;
lightpos += lightstep;
}
}
void SpriteDrawerArgs::DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked)
void SpriteDrawerArgs::DrawMasked2D(RenderThread* thread, double x0, double x1, double y0, double y1, FSoftwareTexture* tex, FRenderStyle style)
{
dc_viewport = thread->Viewport.get();
dc_x = x;
dc_iscale = iscale;
int sx0 = MAX((int)x0, 0);
int sx1 = MIN((int)x1, viewwidth);
int sy0 = MAX((int)y0, 0);
int sy1 = MIN((int)y1, viewheight);
// Normalize to 0-1 range:
double uv_stepd = FIXED2DBL(dc_iscale);
double v_step = uv_stepd / tex->GetPhysicalHeight();
if (sx0 >= sx1 || sy0 >= sy1)
return;
// Convert to uint32_t:
dc_iscale = (uint32_t)(v_step * (1 << 30));
float ustepX = 1.0f / (x1 - x0);
float vstepY = 1.0f / (y1 - y0);
float upos = ustepX * (sx0 + 0.5f - x0);
// Texture mipmap and filter selection:
fixed_t xoffset = col;
uint32_t texelStepX = (uint32_t)(int64_t)(ustepX * 0x1'0000'0000LL);
uint32_t texelStepY = (uint32_t)(int64_t)(vstepY * 0x1'0000'0000LL);
double xmagnitude = 1.0; // To do: pass this into R_DrawMaskedColumn
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;
bool bgra = thread->Viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input;
int texwidth = tex->GetPhysicalWidth();
int texheight = tex->GetPhysicalHeight();
int mipmap_offset = 0;
int mip_width = tex->GetPhysicalWidth();
int mip_height = tex->GetPhysicalHeight();
uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width);
if (r_mipmap && tex->Mipmapped() && mip_width > 1 && mip_height > 1)
vstepY *= texheight;
for (int x = sx0; x < sx1; x++)
{
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);
}
float u = upos;
uint32_t texelX = (uint32_t)(int64_t)((u - std::floor(u)) * 0x1'0000'0000LL);
DrawMaskedColumn(thread, x, sy0, sy0, sy1, texelX, texelStepX, texelStepY, vstepY, false, tex, texwidth, texheight, bgra, style);
upos += ustepX;
}
xoffset = (xpos >> FRACBITS) * mip_width;
}
const uint32_t *pixels = tex->GetPixelsBgra() + mipmap_offset;
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
if (filter_nearest)
void SpriteDrawerArgs::DrawMaskedColumn(RenderThread* thread, int x, int y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style)
{
const FSoftwareTextureSpan* span;
if (bgra)
{
xoffset = MAX(MIN(xoffset, (mip_width << FRACBITS) - 1), 0);
double xmagnitude = fabs(static_cast<int32_t>(texelStepX)* (1.0 / 0x1'0000'0000LL));
double ymagnitude = fabs(static_cast<int32_t>(texelStepY)* (1.0 / 0x1'0000'0000LL));
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 tx = xoffset >> FRACBITS;
dc_source = (uint8_t*)(pixels + tx * mip_height);
dc_source2 = nullptr;
dc_textureheight = mip_height;
dc_texturefracx = 0;
int mipmap_offset = 0;
int mip_width = texwidth;
int mip_height = texheight;
if (r_mipmap && tex->Mipmapped() && mip_width > 1 && mip_height > 1)
{
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);
}
}
const uint32_t* pixels = tex->GetPixelsBgra() + mipmap_offset;
fixed_t xoffset = (texelX >> 16)* mip_width;
bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter);
if (filter_nearest)
{
xoffset = MAX(MIN(xoffset, (mip_width << FRACBITS) - 1), 0);
int tx = xoffset >> FRACBITS;
dc_source = (uint8_t*)(pixels + tx * mip_height);
dc_source2 = nullptr;
dc_textureheight = mip_height;
dc_texturefracx = 0;
}
else
{
xoffset = MAX(MIN(xoffset - (FRACUNIT / 2), (mip_width << FRACBITS) - 1), 0);
int tx0 = xoffset >> FRACBITS;
int tx1 = MIN(tx0 + 1, mip_width - 1);
dc_source = (uint8_t*)(pixels + tx0 * mip_height);
dc_source2 = (uint8_t*)(pixels + tx1 * mip_height);
dc_textureheight = mip_height;
dc_texturefracx = (xoffset >> (FRACBITS - 4)) & 15;
}
int col = ((texelX >> 16)* texwidth) >> 16;
tex->GetColumnBgra(col, &span);
dc_iscale = (uint32_t)(int64_t)(scaleV / texheight * (1 << 30));
dc_x = x;
while (span->Length != 0)
{
const int length = span->Length;
const int top = span->TopOffset;
// calculate unclipped screen coordinates for post
dc_yl = (int)(y1 + top / scaleV + 0.5f);
dc_yh = (int)(y1 + (top + length) / scaleV + 0.5f);
if (flipY)
std::swap(dc_yl, dc_yh);
dc_yl = std::max(dc_yl, cliptop);
dc_yh = std::min(dc_yh, clipbottom);
if (dc_yl <= dc_yh)
{
double v = ((dc_yl + 0.5f - y1) * scaleV) / texheight;
dc_texturefrac = (uint32_t)(v * (1 << 30));
SetDest(dc_viewport, dc_x, dc_yl);
dc_count = dc_yh - dc_yl;
dc_yl--;
(thread->Drawers(dc_viewport)->*colfunc)(*this);
}
span++;
}
}
else
{
xoffset = MAX(MIN(xoffset - (FRACUNIT / 2), (mip_width << FRACBITS) - 1), 0);
int col = ((texelX >> 16)* texwidth) >> 16;
dc_source = tex->GetColumn(style, col, &span);
dc_source2 = nullptr;
int tx0 = xoffset >> FRACBITS;
int tx1 = MIN(tx0 + 1, mip_width - 1);
dc_source = (uint8_t*)(pixels + tx0 * mip_height);
dc_source2 = (uint8_t*)(pixels + tx1 * mip_height);
dc_textureheight = mip_height;
dc_texturefracx = (xoffset >> (FRACBITS - 4)) & 15;
}
dc_iscale = FLOAT2FIXED(scaleV);
dc_x = x;
// Grab the posts we need to draw
const FSoftwareTextureSpan *span;
tex->GetColumnBgra(col >> FRACBITS, &span);
FSoftwareTextureSpan unmaskedSpan[2];
if (unmasked)
{
span = unmaskedSpan;
unmaskedSpan[0].TopOffset = 0;
unmaskedSpan[0].Length = tex->GetPhysicalHeight();
unmaskedSpan[1].TopOffset = 0;
unmaskedSpan[1].Length = 0;
}
// Draw each span post
while (span->Length != 0)
{
const int length = span->Length;
const int top = span->TopOffset;
// calculate unclipped screen coordinates for post
dc_yl = (int)(sprtopscreen + spryscale * top + 0.5);
dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1;
if (sprflipvert)
while (span->Length != 0)
{
swapvalues(dc_yl, dc_yh);
}
const int length = span->Length;
const int top = span->TopOffset;
if (dc_yh >= mfloorclip[dc_x])
{
dc_yh = mfloorclip[dc_x] - 1;
}
if (dc_yl < mceilingclip[dc_x])
{
dc_yl = mceilingclip[dc_x];
}
// calculate unclipped screen coordinates for post
dc_yl = (int)(y1 + top / scaleV + 0.5f);
dc_yh = (int)(y1 + (top + length) / scaleV + 0.5f);
if (dc_yl <= dc_yh)
{
SetDest(dc_viewport, dc_x, dc_yl);
dc_count = dc_yh - dc_yl + 1;
if (flipY)
std::swap(dc_yl, dc_yh);
double v = ((dc_yl + 0.5 - sprtopscreen) / spryscale) / tex->GetPhysicalHeight();
dc_texturefrac = (uint32_t)(v * (1 << 30));
dc_yl = std::max(dc_yl, cliptop);
dc_yh = std::min(dc_yh, clipbottom);
(thread->Drawers(dc_viewport)->*colfunc)(*this);
if (dc_yl < dc_yh)
{
dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5f - y1) * scaleV);
SetDest(thread->Viewport.get(), dc_x, dc_yl);
dc_count = dc_yh - dc_yl;
dc_yl--;
fixed_t maxfrac = ((top + length) << FRACBITS) - 1;
dc_texturefrac = MAX(dc_texturefrac, 0);
dc_texturefrac = MIN(dc_texturefrac, maxfrac);
if (dc_iscale > 0)
dc_count = MIN(dc_count, (maxfrac - dc_texturefrac + dc_iscale - 1) / dc_iscale);
else if (dc_iscale < 0)
dc_count = MIN(dc_count, (dc_texturefrac - dc_iscale) / (-dc_iscale));
(thread->Drawers(dc_viewport)->*colfunc)(*this);
}
span++;
}
span++;
}
}
@ -502,35 +542,10 @@ namespace swrenderer
return SetStyle(viewport, style, FLOAT2FIXED(alpha), translation, color, light);
}
void SpriteDrawerArgs::FillColumn(RenderThread *thread)
{
thread->Drawers(dc_viewport)->FillColumn(*this);
}
void SpriteDrawerArgs::DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount)
{
SetDest(thread->Viewport.get(), 0, 0);
thread->Drawers(dc_viewport)->DrawVoxelBlocks(*this, blocks, blockcount);
#if 0
if (dc_viewport->RenderTarget->IsBgra())
{
double v = vPos / (double)voxelsCount / FRACUNIT;
double vstep = vStep / (double)voxelsCount / FRACUNIT;
dc_texturefrac = (int)(v * (1 << 30));
dc_iscale = (int)(vstep * (1 << 30));
}
else
{
dc_texturefrac = vPos;
dc_iscale = vStep;
}
dc_texturefracx = 0;
dc_source = voxels;
dc_source2 = 0;
dc_textureheight = voxelsCount;
(thread->Drawers(dc_viewport)->*colfunc)(*this);
#endif
}
void SpriteDrawerArgs::SetDest(RenderViewport *viewport, int x, int y)

View file

@ -9,6 +9,8 @@ struct FLightNode;
namespace swrenderer
{
class RenderThread;
struct FWallCoords;
class ProjectedWallLight;
class VoxelBlock
{
@ -28,13 +30,11 @@ namespace swrenderer
bool SetStyle(RenderViewport *viewport, FRenderStyle style, fixed_t alpha, int translation, uint32_t color, const ColormapLight &light);
bool SetStyle(RenderViewport *viewport, FRenderStyle style, float alpha, int translation, uint32_t color, const ColormapLight &light);
void SetDest(RenderViewport *viewport, int x, int y);
void SetCount(int count) { dc_count = count; }
void SetSolidColor(int color) { dc_color = color; dc_color_bgra = GPalette.BaseColors[color]; }
void SetDynamicLight(uint32_t color) { dynlightcolor = color; }
void DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *texture, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked = false);
void FillColumn(RenderThread *thread);
void DrawMasked(RenderThread* thread, double topZ, double scale, bool flipX, bool flipY, const FWallCoords& WallC, const ProjectedWallLight& light, FSoftwareTexture* texture, const short* mfloorclip, const short* mceilingclip, FRenderStyle style);
void DrawMasked2D(RenderThread *thread, double x0, double x1, double y0, double y1, FSoftwareTexture* texture, FRenderStyle style);
void DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount);
uint8_t *Dest() const { return dc_dest; }
@ -69,9 +69,13 @@ namespace swrenderer
RenderViewport *Viewport() const { return dc_viewport; }
private:
void DrawMaskedColumn(RenderThread* thread, int x, int y1, int cliptop, int clipbottom, uint32_t texelX, uint32_t texelStepX, uint32_t texelStepY, float scaleV, bool flipY, FSoftwareTexture* tex, int texwidth, int texheight, bool bgra, FRenderStyle style);
void SetDest(RenderViewport* viewport, int x, int y);
void SetCount(int count) { dc_count = count; }
bool SetBlendFunc(int op, fixed_t fglevel, fixed_t bglevel, int flags);
static fixed_t GetAlpha(int type, fixed_t alpha);
void DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked);
uint8_t *dc_dest = nullptr;
int dc_dest_y = 0;

View file

@ -25,19 +25,12 @@
namespace swrenderer
{
void WallDrawerArgs::SetDest(RenderViewport *viewport, int x, int y)
void WallDrawerArgs::SetDest(RenderViewport *viewport)
{
dc_viewport = viewport;
dc_dest = viewport->GetDest(x, y);
dc_dest_y = y;
}
void WallDrawerArgs::DrawDepthColumn(RenderThread *thread, float idepth)
{
thread->Drawers(dc_viewport)->DrawDepthWallColumn(*this, idepth);
}
void WallDrawerArgs::DrawColumn(RenderThread *thread)
void WallDrawerArgs::DrawWall(RenderThread *thread)
{
(thread->Drawers(dc_viewport)->*wallfunc)(*this);
}
@ -48,7 +41,7 @@ namespace swrenderer
{
if (!additive)
{
wallfunc = &SWPixelFormatDrawers::DrawWallAddColumn;
wallfunc = &SWPixelFormatDrawers::DrawWallAdd;
dc_srcblend = Col2RGB8[alpha >> 10];
dc_destblend = Col2RGB8[(OPAQUE - alpha) >> 10];
dc_srcalpha = alpha;
@ -56,7 +49,7 @@ namespace swrenderer
}
else
{
wallfunc = &SWPixelFormatDrawers::DrawWallAddClampColumn;
wallfunc = &SWPixelFormatDrawers::DrawWallAddClamp;
dc_srcblend = Col2RGB8_LessPrecision[alpha >> 10];
dc_destblend = Col2RGB8_LessPrecision[FRACUNIT >> 10];
dc_srcalpha = alpha;
@ -65,11 +58,11 @@ namespace swrenderer
}
else if (masked)
{
wallfunc = &SWPixelFormatDrawers::DrawWallMaskedColumn;
wallfunc = &SWPixelFormatDrawers::DrawWallMasked;
}
else
{
wallfunc = &SWPixelFormatDrawers::DrawWallColumn;
wallfunc = &SWPixelFormatDrawers::DrawWall;
}
CameraLight *cameraLight = CameraLight::Instance();

View file

@ -2,6 +2,7 @@
#pragma once
#include "r_drawerargs.h"
#include "swrenderer/line/r_wallsetup.h"
struct FSWColormap;
struct FLightNode;
@ -15,70 +16,52 @@ namespace swrenderer
{
public:
void SetStyle(bool masked, bool additive, fixed_t alpha, FDynamicColormap *basecolormap);
void SetDest(RenderViewport *viewport, int x, int y);
void SetCount(int count) { dc_count = count; }
void SetTexture(const uint8_t *pixels, const uint8_t *pixels2, int height)
{
dc_source = pixels;
dc_source2 = pixels2;
dc_textureheight = height;
}
void SetTextureFracBits(int bits) { dc_wall_fracbits = bits; }
void SetTextureUPos(uint32_t pos) { dc_texturefracx = pos; }
void SetTextureVPos(fixed_t pos) { dc_texturefrac = pos; }
void SetTextureVStep(fixed_t step) { dc_iscale = step; }
void SetDest(RenderViewport *viewport);
void DrawWall(RenderThread *thread);
void DrawDepthColumn(RenderThread *thread, float idepth);
void DrawColumn(RenderThread *thread);
uint8_t *Dest() const { return dc_dest; }
int DestY() const { return dc_dest_y; }
int Count() const { return dc_count; }
uint32_t *SrcBlend() const { return dc_srcblend; }
uint32_t *DestBlend() const { return dc_destblend; }
uint32_t* SrcBlend() const { return dc_srcblend; }
uint32_t* DestBlend() const { return dc_destblend; }
fixed_t SrcAlpha() const { return dc_srcalpha; }
fixed_t DestAlpha() const { return dc_destalpha; }
uint32_t TextureUPos() const { return dc_texturefracx; }
fixed_t TextureVPos() const { return dc_texturefrac; }
fixed_t TextureVStep() const { return dc_iscale; }
RenderViewport* Viewport() const { return dc_viewport; }
const uint8_t *TexturePixels() const { return dc_source; }
const uint8_t *TexturePixels2() const { return dc_source2; }
uint32_t TextureHeight() const { return dc_textureheight; }
int x1, x2;
short* uwal;
short* dwal;
FWallCoords WallC;
ProjectedWallTexcoords texcoords;
FLightNode* lightlist = nullptr;
int TextureFracBits() const { return dc_wall_fracbits; }
float lightpos;
float lightstep;
int mShade;
FVector3 dc_normal = { 0,0,0 };
FVector3 dc_viewpos = { 0,0,0 };
FVector3 dc_viewpos_step = { 0,0,0 };
DrawerLight *dc_lights = nullptr;
int dc_num_lights = 0;
int texwidth;
int texheight;
int fracbits;
bool mipmapped;
const void* texpixels;
RenderViewport *Viewport() const { return dc_viewport; }
// Viewport data
uint16_t PortalMirrorFlags;
bool fixedlight;
float CenterX;
float CenterY;
float FocalTangent;
float InvZtoScale;
FVector3 ViewpointPos;
float Sin, Cos, TanCos, TanSin;
private:
uint8_t *dc_dest = nullptr;
int dc_dest_y = 0;
int dc_count = 0;
fixed_t dc_iscale = 0;
fixed_t dc_texturefrac = 0;
uint32_t dc_texturefracx = 0;
uint32_t dc_textureheight = 0;
const uint8_t *dc_source = nullptr;
const uint8_t *dc_source2 = nullptr;
int dc_wall_fracbits = 0;
uint32_t *dc_srcblend = nullptr;
uint32_t *dc_destblend = nullptr;
fixed_t dc_srcalpha = 0;
fixed_t dc_destalpha = 0;
typedef void(SWPixelFormatDrawers::*WallDrawerFunc)(const WallDrawerArgs &args);
WallDrawerFunc wallfunc = nullptr;
RenderViewport *dc_viewport = nullptr;
uint32_t* dc_srcblend = nullptr;
uint32_t* dc_destblend = nullptr;
fixed_t dc_srcalpha = 0;
fixed_t dc_destalpha = 0;
RenderViewport* dc_viewport = nullptr;
};
}

View file

@ -63,7 +63,6 @@ CVAR(Int, vid_showpalette, 0, 0)
EXTERN_CVAR(Bool, ticker)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
EXTERN_CVAR(Bool, vid_vsync)
EXTERN_CVAR(Int, vid_maxfps)
EXTERN_CVAR(Bool, cl_capfps)
EXTERN_CVAR(Int, screenblocks)

View file

@ -69,7 +69,6 @@
#include "version.h"
#include "g_levellocals.h"
#include "am_map.h"
#include "atterm.h"
EXTERN_CVAR(Int, menu_resolution_custom_width)
EXTERN_CVAR(Int, menu_resolution_custom_height)
@ -152,14 +151,6 @@ int DisplayWidth, DisplayHeight;
FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont;
uint32_t Col2RGB8[65][256];
uint32_t *Col2RGB8_LessPrecision[65];
uint32_t Col2RGB8_Inverse[65][256];
ColorTable32k RGB32k;
ColorTable256k RGB256k;
static uint32_t Col2RGB8_2[63][256];
// [RH] The framebuffer is no longer a mere byte array.
// There's also only one, not four.
@ -482,61 +473,6 @@ int V_GetColor(const uint32_t *palette, FScanner &sc)
return V_GetColor(palette, sc.String, &scc);
}
//==========================================================================
//
// BuildTransTable
//
// Build the tables necessary for blending
//
//==========================================================================
static void BuildTransTable (const PalEntry *palette)
{
int r, g, b;
// create the RGB555 lookup table
for (r = 0; r < 32; r++)
for (g = 0; g < 32; g++)
for (b = 0; b < 32; b++)
RGB32k.RGB[r][g][b] = ColorMatcher.Pick ((r<<3)|(r>>2), (g<<3)|(g>>2), (b<<3)|(b>>2));
// create the RGB666 lookup table
for (r = 0; r < 64; r++)
for (g = 0; g < 64; g++)
for (b = 0; b < 64; b++)
RGB256k.RGB[r][g][b] = ColorMatcher.Pick ((r<<2)|(r>>4), (g<<2)|(g>>4), (b<<2)|(b>>4));
int x, y;
// create the swizzled palette
for (x = 0; x < 65; x++)
for (y = 0; y < 256; y++)
Col2RGB8[x][y] = (((palette[y].r*x)>>4)<<20) |
((palette[y].g*x)>>4) |
(((palette[y].b*x)>>4)<<10);
// create the swizzled palette with the lsb of red and blue forced to 0
// (for green, a 1 is okay since it never gets added into)
for (x = 1; x < 64; x++)
{
Col2RGB8_LessPrecision[x] = Col2RGB8_2[x-1];
for (y = 0; y < 256; y++)
{
Col2RGB8_2[x-1][y] = Col2RGB8[x][y] & 0x3feffbff;
}
}
Col2RGB8_LessPrecision[0] = Col2RGB8[0];
Col2RGB8_LessPrecision[64] = Col2RGB8[64];
// create the inverse swizzled palette
for (x = 0; x < 65; x++)
for (y = 0; y < 256; y++)
{
Col2RGB8_Inverse[x][y] = (((((255-palette[y].r)*x)>>4)<<20) |
(((255-palette[y].g)*x)>>4) |
((((255-palette[y].b)*x)>>4)<<10)) & 0x3feffbff;
}
}
CCMD(clean)
{
Printf ("CleanXfac: %d\nCleanYfac: %d\n", CleanXfac, CleanYfac);
@ -621,55 +557,43 @@ bool IVideo::SetResolution ()
// V_Init
//
void V_Init (bool restart)
void V_InitScreenSize ()
{
const char *i;
int width, height, bits;
atterm (V_Shutdown);
// [RH] Initialize palette management
InitPalette ();
if (!restart)
width = height = bits = 0;
if ( (i = Args->CheckValue ("-width")) )
width = atoi (i);
if ( (i = Args->CheckValue ("-height")) )
height = atoi (i);
if (width == 0)
{
width = height = bits = 0;
if ( (i = Args->CheckValue ("-width")) )
width = atoi (i);
if ( (i = Args->CheckValue ("-height")) )
height = atoi (i);
if (width == 0)
if (height == 0)
{
if (height == 0)
{
width = vid_defwidth;
height = vid_defheight;
}
else
{
width = (height * 8) / 6;
}
width = vid_defwidth;
height = vid_defheight;
}
else if (height == 0)
else
{
height = (width * 6) / 8;
width = (height * 8) / 6;
}
// Remember the passed arguments for the next time the game starts up windowed.
vid_defwidth = width;
vid_defheight = height;
screen = new DDummyFrameBuffer (width, height);
}
// Update screen palette when restarting
else
else if (height == 0)
{
screen->UpdatePalette();
height = (width * 6) / 8;
}
// Remember the passed arguments for the next time the game starts up windowed.
vid_defwidth = width;
vid_defheight = height;
}
BuildTransTable (GPalette.BaseColors);
void V_InitScreen()
{
screen = new DDummyFrameBuffer (vid_defwidth, vid_defheight);
}
void V_Init2()
@ -697,23 +621,13 @@ void V_Init2()
menu_resolution_custom_width = SCREENWIDTH;
menu_resolution_custom_height = SCREENHEIGHT;
screen->SetVSync(vid_vsync);
screen->SetGamma ();
FBaseCVar::ResetColors ();
C_NewModeAdjust();
setsizeneeded = true;
}
void V_Shutdown()
{
if (screen)
{
DFrameBuffer *s = screen;
screen = NULL;
delete s;
}
V_ClearFonts();
}
CUSTOM_CVAR (Int, vid_aspect, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
{
setsizeneeded = true;

View file

@ -597,7 +597,8 @@ EXTERN_CVAR (Float, Gamma)
// Allocates buffer screens, call before R_Init.
void V_Init (bool restart);
void V_InitScreenSize();
void V_InitScreen();
// Initializes graphics mode for the first time.
void V_Init2 ();
@ -665,9 +666,13 @@ public:
savedyfac = CleanYfac;
savedwidth = CleanWidth;
savedheight = CleanHeight;
V_CalcCleanFacs(320, 200, screen->GetWidth(), screen->GetHeight(), &CleanXfac, &CleanYfac);
CleanWidth = screen->GetWidth() / CleanXfac;
CleanHeight = screen->GetHeight() / CleanYfac;
if (screen)
{
V_CalcCleanFacs(320, 200, screen->GetWidth(), screen->GetHeight(), &CleanXfac, &CleanYfac);
CleanWidth = screen->GetWidth() / CleanXfac;
CleanHeight = screen->GetHeight() / CleanYfac;
}
}
~ScaleOverrider()

View file

@ -162,7 +162,6 @@ void VkRenderState::Apply(int dt)
mApplyCount++;
if (mApplyCount >= vk_submit_size)
{
EndRenderPass();
GetVulkanFrameBuffer()->FlushCommands(false);
mApplyCount = 0;
}
@ -437,7 +436,6 @@ void VkRenderState::ApplyDynamicSet()
void VkRenderState::WaitForStreamBuffers()
{
EndRenderPass();
GetVulkanFrameBuffer()->WaitForCommands(false);
mApplyCount = 0;
mStreamBufferWriter.Reset();

View file

@ -38,7 +38,7 @@ VkShaderManager::VkShaderManager(VulkanDevice *device) : device(device)
FString defines = defaultshaders[usershaders[i].shaderType].Defines + usershaders[i].defines;
VkShaderProgram prog;
prog.vert = LoadVertShader(name, mainvp, defaultshaders[i].Defines);
prog.vert = LoadVertShader(name, mainvp, defines);
prog.frag = LoadFragShader(name, mainfp, usershaders[i].shader, defaultshaders[usershaders[i].shaderType].lightfunc, defines, true, gbufferpass);
mMaterialShaders[j].push_back(std::move(prog));
}

View file

@ -251,6 +251,8 @@ void VulkanFrameBuffer::FlushCommands(VulkanCommandBuffer **commands, size_t cou
void VulkanFrameBuffer::FlushCommands(bool finish, bool lastsubmit)
{
mRenderState->EndRenderPass();
if (mDrawCommands || mTransferCommands)
{
VulkanCommandBuffer *commands[2];
@ -634,6 +636,7 @@ const char* VulkanFrameBuffer::DeviceName() const
void VulkanFrameBuffer::SetVSync(bool vsync)
{
// This is handled in VulkanSwapChain::AcquireImage.
cur_vsync = vsync;
}
void VulkanFrameBuffer::CleanForRestart()

View file

@ -25,6 +25,7 @@ public:
VulkanDevice *device;
std::unique_ptr<VulkanSwapChain> swapChain;
uint32_t presentImageIndex = 0xffffffff;
bool cur_vsync;
VulkanCommandBuffer *GetTransferCommands();
VulkanCommandBuffer *GetDrawCommands();

View file

@ -3,8 +3,9 @@
#include "vk_objects.h"
#include "c_cvars.h"
#include "version.h"
#include "v_video.h"
#include "vk_framebuffer.h"
EXTERN_CVAR(Bool, vid_vsync);
CVAR(Bool, vk_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
@ -21,12 +22,13 @@ VulkanSwapChain::~VulkanSwapChain()
uint32_t VulkanSwapChain::AcquireImage(int width, int height, VulkanSemaphore *semaphore, VulkanFence *fence)
{
if (lastSwapWidth != width || lastSwapHeight != height || lastVsync != vid_vsync || lastHdr != vk_hdr || !swapChain)
auto vsync = static_cast<VulkanFrameBuffer*>(screen)->cur_vsync;
if (lastSwapWidth != width || lastSwapHeight != height || lastVsync != vsync || lastHdr != vk_hdr || !swapChain)
{
Recreate();
lastSwapWidth = width;
lastSwapHeight = height;
lastVsync = vid_vsync;
lastVsync = vsync;
lastHdr = vk_hdr;
}
@ -271,7 +273,8 @@ void VulkanSwapChain::SelectPresentMode()
VulkanError("No surface present modes supported");
swapChainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
if (vid_vsync)
auto vsync = static_cast<VulkanFrameBuffer*>(screen)->cur_vsync;
if (vsync)
{
bool supportsFifoRelaxed = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != presentModes.end();
if (supportsFifoRelaxed)

View file

@ -69,6 +69,12 @@ void VkHardwareTexture::Reset()
{
ResetDescriptors();
if (mappedSWFB)
{
mImage.Image->Unmap();
mappedSWFB = nullptr;
}
auto &deleteList = fb->FrameDeleteList;
if (mImage.Image) deleteList.Images.push_back(std::move(mImage.Image));
if (mImage.View) deleteList.ImageViews.push_back(std::move(mImage.View));
@ -348,12 +354,13 @@ void VkHardwareTexture::AllocateBuffer(int w, int h, int texelsize)
uint8_t *VkHardwareTexture::MapBuffer()
{
return (uint8_t*)mImage.Image->Map(0, mImage.Image->width * mImage.Image->height * mTexelsize);
if (!mappedSWFB)
mappedSWFB = (uint8_t*)mImage.Image->Map(0, mImage.Image->width * mImage.Image->height * mTexelsize);
return mappedSWFB;
}
unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name)
{
mImage.Image->Unmap();
return 0;
}

View file

@ -77,4 +77,6 @@ private:
int mTexelsize = 4;
VkTextureImage mDepthStencil;
uint8_t* mappedSWFB = nullptr;
};