2017-04-17 10:27:19 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2017-01-03 06:17:54 +00:00
|
|
|
//
|
2017-04-17 10:27:19 +00:00
|
|
|
// Copyright 1993-1996 id Software
|
|
|
|
// Copyright 1999-2016 Randy Heit
|
|
|
|
// Copyright 2016 Magnus Norddahl
|
2017-01-03 06:17:54 +00:00
|
|
|
//
|
2017-04-17 10:27:19 +00:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2017-01-03 06:17:54 +00:00
|
|
|
//
|
2017-04-17 10:27:19 +00:00
|
|
|
// This program is distributed in the hope that it will be useful,
|
2017-01-03 06:17:54 +00:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2017-04-17 10:27:19 +00:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
2017-01-03 06:17:54 +00:00
|
|
|
//
|
2016-12-31 10:42:49 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include "templates.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
#include "doomdef.h"
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "r_sky.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "a_sharedglobal.h"
|
|
|
|
#include "c_console.h"
|
|
|
|
#include "cmdlib.h"
|
|
|
|
#include "d_net.h"
|
|
|
|
#include "g_level.h"
|
2017-03-06 21:14:54 +00:00
|
|
|
#include "g_levellocals.h"
|
2017-01-11 19:42:39 +00:00
|
|
|
#include "swrenderer/scene/r_opaque_pass.h"
|
2016-12-31 10:42:49 +00:00
|
|
|
#include "r_flatplane.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/scene/r_3dfloors.h"
|
2016-12-31 10:42:49 +00:00
|
|
|
#include "v_palette.h"
|
|
|
|
#include "r_data/colormaps.h"
|
|
|
|
#include "swrenderer/drawers/r_draw_rgba.h"
|
2017-03-16 12:49:34 +00:00
|
|
|
#include "a_dynlight.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/segments/r_clipsegment.h"
|
|
|
|
#include "swrenderer/segments/r_drawsegment.h"
|
|
|
|
#include "swrenderer/scene/r_portal.h"
|
2017-01-12 15:21:46 +00:00
|
|
|
#include "swrenderer/scene/r_scene.h"
|
|
|
|
#include "swrenderer/scene/r_light.h"
|
2017-01-11 22:27:35 +00:00
|
|
|
#include "swrenderer/plane/r_visibleplane.h"
|
2017-02-02 14:10:06 +00:00
|
|
|
#include "swrenderer/viewport/r_viewport.h"
|
2016-12-31 10:42:49 +00:00
|
|
|
#include "swrenderer/r_memory.h"
|
2017-02-03 23:25:37 +00:00
|
|
|
#include "swrenderer/r_renderthread.h"
|
2016-12-31 10:42:49 +00:00
|
|
|
|
|
|
|
namespace swrenderer
|
|
|
|
{
|
2017-02-03 23:25:37 +00:00
|
|
|
RenderFlatPlane::RenderFlatPlane(RenderThread *thread)
|
|
|
|
{
|
|
|
|
Thread = thread;
|
|
|
|
}
|
|
|
|
|
2017-01-28 15:36:39 +00:00
|
|
|
void RenderFlatPlane::Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *colormap, FTexture *texture)
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
|
|
|
if (alpha <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-30 11:46:17 +00:00
|
|
|
drawerargs.SetSolidColor(3);
|
2017-03-12 21:53:20 +00:00
|
|
|
drawerargs.SetTexture(Thread, texture);
|
2017-01-28 15:36:39 +00:00
|
|
|
|
2016-12-31 10:42:49 +00:00
|
|
|
double planeang = (pl->xform.Angle + pl->xform.baseAngle).Radians();
|
|
|
|
double xstep, ystep, leftxfrac, leftyfrac, rightxfrac, rightyfrac;
|
|
|
|
double x;
|
|
|
|
|
|
|
|
if (planeang != 0)
|
|
|
|
{
|
|
|
|
double cosine = cos(planeang), sine = sin(planeang);
|
2017-03-12 17:54:39 +00:00
|
|
|
pviewx = pl->xform.xOffs + Thread->Viewport->viewpoint.Pos.X * cosine - Thread->Viewport->viewpoint.Pos.Y * sine;
|
|
|
|
pviewy = pl->xform.yOffs + pl->xform.baseyOffs - Thread->Viewport->viewpoint.Pos.X * sine - Thread->Viewport->viewpoint.Pos.Y * cosine;
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-12 17:54:39 +00:00
|
|
|
pviewx = pl->xform.xOffs + Thread->Viewport->viewpoint.Pos.X;
|
|
|
|
pviewy = pl->xform.yOffs - Thread->Viewport->viewpoint.Pos.Y;
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
2017-02-06 14:15:09 +00:00
|
|
|
pviewx = _xscale * pviewx;
|
|
|
|
pviewy = _yscale * pviewy;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
|
|
|
// left to right mapping
|
2017-03-12 17:54:39 +00:00
|
|
|
planeang += (Thread->Viewport->viewpoint.Angles.Yaw - 90).Radians();
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
auto viewport = Thread->Viewport.get();
|
2017-02-01 15:02:21 +00:00
|
|
|
|
2016-12-31 10:42:49 +00:00
|
|
|
// Scale will be unit scale at FocalLengthX (normally SCREENWIDTH/2) distance
|
2017-02-01 15:02:21 +00:00
|
|
|
xstep = cos(planeang) / viewport->FocalLengthX;
|
|
|
|
ystep = -sin(planeang) / viewport->FocalLengthX;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
|
|
|
// [RH] flip for mirrors
|
2017-02-03 23:25:37 +00:00
|
|
|
RenderPortal *renderportal = Thread->Portal.get();
|
2017-01-05 03:55:26 +00:00
|
|
|
if (renderportal->MirrorFlags & RF_XFLIP)
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
|
|
|
xstep = -xstep;
|
|
|
|
ystep = -ystep;
|
|
|
|
}
|
|
|
|
|
|
|
|
planeang += M_PI / 2;
|
|
|
|
double cosine = cos(planeang), sine = -sin(planeang);
|
2017-07-22 10:29:46 +00:00
|
|
|
x = pl->right - viewport->CenterX + 0.5;
|
2016-12-31 10:42:49 +00:00
|
|
|
rightxfrac = _xscale * (cosine + x * xstep);
|
|
|
|
rightyfrac = _yscale * (sine + x * ystep);
|
2017-02-06 14:15:09 +00:00
|
|
|
x = pl->left - viewport->CenterX + 0.5;
|
2016-12-31 10:42:49 +00:00
|
|
|
leftxfrac = _xscale * (cosine + x * xstep);
|
|
|
|
leftyfrac = _yscale * (sine + x * ystep);
|
|
|
|
|
2017-02-06 14:15:09 +00:00
|
|
|
basexfrac = leftxfrac;
|
|
|
|
baseyfrac = leftyfrac;
|
2017-07-22 10:29:46 +00:00
|
|
|
if (pl->left != pl->right)
|
|
|
|
{
|
|
|
|
xstepscale = (rightxfrac - leftxfrac) / (pl->right - pl->left);
|
|
|
|
ystepscale = (rightyfrac - leftyfrac) / (pl->right - pl->left);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xstepscale = 0;
|
|
|
|
ystepscale = 0;
|
|
|
|
}
|
2017-02-06 14:15:09 +00:00
|
|
|
|
|
|
|
minx = pl->left;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
planeheight = fabs(pl->height.Zat0() - Thread->Viewport->viewpoint.Pos.Z);
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-01-12 20:29:19 +00:00
|
|
|
basecolormap = colormap;
|
2017-03-06 21:14:54 +00:00
|
|
|
|
|
|
|
// [RH] set foggy flag
|
|
|
|
bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE));
|
|
|
|
|
2017-03-12 19:40:00 +00:00
|
|
|
GlobVis = Thread->Light->FlatPlaneGlobVis(foggy) / planeheight;
|
2017-01-30 04:07:07 +00:00
|
|
|
|
2017-01-26 09:22:54 +00:00
|
|
|
CameraLight *cameraLight = CameraLight::Instance();
|
2017-02-03 08:00:46 +00:00
|
|
|
if (cameraLight->FixedLightLevel() >= 0)
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
2017-03-06 22:27:02 +00:00
|
|
|
drawerargs.SetLight(basecolormap, 0, cameraLight->FixedLightLevelShade());
|
2016-12-31 10:42:49 +00:00
|
|
|
plane_shade = false;
|
|
|
|
}
|
2017-02-03 08:00:46 +00:00
|
|
|
else if (cameraLight->FixedColormap())
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
2017-02-03 08:00:46 +00:00
|
|
|
drawerargs.SetLight(cameraLight->FixedColormap(), 0, 0);
|
2016-12-31 10:42:49 +00:00
|
|
|
plane_shade = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
plane_shade = true;
|
2017-03-06 22:27:02 +00:00
|
|
|
planeshade = LightVisibility::LightLevelToShade(pl->lightlevel, foggy);
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
2017-01-30 11:46:17 +00:00
|
|
|
drawerargs.SetStyle(masked, additive, alpha);
|
2016-12-31 13:45:41 +00:00
|
|
|
|
2017-01-11 20:59:26 +00:00
|
|
|
light_list = pl->lights;
|
2016-12-31 13:45:41 +00:00
|
|
|
|
2017-01-11 20:59:26 +00:00
|
|
|
RenderLines(pl);
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 20:59:26 +00:00
|
|
|
void RenderFlatPlane::RenderLine(int y, int x1, int x2)
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
|
|
|
#ifdef RANGECHECK
|
|
|
|
if (x2 < x1 || x1<0 || x2 >= viewwidth || (unsigned)y >= (unsigned)viewheight)
|
|
|
|
{
|
2017-04-17 11:33:19 +00:00
|
|
|
I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
auto viewport = Thread->Viewport.get();
|
2017-02-06 14:15:09 +00:00
|
|
|
|
2017-07-22 10:29:46 +00:00
|
|
|
double curxfrac = basexfrac + xstepscale * (x1 - minx);
|
|
|
|
double curyfrac = baseyfrac + ystepscale * (x1 - minx);
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-02-06 14:15:09 +00:00
|
|
|
double distance = viewport->PlaneDepth(y, planeheight);
|
2018-04-08 11:45:23 +00:00
|
|
|
|
|
|
|
float zbufferdepth = (float)(1.0 / fabs(planeheight / Thread->Viewport->ScreenToViewY(y, 1.0)));
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-06-21 01:08:11 +00:00
|
|
|
drawerargs.SetTextureUStep(distance * xstepscale / drawerargs.TextureWidth());
|
|
|
|
drawerargs.SetTextureUPos((distance * curxfrac + pviewx) / drawerargs.TextureWidth());
|
2017-01-30 11:46:17 +00:00
|
|
|
|
2017-06-21 01:08:11 +00:00
|
|
|
drawerargs.SetTextureVStep(distance * ystepscale / drawerargs.TextureHeight());
|
|
|
|
drawerargs.SetTextureVPos((distance * curyfrac + pviewy) / drawerargs.TextureHeight());
|
2017-02-01 15:02:21 +00:00
|
|
|
|
2017-02-01 20:42:08 +00:00
|
|
|
if (viewport->RenderTarget->IsBgra())
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
2017-02-06 14:15:09 +00:00
|
|
|
double distance2 = viewport->PlaneDepth(y + 1, planeheight);
|
2017-02-01 15:02:21 +00:00
|
|
|
double xmagnitude = fabs(ystepscale * (distance2 - distance) * viewport->FocalLengthX);
|
|
|
|
double ymagnitude = fabs(xstepscale * (distance2 - distance) * viewport->FocalLengthX);
|
2016-12-31 10:42:49 +00:00
|
|
|
double magnitude = MAX(ymagnitude, xmagnitude);
|
|
|
|
double min_lod = -1000.0;
|
2017-01-30 11:46:17 +00:00
|
|
|
drawerargs.SetTextureLOD(MAX(log2(magnitude) + r_lod_bias, min_lod));
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (plane_shade)
|
|
|
|
{
|
|
|
|
// Determine lighting based on the span's distance from the viewer.
|
2017-02-02 10:16:18 +00:00
|
|
|
drawerargs.SetLight(basecolormap, (float)(GlobVis * fabs(viewport->CenterY - y)), planeshade);
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (r_dynlights)
|
|
|
|
{
|
2018-06-05 18:09:02 +00:00
|
|
|
int tx = x1;
|
|
|
|
bool mirror = !!(Thread->Portal->MirrorFlags & RF_XFLIP);
|
|
|
|
if (mirror)
|
|
|
|
tx = viewwidth - tx - 1;
|
|
|
|
|
2016-12-31 10:42:49 +00:00
|
|
|
// Find row position in view space
|
2017-02-01 15:02:21 +00:00
|
|
|
float zspan = (float)(planeheight / (fabs(y + 0.5 - viewport->CenterY) / viewport->InvZtoScale));
|
2018-06-05 18:09:02 +00:00
|
|
|
drawerargs.dc_viewpos.X = (float)((tx + 0.5 - viewport->CenterX) / viewport->CenterX * zspan);
|
2017-01-29 06:49:04 +00:00
|
|
|
drawerargs.dc_viewpos.Y = zspan;
|
2017-02-01 15:02:21 +00:00
|
|
|
drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y - 0.5) / viewport->InvZtoScale * zspan);
|
|
|
|
drawerargs.dc_viewpos_step.X = (float)(zspan / viewport->CenterX);
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2018-06-05 18:09:02 +00:00
|
|
|
if (mirror)
|
|
|
|
drawerargs.dc_viewpos_step.X = -drawerargs.dc_viewpos_step.X;
|
|
|
|
|
2017-01-02 05:52:50 +00:00
|
|
|
// Plane normal
|
2017-01-29 06:49:04 +00:00
|
|
|
drawerargs.dc_normal.X = 0.0f;
|
|
|
|
drawerargs.dc_normal.Y = 0.0f;
|
2017-02-01 15:02:21 +00:00
|
|
|
drawerargs.dc_normal.Z = (y >= viewport->CenterY) ? 1.0f : -1.0f;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-03-10 15:23:16 +00:00
|
|
|
// Calculate max lights that can touch the row so we can allocate memory for the list
|
|
|
|
int max_lights = 0;
|
2017-01-19 02:11:49 +00:00
|
|
|
VisiblePlaneLight *cur_node = light_list;
|
2017-03-10 15:23:16 +00:00
|
|
|
while (cur_node)
|
|
|
|
{
|
|
|
|
if (!(cur_node->lightsource->flags2&MF2_DORMANT))
|
|
|
|
max_lights++;
|
|
|
|
cur_node = cur_node->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
drawerargs.dc_num_lights = 0;
|
|
|
|
drawerargs.dc_lights = Thread->FrameMemory->AllocMemory<DrawerLight>(max_lights);
|
|
|
|
|
|
|
|
// Setup lights for row
|
|
|
|
cur_node = light_list;
|
|
|
|
while (cur_node)
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
2017-03-12 17:54:39 +00:00
|
|
|
double lightX = cur_node->lightsource->X() - Thread->Viewport->viewpoint.Pos.X;
|
|
|
|
double lightY = cur_node->lightsource->Y() - Thread->Viewport->viewpoint.Pos.Y;
|
|
|
|
double lightZ = cur_node->lightsource->Z() - Thread->Viewport->viewpoint.Pos.Z;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
float lx = (float)(lightX * Thread->Viewport->viewpoint.Sin - lightY * Thread->Viewport->viewpoint.Cos);
|
|
|
|
float ly = (float)(lightX * Thread->Viewport->viewpoint.TanCos + lightY * Thread->Viewport->viewpoint.TanSin) - drawerargs.dc_viewpos.Y;
|
2017-01-29 06:49:04 +00:00
|
|
|
float lz = (float)lightZ - drawerargs.dc_viewpos.Z;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
|
|
|
// Precalculate the constant part of the dot here so the drawer doesn't have to.
|
2017-06-18 08:15:31 +00:00
|
|
|
bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0;
|
2016-12-31 10:42:49 +00:00
|
|
|
float lconstant = ly * ly + lz * lz;
|
2017-01-29 06:49:04 +00:00
|
|
|
float nlconstant = is_point_light ? lz * drawerargs.dc_normal.Z : 0.0f;
|
2016-12-31 10:42:49 +00:00
|
|
|
|
|
|
|
// Include light only if it touches this row
|
|
|
|
float radius = cur_node->lightsource->GetRadius();
|
2017-01-02 05:52:50 +00:00
|
|
|
if (radius * radius >= lconstant && nlconstant >= 0.0f)
|
2016-12-31 10:42:49 +00:00
|
|
|
{
|
|
|
|
uint32_t red = cur_node->lightsource->GetRed();
|
|
|
|
uint32_t green = cur_node->lightsource->GetGreen();
|
|
|
|
uint32_t blue = cur_node->lightsource->GetBlue();
|
|
|
|
|
2017-01-29 06:49:04 +00:00
|
|
|
auto &light = drawerargs.dc_lights[drawerargs.dc_num_lights++];
|
2016-12-31 10:42:49 +00:00
|
|
|
light.x = lx;
|
|
|
|
light.y = lconstant;
|
2017-01-02 05:52:50 +00:00
|
|
|
light.z = nlconstant;
|
2016-12-31 10:42:49 +00:00
|
|
|
light.radius = 256.0f / radius;
|
|
|
|
light.color = (red << 16) | (green << 8) | blue;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_node = cur_node->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-01-29 06:49:04 +00:00
|
|
|
drawerargs.dc_num_lights = 0;
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
drawerargs.SetDestY(viewport, y);
|
2017-01-30 11:46:17 +00:00
|
|
|
drawerargs.SetDestX1(x1);
|
|
|
|
drawerargs.SetDestX2(x2);
|
2016-12-31 10:42:49 +00:00
|
|
|
|
2017-02-04 11:38:05 +00:00
|
|
|
drawerargs.DrawSpan(Thread);
|
2018-06-09 10:29:33 +00:00
|
|
|
if (r_modelscene)
|
2018-04-07 13:48:48 +00:00
|
|
|
drawerargs.DrawDepthSpan(Thread, zbufferdepth, zbufferdepth);
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 20:59:26 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2017-02-04 11:38:05 +00:00
|
|
|
|
|
|
|
RenderColoredPlane::RenderColoredPlane(RenderThread *thread)
|
|
|
|
{
|
|
|
|
Thread = thread;
|
|
|
|
}
|
2017-01-11 20:59:26 +00:00
|
|
|
|
2017-01-19 02:11:49 +00:00
|
|
|
void RenderColoredPlane::Render(VisiblePlane *pl)
|
2017-01-11 20:59:26 +00:00
|
|
|
{
|
|
|
|
RenderLines(pl);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderColoredPlane::RenderLine(int y, int x1, int x2)
|
|
|
|
{
|
2017-02-04 11:38:05 +00:00
|
|
|
drawerargs.DrawColoredSpan(Thread, y, x1, x2);
|
2017-01-11 20:59:26 +00:00
|
|
|
}
|
2016-12-31 10:42:49 +00:00
|
|
|
}
|