2016-03-01 15:47:10 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
2017-04-17 10:27:19 +00:00
|
|
|
// Copyright 1993-1996 id Software
|
|
|
|
// Copyright 1999-2016 Randy Heit
|
|
|
|
// Copyright 2006-2016 Christoph Oelckers
|
|
|
|
// Copyright 2016 Magnus Norddahl
|
2016-03-01 15:47:10 +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.
|
2016-03-01 15:47:10 +00:00
|
|
|
//
|
2017-04-17 10:27:19 +00:00
|
|
|
// This program is distributed in the hope that it will be useful,
|
2016-03-01 15:47:10 +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/
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
2016-03-01 15:47:10 +00:00
|
|
|
//
|
|
|
|
// DESCRIPTION:
|
|
|
|
// BSP traversal, handling of LineSegs for rendering.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "templates.h"
|
|
|
|
|
|
|
|
#include "doomdef.h"
|
|
|
|
|
|
|
|
#include "m_bbox.h"
|
|
|
|
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "p_lnspec.h"
|
|
|
|
#include "p_setup.h"
|
|
|
|
|
2016-12-27 05:31:55 +00:00
|
|
|
#include "swrenderer/drawers/r_draw.h"
|
2016-12-31 13:45:41 +00:00
|
|
|
#include "swrenderer/plane/r_visibleplane.h"
|
2017-01-11 22:27:35 +00:00
|
|
|
#include "swrenderer/plane/r_visibleplanelist.h"
|
2017-01-11 14:02:36 +00:00
|
|
|
#include "swrenderer/things/r_sprite.h"
|
2017-01-11 16:59:29 +00:00
|
|
|
#include "swrenderer/things/r_wallsprite.h"
|
|
|
|
#include "swrenderer/things/r_voxel.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/things/r_particle.h"
|
2017-11-27 22:47:26 +00:00
|
|
|
#include "swrenderer/things/r_model.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/segments/r_clipsegment.h"
|
2017-01-01 09:28:35 +00:00
|
|
|
#include "swrenderer/line/r_wallsetup.h"
|
2017-07-12 04:56:34 +00:00
|
|
|
#include "swrenderer/line/r_farclip_line.h"
|
2017-01-12 15:21:46 +00:00
|
|
|
#include "swrenderer/scene/r_scene.h"
|
|
|
|
#include "swrenderer/scene/r_light.h"
|
2017-02-02 14:10:06 +00:00
|
|
|
#include "swrenderer/viewport/r_viewport.h"
|
2017-02-03 23:25:37 +00:00
|
|
|
#include "swrenderer/r_renderthread.h"
|
2016-12-31 13:45:41 +00:00
|
|
|
#include "r_3dfloors.h"
|
2016-12-30 05:15:10 +00:00
|
|
|
#include "r_portal.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
#include "a_sharedglobal.h"
|
|
|
|
#include "g_level.h"
|
|
|
|
#include "p_effect.h"
|
2017-01-04 14:39:47 +00:00
|
|
|
#include "c_console.h"
|
2017-01-11 16:59:29 +00:00
|
|
|
#include "p_maputl.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
// State.
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "r_state.h"
|
2017-01-11 19:42:39 +00:00
|
|
|
#include "r_opaque_pass.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
#include "v_palette.h"
|
|
|
|
#include "r_sky.h"
|
|
|
|
#include "po_man.h"
|
|
|
|
#include "r_data/colormaps.h"
|
2017-01-09 15:16:24 +00:00
|
|
|
#include "g_levellocals.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-28 22:37:57 +00:00
|
|
|
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
|
2017-01-11 16:59:29 +00:00
|
|
|
EXTERN_CVAR(Bool, r_drawvoxels);
|
2017-07-29 20:26:16 +00:00
|
|
|
EXTERN_CVAR(Bool, r_debug_disable_vis_filter);
|
2017-07-29 17:59:36 +00:00
|
|
|
extern uint32_t r_renderercaps;
|
2016-12-01 01:38:32 +00:00
|
|
|
|
2018-06-17 12:56:34 +00:00
|
|
|
double model_distance_cull = 1e16;
|
|
|
|
|
2017-07-12 05:11:43 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
double sprite_distance_cull = 1e16;
|
|
|
|
double line_distance_cull = 1e16;
|
|
|
|
}
|
2017-07-02 20:35:40 +00:00
|
|
|
|
2017-07-20 12:23:45 +00:00
|
|
|
CUSTOM_CVAR(Float, r_sprite_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
2017-07-02 20:35:40 +00:00
|
|
|
{
|
|
|
|
if (r_sprite_distance_cull > 0.0)
|
|
|
|
{
|
|
|
|
sprite_distance_cull = r_sprite_distance_cull * r_sprite_distance_cull;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprite_distance_cull = 1e16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-20 12:23:45 +00:00
|
|
|
CUSTOM_CVAR(Float, r_line_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
2017-07-12 04:56:34 +00:00
|
|
|
{
|
|
|
|
if (r_line_distance_cull > 0.0)
|
|
|
|
{
|
|
|
|
line_distance_cull = r_line_distance_cull * r_line_distance_cull;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line_distance_cull = 1e16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-29 00:09:26 +00:00
|
|
|
CUSTOM_CVAR(Float, r_model_distance_cull, 1024, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/) // Experimental for the moment until a good default is chosen
|
|
|
|
{
|
|
|
|
if (r_model_distance_cull > 0.0)
|
|
|
|
{
|
|
|
|
model_distance_cull = r_model_distance_cull * r_model_distance_cull;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
model_distance_cull = 1e16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-22 04:20:53 +00:00
|
|
|
namespace swrenderer
|
2016-12-01 01:38:32 +00:00
|
|
|
{
|
2017-02-03 23:25:37 +00:00
|
|
|
RenderOpaquePass::RenderOpaquePass(RenderThread *thread) : renderline(thread)
|
2017-01-03 17:57:48 +00:00
|
|
|
{
|
2017-02-03 23:25:37 +00:00
|
|
|
Thread = thread;
|
2017-01-03 17:57:48 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
sector_t *RenderOpaquePass::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, seg_t *backline, int backx1, int backx2, double frontcz1, double frontcz2)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
// If player's view height is underneath fake floor, lower the
|
|
|
|
// drawn ceiling to be just under the floor height, and replace
|
|
|
|
// the drawn floor and ceiling textures, and light level, with
|
|
|
|
// the control sector's.
|
|
|
|
//
|
|
|
|
// Similar for ceiling, only reflected.
|
|
|
|
|
|
|
|
// [RH] allow per-plane lighting
|
2017-01-11 14:02:36 +00:00
|
|
|
if (floorlightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*floorlightlevel = sec->GetFloorLight();
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (ceilinglightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*ceilinglightlevel = sec->GetCeilingLight();
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 18:03:33 +00:00
|
|
|
FakeSide = WaterFakeSide::Center;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
const sector_t *s = sec->GetHeightSec();
|
2017-01-11 14:02:36 +00:00
|
|
|
if (s != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
2017-03-12 17:54:39 +00:00
|
|
|
sector_t *heightsec = Thread->Viewport->viewpoint.sector->heightsec;
|
2017-01-04 14:39:47 +00:00
|
|
|
bool underwater = r_fakingunderwater ||
|
2017-03-12 17:54:39 +00:00
|
|
|
(heightsec && heightsec->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) <= 0);
|
2017-01-04 14:39:47 +00:00
|
|
|
bool doorunderwater = false;
|
2018-05-01 09:29:29 +00:00
|
|
|
int diffTex = (s->MoreFlags & SECMF_CLIPFAKEPLANES);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Replace sector being drawn with a copy to be hacked
|
|
|
|
*tempsec = *sec;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Replace floor and ceiling height with control sector's heights.
|
|
|
|
if (diffTex)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
if (s->floorplane.CopyPlaneIfValid(&tempsec->floorplane, &sec->ceilingplane))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
|
|
|
}
|
2018-05-01 09:29:29 +00:00
|
|
|
else if (s->MoreFlags & SECMF_FAKEFLOORONLY)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
if (underwater)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-03-15 15:47:42 +00:00
|
|
|
tempsec->Colormap = s->Colormap;
|
2018-05-01 09:29:29 +00:00
|
|
|
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->lightlevel = s->lightlevel;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (floorlightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*floorlightlevel = s->GetFloorLight();
|
|
|
|
}
|
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (ceilinglightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*ceilinglightlevel = s->GetCeilingLight();
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 18:03:33 +00:00
|
|
|
FakeSide = WaterFakeSide::BelowFloor;
|
2017-01-04 14:39:47 +00:00
|
|
|
return tempsec;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
return sec;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
tempsec->floorplane = s->floorplane;
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2018-05-01 09:29:29 +00:00
|
|
|
if (!(s->MoreFlags & SECMF_FAKEFLOORONLY))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
if (diffTex)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
if (s->ceilingplane.CopyPlaneIfValid(&tempsec->ceilingplane, &sec->floorplane))
|
|
|
|
{
|
|
|
|
tempsec->SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tempsec->ceilingplane = s->ceilingplane;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
double refceilz = s->ceilingplane.ZatPoint(Thread->Viewport->viewpoint.Pos);
|
|
|
|
double orgceilz = sec->ceilingplane.ZatPoint(Thread->Viewport->viewpoint.Pos);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
#if 1
|
2017-01-04 14:39:47 +00:00
|
|
|
// [RH] Allow viewing underwater areas through doors/windows that
|
|
|
|
// are underwater but not in a water sector themselves.
|
|
|
|
// Only works if you cannot see the top surface of any deep water
|
|
|
|
// sectors at the same time.
|
2017-01-11 14:02:36 +00:00
|
|
|
if (backline && !r_fakingunderwater && backline->frontsector->heightsec == nullptr)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
if (frontcz1 <= s->floorplane.ZatPoint(backline->v1) &&
|
|
|
|
frontcz2 <= s->floorplane.ZatPoint(backline->v2))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
// Check that the window is actually visible
|
|
|
|
for (int z = backx1; z < backx2; ++z)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
if (floorclip[z] > ceilingclip[z])
|
|
|
|
{
|
|
|
|
doorunderwater = true;
|
|
|
|
r_fakingunderwater = true;
|
|
|
|
break;
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
if (underwater || doorunderwater)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->floorplane = sec->floorplane;
|
|
|
|
tempsec->ceilingplane = s->floorplane;
|
|
|
|
tempsec->ceilingplane.FlipVert();
|
|
|
|
tempsec->ceilingplane.ChangeHeight(-1 / 65536.);
|
2017-03-15 15:47:42 +00:00
|
|
|
tempsec->Colormap = s->Colormap;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// killough 11/98: prevent sudden light changes from non-water sectors:
|
|
|
|
if ((underwater && !backline) || doorunderwater)
|
|
|
|
{ // head-below-floor hack
|
|
|
|
tempsec->SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
|
|
|
|
tempsec->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->ceilingplane = s->floorplane;
|
|
|
|
tempsec->ceilingplane.FlipVert();
|
|
|
|
tempsec->ceilingplane.ChangeHeight(-1 / 65536.);
|
|
|
|
if (s->GetTexture(sector_t::ceiling) == skyflatnum)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->floorplane = tempsec->ceilingplane;
|
|
|
|
tempsec->floorplane.FlipVert();
|
|
|
|
tempsec->floorplane.ChangeHeight(+1 / 65536.);
|
|
|
|
tempsec->SetTexture(sector_t::ceiling, tempsec->GetTexture(sector_t::floor), false);
|
|
|
|
tempsec->planes[sector_t::ceiling].xform = tempsec->planes[sector_t::floor].xform;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
else
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
|
|
|
|
tempsec->planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 09:29:29 +00:00
|
|
|
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
tempsec->lightlevel = s->lightlevel;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (floorlightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*floorlightlevel = s->GetFloorLight();
|
|
|
|
}
|
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (ceilinglightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*ceilinglightlevel = s->GetCeilingLight();
|
|
|
|
}
|
|
|
|
}
|
2017-01-04 18:03:33 +00:00
|
|
|
FakeSide = WaterFakeSide::BelowFloor;
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2017-03-12 17:54:39 +00:00
|
|
|
else if (heightsec && heightsec->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) <= 0 &&
|
2018-05-01 09:29:29 +00:00
|
|
|
orgceilz > refceilz && !(s->MoreFlags & SECMF_FAKEFLOORONLY))
|
2017-01-04 14:39:47 +00:00
|
|
|
{ // Above-ceiling hack
|
|
|
|
tempsec->ceilingplane = s->ceilingplane;
|
|
|
|
tempsec->floorplane = s->ceilingplane;
|
|
|
|
tempsec->floorplane.FlipVert();
|
|
|
|
tempsec->floorplane.ChangeHeight(+1 / 65536.);
|
2017-03-15 15:47:42 +00:00
|
|
|
tempsec->Colormap = s->Colormap;
|
2017-01-04 14:39:47 +00:00
|
|
|
|
|
|
|
tempsec->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
|
|
|
|
tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
|
|
|
|
tempsec->planes[sector_t::ceiling].xform = tempsec->planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
|
|
|
|
|
|
|
|
if (s->GetTexture(sector_t::floor) != skyflatnum)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->ceilingplane = sec->ceilingplane;
|
|
|
|
tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
|
|
|
tempsec->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 09:29:29 +00:00
|
|
|
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec->lightlevel = s->lightlevel;
|
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (floorlightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*floorlightlevel = s->GetFloorLight();
|
|
|
|
}
|
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (ceilinglightlevel != nullptr)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
*ceilinglightlevel = s->GetCeilingLight();
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 18:03:33 +00:00
|
|
|
FakeSide = WaterFakeSide::AboveCeiling;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
sec = tempsec; // Use other sector
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
return sec;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Checks BSP node/subtree bounding box.
|
|
|
|
// Returns true if some part of the bbox might be visible.
|
2017-01-11 19:42:39 +00:00
|
|
|
bool RenderOpaquePass::CheckBBox(float *bspcoord)
|
2017-01-01 09:28:35 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
static const int checkcoord[12][4] =
|
|
|
|
{
|
|
|
|
{ 3,0,2,1 },
|
|
|
|
{ 3,0,2,0 },
|
|
|
|
{ 3,1,2,0 },
|
|
|
|
{ 0 },
|
|
|
|
{ 2,0,2,1 },
|
|
|
|
{ 0,0,0,0 },
|
|
|
|
{ 3,1,3,0 },
|
|
|
|
{ 0 },
|
|
|
|
{ 2,0,3,1 },
|
|
|
|
{ 2,1,3,1 },
|
|
|
|
{ 2,1,3,0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int boxx;
|
|
|
|
int boxy;
|
|
|
|
int boxpos;
|
|
|
|
|
|
|
|
double x1, y1, x2, y2;
|
|
|
|
double rx1, ry1, rx2, ry2;
|
|
|
|
int sx1, sx2;
|
|
|
|
|
|
|
|
// Find the corners of the box
|
|
|
|
// that define the edges from current viewpoint.
|
2017-03-12 17:54:39 +00:00
|
|
|
if (Thread->Viewport->viewpoint.Pos.X <= bspcoord[BOXLEFT])
|
2017-01-04 14:39:47 +00:00
|
|
|
boxx = 0;
|
2017-03-12 17:54:39 +00:00
|
|
|
else if (Thread->Viewport->viewpoint.Pos.X < bspcoord[BOXRIGHT])
|
2017-01-04 14:39:47 +00:00
|
|
|
boxx = 1;
|
|
|
|
else
|
|
|
|
boxx = 2;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
if (Thread->Viewport->viewpoint.Pos.Y >= bspcoord[BOXTOP])
|
2017-01-04 14:39:47 +00:00
|
|
|
boxy = 0;
|
2017-03-12 17:54:39 +00:00
|
|
|
else if (Thread->Viewport->viewpoint.Pos.Y > bspcoord[BOXBOTTOM])
|
2017-01-04 14:39:47 +00:00
|
|
|
boxy = 1;
|
|
|
|
else
|
|
|
|
boxy = 2;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
boxpos = (boxy << 2) + boxx;
|
|
|
|
if (boxpos == 5)
|
|
|
|
return true;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
x1 = bspcoord[checkcoord[boxpos][0]] - Thread->Viewport->viewpoint.Pos.X;
|
|
|
|
y1 = bspcoord[checkcoord[boxpos][1]] - Thread->Viewport->viewpoint.Pos.Y;
|
|
|
|
x2 = bspcoord[checkcoord[boxpos][2]] - Thread->Viewport->viewpoint.Pos.X;
|
|
|
|
y2 = bspcoord[checkcoord[boxpos][3]] - Thread->Viewport->viewpoint.Pos.Y;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// check clip list for an open space
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Sitting on a line?
|
|
|
|
if (y1 * (x1 - x2) + x1 * (y2 - y1) >= -EQUAL_EPSILON)
|
|
|
|
return true;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
rx1 = x1 * Thread->Viewport->viewpoint.Sin - y1 * Thread->Viewport->viewpoint.Cos;
|
|
|
|
rx2 = x2 * Thread->Viewport->viewpoint.Sin - y2 * Thread->Viewport->viewpoint.Cos;
|
|
|
|
ry1 = x1 * Thread->Viewport->viewpoint.TanCos + y1 * Thread->Viewport->viewpoint.TanSin;
|
|
|
|
ry2 = x2 * Thread->Viewport->viewpoint.TanCos + y2 * Thread->Viewport->viewpoint.TanSin;
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2017-02-03 23:25:37 +00:00
|
|
|
if (Thread->Portal->MirrorFlags & RF_XFLIP)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
double t = -rx1;
|
|
|
|
rx1 = -rx2;
|
|
|
|
rx2 = t;
|
|
|
|
swapvalues(ry1, ry2);
|
|
|
|
}
|
2017-02-01 15:02:21 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
auto viewport = Thread->Viewport.get();
|
2017-01-04 14:39:47 +00:00
|
|
|
|
|
|
|
if (rx1 >= -ry1)
|
|
|
|
{
|
|
|
|
if (rx1 > ry1) return false; // left edge is off the right side
|
|
|
|
if (ry1 == 0) return false;
|
2017-02-01 15:02:21 +00:00
|
|
|
sx1 = xs_RoundToInt(viewport->CenterX + rx1 * viewport->CenterX / ry1);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rx2 < -ry2) return false; // wall is off the left side
|
|
|
|
if (rx1 - rx2 - ry2 + ry1 == 0) return false; // wall does not intersect view volume
|
|
|
|
sx1 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rx2 <= ry2)
|
|
|
|
{
|
|
|
|
if (rx2 < -ry2) return false; // right edge is off the left side
|
|
|
|
if (ry2 == 0) return false;
|
2017-02-01 15:02:21 +00:00
|
|
|
sx2 = xs_RoundToInt(viewport->CenterX + rx2 * viewport->CenterX / ry2);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rx1 > ry1) return false; // wall is off the right side
|
|
|
|
if (ry2 - ry1 - rx2 + rx1 == 0) return false; // wall does not intersect view volume
|
|
|
|
sx2 = viewwidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the first clippost that touches the source post
|
|
|
|
// (adjacent pixels are touching).
|
|
|
|
|
2017-02-03 23:25:37 +00:00
|
|
|
return Thread->ClipSegments->IsVisible(sx1, sx2);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
void RenderOpaquePass::AddPolyobjs(subsector_t *sub)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-07-02 15:22:59 +00:00
|
|
|
Thread->PreparePolyObject(sub);
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
if (sub->BSP->Nodes.Size() == 0)
|
|
|
|
{
|
|
|
|
RenderSubsector(&sub->BSP->Subsectors[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RenderBSPNode(&sub->BSP->Nodes.Last());
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// kg3D - add fake segs, never rendered
|
2018-05-11 15:00:12 +00:00
|
|
|
void RenderOpaquePass::FakeDrawLoop(subsector_t *sub, sector_t *frontsector, VisiblePlane *floorplane, VisiblePlane *ceilingplane, bool foggy, FDynamicColormap *basecolormap, Fake3DOpaque opaque3dfloor)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
int count;
|
|
|
|
seg_t* line;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
count = sub->numlines;
|
|
|
|
line = sub->firstline;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
while (count--)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
if ((line->sidedef) && !(line->sidedef->Flags & WALLF_POLYOBJ))
|
|
|
|
{
|
2018-03-08 03:05:35 +00:00
|
|
|
renderline.Render(line, InSubsector, frontsector, nullptr, floorplane, ceilingplane, foggy, basecolormap, opaque3dfloor);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
line++;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
void RenderOpaquePass::RenderSubsector(subsector_t *sub)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
// Determine floor/ceiling planes.
|
|
|
|
// Add sprites of things in sector.
|
|
|
|
// Draw one or more line segments.
|
|
|
|
|
2018-05-11 12:27:09 +00:00
|
|
|
bool outersubsector;
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2017-01-11 14:02:36 +00:00
|
|
|
if (InSubsector != nullptr)
|
|
|
|
{ // InSubsector is not nullptr. This means we are rendering from a mini-BSP.
|
2017-01-04 14:39:47 +00:00
|
|
|
outersubsector = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outersubsector = true;
|
|
|
|
InSubsector = sub;
|
2018-05-06 00:54:03 +00:00
|
|
|
|
|
|
|
// Mark the visual sorting depth of this subsector
|
|
|
|
uint32_t subsectorDepth = (uint32_t)PvsSubsectors.size();
|
|
|
|
SubsectorDepths[sub->Index()] = subsectorDepth;
|
|
|
|
PvsSubsectors.push_back(sub->Index());
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
#ifdef RANGECHECK
|
2017-03-16 23:22:52 +00:00
|
|
|
if (outersubsector && (unsigned)sub->Index() >= level.subsectors.Size())
|
|
|
|
I_Error("RenderSubsector: ss %i with numss = %u", sub->Index(), level.subsectors.Size());
|
2016-03-01 15:47:10 +00:00
|
|
|
#endif
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
if (sub->polys)
|
|
|
|
{ // Render the polyobjs in the subsector first
|
|
|
|
AddPolyobjs(sub);
|
|
|
|
if (outersubsector)
|
|
|
|
{
|
2017-01-11 14:02:36 +00:00
|
|
|
InSubsector = nullptr;
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
return;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
sub->sector->MoreFlags |= SECMF_DRAWN;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
2018-05-11 12:27:09 +00:00
|
|
|
sector_t tempsec;
|
|
|
|
int floorlightlevel, ceilinglightlevel;
|
2018-05-11 15:00:12 +00:00
|
|
|
sector_t *frontsector = FakeFlat(sub->sector, &tempsec, &floorlightlevel, &ceilinglightlevel, nullptr, 0, 0, 0, 0);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// [RH] set foggy flag
|
2017-03-15 15:47:42 +00:00
|
|
|
bool foggy = level.fadeto || frontsector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// kg3D - fake lights
|
2017-01-26 09:22:54 +00:00
|
|
|
CameraLight *cameraLight = CameraLight::Instance();
|
2017-01-12 20:29:19 +00:00
|
|
|
FDynamicColormap *basecolormap;
|
2018-05-11 12:27:09 +00:00
|
|
|
int adjusted_ceilinglightlevel = ceilinglightlevel;
|
2017-02-03 08:00:46 +00:00
|
|
|
if (cameraLight->FixedLightLevel() < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2018-05-11 12:27:09 +00:00
|
|
|
lightlist_t *light = P_GetPlaneLight(frontsector, &frontsector->ceilingplane, false);
|
2017-03-15 22:24:53 +00:00
|
|
|
basecolormap = GetColorTable(light->extra_colormap, frontsector->SpecialColors[sector_t::ceiling]);
|
2017-01-04 14:39:47 +00:00
|
|
|
// If this is the real ceiling, don't discard plane lighting R_FakeFlat()
|
|
|
|
// accounted for.
|
|
|
|
if (light->p_lightlevel != &frontsector->lightlevel)
|
|
|
|
{
|
2018-05-11 12:27:09 +00:00
|
|
|
adjusted_ceilinglightlevel = *light->p_lightlevel;
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
else
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-03-15 22:24:53 +00:00
|
|
|
basecolormap = (r_fullbrightignoresectorcolor && cameraLight->FixedLightLevel() >= 0) ? &FullNormalLight : GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::ceiling]);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 12:27:09 +00:00
|
|
|
FSectorPortal *portal = frontsector->ValidatePortal(sector_t::ceiling);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 12:27:09 +00:00
|
|
|
VisiblePlane *ceilingplane = nullptr;
|
|
|
|
if (frontsector->ceilingplane.PointOnSide(Thread->Viewport->viewpoint.Pos) > 0 ||
|
2017-01-04 14:39:47 +00:00
|
|
|
frontsector->GetTexture(sector_t::ceiling) == skyflatnum ||
|
2018-05-11 12:27:09 +00:00
|
|
|
portal ||
|
|
|
|
(frontsector->GetHeightSec() && frontsector->heightsec->GetTexture(sector_t::floor) == skyflatnum))
|
|
|
|
{
|
|
|
|
ceilingplane = Thread->PlaneList->FindPlane(
|
|
|
|
frontsector->ceilingplane,
|
2017-01-04 14:39:47 +00:00
|
|
|
frontsector->GetTexture(sector_t::ceiling),
|
2018-05-11 12:27:09 +00:00
|
|
|
adjusted_ceilinglightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()),
|
2017-01-04 14:39:47 +00:00
|
|
|
frontsector->GetAlpha(sector_t::ceiling),
|
|
|
|
!!(frontsector->GetFlags(sector_t::ceiling) & PLANEF_ADDITIVE),
|
|
|
|
frontsector->planes[sector_t::ceiling].xform,
|
|
|
|
frontsector->sky,
|
2017-01-12 20:29:19 +00:00
|
|
|
portal,
|
2018-03-08 03:05:35 +00:00
|
|
|
basecolormap,
|
|
|
|
Fake3DOpaque::Normal,
|
2018-05-11 12:27:09 +00:00
|
|
|
0);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2017-02-04 01:50:52 +00:00
|
|
|
ceilingplane->AddLights(Thread, frontsector->lighthead);
|
2018-05-11 12:27:09 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 12:27:09 +00:00
|
|
|
int adjusted_floorlightlevel = floorlightlevel;
|
2017-02-03 08:00:46 +00:00
|
|
|
if (cameraLight->FixedLightLevel() < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2018-05-11 12:27:09 +00:00
|
|
|
lightlist_t *light = P_GetPlaneLight(frontsector, &frontsector->floorplane, false);
|
2017-03-15 22:24:53 +00:00
|
|
|
basecolormap = GetColorTable(light->extra_colormap, frontsector->SpecialColors[sector_t::floor]);
|
2017-01-04 14:39:47 +00:00
|
|
|
// If this is the real floor, don't discard plane lighting R_FakeFlat()
|
|
|
|
// accounted for.
|
|
|
|
if (light->p_lightlevel != &frontsector->lightlevel)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2018-05-11 12:27:09 +00:00
|
|
|
adjusted_floorlightlevel = *light->p_lightlevel;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-15 22:24:53 +00:00
|
|
|
basecolormap = (r_fullbrightignoresectorcolor && cameraLight->FixedLightLevel() >= 0) ? &FullNormalLight : GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::floor]);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
portal = frontsector->ValidatePortal(sector_t::floor);
|
|
|
|
|
2018-05-11 12:27:09 +00:00
|
|
|
VisiblePlane *floorplane = nullptr;
|
|
|
|
if (frontsector->floorplane.PointOnSide(Thread->Viewport->viewpoint.Pos) > 0 ||
|
2017-01-04 14:39:47 +00:00
|
|
|
frontsector->GetTexture(sector_t::floor) == skyflatnum ||
|
2018-05-11 12:27:09 +00:00
|
|
|
portal ||
|
|
|
|
(frontsector->GetHeightSec() && frontsector->heightsec->GetTexture(sector_t::ceiling) == skyflatnum))
|
|
|
|
{
|
|
|
|
floorplane = Thread->PlaneList->FindPlane(frontsector->floorplane,
|
2017-01-04 14:39:47 +00:00
|
|
|
frontsector->GetTexture(sector_t::floor),
|
2018-05-11 12:27:09 +00:00
|
|
|
adjusted_floorlightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()),
|
2017-01-04 14:39:47 +00:00
|
|
|
frontsector->GetAlpha(sector_t::floor),
|
|
|
|
!!(frontsector->GetFlags(sector_t::floor) & PLANEF_ADDITIVE),
|
|
|
|
frontsector->planes[sector_t::floor].xform,
|
|
|
|
frontsector->sky,
|
2017-01-12 20:29:19 +00:00
|
|
|
portal,
|
2018-03-08 03:05:35 +00:00
|
|
|
basecolormap,
|
|
|
|
Fake3DOpaque::Normal,
|
2018-05-11 12:27:09 +00:00
|
|
|
0);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2017-02-04 01:50:52 +00:00
|
|
|
floorplane->AddLights(Thread, frontsector->lighthead);
|
2018-05-11 12:27:09 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
Add3DFloorPlanes(sub, frontsector, basecolormap, foggy, adjusted_ceilinglightlevel, adjusted_floorlightlevel);
|
|
|
|
|
|
|
|
// killough 9/18/98: Fix underwater slowdown, by passing real sector
|
|
|
|
// instead of fake one. Improve sprite lighting by basing sprite
|
|
|
|
// lightlevels on floor & ceiling lightlevels in the surrounding area.
|
|
|
|
// [RH] Handle sprite lighting like Duke 3D: If the ceiling is a sky, sprites are lit by
|
|
|
|
// it, otherwise they are lit by the floor.
|
|
|
|
AddSprites(sub->sector, frontsector->GetTexture(sector_t::ceiling) == skyflatnum ? ceilinglightlevel : floorlightlevel, FakeSide, foggy, GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::sprites], true));
|
|
|
|
|
|
|
|
// [RH] Add particles
|
|
|
|
if ((unsigned int)(sub->Index()) < level.subsectors.Size())
|
|
|
|
{ // Only do it for the main BSP.
|
|
|
|
int shade = LightVisibility::LightLevelToShade((floorlightlevel + ceilinglightlevel) / 2 + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy);
|
|
|
|
for (int i = ParticlesInSubsec[sub->Index()]; i != NO_PARTICLE; i = Particles[i].snext)
|
|
|
|
{
|
|
|
|
RenderParticle::Project(Thread, Particles + i, sub->sector, shade, FakeSide, foggy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DVector2 viewpointPos = Thread->Viewport->viewpoint.Pos.XY();
|
|
|
|
|
|
|
|
basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
|
|
|
|
|
|
|
|
seg_t *line = sub->firstline;
|
|
|
|
int count = sub->numlines;
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
double dist1 = (line->v1->fPos() - viewpointPos).LengthSquared();
|
|
|
|
double dist2 = (line->v2->fPos() - viewpointPos).LengthSquared();
|
|
|
|
if (dist1 > line_distance_cull && dist2 > line_distance_cull)
|
|
|
|
{
|
|
|
|
FarClipLine farclip(Thread);
|
|
|
|
farclip.Render(line, InSubsector, floorplane, ceilingplane, Fake3DOpaque::Normal);
|
|
|
|
}
|
|
|
|
else if (!outersubsector || line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ))
|
|
|
|
{
|
|
|
|
Add3DFloorLine(line, frontsector, basecolormap, foggy);
|
|
|
|
renderline.Render(line, InSubsector, frontsector, nullptr, floorplane, ceilingplane, foggy, basecolormap, Fake3DOpaque::Normal); // now real
|
|
|
|
}
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
if (outersubsector)
|
|
|
|
{
|
|
|
|
InSubsector = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderOpaquePass::Add3DFloorLine(seg_t *line, sector_t *frontsector, FDynamicColormap *basecolormap, bool foggy)
|
|
|
|
{
|
|
|
|
// kg3D - fake planes bounding calculation
|
|
|
|
if (r_3dfloors && line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())
|
|
|
|
{
|
|
|
|
Clip3DFloors *clip3d = Thread->Clip3D.get();
|
|
|
|
for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
|
|
|
|
{
|
|
|
|
clip3d->SetFakeFloor(line->backsector->e->XFloor.ffloors[i]);
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_EXISTS)) continue;
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_RENDERPLANES)) continue;
|
|
|
|
if (!clip3d->fakeFloor->fakeFloor->model) continue;
|
|
|
|
Fake3DOpaque opaque3dfloor = Fake3DOpaque::FakeBack;
|
|
|
|
sector_t tempsec = *clip3d->fakeFloor->fakeFloor->model;
|
|
|
|
tempsec.floorplane = *clip3d->fakeFloor->fakeFloor->top.plane;
|
|
|
|
tempsec.ceilingplane = *clip3d->fakeFloor->fakeFloor->bottom.plane;
|
|
|
|
if (clip3d->fakeFloor->validcount != validcount)
|
|
|
|
{
|
|
|
|
clip3d->fakeFloor->validcount = validcount;
|
|
|
|
clip3d->NewClip();
|
|
|
|
}
|
|
|
|
renderline.Render(line, InSubsector, frontsector, &tempsec, nullptr, nullptr, foggy, basecolormap, opaque3dfloor); // fake
|
|
|
|
}
|
|
|
|
clip3d->fakeFloor = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderOpaquePass::Add3DFloorPlanes(subsector_t *sub, sector_t *frontsector, FDynamicColormap *basecolormap, bool foggy, int ceilinglightlevel, int floorlightlevel)
|
|
|
|
{
|
2017-01-04 14:39:47 +00:00
|
|
|
// kg3D - fake planes rendering
|
|
|
|
if (r_3dfloors && frontsector->e && frontsector->e->XFloor.ffloors.Size())
|
|
|
|
{
|
2018-05-11 15:00:12 +00:00
|
|
|
CameraLight *cameraLight = CameraLight::Instance();
|
2017-02-06 15:04:27 +00:00
|
|
|
Clip3DFloors *clip3d = Thread->Clip3D.get();
|
2017-01-04 17:54:14 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// first check all floors
|
|
|
|
for (int i = 0; i < (int)frontsector->e->XFloor.ffloors.Size(); i++)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-02-04 18:13:56 +00:00
|
|
|
clip3d->SetFakeFloor(frontsector->e->XFloor.ffloors[i]);
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_EXISTS)) continue;
|
|
|
|
if (!clip3d->fakeFloor->fakeFloor->model) continue;
|
|
|
|
if (clip3d->fakeFloor->fakeFloor->bottom.plane->isSlope()) continue;
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_NOSHADE) || (clip3d->fakeFloor->fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-02-04 18:13:56 +00:00
|
|
|
clip3d->AddHeight(clip3d->fakeFloor->fakeFloor->top.plane, frontsector);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2017-02-04 18:13:56 +00:00
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_RENDERPLANES)) continue;
|
|
|
|
if (clip3d->fakeFloor->fakeFloor->alpha == 0) continue;
|
|
|
|
if (clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE && clip3d->fakeFloor->fakeFloor->flags & FF_INVERTSECTOR) continue;
|
2018-03-08 03:05:35 +00:00
|
|
|
fixed_t fakeAlpha = MIN<fixed_t>(Scale(clip3d->fakeFloor->fakeFloor->alpha, OPAQUE, 255), OPAQUE);
|
2017-01-04 17:54:14 +00:00
|
|
|
if (clip3d->fakeFloor->validcount != validcount)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 17:54:14 +00:00
|
|
|
clip3d->fakeFloor->validcount = validcount;
|
|
|
|
clip3d->NewClip();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-02-04 18:13:56 +00:00
|
|
|
double fakeHeight = clip3d->fakeFloor->fakeFloor->top.plane->ZatPoint(frontsector->centerspot);
|
2017-03-12 17:54:39 +00:00
|
|
|
if (fakeHeight < Thread->Viewport->viewpoint.Pos.Z &&
|
2017-01-04 14:39:47 +00:00
|
|
|
fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot))
|
|
|
|
{
|
2018-05-11 15:00:12 +00:00
|
|
|
sector_t tempsec = *clip3d->fakeFloor->fakeFloor->model;
|
2017-02-04 18:13:56 +00:00
|
|
|
tempsec.floorplane = *clip3d->fakeFloor->fakeFloor->top.plane;
|
|
|
|
tempsec.ceilingplane = *clip3d->fakeFloor->fakeFloor->bottom.plane;
|
2018-05-11 12:27:09 +00:00
|
|
|
|
|
|
|
int position;
|
2017-02-04 18:13:56 +00:00
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE) && !(clip3d->fakeFloor->fakeFloor->flags & FF_INVERTSECTOR))
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
tempsec.SetTexture(sector_t::floor, tempsec.GetTexture(sector_t::ceiling));
|
|
|
|
position = sector_t::ceiling;
|
|
|
|
}
|
2018-05-11 12:27:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
position = sector_t::floor;
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-02-03 08:00:46 +00:00
|
|
|
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
2018-05-11 15:00:12 +00:00
|
|
|
lightlist_t *light = P_GetPlaneLight(sub->sector, &tempsec.floorplane, false);
|
2017-03-15 15:47:42 +00:00
|
|
|
basecolormap = GetColorTable(light->extra_colormap);
|
2018-05-11 15:00:12 +00:00
|
|
|
floorlightlevel = *light->p_lightlevel;
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
VisiblePlane *floorplane3d = Thread->PlaneList->FindPlane(
|
|
|
|
tempsec.floorplane,
|
|
|
|
tempsec.GetTexture(sector_t::floor),
|
|
|
|
floorlightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()),
|
|
|
|
tempsec.GetAlpha(sector_t::floor),
|
2017-02-04 18:13:56 +00:00
|
|
|
!!(clip3d->fakeFloor->fakeFloor->flags & FF_ADDITIVETRANS),
|
2018-05-11 15:00:12 +00:00
|
|
|
tempsec.planes[position].xform,
|
|
|
|
tempsec.sky,
|
2017-01-12 20:29:19 +00:00
|
|
|
nullptr,
|
2018-03-08 03:05:35 +00:00
|
|
|
basecolormap,
|
|
|
|
Fake3DOpaque::FakeFloor,
|
|
|
|
fakeAlpha);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
floorplane3d->AddLights(Thread, tempsec.lighthead);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
FakeDrawLoop(sub, &tempsec, floorplane3d, nullptr, foggy, basecolormap, Fake3DOpaque::FakeFloor);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
// and now ceilings
|
|
|
|
for (unsigned int i = 0; i < frontsector->e->XFloor.ffloors.Size(); i++)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-02-04 18:13:56 +00:00
|
|
|
clip3d->SetFakeFloor(frontsector->e->XFloor.ffloors[i]);
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_EXISTS)) continue;
|
|
|
|
if (!clip3d->fakeFloor->fakeFloor->model) continue;
|
|
|
|
if (clip3d->fakeFloor->fakeFloor->top.plane->isSlope()) continue;
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_NOSHADE) || (clip3d->fakeFloor->fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-02-04 18:13:56 +00:00
|
|
|
clip3d->AddHeight(clip3d->fakeFloor->fakeFloor->bottom.plane, frontsector);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2017-02-04 18:13:56 +00:00
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_RENDERPLANES)) continue;
|
|
|
|
if (clip3d->fakeFloor->fakeFloor->alpha == 0) continue;
|
|
|
|
if (!(clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE) && (clip3d->fakeFloor->fakeFloor->flags & (FF_SWIMMABLE | FF_INVERTSECTOR)) == (FF_SWIMMABLE | FF_INVERTSECTOR)) continue;
|
2018-03-08 03:05:35 +00:00
|
|
|
fixed_t fakeAlpha = MIN<fixed_t>(Scale(clip3d->fakeFloor->fakeFloor->alpha, OPAQUE, 255), OPAQUE);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 17:54:14 +00:00
|
|
|
if (clip3d->fakeFloor->validcount != validcount)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-04 17:54:14 +00:00
|
|
|
clip3d->fakeFloor->validcount = validcount;
|
|
|
|
clip3d->NewClip();
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2017-02-04 18:13:56 +00:00
|
|
|
double fakeHeight = clip3d->fakeFloor->fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot);
|
2017-03-12 17:54:39 +00:00
|
|
|
if (fakeHeight > Thread->Viewport->viewpoint.Pos.Z &&
|
2017-01-04 14:39:47 +00:00
|
|
|
fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot))
|
|
|
|
{
|
2018-05-11 15:00:12 +00:00
|
|
|
sector_t tempsec = *clip3d->fakeFloor->fakeFloor->model;
|
2017-02-04 18:13:56 +00:00
|
|
|
tempsec.floorplane = *clip3d->fakeFloor->fakeFloor->top.plane;
|
|
|
|
tempsec.ceilingplane = *clip3d->fakeFloor->fakeFloor->bottom.plane;
|
2018-05-11 12:27:09 +00:00
|
|
|
|
|
|
|
int position;
|
2017-02-04 18:13:56 +00:00
|
|
|
if ((!(clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE) && !(clip3d->fakeFloor->fakeFloor->flags & FF_INVERTSECTOR)) ||
|
|
|
|
(clip3d->fakeFloor->fakeFloor->flags & FF_THISINSIDE && clip3d->fakeFloor->fakeFloor->flags & FF_INVERTSECTOR))
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor));
|
|
|
|
position = sector_t::floor;
|
|
|
|
}
|
2018-05-11 12:27:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
position = sector_t::ceiling;
|
|
|
|
}
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
|
2017-02-03 08:00:46 +00:00
|
|
|
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
2018-05-11 15:00:12 +00:00
|
|
|
lightlist_t *light = P_GetPlaneLight(sub->sector, &tempsec.ceilingplane, false);
|
2017-03-15 15:47:42 +00:00
|
|
|
basecolormap = GetColorTable(light->extra_colormap);
|
2018-05-11 15:00:12 +00:00
|
|
|
ceilinglightlevel = *light->p_lightlevel;
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
|
|
|
tempsec.ceilingplane.ChangeHeight(1 / 65536.);
|
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
VisiblePlane *ceilingplane3d = Thread->PlaneList->FindPlane(
|
|
|
|
tempsec.ceilingplane,
|
|
|
|
tempsec.GetTexture(sector_t::ceiling),
|
|
|
|
ceilinglightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()),
|
|
|
|
tempsec.GetAlpha(sector_t::ceiling),
|
2017-02-04 18:13:56 +00:00
|
|
|
!!(clip3d->fakeFloor->fakeFloor->flags & FF_ADDITIVETRANS),
|
2018-05-11 15:00:12 +00:00
|
|
|
tempsec.planes[position].xform,
|
|
|
|
tempsec.sky,
|
2017-01-12 20:29:19 +00:00
|
|
|
nullptr,
|
2018-03-08 03:05:35 +00:00
|
|
|
basecolormap,
|
|
|
|
Fake3DOpaque::FakeCeiling,
|
|
|
|
fakeAlpha);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
ceilingplane3d->AddLights(Thread, tempsec.lighthead);
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2018-05-11 15:00:12 +00:00
|
|
|
FakeDrawLoop(sub, &tempsec, nullptr, ceilingplane3d, foggy, basecolormap, Fake3DOpaque::FakeCeiling);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-11 14:02:36 +00:00
|
|
|
clip3d->fakeFloor = nullptr;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-04 14:39:47 +00:00
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
void RenderOpaquePass::RenderScene()
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-06-27 19:15:26 +00:00
|
|
|
if (Thread->MainThread)
|
|
|
|
WallCycles.Clock();
|
|
|
|
|
2018-05-06 00:54:03 +00:00
|
|
|
for (uint32_t sub : PvsSubsectors)
|
|
|
|
SubsectorDepths[sub] = 0xffffffff;
|
|
|
|
SubsectorDepths.resize(level.subsectors.Size(), 0xffffffff);
|
|
|
|
|
|
|
|
PvsSubsectors.clear();
|
2017-02-04 19:32:06 +00:00
|
|
|
SeenSpriteSectors.clear();
|
|
|
|
SeenActors.clear();
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
InSubsector = nullptr;
|
2017-03-17 00:42:37 +00:00
|
|
|
RenderBSPNode(level.HeadNode()); // The head node is the last node output.
|
2017-06-27 19:15:26 +00:00
|
|
|
|
|
|
|
if (Thread->MainThread)
|
|
|
|
WallCycles.Unclock();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
//
|
|
|
|
// RenderBSPNode
|
|
|
|
// Renders all subsectors below a given node, traversing subtree recursively.
|
|
|
|
// Just call with BSP root and -1.
|
|
|
|
// killough 5/2/98: reformatted, removed tail recursion
|
2017-01-03 17:57:48 +00:00
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
void RenderOpaquePass::RenderBSPNode(void *node)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-03-17 00:42:37 +00:00
|
|
|
if (level.nodes.Size() == 0)
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
2017-03-16 23:22:52 +00:00
|
|
|
RenderSubsector(&level.subsectors[0]);
|
2017-01-04 14:39:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (!((size_t)node & 1)) // Keep going until found a subsector
|
|
|
|
{
|
|
|
|
node_t *bsp = (node_t *)node;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Decide which side the view point is on.
|
2017-03-12 17:54:39 +00:00
|
|
|
int side = R_PointOnSide(Thread->Viewport->viewpoint.Pos, bsp);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Recursively divide front space (toward the viewer).
|
|
|
|
RenderBSPNode(bsp->children[side]);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
// Possibly divide back space (away from the viewer).
|
|
|
|
side ^= 1;
|
|
|
|
if (!CheckBBox(bsp->bbox[side]))
|
|
|
|
return;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-04 14:39:47 +00:00
|
|
|
node = bsp->children[side];
|
|
|
|
}
|
2017-03-09 18:54:41 +00:00
|
|
|
RenderSubsector((subsector_t *)((uint8_t *)node - 1));
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2016-12-01 01:38:32 +00:00
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
void RenderOpaquePass::ClearClip()
|
2017-01-04 14:39:47 +00:00
|
|
|
{
|
|
|
|
fillshort(floorclip, viewwidth, viewheight);
|
2018-03-27 15:13:10 +00:00
|
|
|
fillshort(ceilingclip, viewwidth, 0);
|
2017-01-04 14:39:47 +00:00
|
|
|
}
|
2017-01-11 14:02:36 +00:00
|
|
|
|
2017-01-12 20:29:19 +00:00
|
|
|
void RenderOpaquePass::AddSprites(sector_t *sec, int lightlevel, WaterFakeSide fakeside, bool foggy, FDynamicColormap *basecolormap)
|
2017-01-11 14:02:36 +00:00
|
|
|
{
|
|
|
|
// BSP is traversed by subsector.
|
|
|
|
// A sector might have been split into several
|
|
|
|
// subsectors during BSP building.
|
|
|
|
// Thus we check whether it was already added.
|
2017-02-04 19:32:06 +00:00
|
|
|
if (sec->touching_renderthings == nullptr || SeenSpriteSectors.find(sec) != SeenSpriteSectors.end()/*|| sec->validcount == validcount*/)
|
2017-01-11 14:02:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Well, now it will be done.
|
2017-02-04 19:32:06 +00:00
|
|
|
//sec->validcount = validcount;
|
|
|
|
SeenSpriteSectors.insert(sec);
|
2017-01-11 14:02:36 +00:00
|
|
|
|
2017-03-12 17:54:39 +00:00
|
|
|
int spriteshade = LightVisibility::LightLevelToShade(lightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy);
|
2017-01-11 14:02:36 +00:00
|
|
|
|
|
|
|
// Handle all things in sector.
|
|
|
|
for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext)
|
|
|
|
{
|
|
|
|
auto thing = p->m_thing;
|
2017-02-04 19:32:06 +00:00
|
|
|
if (SeenActors.find(thing) != SeenActors.end()) continue;
|
|
|
|
SeenActors.insert(thing);
|
|
|
|
//if (thing->validcount == validcount) continue;
|
|
|
|
//thing->validcount = validcount;
|
2017-01-11 14:02:36 +00:00
|
|
|
|
2017-04-11 22:07:41 +00:00
|
|
|
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
2017-01-11 14:02:36 +00:00
|
|
|
if (cvar != nullptr && *cvar >= 0)
|
|
|
|
{
|
2017-03-12 17:54:39 +00:00
|
|
|
double dist = (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared();
|
2017-01-11 14:02:36 +00:00
|
|
|
double check = (double)**cvar;
|
|
|
|
if (dist >= check * check)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find fake level
|
2017-01-17 01:32:23 +00:00
|
|
|
F3DFloor *fakeceiling = nullptr;
|
|
|
|
F3DFloor *fakefloor = nullptr;
|
2017-01-11 14:02:36 +00:00
|
|
|
for (auto rover : thing->Sector->e->XFloor.ffloors)
|
|
|
|
{
|
|
|
|
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES)) continue;
|
|
|
|
if (!(rover->flags & FF_SOLID) || rover->alpha != 255) continue;
|
|
|
|
if (!fakefloor)
|
|
|
|
{
|
|
|
|
if (!rover->top.plane->isSlope())
|
|
|
|
{
|
|
|
|
if (rover->top.plane->ZatPoint(0., 0.) <= thing->Z()) fakefloor = rover;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rover->bottom.plane->isSlope())
|
|
|
|
{
|
|
|
|
if (rover->bottom.plane->ZatPoint(0., 0.) >= thing->Top()) fakeceiling = rover;
|
|
|
|
}
|
|
|
|
}
|
2017-01-11 16:59:29 +00:00
|
|
|
|
|
|
|
if (IsPotentiallyVisible(thing))
|
|
|
|
{
|
|
|
|
ThingSprite sprite;
|
2018-06-17 12:56:34 +00:00
|
|
|
int spritenum = thing->sprite;
|
|
|
|
bool isPicnumOverride = thing->picnum.isValid();
|
|
|
|
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
|
|
|
if (r_modelscene && modelframe && (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared() < model_distance_cull)
|
|
|
|
{
|
|
|
|
DVector3 pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
|
|
|
|
RenderModel::Project(Thread, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
|
|
|
|
}
|
|
|
|
else if (GetThingSprite(thing, sprite))
|
2017-01-11 16:59:29 +00:00
|
|
|
{
|
2017-01-17 01:16:13 +00:00
|
|
|
FDynamicColormap *thingColormap = basecolormap;
|
2017-01-17 01:27:59 +00:00
|
|
|
int thingShade = spriteshade;
|
2017-01-17 01:16:13 +00:00
|
|
|
if (sec->sectornum != thing->Sector->sectornum) // compare sectornums to account for R_FakeFlat copies.
|
|
|
|
{
|
|
|
|
int lightlevel = thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight();
|
2017-03-12 17:54:39 +00:00
|
|
|
thingShade = LightVisibility::LightLevelToShade(lightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy);
|
2017-03-15 23:56:03 +00:00
|
|
|
thingColormap = GetColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], true);
|
2017-01-17 01:16:13 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 16:59:29 +00:00
|
|
|
if ((sprite.renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
|
|
|
|
{
|
2017-05-23 07:37:38 +00:00
|
|
|
RenderWallSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, thingShade, foggy, thingColormap);
|
2017-01-11 16:59:29 +00:00
|
|
|
}
|
|
|
|
else if (sprite.voxel)
|
|
|
|
{
|
2017-02-03 23:25:37 +00:00
|
|
|
RenderVoxel::Project(Thread, thing, sprite.pos, sprite.voxel, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap);
|
2017-01-11 16:59:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-17 12:56:34 +00:00
|
|
|
RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap);
|
2017-01-11 16:59:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-11 14:02:36 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-11 16:59:29 +00:00
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
bool RenderOpaquePass::IsPotentiallyVisible(AActor *thing)
|
2017-01-11 16:59:29 +00:00
|
|
|
{
|
|
|
|
// Don't waste time projecting sprites that are definitely not visible.
|
|
|
|
if (thing == nullptr ||
|
|
|
|
(thing->renderflags & RF_INVISIBLE) ||
|
|
|
|
!thing->RenderStyle.IsVisible(thing->Alpha) ||
|
|
|
|
!thing->IsVisibleToPlayer() ||
|
|
|
|
!thing->IsInsideVisibleAngles())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-07-29 17:59:36 +00:00
|
|
|
// check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature,
|
|
|
|
// check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it.
|
2017-08-13 13:42:08 +00:00
|
|
|
if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) ||
|
2017-07-29 17:59:36 +00:00
|
|
|
(!!(thing->RenderHidden & r_renderercaps)))
|
2017-07-29 17:59:36 +00:00
|
|
|
return false;
|
|
|
|
|
2017-01-11 16:59:29 +00:00
|
|
|
// [ZZ] Or less definitely not visible (hue)
|
|
|
|
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal.
|
2017-02-03 23:25:37 +00:00
|
|
|
RenderPortal *renderportal = Thread->Portal.get();
|
2017-01-11 16:59:29 +00:00
|
|
|
if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && !!P_PointOnLineSidePrecise(thing->Pos(), renderportal->CurrentPortal->dst))
|
|
|
|
return false;
|
|
|
|
|
2017-07-02 20:35:40 +00:00
|
|
|
double distanceSquared = (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared();
|
|
|
|
if (distanceSquared > sprite_distance_cull)
|
|
|
|
return false;
|
|
|
|
|
2017-01-11 16:59:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-11 19:42:39 +00:00
|
|
|
bool RenderOpaquePass::GetThingSprite(AActor *thing, ThingSprite &sprite)
|
2017-01-11 16:59:29 +00:00
|
|
|
{
|
2017-03-12 17:54:39 +00:00
|
|
|
sprite.pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
|
|
|
|
sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac);
|
2017-01-11 16:59:29 +00:00
|
|
|
|
|
|
|
sprite.spritenum = thing->sprite;
|
|
|
|
sprite.tex = nullptr;
|
|
|
|
sprite.voxel = nullptr;
|
|
|
|
sprite.spriteScale = thing->Scale;
|
|
|
|
sprite.renderflags = thing->renderflags;
|
|
|
|
|
2017-02-09 11:18:40 +00:00
|
|
|
if (thing->player != nullptr)
|
|
|
|
{
|
|
|
|
P_CheckPlayerSprite(thing, sprite.spritenum, sprite.spriteScale);
|
|
|
|
}
|
|
|
|
|
2017-01-11 16:59:29 +00:00
|
|
|
if (thing->picnum.isValid())
|
|
|
|
{
|
|
|
|
sprite.picnum = thing->picnum;
|
|
|
|
|
|
|
|
sprite.tex = TexMan(sprite.picnum);
|
2018-03-25 18:26:16 +00:00
|
|
|
if (sprite.tex->UseType == ETextureType::Null)
|
2017-01-11 16:59:29 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sprite.tex->Rotations != 0xFFFF)
|
|
|
|
{
|
|
|
|
// choose a different rotation based on player view
|
|
|
|
spriteframe_t *sprframe = &SpriteFrames[sprite.tex->Rotations];
|
2017-03-12 17:54:39 +00:00
|
|
|
DAngle ang = (sprite.pos - Thread->Viewport->viewpoint.Pos).Angle();
|
2017-01-11 16:59:29 +00:00
|
|
|
angle_t rot;
|
|
|
|
if (sprframe->Texture[0] == sprframe->Texture[1])
|
|
|
|
{
|
|
|
|
if (thing->flags7 & MF7_SPRITEANGLE)
|
|
|
|
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
|
|
|
|
else
|
|
|
|
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (thing->flags7 & MF7_SPRITEANGLE)
|
|
|
|
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
|
|
|
else
|
|
|
|
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
|
|
|
}
|
|
|
|
sprite.picnum = sprframe->Texture[rot];
|
|
|
|
if (sprframe->Flip & (1 << rot))
|
|
|
|
{
|
|
|
|
sprite.renderflags ^= RF_XFLIP;
|
|
|
|
}
|
|
|
|
sprite.tex = TexMan[sprite.picnum]; // Do not animate the rotation
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// decide which texture to use for the sprite
|
|
|
|
if ((unsigned)sprite.spritenum >= sprites.Size())
|
|
|
|
{
|
|
|
|
DPrintf(DMSG_ERROR, "R_ProjectSprite: invalid sprite number %u\n", sprite.spritenum);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
spritedef_t *sprdef = &sprites[sprite.spritenum];
|
|
|
|
if (thing->frame >= sprdef->numframes)
|
|
|
|
{
|
|
|
|
// If there are no frames at all for this sprite, don't draw it.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-16 12:49:34 +00:00
|
|
|
auto &viewpoint = Thread->Viewport->viewpoint;
|
|
|
|
DAngle sprangle = thing->GetSpriteAngle((sprite.pos - viewpoint.Pos).Angle(), viewpoint.TicFrac);
|
|
|
|
bool flipX;
|
2017-05-03 17:47:27 +00:00
|
|
|
|
2017-06-01 17:13:30 +00:00
|
|
|
FTextureID tex = sprdef->GetSpriteFrame(thing->frame, -1, sprangle, &flipX, !!(thing->renderflags & RF_SPRITEFLIP));
|
2017-05-31 22:26:25 +00:00
|
|
|
if (tex.isValid())
|
2017-01-11 16:59:29 +00:00
|
|
|
{
|
2017-05-31 22:26:25 +00:00
|
|
|
if (flipX)
|
|
|
|
{
|
|
|
|
sprite.renderflags ^= RF_XFLIP;
|
|
|
|
}
|
|
|
|
sprite.tex = TexMan[tex]; // Do not animate the rotation
|
2017-01-11 16:59:29 +00:00
|
|
|
}
|
2017-05-31 22:26:25 +00:00
|
|
|
|
2017-01-11 16:59:29 +00:00
|
|
|
if (r_drawvoxels)
|
|
|
|
{
|
2017-03-16 12:49:34 +00:00
|
|
|
sprite.voxel = SpriteFrames[sprdef->spriteframes + thing->frame].Voxel;
|
2017-01-11 16:59:29 +00:00
|
|
|
}
|
2017-05-31 22:26:25 +00:00
|
|
|
|
|
|
|
if (sprite.voxel == nullptr && !tex.isValid())
|
|
|
|
return false;
|
2017-01-11 16:59:29 +00:00
|
|
|
}
|
|
|
|
|
2018-03-25 18:26:16 +00:00
|
|
|
if (sprite.voxel == nullptr && (sprite.tex == nullptr || sprite.tex->UseType == ETextureType::Null))
|
2017-01-11 16:59:29 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sprite.spriteScale.Y < 0)
|
|
|
|
{
|
|
|
|
sprite.spriteScale.Y = -sprite.spriteScale.Y;
|
|
|
|
sprite.renderflags ^= RF_YFLIP;
|
|
|
|
}
|
|
|
|
if (sprite.spriteScale.X < 0)
|
|
|
|
{
|
|
|
|
sprite.spriteScale.X = -sprite.spriteScale.X;
|
|
|
|
sprite.renderflags ^= RF_XFLIP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2016-12-01 01:38:32 +00:00
|
|
|
}
|