2015-06-07 17:54:36 +00:00
# ifndef _PORTALS_H_
# define _PORTALS_H_
# include "basictypes.h"
# include "v_video.h"
# include "m_bbox.h"
2016-02-16 11:51:10 +00:00
struct FPortalGroupArray ;
2016-02-15 12:40:31 +00:00
//============================================================================
//
// This table holds the offsets for the different parts of a map
// that are connected by portals.
// The idea here is basically the same as implemented in Eternity Engine:
//
// - each portal creates two sector groups in the map
// which are offset by the displacement of the portal anchors
//
// - for two or multiple groups the displacement is calculated by
// adding the displacements between intermediate groups which
// have to be traversed to connect the two
//
// - any sector not connected to any portal is assigned to group 0
// Group 0 has no displacement to any other group in the level.
//
//============================================================================
2016-02-14 15:26:27 +00:00
struct FDisplacement
{
2016-02-16 15:40:53 +00:00
fixedvec2 pos ;
2016-02-14 15:26:27 +00:00
bool isSet ;
BYTE indirect ; // just for illustration.
2016-02-16 15:40:53 +00:00
2016-02-14 15:26:27 +00:00
} ;
struct FDisplacementTable
{
TArray < FDisplacement > data ;
int size ;
2016-02-19 18:14:49 +00:00
FDisplacementTable ( )
{
Create ( 1 ) ;
}
2016-02-14 15:26:27 +00:00
void Create ( int numgroups )
{
data . Resize ( numgroups * numgroups ) ;
memset ( & data [ 0 ] , 0 , numgroups * numgroups * sizeof ( data [ 0 ] ) ) ;
size = numgroups ;
}
FDisplacement & operator ( ) ( int x , int y )
{
return data [ x + size * y ] ;
}
2016-02-25 15:50:03 +00:00
2016-03-25 15:25:25 +00:00
fixedvec2 _f_getOffset ( int x , int y ) const
2016-02-25 15:50:03 +00:00
{
2016-02-25 16:04:34 +00:00
if ( x = = y )
{
fixedvec2 nulvec = { 0 , 0 } ;
return nulvec ; // shortcut for the most common case
}
2016-02-25 15:50:03 +00:00
return data [ x + size * y ] . pos ;
}
2016-03-25 15:25:25 +00:00
DVector2 getOffset ( int x , int y ) const
{
if ( x = = y )
{
DVector2 nulvec = { 0 , 0 } ;
return nulvec ; // shortcut for the most common case
}
fixedvec2 & p = data [ x + size * y ] . pos ;
return { FIXED2DBL ( p . x ) , FIXED2DBL ( p . y ) } ;
}
2016-02-14 15:26:27 +00:00
} ;
2016-02-05 22:15:56 +00:00
2016-02-14 23:53:59 +00:00
extern FDisplacementTable Displacements ;
2016-02-25 12:00:23 +00:00
//============================================================================
//
// A blockmap that only contains crossable portals
// This is used for quick checks if a vector crosses through one.
//
//============================================================================
struct FPortalBlock
{
2016-02-25 15:50:03 +00:00
bool neighborContainsLines ; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby.
2016-03-07 20:58:34 +00:00
bool containsLinkedPortals ; // this is for sight check optimization. We can't early-out on an impenetrable line if there may be portals being found in the same block later on.
2016-02-25 12:00:23 +00:00
TArray < line_t * > portallines ;
2016-02-25 15:50:03 +00:00
FPortalBlock ( )
{
neighborContainsLines = false ;
2016-03-07 20:58:34 +00:00
containsLinkedPortals = false ;
2016-02-25 15:50:03 +00:00
}
2016-02-25 12:00:23 +00:00
} ;
struct FPortalBlockmap
{
TArray < FPortalBlock > data ;
int dx , dy ;
bool containsLines ;
2016-03-07 20:58:34 +00:00
bool hasLinkedSectorPortals ; // global flag to shortcut portal checks if the map has none.
bool hasLinkedPolyPortals ; // this means that any early-outs in P_CheckSight need to be disabled if a block contains polyobjects.
2016-02-25 12:00:23 +00:00
void Create ( int blockx , int blocky )
{
data . Resize ( blockx * blocky ) ;
dx = blockx ;
dy = blocky ;
}
void Clear ( )
{
data . Clear ( ) ;
data . ShrinkToFit ( ) ;
dx = dy = 0 ;
containsLines = false ;
2016-03-07 20:58:34 +00:00
hasLinkedPolyPortals = false ;
hasLinkedSectorPortals = false ;
2016-02-25 12:00:23 +00:00
}
FPortalBlock & operator ( ) ( int x , int y )
{
return data [ x + dx * y ] ;
}
} ;
extern FPortalBlockmap PortalBlockmap ;
2016-02-15 12:40:31 +00:00
//============================================================================
//
// Flags and types for linedef portals
//
//============================================================================
2016-02-14 23:53:59 +00:00
2016-02-05 22:15:56 +00:00
enum
{
PORTF_VISIBLE = 1 ,
PORTF_PASSABLE = 2 ,
PORTF_SOUNDTRAVERSE = 4 ,
PORTF_INTERACTIVE = 8 ,
PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE ,
PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE ,
} ;
enum
{
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 ,
} ;
2016-02-14 23:53:59 +00:00
enum
{
PCOLL_NOTLINKED = 1 ,
PCOLL_LINKED = 2
} ;
2016-02-15 12:40:31 +00:00
//============================================================================
//
// All information about a line-to-line portal (all types)
// There is no structure for sector plane portals because for historic
// reasons those use actors to connect.
//
//============================================================================
2016-02-05 22:15:56 +00:00
struct FLinePortal
{
line_t * mOrigin ;
line_t * mDestination ;
fixed_t mXDisplacement ;
fixed_t mYDisplacement ;
BYTE mType ;
BYTE mFlags ;
BYTE mDefFlags ;
BYTE mAlign ;
2016-03-16 11:41:26 +00:00
DAngle mAngleDiff ;
2016-03-03 10:58:04 +00:00
fixed_t mSinRot ;
fixed_t mCosRot ;
2016-02-05 22:15:56 +00:00
} ;
extern TArray < FLinePortal > linePortals ;
2016-02-19 19:51:47 +00:00
void P_ClearPortals ( ) ;
2016-02-05 15:58:57 +00:00
void P_SpawnLinePortal ( line_t * line ) ;
2016-02-05 22:15:56 +00:00
void P_FinalizePortals ( ) ;
2016-02-06 20:16:57 +00:00
bool P_ChangePortal ( line_t * ln , int thisid , int destid ) ;
2016-02-14 12:12:03 +00:00
void P_CreateLinkedPortals ( ) ;
2016-02-19 09:39:40 +00:00
bool P_CollectConnectedGroups ( int startgroup , const fixedvec3 & position , fixed_t upperz , fixed_t checkradius , FPortalGroupArray & out ) ;
2016-02-14 23:53:59 +00:00
void P_CollectLinkedPortals ( ) ;
inline int P_NumPortalGroups ( )
{
return Displacements . size ;
}
2016-02-05 15:58:57 +00:00
2015-06-07 17:54:36 +00:00
/* 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 ) ;
2016-03-03 10:58:04 +00:00
void P_TranslatePortalXY ( line_t * src , fixed_t & x , fixed_t & y ) ;
void P_TranslatePortalVXVY ( line_t * src , fixed_t & vx , fixed_t & vy ) ;
2016-03-19 23:54:18 +00:00
inline void P_TranslatePortalVXVY ( line_t * src , double & vx , double & vy )
{
fixed_t x = FLOAT2FIXED ( vx ) ;
fixed_t y = FLOAT2FIXED ( vy ) ;
P_TranslatePortalVXVY ( src , x , y ) ;
vx = FIXED2DBL ( x ) ;
vx = FIXED2DBL ( y ) ;
}
2016-03-16 11:41:26 +00:00
void P_TranslatePortalAngle ( line_t * src , DAngle & angle ) ;
2016-03-03 10:58:04 +00:00
void P_TranslatePortalZ ( line_t * src , fixed_t & z ) ;
2015-06-07 17:54:36 +00:00
void P_NormalizeVXVY ( fixed_t & vx , fixed_t & vy ) ;
fixed_t P_PointLineDistance ( line_t * line , fixed_t x , fixed_t y ) ;
2016-02-29 15:29:51 +00:00
fixedvec2 P_GetOffsetPosition ( fixed_t x , fixed_t y , fixed_t dx , fixed_t dy ) ;
2015-06-07 17:54:36 +00:00
2016-03-22 11:42:27 +00:00
inline DVector2 P_GetOffsetPosition ( double x , double y , double dx , double dy )
{
fixedvec2 v = P_GetOffsetPosition ( FLOAT2FIXED ( x ) , FLOAT2FIXED ( y ) , FLOAT2FIXED ( dx ) , FLOAT2FIXED ( dy ) ) ;
return { FIXED2DBL ( v . x ) , FIXED2DBL ( v . y ) } ;
}
2015-06-07 17:54:36 +00:00
# endif