aboutsummaryrefslogtreecommitdiff
path: root/sp/src/public/disp_common.h
blob: 6dd5561bfed43a5dc66efdc73d07a15e9d84cfc6 (plain) (blame)
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
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#ifndef DISP_COMMON_H
#define DISP_COMMON_H
#ifdef _WIN32
#pragma once
#endif

#include "disp_vertindex.h"
#include "bspfile.h"
#include "utlvector.h"

class CPowerInfo;
class CCoreDispInfo;

// ----------------------------------------------------------------------------- //
// Classes.
// ----------------------------------------------------------------------------- //

// This class provides a set of utility functions for displacements that work in the tools and the engine.
abstract_class CDispUtilsHelper
{
// Derived classes must implement these.
public:
	virtual const CPowerInfo*		GetPowerInfo() const = 0;
	virtual CDispNeighbor*			GetEdgeNeighbor( int index ) = 0;
	virtual CDispCornerNeighbors*	GetCornerNeighbors( int index ) = 0;
	virtual CDispUtilsHelper*		GetDispUtilsByIndex( int index ) = 0;

// Helper functions.
public:

	int					GetPower() const;
	int					GetSideLength() const;
	const CVertIndex&	GetCornerPointIndex( int iCorner ) const;
	int					VertIndexToInt( const CVertIndex &i ) const;
	CVertIndex			GetEdgeMidPoint( int iEdge ) const;
};


// Use this to walk along two neighboring displacements and touch all the
// common vertices.
class CDispSubEdgeIterator
{
public:
						
						CDispSubEdgeIterator();

	// Normally, this will iterate all shared verts along the edge except the corners.
	// If you want the corners to be touched too, then pass in bTouchCorners=true.
	void				Start( CDispUtilsHelper *pDisp, int iEdge, int iSub, bool bTouchCorners = false );
	bool				Next();

	const CVertIndex&	GetVertIndex() const	{ return m_Index; }		// Get the vert index for the displacement in pUtils.
	const CVertIndex&	GetNBVertIndex() const	{ return m_NBIndex; }	// Get the neighbor's vert index.
	CDispUtilsHelper*	GetNeighbor() const		{ return m_pNeighbor; }

	// Returns true if you're on the last vert (ie: the next Next() call will return false).ssssss
	bool				IsLastVert() const;


private:
	CDispUtilsHelper	*m_pNeighbor;	// The neighbor to the edge we were setup on.

	CVertIndex			m_Index;
	CVertIndex			m_Inc;
	
	CVertIndex			m_NBIndex;
	CVertIndex			m_NBInc;

	int					m_End;
	int					m_FreeDim;
};


// Use this to walk along the edge of a displacement, touching the points in common
// between the two neighbors. Note: this won't hit the corner points of any of the displacements.
// (As a result, it won't hit the midpoint of pDisps's edge if there are 2 neighbors).
class CDispEdgeIterator
{
public:
						CDispEdgeIterator( CDispUtilsHelper *pDisp, int iEdge );

	// Seek to the next point on the edge.
	bool				Next();

	const CVertIndex&	GetVertIndex() const	{ return m_It.GetVertIndex(); }		// Get the vert index for the displacement in pUtils.
	const CVertIndex&	GetNBVertIndex() const	{ return m_It.GetNBVertIndex(); }	// Get the neighbor's vert index.

	// What is the current neighbor?
	CDispUtilsHelper*	GetCurrentNeighbor() const	{ return m_It.GetNeighbor(); }


private:
	CDispUtilsHelper		*m_pDisp;
	int						m_iEdge;
	int						m_iCurSub;

	CDispSubEdgeIterator	m_It;
};


// Use this to walk all the corners and edge verts in the displacement.
// It walks the edges in the order of the NEIGHBOREDGE_ defines.
// Iterate like this:
// CDispCircumferenceIterator iterator( pDisp->GetSideLength() );
// while ( iterator.Next() )
//     ...
class CDispCircumferenceIterator
{
public:
						CDispCircumferenceIterator( int sideLength );

	// Seek to the next point. Returns false when there are no more points.
	bool				Next();

	const CVertIndex&	GetVertIndex() const	{ return m_VertIndex; }


private:
	int					m_SideLengthM1;
	int					m_iCurEdge;
	CVertIndex			m_VertIndex;
};


// These store info about how to scale and shift coordinates between neighbors
// of different relations (in g_ShiftInfos).	
class CShiftInfo
{
public:
	int		m_MidPointScale;
	int		m_PowerShiftAdd;
	bool	m_bValid;
};

class CDispBox
{
public:
	Vector	m_Min, m_Max;
};

// ----------------------------------------------------------------------------- //
// Globals.
// ----------------------------------------------------------------------------- //


extern int			g_EdgeDims[4];		// This tells which dimension (0 or 1) is locked on an edge for each NEIGHBOREDGE_ enum.
extern CShiftInfo	g_ShiftInfos[3][3];	// See CShiftInfo.
extern int			g_EdgeSideLenMul[4];// Multiply these by the side length to get the index of the edge.


// ----------------------------------------------------------------------------- //
// Helper functions.
// ----------------------------------------------------------------------------- //

// Reference implementation to generate triangle indices for a displacement.
int		DispCommon_GetNumTriIndices( int power );
void	DispCommon_GenerateTriIndices( int power, unsigned short *indices );

// Returns a NEIGHBOREDGE_ value for the edge that the index is on.
// Returns -1 if the index is not on a side.
// If the point is on a corner, the edges are tested in the order of the NEIGHBOREDGE_ defines.
int		GetEdgeIndexFromPoint( CVertIndex const &index, int iPower );

// Returns a CORNER_ value for the corner the point is on, or -1 if it's not on a corner.
int		GetEdgeIndexFromPoint( CVertIndex const &index, int iPower );

// This returns the neighbor's power, possibly +1 or -1.
//
// It will add one if the neighbor takes up half of your edge (ie: if it took up your 
// whole edge, its resolution would be twice what it really is).
//
// It will subtract one if you take up half of its edge (ie: you only touch half of its verts).
//
// Returns -1 if the edge connection is invalid.
int		GetNeighborEdgePower( CDispUtilsHelper *pDisp, int iEdge, int iSub );

// This function sets you up so you can walk along an edge that joins two neighbors.
// Add myInc to myIndex and nbInc to nbIndex until myIndex[iFreeDim] >= myEnd.
//
// Returns the neighbor displacement, or NULL if the specified sub neighbor isn't valid.
CDispUtilsHelper*	SetupEdgeIncrements(
	CDispUtilsHelper *pDisp,
	int iEdge,
	int iSub,
	CVertIndex &myIndex,
	CVertIndex &myInc,
	CVertIndex &nbIndex,
	CVertIndex &nbInc,
	int &myEnd,
	int &iFreeDim );

// Figure out which sub neighbor nodeIndex touches.
// Returns -1 if there is no valid sub neighbor at the specified index.
int GetSubNeighborIndex( 
	CDispUtilsHelper *pDisp,
	int iEdge,
	CVertIndex const &nodeIndex
	);

// Given a vert index and the CSubNeighbor the vert lies on, this
// transforms the specified vert into the neighbor's space.
//
// Note: for corner verts, there may be multiple neighbors touching the same vert, so the
//       result you get depends on the edge you specify in iEdge (ie: if you specify the same
//       node index but a different edge, you may get a different neighbor).
//
// Note: This only returns a point if the point at nodeIndex actually touches a neighbor point.
//       An example where this might be unexpected is if pDisp is power 4 and its neighbor on iEdge
//       is power 3, and nodeIndex points at a vert in between two of its neighbor's verts.
//       In that case, even though there is a neighbor displacement, nodeIndex doesn't touch 
//       any points on it, so NULL is returned.
CDispUtilsHelper*	TransformIntoSubNeighbor( 
	CDispUtilsHelper *pDisp,
	int iEdge, 
	int iSub,
	CVertIndex const &nodeIndex, 
	CVertIndex &out 
	);

// Transform pDisp's node at nodeIndex into its neighboring connection.
// Returns the neighbor displacement and sets out to the index in the neighbor.
//
// Note: for corner verts, there may be multiple neighbors touching the same vert, so the
//       result you get depends on the edge you specify in iEdge (ie: if you specify the same
//       node index but a different edge, you may get a different neighbor).
//
// Note: This only returns a point if the point at nodeIndex actually touches a neighbor point.
//       An example where this might surprise you is if pDisp is power 4 and its neighbor on iEdge
//       is power 3, and nodeIndex points at a vert in between two of its neighbor's verts.
//       In that case, even though there is a neighbor displacement, nodeIndex doesn't touch 
//       any points on it, so NULL is returned.
CDispUtilsHelper* TransformIntoNeighbor( 
	CDispUtilsHelper *pDisp,
	int iEdge,
	CVertIndex const &nodeIndex, 
	CVertIndex &out );

// Returns true if the specified point has one or more neighbors.
bool DoesPointHaveAnyNeighbors( 
	CDispUtilsHelper *pDisp,
	const CVertIndex &index );


void FindNeighboringDispSurfs( CCoreDispInfo **ppListBase, int nListSize );
void SetupAllowedVerts( CCoreDispInfo **ppListBase, int nListSize );
void GetDispBox( CCoreDispInfo *pDisp, CDispBox &box );

// ----------------------------------------------------------------------------- //
// Inlines.
// ----------------------------------------------------------------------------- //

#include "disp_powerinfo.h"


#endif // DISP_COMMON_H