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-04-21 20:59:07 +00:00
struct portnode_t ;
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-03-31 14:52:25 +00:00
DVector2 pos ;
2016-02-14 15:26:27 +00:00
bool isSet ;
2017-03-08 14:20:00 +00:00
uint8_t 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
DVector2 getOffset ( int x , int y ) const
{
if ( x = = y )
{
DVector2 nulvec = { 0 , 0 } ;
return nulvec ; // shortcut for the most common case
}
2016-03-31 14:52:25 +00:00
return data [ x + size * y ] . pos ;
2016-03-25 15:25:25 +00:00
}
2016-04-17 15:10:11 +00:00
void MoveGroup ( int grp , DVector2 delta )
{
for ( int i = 1 ; i < size ; i + + )
{
data [ grp + size * i ] . pos - = delta ;
data [ i + grp * size ] . pos + = delta ;
}
}
2016-02-14 15:26:27 +00:00
} ;
2016-02-05 22:15:56 +00:00
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 ] ;
}
} ;
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 ,
2016-06-19 10:32:45 +00:00
PORTF_POLYOBJ = 16 ,
2016-02-05 22:15:56 +00:00
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)
//
//============================================================================
2018-04-01 20:26:57 +00:00
struct FLinePortalSpan ;
struct vertex_t ;
2016-02-15 12:40:31 +00:00
2016-02-05 22:15:56 +00:00
struct FLinePortal
{
line_t * mOrigin ;
line_t * mDestination ;
2016-03-27 11:29:58 +00:00
DVector2 mDisplacement ;
2017-03-08 14:20:00 +00:00
uint8_t mType ;
uint8_t mFlags ;
uint8_t mDefFlags ;
uint8_t mAlign ;
2016-03-16 11:41:26 +00:00
DAngle mAngleDiff ;
2016-03-31 14:52:25 +00:00
double mSinRot ;
double mCosRot ;
2017-01-06 10:56:17 +00:00
portnode_t * lineportal_thinglist ;
2018-04-01 20:26:57 +00:00
FLinePortalSpan * mGroup ;
2016-02-05 22:15:56 +00:00
} ;
2018-04-01 20:26:57 +00:00
struct FLinePortalSpan
{
// defines the complete span of connected colinear line portals, if they are of type PORTT_LINKED.
vertex_t * v1 = nullptr , * v2 = nullptr ; // vertices, from v1 to v2
TArray < FLinePortal * > lines ;
int validcount = 0 ;
} ;
2016-04-20 17:20:11 +00:00
//============================================================================
//
// All information about a sector plane portal
//
//============================================================================
enum
{
PORTS_SKYVIEWPOINT = 0 , // a regular skybox
PORTS_STACKEDSECTORTHING , // stacked sectors with the thing method
PORTS_PORTAL , // stacked sectors with Sector_SetPortal
PORTS_LINKEDPORTAL , // linked portal (interactive)
PORTS_PLANE , // EE-style plane portal (not implemented in SW renderer)
PORTS_HORIZON , // EE-style horizon portal (not implemented in SW renderer)
} ;
enum
{
PORTSF_SKYFLATONLY = 1 , // portal is only active on skyflatnum
PORTSF_INSKYBOX = 2 , // to avoid recursion
} ;
struct FSectorPortal
{
int mType ;
int mFlags ;
unsigned mPartner ;
int mPlane ;
sector_t * mOrigin ;
sector_t * mDestination ;
DVector2 mDisplacement ;
double mPlaneZ ;
2017-03-08 12:34:26 +00:00
TObjPtr < AActor * > mSkybox ;
2016-04-20 17:20:11 +00:00
bool MergeAllowed ( ) const
{
// For thing based stack sectors and regular skies the portal has no relevance for merging visplanes.
return ( mType = = PORTS_STACKEDSECTORTHING | | ( mType = = PORTS_SKYVIEWPOINT & & ( mFlags & PORTSF_SKYFLATONLY ) ) ) ;
}
} ;
2018-04-01 20:26:57 +00:00
//============================================================================
//
// This groups all sector portals with identical offset.
//
//============================================================================
struct GLSectorStackPortal ;
struct FSectorPortalGroup
{
DVector2 mDisplacement ;
int plane ;
GLSectorStackPortal * glportal ; // for quick access to the render data. This is only valid during BSP traversal!
GLSectorStackPortal * GetRenderState ( ) ;
} ;
2016-04-20 17:20:11 +00:00
//============================================================================
//
// Functions
//
//============================================================================
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-03-31 14:52:25 +00:00
bool P_CollectConnectedGroups ( int startgroup , const DVector3 & position , double upperz , double checkradius , FPortalGroupArray & out ) ;
2016-02-14 23:53:59 +00:00
void P_CollectLinkedPortals ( ) ;
2017-01-14 15:05:40 +00:00
unsigned P_GetSkyboxPortal ( AActor * actor ) ;
2016-04-20 17:20:11 +00:00
unsigned P_GetPortal ( int type , int plane , sector_t * orgsec , sector_t * destsec , const DVector2 & displacement ) ;
unsigned P_GetStackPortal ( AActor * point , int plane ) ;
2016-02-05 15:58:57 +00:00
2015-06-07 17:54:36 +00:00
/* code ported from prototype */
2016-03-31 14:52:25 +00:00
bool P_ClipLineToPortal ( line_t * line , line_t * portal , DVector2 view , bool partial = true , bool samebehind = true ) ;
void P_TranslatePortalXY ( line_t * src , double & vx , double & vy ) ;
void P_TranslatePortalVXVY ( line_t * src , double & velx , double & vely ) ;
2016-03-16 11:41:26 +00:00
void P_TranslatePortalAngle ( line_t * src , DAngle & angle ) ;
2016-03-31 14:52:25 +00:00
void P_TranslatePortalZ ( line_t * src , double & vz ) ;
DVector2 P_GetOffsetPosition ( double x , double y , double dx , double dy ) ;
2018-04-01 20:26:57 +00:00
void InitPortalGroups ( ) ;
2016-03-22 11:42:27 +00:00
2015-06-07 17:54:36 +00:00
# endif