forked from shokunin000/te120
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdispcoll_common.h
456 lines (373 loc) · 15.9 KB
/
dispcoll_common.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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DISPCOLL_COMMON_H
#define DISPCOLL_COMMON_H
#pragma once
#include "trace.h"
#include "builddisp.h"
#include "bitvec.h"
#ifdef ENGINE_DLL
#include "../engine/zone.h"
#endif
#ifdef ENGINE_DLL
template<typename T>
class CDispVector : public CUtlVector<T, CHunkMemory<T> >
{
};
#else
template<typename T>
class CDispVector : public CUtlVector<T, CUtlMemoryAligned<T,16> >
{
};
#endif
FORWARD_DECLARE_HANDLE( memhandle_t );
#define DISPCOLL_TREETRI_SIZE MAX_DISPTRIS
#define DISPCOLL_DIST_EPSILON 0.03125f
#define DISPCOLL_ROOTNODE_INDEX 0
#define DISPCOLL_INVALID_TRI -1
#define DISPCOLL_INVALID_FRAC -99999.9f
#define DISPCOLL_NORMAL_UNDEF 0xffff
extern double g_flDispCollSweepTimer;
extern double g_flDispCollIntersectTimer;
extern double g_flDispCollInCallTimer;
struct RayDispOutput_t
{
short ndxVerts[4]; // 3 verts and a pad
float u, v; // the u, v paramters (edgeU = v1 - v0, edgeV = v2 - v0)
float dist; // intersection distance
};
// Assumptions:
// Max patch is 17x17, therefore 9 bits needed to represent a triangle index
//
//=============================================================================
// Displacement Collision Triangle
class CDispCollTri
{
struct index_t
{
union
{
struct
{
unsigned short uiVert:9;
unsigned short uiMin:2;
unsigned short uiMax:2;
} m_Index;
unsigned short m_IndexDummy;
};
};
index_t m_TriData[3];
public:
unsigned short m_ucSignBits:3; // Plane test.
unsigned short m_ucPlaneType:3; // Axial test?
unsigned short m_uiFlags:5; // Uses 5-bits - maybe look into merging it with something?
Vector m_vecNormal; // Triangle normal (plane normal).
float m_flDist; // Triangle plane dist.
// Creation.
CDispCollTri();
void Init( void );
void CalcPlane( CDispVector<Vector> &m_aVerts );
void FindMinMax( CDispVector<Vector> &m_aVerts );
// Triangle data.
inline void SetVert( int iPos, int iVert ) { Assert( ( iPos >= 0 ) && ( iPos < 3 ) ); Assert( ( iVert >= 0 ) && ( iVert < ( 1 << 9 ) ) ); m_TriData[iPos].m_Index.uiVert = iVert; }
inline int GetVert( int iPos ) const { Assert( ( iPos >= 0 ) && ( iPos < 3 ) ); return m_TriData[iPos].m_Index.uiVert; }
inline void SetMin( int iAxis, int iMin ) { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); Assert( ( iMin >= 0 ) && ( iMin < 3 ) ); m_TriData[iAxis].m_Index.uiMin = iMin; }
inline int GetMin( int iAxis ) const { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); return m_TriData[iAxis].m_Index.uiMin; }
inline void SetMax( int iAxis, int iMax ) { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); Assert( ( iMax >= 0 ) && ( iMax < 3 ) ); m_TriData[iAxis].m_Index.uiMax = iMax; }
inline int GetMax( int iAxis ) const { Assert( ( iAxis >= 0 ) && ( iAxis < 3 ) ); return m_TriData[iAxis].m_Index.uiMax; }
};
//=============================================================================
// Helper
class CDispCollHelper
{
public:
float m_flStartFrac;
float m_flEndFrac;
Vector m_vecImpactNormal;
float m_flImpactDist;
};
//=============================================================================
// Cache
#pragma pack(1)
class CDispCollTriCache
{
public:
unsigned short m_iCrossX[3];
unsigned short m_iCrossY[3];
unsigned short m_iCrossZ[3];
};
#pragma pack()
#include "mathlib/ssemath.h"
class CDispCollNode
{
public:
FourVectors m_mins;
FourVectors m_maxs;
};
class CDispCollLeaf
{
public:
short m_tris[2];
};
// a power 4 displacement can have 341 nodes, pad out to 344 for 16-byte alignment
const int MAX_DISP_AABB_NODES = 341;
const int MAX_AABB_LIST = 344;
struct rayleaflist_t
{
FourVectors rayStart;
FourVectors rayExtents;
FourVectors invDelta;
int nodeList[MAX_AABB_LIST];
int maxIndex;
};
//=============================================================================
//
// Displacement Collision Tree Data
//
class CDispCollTree
{
public:
// Creation/Destruction.
CDispCollTree();
~CDispCollTree();
virtual bool Create( CCoreDispInfo *pDisp );
// Raycasts.
// NOTE: These assume you've precalculated invDelta as well as culled to the bounds of this disp
bool AABBTree_Ray( const Ray_t &ray, const Vector &invDelta, CBaseTrace *pTrace, bool bSide = true );
bool AABBTree_Ray( const Ray_t &ray, const Vector &invDelta, RayDispOutput_t &output );
// NOTE: Lower perf helper function, should not be used in the game runtime
bool AABBTree_Ray( const Ray_t &ray, RayDispOutput_t &output );
// Hull Sweeps.
// NOTE: These assume you've precalculated invDelta as well as culled to the bounds of this disp
bool AABBTree_SweepAABB( const Ray_t &ray, const Vector &invDelta, CBaseTrace *pTrace );
// Hull Intersection.
bool AABBTree_IntersectAABB( const Vector &absMins, const Vector &absMaxs );
// Point/Box vs. Bounds.
bool PointInBounds( Vector const &vecBoxCenter, Vector const &vecBoxMin, Vector const &vecBoxMax, bool bPoint );
// Utility.
inline void SetPower( int power ) { m_nPower = power; }
inline int GetPower( void ) { return m_nPower; }
inline int GetFlags( void ) { return m_nFlags; }
inline void SetFlags( int nFlags ) { m_nFlags = nFlags; }
inline bool CheckFlags( int nFlags ) { return ( ( nFlags & GetFlags() ) != 0 ) ? true : false; }
inline int GetWidth( void ) { return ( ( 1 << m_nPower ) + 1 ); }
inline int GetHeight( void ) { return ( ( 1 << m_nPower ) + 1 ); }
inline int GetSize( void ) { return ( ( 1 << m_nPower ) + 1 ) * ( ( 1 << m_nPower ) + 1 ); }
inline int GetTriSize( void ) { return ( ( 1 << m_nPower ) * ( 1 << m_nPower ) * 2 ); }
// inline void SetTriFlags( short iTri, unsigned short nFlags ) { m_aTris[iTri].m_uiFlags = nFlags; }
inline void GetStabDirection( Vector &vecDir ) { vecDir = m_vecStabDir; }
inline void GetBounds( Vector &vecBoxMin, Vector &vecBoxMax ) { vecBoxMin = m_mins; vecBoxMax = m_maxs; }
inline int GetContents( void ) { return m_nContents; }
inline void SetSurfaceProps( int iProp, short nSurfProp ) { Assert( ( iProp >= 0 ) && ( iProp < 2 ) ); m_nSurfaceProps[iProp] = nSurfProp; }
inline short GetSurfaceProps( int iProp ) { return m_nSurfaceProps[iProp]; }
inline unsigned int GetMemorySize( void ) { return m_nSize; }
inline unsigned int GetCacheMemorySize( void ) { return ( m_aTrisCache.Count() * sizeof(CDispCollTriCache) + m_aEdgePlanes.Count() * sizeof(Vector) ); }
inline bool IsCached( void ) { return m_aTrisCache.Count() == m_aTris.Count(); }
void GetVirtualMeshList( struct virtualmeshlist_t *pList );
int AABBTree_GetTrisInSphere( const Vector ¢er, float radius, unsigned short *pIndexOut, int indexMax );
public:
inline int Nodes_GetChild( int iNode, int nDirection );
inline int Nodes_CalcCount( int nPower );
inline int Nodes_GetParent( int iNode );
inline int Nodes_GetLevel( int iNode );
inline int Nodes_GetIndexFromComponents( int x, int y );
void LockCache();
void UnlockCache();
void Cache( void );
void Uncache() { m_aTrisCache.Purge(); m_aEdgePlanes.Purge(); }
#ifdef ENGINE_DLL
// Data manager methods
static size_t EstimatedSize( CDispCollTree *pTree )
{
return pTree->GetCacheMemorySize();
}
static CDispCollTree *CreateResource( CDispCollTree *pTree )
{
// Created ahead of time
return pTree;
}
bool GetData()
{
return IsCached();
}
size_t Size()
{
return GetCacheMemorySize();
}
void DestroyResource()
{
Uncache();
m_hCache = NULL;
}
#endif
protected:
bool AABBTree_Create( CCoreDispInfo *pDisp );
void AABBTree_CopyDispData( CCoreDispInfo *pDisp );
void AABBTree_CreateLeafs( void );
void AABBTree_GenerateBoxes_r( int nodeIndex, Vector *pMins, Vector *pMaxs );
void AABBTree_CalcBounds( void );
int AABBTree_BuildTreeTrisInSphere_r( const Vector ¢er, float radius, int iNode, unsigned short *pIndexOut, unsigned short indexMax );
void AABBTree_TreeTrisRayTest( const Ray_t &ray, const Vector &vecInvDelta, int iNode, CBaseTrace *pTrace, bool bSide, CDispCollTri **pImpactTri );
void AABBTree_TreeTrisRayBarycentricTest( const Ray_t &ray, const Vector &vecInvDelta, int iNode, RayDispOutput_t &output, CDispCollTri **pImpactTri );
int FORCEINLINE BuildRayLeafList( int iNode, rayleaflist_t &list );
struct AABBTree_TreeTrisSweepTest_Args_t
{
AABBTree_TreeTrisSweepTest_Args_t( const Ray_t &ray, const Vector &vecInvDelta, const Vector &rayDir, CBaseTrace *pTrace )
: ray( ray ), vecInvDelta( vecInvDelta ), rayDir( rayDir ), pTrace( pTrace ) {}
const Ray_t &ray;
const Vector &vecInvDelta;
const Vector &rayDir;
CBaseTrace *pTrace;
};
protected:
void SweepAABBTriIntersect( const Ray_t &ray, const Vector &rayDir, int iTri, CDispCollTri *pTri, CBaseTrace *pTrace );
void Cache_Create( CDispCollTri *pTri, int iTri ); // Testing!
bool Cache_EdgeCrossAxisX( const Vector &vecEdge, const Vector &vecOnEdge, const Vector &vecOffEdge, CDispCollTri *pTri, unsigned short &iPlane );
bool Cache_EdgeCrossAxisY( const Vector &vecEdge, const Vector &vecOnEdge, const Vector &vecOffEdge, CDispCollTri *pTri, unsigned short &iPlane );
bool Cache_EdgeCrossAxisZ( const Vector &vecEdge, const Vector &vecOnEdge, const Vector &vecOffEdge, CDispCollTri *pTri, unsigned short &iPlane );
inline bool FacePlane( const Ray_t &ray, const Vector &rayDir, CDispCollTri *pTri, CDispCollHelper *pHelper );
bool FORCEINLINE AxisPlanesXYZ( const Ray_t &ray, CDispCollTri *pTri, CDispCollHelper *pHelper );
inline bool EdgeCrossAxisX( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper );
inline bool EdgeCrossAxisY( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper );
inline bool EdgeCrossAxisZ( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper );
bool ResolveRayPlaneIntersect( float flStart, float flEnd, const Vector &vecNormal, float flDist, CDispCollHelper *pHelper );
template <int AXIS> bool FORCEINLINE TestOneAxisPlaneMin( const Ray_t &ray, CDispCollTri *pTri );
template <int AXIS> bool FORCEINLINE TestOneAxisPlaneMax( const Ray_t &ray, CDispCollTri *pTri );
template <int AXIS> bool EdgeCrossAxis( const Ray_t &ray, unsigned short iPlane, CDispCollHelper *pHelper );
// Utility
inline void CalcClosestBoxPoint( const Vector &vecPlaneNormal, const Vector &vecBoxStart, const Vector &vecBoxExtents, Vector &vecBoxPoint );
inline void CalcClosestExtents( const Vector &vecPlaneNormal, const Vector &vecBoxExtents, Vector &vecBoxPoint );
int AddPlane( const Vector &vecNormal );
bool FORCEINLINE IsLeafNode(int iNode);
public:
Vector m_mins; // Bounding box of the displacement surface and base face
int m_iCounter;
Vector m_maxs; // Bounding box of the displacement surface and base face
protected:
int m_nContents; // The displacement surface "contents" (solid, etc...)
#ifdef ENGINE_DLL
memhandle_t m_hCache;
#endif
int m_nPower; // Size of the displacement ( 2^power + 1 )
int m_nFlags;
Vector m_vecSurfPoints[4]; // Base surface points.
// Collision data.
Vector m_vecStabDir; // Direction to stab for this displacement surface (is the base face normal)
short m_nSurfaceProps[2]; // Surface properties (save off from texdata for impact responses)
protected:
CDispVector<Vector> m_aVerts; // Displacement verts.
CDispVector<CDispCollTri> m_aTris; // Displacement triangles.
CDispVector<CDispCollNode> m_nodes; // Nodes.
CDispVector<CDispCollLeaf> m_leaves; // Leaves.
// Cache
CUtlVector<CDispCollTriCache> m_aTrisCache;
CUtlVector<Vector> m_aEdgePlanes;
CDispCollHelper m_Helper;
unsigned int m_nSize;
};
FORCEINLINE bool CDispCollTree::IsLeafNode(int iNode)
{
return iNode >= m_nodes.Count() ? true : false;
}
//-----------------------------------------------------------------------------
// Purpose: get the child node index given the current node index and direction
// of the child (1 of 4)
// Input: iNode - current node index
// nDirection - direction of the child ( [0...3] - SW, SE, NW, NE )
// Output: int - the index of the child node
//-----------------------------------------------------------------------------
inline int CDispCollTree::Nodes_GetChild( int iNode, int nDirection )
{
// node range [0...m_NodeCount)
Assert( iNode >= 0 );
Assert( iNode < m_nodes.Count() );
// ( node index * 4 ) + ( direction + 1 )
return ( ( iNode << 2 ) + ( nDirection + 1 ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline int CDispCollTree::Nodes_CalcCount( int nPower )
{
Assert( nPower >= 1 );
Assert( nPower <= 4 );
return ( ( 1 << ( ( nPower + 1 ) << 1 ) ) / 3 );
}
//-----------------------------------------------------------------------------
// Purpose: get the parent node index given the current node
// Input: iNode - current node index
// Output: int - the index of the parent node
//-----------------------------------------------------------------------------
inline int CDispCollTree::Nodes_GetParent( int iNode )
{
// node range [0...m_NodeCount)
Assert( iNode >= 0 );
Assert( iNode < m_nodes.Count() );
// ( node index - 1 ) / 4
return ( ( iNode - 1 ) >> 2 );
}
//-----------------------------------------------------------------------------
// Purpose:
// TODO: should make this a function - not a hardcoded set of statements!!!
//-----------------------------------------------------------------------------
inline int CDispCollTree::Nodes_GetLevel( int iNode )
{
// node range [0...m_NodeCount)
Assert( iNode >= 0 );
Assert( iNode < m_nodes.Count() );
// level = 2^n + 1
if ( iNode == 0 ) { return 1; }
if ( iNode < 5 ) { return 2; }
if ( iNode < 21 ) { return 3; }
if ( iNode < 85 ) { return 4; }
if ( iNode < 341 ) { return 5; }
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline int CDispCollTree::Nodes_GetIndexFromComponents( int x, int y )
{
int nIndex = 0;
// Interleave bits from the x and y values to create the index
int iShift;
for( iShift = 0; x != 0; iShift += 2, x >>= 1 )
{
nIndex |= ( x & 1 ) << iShift;
}
for( iShift = 1; y != 0; iShift += 2, y >>= 1 )
{
nIndex |= ( y & 1 ) << iShift;
}
return nIndex;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline void CDispCollTree::CalcClosestBoxPoint( const Vector &vecPlaneNormal, const Vector &vecBoxStart,
const Vector &vecBoxExtents, Vector &vecBoxPoint )
{
vecBoxPoint = vecBoxStart;
( vecPlaneNormal[0] < 0.0f ) ? vecBoxPoint[0] += vecBoxExtents[0] : vecBoxPoint[0] -= vecBoxExtents[0];
( vecPlaneNormal[1] < 0.0f ) ? vecBoxPoint[1] += vecBoxExtents[1] : vecBoxPoint[1] -= vecBoxExtents[1];
( vecPlaneNormal[2] < 0.0f ) ? vecBoxPoint[2] += vecBoxExtents[2] : vecBoxPoint[2] -= vecBoxExtents[2];
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
inline void CDispCollTree::CalcClosestExtents( const Vector &vecPlaneNormal, const Vector &vecBoxExtents,
Vector &vecBoxPoint )
{
( vecPlaneNormal[0] < 0.0f ) ? vecBoxPoint[0] = vecBoxExtents[0] : vecBoxPoint[0] = -vecBoxExtents[0];
( vecPlaneNormal[1] < 0.0f ) ? vecBoxPoint[1] = vecBoxExtents[1] : vecBoxPoint[1] = -vecBoxExtents[1];
( vecPlaneNormal[2] < 0.0f ) ? vecBoxPoint[2] = vecBoxExtents[2] : vecBoxPoint[2] = -vecBoxExtents[2];
}
//=============================================================================
// Global Helper Functions
CDispCollTree *DispCollTrees_Alloc( int count );
void DispCollTrees_Free( CDispCollTree *pTrees );
#endif // DISPCOLL_COMMON_H