Counter Strike : Global Offensive Source Code
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.

4239 lines
128 KiB

  1. //======== Copyright � 1996-2009, Valve, L.L.C., All rights reserved. ========
  2. //
  3. // The copyright to the contents herein is the property of Valve, L.L.C.
  4. // The contents may be used and/or copied only with the written permission of
  5. // Valve, L.L.C., or in accordance with the terms and conditions stipulated in
  6. // the agreement/contract under which the contents have been supplied.
  7. //
  8. // $Header: $
  9. // $NoKeywords: $
  10. //
  11. // Purpose:
  12. //
  13. //=============================================================================
  14. // Valve includes
  15. #include "datamodel/dmelement.h"
  16. #include "datamodel/idatamodel.h"
  17. #include "dmxeditlib/dmxedit.h"
  18. #include "mdlobjects/dmeeyeball.h"
  19. #include "mdlobjects/dmeeyelid.h"
  20. #include "mdlobjects/dmemouth.h"
  21. #include "movieobjects/dmobjserializer.h"
  22. #include "movieobjects/dmemakefile.h"
  23. #include "movieobjects/dmemodel.h"
  24. #include "movieobjects/dmeflexrules.h"
  25. #include "tier1/utlstack.h"
  26. #include "dmeutils/dmmeshutils.h"
  27. #include "meshutils/mesh.h"
  28. #include <time.h>
  29. #ifndef __func__
  30. # ifdef __FUNCTION__
  31. # define __func__ __FUNCTION__
  32. # else
  33. # define __func__ DmxEdit
  34. # endif
  35. #endif
  36. //-----------------------------------------------------------------------------
  37. //
  38. //-----------------------------------------------------------------------------
  39. class CDmxEdit : public CBaseAppSystem< IDmxEdit >
  40. {
  41. typedef CBaseAppSystem< IDmxEdit > BaseClass;
  42. public:
  43. CDmxEdit()
  44. : m_nDistanceType( CDmeMesh::DIST_ABSOLUTE )
  45. , m_pDmeMakefile( NULL )
  46. {
  47. }
  48. CDmeMakefile *GetMakefile()
  49. {
  50. if ( !m_pDmeMakefile )
  51. {
  52. m_pDmeMakefile = CreateElement< CDmeMakefile >( "python dmxedit", DMFILEID_INVALID );
  53. }
  54. if ( !m_pDmeMakefile )
  55. return NULL;
  56. return m_pDmeMakefile;
  57. }
  58. CDmeSource *AddSource( const char *pszSource, bool bDmx )
  59. {
  60. CDmeMakefile *pDmeMakefile = GetMakefile();
  61. if ( !pDmeMakefile )
  62. return NULL;
  63. CDmeSource *pDmeSource = pDmeMakefile->AddSource< CDmeSource >( pszSource );
  64. if ( pDmeSource )
  65. {
  66. if ( bDmx )
  67. {
  68. pDmeSource->SetValue( "LoadDmx", true );
  69. }
  70. else
  71. {
  72. pDmeSource->SetValue( "LoadObj", true );
  73. }
  74. }
  75. return pDmeSource;
  76. }
  77. virtual DmxEditErrorState_t GetErrorState() const
  78. {
  79. return m_nErrorState;
  80. }
  81. virtual void ResetErrorState()
  82. {
  83. m_nErrorState = DMXEDIT_OK;
  84. m_sErrorString.Set( "" );
  85. }
  86. virtual const char *GetErrorString() const
  87. {
  88. return m_nErrorState == DMXEDIT_OK ? NULL : m_sErrorString.Get();
  89. }
  90. int SetErrorString( DmxEditErrorState_t nErrorState, const char *pszErrorString, ... )
  91. {
  92. va_list marker;
  93. va_start( marker, pszErrorString );
  94. const int nRetVal = IntSetErrorString( nErrorState, pszErrorString, marker );
  95. va_end( marker );
  96. return nRetVal;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // This is a bit of a hack but CDmxEdit is already a friend of CDmeMesh...
  100. //-----------------------------------------------------------------------------
  101. static bool RemoveBaseState( CDmeMesh *pDmeMesh, CDmeVertexData *pDmeVertexData )
  102. {
  103. return pDmeMesh->RemoveBaseState( pDmeVertexData );
  104. }
  105. //-----------------------------------------------------------------------------
  106. // This is a bit of a hack but CDmxEdit is already a friend of CDmeMesh...
  107. //-----------------------------------------------------------------------------
  108. static CDmeVertexData *FindOrAddBaseState( CDmeMesh *pDmeMesh, CDmeVertexData *pDmeVertexData )
  109. {
  110. return pDmeMesh->FindOrAddBaseState( pDmeVertexData );
  111. }
  112. void SetDistanceType( CDmeMesh::Distance_t nDistanceType )
  113. {
  114. m_nDistanceType = nDistanceType;
  115. }
  116. CDmeMesh::Distance_t GetDistanceType() const
  117. {
  118. return m_nDistanceType;
  119. }
  120. protected:
  121. DmxEditErrorState_t m_nErrorState;
  122. CUtlString m_sErrorString;
  123. int IntSetErrorString( DmxEditErrorState_t nErrorState, const char *pszErrorString, va_list vaList )
  124. {
  125. m_nErrorState = nErrorState;
  126. char tmpBuf[ BUFSIZ ] = "dmxedit.";
  127. enum {
  128. kOffset = 8
  129. };
  130. #ifdef _WIN32
  131. int len = _vsnprintf( tmpBuf + kOffset, sizeof( tmpBuf ) - 1 - kOffset, pszErrorString, vaList );
  132. #elif POSIX
  133. int len = vsnprintf( tmpBuf + kOffset, sizeof( tmpBuf ) - 1 - kOffset, pszErrorString, vaList );
  134. #else
  135. #error "define vsnprintf type."
  136. #endif
  137. // Len < 0 represents an overflow
  138. if( len < 0 )
  139. {
  140. len = sizeof( tmpBuf ) - 1;
  141. tmpBuf[sizeof( tmpBuf ) - 1] = 0;
  142. }
  143. m_sErrorString.Set( tmpBuf );
  144. return len;
  145. }
  146. CDmeMesh::Distance_t m_nDistanceType;
  147. CDmeMakefile *m_pDmeMakefile;
  148. };
  149. //-----------------------------------------------------------------------------
  150. //
  151. //-----------------------------------------------------------------------------
  152. static CDmxEdit g_DmxEdit;
  153. CDmxEdit *g_pDmxEditImpl = &g_DmxEdit;
  154. IDmxEdit *g_pDmxEdit = &g_DmxEdit;
  155. //-----------------------------------------------------------------------------
  156. // Macros for error
  157. //-----------------------------------------------------------------------------
  158. #define DMXEDIT_ERROR( ... ) \
  159. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ );
  160. #define DMXEDIT_ERROR_RETURN_NULL( ... ) \
  161. { \
  162. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ ); \
  163. return NULL; \
  164. }
  165. #define DMXEDIT_ERROR_RETURN_FALSE( ... ) \
  166. { \
  167. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ ); \
  168. return NULL; \
  169. }
  170. #define DMXEDIT_ERROR_RETURN_EMPTY_STRING( ... ) \
  171. { \
  172. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": " __VA_ARGS__ ); \
  173. return ""; \
  174. }
  175. #define DMXEDIT_WARNING( ... ) \
  176. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ );
  177. #define DMXEDIT_WARNING_RETURN_NULL( ... ) \
  178. { \
  179. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ ); \
  180. return NULL; \
  181. }
  182. #define DMXEDIT_WARNING_RETURN_FALSE( ... ) \
  183. { \
  184. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ ); \
  185. return NULL; \
  186. }
  187. #define DMXEDIT_WARNING_RETURN_EMPTY_STRING( ... ) \
  188. { \
  189. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": " __VA_ARGS__ ); \
  190. return ""; \
  191. }
  192. #define DMXEDIT_MESH_ERROR_RETURN_NULL( pDmeMesh ) \
  193. { \
  194. if ( !pDmeMesh ) \
  195. { \
  196. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": No mesh specified" __VA_ARGS__ ); \
  197. return NULL; \
  198. } \
  199. }
  200. #define DMXEDIT_MESH_ERROR_RETURN_FALSE( pDmeMesh ) \
  201. { \
  202. if ( !pDmeMesh ) \
  203. { \
  204. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": No mesh specified" __VA_ARGS__ ); \
  205. return false; \
  206. } \
  207. }
  208. #define DMXEDIT_MESH_ERROR_RETURN_EMPTY_STRING( pDmeMesh ) \
  209. { \
  210. if ( !pDmeMesh ) \
  211. { \
  212. g_pDmxEditImpl->SetErrorString( DMXEDIT_ERROR, __func__ ": No mesh specified" __VA_ARGS__ ); \
  213. return ""; \
  214. } \
  215. }
  216. #define DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh ) \
  217. { \
  218. if ( !pDmeMesh ) \
  219. { \
  220. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": No mesh specified" __VA_ARGS__ ); \
  221. return NULL; \
  222. } \
  223. }
  224. #define DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh ) \
  225. { \
  226. if ( !pDmeMesh ) \
  227. { \
  228. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": No mesh specified" __VA_ARGS__ ); \
  229. return false; \
  230. } \
  231. }
  232. #define DMXEDIT_MESH_WARNING_RETURN_EMPTY_STRING( pDmeMesh ) \
  233. { \
  234. if ( !pDmeMesh ) \
  235. { \
  236. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, __func__ ": No mesh specified" __VA_ARGS__ ); \
  237. return false; \
  238. } \
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Checks whether the specified mesh & base state are valid and the base
  242. // state actually belongs to the mesh
  243. //-----------------------------------------------------------------------------
  244. bool BaseStateSanityCheck( CDmeMesh *pDmeMesh, CDmeVertexData *pDmeBaseState, const char *pszFuncName )
  245. {
  246. if ( !pDmeMesh )
  247. {
  248. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No mesh specified", pszFuncName );
  249. return false;
  250. }
  251. if ( !pDmeBaseState )
  252. {
  253. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No base state specified", pszFuncName );
  254. return false;
  255. }
  256. CDmeVertexData *pDmeBaseStateCheck = pDmeMesh->FindBaseState( pDmeBaseState->GetName() );
  257. if ( !pDmeBaseStateCheck || pDmeBaseState != pDmeBaseStateCheck )
  258. {
  259. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Base state \"%s\" doesn't belong to mesh \"%s\"", pszFuncName, pDmeBaseState->GetName(), pDmeMesh->GetName() );
  260. return false;
  261. }
  262. return true;
  263. }
  264. //-----------------------------------------------------------------------------
  265. //
  266. //-----------------------------------------------------------------------------
  267. static const char s_szEditBaseStateName[] = "__dmxedit_edit";
  268. static const char s_szEditOldCurrentState[] = "__dmxedit_oldCurrentState";
  269. //-----------------------------------------------------------------------------
  270. //
  271. //-----------------------------------------------------------------------------
  272. bool CleanupMeshEditBaseState( CDmeMesh *pDmeMesh )
  273. {
  274. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  275. CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState();
  276. if ( !BaseStateSanityCheck( pDmeMesh, pDmeBindBaseState, __func__ ) )
  277. return false;
  278. if ( !Q_strcmp( pDmeBindBaseState->GetName(), s_szEditOldCurrentState ) )
  279. return false;
  280. // Remove edit base state and restore current base state
  281. if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) )
  282. {
  283. CDmeVertexData *pDmeOldCurrentBaseState = pDmeMesh->GetValueElement< CDmeVertexData >( s_szEditOldCurrentState );
  284. if ( pDmeOldCurrentBaseState )
  285. {
  286. pDmeMesh->SetCurrentBaseState( pDmeOldCurrentBaseState->GetName() );
  287. }
  288. pDmeMesh->RemoveAttribute( s_szEditOldCurrentState );
  289. }
  290. else
  291. {
  292. pDmeMesh->SetCurrentBaseState( pDmeBindBaseState->GetName() );
  293. }
  294. pDmeMesh->DeleteBaseState( s_szEditBaseStateName );
  295. return true;
  296. }
  297. //-----------------------------------------------------------------------------
  298. //
  299. //-----------------------------------------------------------------------------
  300. CDmeVertexData *FindMeshEditBaseState( CDmeMesh *pDmeMesh, const char *pszFuncName )
  301. {
  302. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  303. CDmeVertexData *pDmeEditBaseState = pDmeMesh->FindBaseState( s_szEditBaseStateName );
  304. if ( pDmeEditBaseState && BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, pszFuncName ) )
  305. return pDmeEditBaseState;
  306. return NULL;
  307. }
  308. //-----------------------------------------------------------------------------
  309. //
  310. //-----------------------------------------------------------------------------
  311. CDmeVertexData *FindOrCreateMeshEditBaseState( CDmeMesh *pDmeMesh, const char *pszFuncName )
  312. {
  313. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  314. CDmeVertexData *pDmeEditBaseState = pDmeMesh->FindBaseState( s_szEditBaseStateName );
  315. if ( pDmeEditBaseState )
  316. {
  317. if ( BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, pszFuncName ) )
  318. return pDmeEditBaseState;
  319. return NULL;
  320. }
  321. CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState();
  322. if ( !pDmeBindBaseState )
  323. {
  324. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No bind base state found on mesh \"%s\"", pszFuncName, pDmeMesh->GetName() );
  325. return NULL;
  326. }
  327. pDmeEditBaseState = pDmeMesh->FindOrCreateBaseState( s_szEditBaseStateName );
  328. if ( !pDmeEditBaseState )
  329. {
  330. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Couldn't create edit base state on mesh \"%s\"", pszFuncName, pDmeMesh->GetName() );
  331. return NULL;
  332. }
  333. pDmeBindBaseState->CopyTo( pDmeEditBaseState );
  334. pDmeEditBaseState->SetFileId( DMFILEID_INVALID, TD_ALL );
  335. // Save the current base state so we can restore it on save
  336. CDmAttribute *pDmeOldCurrentStateAttr = NULL;
  337. if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) )
  338. {
  339. pDmeOldCurrentStateAttr = pDmeMesh->GetAttribute( s_szEditOldCurrentState );
  340. if ( !pDmeOldCurrentStateAttr )
  341. {
  342. Msg( "WARNING %s: Attribute %s.%s is of type %s, not AT_ELEMENT, removing", pszFuncName, pDmeMesh->GetName(), pDmeOldCurrentStateAttr->GetName(), pDmeOldCurrentStateAttr->GetTypeString() );
  343. pDmeMesh->RemoveAttribute( s_szEditOldCurrentState );
  344. pDmeOldCurrentStateAttr = NULL;
  345. }
  346. }
  347. if ( pDmeOldCurrentStateAttr == NULL )
  348. {
  349. pDmeOldCurrentStateAttr = pDmeMesh->AddAttributeElement< CDmeVertexData >( s_szEditOldCurrentState );
  350. if ( !pDmeOldCurrentStateAttr )
  351. {
  352. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Couldn't create %s.%s attribute", pszFuncName, pDmeMesh->GetName(), s_szEditOldCurrentState );
  353. return NULL;
  354. }
  355. pDmeOldCurrentStateAttr->AddFlag( FATTRIB_DONTSAVE );
  356. }
  357. pDmeOldCurrentStateAttr->SetValue< CDmeVertexData >( pDmeMesh->GetCurrentBaseState() );
  358. pDmeMesh->SetCurrentBaseState( pDmeEditBaseState->GetName() );
  359. CDmeVertexData *pDmeBaseState = pDmeMesh->GetCurrentBaseState();
  360. if ( BaseStateSanityCheck( pDmeMesh, pDmeBaseState, pszFuncName ) )
  361. return pDmeBaseState;
  362. return NULL;
  363. }
  364. //-----------------------------------------------------------------------------
  365. //
  366. //-----------------------------------------------------------------------------
  367. CDmElement *LoadDmx( const char *pszFilename )
  368. {
  369. CDmElement *pRoot = NULL;
  370. if ( !Q_stricmp( "dmx", Q_GetFileExtension( pszFilename ) ) )
  371. {
  372. g_pDmxEditImpl->AddSource( pszFilename, true );
  373. g_pDataModel->RestoreFromFile( pszFilename, NULL, NULL, &pRoot, CR_COPY_NEW );
  374. if ( !pRoot )
  375. DMXEDIT_ERROR_RETURN_NULL( "DMX Load Fail: \"%s\"", pszFilename );
  376. }
  377. else
  378. DMXEDIT_ERROR_RETURN_NULL( "File without .dmx extension passed to LoadDmx: \"%s\"", pszFilename );
  379. return pRoot;
  380. }
  381. //-----------------------------------------------------------------------------
  382. //
  383. //-----------------------------------------------------------------------------
  384. CDmElement *LoadObj( const char *pszFilename, const char *pszLoadType /* = "ABSOLUTE" */ )
  385. {
  386. CDmElement *pRoot = NULL;
  387. if ( !Q_stricmp( "obj", Q_GetFileExtension( pszFilename ) ) )
  388. {
  389. g_pDmxEditImpl->AddSource( pszFilename, false );
  390. // Load OBJs
  391. bool bAbsoluteObjs = true;
  392. if ( pszLoadType )
  393. {
  394. if ( !Q_stricmp( "absolute", pszLoadType ) )
  395. {
  396. bAbsoluteObjs = true;
  397. }
  398. else if ( !Q_stricmp( "relative", pszLoadType ) )
  399. {
  400. bAbsoluteObjs = false;
  401. }
  402. else
  403. DMXEDIT_ERROR_RETURN_NULL( "Invalid OBJ loadType specified (%s), must be \"ABSOLUTE\" or \"RELATIVE\"", pszLoadType );
  404. }
  405. pRoot = CDmObjSerializer().ReadOBJ( pszFilename, NULL, true, bAbsoluteObjs );
  406. if ( !pRoot )
  407. DMXEDIT_ERROR_RETURN_NULL( "OBJ Load Fail: \"%s\"", pszFilename );
  408. }
  409. else
  410. DMXEDIT_ERROR_RETURN_NULL( "File without .obj extension passed to LoadObj: \"%s\"", pszFilename );
  411. return pRoot;
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Not really pushing and popping as it's not implemented as a stack
  415. // only one level or push allowed. Could be a DM_ELEMENT_ARRAY if needed
  416. // to support arbitrary nesting if required but currently only called
  417. // by Save
  418. //-----------------------------------------------------------------------------
  419. void PushPopEditState( CDmeMesh *pDmeMesh, bool bPush )
  420. {
  421. if ( !pDmeMesh )
  422. return;
  423. const char szPushEdit[] = "__dmxedit_pushEditBase";
  424. const char szPushCurr[] = "__dmxedit_pushCurrBase";
  425. if ( bPush )
  426. {
  427. CDmeVertexData *pDmeEditBaseState = FindMeshEditBaseState( pDmeMesh, __func__ );
  428. if ( !pDmeEditBaseState || pDmeMesh->BaseStateCount() <= 1 )
  429. return;
  430. pDmeMesh->SetValue( szPushEdit, pDmeEditBaseState );
  431. pDmeMesh->GetAttribute( szPushEdit )->AddFlag( FATTRIB_DONTSAVE );
  432. CDmeVertexData *pDmeCurrentBaseState = pDmeMesh->GetCurrentBaseState();
  433. if ( pDmeCurrentBaseState == pDmeEditBaseState )
  434. {
  435. pDmeMesh->SetValue( szPushCurr, pDmeCurrentBaseState );
  436. pDmeMesh->GetAttribute( szPushCurr )->AddFlag( FATTRIB_DONTSAVE );
  437. }
  438. CDmxEdit::RemoveBaseState( pDmeMesh, pDmeEditBaseState );
  439. if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) )
  440. {
  441. CDmeVertexData *pDmeOldCurrentVertexData = pDmeMesh->GetValueElement< CDmeVertexData >( s_szEditOldCurrentState );
  442. if ( pDmeOldCurrentVertexData )
  443. {
  444. pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() );
  445. }
  446. else
  447. {
  448. pDmeOldCurrentVertexData = pDmeMesh->GetBindBaseState();
  449. if ( pDmeOldCurrentVertexData )
  450. {
  451. pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() );
  452. }
  453. else
  454. {
  455. pDmeMesh->SetCurrentBaseState( pDmeMesh->GetBaseState( 0 )->GetName() );
  456. }
  457. }
  458. }
  459. }
  460. else
  461. {
  462. if ( pDmeMesh->HasAttribute( szPushEdit ) )
  463. {
  464. CDmxEdit::FindOrAddBaseState( pDmeMesh, pDmeMesh->GetValueElement< CDmeVertexData >( szPushEdit ) );
  465. pDmeMesh->RemoveAttribute( szPushEdit );
  466. }
  467. if ( pDmeMesh->HasAttribute( szPushCurr ) )
  468. {
  469. pDmeMesh->SetCurrentBaseState( pDmeMesh->GetValueElement< CDmeVertexData >( szPushCurr )->GetName() );
  470. pDmeMesh->RemoveAttribute( szPushCurr );
  471. }
  472. }
  473. }
  474. //-----------------------------------------------------------------------------
  475. //
  476. //-----------------------------------------------------------------------------
  477. void PushPopEditStates( CDmElement *pDmRoot, bool bPush )
  478. {
  479. if ( !pDmRoot )
  480. return;
  481. CDmeDag *pDmeDag = CastElement< CDmeDag >( pDmRoot );
  482. if ( !pDmeDag )
  483. {
  484. pDmeDag = pDmRoot->GetValueElement< CDmeDag >( "model" );
  485. }
  486. if ( !pDmeDag )
  487. return;
  488. CUtlStack< CDmeDag * > traverseStack;
  489. traverseStack.Push( pDmeDag );
  490. while ( traverseStack.Count() )
  491. {
  492. traverseStack.Pop( pDmeDag );
  493. if ( !pDmeDag )
  494. continue;
  495. for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i )
  496. {
  497. traverseStack.Push( pDmeDag->GetChild( i ) );
  498. }
  499. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() );
  500. if ( !pDmeMesh )
  501. continue;
  502. PushPopEditState( pDmeMesh, bPush );
  503. }
  504. }
  505. //-----------------------------------------------------------------------------
  506. //
  507. //-----------------------------------------------------------------------------
  508. void CleanupDmxEdit( CDmeMesh *pDmeMesh )
  509. {
  510. if ( !pDmeMesh )
  511. return;
  512. const char szPushEdit[] = "__dmxedit_pushEditBase";
  513. const char szPushCurr[] = "__dmxedit_pushCurrBase";
  514. CDmeVertexData *pDmeEditBaseState = FindMeshEditBaseState( pDmeMesh, __func__ );
  515. if ( !pDmeEditBaseState || pDmeMesh->BaseStateCount() <= 1 )
  516. return;
  517. pDmeMesh->SetValue( szPushEdit, pDmeEditBaseState );
  518. pDmeMesh->GetAttribute( szPushEdit )->AddFlag( FATTRIB_DONTSAVE );
  519. CDmeVertexData *pDmeCurrentBaseState = pDmeMesh->GetCurrentBaseState();
  520. if ( pDmeCurrentBaseState == pDmeEditBaseState )
  521. {
  522. pDmeMesh->SetValue( szPushCurr, pDmeCurrentBaseState );
  523. pDmeMesh->GetAttribute( szPushCurr )->AddFlag( FATTRIB_DONTSAVE );
  524. }
  525. CDmxEdit::RemoveBaseState( pDmeMesh, pDmeEditBaseState );
  526. if ( pDmeMesh->HasAttribute( s_szEditOldCurrentState ) )
  527. {
  528. CDmeVertexData *pDmeOldCurrentVertexData = pDmeMesh->GetValueElement< CDmeVertexData >( s_szEditOldCurrentState );
  529. if ( pDmeOldCurrentVertexData )
  530. {
  531. pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() );
  532. }
  533. else
  534. {
  535. pDmeOldCurrentVertexData = pDmeMesh->GetBindBaseState();
  536. if ( pDmeOldCurrentVertexData )
  537. {
  538. pDmeMesh->SetCurrentBaseState( pDmeOldCurrentVertexData->GetName() );
  539. }
  540. else
  541. {
  542. pDmeMesh->SetCurrentBaseState( pDmeMesh->GetBaseState( 0 )->GetName() );
  543. }
  544. }
  545. }
  546. }
  547. //-----------------------------------------------------------------------------
  548. //
  549. //-----------------------------------------------------------------------------
  550. void UpdateMakefile( CDmElement *pDmeRoot )
  551. {
  552. if ( !pDmeRoot )
  553. return;
  554. CDmeMakefile *pDmeMakefile = g_pDmxEditImpl->GetMakefile();
  555. if ( !pDmeMakefile )
  556. return;
  557. pDmeRoot->SetValue( "makefile", pDmeMakefile );
  558. pDmeMakefile->SetFileId( pDmeRoot->GetFileId(), TD_ALL );
  559. }
  560. //-----------------------------------------------------------------------------
  561. // In winstuff.cpp
  562. //-----------------------------------------------------------------------------
  563. void MyGetUserName( char *pszBuf, unsigned long *pBufSiz );
  564. void MyGetComputerName( char *pszBuf, unsigned long *pBufSiz );
  565. //-----------------------------------------------------------------------------
  566. //
  567. //-----------------------------------------------------------------------------
  568. void AddExportTags( CDmElement *pDmeRoot, const char *pszFilename )
  569. {
  570. if ( !pDmeRoot )
  571. return;
  572. CDmElement *pExportTags = CreateElement< CDmElement >( "python_dmxedit_exportTags", pDmeRoot->GetFileId() );
  573. char szTmpBuf[ BUFSIZ ];
  574. _strdate( szTmpBuf );
  575. pExportTags->SetValue( "date", szTmpBuf );
  576. _strtime( szTmpBuf );
  577. pExportTags->SetValue( "time", szTmpBuf );
  578. unsigned long dwSize( sizeof( szTmpBuf ) );
  579. *szTmpBuf ='\0';
  580. MyGetUserName( szTmpBuf, &dwSize);
  581. pExportTags->SetValue( "user", szTmpBuf );
  582. *szTmpBuf ='\0';
  583. dwSize = sizeof( szTmpBuf );
  584. MyGetComputerName( szTmpBuf, &dwSize);
  585. pExportTags->SetValue( "machine", szTmpBuf );
  586. pExportTags->SetValue( "app", "python" );
  587. pExportTags->SetValue( "cmdLine", "python <wuzza>" );
  588. CDmAttribute *pDmeLoadDmxAttr = pExportTags->AddAttribute( "LoadDmx", AT_STRING_ARRAY );
  589. CDmAttribute *pDmeLoadObjAttr = pExportTags->AddAttribute( "LoadObj", AT_STRING_ARRAY );
  590. CDmeMakefile *pDmeMakefile = g_pDmxEditImpl->GetMakefile();
  591. if ( pDmeMakefile )
  592. {
  593. const int nSourceCount = pDmeMakefile->GetSourceCount();
  594. for ( int i = 0; i < nSourceCount; ++i )
  595. {
  596. CDmeSource *pDmeSource = pDmeMakefile->GetSource( i );
  597. if ( pDmeSource->HasAttribute( "LoadDmx" ) )
  598. {
  599. CDmrStringArray( pDmeLoadDmxAttr ).AddToTail( pDmeSource->GetName() );
  600. }
  601. else
  602. {
  603. CDmrStringArray( pDmeLoadObjAttr ).AddToTail( pDmeSource->GetName() );
  604. }
  605. }
  606. }
  607. pExportTags->SetValue( "Save", pszFilename );
  608. pDmeRoot->SetValue( "python_dmxedit_exportTags", pExportTags );
  609. }
  610. //-----------------------------------------------------------------------------
  611. //
  612. //-----------------------------------------------------------------------------
  613. void RemoveExportTags( CDmElement *pRoot, const char *pExportTagsName )
  614. {
  615. if ( !pRoot )
  616. return;
  617. pRoot->RemoveAttribute( pExportTagsName );
  618. }
  619. //-----------------------------------------------------------------------------
  620. //
  621. //-----------------------------------------------------------------------------
  622. bool SaveDmx( CDmElement *pDmeRoot, const char *pszFilename )
  623. {
  624. if ( !pszFilename )
  625. DMXEDIT_WARNING_RETURN_FALSE( "No filename specified" );
  626. if ( !pDmeRoot )
  627. DMXEDIT_WARNING_RETURN_FALSE( "No root DmElement specified" );
  628. RemoveExportTags( pDmeRoot, "vsDmxIO_exportTags" );
  629. AddExportTags( pDmeRoot, pszFilename );
  630. UpdateMakefile( pDmeRoot );
  631. PushPopEditStates( pDmeRoot, true ); // push - hide them on save
  632. bool bRetVal = false;
  633. if ( !Q_stricmp( "dmx", Q_GetFileExtension( pszFilename ) ) )
  634. {
  635. bRetVal = g_pDataModel->SaveToFile( pszFilename, NULL, "keyvalues2", "model", pDmeRoot );
  636. if ( !bRetVal )
  637. {
  638. DMXEDIT_WARNING( "Couldn't write dmx file \"%s\"", pszFilename );
  639. }
  640. }
  641. else
  642. {
  643. DMXEDIT_WARNING( "Filename without .dmx extension passed to SaveDmx( \"%s\" )", pszFilename );
  644. }
  645. PushPopEditStates( pDmeRoot, false ); // pop
  646. return bRetVal;
  647. }
  648. //-----------------------------------------------------------------------------
  649. //
  650. //-----------------------------------------------------------------------------
  651. bool SaveObj( CDmElement *pDmeRoot, const char *pszFilename, const char *pszObjSaveType /* = "ABSOLUTE" */, const char *pszDeltaName /* = NULL */ )
  652. {
  653. if ( !pszFilename )
  654. DMXEDIT_WARNING_RETURN_FALSE( "No filename specified" );
  655. if ( !pDmeRoot )
  656. DMXEDIT_WARNING_RETURN_FALSE( "No root DmElement specified" );
  657. PushPopEditStates( pDmeRoot, true ); // push - hide them on save
  658. bool bRetVal = false;
  659. if ( !Q_stricmp( "obj", Q_GetFileExtension( pszFilename ) ) )
  660. {
  661. bool bAbsoluteObjs = true;
  662. if ( pszObjSaveType )
  663. {
  664. if ( !Q_stricmp( "absolute", pszObjSaveType ) )
  665. {
  666. bAbsoluteObjs = true;
  667. }
  668. else if ( !Q_stricmp( "relative", pszObjSaveType ) )
  669. {
  670. bAbsoluteObjs = false;
  671. }
  672. else
  673. {
  674. DMXEDIT_ERROR( "Invalid OBJ Save specified (%s), must be \"ABSOLUTE\" or \"RELATIVE\"", pszObjSaveType );
  675. }
  676. }
  677. if ( pszDeltaName )
  678. {
  679. if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) )
  680. {
  681. bRetVal = CDmObjSerializer().WriteOBJ( pszFilename, pDmeRoot, false, NULL, bAbsoluteObjs );
  682. }
  683. else
  684. {
  685. bRetVal = CDmObjSerializer().WriteOBJ( pszFilename, pDmeRoot, true, pszDeltaName, bAbsoluteObjs );
  686. }
  687. }
  688. else
  689. {
  690. bRetVal = CDmObjSerializer().WriteOBJ( pszFilename, pDmeRoot, true, NULL, bAbsoluteObjs );
  691. }
  692. }
  693. else
  694. {
  695. DMXEDIT_WARNING( "Filename without .obj extension passed to SaveDmx( \"%s\" )", pszFilename );
  696. }
  697. PushPopEditStates( pDmeRoot, false ); // pop
  698. return bRetVal;
  699. }
  700. //-----------------------------------------------------------------------------
  701. // The internal version of FindMesh
  702. //-----------------------------------------------------------------------------
  703. CDmeMesh *FindMesh( CDmElement *pRoot, const char *pszMeshSearchName, bool bComboOnly )
  704. {
  705. if ( !pRoot )
  706. return NULL;
  707. CDmeDag *pDmeDag = CastElement< CDmeDag >( pRoot );
  708. if ( !pDmeDag )
  709. {
  710. pDmeDag = pRoot->GetValueElement< CDmeDag >( "model" );
  711. }
  712. if ( !pDmeDag )
  713. DMXEDIT_WARNING_RETURN_NULL( "Invalid DmElement passed, DmeDag or element with \"model\" attribute required" );
  714. CUtlStack< CDmeDag * > traverseStack;
  715. traverseStack.Push( pDmeDag );
  716. while ( traverseStack.Count() )
  717. {
  718. traverseStack.Pop( pDmeDag );
  719. if ( !pDmeDag )
  720. continue;
  721. for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i )
  722. {
  723. traverseStack.Push( pDmeDag->GetChild( i ) );
  724. }
  725. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() );
  726. if ( !pDmeMesh )
  727. continue;
  728. // Looking for a named mesh? Return if found
  729. if ( pszMeshSearchName && ( !Q_strcmp( pszMeshSearchName, pDmeDag->GetName() ) || !Q_strcmp( pszMeshSearchName, pDmeMesh->GetName() ) ) )
  730. return pDmeMesh;
  731. // Looking for a combo mesh? Return if found
  732. if ( bComboOnly && pDmeMesh->DeltaStateCount() )
  733. return pDmeMesh;
  734. // Looking for a named or combo mesh, this wasn't it so keep looking
  735. if ( bComboOnly || pszMeshSearchName )
  736. continue;
  737. // Looking for the first mesh? Ok!
  738. return pDmeMesh;
  739. }
  740. // No mesh found
  741. return NULL;
  742. }
  743. //-----------------------------------------------------------------------------
  744. //
  745. //-----------------------------------------------------------------------------
  746. CDmeMesh *GetFirstComboMesh( CDmElement *pRoot )
  747. {
  748. CDmeMesh *pDmeMesh = FindMesh( pRoot, NULL, true );
  749. if ( !pDmeMesh )
  750. DMXEDIT_WARNING_RETURN_NULL( "No mesh with combinations found" );
  751. return pDmeMesh;
  752. }
  753. //-----------------------------------------------------------------------------
  754. //
  755. //-----------------------------------------------------------------------------
  756. CDmeMesh *GetNamedMesh( CDmElement *pRoot, const char *pszMeshSearchName )
  757. {
  758. CDmeMesh *pDmeMesh = FindMesh( pRoot, pszMeshSearchName, false );
  759. if ( !pDmeMesh )
  760. DMXEDIT_WARNING_RETURN_NULL( "No mesh named \"%s\" found", pszMeshSearchName );
  761. return pDmeMesh;
  762. }
  763. //-----------------------------------------------------------------------------
  764. //
  765. //-----------------------------------------------------------------------------
  766. CDmeMesh *GetFirstMesh( CDmElement *pDmeRoot )
  767. {
  768. CDmeMesh *pDmeMesh = FindMesh( pDmeRoot, NULL, false );
  769. if ( !pDmeMesh )
  770. DMXEDIT_WARNING_RETURN_NULL( "No mesh found" );
  771. return pDmeMesh;
  772. }
  773. //-----------------------------------------------------------------------------
  774. // Do a depth first walk of all siblings of the dmeDag owning this mesh
  775. //-----------------------------------------------------------------------------
  776. CDmeMesh *GetNextMesh( CDmeMesh *pCurrentDmeMesh )
  777. {
  778. DMXEDIT_MESH_WARNING_RETURN_NULL( pCurrentDmeMesh );
  779. CDmeDag *pDmeDag = FindReferringElement< CDmeDag >( pCurrentDmeMesh, "shape" );
  780. if ( !pDmeDag )
  781. DMXEDIT_WARNING_RETURN_NULL( "No dmeDag owning mesh \"%s\"", pCurrentDmeMesh->GetName() );
  782. // Walk up to the root
  783. CDmeDag *pDmeDagParent = NULL;
  784. for ( ;; )
  785. {
  786. pDmeDagParent = FindReferringElement< CDmeDag >( pDmeDag, "children" );
  787. if ( !pDmeDagParent )
  788. break;
  789. pDmeDag = pDmeDagParent;
  790. }
  791. CUtlStack< CDmeDag * > traverseStack;
  792. for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i )
  793. {
  794. traverseStack.Push( pDmeDag->GetChild( i ) );
  795. }
  796. bool bNext = false;
  797. while ( traverseStack.Count() )
  798. {
  799. traverseStack.Pop( pDmeDag );
  800. if ( !pDmeDag )
  801. continue;
  802. for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i )
  803. {
  804. traverseStack.Push( pDmeDag->GetChild( i ) );
  805. }
  806. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() );
  807. if ( !pDmeMesh )
  808. continue;
  809. if ( pDmeMesh == pCurrentDmeMesh )
  810. {
  811. bNext = true;
  812. continue;
  813. }
  814. if ( bNext )
  815. return pDmeMesh;
  816. }
  817. return NULL;
  818. }
  819. //-----------------------------------------------------------------------------
  820. // Prints a list of all of the deltas present in the specified mesh
  821. //-----------------------------------------------------------------------------
  822. bool ListDeltas( CDmeMesh *pDmeMesh )
  823. {
  824. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  825. const int nDeltas = pDmeMesh->DeltaStateCount();
  826. if ( nDeltas <= 0 )
  827. DMXEDIT_WARNING_RETURN_FALSE( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
  828. for ( int i( 0 ); i < nDeltas; ++i )
  829. {
  830. Msg( "# Delta %d: %s\n", i, pDmeMesh->GetDeltaState( i )->GetName() );
  831. }
  832. return true;
  833. }
  834. //-----------------------------------------------------------------------------
  835. //
  836. //-----------------------------------------------------------------------------
  837. int DeltaCount( CDmeMesh *pDmeMesh )
  838. {
  839. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  840. return pDmeMesh->DeltaStateCount();
  841. }
  842. //-----------------------------------------------------------------------------
  843. //
  844. //-----------------------------------------------------------------------------
  845. const char *DeltaName( CDmeMesh *pDmeMesh, int nDeltaIndex )
  846. {
  847. DMXEDIT_MESH_WARNING_RETURN_EMPTY_STRING( pDmeMesh );
  848. const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
  849. if ( nDeltaStateCount <= 0 )
  850. DMXEDIT_WARNING_RETURN_EMPTY_STRING( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
  851. if ( nDeltaIndex < 0 && nDeltaIndex >= nDeltaStateCount )
  852. DMXEDIT_WARNING_RETURN_EMPTY_STRING( "Delta %n out of range, Mesh \"%s\" has %d deltas", nDeltaIndex, pDmeMesh->GetName(), nDeltaStateCount );
  853. return pDmeMesh->GetDeltaState( nDeltaIndex )->GetName();
  854. }
  855. //-----------------------------------------------------------------------------
  856. //
  857. //-----------------------------------------------------------------------------
  858. CDmeVertexDeltaData *GetDeltaState( CDmeMesh *pDmeMesh, int nDeltaIndex )
  859. {
  860. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  861. const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
  862. if ( nDeltaStateCount <= 0 )
  863. DMXEDIT_WARNING_RETURN_NULL( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
  864. if ( nDeltaIndex < 0 && nDeltaIndex >= nDeltaStateCount )
  865. DMXEDIT_WARNING_RETURN_NULL( "Delta %n out of range, Mesh \"%s\" has %d deltas", nDeltaIndex, pDmeMesh->GetName(), nDeltaStateCount );
  866. return pDmeMesh->GetDeltaState( nDeltaIndex );
  867. }
  868. //-----------------------------------------------------------------------------
  869. //
  870. //-----------------------------------------------------------------------------
  871. CDmeVertexDeltaData *GetDeltaState( CDmeMesh *pDmeMesh, const char *pszDeltaName )
  872. {
  873. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  874. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  875. if ( pDmeDelta )
  876. DMXEDIT_WARNING_RETURN_NULL( "Mesh \"%s\" has no deltas", pDmeMesh->GetName() );
  877. return pDmeDelta;
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Checks whether the specified mesh & base state are valid and the base
  881. // state actually belongs to the mesh
  882. // TODO: verify base state is the same as bind state?
  883. // TODO: Size checks?
  884. //-----------------------------------------------------------------------------
  885. bool DeltaStateSanityCheck( CDmeMesh *pDmeMesh, CDmeVertexDeltaData *pDmeDeltaState, const char *pszFuncName )
  886. {
  887. if ( !pDmeMesh )
  888. {
  889. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: No mesh specified", pszFuncName );
  890. return false;
  891. }
  892. if ( !pDmeDeltaState )
  893. {
  894. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Non-existent delta state specified", pszFuncName );
  895. return false;
  896. }
  897. CDmeVertexDeltaData *pDmeDeltaStateCheck = pDmeMesh->FindDeltaState( pDmeDeltaState->GetName() );
  898. if ( !pDmeDeltaStateCheck || pDmeDeltaState != pDmeDeltaStateCheck )
  899. {
  900. g_pDmxEditImpl->SetErrorString( DMXEDIT_WARNING, "%s: Delta state \"%s\" doesn't belong to mesh \"%s\"", pszFuncName, pDmeDeltaState->GetName(), pDmeMesh->GetName() );
  901. return false;
  902. }
  903. return true;
  904. }
  905. //-----------------------------------------------------------------------------
  906. //
  907. //-----------------------------------------------------------------------------
  908. bool ResetState( CDmeMesh *pDmeMesh )
  909. {
  910. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  911. CDmeVertexData *pDmeEditBaseState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  912. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, __func__ ) )
  913. return false;
  914. return pDmeMesh->SetBaseStateToDelta( NULL, pDmeEditBaseState );
  915. }
  916. //-----------------------------------------------------------------------------
  917. //
  918. //-----------------------------------------------------------------------------
  919. bool SetState( CDmeMesh *pDmeMesh, const char *pszDeltaName )
  920. {
  921. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  922. CDmeVertexData *pDmeEditBaseState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  923. if ( !pDmeEditBaseState )
  924. return false;
  925. if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) )
  926. return ResetState( pDmeMesh );
  927. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  928. if ( !DeltaStateSanityCheck( pDmeMesh, pDmeDelta, __func__ ) )
  929. return false;
  930. pDmeDelta->Resolve();
  931. return pDmeMesh->SetBaseStateToDelta( pDmeDelta, pDmeEditBaseState );
  932. }
  933. //-----------------------------------------------------------------------------
  934. //
  935. //-----------------------------------------------------------------------------
  936. bool RemoveFacesWithMaterial( CDmeMesh *pDmeMesh, const char *pszMaterialName )
  937. {
  938. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  939. return CDmMeshUtils::RemoveFacesWithMaterial( pDmeMesh, pszMaterialName );
  940. }
  941. //-----------------------------------------------------------------------------
  942. //
  943. //-----------------------------------------------------------------------------
  944. bool RemoveFacesWithMoreThanNVerts( CDmeMesh *pDmeMesh, int nVertexCount )
  945. {
  946. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  947. return CDmMeshUtils::RemoveFacesWithMoreThanNVerts( pDmeMesh, nVertexCount );
  948. }
  949. //-----------------------------------------------------------------------------
  950. // After an operation to the bind base state, copy the bind data around to all
  951. // other base states...
  952. //-----------------------------------------------------------------------------
  953. void FixupBaseStates( CDmeMesh * pDmeMesh )
  954. {
  955. CDmeVertexData *pBindState = pDmeMesh->GetBindBaseState();
  956. if ( pBindState )
  957. {
  958. const int nBaseStateCount = pDmeMesh->BaseStateCount();
  959. for ( int i = 0; i < nBaseStateCount; ++i )
  960. {
  961. CDmeVertexData *pBaseState = pDmeMesh->GetBaseState( i );
  962. if ( pBindState != pBaseState )
  963. {
  964. pBindState->CopyTo( pBaseState );
  965. }
  966. }
  967. }
  968. }
  969. //-----------------------------------------------------------------------------
  970. //
  971. //-----------------------------------------------------------------------------
  972. bool Mirror( CDmeMesh *pDmeMesh, const char *pszAxis /* = "x" */ )
  973. {
  974. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  975. if ( !pszAxis || !*pszAxis )
  976. DMXEDIT_WARNING_RETURN_FALSE( "No axis specified" );
  977. int nAxis = -1;
  978. switch ( *pszAxis )
  979. {
  980. case 'x':
  981. case 'X':
  982. nAxis = 0;
  983. break;
  984. case 'y':
  985. case 'Y':
  986. nAxis = 1;
  987. break;
  988. case 'z':
  989. case 'Z':
  990. nAxis = 2;
  991. break;
  992. }
  993. if ( nAxis < 0 )
  994. DMXEDIT_WARNING_RETURN_FALSE( "Invalid axis \"%s\" specified, must be one of \"x\", \"y\" or \"z\"", pszAxis );
  995. // Mirror operates on "bind" state
  996. const bool bRetVal = CDmMeshUtils::Mirror( pDmeMesh, nAxis );
  997. FixupBaseStates( pDmeMesh );
  998. return bRetVal;
  999. }
  1000. //-----------------------------------------------------------------------------
  1001. //
  1002. //-----------------------------------------------------------------------------
  1003. bool ComputeNormals( CDmeMesh *pDmeMesh )
  1004. {
  1005. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1006. pDmeMesh->ComputeDeltaStateNormals();
  1007. return true;
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Returns the CDmeCombinationOperator ultimately controlling the specified
  1011. // DmeMesh by searched backwards on elements referring to "targets"
  1012. // Returns NULL if not found
  1013. //-----------------------------------------------------------------------------
  1014. CDmeCombinationOperator *GetComboOpFromMesh( CDmeMesh *pDmeMesh )
  1015. {
  1016. if ( !pDmeMesh )
  1017. return NULL;
  1018. CUtlRBTree< CDmElement * > visited( CDefOps< CDmElement * >::LessFunc );
  1019. visited.Insert( pDmeMesh );
  1020. const CUtlSymbolLarge sTargets = g_pDataModel->GetSymbol( "targets" );
  1021. const CUtlSymbolLarge sTarget = g_pDataModel->GetSymbol( "target" );
  1022. CDmElement *pDmThisElement = pDmeMesh;
  1023. CDmElement *pDmNextElement = NULL;
  1024. while ( pDmThisElement )
  1025. {
  1026. pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTargets );
  1027. if ( !pDmNextElement )
  1028. {
  1029. pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTarget );
  1030. }
  1031. if ( !pDmNextElement )
  1032. break;
  1033. pDmThisElement = pDmNextElement;
  1034. if ( CastElement< CDmeCombinationOperator >( pDmThisElement ) )
  1035. return CastElement< CDmeCombinationOperator >( pDmThisElement );
  1036. if ( visited.IsValidIndex( visited.Find( pDmThisElement ) ) )
  1037. break;
  1038. visited.Insert( pDmThisElement );
  1039. }
  1040. return NULL;
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. //
  1044. //-----------------------------------------------------------------------------
  1045. bool ComputeWrinkles( CDmeMesh *pDmeMesh, bool bOverwrite /* = false */ )
  1046. {
  1047. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1048. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1049. if ( !pDmeCombo )
  1050. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1051. pDmeCombo->GenerateWrinkleDeltas( bOverwrite );
  1052. return true;
  1053. }
  1054. //-----------------------------------------------------------------------------
  1055. //
  1056. //-----------------------------------------------------------------------------
  1057. bool ComputeNormalWrinkles( CDmeMesh *pDmeMesh, float flScale, bool bOverwrite /* = false */ )
  1058. {
  1059. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1060. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1061. if ( !pDmeCombo )
  1062. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1063. pDmeCombo->GenerateWrinkleDeltas( bOverwrite, true, flScale );
  1064. return true;
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. //
  1068. //-----------------------------------------------------------------------------
  1069. bool ComputeWrinkle( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flScale, const char *pszOperation /* = "replace" */ )
  1070. {
  1071. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1072. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  1073. if ( !pDmeDelta )
  1074. DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
  1075. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1076. if ( !pDmeCombo )
  1077. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1078. CDmMeshUtils::WrinkleOp wrinkleOp = StringHasPrefix( pszOperation, "r" ) ? CDmMeshUtils::kReplace : CDmMeshUtils::kAdd;
  1079. const int nControlCount = pDmeCombo->GetControlCount();
  1080. for ( int nControlIndex = 0; nControlIndex < nControlCount; ++nControlIndex )
  1081. {
  1082. const int nRawControlCount = pDmeCombo->GetRawControlCount( nControlIndex );
  1083. for ( int nRawControlIndex = 0; nRawControlIndex < nRawControlCount; ++nRawControlIndex )
  1084. {
  1085. if ( Q_strcmp( pszDeltaName, pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ) ) )
  1086. continue;
  1087. pDmeCombo->SetWrinkleScale( nControlIndex, pszDeltaName, 1.0f );
  1088. break;
  1089. }
  1090. }
  1091. CDmeVertexData *pDmeBindState = pDmeMesh->GetBindBaseState();
  1092. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  1093. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  1094. return false;
  1095. return CDmMeshUtils::CreateWrinkleDeltaFromBaseState( pDmeDelta, flScale, wrinkleOp, pDmeMesh, pDmeBindState, pDmeEditState );
  1096. }
  1097. //-----------------------------------------------------------------------------
  1098. //
  1099. //-----------------------------------------------------------------------------
  1100. bool ComputeNormalWrinkle( CDmeMesh *pDmeMesh, const char *pszDeltaName, float flScale, const char *pszOperation /* = "replace" */ )
  1101. {
  1102. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1103. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  1104. if ( !pDmeDelta )
  1105. DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
  1106. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1107. if ( !pDmeCombo )
  1108. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1109. CDmMeshUtils::WrinkleOp wrinkleOp = StringHasPrefix( pszOperation, "r" ) ? CDmMeshUtils::kReplace : CDmMeshUtils::kAdd;
  1110. const int nControlCount = pDmeCombo->GetControlCount();
  1111. for ( int nControlIndex = 0; nControlIndex < nControlCount; ++nControlIndex )
  1112. {
  1113. const int nRawControlCount = pDmeCombo->GetRawControlCount( nControlIndex );
  1114. for ( int nRawControlIndex = 0; nRawControlIndex < nRawControlCount; ++nRawControlIndex )
  1115. {
  1116. if ( Q_strcmp( pszDeltaName, pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ) ) )
  1117. continue;
  1118. pDmeCombo->SetWrinkleScale( nControlIndex, pszDeltaName, 1.0f );
  1119. break;
  1120. }
  1121. }
  1122. CDmeVertexData *pDmeBindState = pDmeMesh->GetBindBaseState();
  1123. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  1124. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  1125. return false;
  1126. return CDmMeshUtils::CreateWrinkleDeltaFromBaseState( pDmeDelta, flScale, wrinkleOp, pDmeMesh, pDmeBindState, pDmeEditState, true );
  1127. }
  1128. //-----------------------------------------------------------------------------
  1129. //
  1130. //-----------------------------------------------------------------------------
  1131. bool SaveDelta( CDmeMesh *pDmeMesh, const char *pszDeltaName )
  1132. {
  1133. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1134. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  1135. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  1136. return false;
  1137. // See if it's the "base" state we're updating and not a new delta state at all
  1138. if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) )
  1139. {
  1140. CDmeVertexData *pDmeBind = pDmeMesh->GetBindBaseState();
  1141. if ( !pDmeBind )
  1142. DMXEDIT_WARNING_RETURN_FALSE( "Couldn't get bind base state from mesh \"%s\"", pDmeMesh->GetName() );
  1143. if ( pDmeEditState == pDmeBind )
  1144. DMXEDIT_WARNING_RETURN_FALSE( "Current state on mesh is the bind state on mesh \"%s\"", pDmeMesh->GetName() );
  1145. pDmeEditState->CopyTo( pDmeBind );
  1146. return true;
  1147. }
  1148. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->ModifyOrCreateDeltaStateFromBaseState( pszDeltaName, pDmeEditState );
  1149. if ( pDmeDelta )
  1150. {
  1151. pDmeDelta->Resolve();
  1152. return true;
  1153. }
  1154. DMXEDIT_WARNING_RETURN_FALSE( "Couldn't create new delta state from base state on mesh \"%s\"", pDmeMesh->GetName() );
  1155. }
  1156. //-----------------------------------------------------------------------------
  1157. //
  1158. //-----------------------------------------------------------------------------
  1159. bool DeleteDelta( CDmeMesh *pDmeMesh, const char *pszDeltaName )
  1160. {
  1161. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1162. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  1163. if ( !pDmeDelta )
  1164. DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
  1165. return pDmeMesh->DeleteDeltaState( pszDeltaName );
  1166. }
  1167. //-----------------------------------------------------------------------------
  1168. // Helper function for Scale
  1169. //-----------------------------------------------------------------------------
  1170. static void ScaleDeltaPositions(
  1171. const CDmrArrayConst< Vector > &bindPosData,
  1172. CDmeVertexDeltaData *pDmeDelta,
  1173. float flScaleX,
  1174. float flScaleY,
  1175. float flScaleZ )
  1176. {
  1177. const int nPosIndex = pDmeDelta->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  1178. if ( nPosIndex < 0 )
  1179. return;
  1180. CDmrArray< Vector > posData = pDmeDelta->GetVertexData( nPosIndex );
  1181. const int nPosDataCount = posData.Count();
  1182. if ( nPosDataCount <= 0 )
  1183. return;
  1184. Vector *pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) );
  1185. for ( int j = 0; j < nPosDataCount; ++j )
  1186. {
  1187. const Vector &s = posData.Get( j );
  1188. Vector &d = pPosArray[ j ];
  1189. d.x = s.x * flScaleX;
  1190. d.y = s.y * flScaleY;
  1191. d.z = s.z * flScaleZ;
  1192. }
  1193. posData.SetMultiple( 0, nPosDataCount, pPosArray );
  1194. }
  1195. //-----------------------------------------------------------------------------
  1196. //
  1197. //-----------------------------------------------------------------------------
  1198. bool Scale( CDmeMesh *pDmeMesh, float flScaleX, float flScaleY, float flScaleZ )
  1199. {
  1200. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1201. int nArraySize = 0;
  1202. Vector *pPosArray = NULL;
  1203. const int nBaseStateCount = pDmeMesh->BaseStateCount();
  1204. for ( int i = 0; i < nBaseStateCount; ++i )
  1205. {
  1206. CDmeVertexData *pBase = pDmeMesh->GetBaseState( i );
  1207. const int nPosIndex = pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  1208. if ( nPosIndex < 0 )
  1209. continue;
  1210. CDmrArray< Vector > posData = pBase->GetVertexData( nPosIndex );
  1211. const int nPosDataCount = posData.Count();
  1212. if ( nPosDataCount <= 0 )
  1213. continue;
  1214. if ( nArraySize < nPosDataCount || pPosArray == NULL )
  1215. {
  1216. pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) );
  1217. if ( pPosArray )
  1218. {
  1219. nArraySize = nPosDataCount;
  1220. }
  1221. }
  1222. if ( nArraySize < nPosDataCount )
  1223. continue;
  1224. for ( int j = 0; j < nPosDataCount; ++j )
  1225. {
  1226. const Vector &s = posData.Get( j );
  1227. Vector &d = pPosArray[ j ];
  1228. d.x = s.x * flScaleX;
  1229. d.y = s.y * flScaleY;
  1230. d.z = s.z * flScaleZ;
  1231. }
  1232. posData.SetMultiple( 0, nPosDataCount, pPosArray );
  1233. }
  1234. {
  1235. CDmeVertexData *pBind = pDmeMesh->GetBindBaseState();
  1236. const int nPosIndex = pBind ? pBind->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) : -1;
  1237. if ( !pBind || nPosIndex < 0 )
  1238. DMXEDIT_WARNING_RETURN_FALSE( "Can't scale delta states on mesh \"%s\"", pDmeMesh->GetName() );
  1239. const CDmrArrayConst< Vector > posData = pBind->GetVertexData( nPosIndex );
  1240. const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
  1241. for ( int i = 0; i < nDeltaStateCount; ++i )
  1242. {
  1243. ScaleDeltaPositions( posData, pDmeMesh->GetDeltaState( i ), flScaleX, flScaleY, flScaleZ );
  1244. }
  1245. }
  1246. return true;
  1247. }
  1248. //-----------------------------------------------------------------------------
  1249. //
  1250. //-----------------------------------------------------------------------------
  1251. bool Scale( CDmeMesh *pDmeMesh, float flScale )
  1252. {
  1253. return Scale( pDmeMesh, flScale, flScale, flScale );
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. //
  1257. //-----------------------------------------------------------------------------
  1258. bool SetStereoControl( CDmeMesh *pDmeMesh, const char *pszControlName, bool bStereo /* = true */ )
  1259. {
  1260. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1261. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1262. if ( !pDmeCombo )
  1263. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1264. const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName );
  1265. if ( nControlIndex < 0 )
  1266. DMXEDIT_WARNING_RETURN_FALSE( "No control named \"%s\" found on combo op \"%s\" on mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
  1267. pDmeCombo->SetStereoControl( nControlIndex, bStereo );
  1268. return true;
  1269. }
  1270. //-----------------------------------------------------------------------------
  1271. //
  1272. //-----------------------------------------------------------------------------
  1273. bool SetEyelidControl( CDmeMesh *pDmeMesh, const char *pszControlName, bool bEyelid /* = true */ )
  1274. {
  1275. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1276. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1277. if ( !pDmeCombo )
  1278. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1279. const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName );
  1280. if ( nControlIndex < 0 )
  1281. DMXEDIT_WARNING_RETURN_FALSE( "No control named \"%s\" found on combo op \"%s\" on mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
  1282. pDmeCombo->SetEyelidControl( nControlIndex, bEyelid );
  1283. return true;
  1284. }
  1285. //-----------------------------------------------------------------------------
  1286. //
  1287. //-----------------------------------------------------------------------------
  1288. float MaxDeltaDistance( CDmeMesh *pDmeMesh, const char *pszDeltaName )
  1289. {
  1290. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1291. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  1292. if ( !pDmeDelta )
  1293. DMXEDIT_WARNING_RETURN_FALSE( "Cannot find Delta state \"%s\" on mesh \"%s\"", pszDeltaName, pDmeMesh->GetName() );
  1294. if ( !pDmeDelta )
  1295. return 0.0f;
  1296. float fSqMaxDelta = 0.0f;
  1297. float fTmpSqLength;
  1298. const CUtlVector< Vector > &positions = pDmeDelta->GetPositionData();
  1299. const int nPositionCount = positions.Count();
  1300. for ( int i = 0; i < nPositionCount; ++i )
  1301. {
  1302. fTmpSqLength = positions[ i ].LengthSqr();
  1303. if ( fTmpSqLength < fSqMaxDelta )
  1304. continue;
  1305. fSqMaxDelta = fTmpSqLength;
  1306. }
  1307. return sqrt( fSqMaxDelta );
  1308. }
  1309. //-----------------------------------------------------------------------------
  1310. //
  1311. //-----------------------------------------------------------------------------
  1312. bool SetWrinkleScale( CDmeMesh *pDmeMesh, const char *pszControlName, const char *pszRawControlName, float flScale )
  1313. {
  1314. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1315. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1316. if ( !pDmeCombo )
  1317. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1318. const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName );
  1319. if ( nControlIndex < 0 )
  1320. DMXEDIT_WARNING_RETURN_FALSE( "No control named \"%s\" found on combo op \"%s\" on mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
  1321. // Check to see if the raw control exists
  1322. bool bFoundRawControl = false;
  1323. for ( int nRawControlIndex = 0; nRawControlIndex < pDmeCombo->GetRawControlCount( nControlIndex ); ++nRawControlIndex )
  1324. {
  1325. if ( !Q_strcmp( pszRawControlName, pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex ) ) )
  1326. {
  1327. bFoundRawControl = true;
  1328. break;
  1329. }
  1330. }
  1331. if ( !bFoundRawControl )
  1332. {
  1333. CUtlString rawControls;
  1334. for ( int nRawControlIndex = 0; nRawControlIndex < pDmeCombo->GetRawControlCount( nControlIndex ); ++nRawControlIndex )
  1335. {
  1336. if ( rawControls.Length() > 0 )
  1337. {
  1338. rawControls += ", ";
  1339. }
  1340. rawControls += pDmeCombo->GetRawControlName( nControlIndex, nRawControlIndex );
  1341. }
  1342. DMXEDIT_WARNING_RETURN_FALSE( "Control \"%s\" does not have Raw Control \"%s\" on combo op \"%s\" on mesh \"%s\"", pszControlName, pszRawControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
  1343. }
  1344. pDmeCombo->SetWrinkleScale( nControlIndex, pszRawControlName, flScale );
  1345. return true;
  1346. }
  1347. //-----------------------------------------------------------------------------
  1348. // If it finds a duplicate control name, reports an error message and
  1349. // returns it found one
  1350. // Helper function for GroupControls
  1351. //-----------------------------------------------------------------------------
  1352. bool HasDuplicateControlName(
  1353. CDmeCombinationOperator *pDmeCombo,
  1354. const char *pControlName,
  1355. CUtlVector< const char * > &retiredControlNames )
  1356. {
  1357. int i;
  1358. int nRetiredControlNameCount = retiredControlNames.Count();
  1359. for ( i = 0; i < nRetiredControlNameCount; ++i )
  1360. {
  1361. if ( !Q_stricmp( retiredControlNames[i], pControlName ) )
  1362. break;
  1363. }
  1364. if ( i == nRetiredControlNameCount )
  1365. {
  1366. if ( pDmeCombo->FindControlIndex( pControlName ) >= 0 )
  1367. return true;
  1368. }
  1369. return false;
  1370. }
  1371. //-----------------------------------------------------------------------------
  1372. //
  1373. //-----------------------------------------------------------------------------
  1374. bool GroupControls( CDmeMesh *pDmeMesh, const char *pszGroupName, CUtlVector< const char * > &rawControlNames )
  1375. {
  1376. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1377. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1378. if ( !pDmeCombo )
  1379. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1380. // Loop through controls to see if any are already group controls, warn and remove
  1381. CUtlVector< const char * > validControlNames;
  1382. bool bStereo = false;
  1383. bool bEyelid = false;
  1384. for ( int i = 0; i < rawControlNames.Count(); ++i )
  1385. {
  1386. ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( rawControlNames[ i ] );
  1387. if ( nControlIndex < 0 )
  1388. {
  1389. DMXEDIT_WARNING( "Control \"%s\" Doesn't Exist, Ignoring", pszGroupName );
  1390. continue;
  1391. }
  1392. if ( pDmeCombo->GetRawControlCount( nControlIndex ) > 1 )
  1393. {
  1394. DMXEDIT_WARNING( "Control \"%s\" Isn't A Raw Control, Ignoring", pszGroupName );
  1395. continue;
  1396. }
  1397. validControlNames.AddToTail( rawControlNames[ i ] );
  1398. if ( pDmeCombo->IsStereoControl( nControlIndex ) )
  1399. {
  1400. bStereo = true;
  1401. }
  1402. if ( pDmeCombo->IsEyelidControl( nControlIndex ) )
  1403. {
  1404. bEyelid = true;
  1405. }
  1406. }
  1407. if ( HasDuplicateControlName( pDmeCombo, pszGroupName, validControlNames ) )
  1408. DMXEDIT_WARNING_RETURN_FALSE( "Duplicate Control \"%s\" Found", pszGroupName );
  1409. if ( validControlNames.Count() <= 0 )
  1410. DMXEDIT_WARNING_RETURN_FALSE( "No Valid Controls Specified" );
  1411. // Remove the old controls
  1412. for ( int i = 0; i < validControlNames.Count(); ++i )
  1413. {
  1414. pDmeCombo->RemoveControl( validControlNames[i] );
  1415. }
  1416. // Create new control
  1417. ControlIndex_t nNewControl = pDmeCombo->FindOrCreateControl( pszGroupName, bStereo );
  1418. pDmeCombo->SetEyelidControl( nNewControl, bEyelid );
  1419. for ( int i = 0; i < validControlNames.Count(); ++i )
  1420. {
  1421. pDmeCombo->AddRawControl( nNewControl, validControlNames[i] );
  1422. }
  1423. return true;
  1424. }
  1425. //-----------------------------------------------------------------------------
  1426. //
  1427. //-----------------------------------------------------------------------------
  1428. void GetDeltaNames( CDmeMesh *pDmeMesh, CUtlVector< const char * > *pOutStringList )
  1429. {
  1430. if ( !pOutStringList )
  1431. {
  1432. DMXEDIT_WARNING( "No storage passed for result" );
  1433. return;
  1434. }
  1435. pOutStringList->RemoveAll();
  1436. if ( !pDmeMesh )
  1437. {
  1438. DMXEDIT_WARNING( "No mesh specified" );
  1439. return;
  1440. }
  1441. const int nDeltaStateCount = pDmeMesh->DeltaStateCount();
  1442. for ( int i = 0; i < nDeltaStateCount; ++i )
  1443. {
  1444. const CDmeVertexDeltaData *pDmeDelta = pDmeMesh->GetDeltaState( i );
  1445. if ( !pDmeDelta )
  1446. {
  1447. pOutStringList->AddToTail( "<unknown>" );
  1448. }
  1449. else
  1450. {
  1451. pOutStringList->AddToTail( pDmeDelta->GetName() );
  1452. }
  1453. }
  1454. }
  1455. //-----------------------------------------------------------------------------
  1456. //
  1457. //-----------------------------------------------------------------------------
  1458. void GetRawControlNames( CDmeMesh *pDmeMesh, CUtlVector< const char * > *pOutStringList, const char *pszControlName /* = NULL */ )
  1459. {
  1460. if ( !pOutStringList )
  1461. {
  1462. DMXEDIT_WARNING( "No storage passed for result" );
  1463. return;
  1464. }
  1465. pOutStringList->RemoveAll();
  1466. if ( !pDmeMesh )
  1467. {
  1468. DMXEDIT_WARNING( "No mesh specified" );
  1469. return;
  1470. }
  1471. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1472. if ( !pDmeCombo )
  1473. {
  1474. DMXEDIT_WARNING( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1475. return;
  1476. }
  1477. if ( pszControlName )
  1478. {
  1479. const ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( pszControlName );
  1480. if ( nControlIndex < 0 )
  1481. {
  1482. DMXEDIT_WARNING( "No control named \"%s\" on DmeCombinationOperator \"%s\" controlling mesh \"%s\"", pszControlName, pDmeCombo->GetName(), pDmeMesh->GetName() );
  1483. }
  1484. else
  1485. {
  1486. const int nRawControlCount = pDmeCombo->GetRawControlCount( nControlIndex );
  1487. for ( int i = 0; i < nRawControlCount; ++i )
  1488. {
  1489. pOutStringList->AddToTail( pDmeCombo->GetRawControlName( nControlIndex, i ) );
  1490. }
  1491. }
  1492. }
  1493. else
  1494. {
  1495. const int nRawControlCount = pDmeCombo->GetRawControlCount();
  1496. for ( int i = 0; i < nRawControlCount; ++i )
  1497. {
  1498. pOutStringList->AddToTail( pDmeCombo->GetRawControlName( i ) );
  1499. }
  1500. }
  1501. }
  1502. //-----------------------------------------------------------------------------
  1503. //
  1504. //-----------------------------------------------------------------------------
  1505. void GetControlNames( CDmeMesh *pDmeMesh, CUtlVector< const char * > *pOutStringList )
  1506. {
  1507. if ( !pOutStringList )
  1508. {
  1509. DMXEDIT_WARNING( "No storage passed for result" );
  1510. return;
  1511. }
  1512. pOutStringList->RemoveAll();
  1513. if ( !pDmeMesh )
  1514. {
  1515. DMXEDIT_WARNING( "No mesh specified" );
  1516. return;
  1517. }
  1518. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1519. if ( !pDmeCombo )
  1520. {
  1521. DMXEDIT_WARNING( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1522. return;
  1523. }
  1524. const int nControlCount = pDmeCombo->GetControlCount();
  1525. for ( int i = 0; i < nControlCount; ++i )
  1526. {
  1527. pOutStringList->AddToTail( pDmeCombo->GetControlName( i ) );
  1528. }
  1529. }
  1530. //-----------------------------------------------------------------------------
  1531. //
  1532. //-----------------------------------------------------------------------------
  1533. bool ReorderControls( CDmeMesh *pDmeMesh, CUtlVector< const char * > &controlNames )
  1534. {
  1535. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1536. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1537. if ( !pDmeCombo )
  1538. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1539. // Loop through controls to see if any are already group controls, warn and remove
  1540. CUtlVector< const char * > validControlNames;
  1541. for ( int i = 0; i < controlNames.Count(); ++i )
  1542. {
  1543. ControlIndex_t nControlIndex = pDmeCombo->FindControlIndex( controlNames[ i ] );
  1544. if ( nControlIndex < 0 )
  1545. {
  1546. DMXEDIT_WARNING( "Control \"%s\" doesn't exist, ignoring", controlNames[ i ] );
  1547. continue;
  1548. }
  1549. validControlNames.AddToTail( controlNames[ i ] );
  1550. }
  1551. if ( validControlNames.Count() <= 0 )
  1552. DMXEDIT_WARNING_RETURN_FALSE( "No Valid Controls Specified" );
  1553. for ( int i = 0; i < validControlNames.Count(); ++i )
  1554. {
  1555. pDmeCombo->MoveControlBefore( validControlNames[ i ], pDmeCombo->GetControlName( i ) );
  1556. }
  1557. return true;
  1558. }
  1559. //-----------------------------------------------------------------------------
  1560. //
  1561. //-----------------------------------------------------------------------------
  1562. bool AddDominationRule( CDmeMesh *pDmeMesh, CUtlVector< const char * > &dominators, CUtlVector< const char * > &supressed )
  1563. {
  1564. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1565. CDmeCombinationOperator *pDmeCombo = GetComboOpFromMesh( pDmeMesh );
  1566. if ( !pDmeCombo )
  1567. DMXEDIT_WARNING_RETURN_FALSE( "No DmeCombinationOperator found controlling mesh \"%s\"", pDmeMesh->GetName() );
  1568. pDmeCombo->AddDominationRule(
  1569. dominators.Count(), ( const char ** )dominators.Base(),
  1570. supressed.Count(), ( const char ** )supressed.Base() );
  1571. return true;
  1572. }
  1573. //-----------------------------------------------------------------------------
  1574. //
  1575. //-----------------------------------------------------------------------------
  1576. static const char s_szSelAttrName[] = "__dmxedit_selection";
  1577. //-----------------------------------------------------------------------------
  1578. //
  1579. //-----------------------------------------------------------------------------
  1580. CDmeSingleIndexedComponent *FindOrCreateMeshSelection( CDmeMesh *pDmeMesh, CDmeSingleIndexedComponent *pDmePassedSelection )
  1581. {
  1582. if ( pDmePassedSelection )
  1583. return pDmePassedSelection;
  1584. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  1585. CDmAttribute *pDmeSelAttr = NULL;
  1586. if ( pDmeMesh->HasAttribute( s_szSelAttrName ) )
  1587. {
  1588. pDmeSelAttr = pDmeMesh->GetAttribute( s_szSelAttrName, AT_ELEMENT );
  1589. if ( !pDmeSelAttr )
  1590. {
  1591. DMXEDIT_WARNING( "Attribute %s.%s is of type %s, not AT_ELEMENT, removing", pDmeMesh->GetName(), pDmeSelAttr->GetName(), pDmeSelAttr->GetTypeString() );
  1592. pDmeMesh->RemoveAttribute( s_szSelAttrName );
  1593. pDmeSelAttr = NULL;
  1594. }
  1595. }
  1596. if ( pDmeSelAttr == NULL )
  1597. {
  1598. CDmeSingleIndexedComponent *pTempSelection = CreateElement< CDmeSingleIndexedComponent >( s_szSelAttrName, DMFILEID_INVALID );
  1599. if ( !pTempSelection )
  1600. DMXEDIT_WARNING_RETURN_NULL( "Couldn't create CDmeSingleIndexedComponent %s element", s_szSelAttrName );
  1601. pDmeSelAttr = pDmeMesh->AddAttributeElement< CDmeSingleIndexedComponent >( s_szSelAttrName );
  1602. if ( !pDmeSelAttr )
  1603. DMXEDIT_WARNING_RETURN_NULL( "Couldn't create %s.%s attribute", pDmeMesh->GetName(), s_szSelAttrName );
  1604. pDmeSelAttr->AddFlag( FATTRIB_DONTSAVE );
  1605. pDmeSelAttr->SetValue< CDmeSingleIndexedComponent >( pTempSelection );
  1606. }
  1607. return pDmeSelAttr->GetValueElement< CDmeSingleIndexedComponent >();
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. //
  1611. //-----------------------------------------------------------------------------
  1612. bool CleanupMeshSelection( CDmeMesh *pDmeMesh )
  1613. {
  1614. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1615. pDmeMesh->RemoveAttribute( s_szSelAttrName );
  1616. return true;
  1617. }
  1618. //-----------------------------------------------------------------------------
  1619. // Combines the two selections via the selectOp and puts result into pOriginal
  1620. //-----------------------------------------------------------------------------
  1621. void DoSelectOp( const SelectOp_t &nSelectOp, CDmeSingleIndexedComponent *pDmeOriginalSel, const CDmeSingleIndexedComponent *pDmeNewSel )
  1622. {
  1623. if ( !pDmeOriginalSel || !pDmeNewSel )
  1624. return;
  1625. switch ( nSelectOp )
  1626. {
  1627. case ADD_SELECT_OP:
  1628. pDmeOriginalSel->Add( pDmeNewSel );
  1629. break;
  1630. case SUBTRACT_SELECT_OP:
  1631. pDmeOriginalSel->Subtract( pDmeNewSel );
  1632. break;
  1633. case TOGGLE_SELECT_OP:
  1634. {
  1635. CDmeSingleIndexedComponent *pIntersection = CreateElement< CDmeSingleIndexedComponent >( "__dmxedit_intersection", DMFILEID_INVALID );
  1636. if ( !pIntersection )
  1637. return;
  1638. CDmeSingleIndexedComponent *pNewCopy = CreateElement< CDmeSingleIndexedComponent >( "__dmxedit_newCopy", DMFILEID_INVALID );
  1639. if ( !pNewCopy )
  1640. {
  1641. g_pDataModel->DestroyElement( pIntersection->GetHandle() );
  1642. return;
  1643. }
  1644. pDmeOriginalSel->CopyAttributesTo( pIntersection );
  1645. pIntersection->Intersection( pDmeNewSel );
  1646. pDmeOriginalSel->Subtract( pIntersection );
  1647. pDmeNewSel->CopyAttributesTo( pNewCopy );
  1648. pNewCopy->Subtract( pIntersection );
  1649. pDmeOriginalSel->Add( pNewCopy );
  1650. g_pDataModel->DestroyElement( pIntersection->GetHandle() );
  1651. g_pDataModel->DestroyElement( pNewCopy->GetHandle() );
  1652. }
  1653. break;
  1654. case INTERSECT_SELECT_OP:
  1655. pDmeOriginalSel->Intersection( pDmeNewSel );
  1656. break;
  1657. case REPLACE_SELECT_OP:
  1658. {
  1659. CUtlString originalName = pDmeOriginalSel->GetName();
  1660. pDmeNewSel->CopyAttributesTo( pDmeOriginalSel );
  1661. pDmeOriginalSel->SetName( originalName );
  1662. }
  1663. break;
  1664. }
  1665. }
  1666. //-----------------------------------------------------------------------------
  1667. //
  1668. //-----------------------------------------------------------------------------
  1669. CDmeSingleIndexedComponent *Select(
  1670. CDmeMesh *pDmeMesh,
  1671. SelectOp_t nSelectOp,
  1672. const char *pszSelectString,
  1673. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  1674. {
  1675. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  1676. if ( nSelectOp < 0 || nSelectOp >= INVALID_SELECT_OP )
  1677. return NULL;
  1678. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  1679. if ( !pDmeSelection )
  1680. DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  1681. // Figure out if pszSelectString is one of the keywords, all, none or a delta state
  1682. // NOTE: This means that delta states with a name of all or none are not selectable
  1683. if ( !Q_stricmp( "ALL", pszSelectString ) )
  1684. {
  1685. pDmeMesh->SelectAllVertices( pDmeSelection );
  1686. }
  1687. else if ( !Q_stricmp( "NONE", pszSelectString ) )
  1688. {
  1689. pDmeSelection->Clear();
  1690. }
  1691. else
  1692. {
  1693. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszSelectString );
  1694. if ( !pDmeDelta )
  1695. DMXEDIT_WARNING_RETURN_NULL( "Mesh \"%s\" does not have a delta state named \"%s\" to select", pDmeMesh->GetName(), pszSelectString );
  1696. if ( nSelectOp == REPLACE_SELECT_OP )
  1697. {
  1698. pDmeMesh->SelectVerticesFromDelta( pDmeDelta, pDmeSelection );
  1699. }
  1700. else
  1701. {
  1702. CDmeSingleIndexedComponent *pDmeTmpSelection = CreateElement< CDmeSingleIndexedComponent >( "__dmxedit_tmpSelection", DMFILEID_INVALID );
  1703. if ( !pDmeTmpSelection )
  1704. DMXEDIT_WARNING_RETURN_NULL( "Couldn't create a tmp selection element while selecting delta \"%s\" on mesh \"%s\"", pszSelectString, pDmeMesh->GetName() );
  1705. pDmeMesh->SelectVerticesFromDelta( pDmeDelta, pDmeTmpSelection );
  1706. DoSelectOp( nSelectOp, pDmeSelection, pDmeTmpSelection );
  1707. g_pDataModel->DestroyElement( pDmeTmpSelection->GetHandle() );
  1708. }
  1709. }
  1710. return pDmeSelection;
  1711. }
  1712. //-----------------------------------------------------------------------------
  1713. //
  1714. //-----------------------------------------------------------------------------
  1715. SelectOp_t StringToSelectOp_t( const char *pszSelectOpString )
  1716. {
  1717. if ( StringHasPrefix( pszSelectOpString, "A" ) )
  1718. return ADD_SELECT_OP;
  1719. if ( StringHasPrefix( pszSelectOpString, "S" ) )
  1720. return SUBTRACT_SELECT_OP;
  1721. if ( StringHasPrefix( pszSelectOpString, "T" ) )
  1722. return TOGGLE_SELECT_OP;
  1723. if ( StringHasPrefix( pszSelectOpString, "I" ) )
  1724. return INTERSECT_SELECT_OP;
  1725. if ( StringHasPrefix( pszSelectOpString, "R" ) )
  1726. return REPLACE_SELECT_OP;
  1727. DMXEDIT_WARNING( "Invalid Selection Operation string specified: \"%s\"", pszSelectOpString );
  1728. return INVALID_SELECT_OP;
  1729. }
  1730. //-----------------------------------------------------------------------------
  1731. //
  1732. //-----------------------------------------------------------------------------
  1733. CDmeSingleIndexedComponent *Select(
  1734. CDmeMesh *pDmeMesh,
  1735. const char *pszSelectString,
  1736. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  1737. {
  1738. return Select( pDmeMesh, REPLACE_SELECT_OP, pszSelectString, pDmePassedSelection );
  1739. }
  1740. //-----------------------------------------------------------------------------
  1741. //
  1742. //-----------------------------------------------------------------------------
  1743. CDmeSingleIndexedComponent *Select(
  1744. CDmeMesh *pDmeMesh,
  1745. const char *pszSelectOpString,
  1746. const char *pszSelectString,
  1747. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  1748. {
  1749. return Select( pDmeMesh, StringToSelectOp_t( pszSelectOpString ), pszSelectString, pDmePassedSelection );
  1750. }
  1751. //-----------------------------------------------------------------------------
  1752. //
  1753. // An Efficient Bounding Sphere
  1754. // by Jack Ritter
  1755. // from "Graphics Gems", Academic Press, 1990
  1756. //
  1757. // Routine to calculate tight bounding sphere over
  1758. // a set of points in 3D
  1759. // This contains the routine find_bounding_sphere(),
  1760. // the struct definition, and the globals used for parameters.
  1761. // The abs() of all coordinates must be < BIGNUMBER
  1762. // Code written by Jack Ritter and Lyle Rains.
  1763. //-----------------------------------------------------------------------------
  1764. void FindBoundingSphere( CUtlVector< Vector > &points, Vector &cen, float &fRad )
  1765. {
  1766. if ( points.Count() <= 0 )
  1767. {
  1768. cen.Zero();
  1769. fRad = 0.0f;
  1770. return;
  1771. }
  1772. double dx,dy,dz;
  1773. double rad_sq,xspan,yspan,zspan,maxspan;
  1774. double old_to_p,old_to_p_sq,old_to_new;
  1775. Vector xmin,xmax,ymin,ymax,zmin,zmax,dia1,dia2;
  1776. // DVec cen;
  1777. double rad;
  1778. cen = points[ 0 ];
  1779. fRad = 0.0f;
  1780. xmin.x=ymin.y=zmin.z= FLT_MAX; /* initialize for min/max compare */
  1781. xmax.x=ymax.y=zmax.z= -FLT_MAX;
  1782. for ( int i = 0; i < points.Count(); ++i )
  1783. {
  1784. const Vector &caller_p = points[ i ];
  1785. if (caller_p.x<xmin.x)
  1786. xmin = caller_p; /* New xminimum point */
  1787. if (caller_p.x>xmax.x)
  1788. xmax = caller_p;
  1789. if (caller_p.y<ymin.y)
  1790. ymin = caller_p;
  1791. if (caller_p.y>ymax.y)
  1792. ymax = caller_p;
  1793. if (caller_p.z<zmin.z)
  1794. zmin = caller_p;
  1795. if (caller_p.z>zmax.z)
  1796. zmax = caller_p;
  1797. }
  1798. /* Set xspan = distance between the 2 points xmin & xmax (squared) */
  1799. dx = xmax.x - xmin.x;
  1800. dy = xmax.y - xmin.y;
  1801. dz = xmax.z - xmin.z;
  1802. xspan = dx*dx + dy*dy + dz*dz;
  1803. /* Same for y & z spans */
  1804. dx = ymax.x - ymin.x;
  1805. dy = ymax.y - ymin.y;
  1806. dz = ymax.z - ymin.z;
  1807. yspan = dx*dx + dy*dy + dz*dz;
  1808. dx = zmax.x - zmin.x;
  1809. dy = zmax.y - zmin.y;
  1810. dz = zmax.z - zmin.z;
  1811. zspan = dx*dx + dy*dy + dz*dz;
  1812. /* Set points dia1 & dia2 to the maximally separated pair */
  1813. dia1 = xmin; dia2 = xmax; /* assume xspan biggest */
  1814. maxspan = xspan;
  1815. if (yspan>maxspan)
  1816. {
  1817. maxspan = yspan;
  1818. dia1 = ymin; dia2 = ymax;
  1819. }
  1820. if (zspan>maxspan)
  1821. {
  1822. dia1 = zmin; dia2 = zmax;
  1823. }
  1824. /* dia1,dia2 is a diameter of initial sphere */
  1825. /* calc initial center */
  1826. cen.x = (dia1.x+dia2.x)/2.0;
  1827. cen.y = (dia1.y+dia2.y)/2.0;
  1828. cen.z = (dia1.z+dia2.z)/2.0;
  1829. /* calculate initial radius**2 and radius */
  1830. dx = dia2.x-cen.x; /* x component of radius vector */
  1831. dy = dia2.y-cen.y; /* y component of radius vector */
  1832. dz = dia2.z-cen.z; /* z component of radius vector */
  1833. rad_sq = dx*dx + dy*dy + dz*dz;
  1834. rad = sqrt(rad_sq);
  1835. /* SECOND PASS: increment current sphere */
  1836. for ( int i = 0; i < points.Count(); ++i )
  1837. {
  1838. const Vector &caller_p = points[ i ];
  1839. dx = caller_p.x-cen.x;
  1840. dy = caller_p.y-cen.y;
  1841. dz = caller_p.z-cen.z;
  1842. old_to_p_sq = dx*dx + dy*dy + dz*dz;
  1843. if (old_to_p_sq > rad_sq) /* do r**2 test first */
  1844. { /* this point is outside of current sphere */
  1845. old_to_p = sqrt(old_to_p_sq);
  1846. /* calc radius of new sphere */
  1847. rad = (rad + old_to_p) / 2.0;
  1848. rad_sq = rad*rad; /* for next r**2 compare */
  1849. old_to_new = old_to_p - rad;
  1850. /* calc center of new sphere */
  1851. cen.x = (rad*cen.x + old_to_new*caller_p.x) / old_to_p;
  1852. cen.y = (rad*cen.y + old_to_new*caller_p.y) / old_to_p;
  1853. cen.z = (rad*cen.z + old_to_new*caller_p.z) / old_to_p;
  1854. }
  1855. }
  1856. /*
  1857. fCen.x = cen.x;
  1858. fCen.y = cen.y;
  1859. fCen.z = cen.z;
  1860. */
  1861. fRad = rad;
  1862. }
  1863. //-----------------------------------------------------------------------------
  1864. //
  1865. //-----------------------------------------------------------------------------
  1866. float DeltaRadius( CDmeMesh *pDmeMesh, const char *pszDeltaName )
  1867. {
  1868. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  1869. CDmeVertexData *pBind = pDmeMesh->GetBindBaseState();
  1870. if ( !pBind || !BaseStateSanityCheck( pDmeMesh, pBind, __func__ ) )
  1871. return 0.0f;
  1872. CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  1873. if ( !pDelta || !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) )
  1874. return 0.0f;
  1875. const CUtlVector< Vector > &bindPos = pBind->GetPositionData();
  1876. const CUtlVector< int > &deltaPosIndices = pDelta->GetVertexIndexData( CDmeVertexData::FIELD_POSITION );
  1877. const CUtlVector< Vector > &deltaPos = pDelta->GetPositionData();
  1878. Assert( deltaPosIndices.Count() == deltaPos.Count() );
  1879. CUtlVector< Vector > newPos;
  1880. newPos.SetSize( deltaPos.Count() );
  1881. for ( int i = 0; i < newPos.Count(); ++i )
  1882. {
  1883. newPos[ i ] = bindPos[ deltaPosIndices[ i ] ] + deltaPos[ i ];
  1884. }
  1885. Vector vCenter;
  1886. float flRadius = 0.0;
  1887. FindBoundingSphere( newPos, vCenter, flRadius );
  1888. return flRadius;
  1889. }
  1890. //-----------------------------------------------------------------------------
  1891. //
  1892. //-----------------------------------------------------------------------------
  1893. float SelectionRadius( CDmeMesh *pDmeMesh, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  1894. {
  1895. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1896. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  1897. if ( !pDmeSelection )
  1898. {
  1899. DMXEDIT_WARNING( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  1900. return 0.0f;
  1901. }
  1902. if ( pDmeSelection->Count() == 0 )
  1903. return 0.0f;
  1904. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  1905. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  1906. return 0.0f;
  1907. CUtlVector< int > selection;
  1908. pDmeSelection->GetComponents( selection );
  1909. const CUtlVector< Vector > &pos = pDmeEditState->GetPositionData();
  1910. CUtlVector< Vector > newPos;
  1911. newPos.SetSize( selection.Count() );
  1912. for ( int i = 0; i < newPos.Count(); ++i )
  1913. {
  1914. newPos[ i ] = pos[ selection[ i ] ];
  1915. }
  1916. Vector vCenter;
  1917. float flRadius = 0.0;
  1918. FindBoundingSphere( newPos, vCenter, flRadius );
  1919. return flRadius;
  1920. }
  1921. //-----------------------------------------------------------------------------
  1922. //
  1923. //-----------------------------------------------------------------------------
  1924. bool GrowSelection( CDmeMesh *pDmeMesh, int nSize /* = 1 */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  1925. {
  1926. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1927. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  1928. if ( !pDmeSelection )
  1929. {
  1930. DMXEDIT_WARNING( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  1931. return 0.0f;
  1932. }
  1933. // TODO: Cache the CDmMeshComp object, make it into winged or half edge data structure
  1934. pDmeMesh->GrowSelection( nSize, pDmeSelection, NULL );
  1935. return true;
  1936. }
  1937. //-----------------------------------------------------------------------------
  1938. //
  1939. //-----------------------------------------------------------------------------
  1940. bool ShrinkSelection( CDmeMesh *pDmeMesh, int nSize /* = 1 */, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  1941. {
  1942. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  1943. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  1944. if ( !pDmeSelection )
  1945. {
  1946. DMXEDIT_WARNING( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  1947. return 0.0f;
  1948. }
  1949. // TODO: Cache the CDmMeshComp object, make it into winged or half edge data structure
  1950. pDmeMesh->ShrinkSelection( nSize, pDmeSelection, NULL );
  1951. return true;
  1952. }
  1953. //-----------------------------------------------------------------------------
  1954. //
  1955. //-----------------------------------------------------------------------------
  1956. int StringToDistanceType( const char *pszDistanceTypeString )
  1957. {
  1958. if ( pszDistanceTypeString && ( *pszDistanceTypeString == 'a' || *pszDistanceTypeString == 'A' ) )
  1959. return CDmeMesh::DIST_ABSOLUTE;
  1960. if ( pszDistanceTypeString && ( *pszDistanceTypeString == 'r' || *pszDistanceTypeString == 'R' ) )
  1961. return CDmeMesh::DIST_RELATIVE;
  1962. if ( pszDistanceTypeString && ( *pszDistanceTypeString == 'd' || *pszDistanceTypeString == 'D' ) )
  1963. return CDmeMesh::DIST_DEFAULT;
  1964. DMXEDIT_WARNING( "Invalid Distance Type string specified: \"%s\"", pszDistanceTypeString );
  1965. return -1;
  1966. }
  1967. //-----------------------------------------------------------------------------
  1968. //
  1969. //-----------------------------------------------------------------------------
  1970. bool SetDistanceType( CDmeMesh::Distance_t nDistanceType )
  1971. {
  1972. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  1973. DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
  1974. g_pDmxEditImpl->SetDistanceType( nDistanceType );
  1975. return true;
  1976. }
  1977. //-----------------------------------------------------------------------------
  1978. //
  1979. //-----------------------------------------------------------------------------
  1980. bool SetDistanceType( const char *pszDistanceType )
  1981. {
  1982. const int nDistanceType = StringToDistanceType( pszDistanceType );
  1983. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  1984. return false;
  1985. return SetDistanceType( static_cast< CDmeMesh::Distance_t >( nDistanceType ) );
  1986. }
  1987. //-----------------------------------------------------------------------------
  1988. //
  1989. //-----------------------------------------------------------------------------
  1990. int StringToFalloffType( const char *pszFalloffTypeString )
  1991. {
  1992. if ( !Q_strnicmp( pszFalloffTypeString, "L", 1 ) )
  1993. return CDmeMesh::LINEAR;
  1994. else if ( !Q_strnicmp( pszFalloffTypeString, "ST", 2 ) )
  1995. return CDmeMesh::STRAIGHT;
  1996. else if ( !Q_strnicmp( pszFalloffTypeString, "B", 1 ) )
  1997. return CDmeMesh::BELL;
  1998. else if ( !Q_strnicmp( pszFalloffTypeString, "SM", 2 ) )
  1999. return CDmeMesh::SMOOTH;
  2000. else if ( !Q_strnicmp( pszFalloffTypeString, "SP", 2 ) )
  2001. return CDmeMesh::SPIKE;
  2002. else if ( !Q_strnicmp( pszFalloffTypeString, "D", 1 ) )
  2003. return CDmeMesh::DOME;
  2004. DMXEDIT_WARNING( "Invalid Falloff Type string specified: \"%s\"", pszFalloffTypeString );
  2005. return -1;
  2006. }
  2007. //-----------------------------------------------------------------------------
  2008. //
  2009. //-----------------------------------------------------------------------------
  2010. bool Interp(
  2011. CDmeMesh *pDmeMesh,
  2012. const char *pszDeltaName,
  2013. float flWeight /* = 1.0f */,
  2014. float flFeatherDistance /* = 0.0f */,
  2015. CDmeMesh::Falloff_t nFalloffType /* CDmeMesh::STRAIGHT */,
  2016. CDmeMesh::Distance_t nDistanceType /* = CDmeMesh::DIST_DEFAULT */,
  2017. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2018. {
  2019. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2020. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2021. DMXEDIT_WARNING_RETURN_FALSE( "Unknown falloff type: %d", nFalloffType );
  2022. nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
  2023. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2024. DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
  2025. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  2026. if ( !pDmeSelection )
  2027. DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  2028. CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : NULL;
  2029. bool bRetVal = false;
  2030. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  2031. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  2032. return false;
  2033. if ( !Q_stricmp( "base", pszDeltaName ) || !Q_stricmp( "bind", pszDeltaName ) )
  2034. {
  2035. bRetVal = pDmeMesh->InterpMaskedDelta( NULL, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection );
  2036. }
  2037. else
  2038. {
  2039. CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  2040. if ( !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) )
  2041. return false;
  2042. bRetVal = pDmeMesh->InterpMaskedDelta( pDelta, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection );
  2043. }
  2044. if ( pNewSelection )
  2045. {
  2046. g_pDataModel->DestroyElement( pNewSelection->GetHandle() );
  2047. }
  2048. return bRetVal;
  2049. }
  2050. //-----------------------------------------------------------------------------
  2051. //
  2052. //-----------------------------------------------------------------------------
  2053. bool Interp(
  2054. CDmeMesh *pDmeMesh,
  2055. const char *pszDeltaName,
  2056. float flWeight /* = 1.0f */,
  2057. float flFeatherDistance /* = 0.0f */,
  2058. const char *pszFalloffType /* = "STRAIGHT" */,
  2059. const char *pszDistanceType /* = "DEFAULT" */,
  2060. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2061. {
  2062. const int nFalloffType = StringToFalloffType( pszFalloffType );
  2063. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2064. return false;
  2065. const int nDistanceType = StringToDistanceType( pszDistanceType );
  2066. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2067. return false;
  2068. return Interp( pDmeMesh, pszDeltaName, flWeight, flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), CDmeMesh::Distance_t( nDistanceType ), pDmePassedSelection );
  2069. }
  2070. //-----------------------------------------------------------------------------
  2071. //
  2072. //-----------------------------------------------------------------------------
  2073. bool Add(
  2074. CDmeMesh *pDmeMesh,
  2075. const char *pDeltaName,
  2076. float flWeight /* = 1.0f */,
  2077. float flFeatherDistance /* = 0.0f */,
  2078. CDmeMesh::Falloff_t nFalloffType /* = CDmeMesh::STRAIGHT */,
  2079. CDmeMesh::Distance_t nDistanceType /* = CDmeMesh::DIST_DEFAULT */,
  2080. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2081. {
  2082. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2083. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2084. DMXEDIT_WARNING_RETURN_FALSE( "Unknown falloff type: %d", nFalloffType );
  2085. nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
  2086. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2087. DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
  2088. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  2089. if ( !pDmeSelection )
  2090. DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  2091. CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : NULL;
  2092. bool bRetVal = false;
  2093. CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pDeltaName );
  2094. if ( !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) )
  2095. return false;
  2096. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  2097. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  2098. return false;
  2099. bRetVal = pDmeMesh->AddMaskedDelta( pDelta, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection );
  2100. if ( pNewSelection )
  2101. {
  2102. g_pDataModel->DestroyElement( pNewSelection->GetHandle() );
  2103. }
  2104. return bRetVal;
  2105. }
  2106. //-----------------------------------------------------------------------------
  2107. //
  2108. //-----------------------------------------------------------------------------
  2109. bool Add(
  2110. CDmeMesh *pDmeMesh,
  2111. const char *pszDeltaName,
  2112. float flWeight /* = 1.0f */,
  2113. float flFeatherDistance /* = 0.0f */,
  2114. const char *pszFalloffType /* = "STRAIGHT" */,
  2115. const char *pszDistanceType /* = "DEFAULT" */,
  2116. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2117. {
  2118. const int nFalloffType = StringToFalloffType( pszFalloffType );
  2119. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2120. return false;
  2121. const int nDistanceType = StringToDistanceType( pszDistanceType );
  2122. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2123. return false;
  2124. return Add( pDmeMesh, pszDeltaName, flWeight, flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), CDmeMesh::Distance_t( nDistanceType ), pDmePassedSelection );
  2125. }
  2126. //-----------------------------------------------------------------------------
  2127. //
  2128. //-----------------------------------------------------------------------------
  2129. bool AddCorrected(
  2130. CDmeMesh *pDmeMesh,
  2131. const char *pDeltaName,
  2132. float flWeight /* = 1.0f */,
  2133. float flFeatherDistance /* = 0.0f */,
  2134. CDmeMesh::Falloff_t nFalloffType /* = CDmeMesh::STRAIGHT */,
  2135. CDmeMesh::Distance_t nDistanceType /* = CDmeMesh::DIST_DEFAULT */,
  2136. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2137. {
  2138. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2139. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2140. DMXEDIT_WARNING_RETURN_FALSE( "Unknown falloff type: %d", nFalloffType );
  2141. nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
  2142. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2143. DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
  2144. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  2145. if ( !pDmeSelection )
  2146. DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  2147. CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : NULL;
  2148. bool bRetVal = false;
  2149. CDmeVertexDeltaData *pDelta = pDmeMesh->FindDeltaState( pDeltaName );
  2150. if ( !DeltaStateSanityCheck( pDmeMesh, pDelta, __func__ ) )
  2151. return false;
  2152. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  2153. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  2154. return false;
  2155. bRetVal = pDmeMesh->AddCorrectedMaskedDelta( pDelta, pDmeEditState, flWeight, pNewSelection ? pNewSelection : pDmeSelection );
  2156. if ( pNewSelection )
  2157. {
  2158. g_pDataModel->DestroyElement( pNewSelection->GetHandle() );
  2159. }
  2160. return bRetVal;
  2161. }
  2162. //-----------------------------------------------------------------------------
  2163. //
  2164. //-----------------------------------------------------------------------------
  2165. bool AddCorrected(
  2166. CDmeMesh *pDmeMesh,
  2167. const char *pszDeltaName,
  2168. float flWeight /* = 1.0f */,
  2169. float flFeatherDistance /* = 0.0f */,
  2170. const char *pszFalloffType /* = "STRAIGHT" */,
  2171. const char *pszDistanceType /* = "DEFAULT" */,
  2172. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2173. {
  2174. const int nFalloffType = StringToFalloffType( pszFalloffType );
  2175. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2176. return false;
  2177. const int nDistanceType = StringToDistanceType( pszDistanceType );
  2178. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2179. return false;
  2180. return AddCorrected( pDmeMesh, pszDeltaName, flWeight, flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), CDmeMesh::Distance_t( nDistanceType ), pDmePassedSelection );
  2181. }
  2182. //-----------------------------------------------------------------------------
  2183. //
  2184. //-----------------------------------------------------------------------------
  2185. bool Translate(
  2186. CDmeMesh *pDmeMesh,
  2187. Vector vT,
  2188. float flFeatherDistance,
  2189. CDmeMesh::Falloff_t nFalloffType,
  2190. CDmeMesh::Distance_t nDistanceType,
  2191. CDmeSingleIndexedComponent *pDmePassedSelection )
  2192. {
  2193. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2194. nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
  2195. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2196. DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
  2197. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  2198. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  2199. return false;
  2200. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  2201. if ( !pDmeSelection )
  2202. DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  2203. CDmeSingleIndexedComponent *pTmpSelection = NULL;
  2204. if ( !pDmeSelection || pDmeSelection->Count() == 0 )
  2205. {
  2206. pTmpSelection = CreateElement< CDmeSingleIndexedComponent >( "__selectAll", DMFILEID_INVALID );
  2207. pDmeSelection = pTmpSelection;
  2208. pDmeMesh->SelectAllVertices( pDmeSelection );
  2209. }
  2210. CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : pDmeSelection;
  2211. int nArraySize = 0;
  2212. Vector *pPosArray = NULL;
  2213. const int nPosIndex = pDmeEditState->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  2214. if ( nPosIndex < 0 )
  2215. return false;
  2216. CDmrArray< Vector > posData = pDmeEditState->GetVertexData( nPosIndex );
  2217. const int nPosDataCount = posData.Count();
  2218. if ( nPosDataCount <= 0 )
  2219. return false;
  2220. if ( nArraySize < nPosDataCount || pPosArray == NULL )
  2221. {
  2222. pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) );
  2223. if ( pPosArray )
  2224. {
  2225. nArraySize = nPosDataCount;
  2226. }
  2227. }
  2228. if ( nArraySize < nPosDataCount )
  2229. return false;
  2230. if ( nDistanceType == CDmeMesh::DIST_RELATIVE )
  2231. {
  2232. Vector vCenter;
  2233. float fRadius;
  2234. pDmeMesh->GetBoundingSphere( vCenter, fRadius, pDmeEditState, pDmeSelection );
  2235. vT *= fRadius;
  2236. }
  2237. if ( pNewSelection )
  2238. {
  2239. memcpy( pPosArray, posData.Base(), nPosDataCount * sizeof( Vector ) );
  2240. const int nSelectionCount = pNewSelection->Count();
  2241. int nIndex;
  2242. float fWeight;
  2243. for ( int j = 0; j < nSelectionCount; ++j )
  2244. {
  2245. pNewSelection->GetComponent( j, nIndex, fWeight );
  2246. const Vector &s = posData.Get( nIndex );
  2247. Vector &d = pPosArray[ nIndex ];
  2248. d = s + vT * fWeight;
  2249. }
  2250. }
  2251. else
  2252. {
  2253. for ( int j = 0; j < nPosDataCount; ++j )
  2254. {
  2255. const Vector &s = posData.Get( j );
  2256. Vector &d = pPosArray[ j ];
  2257. d = s + vT;
  2258. }
  2259. }
  2260. posData.SetMultiple( 0, nPosDataCount, pPosArray );
  2261. if ( pTmpSelection )
  2262. {
  2263. g_pDataModel->DestroyElement( pTmpSelection->GetHandle() );
  2264. }
  2265. if ( pNewSelection != pDmeSelection )
  2266. {
  2267. g_pDataModel->DestroyElement( pNewSelection->GetHandle() );
  2268. }
  2269. return true;
  2270. }
  2271. //-----------------------------------------------------------------------------
  2272. //
  2273. //-----------------------------------------------------------------------------
  2274. bool Translate(
  2275. CDmeMesh *pDmeMesh,
  2276. float flTx,
  2277. float flTy,
  2278. float flTz,
  2279. float flFeatherDistance /* = 0.0f */,
  2280. const char *pszFalloffType /* = "STRAIGHT" */,
  2281. const char *pszDistanceType /* = "DEFAULT" */,
  2282. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2283. {
  2284. const int nFalloffType = StringToFalloffType( pszFalloffType );
  2285. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2286. return false;
  2287. const int nDistanceType = StringToDistanceType( pszDistanceType );
  2288. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2289. return false;
  2290. return Translate( pDmeMesh, Vector( flTx, flTy, flTz ), flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), static_cast< CDmeMesh::Distance_t >( nDistanceType ), pDmePassedSelection );
  2291. }
  2292. //-----------------------------------------------------------------------------
  2293. //
  2294. //-----------------------------------------------------------------------------
  2295. bool Rotate(
  2296. CDmeMesh *pDmeMesh,
  2297. Vector vR,
  2298. Vector vO,
  2299. float flFeatherDistance,
  2300. CDmeMesh::Falloff_t nFalloffType,
  2301. CDmeMesh::Distance_t nDistanceType,
  2302. CDmeSingleIndexedComponent *pDmePassedSelection )
  2303. {
  2304. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2305. nDistanceType = nDistanceType == CDmeMesh::DIST_DEFAULT ? g_pDmxEditImpl->GetDistanceType() : nDistanceType;
  2306. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2307. DMXEDIT_WARNING_RETURN_FALSE( "Unknown distance type: %d", nDistanceType );
  2308. CDmeVertexData *pDmeEditState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  2309. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditState, __func__ ) )
  2310. return false;
  2311. CDmeSingleIndexedComponent *pDmeSelection = FindOrCreateMeshSelection( pDmeMesh, pDmePassedSelection );
  2312. if ( !pDmeSelection )
  2313. DMXEDIT_WARNING_RETURN_NULL( "Couldn't find or create selection for mesh %s\n", pDmeMesh->GetName() );
  2314. CDmeSingleIndexedComponent *pTmpSelection = NULL;
  2315. if ( !pDmeSelection || pDmeSelection->Count() == 0 )
  2316. {
  2317. pTmpSelection = CreateElement< CDmeSingleIndexedComponent >( "__selectAll", DMFILEID_INVALID );
  2318. pDmeSelection = pTmpSelection;
  2319. pDmeMesh->SelectAllVertices( pDmeSelection );
  2320. }
  2321. CDmeSingleIndexedComponent *pNewSelection = flFeatherDistance > 0.0f ? pDmeMesh->FeatherSelection( flFeatherDistance, nFalloffType, nDistanceType, pDmeSelection, NULL ) : pDmeSelection;
  2322. int nArraySize = 0;
  2323. Vector *pPosArray = NULL;
  2324. const int nPosIndex = pDmeEditState->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  2325. if ( nPosIndex < 0 )
  2326. return false;
  2327. CDmrArray< Vector > posData = pDmeEditState->GetVertexData( nPosIndex );
  2328. const int nPosDataCount = posData.Count();
  2329. if ( nPosDataCount <= 0 )
  2330. return false;
  2331. if ( nArraySize < nPosDataCount || pPosArray == NULL )
  2332. {
  2333. pPosArray = reinterpret_cast< Vector * >( alloca( nPosDataCount * sizeof( Vector ) ) );
  2334. if ( pPosArray )
  2335. {
  2336. nArraySize = nPosDataCount;
  2337. }
  2338. }
  2339. if ( nArraySize < nPosDataCount )
  2340. return false;
  2341. Vector vCenter;
  2342. float fRadius;
  2343. pDmeMesh->GetBoundingSphere( vCenter, fRadius, pDmeEditState, pDmeSelection );
  2344. if ( nDistanceType == CDmeMesh::DIST_RELATIVE )
  2345. {
  2346. vR *= fRadius;
  2347. }
  2348. VectorAdd( vCenter, vO, vCenter );
  2349. matrix3x4_t rpMat;
  2350. SetIdentityMatrix( rpMat );
  2351. PositionMatrix( vCenter, rpMat );
  2352. matrix3x4_t rpiMat;
  2353. SetIdentityMatrix( rpiMat );
  2354. PositionMatrix( -vCenter, rpiMat );
  2355. matrix3x4_t rMat;
  2356. SetIdentityMatrix( rMat );
  2357. if ( pNewSelection )
  2358. {
  2359. memcpy( pPosArray, posData.Base(), nPosDataCount * sizeof( Vector ) );
  2360. const int nSelectionCount = pNewSelection->Count();
  2361. int nIndex;
  2362. float fWeight;
  2363. for ( int j = 0; j < nSelectionCount; ++j )
  2364. {
  2365. pNewSelection->GetComponent( j, nIndex, fWeight );
  2366. const Vector &s = posData.Get( nIndex );
  2367. Vector &d = pPosArray[ nIndex ];
  2368. AngleMatrix( RadianEuler( DEG2RAD( vR.x * fWeight ), DEG2RAD( vR.y * fWeight ), DEG2RAD( vR.z * fWeight ) ), rMat );
  2369. ConcatTransforms( rpMat, rMat, rMat );
  2370. ConcatTransforms( rMat, rpiMat, rMat );
  2371. VectorTransform( s, rMat, d );
  2372. }
  2373. }
  2374. else
  2375. {
  2376. AngleMatrix( RadianEuler( DEG2RAD( vR.x ), DEG2RAD( vR.y ), DEG2RAD( vR.z ) ), rMat );
  2377. ConcatTransforms( rpMat, rMat, rMat );
  2378. ConcatTransforms( rMat, rpiMat, rMat );
  2379. for ( int j = 0; j < nPosDataCount; ++j )
  2380. {
  2381. const Vector &s = posData.Get( j );
  2382. Vector &d = pPosArray[ j ];
  2383. VectorTransform( s, rMat, d );
  2384. }
  2385. }
  2386. posData.SetMultiple( 0, nPosDataCount, pPosArray );
  2387. if ( pTmpSelection )
  2388. {
  2389. g_pDataModel->DestroyElement( pTmpSelection->GetHandle() );
  2390. }
  2391. if ( pNewSelection != pDmeSelection )
  2392. {
  2393. g_pDataModel->DestroyElement( pNewSelection->GetHandle() );
  2394. }
  2395. return true;
  2396. }
  2397. //-----------------------------------------------------------------------------
  2398. //
  2399. //-----------------------------------------------------------------------------
  2400. bool Rotate(
  2401. CDmeMesh *pDmeMesh,
  2402. float flRx,
  2403. float flRy,
  2404. float flRz,
  2405. float flOx /* = 0.0f */,
  2406. float flOy /* = 0.0f */,
  2407. float flOz /* = 0.0f */,
  2408. float flFeatherDistance /* = 0.0f */,
  2409. const char *pszFalloffType /* = "STRAIGHT" */,
  2410. const char *pszDistanceType /* = "DEFAULT" */,
  2411. CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2412. {
  2413. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2414. const int nFalloffType = StringToFalloffType( pszFalloffType );
  2415. if ( nFalloffType < 0 || nFalloffType > CDmeMesh::DOME )
  2416. return false;
  2417. const int nDistanceType = StringToDistanceType( pszDistanceType );
  2418. if ( nDistanceType < 0 || nDistanceType > CDmeMesh::DIST_DEFAULT )
  2419. return false;
  2420. return Rotate( pDmeMesh, Vector( flRx, flRy, flRz ), Vector( flOx, flOy, flOz ), flFeatherDistance, static_cast< CDmeMesh::Falloff_t >( nFalloffType ), static_cast< CDmeMesh::Distance_t >( nDistanceType ), pDmePassedSelection );
  2421. }
  2422. //-----------------------------------------------------------------------------
  2423. //
  2424. //-----------------------------------------------------------------------------
  2425. bool RemapMaterial( CDmeMesh *pDmeMesh, int nMaterialIndex, const char *pszNewMaterialName )
  2426. {
  2427. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2428. return CDmMeshUtils::RemapMaterial( pDmeMesh, nMaterialIndex, pszNewMaterialName );
  2429. }
  2430. //-----------------------------------------------------------------------------
  2431. // Adds the src mesh into the dst mesh
  2432. //-----------------------------------------------------------------------------
  2433. bool Combine( CDmeMesh *pDmeMesh, CDmeMesh *pDmeSrcMesh, const char *pszDstSkinningBoneName /* = NULL */ )
  2434. {
  2435. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2436. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeSrcMesh );
  2437. int nSkinningJointIndex = -1;
  2438. if ( pszDstSkinningBoneName )
  2439. {
  2440. // Find the DmeModel of the destination mesh scene
  2441. CDmeDag *pDmeDag = FindReferringElement< CDmeDag >( pDmeMesh, "shape" );
  2442. while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) )
  2443. {
  2444. pDmeDag = pDmeDag->GetParent();
  2445. }
  2446. CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag );
  2447. if ( pDmeModel )
  2448. {
  2449. CDmeDag *pDmeJoint = pDmeModel->GetJoint( pszDstSkinningBoneName );
  2450. if ( pDmeJoint )
  2451. {
  2452. nSkinningJointIndex = pDmeModel->GetJointIndex( pDmeJoint );
  2453. }
  2454. }
  2455. else
  2456. {
  2457. DMXEDIT_WARNING( "Couldn't find the DmeModel associated with mesh \"%s\"", pDmeMesh->GetName() );
  2458. }
  2459. if ( nSkinningJointIndex < 0 )
  2460. {
  2461. DMXEDIT_WARNING( "Couldn't find bone named \"%s\", for skinning", pszDstSkinningBoneName );
  2462. }
  2463. }
  2464. const bool bRetVal = CDmMeshUtils::Merge( pDmeSrcMesh, pDmeMesh, nSkinningJointIndex );
  2465. FixupBaseStates( pDmeMesh );
  2466. return bRetVal;
  2467. }
  2468. //-----------------------------------------------------------------------------
  2469. //
  2470. //-----------------------------------------------------------------------------
  2471. bool Merge( CDmElement *pDmDstRoot, CDmeMesh *pSrcMesh )
  2472. {
  2473. DMXEDIT_MESH_WARNING_RETURN_FALSE( pSrcMesh );
  2474. if ( !pDmDstRoot )
  2475. DMXEDIT_WARNING_RETURN_FALSE( "No element passed" );
  2476. CDmMeshComp srcComp( pSrcMesh );
  2477. CUtlVector< CUtlVector< CDmMeshComp::CEdge * > > srcBorderEdgesList;
  2478. if ( srcComp.GetBorderEdges( srcBorderEdgesList ) == 0 )
  2479. return false;
  2480. CDmeMesh *pDmeSocketMesh = CastElement< CDmeMesh >( pDmDstRoot );
  2481. if ( pDmeSocketMesh )
  2482. {
  2483. const int nEdgeListIndex = CDmMeshUtils::FindMergeSocket( srcBorderEdgesList, pDmeSocketMesh );
  2484. if ( nEdgeListIndex < 0 )
  2485. DMXEDIT_WARNING_RETURN_FALSE( "No merge socket found on specified mesh: \"%s\"\n", pDmeSocketMesh->GetName() );
  2486. CleanupMeshEditBaseState( pSrcMesh );
  2487. CleanupMeshSelection( pSrcMesh );
  2488. bool bRetVal = CDmMeshUtils::Merge( srcComp, srcBorderEdgesList[ nEdgeListIndex ], pDmeSocketMesh );
  2489. FixupBaseStates( pDmeSocketMesh );
  2490. pDmeSocketMesh->Resolve();
  2491. return bRetVal;
  2492. }
  2493. CDmeDag *pDmeDag = CastElement< CDmeDag >( pDmDstRoot );
  2494. if ( !pDmeDag )
  2495. {
  2496. pDmeDag = pDmDstRoot->GetValueElement< CDmeDag >( "model" );
  2497. }
  2498. if ( !pDmeDag )
  2499. DMXEDIT_WARNING_RETURN_FALSE( "Invalid DmElement passed, DmeMesh, DmeDag or DmElement with \"model\" attribute required" );
  2500. Vector vSrcCenter;
  2501. float flSrcRadius;
  2502. pSrcMesh->GetBoundingSphere( vSrcCenter, flSrcRadius );
  2503. Vector vDstCenter;
  2504. float flDstRadius;
  2505. float flSqDist = FLT_MAX;
  2506. int nEdgeListIndex = -1;
  2507. CUtlStack< CDmeDag * > traverseStack;
  2508. traverseStack.Push( pDmeDag );
  2509. while ( traverseStack.Count() )
  2510. {
  2511. traverseStack.Pop( pDmeDag );
  2512. if ( !pDmeDag )
  2513. continue;
  2514. for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i )
  2515. {
  2516. traverseStack.Push( pDmeDag->GetChild( i ) );
  2517. }
  2518. CDmeMesh *pDmeTmpMesh = CastElement< CDmeMesh >( pDmeDag->GetShape() );
  2519. if ( !pDmeTmpMesh )
  2520. continue;
  2521. const int nTmpEdgeListIndex = CDmMeshUtils::FindMergeSocket( srcBorderEdgesList, pDmeTmpMesh );
  2522. if ( nTmpEdgeListIndex < 0 )
  2523. continue;
  2524. pDmeTmpMesh->GetBoundingSphere( vDstCenter, flDstRadius );
  2525. flDstRadius = vDstCenter.DistToSqr( vSrcCenter );
  2526. if ( flDstRadius < flSqDist )
  2527. {
  2528. flSqDist = flDstRadius;
  2529. pDmeSocketMesh = pDmeTmpMesh;
  2530. nEdgeListIndex = nTmpEdgeListIndex;
  2531. }
  2532. }
  2533. if ( pDmeSocketMesh && nEdgeListIndex >= 0 )
  2534. {
  2535. CleanupMeshEditBaseState( pSrcMesh );
  2536. CleanupMeshSelection( pSrcMesh );
  2537. bool bRetVal = CDmMeshUtils::Merge( srcComp, srcBorderEdgesList[ nEdgeListIndex ], pDmeSocketMesh );
  2538. FixupBaseStates( pDmeSocketMesh );
  2539. pDmeSocketMesh->Resolve();
  2540. return bRetVal;
  2541. }
  2542. DMXEDIT_WARNING_RETURN_FALSE( "No merge socket found in specified scene, i.e. a Set of border edges on the source model that are found on the merge model" );
  2543. }
  2544. bool ApplyMaskToDelta( CDmeVertexDeltaData *pTheDelta, CDmeSingleIndexedComponent *pDmePassedSelection )
  2545. {
  2546. CDmrArray< int > positionIndices = pTheDelta->GetAttribute( "positionsIndices" );
  2547. CDmrArray< Vector > positions = pTheDelta->GetAttribute( "positions" );
  2548. CDmrArray< float > weightData = pDmePassedSelection->GetAttribute( "weights" );
  2549. int numVerts = positionIndices.Count();
  2550. for ( int n=0; n < numVerts; n++ )
  2551. {
  2552. int idx = positionIndices[ n ];
  2553. float fWeight = weightData[ idx ];
  2554. const Vector vNewPos = positions[ n ] * fWeight;
  2555. positions.Set( n, vNewPos );
  2556. }
  2557. //do we have normals to deal with?
  2558. CDmAttribute *pNormalsIndicesAttr = pTheDelta->GetAttribute( "normalsIndices" );
  2559. if ( pNormalsIndicesAttr )
  2560. {
  2561. CDmrArray< int > normalsIndices = pNormalsIndicesAttr;
  2562. CDmrArray< Vector > normals = pTheDelta->GetAttribute( "normals" );
  2563. for ( int n=0; n < numVerts; n++ )
  2564. {
  2565. int idx = normalsIndices[ n ];
  2566. float fWeight = weightData[ idx ];
  2567. Vector vNewNormal = normals[ n ] * fWeight;
  2568. vNewNormal.NormalizeInPlace();
  2569. normals.Set( n, Vector( vNewNormal ) );
  2570. }
  2571. }
  2572. return pTheDelta == NULL;
  2573. }
  2574. bool CreateDeltaFromMesh( CDmeMesh *pBaseMesh, CDmeMesh *pMeshToUseAsDelta, const char *pDeltaName, CDmeSingleIndexedComponent *pDmePassedSelection /* = NULL */ )
  2575. {
  2576. DMXEDIT_MESH_WARNING_RETURN_FALSE( pBaseMesh );
  2577. DMXEDIT_MESH_WARNING_RETURN_FALSE( pMeshToUseAsDelta );
  2578. CDmeVertexDeltaData *pRet = pBaseMesh->ModifyOrCreateDeltaStateFromBaseState( pDeltaName, pMeshToUseAsDelta->GetCurrentBaseState(), true );
  2579. if ( pDmePassedSelection )
  2580. {
  2581. ApplyMaskToDelta( pRet, pDmePassedSelection );
  2582. }
  2583. return pRet == NULL;
  2584. }
  2585. //-----------------------------------------------------------------------------
  2586. //
  2587. //-----------------------------------------------------------------------------
  2588. CDmeMesh *ComputeConvexHull3D( CDmeMesh *pDmeMesh, float flCoplanarEpsilon /* = ONE_32ND_UNIT */ )
  2589. {
  2590. CMesh mesh;
  2591. if ( ConvertMeshFromDMX( &mesh, pDmeMesh ) )
  2592. {
  2593. CMesh convexHullMesh;
  2594. ConvexHull3D( &convexHullMesh, mesh, flCoplanarEpsilon );
  2595. CUtlString meshName( pDmeMesh->GetName() );
  2596. meshName += "_convexHull";
  2597. CDmeMesh *pDmeConvexHullMesh = CreateElement< CDmeMesh >( meshName.Get(), pDmeMesh->GetFileId() );
  2598. if ( pDmeConvexHullMesh )
  2599. {
  2600. ConvertMeshToDMX( pDmeConvexHullMesh, &convexHullMesh, true );
  2601. return pDmeConvexHullMesh;
  2602. }
  2603. }
  2604. return NULL;
  2605. }
  2606. //-----------------------------------------------------------------------------
  2607. //
  2608. //-----------------------------------------------------------------------------
  2609. CDmeCombinationOperator *FindOrCreateComboOp( CDmeMesh *pDmeMesh )
  2610. {
  2611. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  2612. CDmeCombinationOperator *pDmeComboOp = GetComboOpFromMesh( pDmeMesh );
  2613. if ( pDmeComboOp )
  2614. return pDmeComboOp;
  2615. // Find the DmeModel of the destination mesh scene
  2616. CDmeDag *pDmeDag = FindReferringElement< CDmeDag >( pDmeMesh, "shape" );
  2617. while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) )
  2618. {
  2619. pDmeDag = pDmeDag->GetParent();
  2620. }
  2621. CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag );
  2622. if ( !pDmeModel )
  2623. DMXEDIT_ERROR_RETURN_NULL( "Couldn't Find The DmeModel for the mesh: \"%s\"", pDmeMesh->GetName() );
  2624. // Find the root node for the DmeModel (by "model" or "skeleton" attribute):
  2625. CDmElement *pDmRoot = FindReferringElement< CDmElement >( pDmeModel, "model" );
  2626. if ( !pDmRoot )
  2627. {
  2628. pDmRoot = FindReferringElement< CDmElement >( pDmeModel, "skeleton" );
  2629. }
  2630. if ( !pDmRoot )
  2631. DMXEDIT_ERROR_RETURN_NULL( "Couldn't Find The root Dme node referring to the DmeModel \"%s\" for the mesh: \"%s\"", pDmeModel->GetName(), pDmeMesh->GetName() );
  2632. pDmeComboOp = pDmRoot->GetValueElement< CDmeCombinationOperator >( "combinationOperator" );
  2633. if ( !pDmeComboOp )
  2634. {
  2635. CUtlString comboOpName = pDmeMesh->GetName();
  2636. comboOpName += "_comboOp";
  2637. pDmeComboOp = CreateElement< CDmeCombinationOperator >( comboOpName.Get(), pDmeMesh->GetFileId() );
  2638. if ( !pDmeComboOp )
  2639. DMXEDIT_WARNING_RETURN_NULL( "Couldn't create DmeCombinationOperator for \"%s\"", pDmeMesh->GetName() );
  2640. pDmRoot->SetValue( "combinationOperator", pDmeComboOp );
  2641. }
  2642. pDmeComboOp->AddTarget( pDmeMesh );
  2643. return pDmeComboOp;
  2644. }
  2645. //-----------------------------------------------------------------------------
  2646. //
  2647. //-----------------------------------------------------------------------------
  2648. bool SetMeshFromSkeleton( CDmeMesh *pDmeMesh )
  2649. {
  2650. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2651. CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState();
  2652. if ( !BaseStateSanityCheck( pDmeMesh, pDmeBindBaseState, __func__ ) )
  2653. return false;
  2654. CDmeVertexData *pDmeEditBaseState = FindOrCreateMeshEditBaseState( pDmeMesh, __func__ );
  2655. if ( !BaseStateSanityCheck( pDmeMesh, pDmeEditBaseState, __func__ ) )
  2656. return false;
  2657. if ( !pDmeBindBaseState->HasSkinningData() )
  2658. DMXEDIT_ERROR_RETURN_FALSE( "No skinning data on specified mesh: \"%s\"", pDmeMesh->GetName() );
  2659. const FieldIndex_t nBindPosField = pDmeBindBaseState->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  2660. if ( nBindPosField < 0 )
  2661. DMXEDIT_ERROR_RETURN_FALSE( "Cannot find position data on mesh \"%s\" base state", pDmeMesh->GetName() );
  2662. const FieldIndex_t nEditPosField = pDmeEditBaseState->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  2663. if ( nEditPosField < 0 )
  2664. DMXEDIT_ERROR_RETURN_FALSE( "Cannot find position data on mesh \"%s\" edit state", pDmeMesh->GetName() );
  2665. CDmeDag *pDmeDag = pDmeMesh->GetParent();
  2666. while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) )
  2667. {
  2668. pDmeDag = pDmeDag->GetParent();
  2669. }
  2670. CDmeModel *pDmeModel = CastElement< CDmeModel >( pDmeDag );
  2671. if ( !pDmeModel )
  2672. DMXEDIT_ERROR_RETURN_NULL( "Couldn't Find The DmeModel for the mesh: \"%s\"", pDmeMesh->GetName() );
  2673. const CUtlVector< Vector > &posData = CDmrArrayConst< Vector >( pDmeBindBaseState->GetVertexData( nBindPosField ) ).Get();
  2674. const int nVertexCount = posData.Count();
  2675. const CUtlVector< Vector > &editPosData = CDmrArrayConst< Vector >( pDmeEditBaseState->GetVertexData( nEditPosField ) ).Get();
  2676. const int nEditVertexCount = editPosData.Count();
  2677. Assert( nVertexCount == nEditVertexCount );
  2678. if ( nVertexCount != nEditVertexCount )
  2679. DMXEDIT_ERROR_RETURN_FALSE( "Base Pos Count: %d Versus Edit Pos Count: %d\n", nVertexCount, nEditVertexCount );
  2680. Vector *pVertices = reinterpret_cast< Vector * >( alloca( nVertexCount * sizeof( Vector ) ) );
  2681. matrix3x4_t shapeToWorld;
  2682. SetIdentityMatrix( shapeToWorld );
  2683. CDmeModel::s_ModelStack.Push( pDmeModel );
  2684. matrix3x4_t *pPoseToWorld = CDmeModel::SetupModelRenderState( shapeToWorld, pDmeBindBaseState->HasSkinningData(), true );
  2685. CDmeModel::s_ModelStack.Pop();
  2686. CDmeMeshRenderInfo renderInfo( pDmeBindBaseState );
  2687. Assert( renderInfo.HasPositionData() );
  2688. for ( int i = 0; i < nVertexCount; ++i )
  2689. {
  2690. renderInfo.ComputePosition( i, pPoseToWorld, static_cast< Vector * >( NULL ), pVertices );
  2691. }
  2692. pDmeEditBaseState->SetVertexData( nEditPosField, 0, nVertexCount, AT_VECTOR3, pVertices );
  2693. CDmeModel::CleanupModelRenderState();
  2694. return false;
  2695. }
  2696. //-----------------------------------------------------------------------------
  2697. // Sets wrinkle deltas from the specified selection
  2698. //-----------------------------------------------------------------------------
  2699. void SetWrinkleWeight( CDmeVertexData *pDmeBindBaseState, CDmeVertexDeltaData *pDmeDelta, CDmeSingleIndexedComponent *pDmeSelection, float flScale )
  2700. {
  2701. FieldIndex_t nPosIndex = pDmeDelta->FindFieldIndex( CDmeVertexDeltaData::FIELD_POSITION );
  2702. if ( nPosIndex < 0 )
  2703. return;
  2704. FieldIndex_t nBaseTexCoordIndex = pDmeBindBaseState->FindFieldIndex( CDmeVertexData::FIELD_TEXCOORD );
  2705. if ( nBaseTexCoordIndex < 0 )
  2706. return;
  2707. FieldIndex_t nWrinkleIndex = pDmeDelta->FindFieldIndex( CDmeVertexDeltaData::FIELD_WRINKLE );
  2708. if ( nWrinkleIndex < 0 )
  2709. {
  2710. nWrinkleIndex = pDmeDelta->CreateField( CDmeVertexDeltaData::FIELD_WRINKLE );
  2711. }
  2712. const CUtlVector<int> &baseTexCoordIndices = pDmeBindBaseState->GetVertexIndexData( nBaseTexCoordIndex );
  2713. CDmrArrayConst<Vector2D> texData( pDmeBindBaseState->GetVertexData( nBaseTexCoordIndex ) );
  2714. const int nBaseTexCoordCount = texData.Count();
  2715. const int nBufSize = ( ( nBaseTexCoordCount + 7 ) >> 3 );
  2716. unsigned char *pUsedBits = (unsigned char*)_alloca( nBufSize );
  2717. memset( pUsedBits, 0, nBufSize );
  2718. // Construct a temporary array of wrinkle values for the entire mesh
  2719. // Same size as the number of texture coordinate values
  2720. // 0 means no wrinkle data, so initialize to 0
  2721. CUtlVector< float > wrinkleData;
  2722. wrinkleData.SetCount( nBaseTexCoordCount );
  2723. memset( wrinkleData.Base(), 0, wrinkleData.Count() * sizeof( float ) );
  2724. // Copy the old wrinkle data if any exists
  2725. CDmAttribute *pWrinkleDeltaAttr = pDmeDelta->GetVertexData( nWrinkleIndex );
  2726. if ( pWrinkleDeltaAttr )
  2727. {
  2728. CDmrArrayConst< float > wrinkleDeltaArray( pWrinkleDeltaAttr );
  2729. if ( wrinkleDeltaArray.Count() )
  2730. {
  2731. const CUtlVector< int > &wrinkleDeltaIndices = pDmeDelta->GetVertexIndexData( nWrinkleIndex );
  2732. Assert( wrinkleDeltaIndices.Count() == wrinkleDeltaArray.Count() );
  2733. int nWrinkleIndex;
  2734. for ( int i = 0; i < wrinkleDeltaIndices.Count(); ++i )
  2735. {
  2736. nWrinkleIndex = wrinkleDeltaIndices[ i ];
  2737. wrinkleData[ nWrinkleIndex ] = wrinkleDeltaArray[ i ];
  2738. }
  2739. }
  2740. }
  2741. // Write new wrinkle values overtop of existing wrinkle values
  2742. int nComponentIndex;
  2743. float flWeight;
  2744. for ( int i = 0; i < pDmeSelection->Count(); ++i )
  2745. {
  2746. if ( !pDmeSelection->GetComponent( i, nComponentIndex, flWeight ) )
  2747. continue;
  2748. flWeight *= flScale;
  2749. // NOTE: This will produce bad behavior in cases where two positions share the
  2750. // same texcoord, which shouldn't theoretically happen.
  2751. const CUtlVector< int > &baseVerts = pDmeBindBaseState->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_POSITION, nComponentIndex );
  2752. for ( int j = 0; j < baseVerts.Count(); ++j )
  2753. {
  2754. // See if we have a delta for this texcoord...
  2755. const int nTexCoordIndex = baseTexCoordIndices[ baseVerts[j] ];
  2756. if ( pUsedBits[ nTexCoordIndex >> 3 ] & ( 1 << ( nTexCoordIndex & 0x7 ) ) )
  2757. continue;
  2758. pUsedBits[ nTexCoordIndex >> 3 ] |= 1 << ( nTexCoordIndex & 0x7 );
  2759. wrinkleData[ nTexCoordIndex ] = flWeight;
  2760. }
  2761. }
  2762. // Remove previous wrinkle data (if any exists)
  2763. pDmeDelta->RemoveAllVertexData( nWrinkleIndex );
  2764. // Write new non-zero wrinkles
  2765. for ( int i = 0; i < wrinkleData.Count(); ++i )
  2766. {
  2767. if ( fabs( wrinkleData[ i ] ) < 0.00001 )
  2768. continue;
  2769. int nDeltaIndex = pDmeDelta->AddVertexData( nWrinkleIndex, 1 );
  2770. pDmeDelta->SetVertexIndices( nWrinkleIndex, nDeltaIndex, 1, &i );
  2771. pDmeDelta->SetVertexData( nWrinkleIndex, nDeltaIndex, 1, AT_FLOAT, &wrinkleData[ i ] );
  2772. }
  2773. }
  2774. //-----------------------------------------------------------------------------
  2775. //
  2776. //-----------------------------------------------------------------------------
  2777. bool SetWrinkleWeight( CDmeMesh *pDmeMesh, const char *pszDeltaName, CDmeSingleIndexedComponent *pDmeSelection, float flScale /* = 1.0 */ )
  2778. {
  2779. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  2780. CDmeVertexData *pDmeBindBaseState = pDmeMesh->GetBindBaseState();
  2781. if ( !BaseStateSanityCheck( pDmeMesh, pDmeBindBaseState, __func__ ) )
  2782. return false;
  2783. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->FindDeltaState( pszDeltaName );
  2784. if ( !pDmeDelta )
  2785. DMXEDIT_WARNING_RETURN_FALSE( "Mesh \"%s\" has no delta named \"%s\"", pDmeMesh->GetName(), pszDeltaName );
  2786. if ( !pDmeSelection )
  2787. DMXEDIT_WARNING_RETURN_FALSE( "No selection specified\n" );
  2788. SetWrinkleWeight( pDmeBindBaseState, pDmeDelta, pDmeSelection, flScale );
  2789. return true;
  2790. }
  2791. //-----------------------------------------------------------------------------
  2792. //
  2793. //-----------------------------------------------------------------------------
  2794. float WrapDeform_ComputeOptimalDistSqr( const CUtlVector< Vector > &iPos, const CUtlVector< Vector > &tPos )
  2795. {
  2796. float flRetDistSqr = 0.0f;
  2797. float flMaxDistSqr;
  2798. float flTmpDistSqr;
  2799. for ( int i = 0; i < tPos.Count(); ++i )
  2800. {
  2801. flMaxDistSqr = 0.0f;
  2802. const Vector &vt = tPos[i];
  2803. for ( int j = 0; j < iPos.Count(); ++j )
  2804. {
  2805. flTmpDistSqr = vt.DistToSqr( iPos[j] );
  2806. if ( flTmpDistSqr > flMaxDistSqr )
  2807. {
  2808. flMaxDistSqr = flTmpDistSqr;
  2809. }
  2810. }
  2811. if ( flMaxDistSqr > flRetDistSqr )
  2812. {
  2813. flRetDistSqr = flMaxDistSqr;
  2814. }
  2815. }
  2816. return flRetDistSqr;
  2817. }
  2818. //-----------------------------------------------------------------------------
  2819. //
  2820. //-----------------------------------------------------------------------------
  2821. class CWrapVert
  2822. {
  2823. public:
  2824. CWrapVert()
  2825. : m_flTotalDist( 0.0f )
  2826. {}
  2827. void AddInfluenceVert( int nInfluenceVert, float flDistSqr )
  2828. {
  2829. const float flDist = sqrtf( flDistSqr );
  2830. if ( Count() < s_nMaxInfluence )
  2831. {
  2832. WrapVert_s &wrapVert = m_wrapVerts[ m_wrapVerts.AddToTail() ];
  2833. wrapVert.m_nInfluenceIndex = nInfluenceVert;
  2834. wrapVert.m_flDist = sqrtf( flDistSqr );
  2835. m_flTotalDist += wrapVert.m_flDist;
  2836. }
  2837. else
  2838. {
  2839. WrapVert_s &wrapVert = m_wrapVerts.Tail();
  2840. if ( flDist >= wrapVert.m_flDist )
  2841. return;
  2842. wrapVert.m_nInfluenceIndex = nInfluenceVert;
  2843. wrapVert.m_flDist = sqrtf( flDistSqr );
  2844. m_flTotalDist = 0.0f;
  2845. for ( int i = 0; i < m_wrapVerts.Count(); ++i )
  2846. {
  2847. m_flTotalDist += m_wrapVerts[i].m_flDist;
  2848. }
  2849. }
  2850. qsort( m_wrapVerts.Base(), m_wrapVerts.Count(), sizeof( WrapVert_s ), SortWrapVertFunc );
  2851. }
  2852. int Count() const
  2853. {
  2854. return m_wrapVerts.Count();
  2855. }
  2856. bool GetInfluenceIndexAndWeight( int &nInfluenceIndex, float &flWeight, int nLocalIndex ) const
  2857. {
  2858. const int nCount = Count();
  2859. if ( nCount <= 0 || nLocalIndex >= nCount || nLocalIndex < 0 || m_flTotalDist <= 0.0f )
  2860. return false;
  2861. const WrapVert_s &wrapVert = m_wrapVerts[nLocalIndex];
  2862. nInfluenceIndex = wrapVert.m_nInfluenceIndex;
  2863. if ( nCount == 1 )
  2864. {
  2865. flWeight = 1.0f;
  2866. }
  2867. else
  2868. {
  2869. float flTotal = 0.0f;
  2870. for ( int i = 0; i < m_wrapVerts.Count(); ++i )
  2871. {
  2872. flTotal += ( m_flTotalDist - m_wrapVerts[i].m_flDist );
  2873. }
  2874. flWeight = ( m_flTotalDist - wrapVert.m_flDist ) / flTotal;
  2875. }
  2876. return true;
  2877. }
  2878. protected:
  2879. static int SortWrapVertFunc( const void *pLhs, const void *pRhs )
  2880. {
  2881. const WrapVert_s &lWrapVert = *reinterpret_cast< const WrapVert_s * >( pLhs );
  2882. const WrapVert_s &rWrapVert = *reinterpret_cast< const WrapVert_s * >( pRhs );
  2883. if ( lWrapVert.m_flDist < rWrapVert.m_flDist )
  2884. return -1;
  2885. if ( lWrapVert.m_flDist > rWrapVert.m_flDist )
  2886. return 1;
  2887. return 0;
  2888. }
  2889. struct WrapVert_s
  2890. {
  2891. int m_nInfluenceIndex;
  2892. float m_flDist;
  2893. };
  2894. CUtlVector< WrapVert_s > m_wrapVerts;
  2895. float m_flTotalDist;
  2896. static int s_nMaxInfluence;
  2897. };
  2898. //-----------------------------------------------------------------------------
  2899. //
  2900. //-----------------------------------------------------------------------------
  2901. int CWrapVert::s_nMaxInfluence = 10;
  2902. //-----------------------------------------------------------------------------
  2903. //
  2904. //-----------------------------------------------------------------------------
  2905. void WrapDeform_ComputeInfluence( CUtlVector< CWrapVert > &influenceIndices, const CUtlVector< Vector > &iPos, const CUtlVector< Vector > &tPos, float flMaxDistSqr )
  2906. {
  2907. influenceIndices.SetCount( tPos.Count() );
  2908. float flTmpDistSqr;
  2909. for ( int i = 0; i < tPos.Count(); ++i )
  2910. {
  2911. const Vector &vt = tPos[i];
  2912. CWrapVert &wrapVert = influenceIndices[i];
  2913. for ( int j = 0; j < iPos.Count(); ++j )
  2914. {
  2915. flTmpDistSqr = vt.DistToSqr( iPos[j] );
  2916. if ( flTmpDistSqr <= flMaxDistSqr )
  2917. {
  2918. wrapVert.AddInfluenceVert( j, flTmpDistSqr );
  2919. }
  2920. }
  2921. }
  2922. }
  2923. //-----------------------------------------------------------------------------
  2924. //
  2925. //-----------------------------------------------------------------------------
  2926. void WrapDeform_ComputeWrap(
  2927. CUtlVector< Vector > &tPosCurr,
  2928. const CUtlVector< CWrapVert > &influenceIndices,
  2929. const CUtlVector< Vector > &iPosBind,
  2930. const CUtlVector< Vector > &iPosCurr,
  2931. const CUtlVector< Vector > &tPosBind )
  2932. {
  2933. Assert( tPosBind.Count() == influenceIndices.Count() );
  2934. tPosCurr = tPosBind; // Copy as a default and to set size
  2935. int nInfluenceIndex;
  2936. float flInfluenceWeight;
  2937. Vector vTemp0;
  2938. Vector vTemp1;
  2939. for ( int i = 0; i < tPosCurr.Count(); ++i )
  2940. {
  2941. Vector &vt = tPosCurr[i];
  2942. const CWrapVert &wrapVert = influenceIndices[i];
  2943. for ( int j = 0; j < wrapVert.Count(); ++j )
  2944. {
  2945. wrapVert.GetInfluenceIndexAndWeight( nInfluenceIndex, flInfluenceWeight, j );
  2946. VectorSubtract( iPosCurr[nInfluenceIndex], iPosBind[nInfluenceIndex], vTemp0 );
  2947. VectorScale( vTemp0, flInfluenceWeight, vTemp1 );
  2948. VectorAdd( vTemp1, vt, vt );
  2949. }
  2950. }
  2951. }
  2952. //-----------------------------------------------------------------------------
  2953. //
  2954. //-----------------------------------------------------------------------------
  2955. bool WrapDeform( CDmeMesh *pDmeInfluenceMesh, CDmeMesh *pDmeTargetMesh )
  2956. {
  2957. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeInfluenceMesh );
  2958. CDmeVertexData *pIBind = pDmeInfluenceMesh->GetBindBaseState();
  2959. if ( !BaseStateSanityCheck( pDmeInfluenceMesh, pIBind, __func__ ) )
  2960. return false;
  2961. pIBind->Resolve();
  2962. CDmeVertexData *pICurrent = pDmeInfluenceMesh->GetCurrentBaseState();
  2963. if ( !BaseStateSanityCheck( pDmeInfluenceMesh, pICurrent, __func__ ) )
  2964. return false;
  2965. pICurrent->Resolve();
  2966. if ( pIBind == pICurrent )
  2967. DMXEDIT_ERROR_RETURN_FALSE( "Bind base state must be different from current base state on influence mesh in order for Wrap to do anything" );
  2968. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeTargetMesh );
  2969. CDmeVertexData *pTBind = pDmeTargetMesh->GetBindBaseState();
  2970. if ( !BaseStateSanityCheck( pDmeTargetMesh, pTBind, __func__ ) )
  2971. return false;
  2972. pTBind->Resolve();
  2973. CDmeVertexData *pTEdit = FindOrCreateMeshEditBaseState( pDmeTargetMesh, __func__ );
  2974. if ( !BaseStateSanityCheck( pDmeTargetMesh, pTEdit, __func__ ) )
  2975. return false;
  2976. const CUtlVector< Vector > &iPosBind = pIBind->GetPositionData();
  2977. const CUtlVector< Vector > &tPosBind = pTBind->GetPositionData();
  2978. const float flMinDistSqr = WrapDeform_ComputeOptimalDistSqr( iPosBind, tPosBind ) + 4.0 + FLT_EPSILON;
  2979. CUtlVector< CWrapVert > influenceIndices;
  2980. WrapDeform_ComputeInfluence( influenceIndices, iPosBind, tPosBind, flMinDistSqr );
  2981. const CUtlVector< Vector > &iPosCurr = pICurrent->GetPositionData();
  2982. CUtlVector< Vector > tPosCurr;
  2983. WrapDeform_ComputeWrap( tPosCurr, influenceIndices, iPosBind, iPosCurr, tPosBind );
  2984. const int nEditPosField = pTEdit->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  2985. pTEdit->RemoveAllVertexData( nEditPosField );
  2986. pTEdit->AddVertexData( nEditPosField, tPosCurr.Count() );
  2987. pTEdit->SetVertexData( nEditPosField, 0, tPosCurr.Count(), AT_VECTOR3, tPosCurr.Base() );
  2988. return true;
  2989. }
  2990. //-----------------------------------------------------------------------------
  2991. //
  2992. //-----------------------------------------------------------------------------
  2993. Vector ComputeMean( const CUtlVector< Vector > &pointList )
  2994. {
  2995. Vector vMean;
  2996. vMean.Zero();
  2997. const int nPointCount = pointList.Count();
  2998. for ( int i = 0; i < nPointCount; ++i )
  2999. {
  3000. VectorAdd( vMean, pointList[i], vMean );
  3001. }
  3002. VectorDivide( vMean, static_cast< float >( nPointCount ), vMean );
  3003. return vMean;
  3004. }
  3005. //-----------------------------------------------------------------------------
  3006. //
  3007. //-----------------------------------------------------------------------------
  3008. matrix3x4_t ComputeCovariantMatrix( const CUtlVector< Vector > &pointList, const Vector &vMean )
  3009. {
  3010. matrix3x4_t mCovariant;
  3011. SetIdentityMatrix( mCovariant );
  3012. const int nPointCount = pointList.Count();
  3013. if ( nPointCount <= 0 )
  3014. return mCovariant;
  3015. CUtlVector< Vector > skewedPointList;
  3016. skewedPointList = pointList;
  3017. Assert( nPointCount == skewedPointList.Count() );
  3018. for ( int i = 0; i < nPointCount; ++i )
  3019. {
  3020. VectorSubtract( skewedPointList[i], vMean, skewedPointList[i] );
  3021. }
  3022. float flCovariance;
  3023. for ( int i = 0; i < 3; ++i )
  3024. {
  3025. for ( int j = 0; j < 3; ++j )
  3026. {
  3027. flCovariance = 0.0f;
  3028. for ( int k = 0; k < nPointCount; ++k )
  3029. {
  3030. flCovariance += skewedPointList[k][i] * skewedPointList[k][j];
  3031. }
  3032. mCovariant[i][j] = flCovariance / static_cast< float >( nPointCount );
  3033. }
  3034. }
  3035. return mCovariant;
  3036. }
  3037. //-----------------------------------------------------------------------------
  3038. //
  3039. //-----------------------------------------------------------------------------
  3040. matrix3x4_t ComputeCovariantMatrix( const CUtlVector< Vector > &pointList )
  3041. {
  3042. const Vector vMean = ComputeMean( pointList );
  3043. return ComputeCovariantMatrix( pointList, vMean );
  3044. }
  3045. //-----------------------------------------------------------------------------
  3046. //
  3047. //-----------------------------------------------------------------------------
  3048. bool MergeMeshAndSkeleton( CDmeMesh *pDstMesh, CDmeMesh *pSrcMesh )
  3049. {
  3050. return CDmMeshUtils::MergeMeshAndSkeleton( pDstMesh, pSrcMesh );
  3051. }
  3052. //-----------------------------------------------------------------------------
  3053. //
  3054. //-----------------------------------------------------------------------------
  3055. bool FlexLocalVar( CDmeMesh *pDmeMesh, const char *pszFlexRuleLocalVar )
  3056. {
  3057. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  3058. CDmeFlexRules *pDmeFlexRules = FindOrAddDmeFlexRules( pDmeMesh );
  3059. if ( !pDmeFlexRules )
  3060. DMXEDIT_WARNING_RETURN_FALSE( "DmeFlexRules could not be created for mesh \"%s\"", pDmeMesh->GetName() );
  3061. CDmeFlexRuleLocalVar *pDmeFlexRuleLocalVar = CreateElement< CDmeFlexRuleLocalVar >( pszFlexRuleLocalVar, pDmeMesh->GetFileId() );
  3062. pDmeFlexRules->AddFlexRule( pDmeFlexRuleLocalVar );
  3063. return true;
  3064. }
  3065. //-----------------------------------------------------------------------------
  3066. //
  3067. //-----------------------------------------------------------------------------
  3068. bool FlexRuleExpression( CDmeMesh *pDmeMesh, const char *pszExpression )
  3069. {
  3070. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  3071. CDmeFlexRules *pDmeFlexRules = FindOrAddDmeFlexRules( pDmeMesh );
  3072. if ( !pDmeFlexRules )
  3073. DMXEDIT_WARNING_RETURN_FALSE( "DmeFlexRules could not be created for mesh \"%s\"", pDmeMesh->GetName() );
  3074. char szBuf[ 512 ];
  3075. if ( sscanf( pszExpression, "%512s =", szBuf ) != 1 )
  3076. DMXEDIT_WARNING_RETURN_FALSE( "Improperly formatted expression: \"%s\"", pszExpression );
  3077. CDmeFlexRuleExpression *pDmeFlexRuleExpression = CreateElement< CDmeFlexRuleExpression >( szBuf, pDmeMesh->GetFileId() );
  3078. pDmeFlexRuleExpression->SetExpression( pszExpression );
  3079. pDmeFlexRules->AddFlexRule( pDmeFlexRuleExpression );
  3080. return true;
  3081. }
  3082. //-----------------------------------------------------------------------------
  3083. // Returns the CDmeFlexRules ultimately controlling the specified
  3084. // DmeMesh by searched backwards on elements referring to "targets" or "target"
  3085. // Returns NULL if not found
  3086. //-----------------------------------------------------------------------------
  3087. static CDmeFlexRules *GetFlexRulesForMesh( CDmeMesh *pDmeMesh )
  3088. {
  3089. if ( !pDmeMesh )
  3090. return NULL;
  3091. CUtlRBTree< CDmElement * > visited( CDefOps< CDmElement * >::LessFunc );
  3092. visited.Insert( pDmeMesh );
  3093. const CUtlSymbolLarge sTargets = g_pDataModel->GetSymbol( "targets" );
  3094. const CUtlSymbolLarge sTarget = g_pDataModel->GetSymbol( "target" );
  3095. CDmElement *pDmThisElement = pDmeMesh;
  3096. CDmElement *pDmNextElement = NULL;
  3097. while ( pDmThisElement )
  3098. {
  3099. pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTargets );
  3100. if ( !pDmNextElement )
  3101. {
  3102. pDmNextElement = FindReferringElement< CDmElement >( pDmThisElement, sTarget );
  3103. }
  3104. if ( !pDmNextElement )
  3105. break;
  3106. pDmThisElement = pDmNextElement;
  3107. if ( CastElement< CDmeFlexRules >( pDmThisElement ) )
  3108. return CastElement< CDmeFlexRules >( pDmThisElement );
  3109. if ( visited.IsValidIndex( visited.Find( pDmThisElement ) ) )
  3110. break;
  3111. visited.Insert( pDmThisElement );
  3112. }
  3113. return NULL;
  3114. }
  3115. //-----------------------------------------------------------------------------
  3116. //
  3117. //-----------------------------------------------------------------------------
  3118. CDmeFlexRules *FindOrAddDmeFlexRules( CDmeMesh *pDmeMesh )
  3119. {
  3120. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  3121. CDmeFlexRules *pDmeFlexRules = GetFlexRulesForMesh( pDmeMesh );
  3122. if ( pDmeFlexRules )
  3123. return pDmeFlexRules;
  3124. CDmeCombinationOperator *pDmeComboOp = FindOrCreateComboOp( pDmeMesh );
  3125. if ( !pDmeComboOp )
  3126. DMXEDIT_WARNING_RETURN_NULL( "DmeCombinationOperator could not be created for mesh \"%s\"", pDmeMesh->GetName() );
  3127. CUtlString flexRulesName = pDmeMesh->GetName();
  3128. flexRulesName += "_flexRules";
  3129. pDmeFlexRules = CreateElement< CDmeFlexRules >( flexRulesName.Get(), pDmeMesh->GetFileId() );
  3130. if ( !pDmeFlexRules )
  3131. DMXEDIT_WARNING_RETURN_NULL( "DmeFlexRules could not be created for mesh \"%s\"", pDmeMesh->GetName() );
  3132. pDmeComboOp->RemoveAllTargets();
  3133. pDmeComboOp->AddTarget( pDmeFlexRules );
  3134. pDmeFlexRules->SetTarget( pDmeMesh );
  3135. return pDmeFlexRules;
  3136. }
  3137. //-----------------------------------------------------------------------------
  3138. //
  3139. //-----------------------------------------------------------------------------
  3140. ControlIndex_t FlexControl( CDmeMesh *pDmeMesh, const char *pszName, float flMin /* = 0.0f */, float flMax /* = 1.0f */ )
  3141. {
  3142. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  3143. CDmeCombinationOperator *pDmeComboOp = FindOrCreateComboOp( pDmeMesh );
  3144. if ( !pDmeComboOp )
  3145. DMXEDIT_WARNING_RETURN_FALSE( "DmeCombinationOperator could not be created for mesh \"%s\"", pDmeMesh->GetName() );
  3146. const ControlIndex_t nIndex = pDmeComboOp->FindOrCreateControl( pszName, false, true );
  3147. if ( nIndex >= 0 && ( flMin != 0.0f || flMax != 1.0f ) )
  3148. {
  3149. SetControlMinMax( pDmeMesh, nIndex, flMin, flMax );
  3150. }
  3151. return nIndex;
  3152. }
  3153. //-----------------------------------------------------------------------------
  3154. //
  3155. //-----------------------------------------------------------------------------
  3156. bool SetControlMinMax( CDmeMesh *pDmeMesh, ControlIndex_t nControlIndex, float flMin, float flMax )
  3157. {
  3158. DMXEDIT_MESH_WARNING_RETURN_FALSE( pDmeMesh );
  3159. CDmeCombinationOperator *pDmeComboOp = FindOrCreateComboOp( pDmeMesh );
  3160. if ( !pDmeComboOp )
  3161. DMXEDIT_WARNING_RETURN_FALSE( "DmeCombinationOperator could not be created for mesh \"%s\"", pDmeMesh->GetName() );
  3162. CDmAttribute *pControlsAttr = pDmeComboOp->GetAttribute( "controls", AT_ELEMENT_ARRAY );
  3163. if ( !pControlsAttr )
  3164. DMXEDIT_WARNING_RETURN_FALSE( "No 'controls' attribute on ComboOp \"%s\"", pDmeComboOp->GetName() );
  3165. CDmrElementArray< CDmElement > controlsAttr( pControlsAttr );
  3166. if ( nControlIndex < controlsAttr.Count() )
  3167. {
  3168. CDmElement *pControlElement = controlsAttr[ nControlIndex ];
  3169. if ( pControlElement )
  3170. {
  3171. pControlElement->SetValue( "flexMin", flMin );
  3172. pControlElement->SetValue( "flexMax", flMax );
  3173. }
  3174. }
  3175. return true;
  3176. }
  3177. //-----------------------------------------------------------------------------
  3178. //
  3179. //-----------------------------------------------------------------------------
  3180. static CDmeModel *GetDmeModel( CDmeMesh *pDmeMesh )
  3181. {
  3182. if ( !pDmeMesh )
  3183. return NULL;
  3184. // Find the DmeModel of the destination mesh scene
  3185. CDmeDag *pDmeDag = pDmeMesh->GetParent();
  3186. while ( pDmeDag && !pDmeDag->IsA( CDmeModel::GetStaticTypeSymbol() ) )
  3187. {
  3188. pDmeDag = pDmeDag->GetParent();
  3189. }
  3190. return CastElement< CDmeModel >( pDmeDag );
  3191. }
  3192. //-----------------------------------------------------------------------------
  3193. //
  3194. //-----------------------------------------------------------------------------
  3195. CDmAttribute *GetQcModelElementsAttr( CDmeMesh *pDmeMesh )
  3196. {
  3197. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  3198. CDmeModel *pDmeModel = GetDmeModel( pDmeMesh );
  3199. if ( !pDmeModel )
  3200. DMXEDIT_WARNING_RETURN_NULL( "Can't Find DmeModel for mesh \"%s\"", pDmeMesh->GetName() );
  3201. CDmAttribute *pDmAttr = pDmeModel->GetAttribute( "qcModelElements" );
  3202. if ( !pDmAttr )
  3203. {
  3204. pDmAttr = pDmeModel->AddAttribute( "qcModelElements", AT_ELEMENT_ARRAY );
  3205. }
  3206. if ( !pDmAttr || pDmAttr->GetType() != AT_ELEMENT_ARRAY )
  3207. DMXEDIT_WARNING_RETURN_NULL( "Can't find or create %s.qcModelElements element array attribute", pDmeModel->GetName() );
  3208. return pDmAttr;
  3209. }
  3210. //-----------------------------------------------------------------------------
  3211. //
  3212. //-----------------------------------------------------------------------------
  3213. bool Eyeball(
  3214. CDmeMesh *pDmeMesh,
  3215. const char *pszName,
  3216. const char *pszBoneName,
  3217. const Vector &vPosition,
  3218. const char *pszMaterialName,
  3219. const float flDiameter,
  3220. const float flAngle,
  3221. const float flPupilScale )
  3222. {
  3223. CDmAttribute *pDmAttr = GetQcModelElementsAttr( pDmeMesh );
  3224. if ( !pDmAttr )
  3225. return false;
  3226. CDmrElementArray<> qcModelElements( pDmAttr );
  3227. CDmeEyeball *pDmeEyeball = CreateElement< CDmeEyeball >( pszName, pDmAttr->GetOwner()->GetFileId() );
  3228. if ( !pDmeEyeball )
  3229. DMXEDIT_WARNING_RETURN_FALSE( "Can't create DmeEyeball element" );
  3230. pDmeEyeball->m_sParentBoneName.Set( pszBoneName );
  3231. pDmeEyeball->m_vPosition.Set( vPosition );
  3232. pDmeEyeball->m_sMaterialName.Set( pszMaterialName );
  3233. pDmeEyeball->m_flRadius.Set( flDiameter / 2.0f );
  3234. pDmeEyeball->m_flYawAngle.Set( flAngle );
  3235. pDmeEyeball->m_flIrisScale.Set( flPupilScale );
  3236. qcModelElements.AddToTail( pDmeEyeball );
  3237. return true;
  3238. }
  3239. //-----------------------------------------------------------------------------
  3240. //
  3241. //-----------------------------------------------------------------------------
  3242. bool Eyelid(
  3243. CDmeMesh *pDmeMesh,
  3244. bool bUpper,
  3245. const char *pszLowererFlex,
  3246. float flLowererHeight,
  3247. const char *pszNeutralFlex,
  3248. float flNeutralHeight,
  3249. const char *pszRaiserFlex,
  3250. float flRaiserHeight,
  3251. const char *pszRightMaterialName,
  3252. const char *pszLeftMaterialName )
  3253. {
  3254. CDmAttribute *pDmAttr = GetQcModelElementsAttr( pDmeMesh );
  3255. if ( !pDmAttr )
  3256. return false;
  3257. CDmrElementArray<> qcModelElements( pDmAttr );
  3258. CDmeEyelid *pDmeEyelid = CreateElement< CDmeEyelid >( bUpper ? "upper" : "lower", pDmAttr->GetOwner()->GetFileId() );
  3259. if ( !pDmeEyelid )
  3260. DMXEDIT_WARNING_RETURN_FALSE( "Can't create DmeEyelid element" );
  3261. pDmeEyelid->m_bUpper.Set( bUpper );
  3262. pDmeEyelid->m_sLowererFlex.Set( pszLowererFlex );
  3263. pDmeEyelid->m_flLowererHeight.Set( flLowererHeight );
  3264. pDmeEyelid->m_sNeutralFlex.Set( pszNeutralFlex );
  3265. pDmeEyelid->m_flNeutralHeight.Set( flNeutralHeight );
  3266. pDmeEyelid->m_sRaiserFlex.Set( pszRaiserFlex );
  3267. pDmeEyelid->m_flRaiserHeight.Set( flRaiserHeight );
  3268. pDmeEyelid->m_sRightEyeballName.Set( pszRightMaterialName );
  3269. pDmeEyelid->m_sLeftEyeballName.Set( pszLeftMaterialName );
  3270. qcModelElements.AddToTail( pDmeEyelid );
  3271. return true;
  3272. }
  3273. //-----------------------------------------------------------------------------
  3274. //
  3275. //-----------------------------------------------------------------------------
  3276. bool Mouth(
  3277. CDmeMesh *pDmeMesh,
  3278. int nMouthNumber,
  3279. const char *pszFlexControllerName,
  3280. const char *pszBoneName,
  3281. const Vector &vForward )
  3282. {
  3283. CDmAttribute *pDmAttr = GetQcModelElementsAttr( pDmeMesh );
  3284. if ( !pDmAttr )
  3285. return false;
  3286. CDmrElementArray<> qcModelElements( pDmAttr );
  3287. CUtlString sMouthName( "mouth" );
  3288. sMouthName += nMouthNumber;
  3289. CDmeMouth *pDmeMouth = CreateElement< CDmeMouth >( sMouthName.Get(), pDmAttr->GetOwner()->GetFileId() );
  3290. if ( !pDmeMouth )
  3291. DMXEDIT_WARNING_RETURN_FALSE( "Can't create DmeMouth element" );
  3292. pDmeMouth->m_nMouthNumber.Set( nMouthNumber );
  3293. pDmeMouth->m_sFlexControllerName.Set( pszFlexControllerName );
  3294. pDmeMouth->m_sBoneName.Set( pszBoneName );
  3295. pDmeMouth->m_vForward.Set( vForward );
  3296. qcModelElements.AddToTail( pDmeMouth );
  3297. return true;
  3298. }
  3299. //-----------------------------------------------------------------------------
  3300. //
  3301. //-----------------------------------------------------------------------------
  3302. bool ClearFlexRules( CDmeMesh *pDmeMesh )
  3303. {
  3304. DMXEDIT_MESH_WARNING_RETURN_NULL( pDmeMesh );
  3305. CDmeFlexRules *pDmeFlexRules = GetFlexRulesForMesh( pDmeMesh );
  3306. if ( pDmeFlexRules )
  3307. {
  3308. pDmeFlexRules->RemoveAllRules();
  3309. }
  3310. CDmeCombinationOperator *pDmeComboOp = GetComboOpFromMesh( pDmeMesh );
  3311. if ( pDmeComboOp )
  3312. {
  3313. pDmeComboOp->RemoveAllControls();
  3314. }
  3315. return true;
  3316. }