/
portal.h
301 lines (252 loc) · 6.95 KB
/
portal.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#ifndef _PORTALS_H_
#define _PORTALS_H_
#include "basics.h"
#include "m_bbox.h"
struct linebase_t;
struct line_t;
struct sector_t;
struct FPortalGroupArray;
struct portnode_t;
struct subsector_t;
//============================================================================
//
// 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
//
//============================================================================
struct FDisplacement
{
DVector2 pos;
bool isSet;
uint8_t indirect; // just for illustration.
};
struct FDisplacementTable
{
TArray<FDisplacement> data;
int size;
FDisplacementTable()
{
Create(1);
}
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];
}
DVector2 getOffset(int x, int y) const
{
if (x == y)
{
DVector2 nulvec = { 0,0 };
return nulvec; // shortcut for the most common case
}
return data[x + size*y].pos;
}
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;
}
}
};
//============================================================================
//
// A blockmap that only contains crossable portals
// This is used for quick checks if a vector crosses through one.
//
//============================================================================
struct FPortalBlock
{
bool neighborContainsLines; // this is for skipping the traverser and exiting early if we can quickly decide that there's no portals nearby.
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.
TArray<line_t*> portallines;
FPortalBlock()
{
neighborContainsLines = false;
containsLinkedPortals = false;
}
};
struct FPortalBlockmap
{
TArray<FPortalBlock> data;
int dx, dy;
bool containsLines;
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.
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;
hasLinkedPolyPortals = false;
hasLinkedSectorPortals = false;
}
FPortalBlock &operator()(int x, int y)
{
return data[x + dx*y];
}
};
//============================================================================
//
// Flags and types for linedef portals
//
//============================================================================
enum
{
PORTF_VISIBLE = 1,
PORTF_PASSABLE = 2,
PORTF_SOUNDTRAVERSE = 4,
PORTF_INTERACTIVE = 8,
PORTF_POLYOBJ = 16,
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,
};
enum
{
PCOLL_NOTLINKED = 1,
PCOLL_LINKED = 2
};
//============================================================================
//
// All information about a line-to-line portal (all types)
//
//============================================================================
struct FLinePortalSpan;
struct vertex_t;
struct FLinePortal
{
line_t *mOrigin;
line_t *mDestination;
DVector2 mDisplacement;
uint8_t mType;
uint8_t mFlags;
uint8_t mDefFlags;
uint8_t mAlign;
DAngle mAngleDiff;
double mSinRot;
double mCosRot;
portnode_t *lineportal_thinglist;
FLinePortalSpan *mGroup;
FLinePortal()
{
Clear();
}
void Clear()
{
memset((void*)this, 0, sizeof * this);
}
};
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;
};
//============================================================================
//
// 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;
TObjPtr<AActor*> mSkybox;
FSectorPortal()
{
Clear();
}
void Clear()
{
memset((void*)this, 0, sizeof * this);
}
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)));
}
};
//============================================================================
//
// This groups all sector portals with identical offset.
//
//============================================================================
struct FSectorPortalGroup
{
DVector2 mDisplacement;
int plane;
};
//============================================================================
//
// Functions
//
//============================================================================
/* code ported from prototype */
bool P_ClipLineToPortal(linebase_t* line, linebase_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);
void P_TranslatePortalAngle(line_t* src, DAngle& angle);
void P_TranslatePortalZ(line_t* src, double& vz);
struct FLevelLocals;
void InitPortalGroups(FLevelLocals *Level);
#endif