mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-27 22:22:08 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
# Conflicts: # src/g_doomedmap.cpp # src/info.h # src/p_saveg.cpp # src/p_setup.cpp # src/p_spec.cpp # src/r_defs.h # wadsrc/static/mapinfo/eternity.txt # wadsrc/static/xlat/eternity.txt
This commit is contained in:
commit
f8e5a0ebf0
36 changed files with 399 additions and 187 deletions
|
@ -139,7 +139,6 @@ DEFINE_SPECIAL(Sector_ChangeSound, 140, 2, 2, 2)
|
||||||
|
|
||||||
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
|
DEFINE_SPECIAL(Teleport_NoStop, 154, 2, 3, 3)
|
||||||
// portal specials
|
// portal specials
|
||||||
DEFINE_SPECIAL(Line_SetVisualPortal, 155, -1, -1, 3)
|
|
||||||
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3)
|
DEFINE_SPECIAL(Line_SetPortal, 156, -1, -1, 3)
|
||||||
// GZDoom/Vavoom specials
|
// GZDoom/Vavoom specials
|
||||||
// Although ZDoom doesn't support them it's better to have them defined so that
|
// Although ZDoom doesn't support them it's better to have them defined so that
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
#ifndef AUTOSEGS_H
|
#ifndef AUTOSEGS_H
|
||||||
#define AUTOSEGS_H
|
#define AUTOSEGS_H
|
||||||
|
|
||||||
|
#include "doomtype.h"
|
||||||
|
|
||||||
#define REGMARKER(x) (x)
|
#define REGMARKER(x) (x)
|
||||||
typedef void * const REGINFO;
|
typedef void * const REGINFO;
|
||||||
typedef void * NCREGINFO;
|
typedef void * NCREGINFO;
|
||||||
|
@ -73,11 +75,11 @@ class FAutoSegIterator
|
||||||
}
|
}
|
||||||
Probe = Head;
|
Probe = Head;
|
||||||
}
|
}
|
||||||
NCREGINFO operator*() const
|
NCREGINFO operator*() const NO_SANITIZE
|
||||||
{
|
{
|
||||||
return *Probe;
|
return *Probe;
|
||||||
}
|
}
|
||||||
FAutoSegIterator &operator++()
|
FAutoSegIterator &operator++() NO_SANITIZE
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
|
@ -2723,9 +2723,9 @@ static bool LoadDehSupp ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
|
||||||
if (args.Size() != 0 && !(args[0] & VARF_Optional))
|
if (args.Size() > 3 && !(args[3] & VARF_Optional))
|
||||||
{
|
{
|
||||||
sc.ScriptError("Incompatible code pointer '%s'", sc.String);
|
sc.ScriptMessage("Incompatible code pointer '%s' %d, %d", sc.String, args.Size(), args.Size() > 3? args[3] : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Actions.Push(sym);
|
Actions.Push(sym);
|
||||||
|
|
|
@ -1986,7 +1986,7 @@ END_POINTERS
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static int STACK_ARGS cregcmp (const void *a, const void *b)
|
static int STACK_ARGS cregcmp (const void *a, const void *b) NO_SANITIZE
|
||||||
{
|
{
|
||||||
const PClass *class1 = *(const PClass **)a;
|
const PClass *class1 = *(const PClass **)a;
|
||||||
const PClass *class2 = *(const PClass **)b;
|
const PClass *class2 = *(const PClass **)b;
|
||||||
|
|
|
@ -113,6 +113,16 @@ typedef TMap<int, PClassActor *> FClassMap;
|
||||||
#define NOVTABLE
|
#define NOVTABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#if defined(__has_feature) && __has_feature(address_sanitizer))
|
||||||
|
#define NO_SANITIZE __attribute__((no_sanitize("address")))
|
||||||
|
#else
|
||||||
|
#define NO_SANITIZE
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define NO_SANITIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "basictypes.h"
|
#include "basictypes.h"
|
||||||
|
|
||||||
// Bounding box coordinate storage.
|
// Bounding box coordinate storage.
|
||||||
|
|
|
@ -286,9 +286,11 @@ template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font)
|
||||||
struct FStrifeDialogueNode;
|
struct FStrifeDialogueNode;
|
||||||
struct FSwitchDef;
|
struct FSwitchDef;
|
||||||
struct FDoorAnimation;
|
struct FDoorAnimation;
|
||||||
|
struct FLinePortal;
|
||||||
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
|
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
|
||||||
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
|
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
|
||||||
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);
|
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);
|
||||||
|
FArchive &operator<< (FArchive &arc, FLinePortal &da);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ const char *SpecialMapthingNames[] = {
|
||||||
"$CopyCeilingPlane",
|
"$CopyCeilingPlane",
|
||||||
"$VertexFloorZ",
|
"$VertexFloorZ",
|
||||||
"$VertexCeilingZ",
|
"$VertexCeilingZ",
|
||||||
"$EDFThing",
|
"$EDThing",
|
||||||
|
|
||||||
};
|
};
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -310,7 +310,7 @@ enum ESpecialMapthings
|
||||||
SMT_CopyCeilingPlane,
|
SMT_CopyCeilingPlane,
|
||||||
SMT_VertexFloorZ,
|
SMT_VertexFloorZ,
|
||||||
SMT_VertexCeilingZ,
|
SMT_VertexCeilingZ,
|
||||||
SMT_EDFThing,
|
SMT_EDThing,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ void FName::NameManager::InitBuckets ()
|
||||||
// Register built-in names. 'None' must be name 0.
|
// Register built-in names. 'None' must be name 0.
|
||||||
for (size_t i = 0; i < countof(PredefinedNames); ++i)
|
for (size_t i = 0; i < countof(PredefinedNames); ++i)
|
||||||
{
|
{
|
||||||
assert((NULL == FindName(PredefinedNames[i], true)) && "Predefined name already inserted");
|
assert((0 == FindName(PredefinedNames[i], true)) && "Predefined name already inserted");
|
||||||
FindName (PredefinedNames[i], false);
|
FindName (PredefinedNames[i], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8299,9 +8299,6 @@ scriptwait:
|
||||||
line->args[4] = STACK(1);
|
line->args[4] = STACK(1);
|
||||||
DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n",
|
DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n",
|
||||||
linenum, STACK(7), specnum, arg0, STACK(4), STACK(3), STACK(2), STACK(1));
|
linenum, STACK(7), specnum, arg0, STACK(4), STACK(3), STACK(2), STACK(1));
|
||||||
|
|
||||||
// [ZZ] re-link with portals (in case this was something related to portal specials)
|
|
||||||
P_CheckPortal(line);
|
|
||||||
}
|
}
|
||||||
sp -= 7;
|
sp -= 7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -630,11 +630,6 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// [ZZ] set initial line portal link
|
|
||||||
// (even though this is rather hard to happen... build doesn't have portals in our sense and it's walls don't get translated into anything like this)
|
|
||||||
for (int i = 0; i < numlines; i++)
|
|
||||||
P_CheckPortal(&lines[i]);
|
|
||||||
|
|
||||||
// Finish setting sector properties that depend on walls
|
// Finish setting sector properties that depend on walls
|
||||||
for (i = 0; i < numsectors; ++i, ++bsec)
|
for (i = 0; i < numsectors; ++i, ++bsec)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3781,7 +3781,7 @@ int P_ExecuteSpecial(int num,
|
||||||
int arg4,
|
int arg4,
|
||||||
int arg5)
|
int arg5)
|
||||||
{
|
{
|
||||||
if (num >= 0 && num < countof(LineSpecials))
|
if (num >= 0 && num < (int)countof(LineSpecials))
|
||||||
{
|
{
|
||||||
return LineSpecials[num](line, activator, backSide, arg1, arg2, arg3, arg4, arg5);
|
return LineSpecials[num](line, activator, backSide, arg1, arg2, arg3, arg4, arg5);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "p_lnspec.h"
|
#include "p_lnspec.h"
|
||||||
#include "p_acs.h"
|
#include "p_acs.h"
|
||||||
#include "p_terrain.h"
|
#include "p_terrain.h"
|
||||||
|
#include "portal.h"
|
||||||
|
|
||||||
static void CopyPlayer (player_t *dst, player_t *src, const char *name);
|
static void CopyPlayer (player_t *dst, player_t *src, const char *name);
|
||||||
static void ReadOnePlayer (FArchive &arc, bool skipload);
|
static void ReadOnePlayer (FArchive &arc, bool skipload);
|
||||||
|
@ -477,6 +478,12 @@ void P_SerializeWorld (FArchive &arc)
|
||||||
}
|
}
|
||||||
arc << li->args[1] << li->args[2] << li->args[3] << li->args[4];
|
arc << li->args[1] << li->args[2] << li->args[3] << li->args[4];
|
||||||
|
|
||||||
|
if (SaveVersion >= 4532)
|
||||||
|
{
|
||||||
|
arc << li->portalindex;
|
||||||
|
}
|
||||||
|
else li->portalindex = UINT_MAX;
|
||||||
|
|
||||||
if (SaveVersion >= 4531)
|
if (SaveVersion >= 4531)
|
||||||
{
|
{
|
||||||
arc << li->skybox;
|
arc << li->skybox;
|
||||||
|
@ -516,6 +523,15 @@ void P_SerializeWorld (FArchive &arc)
|
||||||
{
|
{
|
||||||
arc << zn->Environment;
|
arc << zn->Environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SaveVersion >= 4532)
|
||||||
|
{
|
||||||
|
arc << linePortals;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
linePortals.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void extsector_t::Serialize(FArchive &arc)
|
void extsector_t::Serialize(FArchive &arc)
|
||||||
|
|
|
@ -1769,7 +1769,7 @@ void P_LoadThings (MapData * map)
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_EDATA
|
#ifndef NO_EDATA
|
||||||
if (mti[i].info != NULL && mti[i].info->Special == SMT_EDFThing)
|
if (mti[i].info != NULL && mti[i].info->Special == SMT_EDThing)
|
||||||
{
|
{
|
||||||
ProcessEDMapthing(&mti[i], flags);
|
ProcessEDMapthing(&mti[i], flags);
|
||||||
}
|
}
|
||||||
|
@ -1976,7 +1976,6 @@ void P_SetLineID (int i, line_t *ld)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Line_SetPortal:
|
case Line_SetPortal:
|
||||||
case Line_SetVisualPortal:
|
|
||||||
setid = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor
|
setid = ld->args[1]; // 0 = target id, 1 = this id, 2 = plane anchor
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2079,9 +2078,6 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha)
|
||||||
ld->special = 0;
|
ld->special = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [ZZ] check initial portal link
|
|
||||||
P_CheckPortal(ld);
|
|
||||||
}
|
}
|
||||||
// killough 4/4/98: delay using sidedefs until they are loaded
|
// killough 4/4/98: delay using sidedefs until they are loaded
|
||||||
void P_FinishLoadingLineDefs ()
|
void P_FinishLoadingLineDefs ()
|
||||||
|
@ -2174,6 +2170,7 @@ void P_LoadLineDefs (MapData * map)
|
||||||
for (i = 0; i < numlines; i++, mld++, ld++)
|
for (i = 0; i < numlines; i++, mld++, ld++)
|
||||||
{
|
{
|
||||||
ld->Alpha = FRACUNIT; // [RH] Opaque by default
|
ld->Alpha = FRACUNIT; // [RH] Opaque by default
|
||||||
|
ld->portalindex = UINT_MAX;
|
||||||
|
|
||||||
// [RH] Translate old linedef special and flags to be
|
// [RH] Translate old linedef special and flags to be
|
||||||
// compatible with the new format.
|
// compatible with the new format.
|
||||||
|
@ -2266,6 +2263,8 @@ void P_LoadLineDefs2 (MapData * map)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
|
ld->portalindex = UINT_MAX;
|
||||||
|
|
||||||
for (j = 0; j < 5; j++)
|
for (j = 0; j < 5; j++)
|
||||||
ld->args[j] = mld->args[j];
|
ld->args[j] = mld->args[j];
|
||||||
|
|
||||||
|
@ -3395,6 +3394,7 @@ void P_FreeLevelData ()
|
||||||
level.killed_monsters = level.found_items = level.found_secrets =
|
level.killed_monsters = level.found_items = level.found_secrets =
|
||||||
wminfo.maxfrags = 0;
|
wminfo.maxfrags = 0;
|
||||||
|
|
||||||
|
linePortals.Clear();
|
||||||
FBehavior::StaticUnloadModules ();
|
FBehavior::StaticUnloadModules ();
|
||||||
if (vertexes != NULL)
|
if (vertexes != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include "a_keys.h"
|
#include "a_keys.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
#include "r_sky.h"
|
#include "r_sky.h"
|
||||||
|
#include "portal.h"
|
||||||
#ifndef NO_EDATA
|
#ifndef NO_EDATA
|
||||||
#include "edata.h"
|
#include "edata.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1465,6 +1466,10 @@ void P_SpawnSpecials (void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Line_SetPortal:
|
||||||
|
P_SpawnLinePortal(&lines[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
// [RH] ZDoom Static_Init settings
|
// [RH] ZDoom Static_Init settings
|
||||||
case Static_Init:
|
case Static_Init:
|
||||||
switch (lines[i].args[1])
|
switch (lines[i].args[1])
|
||||||
|
@ -1536,6 +1541,7 @@ void P_SpawnSpecials (void)
|
||||||
}
|
}
|
||||||
// [RH] Start running any open scripts on this map
|
// [RH] Start running any open scripts on this map
|
||||||
FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false);
|
FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false);
|
||||||
|
P_FinalizePortals();
|
||||||
}
|
}
|
||||||
|
|
||||||
// killough 2/28/98:
|
// killough 2/28/98:
|
||||||
|
|
|
@ -247,6 +247,18 @@ bool FTagManager::SectorHasTag(const sector_t *sector, int tag) const
|
||||||
//
|
//
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int FTagManager::GetFirstLineID(const line_t *line) const
|
||||||
|
{
|
||||||
|
int i = lineindex(line);
|
||||||
|
return LineHasIDs(i) ? allIDs[startForLine[i]].tag : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
bool FTagManager::LineHasID(int i, int tag) const
|
bool FTagManager::LineHasID(int i, int tag) const
|
||||||
{
|
{
|
||||||
if (LineHasIDs(i))
|
if (LineHasIDs(i))
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
bool SectorHasTag(int sector, int tag) const;
|
bool SectorHasTag(int sector, int tag) const;
|
||||||
bool SectorHasTag(const sector_t *sector, int tag) const;
|
bool SectorHasTag(const sector_t *sector, int tag) const;
|
||||||
|
|
||||||
|
int GetFirstLineID(const line_t *line) const;
|
||||||
bool LineHasID(int line, int id) const;
|
bool LineHasID(int line, int id) const;
|
||||||
bool LineHasID(const line_t *line, int id) const;
|
bool LineHasID(const line_t *line, int id) const;
|
||||||
|
|
||||||
|
|
|
@ -792,6 +792,7 @@ public:
|
||||||
|
|
||||||
memset(ld, 0, sizeof(*ld));
|
memset(ld, 0, sizeof(*ld));
|
||||||
ld->Alpha = FRACUNIT;
|
ld->Alpha = FRACUNIT;
|
||||||
|
ld->portalindex = UINT_MAX;
|
||||||
ld->sidedef[0] = ld->sidedef[1] = NULL;
|
ld->sidedef[0] = ld->sidedef[1] = NULL;
|
||||||
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
|
if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
|
||||||
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
|
if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
|
||||||
|
|
286
src/portal.cpp
286
src/portal.cpp
|
@ -6,97 +6,35 @@
|
||||||
#include "c_cvars.h"
|
#include "c_cvars.h"
|
||||||
#include "m_bbox.h"
|
#include "m_bbox.h"
|
||||||
#include "p_tags.h"
|
#include "p_tags.h"
|
||||||
|
#include "farchive.h"
|
||||||
|
|
||||||
// simulation recurions maximum
|
// simulation recurions maximum
|
||||||
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
CVAR(Int, sv_portal_recursions, 4, CVAR_ARCHIVE|CVAR_SERVERINFO)
|
||||||
|
|
||||||
PortalDrawseg* CurrentPortal = NULL;
|
TArray<FLinePortal> linePortals;
|
||||||
int CurrentPortalUniq = 0;
|
|
||||||
bool CurrentPortalInSkybox = false;
|
|
||||||
|
|
||||||
// [ZZ] lots of floats here to avoid overflowing a lot
|
|
||||||
bool R_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y,
|
FArchive &operator<< (FArchive &arc, FLinePortal &port)
|
||||||
fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y,
|
|
||||||
fixed_t& rx, fixed_t& ry)
|
|
||||||
{
|
{
|
||||||
float xx = FIXED2FLOAT(o2x) - FIXED2FLOAT(o1x);
|
arc << port.mOrigin
|
||||||
float xy = FIXED2FLOAT(o2y) - FIXED2FLOAT(o1y);
|
<< port.mDestination
|
||||||
|
<< port.mXDisplacement
|
||||||
float d1x = FIXED2FLOAT(p1x) - FIXED2FLOAT(o1x);
|
<< port.mYDisplacement
|
||||||
float d1y = FIXED2FLOAT(p1y) - FIXED2FLOAT(o1y);
|
<< port.mType
|
||||||
|
<< port.mFlags
|
||||||
if (d1x > d1y)
|
<< port.mDefFlags
|
||||||
{
|
<< port.mAlign;
|
||||||
d1y = d1y / d1x * 32767.0f;
|
return arc;
|
||||||
d1x = 32767.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d1x = d1x / d1y * 32767.0f;
|
|
||||||
d1y = 32767.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float d2x = FIXED2FLOAT(p2x) - FIXED2FLOAT(o2x);
|
|
||||||
float d2y = FIXED2FLOAT(p2y) - FIXED2FLOAT(o2y);
|
|
||||||
|
|
||||||
float cross = d1x*d2y - d1y*d2x;
|
|
||||||
if (fabs(cross) < 1e-8)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float t1 = (xx * d2y - xy * d2x)/cross;
|
|
||||||
rx = o1x + FLOAT2FIXED(d1x * t1);
|
|
||||||
ry = o1y + FLOAT2FIXED(d1y * t1);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
|
|
||||||
|
void P_SpawnLinePortal(line_t* line)
|
||||||
{
|
{
|
||||||
return DMulScale32 (y-y1, x2-x1, x1-x, y2-y1) > 0;
|
// portal destination is special argument #0
|
||||||
}
|
line_t* dst = NULL;
|
||||||
|
|
||||||
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial, bool samebehind)
|
if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED)
|
||||||
{
|
|
||||||
// check if this line is between portal and the viewer. clip away if it is.
|
|
||||||
bool behind1 = !!P_PointOnLineSide(line->v1->x, line->v1->y, portal);
|
|
||||||
bool behind2 = !!P_PointOnLineSide(line->v2->x, line->v2->y, portal);
|
|
||||||
|
|
||||||
// [ZZ] update 16.12.2014: if a vertex equals to one of portal's vertices, it's treated as being behind the portal.
|
|
||||||
// this is required in order to clip away diagonal lines around the portal (example: 1-sided triangle shape with a mirror on it's side)
|
|
||||||
if ((line->v1->x == portal->v1->x && line->v1->y == portal->v1->y) ||
|
|
||||||
(line->v1->x == portal->v2->x && line->v1->y == portal->v2->y))
|
|
||||||
behind1 = samebehind;
|
|
||||||
if ((line->v2->x == portal->v1->x && line->v2->y == portal->v1->y) ||
|
|
||||||
(line->v2->x == portal->v2->x && line->v2->y == portal->v2->y))
|
|
||||||
behind2 = samebehind;
|
|
||||||
|
|
||||||
if (behind1 && behind2)
|
|
||||||
{
|
{
|
||||||
// line is behind the portal plane. now check if it's in front of two view plane borders (i.e. if it will get in the way of rendering)
|
|
||||||
fixed_t dummyx, dummyy;
|
|
||||||
bool infront1 = R_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v1->x, portal->v1->y, dummyx, dummyy);
|
|
||||||
bool infront2 = R_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v2->x, portal->v2->y, dummyx, dummyy);
|
|
||||||
if (infront1 && infront2)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool P_CheckPortal(line_t* line)
|
|
||||||
{
|
|
||||||
if (line->special == Line_Mirror)
|
|
||||||
{
|
|
||||||
line->portal = true;
|
|
||||||
line->portal_mirror = true;
|
|
||||||
line->portal_passive = true;
|
|
||||||
line->portal_dst = line;
|
|
||||||
}
|
|
||||||
else if (line->special == Line_SetPortal ||
|
|
||||||
line->special == Line_SetVisualPortal)
|
|
||||||
{
|
|
||||||
// portal destination is special argument #0
|
|
||||||
line_t* dst = NULL;
|
|
||||||
|
|
||||||
if (line->args[0] > 0)
|
if (line->args[0] > 0)
|
||||||
{
|
{
|
||||||
int linenum = -1;
|
int linenum = -1;
|
||||||
|
@ -113,30 +51,161 @@ bool P_CheckPortal(line_t* line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dst)
|
line->portalindex = linePortals.Reserve(1);
|
||||||
|
FLinePortal *port = &linePortals.Last();
|
||||||
|
|
||||||
|
memset(port, 0, sizeof(FLinePortal));
|
||||||
|
port->mOrigin = line;
|
||||||
|
port->mDestination = dst;
|
||||||
|
port->mType = BYTE(line->args[2]); // range check is done above.
|
||||||
|
port->mAlign = BYTE(line->args[3] >= PORG_ABSOLUTE && line->args[3] <= PORG_CEILING ? line->args[3] : PORG_ABSOLUTE);
|
||||||
|
if (port->mDestination != NULL)
|
||||||
{
|
{
|
||||||
line->portal = true;
|
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
|
||||||
line->portal_mirror = false;
|
|
||||||
line->portal_passive = (line->special == Line_SetVisualPortal);
|
|
||||||
line->portal_dst = dst;
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0)
|
||||||
|
{
|
||||||
|
// EE-style portals require that the first line ID is identical and the first arg of the two linked linedefs are 0 and 1 respectively.
|
||||||
|
|
||||||
|
int mytag = tagManager.GetFirstLineID(line);
|
||||||
|
|
||||||
|
for (int i = 0; i < numlines; i++)
|
||||||
{
|
{
|
||||||
line->portal = false;
|
if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1)
|
||||||
line->portal_mirror = false;
|
{
|
||||||
line->portal_passive = false;
|
line->portalindex = linePortals.Reserve(1);
|
||||||
line->portal_dst = NULL;
|
FLinePortal *port = &linePortals.Last();
|
||||||
|
|
||||||
|
memset(port, 0, sizeof(FLinePortal));
|
||||||
|
port->mOrigin = line;
|
||||||
|
port->mDestination = &lines[i];
|
||||||
|
port->mType = PORTT_LINKED;
|
||||||
|
port->mAlign = PORG_ABSOLUTE;
|
||||||
|
port->mDefFlags = PORTF_TYPEINTERACTIVE;
|
||||||
|
|
||||||
|
// we need to create the backlink here, too.
|
||||||
|
lines[i].portalindex = linePortals.Reserve(1);
|
||||||
|
port = &linePortals.Last();
|
||||||
|
|
||||||
|
memset(port, 0, sizeof(FLinePortal));
|
||||||
|
port->mOrigin = &lines[i];
|
||||||
|
port->mDestination = line;
|
||||||
|
port->mType = PORTT_LINKED;
|
||||||
|
port->mAlign = PORG_ABSOLUTE;
|
||||||
|
port->mDefFlags = PORTF_TYPEINTERACTIVE;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
line->portal = false;
|
// undefined type
|
||||||
line->portal_mirror = false;
|
return;
|
||||||
line->portal_passive = false;
|
}
|
||||||
line->portal_dst = NULL;
|
}
|
||||||
|
|
||||||
|
void P_UpdatePortal(FLinePortal *port)
|
||||||
|
{
|
||||||
|
if (port->mDestination == NULL)
|
||||||
|
{
|
||||||
|
// Portal has no destination: switch it off
|
||||||
|
port->mFlags = 0;
|
||||||
|
}
|
||||||
|
else if (port->mDestination->getPortalDestination() != port->mOrigin)
|
||||||
|
{
|
||||||
|
//portal doesn't link back. This will be a simple teleporter portal.
|
||||||
|
port->mFlags = port->mDefFlags & ~PORTF_INTERACTIVE;
|
||||||
|
if (port->mType == PORTT_LINKED)
|
||||||
|
{
|
||||||
|
// this is illegal. Demote the type to TELEPORT
|
||||||
|
port->mType = PORTT_TELEPORT;
|
||||||
|
port->mDefFlags &= ~PORTF_INTERACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port->mFlags = port->mDefFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void P_FinalizePortals()
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < linePortals.Size(); i++)
|
||||||
|
{
|
||||||
|
FLinePortal * port = &linePortals[i];
|
||||||
|
P_UpdatePortal(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [ZZ] lots of floats here to avoid overflowing a lot
|
||||||
|
bool P_IntersectLines(fixed_t o1x, fixed_t o1y, fixed_t p1x, fixed_t p1y,
|
||||||
|
fixed_t o2x, fixed_t o2y, fixed_t p2x, fixed_t p2y,
|
||||||
|
fixed_t& rx, fixed_t& ry)
|
||||||
|
{
|
||||||
|
double xx = FIXED2DBL(o2x) - FIXED2DBL(o1x);
|
||||||
|
double xy = FIXED2DBL(o2y) - FIXED2DBL(o1y);
|
||||||
|
|
||||||
|
double d1x = FIXED2DBL(p1x) - FIXED2DBL(o1x);
|
||||||
|
double d1y = FIXED2DBL(p1y) - FIXED2DBL(o1y);
|
||||||
|
|
||||||
|
if (d1x > d1y)
|
||||||
|
{
|
||||||
|
d1y = d1y / d1x * 32767.0f;
|
||||||
|
d1x = 32767.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d1x = d1x / d1y * 32767.0f;
|
||||||
|
d1y = 32767.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (line->portal);
|
double d2x = FIXED2DBL(p2x) - FIXED2DBL(o2x);
|
||||||
|
double d2y = FIXED2DBL(p2y) - FIXED2DBL(o2y);
|
||||||
|
|
||||||
|
double cross = d1x*d2y - d1y*d2x;
|
||||||
|
if (fabs(cross) < 1e-8)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double t1 = (xx * d2y - xy * d2x)/cross;
|
||||||
|
rx = o1x + FLOAT2FIXED(d1x * t1);
|
||||||
|
ry = o1y + FLOAT2FIXED(d1y * t1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int P_PointOnLineSideExplicit (fixed_t x, fixed_t y, fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
|
||||||
|
{
|
||||||
|
return DMulScale32 (y-y1, x2-x1, x1-x, y2-y1) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial, bool samebehind)
|
||||||
|
{
|
||||||
|
// check if this line is between portal and the viewer. clip away if it is.
|
||||||
|
bool behind1 = !!P_PointOnLineSidePrecise(line->v1->x, line->v1->y, portal);
|
||||||
|
bool behind2 = !!P_PointOnLineSidePrecise(line->v2->x, line->v2->y, portal);
|
||||||
|
|
||||||
|
// [ZZ] update 16.12.2014: if a vertex equals to one of portal's vertices, it's treated as being behind the portal.
|
||||||
|
// this is required in order to clip away diagonal lines around the portal (example: 1-sided triangle shape with a mirror on it's side)
|
||||||
|
if ((line->v1->x == portal->v1->x && line->v1->y == portal->v1->y) ||
|
||||||
|
(line->v1->x == portal->v2->x && line->v1->y == portal->v2->y))
|
||||||
|
behind1 = samebehind;
|
||||||
|
if ((line->v2->x == portal->v1->x && line->v2->y == portal->v1->y) ||
|
||||||
|
(line->v2->x == portal->v2->x && line->v2->y == portal->v2->y))
|
||||||
|
behind2 = samebehind;
|
||||||
|
|
||||||
|
if (behind1 && behind2)
|
||||||
|
{
|
||||||
|
// line is behind the portal plane. now check if it's in front of two view plane borders (i.e. if it will get in the way of rendering)
|
||||||
|
fixed_t dummyx, dummyy;
|
||||||
|
bool infront1 = P_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v1->x, portal->v1->y, dummyx, dummyy);
|
||||||
|
bool infront2 = P_IntersectLines(line->v1->x, line->v1->y, line->v2->x, line->v2->y, viewx, viewy, portal->v2->x, portal->v2->y, dummyx, dummyy);
|
||||||
|
if (infront1 && infront2)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
|
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
|
||||||
|
@ -211,17 +280,22 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle)
|
||||||
|
|
||||||
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z)
|
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z)
|
||||||
{
|
{
|
||||||
// args[2] = 0 - no teleport
|
// args[2] = 0 - no adjustment
|
||||||
// args[2] = 1 - adjust by floor difference
|
// args[2] = 1 - adjust by floor difference
|
||||||
// args[2] = 2 - adjust by ceiling difference
|
// args[2] = 2 - adjust by ceiling difference
|
||||||
|
|
||||||
if (src->args[2] == 1)
|
switch (src->getPortalAlignment())
|
||||||
{
|
{
|
||||||
|
case PORG_FLOOR:
|
||||||
z = z - src->frontsector->floorplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->floorplane.ZatPoint(dst->v2->x, dst->v2->y);
|
z = z - src->frontsector->floorplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->floorplane.ZatPoint(dst->v2->x, dst->v2->y);
|
||||||
}
|
return;
|
||||||
else if (src->args[2] == 2)
|
|
||||||
{
|
case PORG_CEILING:
|
||||||
z = z - src->frontsector->ceilingplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->ceilingplane.ZatPoint(dst->v2->x, dst->v2->y);
|
z = z - src->frontsector->ceilingplane.ZatPoint(src->v1->x, src->v1->y) + dst->frontsector->ceilingplane.ZatPoint(dst->v2->x, dst->v2->y);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,9 +318,9 @@ fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y)
|
||||||
|
|
||||||
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
|
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
|
||||||
{
|
{
|
||||||
float _vx = FIXED2FLOAT(vx);
|
double _vx = FIXED2DBL(vx);
|
||||||
float _vy = FIXED2FLOAT(vy);
|
double _vy = FIXED2DBL(vy);
|
||||||
float len = sqrt(_vx*_vx+_vy*_vy);
|
double len = sqrt(_vx*_vx+_vy*_vy);
|
||||||
vx = FLOAT2FIXED(_vx/len);
|
vx = FLOAT2FIXED(_vx/len);
|
||||||
vy = FLOAT2FIXED(_vy/len);
|
vy = FLOAT2FIXED(_vy/len);
|
||||||
}
|
}
|
||||||
|
@ -302,12 +376,12 @@ bool PortalTracer::TraceStep()
|
||||||
{
|
{
|
||||||
li = in->d.line;
|
li = in->d.line;
|
||||||
|
|
||||||
if (li->portal && !li->portal_passive)
|
if (li->isLinePortal())
|
||||||
{
|
{
|
||||||
if (P_PointOnLineSide(startx-dirx, starty-diry, li))
|
if (P_PointOnLineSide(startx-dirx, starty-diry, li))
|
||||||
continue; // we're at the back side of this line
|
continue; // we're at the back side of this line
|
||||||
|
|
||||||
line_t* out = li->portal_dst;
|
line_t* out = li->getPortalDestination();
|
||||||
|
|
||||||
this->in = li;
|
this->in = li;
|
||||||
this->out = out;
|
this->out = out;
|
||||||
|
@ -361,7 +435,7 @@ bool PortalTracer::TraceStep()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2FLOAT(this->vx), FIXED2FLOAT(this->vy));
|
//Printf("returning %d; vx = %.2f; vy = %.2f\n", (oDepth != depth), FIXED2DBL(this->vx), FIXED2DBL(this->vy));
|
||||||
|
|
||||||
return (oDepth != depth); // if a portal has been found, return false
|
return (oDepth != depth); // if a portal has been found, return false
|
||||||
}
|
}
|
||||||
|
|
80
src/portal.h
80
src/portal.h
|
@ -8,29 +8,54 @@
|
||||||
#include "p_local.h"
|
#include "p_local.h"
|
||||||
#include "m_bbox.h"
|
#include "m_bbox.h"
|
||||||
|
|
||||||
/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */
|
|
||||||
struct PortalDrawseg
|
enum
|
||||||
{
|
{
|
||||||
line_t* src; // source line (the one drawn) this doesn't change over render loops
|
PORTF_VISIBLE = 1,
|
||||||
line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors)
|
PORTF_PASSABLE = 2,
|
||||||
|
PORTF_SOUNDTRAVERSE = 4,
|
||||||
|
PORTF_INTERACTIVE = 8,
|
||||||
|
|
||||||
int x1; // drawseg x1
|
PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE,
|
||||||
int x2; // drawseg x2
|
PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE,
|
||||||
|
|
||||||
int len;
|
|
||||||
TArray<short> ceilingclip;
|
|
||||||
TArray<short> floorclip;
|
|
||||||
|
|
||||||
bool mirror; // true if this is a mirror (src should equal dst)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PortalDrawseg* CurrentPortal;
|
enum
|
||||||
extern int CurrentPortalUniq;
|
{
|
||||||
extern bool CurrentPortalInSkybox;
|
PORTT_VISUAL,
|
||||||
|
PORTT_TELEPORT,
|
||||||
|
PORTT_INTERACTIVE,
|
||||||
|
PORTT_LINKED,
|
||||||
|
PORTT_LINKEDEE // Eternity compatible definition which uses only one line ID and a different anchor type to link to.
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PORG_ABSOLUTE, // does not align at all. z-ccoordinates must match.
|
||||||
|
PORG_FLOOR,
|
||||||
|
PORG_CEILING,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FLinePortal
|
||||||
|
{
|
||||||
|
line_t *mOrigin;
|
||||||
|
line_t *mDestination;
|
||||||
|
fixed_t mXDisplacement;
|
||||||
|
fixed_t mYDisplacement;
|
||||||
|
BYTE mType;
|
||||||
|
BYTE mFlags;
|
||||||
|
BYTE mDefFlags;
|
||||||
|
BYTE mAlign;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TArray<FLinePortal> linePortals;
|
||||||
|
|
||||||
|
void P_SpawnLinePortal(line_t* line);
|
||||||
|
void P_FinalizePortals();
|
||||||
|
|
||||||
|
|
||||||
/* code ported from prototype */
|
/* code ported from prototype */
|
||||||
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial = true, bool samebehind = true);
|
bool P_ClipLineToPortal(line_t* line, line_t* portal, fixed_t viewx, fixed_t viewy, bool partial = true, bool samebehind = true);
|
||||||
bool P_CheckPortal(line_t* line);
|
|
||||||
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y);
|
void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y);
|
||||||
void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy);
|
void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy);
|
||||||
void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
|
void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
|
||||||
|
@ -71,4 +96,27 @@ public:
|
||||||
/* new code */
|
/* new code */
|
||||||
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
|
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
|
||||||
|
|
||||||
|
|
||||||
|
// returns true if the portal is crossable by actors
|
||||||
|
inline bool line_t::isLinePortal() const
|
||||||
|
{
|
||||||
|
return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the portal needs to be handled by the renderer
|
||||||
|
inline bool line_t::isVisualPortal() const
|
||||||
|
{
|
||||||
|
return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline line_t *line_t::getPortalDestination() const
|
||||||
|
{
|
||||||
|
return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int line_t::getPortalAlignment() const
|
||||||
|
{
|
||||||
|
return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -99,7 +99,7 @@ static BYTE FakeSide;
|
||||||
|
|
||||||
int WindowLeft, WindowRight;
|
int WindowLeft, WindowRight;
|
||||||
WORD MirrorFlags;
|
WORD MirrorFlags;
|
||||||
TArray<PortalDrawseg> WallPortals;
|
TArray<PortalDrawseg> WallPortals(1000); // note: this array needs to go away as reallocation can cause crashes.
|
||||||
|
|
||||||
|
|
||||||
static subsector_t *InSubsector;
|
static subsector_t *InSubsector;
|
||||||
|
@ -590,7 +590,7 @@ void R_AddLine (seg_t *line)
|
||||||
rw_havehigh = rw_havelow = false;
|
rw_havehigh = rw_havelow = false;
|
||||||
|
|
||||||
// Single sided line?
|
// Single sided line?
|
||||||
if (backsector == NULL || (line->linedef->portal && line->sidedef == line->linedef->sidedef[0]))
|
if (backsector == NULL || (line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0]))
|
||||||
{
|
{
|
||||||
solid = true;
|
solid = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,8 +107,6 @@ extern size_t FirstInterestingDrawseg;
|
||||||
extern int WindowLeft, WindowRight;
|
extern int WindowLeft, WindowRight;
|
||||||
extern WORD MirrorFlags;
|
extern WORD MirrorFlags;
|
||||||
|
|
||||||
extern TArray<PortalDrawseg> WallPortals;
|
|
||||||
|
|
||||||
typedef void (*drawfunc_t) (int start, int stop);
|
typedef void (*drawfunc_t) (int start, int stop);
|
||||||
|
|
||||||
EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs?
|
EXTERN_CVAR (Bool, r_drawflat) // [RH] Don't texture segs?
|
||||||
|
|
16
src/r_defs.h
16
src/r_defs.h
|
@ -379,6 +379,7 @@ enum
|
||||||
PLANEF_NOPASS = 16,
|
PLANEF_NOPASS = 16,
|
||||||
PLANEF_BLOCKSOUND = 32,
|
PLANEF_BLOCKSOUND = 32,
|
||||||
PLANEF_DISABLED = 64,
|
PLANEF_DISABLED = 64,
|
||||||
|
PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal sector flags
|
// Internal sector flags
|
||||||
|
@ -1084,16 +1085,15 @@ struct line_t
|
||||||
sector_t *frontsector, *backsector;
|
sector_t *frontsector, *backsector;
|
||||||
int validcount; // if == validcount, already checked
|
int validcount; // if == validcount, already checked
|
||||||
int locknumber; // [Dusk] lock number for special
|
int locknumber; // [Dusk] lock number for special
|
||||||
line_t *portal_dst;
|
unsigned portalindex;
|
||||||
bool portal;
|
|
||||||
bool portal_mirror;
|
|
||||||
bool portal_passive;
|
|
||||||
TObjPtr<ASkyViewpoint> skybox;
|
TObjPtr<ASkyViewpoint> skybox;
|
||||||
|
|
||||||
bool isLinePortal() const
|
// returns true if the portal is crossable by actors
|
||||||
{
|
bool isLinePortal() const;
|
||||||
return portal;
|
// returns true if the portal needs to be handled by the renderer
|
||||||
}
|
bool isVisualPortal() const;
|
||||||
|
line_t *getPortalDestination() const;
|
||||||
|
int getPortalAlignment() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// phares 3/14/98
|
// phares 3/14/98
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "r_local.h"
|
#include "r_local.h"
|
||||||
#include "r_plane.h"
|
#include "r_plane.h"
|
||||||
#include "r_bsp.h"
|
#include "r_bsp.h"
|
||||||
|
#include "r_segs.h"
|
||||||
#include "r_3dfloors.h"
|
#include "r_3dfloors.h"
|
||||||
#include "r_sky.h"
|
#include "r_sky.h"
|
||||||
#include "st_stuff.h"
|
#include "st_stuff.h"
|
||||||
|
|
|
@ -67,6 +67,9 @@ CVAR(Bool, r_np2, true, 0)
|
||||||
|
|
||||||
extern fixed_t globaluclip, globaldclip;
|
extern fixed_t globaluclip, globaldclip;
|
||||||
|
|
||||||
|
PortalDrawseg* CurrentPortal = NULL;
|
||||||
|
int CurrentPortalUniq = 0;
|
||||||
|
bool CurrentPortalInSkybox = false;
|
||||||
|
|
||||||
// OPTIMIZE: closed two sided lines as single sided
|
// OPTIMIZE: closed two sided lines as single sided
|
||||||
|
|
||||||
|
@ -517,7 +520,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
|
||||||
wallupper[i] = mceilingclip[i];
|
wallupper[i] = mceilingclip[i];
|
||||||
}
|
}
|
||||||
mceilingclip = wallupper;
|
mceilingclip = wallupper;
|
||||||
}
|
}
|
||||||
if (fake3D & FAKE3D_CLIPBOTTOM)
|
if (fake3D & FAKE3D_CLIPBOTTOM)
|
||||||
{
|
{
|
||||||
OWallMost(walllower, sclipBottom - viewz, &WallC);
|
OWallMost(walllower, sclipBottom - viewz, &WallC);
|
||||||
|
@ -2001,8 +2004,7 @@ void R_NewWall (bool needlights)
|
||||||
midtexture = toptexture = bottomtexture = 0;
|
midtexture = toptexture = bottomtexture = 0;
|
||||||
|
|
||||||
if (sidedef == linedef->sidedef[0] &&
|
if (sidedef == linedef->sidedef[0] &&
|
||||||
linedef->portal &&
|
(linedef->isVisualPortal() || (linedef->special == Line_Mirror && r_drawmirrors))) // [ZZ] compatibility with r_drawmirrors cvar that existed way before portals
|
||||||
(!linedef->portal_mirror || r_drawmirrors)) // [ZZ] compatibility with r_drawmirrors cvar that existed way before portals
|
|
||||||
{
|
{
|
||||||
markfloor = markceiling = true; // act like an one-sided wall here (todo: check how does this work with transparency)
|
markfloor = markceiling = true; // act like an one-sided wall here (todo: check how does this work with transparency)
|
||||||
rw_markportal = true;
|
rw_markportal = true;
|
||||||
|
@ -2629,7 +2631,7 @@ void R_StoreWallRange (int start, int stop)
|
||||||
{
|
{
|
||||||
PortalDrawseg pds;
|
PortalDrawseg pds;
|
||||||
pds.src = curline->linedef;
|
pds.src = curline->linedef;
|
||||||
pds.dst = curline->linedef->portal_dst;
|
pds.dst = curline->linedef->special == Line_Mirror? curline->linedef : curline->linedef->getPortalDestination();
|
||||||
pds.x1 = ds_p->x1;
|
pds.x1 = ds_p->x1;
|
||||||
pds.x2 = ds_p->x2;
|
pds.x2 = ds_p->x2;
|
||||||
pds.len = pds.x2 - pds.x1;
|
pds.len = pds.x2 - pds.x1;
|
||||||
|
@ -2650,7 +2652,7 @@ void R_StoreWallRange (int start, int stop)
|
||||||
pds.floorclip[i] = RenderTarget->GetHeight()-1;
|
pds.floorclip[i] = RenderTarget->GetHeight()-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pds.mirror = curline->linedef->portal_mirror;
|
pds.mirror = curline->linedef->special == Line_Mirror;
|
||||||
WallPortals.Push(pds);
|
WallPortals.Push(pds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2761,11 +2763,6 @@ int OWallMost (short *mostbuf, fixed_t z, const FWallCoords *wallc)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
|
|
||||||
else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight;
|
|
||||||
if (mostbuf[ix2-1] < 0) mostbuf[ix2-1] = 0;
|
|
||||||
else if (mostbuf[ix2-1] > viewheight) mostbuf[ix2-1] = (short)viewheight;
|
|
||||||
|
|
||||||
return bad;
|
return bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2919,11 +2916,6 @@ int WallMost (short *mostbuf, const secplane_t &plane, const FWallCoords *wallc)
|
||||||
qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac,yinc);
|
qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac,yinc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
|
|
||||||
else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight;
|
|
||||||
if (mostbuf[ix2-1] < 0) mostbuf[ix2-1] = 0;
|
|
||||||
else if (mostbuf[ix2-1] > viewheight) mostbuf[ix2-1] = (short)viewheight;
|
|
||||||
|
|
||||||
return bad;
|
return bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
src/r_segs.h
21
src/r_segs.h
|
@ -49,4 +49,25 @@ extern fixed_t rw_lightstep;
|
||||||
extern fixed_t rw_lightleft;
|
extern fixed_t rw_lightleft;
|
||||||
extern fixed_t rw_offset;
|
extern fixed_t rw_offset;
|
||||||
|
|
||||||
|
/* portal structure, this is used in r_ code in order to store drawsegs with portals (and mirrors) */
|
||||||
|
struct PortalDrawseg
|
||||||
|
{
|
||||||
|
line_t* src; // source line (the one drawn) this doesn't change over render loops
|
||||||
|
line_t* dst; // destination line (the one that the portal is linked with, equals 'src' for mirrors)
|
||||||
|
|
||||||
|
int x1; // drawseg x1
|
||||||
|
int x2; // drawseg x2
|
||||||
|
|
||||||
|
int len;
|
||||||
|
TArray<short> ceilingclip;
|
||||||
|
TArray<short> floorclip;
|
||||||
|
|
||||||
|
bool mirror; // true if this is a mirror (src should equal dst)
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PortalDrawseg* CurrentPortal;
|
||||||
|
extern int CurrentPortalUniq;
|
||||||
|
extern bool CurrentPortalInSkybox;
|
||||||
|
extern TArray<PortalDrawseg> WallPortals;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "p_lnspec.h"
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
#include "doomdef.h"
|
#include "doomdef.h"
|
||||||
#include "m_swap.h"
|
#include "m_swap.h"
|
||||||
|
@ -339,11 +340,11 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit
|
||||||
if (!seg->curline) continue;
|
if (!seg->curline) continue;
|
||||||
|
|
||||||
line_t* line = seg->curline->linedef;
|
line_t* line = seg->curline->linedef;
|
||||||
// divline? wtf, anyway, divlines aren't supposed to be drawn. But I definitely saw NULL linedefs in drawsegs.
|
// ignore minisegs from GL nodes.
|
||||||
if (!line) continue;
|
if (!line) continue;
|
||||||
|
|
||||||
// check if this line will clip sprites to itself
|
// check if this line will clip sprites to itself
|
||||||
if (!line->portal)
|
if (!line->isVisualPortal() && line->special != Line_Mirror)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// don't clip sprites with portal's back side (it's transparent)
|
// don't clip sprites with portal's back side (it's transparent)
|
||||||
|
@ -739,7 +740,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor
|
||||||
|
|
||||||
// [ZZ] Or less definitely not visible (hue)
|
// [ZZ] Or less definitely not visible (hue)
|
||||||
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal.
|
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal.
|
||||||
if (!CurrentPortalInSkybox && CurrentPortal && !!P_PointOnLineSide(thing->X(), thing->Y(), CurrentPortal->dst))
|
if (!CurrentPortalInSkybox && CurrentPortal && !!P_PointOnLineSidePrecise(thing->X(), thing->Y(), CurrentPortal->dst))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// [RH] Interpolate the sprite's position to make it look smooth
|
// [RH] Interpolate the sprite's position to make it look smooth
|
||||||
|
|
|
@ -58,6 +58,11 @@ inline int R_PointOnSide (fixed_t x, fixed_t y, const node_t *node)
|
||||||
|
|
||||||
angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
|
angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
|
||||||
inline angle_t R_PointToAngle (fixed_t x, fixed_t y) { return R_PointToAngle2 (viewx, viewy, x, y); }
|
inline angle_t R_PointToAngle (fixed_t x, fixed_t y) { return R_PointToAngle2 (viewx, viewy, x, y); }
|
||||||
|
inline angle_t R_PointToAnglePrecise (fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y)
|
||||||
|
{
|
||||||
|
return xs_RoundToUInt(atan2(double(y-viewy), double(x-viewx)) * (ANGLE_180/M_PI));
|
||||||
|
}
|
||||||
|
|
||||||
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
|
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
|
||||||
fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy);
|
fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy);
|
||||||
void R_ResetViewInterpolation ();
|
void R_ResetViewInterpolation ();
|
||||||
|
|
|
@ -856,7 +856,7 @@ int FScanner::MustMatchString (const char * const *strings, size_t stride)
|
||||||
i = MatchString (strings, stride);
|
i = MatchString (strings, stride);
|
||||||
if (i == -1)
|
if (i == -1)
|
||||||
{
|
{
|
||||||
ScriptError (NULL);
|
ScriptError ("Unknown keyword '%s'", String);
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
@ -676,7 +676,7 @@ static void DoJump(AActor *self, AActor *stateowner, FState *callingstate, FStat
|
||||||
{
|
{
|
||||||
P_SetPsprite(self->player, ps_flash, jumpto);
|
P_SetPsprite(self->player, ps_flash, jumpto);
|
||||||
}
|
}
|
||||||
else if (callingstate == self->state)
|
else if (callingstate == self->state || (self->ObjectFlags & OF_StateChanged))
|
||||||
{
|
{
|
||||||
// Rather than using self->SetState(jumpto) to set the state,
|
// Rather than using self->SetState(jumpto) to set the state,
|
||||||
// set the state directly. Since this function is only called by
|
// set the state directly. Since this function is only called by
|
||||||
|
|
|
@ -892,6 +892,19 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxReturnStatement
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxReturnStatement : public FxTailable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FxReturnStatement(const FScriptPosition &pos);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -3484,6 +3484,21 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build, bool tailcall)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
FxReturnStatement::FxReturnStatement(const FScriptPosition &pos)
|
||||||
|
: FxTailable(pos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build, bool tailcall)
|
||||||
|
{
|
||||||
|
build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
FxClassTypeCast::FxClassTypeCast(const PClass *dtype, FxExpression *x)
|
FxClassTypeCast::FxClassTypeCast(const PClass *dtype, FxExpression *x)
|
||||||
: FxExpression(x->ScriptPosition)
|
: FxExpression(x->ScriptPosition)
|
||||||
{
|
{
|
||||||
|
|
|
@ -386,6 +386,12 @@ FxTailable *ParseActions(FScanner &sc, FState state, FString statestring, Baggag
|
||||||
}
|
}
|
||||||
add = new FxIfStatement(cond, true_part, false_part, sc);
|
add = new FxIfStatement(cond, true_part, false_part, sc);
|
||||||
}
|
}
|
||||||
|
else if (sc.Compare("return"))
|
||||||
|
{ // Handle a return statement
|
||||||
|
sc.MustGetStringName(";");
|
||||||
|
sc.MustGetString();
|
||||||
|
add = new FxReturnStatement(sc);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{ // Handle a regular action function call
|
{ // Handle a regular action function call
|
||||||
add = ParseAction(sc, state, statestring, bag);
|
add = ParseAction(sc, state, statestring, bag);
|
||||||
|
|
|
@ -76,7 +76,7 @@ const char *GetVersionString();
|
||||||
|
|
||||||
// Use 4500 as the base git save version, since it's higher than the
|
// Use 4500 as the base git save version, since it's higher than the
|
||||||
// SVN revision ever got.
|
// SVN revision ever got.
|
||||||
#define SAVEVER 4531
|
#define SAVEVER 4532
|
||||||
|
|
||||||
#define SAVEVERSTRINGIFY2(x) #x
|
#define SAVEVERSTRINGIFY2(x) #x
|
||||||
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
DoomEdNums
|
DoomEdNums
|
||||||
{
|
{
|
||||||
5003 = none
|
5003 = none
|
||||||
5004 = "$EDFThing"
|
5004 = "$EDThing"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,9 +67,7 @@ enum
|
||||||
// Parameterized linedefs
|
// Parameterized linedefs
|
||||||
// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270.
|
// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270.
|
||||||
// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF.
|
// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF.
|
||||||
// The translation here is for the odd EDF that specifies them as numbers.
|
// The translation here is for the odd Extradata that specifies them as numbers.
|
||||||
|
|
||||||
/*
|
|
||||||
300 = 0, Door_Raise(0)
|
300 = 0, Door_Raise(0)
|
||||||
301 = 0, Door_Open(0)
|
301 = 0, Door_Open(0)
|
||||||
302 = 0, Door_Close(0)
|
302 = 0, Door_Close(0)
|
||||||
|
@ -77,7 +75,7 @@ enum
|
||||||
304 = 0, Door_WaitRaise(0)
|
304 = 0, Door_WaitRaise(0)
|
||||||
305 = 0, Door_WaitClose(0)
|
305 = 0, Door_WaitClose(0)
|
||||||
306 = 0, Floor_RaiseToHighest(0)
|
306 = 0, Floor_RaiseToHighest(0)
|
||||||
307 = 0, Floor_LowerToHighest(0)
|
307 = 0, Floor_LowerToHighestEE(0)
|
||||||
308 = 0, Floor_RaiseToLowest(0)
|
308 = 0, Floor_RaiseToLowest(0)
|
||||||
309 = 0, Floor_LowerToLowest(0)
|
309 = 0, Floor_LowerToLowest(0)
|
||||||
310 = 0, Floor_RaiseToNearest(0)
|
310 = 0, Floor_RaiseToNearest(0)
|
||||||
|
@ -114,7 +112,6 @@ enum
|
||||||
341 = 0, Stairs_BuildDownDoom(0)
|
341 = 0, Stairs_BuildDownDoom(0)
|
||||||
342 = 0, Stairs_BuildUpDoomSync(0)
|
342 = 0, Stairs_BuildUpDoomSync(0)
|
||||||
343 = 0, Stairs_BuildDownDoomSync(0)
|
343 = 0, Stairs_BuildDownDoomSync(0)
|
||||||
*/
|
|
||||||
|
|
||||||
// Two-way portals are not supported yet either
|
// Two-way portals are not supported yet either
|
||||||
344 = 0, Unsupported() // "Portal_TwowayCeiling"
|
344 = 0, Unsupported() // "Portal_TwowayCeiling"
|
||||||
|
@ -157,11 +154,11 @@ enum
|
||||||
375 = 0, Radius_Quake(0)
|
375 = 0, Radius_Quake(0)
|
||||||
|
|
||||||
// Eternity's linked portals, horizontal link version (wall-to-wall)
|
// Eternity's linked portals, horizontal link version (wall-to-wall)
|
||||||
376 = 0, Unsupported() // "Portal_LinkedLineToLine"
|
376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine"
|
||||||
377 = 0, Unsupported() // "Portal_LinkedLineToLineAnchor"
|
377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor"
|
||||||
|
|
||||||
// The famous Hexen linedef
|
// The famous Hexen linedef
|
||||||
// 378 = Line_SetIdentification
|
378 = 0, Line_SetIdentification(0)
|
||||||
|
|
||||||
// Attached sectors == linked sectors; However, the implementation in Eternity
|
// Attached sectors == linked sectors; However, the implementation in Eternity
|
||||||
// is based on front sectors of tagged lines, not on sector tags. So instead
|
// is based on front sectors of tagged lines, not on sector tags. So instead
|
||||||
|
|
Loading…
Reference in a new issue