Merge remote-tracking branch 'origin/master' into polybackend
This commit is contained in:
commit
4a25c9f69b
658 changed files with 75029 additions and 68704 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ namespace swrenderer
|
|||
fixed_t backcyl = 0;
|
||||
double skymid = 0.0;
|
||||
angle_t skyangle = 0;
|
||||
int skyoffset = 0;
|
||||
|
||||
SkyDrawerArgs drawerargs;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
VulkanDevice *device;
|
||||
std::unique_ptr<VulkanSwapChain> swapChain;
|
||||
uint32_t presentImageIndex = 0xffffffff;
|
||||
bool cur_vsync;
|
||||
|
||||
VulkanCommandBuffer *GetTransferCommands();
|
||||
VulkanCommandBuffer *GetDrawCommands();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,4 +77,6 @@ private:
|
|||
int mTexelsize = 4;
|
||||
|
||||
VkTextureImage mDepthStencil;
|
||||
|
||||
uint8_t* mappedSWFB = nullptr;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue