aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_baseflex.h
blob: 71cee3d81e7f4c26f0b5383dce67198371fb6483 (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
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
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//===========================================================================//
// Client-side CBasePlayer

#ifndef C_STUDIOFLEX_H
#define C_STUDIOFLEX_H
#pragma once


#include "c_baseanimating.h"
#include "c_baseanimatingoverlay.h"
#include "sceneentity_shared.h"

#include "utlvector.h"

//-----------------------------------------------------------------------------
// Purpose: Item in list of loaded scene files
//-----------------------------------------------------------------------------
class CFlexSceneFile
{
public:
	enum
	{
		MAX_FLEX_FILENAME = 128,
	};

	char			filename[ MAX_FLEX_FILENAME ];
	void			*buffer;
};

// For phoneme emphasis track
struct Emphasized_Phoneme;
class CSentence;

enum
{
	PHONEME_CLASS_WEAK = 0,
	PHONEME_CLASS_NORMAL,
	PHONEME_CLASS_STRONG,

	NUM_PHONEME_CLASSES
};

// Mapping for each loaded scene file used by this actor
struct FS_LocalToGlobal_t
{
	explicit FS_LocalToGlobal_t() :
	m_Key( 0 ),
		m_nCount( 0 ),
		m_Mapping( 0 )
	{
	}

	explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) :
	m_Key( key ),
		m_nCount( 0 ),
		m_Mapping( 0 )
	{
	}		

	void SetCount( int count )
	{
		Assert( !m_Mapping );
		Assert( count > 0 );
		m_nCount = count;
		m_Mapping = new int[ m_nCount ];
		Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) );
	}

	FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src )
	{
		m_Key = src.m_Key;
		delete m_Mapping;
		m_Mapping = new int[ src.m_nCount ];
		Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) );

		m_nCount = src.m_nCount;
	}

	~FS_LocalToGlobal_t()
	{
		delete m_Mapping;
		m_nCount = 0;
		m_Mapping = 0;
	}

	const flexsettinghdr_t	*m_Key;
	int						m_nCount;
	int						*m_Mapping;	
};

bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs );

class IHasLocalToGlobalFlexSettings
{
public:
	virtual void		EnsureTranslations( const flexsettinghdr_t *pSettinghdr ) = 0;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
struct Emphasized_Phoneme
{
	// Global fields, setup at start
	char			classname[ 64 ];
	bool			required;
	// Global fields setup first time tracks played
	bool			basechecked;
	const flexsettinghdr_t *base;
	const flexsetting_t *exp;

	// Local fields, processed for each sentence
	bool			valid;
	float			amount;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings
{
	DECLARE_CLASS( C_BaseFlex, C_BaseAnimatingOverlay );
public:
	DECLARE_CLIENTCLASS();
	DECLARE_PREDICTABLE();
	DECLARE_INTERPOLATION();

					C_BaseFlex();
	virtual			~C_BaseFlex();

	virtual void Spawn();

	virtual void InitPhonemeMappings();

	void		SetupMappings( char const *pchFileRoot );

	virtual CStudioHdr *OnNewModel( void );

	virtual void	StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );

	virtual void OnThreadedDrawSetup();

	// model specific
	virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed );
	static void		LinkToGlobalFlexControllers( CStudioHdr *hdr );
	virtual	void	SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
	virtual	bool	SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
	static void		RunFlexDelay( int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights, float &flFlexDelayTime );
	virtual	void	SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
	virtual bool	UsesFlexDelayedWeights();

	static	void	RunFlexRules( CStudioHdr *pStudioHdr, float *dest );

	virtual Vector	SetViewTarget( CStudioHdr *pStudioHdr );

	virtual bool	GetSoundSpatialization( SpatializationInfo_t& info );

	virtual void	GetToolRecordingState( KeyValues *msg );

	// Called at the lowest level to actually apply a flex animation
	void				AddFlexAnimation( CSceneEventInfo *info );

	void			SetFlexWeight( LocalFlexController_t index, float value );
	float			GetFlexWeight( LocalFlexController_t index );

	// Look up flex controller index by global name
	LocalFlexController_t				FindFlexController( const char *szName );

public:
	Vector			m_viewtarget;
	CInterpolatedVar< Vector >	m_iv_viewtarget;
	// indexed by model local flexcontroller
	float			m_flexWeight[MAXSTUDIOFLEXCTRL];
	CInterpolatedVarArray< float, MAXSTUDIOFLEXCTRL >	m_iv_flexWeight;

	int				m_blinktoggle;

	static int		AddGlobalFlexController( const char *szName );
	static char const *GetGlobalFlexControllerName( int idx );

	// bah, this should be unified with all prev/current stuff.

public:

	// Keep track of what scenes are being played
	void				StartChoreoScene( CChoreoScene *scene );
	void				RemoveChoreoScene( CChoreoScene *scene );

	// Start the specifics of an scene event
	virtual bool		StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, C_BaseEntity *pTarget );

	// Manipulation of events for the object
	// Should be called by think function to process all scene events
	// The default implementation resets m_flexWeight array and calls
	//  AddSceneEvents
	virtual void		ProcessSceneEvents( bool bFlexEvents );

	// Assumes m_flexWeight array has been set up, this adds the actual currently playing
	//  expressions to the flex weights and adds other scene events as needed
	virtual	bool		ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );

	virtual bool		ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );

	// Remove all playing events
	void				ClearSceneEvents( CChoreoScene *scene, bool canceled );

	// Stop specifics of event
	virtual	bool		ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled );

	// Add the event to the queue for this actor
	void				AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false );

	// Remove the event from the queue for this actor
	void				RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill );

	// Checks to see if the event should be considered "completed"
	bool				CheckSceneEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event );

	// Checks to see if a event should be considered "completed"
	virtual bool		CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event );

	int					FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key );

	// IHasLocalToGlobalFlexSettings
	virtual void		EnsureTranslations( const flexsettinghdr_t *pSettinghdr );

	// For handling scene files
	void				*FindSceneFile( const char *filename );

private:

	bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );

	bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
	bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event );
	void AddFlexSetting( const char *expr, float scale, 
		const flexsettinghdr_t *pSettinghdr, bool newexpression );

	// Array of active SceneEvents, in order oldest to newest
	CUtlVector < CSceneEventInfo >		m_SceneEvents;
	CUtlVector < CChoreoScene * >		m_ActiveChoreoScenes;

	bool				HasSceneEvents() const;

private:
	CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal;

	float			m_blinktime;
	int				m_prevblinktoggle;

	int				m_iBlink;
	LocalFlexController_t				m_iEyeUpdown;
	LocalFlexController_t				m_iEyeRightleft;
	bool			m_bSearchedForEyeFlexes;
	int				m_iMouthAttachment;

	float			m_flFlexDelayTime;
	float			*m_flFlexDelayedWeight;
	int				m_cFlexDelayedWeight;

	// shared flex controllers
	static int		g_numflexcontrollers;
	static char		*g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; // room for global set of flexcontrollers
	static float	g_flexweight[MAXSTUDIOFLEXDESC];

protected:

	Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ];

private:

	C_BaseFlex( const C_BaseFlex & ); // not defined, not accessible

	const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr );

	void			ProcessVisemes( Emphasized_Phoneme *classes );
	void			AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted );
	void			AddViseme( Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression );
	bool			SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme );
	void			ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity );

#ifdef HL2_CLIENT_DLL
public:

	Vector			m_vecLean;
	CInterpolatedVar< Vector >	m_iv_vecLean;
	Vector			m_vecShift;
	CInterpolatedVar< Vector >	m_iv_vecShift;
#endif
};


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CFlexSceneFileManager : CAutoGameSystem
{
public:

	CFlexSceneFileManager() : CAutoGameSystem( "CFlexSceneFileManager" )
	{
	}

	virtual bool Init();
	virtual void Shutdown();

	void EnsureTranslations( IHasLocalToGlobalFlexSettings *instance, const flexsettinghdr_t *pSettinghdr );
	void *FindSceneFile( IHasLocalToGlobalFlexSettings *instance, const char *filename, bool allowBlockingIO );

private:
	void DeleteSceneFiles();

	CUtlVector< CFlexSceneFile * > m_FileList;
};


//-----------------------------------------------------------------------------
// Do we have active expressions?
//-----------------------------------------------------------------------------
inline bool C_BaseFlex::HasSceneEvents() const
{
	return m_SceneEvents.Count() != 0;
}


EXTERN_RECV_TABLE(DT_BaseFlex);

float *GetVisemeWeights( int phoneme );


#endif // C_STUDIOFLEX_H