qzdoom/src/gl/scene/gl_fakeflat.cpp
Christoph Oelckers 9a24771a7d - refactored FDynamicColormap out of sector_t.
This has increasingly become an obstacle with the hardware renderer, so now the values are being stored as plain data in the sector, with the software renderer getting the actual color tables when needed. While this is a bit slower than storing the pregenerated colormap, in realistic situations the added time is mostly negligible in the microseconds range.
2017-03-15 22:04:59 +01:00

392 lines
13 KiB
C++

//
//---------------------------------------------------------------------------
//
// Copyright(C) 2001-2016 Christoph Oelckers
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_fakeflat.cpp
** Fake flat functions to render stacked sectors
**
*/
#include "p_lnspec.h"
#include "p_local.h"
#include "g_levellocals.h"
#include "a_sharedglobal.h"
#include "r_sky.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/scene/gl_scenedrawer.h"
#include "gl/data/gl_data.h"
//==========================================================================
//
// Check whether the player can look beyond this line
//
//==========================================================================
CVAR(Bool, gltest_slopeopt, false, 0)
bool gl_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector)
{
line_t *linedef = sidedef->linedef;
double bs_floorheight1;
double bs_floorheight2;
double bs_ceilingheight1;
double bs_ceilingheight2;
double fs_floorheight1;
double fs_floorheight2;
double fs_ceilingheight1;
double fs_ceilingheight2;
// Mirrors and horizons always block the view
//if (linedef->special==Line_Mirror || linedef->special==Line_Horizon) return true;
// Lines with portals must never block.
// Portals which require the sky flat are excluded here, because for them the special sky semantics apply.
if (!(frontsector->GetPortal(sector_t::ceiling)->mFlags & PORTSF_SKYFLATONLY) ||
!(frontsector->GetPortal(sector_t::floor)->mFlags & PORTSF_SKYFLATONLY) ||
!(backsector->GetPortal(sector_t::ceiling)->mFlags & PORTSF_SKYFLATONLY) ||
!(backsector->GetPortal(sector_t::floor)->mFlags & PORTSF_SKYFLATONLY))
{
return false;
}
// on large levels this distinction can save some time
// That's a lot of avoided multiplications if there's a lot to see!
if (frontsector->ceilingplane.isSlope())
{
fs_ceilingheight1 = frontsector->ceilingplane.ZatPoint(linedef->v1);
fs_ceilingheight2 = frontsector->ceilingplane.ZatPoint(linedef->v2);
}
else
{
fs_ceilingheight2 = fs_ceilingheight1 = frontsector->ceilingplane.fD();
}
if (frontsector->floorplane.isSlope())
{
fs_floorheight1 = frontsector->floorplane.ZatPoint(linedef->v1);
fs_floorheight2 = frontsector->floorplane.ZatPoint(linedef->v2);
}
else
{
fs_floorheight2 = fs_floorheight1 = -frontsector->floorplane.fD();
}
if (backsector->ceilingplane.isSlope())
{
bs_ceilingheight1 = backsector->ceilingplane.ZatPoint(linedef->v1);
bs_ceilingheight2 = backsector->ceilingplane.ZatPoint(linedef->v2);
}
else
{
bs_ceilingheight2 = bs_ceilingheight1 = backsector->ceilingplane.fD();
}
if (backsector->floorplane.isSlope())
{
bs_floorheight1 = backsector->floorplane.ZatPoint(linedef->v1);
bs_floorheight2 = backsector->floorplane.ZatPoint(linedef->v2);
}
else
{
bs_floorheight2 = bs_floorheight1 = -backsector->floorplane.fD();
}
// now check for closed sectors!
if (bs_ceilingheight1 <= fs_floorheight1 && bs_ceilingheight2 <= fs_floorheight2)
{
FTexture * tex = TexMan(sidedef->GetTexture(side_t::top));
if (!tex || tex->UseType == FTexture::TEX_Null) return false;
if (backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false;
return true;
}
if (fs_ceilingheight1 <= bs_floorheight1 && fs_ceilingheight2 <= bs_floorheight2)
{
FTexture * tex = TexMan(sidedef->GetTexture(side_t::bottom));
if (!tex || tex->UseType == FTexture::TEX_Null) return false;
// properly render skies (consider door "open" if both floors are sky):
if (backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false;
return true;
}
if (bs_ceilingheight1 <= bs_floorheight1 && bs_ceilingheight2 <= bs_floorheight2)
{
// preserve a kind of transparent door/lift special effect:
if (bs_ceilingheight1 < fs_ceilingheight1 || bs_ceilingheight2 < fs_ceilingheight2)
{
FTexture * tex = TexMan(sidedef->GetTexture(side_t::top));
if (!tex || tex->UseType == FTexture::TEX_Null) return false;
}
if (bs_floorheight1 > fs_floorheight1 || bs_floorheight2 > fs_floorheight2)
{
FTexture * tex = TexMan(sidedef->GetTexture(side_t::bottom));
if (!tex || tex->UseType == FTexture::TEX_Null) return false;
}
if (backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false;
if (backsector->GetTexture(sector_t::floor) == skyflatnum && frontsector->GetTexture(sector_t::floor)
== skyflatnum) return false;
return true;
}
return false;
}
//==========================================================================
//
// check for levels with exposed lower areas
//
//==========================================================================
void GLSceneDrawer::CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector)
{
if (in_area == area_default &&
(backsector->heightsec && !(backsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)) &&
(!frontsector->heightsec || frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
{
sector_t * s = backsector->heightsec;
double cz1 = frontsector->ceilingplane.ZatPoint(v1);
double cz2 = frontsector->ceilingplane.ZatPoint(v2);
double fz1 = s->floorplane.ZatPoint(v1);
double fz2 = s->floorplane.ZatPoint(v2);
// allow some tolerance in case slopes are involved
if (cz1 <= fz1 + 1. / 100 && cz2 <= fz2 + 1. / 100)
in_area = area_below;
else
in_area = area_normal;
}
}
//==========================================================================
//
// This is mostly like R_FakeFlat but with a few alterations necessitated
// by hardware rendering
//
//==========================================================================
sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back)
{
if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || sec->heightsec==sec)
{
// check for backsectors with the ceiling lower than the floor. These will create
// visual glitches because upper amd lower textures overlap.
if (back && sec->planes[sector_t::floor].TexZ > sec->planes[sector_t::ceiling].TexZ)
{
if (!sec->floorplane.isSlope() && !sec->ceilingplane.isSlope())
{
*dest = *sec;
dest->ceilingplane=sec->floorplane;
dest->ceilingplane.FlipVert();
dest->planes[sector_t::ceiling].TexZ = dest->planes[sector_t::floor].TexZ;
dest->ClearPortal(sector_t::ceiling);
dest->ClearPortal(sector_t::floor);
return dest;
}
}
return sec;
}
#ifdef _DEBUG
if (sec->sectornum==560)
{
int a = 0;
}
#endif
if (in_area==area_above)
{
if (sec->heightsec->MoreFlags&SECF_FAKEFLOORONLY /*|| sec->GetTexture(sector_t::ceiling)==skyflatnum*/) in_area=area_normal;
}
int diffTex = (sec->heightsec->MoreFlags & SECF_CLIPFAKEPLANES);
sector_t * s = sec->heightsec;
#if 0
*dest=*sec; // This will invoke the copy operator which isn't really needed here. Memcpy is faster.
#else
memcpy(dest, sec, sizeof(sector_t));
#endif
// Replace floor and ceiling height with control sector's heights.
if (diffTex)
{
if (s->floorplane.CopyPlaneIfValid (&dest->floorplane, &sec->ceilingplane))
{
dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
dest->SetPlaneTexZ(sector_t::floor, s->GetPlaneTexZ(sector_t::floor));
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::vbo_fakefloor];
dest->vboheight[sector_t::floor] = s->vboheight[sector_t::floor];
}
else if (s->MoreFlags & SECF_FAKEFLOORONLY)
{
if (in_area==area_below)
{
dest->CopyColors(s);
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
dest->ChangeFlags(sector_t::ceiling, -1, s->GetFlags(sector_t::ceiling));
}
return dest;
}
return sec;
}
}
else
{
dest->SetPlaneTexZ(sector_t::floor, s->GetPlaneTexZ(sector_t::floor));
dest->floorplane = s->floorplane;
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::vbo_fakefloor];
dest->vboheight[sector_t::floor] = s->vboheight[sector_t::floor];
}
if (!(s->MoreFlags&SECF_FAKEFLOORONLY))
{
if (diffTex)
{
if (s->ceilingplane.CopyPlaneIfValid (&dest->ceilingplane, &sec->floorplane))
{
dest->SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
dest->SetPlaneTexZ(sector_t::ceiling, s->GetPlaneTexZ(sector_t::ceiling));
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakeceiling];
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::ceiling];
}
}
else
{
dest->ceilingplane = s->ceilingplane;
dest->SetPlaneTexZ(sector_t::ceiling, s->GetPlaneTexZ(sector_t::ceiling));
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakeceiling];
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::ceiling];
}
}
if (in_area==area_below)
{
dest->CopyColors(s);
dest->SetPlaneTexZ(sector_t::floor, sec->GetPlaneTexZ(sector_t::floor));
dest->SetPlaneTexZ(sector_t::ceiling, s->GetPlaneTexZ(sector_t::floor));
dest->floorplane=sec->floorplane;
dest->ceilingplane=s->floorplane;
dest->ceilingplane.FlipVert();
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::floor];
dest->vboheight[sector_t::floor] = sec->vboheight[sector_t::floor];
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakefloor];
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::floor];
dest->ClearPortal(sector_t::ceiling);
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
}
if (!back)
{
dest->SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
dest->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
//dest->ceilingplane = s->floorplane;
if (s->GetTexture(sector_t::ceiling) == skyflatnum)
{
dest->SetTexture(sector_t::ceiling, dest->GetTexture(sector_t::floor), false);
//dest->floorplane = dest->ceilingplane;
//dest->floorplane.FlipVert ();
//dest->floorplane.ChangeHeight (+1);
dest->planes[sector_t::ceiling].xform = dest->planes[sector_t::floor].xform;
}
else
{
dest->SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
dest->planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
}
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
dest->ChangeFlags(sector_t::ceiling, -1, s->GetFlags(sector_t::ceiling));
}
}
}
else if (in_area == area_above)
{
dest->CopyColors(s);
dest->SetPlaneTexZ(sector_t::ceiling, sec->GetPlaneTexZ(sector_t::ceiling));
dest->SetPlaneTexZ(sector_t::floor, s->GetPlaneTexZ(sector_t::ceiling));
dest->ceilingplane = sec->ceilingplane;
dest->floorplane = s->ceilingplane;
dest->floorplane.FlipVert();
dest->vboindex[sector_t::floor] = sec->vboindex[sector_t::vbo_fakeceiling];
dest->vboheight[sector_t::floor] = s->vboheight[sector_t::ceiling];
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::ceiling];
dest->vboheight[sector_t::ceiling] = sec->vboheight[sector_t::ceiling];
dest->ClearPortal(sector_t::floor);
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
}
if (!back)
{
dest->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
dest->planes[sector_t::ceiling].xform = dest->planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
if (s->GetTexture(sector_t::floor) != skyflatnum)
{
dest->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
dest->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
}
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
dest->ChangeFlags(sector_t::ceiling, -1, s->GetFlags(sector_t::ceiling));
}
}
}
return dest;
}