Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

433 lines
9.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "hlfaceposer.h"
  8. #include <mxtk/mx.h>
  9. #include "resource.h"
  10. #include "PhonemeProperties.h"
  11. #include "expressions.h"
  12. #include "expclass.h"
  13. #include "mdlviewer.h"
  14. static CPhonemeParams g_Params;
  15. static int g_nPhonemeCount = 0;
  16. static HWND *g_rgButtons = NULL;
  17. #define IDC_PHONEME 2000
  18. #define PHONEME_WIDTH 50
  19. #define PHONEME_HEIGHT 18
  20. #define PHONEME_GAP 10
  21. #define PHONEME_VGAP 5
  22. typedef long (__stdcall *WINPROCTYPE)( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  23. static WINPROCTYPE lpfnOldButtonProc;
  24. static BOOL CALLBACK PhonemeBtnProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  25. {
  26. switch ( uMsg )
  27. {
  28. case WM_MOUSEMOVE:
  29. {
  30. HWND dialog = GetParent( hwnd );
  31. if ( dialog )
  32. {
  33. // Get the hint text item
  34. HWND helpText = GetDlgItem( dialog, IDC_STATIC_HELPTEXT );
  35. if ( helpText )
  36. {
  37. CExpression *exp = ( CExpression * )GetWindowLong( (HWND)hwnd, GWL_USERDATA );
  38. if ( exp )
  39. {
  40. SendMessage( helpText, WM_SETTEXT, 0, (LPARAM)exp->description );
  41. }
  42. }
  43. }
  44. }
  45. return 0;
  46. default:
  47. break;
  48. }
  49. return CallWindowProc( lpfnOldButtonProc, hwnd, uMsg, wParam, lParam );
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Purpose:
  53. // Input : phoneme -
  54. // Output : static void
  55. //-----------------------------------------------------------------------------
  56. static void ClickedPhoneme( HWND hwndDlg, int phoneme )
  57. {
  58. HWND ctrl = GetDlgItem( hwndDlg, IDC_EDIT_PHONEME );
  59. if ( !ctrl )
  60. return;
  61. if ( !g_Params.m_bMultiplePhoneme )
  62. {
  63. g_Params.m_szName[ 0 ] = 0;
  64. }
  65. else
  66. {
  67. SendMessage( ctrl, WM_GETTEXT, (WPARAM)sizeof( g_Params.m_szName ), (LPARAM)g_Params.m_szName );
  68. }
  69. if ( phoneme >= g_nPhonemeCount || phoneme < 0 )
  70. {
  71. Assert( 0 );
  72. return;
  73. }
  74. HWND button = g_rgButtons[ phoneme ];
  75. CExpression *exp = ( CExpression * )GetWindowLong( (HWND)button, GWL_USERDATA );
  76. if ( exp )
  77. {
  78. if ( strlen( g_Params.m_szName ) > 0 )
  79. {
  80. strcat( g_Params.m_szName, " " );
  81. }
  82. strcat( g_Params.m_szName, exp->name );
  83. if ( g_Params.m_bMultiplePhoneme )
  84. {
  85. SetFocus( ctrl );
  86. SendMessage( ctrl, WM_SETTEXT, 0, (LPARAM)g_Params.m_szName );
  87. SendMessage( ctrl, EM_SETSEL, 0, MAKELONG(0, 0xffff) );
  88. }
  89. }
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. // Input : hwndDlg -
  94. // Output : static void
  95. //-----------------------------------------------------------------------------
  96. static void CreateAndLayoutControls( HWND hwndDlg, CPhonemeParams* params )
  97. {
  98. g_nPhonemeCount = 0;
  99. // Find phomemes
  100. // Make sure phonemes are loaded
  101. FacePoser_EnsurePhonemesLoaded();
  102. CExpClass *cl = expressions->FindClass( "phonemes", true );
  103. if ( !cl )
  104. return;
  105. g_nPhonemeCount = cl->GetNumExpressions();
  106. if ( g_nPhonemeCount == 0 )
  107. return;
  108. g_rgButtons = new HWND[ g_nPhonemeCount ];
  109. Assert( g_rgButtons );
  110. int columns = 7;
  111. int rows = ( g_nPhonemeCount / columns ) + 1;
  112. int dialogW = columns * ( PHONEME_WIDTH + PHONEME_GAP ) + 2 * PHONEME_GAP;
  113. int dialogH = rows * ( PHONEME_HEIGHT + PHONEME_VGAP ) + 40 + 55 + 30;
  114. int startx = PHONEME_GAP;
  115. int starty = 40;
  116. if ( params->m_bPositionDialog )
  117. {
  118. int top = params->m_nTop - dialogH - 5;
  119. int left = params->m_nLeft;
  120. MoveWindow( hwndDlg,
  121. left,
  122. top,
  123. dialogW,
  124. dialogH,
  125. TRUE );
  126. }
  127. else
  128. {
  129. MoveWindow( hwndDlg,
  130. ( GetSystemMetrics( SM_CXFULLSCREEN ) - dialogW ) / 2,
  131. ( GetSystemMetrics( SM_CYFULLSCREEN ) - dialogH ) / 2,
  132. dialogW,
  133. dialogH,
  134. TRUE );
  135. }
  136. HWND ctrl = GetDlgItem( hwndDlg, IDOK );
  137. if ( ctrl )
  138. {
  139. MoveWindow( ctrl, dialogW - 220, dialogH - 58, 100, 20, TRUE );
  140. }
  141. ctrl = GetDlgItem( hwndDlg, IDCANCEL );
  142. if ( ctrl )
  143. {
  144. MoveWindow( ctrl, dialogW - 110, dialogH - 58, 100, 20, TRUE );
  145. }
  146. ctrl = GetDlgItem( hwndDlg, IDC_PHONEMETEXTPROMPT );
  147. if ( ctrl )
  148. {
  149. MoveWindow( ctrl, startx, dialogH - 55, 50, 20, TRUE );
  150. }
  151. ctrl = GetDlgItem( hwndDlg, IDC_EDIT_PHONEME );
  152. if ( ctrl )
  153. {
  154. MoveWindow( ctrl, startx + 50, dialogH - 58, 100, 20, TRUE );
  155. }
  156. ctrl = GetDlgItem( hwndDlg, IDC_STATIC_HELPTEXT );
  157. if ( ctrl )
  158. {
  159. MoveWindow( ctrl, startx, dialogH - 85, dialogW - startx - 20, 20, TRUE );
  160. }
  161. int r = 0;
  162. int c = 0;
  163. for ( int i = 0; i < g_nPhonemeCount; i++ )
  164. {
  165. CExpression *exp = cl->GetExpression( i );
  166. if ( !exp )
  167. continue;
  168. HWND button = CreateWindowEx(
  169. 0,
  170. "BUTTON",
  171. va( "%s", exp->name ),
  172. WS_CHILD | WS_VISIBLE | BS_LEFT,
  173. startx + c * ( PHONEME_WIDTH + PHONEME_GAP ),
  174. starty + r * ( PHONEME_HEIGHT + PHONEME_VGAP ),
  175. PHONEME_WIDTH,
  176. PHONEME_HEIGHT,
  177. hwndDlg,
  178. (HMENU)( IDC_PHONEME + i ),
  179. (HINSTANCE)GetModuleHandle( 0 ),
  180. NULL );
  181. Assert( button );
  182. SetWindowLong( (HWND)button, GWL_USERDATA, (LONG)exp );
  183. // Subclass it
  184. lpfnOldButtonProc = (WINPROCTYPE)SetWindowLong( (HWND)button, GWL_WNDPROC, (LONG)PhonemeBtnProc );
  185. SendMessage ((HWND)button, WM_SETFONT, (WPARAM) (HFONT) GetStockObject (ANSI_VAR_FONT), MAKELPARAM (TRUE, 0));
  186. g_rgButtons[ i ] = button;
  187. c++;
  188. if ( c >= columns )
  189. {
  190. r++;
  191. c = 0;
  192. }
  193. }
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose:
  197. // Input : hwndDlg -
  198. // Output : static void
  199. //-----------------------------------------------------------------------------
  200. static void DestroyControls( HWND hwndDlg )
  201. {
  202. for ( int i = 0 ; i < g_nPhonemeCount; i++ )
  203. {
  204. if ( g_rgButtons[ i ] )
  205. {
  206. DestroyWindow( g_rgButtons[ i ] );
  207. g_rgButtons[ i ] = NULL;
  208. }
  209. }
  210. delete[] g_rgButtons;
  211. g_nPhonemeCount = 0;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. // Input : hwndDlg -
  216. // Output : static void
  217. //-----------------------------------------------------------------------------
  218. static void PhonemePropertiesDialogExit( HWND hwndDlg, int exitCode )
  219. {
  220. DestroyControls( hwndDlg );
  221. EndDialog( hwndDlg, exitCode );
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. // Input : allowmultiple -
  226. // *input -
  227. // *output -
  228. // Output : static bool
  229. //-----------------------------------------------------------------------------
  230. static bool ValidatePhonemeString( bool allowmultiple, char const *input, char *output )
  231. {
  232. // Make sure phonemes are loaded
  233. FacePoser_EnsurePhonemesLoaded();
  234. CExpClass *cl = expressions->FindClass( "phonemes", true );
  235. if ( !cl )
  236. return false;
  237. if ( !input || !input[ 0 ] )
  238. return false;
  239. // Go one by one
  240. int count = 1;
  241. char phoneme[ 128 ];
  242. char *in, *out;
  243. *output = 0;
  244. in = (char *)input;
  245. do
  246. {
  247. out = phoneme;
  248. while ( *in > 32 )
  249. {
  250. *out++ = *in++;
  251. }
  252. *out = 0;
  253. // Validate phoneme entered
  254. for ( int i = 0; i < g_nPhonemeCount; i++ )
  255. {
  256. CExpression *exp = cl->GetExpression( i );
  257. if ( !exp )
  258. continue;
  259. if ( !stricmp( exp->name, phoneme ) )
  260. {
  261. // Found it
  262. if ( count != 1 )
  263. {
  264. strcat( output, " " );
  265. }
  266. strcat( output, phoneme );
  267. break;
  268. }
  269. }
  270. if ( !*in )
  271. break;
  272. // Skip whitespace
  273. in++;
  274. count++;
  275. // Only keep first one
  276. if ( !allowmultiple )
  277. break;
  278. } while ( 1 );
  279. return true;
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose:
  283. // Input : hwndDlg -
  284. // uMsg -
  285. // wParam -
  286. // lParam -
  287. // Output : static BOOL CALLBACK
  288. //-----------------------------------------------------------------------------
  289. static BOOL CALLBACK PhonemePropertiesDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  290. {
  291. switch(uMsg)
  292. {
  293. case WM_INITDIALOG:
  294. // Insert code here to put the string (to find and replace with)
  295. // into the edit controls.
  296. // ...
  297. {
  298. g_Params.PositionSelf( hwndDlg );
  299. SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
  300. CreateAndLayoutControls( hwndDlg, &g_Params );
  301. HWND control = GetDlgItem( hwndDlg, IDC_PHONEMENAME );
  302. if ( control )
  303. {
  304. SendMessage( control, WM_SETTEXT , 0,
  305. ( LPARAM )(
  306. g_Params.m_bMultiplePhoneme ?
  307. "Click or enter one or more phonemes from list below"
  308. :
  309. va( "Phoneme/Viseme: %s", g_Params.m_szName ) ) );
  310. }
  311. control = GetDlgItem( hwndDlg, IDC_EDIT_PHONEME );
  312. if ( control )
  313. {
  314. SetFocus( control );
  315. SendMessage( control, WM_SETTEXT , 0, ( LPARAM )g_Params.m_szName );
  316. SendMessage( control, EM_SETSEL, 0, MAKELONG(0, 0xffff) );
  317. return FALSE;
  318. }
  319. }
  320. return TRUE;
  321. case WM_COMMAND:
  322. {
  323. int cmd = LOWORD( wParam );
  324. if ( ( cmd >= IDC_PHONEME ) &&
  325. ( cmd < ( IDC_PHONEME + g_nPhonemeCount ) ) )
  326. {
  327. ClickedPhoneme( hwndDlg, cmd - IDC_PHONEME );
  328. if ( !g_Params.m_bMultiplePhoneme )
  329. {
  330. PhonemePropertiesDialogExit( hwndDlg, 1 );
  331. }
  332. }
  333. else if ( cmd != IDC_EDIT_PHONEME )
  334. {
  335. switch ( cmd )
  336. {
  337. case IDOK:
  338. {
  339. // Retrieve text
  340. char szPhoneme[ 256 ];
  341. HWND ctrl = GetDlgItem( hwndDlg, IDC_EDIT_PHONEME );
  342. if ( ctrl )
  343. {
  344. SendMessage( ctrl, WM_GETTEXT, (WPARAM)sizeof( szPhoneme ), (LPARAM)szPhoneme );
  345. ValidatePhonemeString( g_Params.m_bMultiplePhoneme, szPhoneme, g_Params.m_szName );
  346. }
  347. PhonemePropertiesDialogExit( hwndDlg, 1 );
  348. }
  349. break;
  350. case IDCANCEL:
  351. PhonemePropertiesDialogExit( hwndDlg, 0 );
  352. break;
  353. }
  354. }
  355. }
  356. return TRUE;
  357. }
  358. return FALSE;
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Purpose:
  362. // Input : *view -
  363. // *actor -
  364. // Output : int
  365. //-----------------------------------------------------------------------------
  366. int PhonemeProperties( CPhonemeParams *params )
  367. {
  368. g_Params = *params;
  369. int retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
  370. MAKEINTRESOURCE( IDD_PHONEMEPROPERTIES ),
  371. (HWND)g_MDLViewer->getHandle(),
  372. (DLGPROC)PhonemePropertiesDialogProc );
  373. *params = g_Params;
  374. return retval;
  375. }