mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2025-05-31 01:10:52 +00:00
- Fixed: The resurrect cheat also needs to restore the player's radius. - Changed P_CheckPlayerSprites() so that it does not alter any actor data. It is now called by R_ProjectSprite() to modify the appropriate data right before it is needed for rendering.- Never set the player actor's scale to the skin's directly. Only do it indirectly through P_CheckPlayerSprite(). - Fixed: When P_Add3DFloor() adds the "inside" plane, it needs to copy the translucency flags from the original plane. - Added JLOSF_NOAUTOAIM flag for when you want to use A_JumpIfTargetInLOS in conjunction with something that never autoaims, such as a railgun. - Fixed: A_JumpIfTargetInLOS should use P_AimLineAttack() instead of P_BulletSlope(), because the latter intentionally checks to the sides of the aimed line. - Do not wake Oracle spectres that are dead. - Do not "wake" Oracle spectres that killed an Oracle. (Because if they killed it, they're obviously already awake. Also, we don't want them to end up targeting themselves.) - Fixed: Don't use the player skin in the cast call if the class being shown has been removed from the PlayerClasses array (and therefore does not have a valid default skin). - Do not double-scale player classes that use non-1.0 default scales. - P_DamageMobj() now returns the amount of damage actually done so that the bleed functions can perform based on the amount of damage actually taken after all modifications are done to it. However, if the damage is canceled away, blood will still spawn for the original damage amount rather than the modified amount. * Fixed decals not being lit correctly in the older lighting mode. * Fixed: 3D middle textures with a valid backsector need to be rendered as two-sided even if they lack the two-sided flag. (It works in ZDoom.) git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@1500 b0f79afe-0144-0410-b225-9a4edf0717df
913 lines
27 KiB
C++
913 lines
27 KiB
C++
/*
|
|
** p_3dfloor.cpp
|
|
**
|
|
** 3D-floor handling
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 2005-2008 Christoph Oelckers
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
** 4. Full disclosure of the entire project's source code, except for third
|
|
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
#include "templates.h"
|
|
#include "p_local.h"
|
|
#include "p_lnspec.h"
|
|
#include "w_wad.h"
|
|
#include "sc_man.h"
|
|
#include "g_level.h"
|
|
#include "r_data/colormaps.h"
|
|
|
|
#ifdef _3DFLOORS
|
|
EXTERN_CVAR(Int, vid_renderer)
|
|
|
|
//==========================================================================
|
|
//
|
|
// 3D Floors
|
|
//
|
|
//==========================================================================
|
|
|
|
//==========================================================================
|
|
//
|
|
// Wrappers to access the colormap information
|
|
//
|
|
//==========================================================================
|
|
|
|
FDynamicColormap *F3DFloor::GetColormap()
|
|
{
|
|
// If there's no fog in either model or target sector this is easy and fast.
|
|
if ((target->ColorMap->Fade == 0 && model->ColorMap->Fade == 0) || (flags & FF_FADEWALLS))
|
|
{
|
|
return model->ColorMap;
|
|
}
|
|
else
|
|
{
|
|
// We must create a new colormap combining the properties we need
|
|
return GetSpecialLights(model->ColorMap->Color, target->ColorMap->Fade, model->ColorMap->Desaturate);
|
|
}
|
|
}
|
|
|
|
PalEntry F3DFloor::GetBlend()
|
|
{
|
|
// The model sector's fog is used as blend unless FF_FADEWALLS is set.
|
|
if (!(flags & FF_FADEWALLS) && target->ColorMap->Fade != model->ColorMap->Fade)
|
|
{
|
|
return model->ColorMap->Fade;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void F3DFloor::UpdateColormap(FDynamicColormap *&map)
|
|
{
|
|
// If there's no fog in either model or target sector (or both have the same fog) this is easy and fast.
|
|
if ((target->ColorMap->Fade == 0 && model->ColorMap->Fade == 0) || (flags & FF_FADEWALLS) ||
|
|
target->ColorMap->Fade == model->ColorMap->Fade)
|
|
{
|
|
map = model->ColorMap;
|
|
}
|
|
else
|
|
{
|
|
// since rebuilding the map is not a cheap operation let's only do it if something really changed.
|
|
if (map->Color != model->ColorMap->Color || map->Fade != target->ColorMap->Fade ||
|
|
map->Desaturate != model->ColorMap->Desaturate)
|
|
{
|
|
map = GetSpecialLights(model->ColorMap->Color, target->ColorMap->Fade, model->ColorMap->Desaturate);
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// Add one 3D floor to the sector
|
|
//
|
|
//==========================================================================
|
|
static void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int alpha)
|
|
{
|
|
F3DFloor* ffloor;
|
|
unsigned i;
|
|
|
|
if(!(flags & FF_THISINSIDE)) {
|
|
for(i = 0; i < sec2->e->XFloor.attached.Size(); i++) if(sec2->e->XFloor.attached[i] == sec) return;
|
|
sec2->e->XFloor.attached.Push(sec);
|
|
}
|
|
|
|
//Add the floor
|
|
ffloor = new F3DFloor;
|
|
ffloor->top.model = ffloor->bottom.model = ffloor->model = sec2;
|
|
ffloor->target = sec;
|
|
ffloor->ceilingclip = ffloor->floorclip = NULL;
|
|
ffloor->validcount = 0;
|
|
|
|
if (!(flags&FF_THINFLOOR))
|
|
{
|
|
ffloor->bottom.plane = &sec2->floorplane;
|
|
ffloor->bottom.texture = &sec2->planes[sector_t::floor].Texture;
|
|
ffloor->bottom.texheight = &sec2->planes[sector_t::floor].TexZ;
|
|
ffloor->bottom.isceiling = sector_t::floor;
|
|
}
|
|
else
|
|
{
|
|
ffloor->bottom.plane = &sec2->ceilingplane;
|
|
ffloor->bottom.texture = &sec2->planes[sector_t::ceiling].Texture;
|
|
ffloor->bottom.texheight = &sec2->planes[sector_t::ceiling].TexZ;
|
|
ffloor->bottom.isceiling = sector_t::ceiling;
|
|
}
|
|
|
|
if (!(flags&FF_FIX))
|
|
{
|
|
ffloor->top.plane = &sec2->ceilingplane;
|
|
ffloor->top.texture = &sec2->planes[sector_t::ceiling].Texture;
|
|
ffloor->top.texheight = &sec2->planes[sector_t::ceiling].TexZ;
|
|
ffloor->toplightlevel = &sec2->lightlevel;
|
|
ffloor->top.isceiling = sector_t::ceiling;
|
|
}
|
|
else // FF_FIX is a special case to patch rendering holes
|
|
{
|
|
ffloor->top.plane = &sec->floorplane;
|
|
ffloor->top.texture = &sec2->planes[sector_t::floor].Texture;
|
|
ffloor->top.texheight = &sec2->planes[sector_t::floor].TexZ;
|
|
ffloor->toplightlevel = &sec->lightlevel;
|
|
ffloor->top.isceiling = sector_t::floor;
|
|
ffloor->top.model = sec;
|
|
}
|
|
|
|
// Hacks for Vavoom's idiotic implementation
|
|
if (flags&FF_INVERTSECTOR)
|
|
{
|
|
// switch the planes
|
|
F3DFloor::planeref sp = ffloor->top;
|
|
|
|
ffloor->top=ffloor->bottom;
|
|
ffloor->bottom=sp;
|
|
|
|
if (flags&FF_SWIMMABLE)
|
|
{
|
|
// Vavoom floods the lower part if it is swimmable.
|
|
// fortunately this plane won't be rendered - otherwise this wouldn't work...
|
|
ffloor->bottom.plane=&sec->floorplane;
|
|
ffloor->bottom.model=sec;
|
|
ffloor->bottom.isceiling = sector_t::floor;
|
|
}
|
|
}
|
|
|
|
ffloor->flags = flags;
|
|
ffloor->master = master;
|
|
ffloor->alpha = alpha;
|
|
ffloor->top.vindex = ffloor->bottom.vindex = -1;
|
|
|
|
// The engine cannot handle sloped translucent floors. Sorry
|
|
if (ffloor->top.plane->a || ffloor->top.plane->b || ffloor->bottom.plane->a || ffloor->bottom.plane->b)
|
|
{
|
|
ffloor->alpha = FRACUNIT;
|
|
ffloor->flags &= ~FF_ADDITIVETRANS;
|
|
}
|
|
|
|
if(flags & FF_THISINSIDE) {
|
|
// switch the planes
|
|
F3DFloor::planeref sp = ffloor->top;
|
|
ffloor->top=ffloor->bottom;
|
|
ffloor->bottom=sp;
|
|
}
|
|
|
|
sec->e->XFloor.ffloors.Push(ffloor);
|
|
|
|
// kg3D - software renderer only hack
|
|
// this is really required because of ceilingclip and floorclip
|
|
if((vid_renderer == 0) && (flags & FF_BOTHPLANES))
|
|
{
|
|
P_Add3DFloor(sec, sec2, master, FF_EXISTS | FF_THISINSIDE | FF_RENDERPLANES | FF_NOSHADE | FF_SEETHROUGH | FF_SHOOTTHROUGH |
|
|
(flags & (FF_INVERTSECTOR | FF_TRANSLUCENT | FF_ADDITIVETRANS)), alpha);
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// Creates all 3D floors defined by one linedef
|
|
//
|
|
//==========================================================================
|
|
static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
|
|
{
|
|
int s,i;
|
|
int flags;
|
|
int tag=line->args[0];
|
|
sector_t * sec = line->frontsector, * ss;
|
|
|
|
for (s=-1; (s = P_FindSectorFromTag(tag,s)) >= 0;)
|
|
{
|
|
ss=§ors[s];
|
|
|
|
if (param==0)
|
|
{
|
|
flags=FF_EXISTS|FF_RENDERALL|FF_SOLID|FF_INVERTSECTOR;
|
|
for (i=0;i<sec->linecount;i++)
|
|
{
|
|
line_t * l=sec->lines[i];
|
|
|
|
alpha=255;
|
|
if (l->special==Sector_SetContents && l->frontsector==sec)
|
|
{
|
|
alpha=clamp<int>(l->args[1], 0, 100);
|
|
if (l->args[2] & 1) flags &= ~FF_SOLID;
|
|
if (l->args[2] & 2) flags |= FF_SEETHROUGH;
|
|
if (l->args[2] & 4) flags |= FF_SHOOTTHROUGH;
|
|
if (l->args[2] & 8) flags |= FF_ADDITIVETRANS;
|
|
if (alpha!=100) flags|=FF_TRANSLUCENT;//|FF_BOTHPLANES|FF_ALLSIDES;
|
|
if (l->args[0])
|
|
{
|
|
// Yes, Vavoom's 3D-floor definitions suck!
|
|
// The content list changed in r1783 of Vavoom to be unified
|
|
// among all its supported games, so it has now ten different
|
|
// values instead of just five.
|
|
static DWORD vavoomcolors[]={VC_EMPTY,
|
|
VC_WATER, VC_LAVA, VC_NUKAGE, VC_SLIME, VC_HELLSLIME,
|
|
VC_BLOOD, VC_SLUDGE, VC_HAZARD, VC_BOOMWATER};
|
|
flags|=FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_FLOOD;
|
|
|
|
l->frontsector->ColorMap =
|
|
GetSpecialLights (l->frontsector->ColorMap->Color,
|
|
(unsigned int)(vavoomcolors[l->args[0]]&VC_COLORMASK),
|
|
(unsigned int)(vavoomcolors[l->args[0]]&VC_ALPHAMASK)>>24);
|
|
// l->frontsector->ColorMap->Desaturate);
|
|
}
|
|
alpha=(alpha*255)/100;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (param==4)
|
|
{
|
|
flags=FF_EXISTS|FF_RENDERPLANES|FF_INVERTPLANES|FF_NOSHADE|FF_FIX;
|
|
alpha=255;
|
|
}
|
|
else
|
|
{
|
|
static const int defflags[]= {0,
|
|
FF_SOLID,
|
|
FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_SHOOTTHROUGH|FF_SEETHROUGH,
|
|
FF_SHOOTTHROUGH|FF_SEETHROUGH,
|
|
};
|
|
|
|
flags = defflags[param&3] | FF_EXISTS|FF_RENDERALL;
|
|
|
|
if (param&4) flags |= FF_ALLSIDES|FF_BOTHPLANES;
|
|
if (param&16) flags ^= FF_SEETHROUGH;
|
|
if (param&32) flags ^= FF_SHOOTTHROUGH;
|
|
|
|
if (param2&1) flags |= FF_NOSHADE;
|
|
if (param2&2) flags |= FF_DOUBLESHADOW;
|
|
if (param2&4) flags |= FF_FOG;
|
|
if (param2&8) flags |= FF_THINFLOOR;
|
|
if (param2&16) flags |= FF_UPPERTEXTURE;
|
|
if (param2&32) flags |= FF_LOWERTEXTURE;
|
|
if (param2&64) flags |= FF_ADDITIVETRANS|FF_TRANSLUCENT;
|
|
// if flooding is used the floor must be non-solid and is automatically made shootthrough and seethrough
|
|
if ((param2&128) && !(flags & FF_SOLID)) flags |= FF_FLOOD|FF_SEETHROUGH|FF_SHOOTTHROUGH;
|
|
if (param2&512) flags |= FF_FADEWALLS;
|
|
FTextureID tex = line->sidedef[0]->GetTexture(side_t::top);
|
|
if (!tex.Exists() && alpha<255)
|
|
{
|
|
alpha=clamp(-tex.GetIndex(), 0, 255);
|
|
}
|
|
if (alpha==0) flags&=~(FF_RENDERALL|FF_BOTHPLANES|FF_ALLSIDES);
|
|
else if (alpha!=255) flags|=FF_TRANSLUCENT;
|
|
|
|
}
|
|
P_Add3DFloor(ss, sec, line, flags, alpha);
|
|
}
|
|
// To be 100% safe this should be done even if the alpha by texture value isn't used.
|
|
if (!line->sidedef[0]->GetTexture(side_t::top).isValid())
|
|
line->sidedef[0]->SetTexture(side_t::top, FNullTextureID());
|
|
return 1;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_PlayerOnSpecial3DFloor
|
|
// Checks to see if a player is standing on or is inside a 3D floor (water)
|
|
// and applies any specials..
|
|
//
|
|
//==========================================================================
|
|
|
|
void P_PlayerOnSpecial3DFloor(player_t* player)
|
|
{
|
|
sector_t * sector = player->mo->Sector;
|
|
|
|
for(unsigned i=0;i<sector->e->XFloor.ffloors.Size();i++)
|
|
{
|
|
F3DFloor* rover=sector->e->XFloor.ffloors[i];
|
|
|
|
if (!(rover->flags & FF_EXISTS)) continue;
|
|
if (rover->flags & FF_FIX) continue;
|
|
|
|
// Check the 3D floor's type...
|
|
if(rover->flags & FF_SOLID)
|
|
{
|
|
// Player must be on top of the floor to be affected...
|
|
if(player->mo->z != rover->top.plane->ZatPoint(player->mo->x, player->mo->y)) continue;
|
|
}
|
|
else
|
|
{
|
|
//Water and DEATH FOG!!! heh
|
|
if (player->mo->z > rover->top.plane->ZatPoint(player->mo->x, player->mo->y) ||
|
|
(player->mo->z + player->mo->height) < rover->bottom.plane->ZatPoint(player->mo->x, player->mo->y))
|
|
continue;
|
|
}
|
|
|
|
if (rover->model->special || rover->model->damage) P_PlayerInSpecialSector(player, rover->model);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_CheckFor3DFloorHit
|
|
// Checks whether the player's feet touch a solid 3D floor in the sector
|
|
//
|
|
//==========================================================================
|
|
bool P_CheckFor3DFloorHit(AActor * mo)
|
|
{
|
|
sector_t * sector = mo->Sector;
|
|
|
|
if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false;
|
|
|
|
for(unsigned i=0;i<sector->e->XFloor.ffloors.Size();i++)
|
|
{
|
|
F3DFloor* rover=sector->e->XFloor.ffloors[i];
|
|
|
|
if (!(rover->flags & FF_EXISTS)) continue;
|
|
|
|
if(rover->flags & FF_SOLID && rover->model->SecActTarget)
|
|
{
|
|
if(mo->floorz == rover->top.plane->ZatPoint(mo->x, mo->y))
|
|
{
|
|
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitFloor);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_CheckFor3DCeilingHit
|
|
// Checks whether the player's head touches a solid 3D floor in the sector
|
|
//
|
|
//==========================================================================
|
|
bool P_CheckFor3DCeilingHit(AActor * mo)
|
|
{
|
|
sector_t * sector = mo->Sector;
|
|
|
|
if ((mo->player && (mo->player->cheats & CF_PREDICTING))) return false;
|
|
|
|
for(unsigned i=0;i<sector->e->XFloor.ffloors.Size();i++)
|
|
{
|
|
F3DFloor* rover=sector->e->XFloor.ffloors[i];
|
|
|
|
if (!(rover->flags & FF_EXISTS)) continue;
|
|
|
|
if(rover->flags & FF_SOLID && rover->model->SecActTarget)
|
|
{
|
|
if(mo->ceilingz == rover->bottom.plane->ZatPoint(mo->x, mo->y))
|
|
{
|
|
rover->model->SecActTarget->TriggerAction (mo, SECSPAC_HitCeiling);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// P_Recalculate3DFloors
|
|
//
|
|
// This function sorts the ffloors by height and creates the lightlists
|
|
// that the given sector uses to light floors/ceilings/walls according to the 3D floors.
|
|
//
|
|
//==========================================================================
|
|
|
|
void P_Recalculate3DFloors(sector_t * sector)
|
|
{
|
|
F3DFloor * rover;
|
|
F3DFloor * pick;
|
|
unsigned pickindex;
|
|
F3DFloor * clipped=NULL;
|
|
fixed_t clipped_top;
|
|
fixed_t clipped_bottom=0;
|
|
fixed_t maxheight, minheight;
|
|
unsigned i, j;
|
|
lightlist_t newlight;
|
|
|
|
TArray<F3DFloor*> & ffloors=sector->e->XFloor.ffloors;
|
|
TArray<lightlist_t> & lightlist = sector->e->XFloor.lightlist;
|
|
|
|
// Sort the floors top to bottom for quicker access here and later
|
|
// Translucent and swimmable floors are split if they overlap with solid ones.
|
|
if (ffloors.Size()>1)
|
|
{
|
|
TArray<F3DFloor*> oldlist;
|
|
|
|
oldlist = ffloors;
|
|
ffloors.Clear();
|
|
|
|
// first delete the old dynamic stuff
|
|
for(i=0;i<oldlist.Size();i++)
|
|
{
|
|
F3DFloor * rover=oldlist[i];
|
|
|
|
if (rover->flags&FF_DYNAMIC)
|
|
{
|
|
delete rover;
|
|
oldlist.Delete(i);
|
|
i--;
|
|
continue;
|
|
}
|
|
if (rover->flags&FF_CLIPPED)
|
|
{
|
|
rover->flags&=~FF_CLIPPED;
|
|
rover->flags|=FF_EXISTS;
|
|
}
|
|
}
|
|
|
|
while (oldlist.Size())
|
|
{
|
|
pick=oldlist[0];
|
|
fixed_t height=pick->top.plane->ZatPoint(CenterSpot(sector));
|
|
|
|
// find highest starting ffloor - intersections are not supported!
|
|
pickindex=0;
|
|
for (j=1;j<oldlist.Size();j++)
|
|
{
|
|
fixed_t h2=oldlist[j]->top.plane->ZatPoint(CenterSpot(sector));
|
|
|
|
if (h2>height)
|
|
{
|
|
pick=oldlist[j];
|
|
pickindex=j;
|
|
height=h2;
|
|
}
|
|
}
|
|
|
|
oldlist.Delete(pickindex);
|
|
|
|
if (pick->flags & FF_THISINSIDE)
|
|
{
|
|
// These have the floor higher than the ceiling and cannot be processed
|
|
// by the clipping code below.
|
|
ffloors.Push(pick);
|
|
}
|
|
else if (pick->flags&(FF_SWIMMABLE|FF_TRANSLUCENT) && pick->flags&FF_EXISTS)
|
|
{
|
|
clipped=pick;
|
|
clipped_top=height;
|
|
clipped_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
|
ffloors.Push(pick);
|
|
}
|
|
else if (clipped && clipped_bottom<height)
|
|
{
|
|
// translucent floor above must be clipped to this one!
|
|
F3DFloor * dyn=new F3DFloor;
|
|
*dyn=*clipped;
|
|
clipped->flags|=FF_CLIPPED;
|
|
clipped->flags&=~FF_EXISTS;
|
|
dyn->flags|=FF_DYNAMIC;
|
|
dyn->bottom=pick->top;
|
|
ffloors.Push(dyn);
|
|
ffloors.Push(pick);
|
|
|
|
fixed_t pick_bottom=pick->bottom.plane->ZatPoint(CenterSpot(sector));
|
|
|
|
if (pick_bottom<=clipped_bottom)
|
|
{
|
|
clipped=NULL;
|
|
}
|
|
else
|
|
{
|
|
// the translucent part extends below the clipper
|
|
dyn=new F3DFloor;
|
|
*dyn=*clipped;
|
|
dyn->flags|=FF_DYNAMIC|FF_EXISTS;
|
|
dyn->top=pick->bottom;
|
|
ffloors.Push(dyn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clipped=NULL;
|
|
ffloors.Push(pick);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// having the floors sorted makes this routine significantly simpler
|
|
// Only some overlapping cases with FF_DOUBLESHADOW might create anomalies
|
|
// but these are clearly undefined.
|
|
if(ffloors.Size())
|
|
{
|
|
lightlist.Resize(1);
|
|
lightlist[0].plane = sector->ceilingplane;
|
|
lightlist[0].p_lightlevel = §or->lightlevel;
|
|
lightlist[0].caster = NULL;
|
|
lightlist[0].lightsource = NULL;
|
|
lightlist[0].extra_colormap = sector->ColorMap;
|
|
lightlist[0].blend = 0;
|
|
lightlist[0].flags = 0;
|
|
|
|
maxheight = sector->CenterCeiling();
|
|
minheight = sector->CenterFloor();
|
|
for(i = 0; i < ffloors.Size(); i++)
|
|
{
|
|
rover=ffloors[i];
|
|
|
|
if ( !(rover->flags & FF_EXISTS) || rover->flags & FF_NOSHADE )
|
|
continue;
|
|
|
|
fixed_t ff_top=rover->top.plane->ZatPoint(CenterSpot(sector));
|
|
if (ff_top < minheight) break; // reached the floor
|
|
if (ff_top < maxheight)
|
|
{
|
|
newlight.plane = *rover->top.plane;
|
|
newlight.p_lightlevel = rover->toplightlevel;
|
|
newlight.caster = rover;
|
|
newlight.lightsource = rover;
|
|
newlight.extra_colormap = rover->GetColormap();
|
|
newlight.blend = rover->GetBlend();
|
|
newlight.flags = rover->flags;
|
|
lightlist.Push(newlight);
|
|
}
|
|
else if (i==0)
|
|
{
|
|
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(CenterSpot(sector));
|
|
if (ff_bottom<maxheight)
|
|
{
|
|
// this segment begins over the ceiling and extends beyond it
|
|
lightlist[0].p_lightlevel = rover->toplightlevel;
|
|
lightlist[0].caster = rover;
|
|
lightlist[0].lightsource = rover;
|
|
lightlist[0].extra_colormap = rover->GetColormap();
|
|
lightlist[0].blend = rover->GetBlend();
|
|
lightlist[0].flags = rover->flags;
|
|
}
|
|
}
|
|
if (rover->flags&FF_DOUBLESHADOW)
|
|
{
|
|
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(CenterSpot(sector));
|
|
if(ff_bottom < maxheight && ff_bottom>minheight)
|
|
{
|
|
newlight.caster = rover;
|
|
newlight.plane = *rover->bottom.plane;
|
|
if (lightlist.Size()>1)
|
|
{
|
|
newlight.lightsource = lightlist[lightlist.Size()-2].lightsource;
|
|
newlight.p_lightlevel = lightlist[lightlist.Size()-2].p_lightlevel;
|
|
newlight.extra_colormap = lightlist[lightlist.Size()-2].extra_colormap;
|
|
newlight.blend = lightlist[lightlist.Size()-2].blend;
|
|
}
|
|
else
|
|
{
|
|
newlight.lightsource = NULL;
|
|
newlight.p_lightlevel = §or->lightlevel;
|
|
newlight.extra_colormap = sector->ColorMap;
|
|
newlight.blend = 0;
|
|
}
|
|
newlight.flags = rover->flags;
|
|
lightlist.Push(newlight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// recalculates 3D floors for all attached sectors
|
|
//
|
|
//==========================================================================
|
|
|
|
void P_RecalculateAttached3DFloors(sector_t * sec)
|
|
{
|
|
extsector_t::xfloor &x = sec->e->XFloor;
|
|
|
|
for(unsigned int i=0; i<x.attached.Size(); i++)
|
|
{
|
|
P_Recalculate3DFloors(x.attached[i]);
|
|
}
|
|
P_Recalculate3DFloors(sec);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// recalculates light lists for this sector
|
|
//
|
|
//==========================================================================
|
|
|
|
void P_RecalculateLights(sector_t *sector)
|
|
{
|
|
TArray<lightlist_t> &lightlist = sector->e->XFloor.lightlist;
|
|
|
|
for(unsigned i = 0; i < lightlist.Size(); i++)
|
|
{
|
|
lightlist_t *ll = &lightlist[i];
|
|
if (ll->lightsource != NULL)
|
|
{
|
|
ll->lightsource->UpdateColormap(ll->extra_colormap);
|
|
ll->blend = ll->lightsource->GetBlend();
|
|
}
|
|
else
|
|
{
|
|
ll->extra_colormap = sector->ColorMap;
|
|
ll->blend = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// recalculates light lists for all attached sectors
|
|
//
|
|
//==========================================================================
|
|
|
|
void P_RecalculateAttachedLights(sector_t *sector)
|
|
{
|
|
extsector_t::xfloor &x = sector->e->XFloor;
|
|
|
|
for(unsigned int i=0; i<x.attached.Size(); i++)
|
|
{
|
|
P_RecalculateLights(x.attached[i]);
|
|
}
|
|
P_RecalculateLights(sector);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
lightlist_t * P_GetPlaneLight(sector_t * sector, secplane_t * plane, bool underside)
|
|
{
|
|
unsigned i;
|
|
TArray<lightlist_t> &lightlist = sector->e->XFloor.lightlist;
|
|
|
|
fixed_t planeheight=plane->ZatPoint(CenterSpot(sector));
|
|
if(underside) planeheight--;
|
|
|
|
for(i = 1; i < lightlist.Size(); i++)
|
|
if (lightlist[i].plane.ZatPoint(CenterSpot(sector)) <= planeheight)
|
|
return &lightlist[i - 1];
|
|
|
|
return &lightlist[lightlist.Size() - 1];
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// Extended P_LineOpening
|
|
//
|
|
//==========================================================================
|
|
|
|
void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *linedef,
|
|
fixed_t x, fixed_t y, fixed_t refx, fixed_t refy, bool restrict)
|
|
{
|
|
if(thing)
|
|
{
|
|
fixed_t thingbot, thingtop;
|
|
|
|
thingbot = thing->z;
|
|
thingtop = thingbot + (thing->height==0? 1:thing->height);
|
|
|
|
extsector_t::xfloor *xf[2] = {&linedef->frontsector->e->XFloor, &linedef->backsector->e->XFloor};
|
|
|
|
// Check for 3D-floors in the sector (mostly identical to what Legacy does here)
|
|
if(xf[0]->ffloors.Size() || xf[1]->ffloors.Size())
|
|
{
|
|
fixed_t lowestceiling = open.top;
|
|
fixed_t highestfloor = open.bottom;
|
|
fixed_t lowestfloor[2] = {
|
|
linedef->frontsector->floorplane.ZatPoint(x, y),
|
|
linedef->backsector->floorplane.ZatPoint(x, y) };
|
|
FTextureID highestfloorpic;
|
|
FTextureID lowestceilingpic;
|
|
|
|
highestfloorpic.SetInvalid();
|
|
lowestceilingpic.SetInvalid();
|
|
|
|
for(int j=0;j<2;j++)
|
|
{
|
|
for(unsigned i=0;i<xf[j]->ffloors.Size();i++)
|
|
{
|
|
F3DFloor *rover = xf[j]->ffloors[i];
|
|
|
|
if (!(rover->flags & FF_EXISTS)) continue;
|
|
if (!(rover->flags & FF_SOLID)) continue;
|
|
|
|
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(x, y);
|
|
fixed_t ff_top=rover->top.plane->ZatPoint(x, y);
|
|
|
|
fixed_t delta1 = abs(thingbot - ((ff_bottom + ff_top) / 2));
|
|
fixed_t delta2 = abs(thingtop - ((ff_bottom + ff_top) / 2));
|
|
|
|
if(ff_bottom < lowestceiling && delta1 >= delta2)
|
|
{
|
|
lowestceiling = ff_bottom;
|
|
lowestceilingpic = *rover->bottom.texture;
|
|
}
|
|
|
|
if(ff_top > highestfloor && delta1 < delta2 && (!restrict || thing->z >= ff_top))
|
|
{
|
|
highestfloor = ff_top;
|
|
highestfloorpic = *rover->top.texture;
|
|
}
|
|
if(ff_top > lowestfloor[j] && ff_top <= thing->z + thing->MaxStepHeight) lowestfloor[j] = ff_top;
|
|
}
|
|
}
|
|
|
|
if(highestfloor > open.bottom)
|
|
{
|
|
open.bottom = highestfloor;
|
|
open.floorpic = highestfloorpic;
|
|
}
|
|
|
|
if(lowestceiling < open.top)
|
|
{
|
|
open.top = lowestceiling;
|
|
open.ceilingpic = lowestceilingpic;
|
|
}
|
|
|
|
open.lowfloor = MIN(lowestfloor[0], lowestfloor[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Spawns 3D floors
|
|
//
|
|
//==========================================================================
|
|
void P_Spawn3DFloors (void)
|
|
{
|
|
static int flagvals[] = {128+512, 2+512, 512};
|
|
int i;
|
|
line_t * line;
|
|
|
|
for (i=0,line=lines;i<numlines;i++,line++)
|
|
{
|
|
switch(line->special)
|
|
{
|
|
case ExtraFloor_LightOnly:
|
|
// Note: I am spawning both this and ZDoom's ExtraLight data
|
|
// I don't want to mess with both at the same time during rendering
|
|
// so inserting this into the 3D-floor table as well seemed to be
|
|
// the best option.
|
|
//
|
|
// This does not yet handle case 0 properly!
|
|
if (line->args[1] < 0 || line->args[1] > 2) line->args[1] = 0;
|
|
P_Set3DFloor(line, 3, flagvals[line->args[1]], 0);
|
|
break;
|
|
|
|
case Sector_Set3DFloor:
|
|
// The flag high-byte/line id is only needed in Hexen format.
|
|
// UDMF can set both of these parameters without any restriction of the usable values.
|
|
// In Doom format the translators can take full integers for the tag and the line ID always is the same as the tag.
|
|
if (level.maptype == MAPTYPE_HEXEN)
|
|
{
|
|
if (line->args[1]&8)
|
|
{
|
|
line->id = line->args[4];
|
|
}
|
|
else
|
|
{
|
|
line->args[0]+=256*line->args[4];
|
|
line->args[4]=0;
|
|
}
|
|
}
|
|
P_Set3DFloor(line, line->args[1]&~8, line->args[2], line->args[3]);
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
line->special=0;
|
|
line->args[0] = line->args[1] = line->args[2] = line->args[3] = line->args[4] = 0;
|
|
}
|
|
// kg3D - do it in software
|
|
for (i = 0; i < numsectors; i++)
|
|
{
|
|
P_Recalculate3DFloors(§ors[i]);
|
|
}
|
|
}
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// Returns a 3D floorplane appropriate for the given coordinates
|
|
//
|
|
//==========================================================================
|
|
|
|
secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z)
|
|
{
|
|
secplane_t retplane = sector->floorplane;
|
|
if (sector->e) // apparently this can be called when the data is already gone
|
|
{
|
|
for(unsigned int i=0;i<sector->e->XFloor.ffloors.Size();i++)
|
|
{
|
|
F3DFloor * rover= sector->e->XFloor.ffloors[i];
|
|
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
|
|
|
|
if (rover->top.plane->ZatPoint(x, y) == z)
|
|
{
|
|
retplane = *rover->top.plane;
|
|
if (retplane.c<0) retplane.FlipVert();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return retplane;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// Gives the index to an extra floor above or below the given location.
|
|
// -1 means normal floor or ceiling
|
|
//
|
|
//==========================================================================
|
|
|
|
int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz)
|
|
{
|
|
// If no sector given, find the one appropriate
|
|
if (sec == NULL)
|
|
sec = R_PointInSubsector(x, y)->sector;
|
|
|
|
// Above normal ceiling
|
|
cmpz = sec->ceilingplane.ZatPoint(x, y);
|
|
if (z >= cmpz)
|
|
return -1;
|
|
|
|
// Below normal floor
|
|
cmpz = sec->floorplane.ZatPoint(x, y);
|
|
if (z <= cmpz)
|
|
return -1;
|
|
|
|
// Looking through planes from top to bottom
|
|
for (int i = 0; i < (signed)sec->e->XFloor.ffloors.Size(); ++i)
|
|
{
|
|
F3DFloor *rover = sec->e->XFloor.ffloors[i];
|
|
|
|
// We are only interested in solid 3D floors here
|
|
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
|
|
|
|
if (above)
|
|
{
|
|
// z is above that floor
|
|
if (floor && (z >= (cmpz = rover->top.plane->ZatPoint(x, y))))
|
|
return i - 1;
|
|
// z is above that ceiling
|
|
if (z >= (cmpz = rover->bottom.plane->ZatPoint(x, y)))
|
|
return i - 1;
|
|
}
|
|
else // below
|
|
{
|
|
// z is below that ceiling
|
|
if (!floor && (z <= (cmpz = rover->bottom.plane->ZatPoint(x, y))))
|
|
return i;
|
|
// z is below that floor
|
|
if (z <= (cmpz = rover->top.plane->ZatPoint(x, y)))
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// Failsafe
|
|
return -1;
|
|
}
|
|
|
|
#endif
|