mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-03-01 23:31:16 +00:00
'ceilingterrain' is needed because the top of 3D-floors refers to the model sector's ceiling, so in order to give a 3D floor a terrain it must be assignable to the sector's ceiling. Note that although it is basically the same property, its actual function bears no relevance to its use in Eternity.
1082 lines
25 KiB
C++
1082 lines
25 KiB
C++
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// This source is available for distribution and/or modification
|
|
// only under the terms of the DOOM Source Code License as
|
|
// published by id Software. All rights reserved.
|
|
//
|
|
// The source is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
|
// for more details.
|
|
//
|
|
// $Log:$
|
|
//
|
|
// DESCRIPTION:
|
|
// Sector utility functions.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "p_spec.h"
|
|
#include "c_cvars.h"
|
|
#include "doomstat.h"
|
|
#include "g_level.h"
|
|
#include "nodebuild.h"
|
|
#include "p_terrain.h"
|
|
#include "po_man.h"
|
|
#include "farchive.h"
|
|
#include "r_utility.h"
|
|
#include "a_sharedglobal.h"
|
|
#include "r_data/colormaps.h"
|
|
|
|
|
|
// [RH]
|
|
// P_NextSpecialSector()
|
|
//
|
|
// Returns the next special sector attached to this sector
|
|
// with a certain special.
|
|
sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
|
|
{
|
|
sector_t *tsec;
|
|
int i;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line_t *ln = lines[i];
|
|
|
|
if (NULL != (tsec = getNextSector (ln, this)) &&
|
|
tsec != nogood &&
|
|
tsec->special == type)
|
|
{
|
|
return tsec;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// P_FindLowestFloorSurrounding()
|
|
// FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindLowestFloorSurrounding (vertex_t **v) const
|
|
{
|
|
int i;
|
|
sector_t *other;
|
|
line_t *check;
|
|
fixed_t floor;
|
|
fixed_t ofloor;
|
|
vertex_t *spot;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
floor = floorplane.ZatPoint (spot);
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v1))
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v2))
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return floor;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_FindHighestFloorSurrounding()
|
|
// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindHighestFloorSurrounding (vertex_t **v) const
|
|
{
|
|
int i;
|
|
line_t *check;
|
|
sector_t *other;
|
|
fixed_t floor;
|
|
fixed_t ofloor;
|
|
vertex_t *spot;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
floor = FIXED_MIN;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
if (ofloor > floor)
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
if (ofloor > floor)
|
|
{
|
|
floor = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return floor;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_FindNextHighestFloor()
|
|
//
|
|
// Passed a sector and a floor height, returns the fixed point value
|
|
// of the smallest floor height in a surrounding sector larger than
|
|
// the floor height passed. If no such height exists the floorheight
|
|
// passed is returned.
|
|
//
|
|
// Rewritten by Lee Killough to avoid fixed array and to be faster
|
|
//
|
|
fixed_t sector_t::FindNextHighestFloor (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t ofloor, floor;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
height = floorplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
floor = floorplane.ZatPoint (check->v1);
|
|
if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = ofloor - floor;
|
|
height = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
floor = floorplane.ZatPoint (check->v2);
|
|
if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = ofloor - floor;
|
|
height = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindNextLowestFloor()
|
|
//
|
|
// Passed a sector and a floor height, returns the fixed point value
|
|
// of the largest floor height in a surrounding sector smaller than
|
|
// the floor height passed. If no such height exists the floorheight
|
|
// passed is returned.
|
|
//
|
|
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
|
|
//
|
|
fixed_t sector_t::FindNextLowestFloor (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t ofloor, floor;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
|
|
|
|
spot = lines[0]->v1;
|
|
height = floorplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
ofloor = other->floorplane.ZatPoint (check->v1);
|
|
floor = floorplane.ZatPoint (check->v1);
|
|
if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = floor - ofloor;
|
|
height = ofloor;
|
|
spot = check->v1;
|
|
}
|
|
ofloor = other->floorplane.ZatPoint (check->v2);
|
|
floor = floorplane.ZatPoint (check->v2);
|
|
if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
|
|
{
|
|
heightdiff = floor - ofloor;
|
|
height = ofloor;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// P_FindNextLowestCeiling()
|
|
//
|
|
// Passed a sector and a ceiling height, returns the fixed point value
|
|
// of the largest ceiling height in a surrounding sector smaller than
|
|
// the ceiling height passed. If no such height exists the ceiling height
|
|
// passed is returned.
|
|
//
|
|
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
|
|
//
|
|
fixed_t sector_t::FindNextLowestCeiling (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t oceil, ceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = ceilingplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
ceil = ceilingplane.ZatPoint (check->v1);
|
|
if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = ceil - oceil;
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
ceil = ceilingplane.ZatPoint (check->v2);
|
|
if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = ceil - oceil;
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// P_FindNextHighestCeiling()
|
|
//
|
|
// Passed a sector and a ceiling height, returns the fixed point value
|
|
// of the smallest ceiling height in a surrounding sector larger than
|
|
// the ceiling height passed. If no such height exists the ceiling height
|
|
// passed is returned.
|
|
//
|
|
// jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
|
|
//
|
|
fixed_t sector_t::FindNextHighestCeiling (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t heightdiff;
|
|
fixed_t oceil, ceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = ceilingplane.ZatPoint (spot);
|
|
heightdiff = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
ceil = ceilingplane.ZatPoint (check->v1);
|
|
if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = oceil - ceil;
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
ceil = ceilingplane.ZatPoint (check->v2);
|
|
if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
|
|
{
|
|
heightdiff = oceil - ceil;
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindLowestCeilingSurrounding (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t oceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = FIXED_MAX;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
if (oceil < height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
if (oceil < height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
|
|
//
|
|
// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
|
|
//
|
|
fixed_t sector_t::FindHighestCeilingSurrounding (vertex_t **v) const
|
|
{
|
|
fixed_t height;
|
|
fixed_t oceil;
|
|
sector_t *other;
|
|
vertex_t *spot;
|
|
line_t *check;
|
|
int i;
|
|
|
|
if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
|
|
|
|
spot = lines[0]->v1;
|
|
height = FIXED_MIN;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
check = lines[i];
|
|
if (NULL != (other = getNextSector (check, this)))
|
|
{
|
|
oceil = other->ceilingplane.ZatPoint (check->v1);
|
|
if (oceil > height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v1;
|
|
}
|
|
oceil = other->ceilingplane.ZatPoint (check->v2);
|
|
if (oceil > height)
|
|
{
|
|
height = oceil;
|
|
spot = check->v2;
|
|
}
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// P_FindShortestTextureAround()
|
|
//
|
|
// Passed a sector number, returns the shortest lower texture on a
|
|
// linedef bounding the sector.
|
|
//
|
|
// jff 02/03/98 Add routine to find shortest lower texture
|
|
//
|
|
|
|
static inline void CheckShortestTex (FTextureID texnum, fixed_t &minsize)
|
|
{
|
|
if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX)))
|
|
{
|
|
FTexture *tex = TexMan[texnum];
|
|
if (tex != NULL)
|
|
{
|
|
fixed_t h = tex->GetScaledHeight()<<FRACBITS;
|
|
if (h < minsize)
|
|
{
|
|
minsize = h;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fixed_t sector_t::FindShortestTextureAround () const
|
|
{
|
|
fixed_t minsize = FIXED_MAX;
|
|
|
|
for (int i = 0; i < linecount; i++)
|
|
{
|
|
if (lines[i]->flags & ML_TWOSIDED)
|
|
{
|
|
CheckShortestTex (lines[i]->sidedef[0]->GetTexture(side_t::bottom), minsize);
|
|
CheckShortestTex (lines[i]->sidedef[1]->GetTexture(side_t::bottom), minsize);
|
|
}
|
|
}
|
|
return minsize < FIXED_MAX ? minsize : TexMan[0]->GetHeight() * FRACUNIT;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindShortestUpperAround()
|
|
//
|
|
// Passed a sector number, returns the shortest upper texture on a
|
|
// linedef bounding the sector.
|
|
//
|
|
// Note: If no upper texture exists MAXINT is returned.
|
|
//
|
|
// jff 03/20/98 Add routine to find shortest upper texture
|
|
//
|
|
fixed_t sector_t::FindShortestUpperAround () const
|
|
{
|
|
fixed_t minsize = FIXED_MAX;
|
|
|
|
for (int i = 0; i < linecount; i++)
|
|
{
|
|
if (lines[i]->flags & ML_TWOSIDED)
|
|
{
|
|
CheckShortestTex (lines[i]->sidedef[0]->GetTexture(side_t::top), minsize);
|
|
CheckShortestTex (lines[i]->sidedef[1]->GetTexture(side_t::top), minsize);
|
|
}
|
|
}
|
|
return minsize < FIXED_MAX ? minsize : TexMan[0]->GetHeight() * FRACUNIT;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindModelFloorSector()
|
|
//
|
|
// Passed a floor height and a sector number, return a pointer to a
|
|
// a sector with that floor height across the lowest numbered two sided
|
|
// line surrounding the sector.
|
|
//
|
|
// Note: If no sector at that height bounds the sector passed, return NULL
|
|
//
|
|
// jff 02/03/98 Add routine to find numeric model floor
|
|
// around a sector specified by sector number
|
|
// jff 3/14/98 change first parameter to plain height to allow call
|
|
// from routine not using floormove_t
|
|
//
|
|
sector_t *sector_t::FindModelFloorSector (fixed_t floordestheight) const
|
|
{
|
|
int i;
|
|
sector_t *sec;
|
|
|
|
//jff 5/23/98 don't disturb sec->linecount while searching
|
|
// but allow early exit in old demos
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
sec = getNextSector (lines[i], this);
|
|
if (sec != NULL &&
|
|
(sec->floorplane.ZatPoint (lines[i]->v1) == floordestheight ||
|
|
sec->floorplane.ZatPoint (lines[i]->v2) == floordestheight))
|
|
{
|
|
return sec;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// P_FindModelCeilingSector()
|
|
//
|
|
// Passed a ceiling height and a sector number, return a pointer to a
|
|
// a sector with that ceiling height across the lowest numbered two sided
|
|
// line surrounding the sector.
|
|
//
|
|
// Note: If no sector at that height bounds the sector passed, return NULL
|
|
//
|
|
// jff 02/03/98 Add routine to find numeric model ceiling
|
|
// around a sector specified by sector number
|
|
// used only from generalized ceiling types
|
|
// jff 3/14/98 change first parameter to plain height to allow call
|
|
// from routine not using ceiling_t
|
|
//
|
|
sector_t *sector_t::FindModelCeilingSector (fixed_t floordestheight) const
|
|
{
|
|
int i;
|
|
sector_t *sec;
|
|
|
|
//jff 5/23/98 don't disturb sec->linecount while searching
|
|
// but allow early exit in old demos
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
sec = getNextSector (lines[i], this);
|
|
if (sec != NULL &&
|
|
(sec->ceilingplane.ZatPoint (lines[i]->v1) == floordestheight ||
|
|
sec->ceilingplane.ZatPoint (lines[i]->v2) == floordestheight))
|
|
{
|
|
return sec;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Find minimum light from an adjacent sector
|
|
//
|
|
int sector_t::FindMinSurroundingLight (int min) const
|
|
{
|
|
int i;
|
|
line_t* line;
|
|
sector_t* check;
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line = lines[i];
|
|
if (NULL != (check = getNextSector (line, this)) &&
|
|
check->lightlevel < min)
|
|
{
|
|
min = check->lightlevel;
|
|
}
|
|
}
|
|
return min;
|
|
}
|
|
|
|
//
|
|
// Find the highest point on the floor of the sector
|
|
//
|
|
fixed_t sector_t::FindHighestFloorPoint (vertex_t **v) const
|
|
{
|
|
int i;
|
|
line_t *line;
|
|
fixed_t height = FIXED_MIN;
|
|
fixed_t probeheight;
|
|
vertex_t *spot = NULL;
|
|
|
|
if ((floorplane.a | floorplane.b) == 0)
|
|
{
|
|
if (v != NULL)
|
|
{
|
|
if (linecount == 0) *v = &vertexes[0];
|
|
else *v = lines[0]->v1;
|
|
}
|
|
return -floorplane.d;
|
|
}
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line = lines[i];
|
|
probeheight = floorplane.ZatPoint (line->v1);
|
|
if (probeheight > height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v1;
|
|
}
|
|
probeheight = floorplane.ZatPoint (line->v2);
|
|
if (probeheight > height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v2;
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
//
|
|
// Find the lowest point on the ceiling of the sector
|
|
//
|
|
fixed_t sector_t::FindLowestCeilingPoint (vertex_t **v) const
|
|
{
|
|
int i;
|
|
line_t *line;
|
|
fixed_t height = FIXED_MAX;
|
|
fixed_t probeheight;
|
|
vertex_t *spot = NULL;
|
|
|
|
if ((ceilingplane.a | ceilingplane.b) == 0)
|
|
{
|
|
if (v != NULL)
|
|
{
|
|
if (linecount == 0) *v = &vertexes[0];
|
|
else *v = lines[0]->v1;
|
|
}
|
|
return ceilingplane.d;
|
|
}
|
|
|
|
for (i = 0; i < linecount; i++)
|
|
{
|
|
line = lines[i];
|
|
probeheight = ceilingplane.ZatPoint (line->v1);
|
|
if (probeheight < height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v1;
|
|
}
|
|
probeheight = ceilingplane.ZatPoint (line->v2);
|
|
if (probeheight < height)
|
|
{
|
|
height = probeheight;
|
|
spot = line->v2;
|
|
}
|
|
}
|
|
if (v != NULL)
|
|
*v = spot;
|
|
return height;
|
|
}
|
|
|
|
|
|
void sector_t::SetColor(int r, int g, int b, int desat)
|
|
{
|
|
PalEntry color = PalEntry (r,g,b);
|
|
ColorMap = GetSpecialLights (color, ColorMap->Fade, desat);
|
|
P_RecalculateAttachedLights(this);
|
|
}
|
|
|
|
void sector_t::SetFade(int r, int g, int b)
|
|
{
|
|
PalEntry fade = PalEntry (r,g,b);
|
|
ColorMap = GetSpecialLights (ColorMap->Color, fade, ColorMap->Desaturate);
|
|
P_RecalculateAttachedLights(this);
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// sector_t :: ClosestPoint
|
|
//
|
|
// Given a point (x,y), returns the point (ox,oy) on the sector's defining
|
|
// lines that is nearest to (x,y).
|
|
//
|
|
//===========================================================================
|
|
|
|
void sector_t::ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy) const
|
|
{
|
|
int i;
|
|
double x = fx, y = fy;
|
|
double bestdist = HUGE_VAL;
|
|
double bestx = 0, besty = 0;
|
|
|
|
for (i = 0; i < linecount; ++i)
|
|
{
|
|
vertex_t *v1 = lines[i]->v1;
|
|
vertex_t *v2 = lines[i]->v2;
|
|
double a = v2->x - v1->x;
|
|
double b = v2->y - v1->y;
|
|
double den = a*a + b*b;
|
|
double ix, iy, dist;
|
|
|
|
if (den == 0)
|
|
{ // Line is actually a point!
|
|
ix = v1->x;
|
|
iy = v1->y;
|
|
}
|
|
else
|
|
{
|
|
double num = (x - v1->x) * a + (y - v1->y) * b;
|
|
double u = num / den;
|
|
if (u <= 0)
|
|
{
|
|
ix = v1->x;
|
|
iy = v1->y;
|
|
}
|
|
else if (u >= 1)
|
|
{
|
|
ix = v2->x;
|
|
iy = v2->y;
|
|
}
|
|
else
|
|
{
|
|
ix = v1->x + u * a;
|
|
iy = v1->y + u * b;
|
|
}
|
|
}
|
|
a = (ix - x);
|
|
b = (iy - y);
|
|
dist = a*a + b*b;
|
|
if (dist < bestdist)
|
|
{
|
|
bestdist = dist;
|
|
bestx = ix;
|
|
besty = iy;
|
|
}
|
|
}
|
|
ox = fixed_t(bestx);
|
|
oy = fixed_t(besty);
|
|
}
|
|
|
|
|
|
bool sector_t::PlaneMoving(int pos)
|
|
{
|
|
if (pos == floor)
|
|
return (floordata != NULL || (planes[floor].Flags & PLANEF_BLOCKED));
|
|
else
|
|
return (ceilingdata != NULL || (planes[ceiling].Flags & PLANEF_BLOCKED));
|
|
}
|
|
|
|
|
|
int sector_t::GetFloorLight () const
|
|
{
|
|
if (GetFlags(sector_t::floor) & PLANEF_ABSLIGHTING)
|
|
{
|
|
return GetPlaneLight(floor);
|
|
}
|
|
else
|
|
{
|
|
return ClampLight(lightlevel + GetPlaneLight(floor));
|
|
}
|
|
}
|
|
|
|
int sector_t::GetCeilingLight () const
|
|
{
|
|
if (GetFlags(ceiling) & PLANEF_ABSLIGHTING)
|
|
{
|
|
return GetPlaneLight(ceiling);
|
|
}
|
|
else
|
|
{
|
|
return ClampLight(lightlevel + GetPlaneLight(ceiling));
|
|
}
|
|
}
|
|
|
|
|
|
ASkyViewpoint *sector_t::GetSkyBox(int which)
|
|
{
|
|
if (which == floor)
|
|
{
|
|
if (FloorSkyBox != NULL) return FloorSkyBox;
|
|
if (MoreFlags & SECF_NOFLOORSKYBOX) return NULL;
|
|
}
|
|
else
|
|
{
|
|
if (CeilingSkyBox != NULL) return CeilingSkyBox;
|
|
if (MoreFlags & SECF_NOCEILINGSKYBOX) return NULL;
|
|
}
|
|
return level.DefaultSkybox;
|
|
}
|
|
|
|
|
|
sector_t *sector_t::GetHeightSec() const
|
|
{
|
|
if (heightsec == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (e && e->XFloor.ffloors.Size())
|
|
{
|
|
// If any of these fake floors render their planes, ignore heightsec.
|
|
for (unsigned i = e->XFloor.ffloors.Size(); i-- > 0; )
|
|
{
|
|
if ((e->XFloor.ffloors[i]->flags & (FF_EXISTS | FF_RENDERPLANES)) == (FF_EXISTS | FF_RENDERPLANES))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return heightsec;
|
|
}
|
|
|
|
|
|
void sector_t::GetSpecial(secspecial_t *spec)
|
|
{
|
|
spec->special = special;
|
|
spec->damageamount = damageamount;
|
|
spec->damagetype = damagetype;
|
|
spec->damageinterval = damageinterval;
|
|
spec->leakydamage = leakydamage;
|
|
spec->Flags = Flags & SECF_SPECIALFLAGS;
|
|
}
|
|
|
|
void sector_t::SetSpecial(const secspecial_t *spec)
|
|
{
|
|
special = spec->special;
|
|
damageamount = spec->damageamount;
|
|
damagetype = spec->damagetype;
|
|
damageinterval = spec->damageinterval;
|
|
leakydamage = spec->leakydamage;
|
|
Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS);
|
|
}
|
|
|
|
void sector_t::TransferSpecial(sector_t *model)
|
|
{
|
|
special = model->special;
|
|
damageamount = model->damageamount;
|
|
damagetype = model->damagetype;
|
|
damageinterval = model->damageinterval;
|
|
leakydamage = model->leakydamage;
|
|
Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS);
|
|
}
|
|
|
|
int sector_t::GetTerrain(int pos) const
|
|
{
|
|
return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)];
|
|
}
|
|
|
|
FArchive &operator<< (FArchive &arc, secspecial_t &p)
|
|
{
|
|
if (SaveVersion < 4529)
|
|
{
|
|
short special;
|
|
arc << special;
|
|
sector_t sec;
|
|
P_InitSectorSpecial(&sec, special, true);
|
|
sec.GetSpecial(&p);
|
|
}
|
|
else
|
|
{
|
|
arc << p.special
|
|
<< p.damageamount
|
|
<< p.damagetype
|
|
<< p.damageinterval
|
|
<< p.leakydamage
|
|
<< p.Flags;
|
|
}
|
|
return arc;
|
|
}
|
|
|
|
|
|
|
|
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
|
|
{
|
|
bool copy = false;
|
|
|
|
// If the planes do not have matching slopes, then always copy them
|
|
// because clipping would require creating new sectors.
|
|
if (a != dest->a || b != dest->b || c != dest->c)
|
|
{
|
|
copy = true;
|
|
}
|
|
else if (opp->a != -dest->a || opp->b != -dest->b || opp->c != -dest->c)
|
|
{
|
|
if (d < dest->d)
|
|
{
|
|
copy = true;
|
|
}
|
|
}
|
|
else if (d < dest->d && d > -opp->d)
|
|
{
|
|
copy = true;
|
|
}
|
|
|
|
if (copy)
|
|
{
|
|
*dest = *this;
|
|
}
|
|
|
|
return copy;
|
|
}
|
|
|
|
FArchive &operator<< (FArchive &arc, secplane_t &plane)
|
|
{
|
|
arc << plane.a << plane.b << plane.c << plane.d;
|
|
//if (plane.c != 0)
|
|
{ // plane.c should always be non-0. Otherwise, the plane
|
|
// would be perfectly vertical.
|
|
plane.ic = DivScale32 (1, plane.c);
|
|
}
|
|
return arc;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_AlignFlat
|
|
//
|
|
//==========================================================================
|
|
|
|
bool P_AlignFlat (int linenum, int side, int fc)
|
|
{
|
|
line_t *line = lines + linenum;
|
|
sector_t *sec = side ? line->backsector : line->frontsector;
|
|
|
|
if (!sec)
|
|
return false;
|
|
|
|
fixed_t x = line->v1->x;
|
|
fixed_t y = line->v1->y;
|
|
|
|
angle_t angle = R_PointToAngle2 (x, y, line->v2->x, line->v2->y);
|
|
angle_t norm = (angle-ANGLE_90) >> ANGLETOFINESHIFT;
|
|
|
|
fixed_t dist = -DMulScale16 (finecosine[norm], x, finesine[norm], y);
|
|
|
|
if (side)
|
|
{
|
|
angle = angle + ANGLE_180;
|
|
dist = -dist;
|
|
}
|
|
|
|
sec->SetBase(fc, dist & ((1<<(FRACBITS+8))-1), 0-angle);
|
|
return true;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_BuildPolyBSP
|
|
//
|
|
//==========================================================================
|
|
static FNodeBuilder::FLevel PolyNodeLevel;
|
|
static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
|
|
|
|
void subsector_t::BuildPolyBSP()
|
|
{
|
|
assert((BSP == NULL || BSP->bDirty) && "BSP computed more than once");
|
|
|
|
// Set up level information for the node builder.
|
|
PolyNodeLevel.Sides = sides;
|
|
PolyNodeLevel.NumSides = numsides;
|
|
PolyNodeLevel.Lines = lines;
|
|
PolyNodeLevel.NumLines = numlines;
|
|
|
|
// Feed segs to the nodebuilder and build the nodes.
|
|
PolyNodeBuilder.Clear();
|
|
PolyNodeBuilder.AddSegs(firstline, numlines);
|
|
for (FPolyNode *pn = polys; pn != NULL; pn = pn->pnext)
|
|
{
|
|
PolyNodeBuilder.AddPolySegs(&pn->segs[0], (int)pn->segs.Size());
|
|
}
|
|
PolyNodeBuilder.BuildMini(false);
|
|
if (BSP == NULL)
|
|
{
|
|
BSP = new FMiniBSP;
|
|
}
|
|
PolyNodeBuilder.ExtractMini(BSP);
|
|
for (unsigned int i = 0; i < BSP->Subsectors.Size(); ++i)
|
|
{
|
|
BSP->Subsectors[i].sector = sector;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|
{
|
|
if (self < 0) self = 1;
|
|
else if (self > 2) self = 2;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
int side_t::GetLightLevel (bool foggy, int baselight, bool noabsolute, int *pfakecontrast) const
|
|
{
|
|
if (!noabsolute && (Flags & WALLF_ABSLIGHTING))
|
|
{
|
|
baselight = Light;
|
|
}
|
|
|
|
if (pfakecontrast != NULL)
|
|
{
|
|
*pfakecontrast = 0;
|
|
}
|
|
|
|
if (!foggy || level.flags3 & LEVEL3_FORCEFAKECONTRAST) // Don't do relative lighting in foggy sectors
|
|
{
|
|
if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0)
|
|
{
|
|
int rel;
|
|
if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) &&
|
|
linedef->dx != 0)
|
|
{
|
|
rel = xs_RoundToInt // OMG LEE KILLOUGH LIVES! :/
|
|
(
|
|
level.WallHorizLight
|
|
+ fabs(atan(double(linedef->dy) / linedef->dx) / 1.57079)
|
|
* (level.WallVertLight - level.WallHorizLight)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
rel = linedef->dx == 0 ? level.WallVertLight :
|
|
linedef->dy == 0 ? level.WallHorizLight : 0;
|
|
}
|
|
if (pfakecontrast != NULL)
|
|
{
|
|
*pfakecontrast = rel;
|
|
}
|
|
else
|
|
{
|
|
baselight += rel;
|
|
}
|
|
}
|
|
}
|
|
if (!(Flags & WALLF_ABSLIGHTING) && (!foggy || (Flags & WALLF_LIGHT_FOG)))
|
|
{
|
|
baselight += this->Light;
|
|
}
|
|
return baselight;
|
|
}
|
|
|