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

436 lines
9.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "MAX.H"
  9. #include "DECOMP.H"
  10. #include "STDMAT.H"
  11. #include "ANIMTBL.H"
  12. #include "istdplug.h"
  13. #include "phyexp.h"
  14. #include "BonesPro.h"
  15. #include "vweightexprc.h"
  16. #include "vweightexp.h"
  17. #include "vweightimp.h"
  18. // Save for use with dialogs
  19. static HINSTANCE hInstance;
  20. // We just need one of these to hand off to 3DSMAX.
  21. static VWeightExportClassDesc VWeightExportCD;
  22. static VWeightImportClassDesc VWeightImportCD;
  23. //===================================================================
  24. // Required plug-in export functions
  25. //
  26. BOOL WINAPI DllMain( HINSTANCE hinstDLL, ULONG fdwReason, LPVOID lpvReserved)
  27. {
  28. static int fFirstTimeHere = TRUE;
  29. if (fFirstTimeHere)
  30. {
  31. fFirstTimeHere = FALSE;
  32. hInstance = hinstDLL;
  33. }
  34. return TRUE;
  35. }
  36. EXPORT_THIS int LibNumberClasses(void)
  37. {
  38. return 2;
  39. }
  40. EXPORT_THIS ClassDesc *LibClassDesc(int iWhichClass)
  41. {
  42. switch(iWhichClass)
  43. {
  44. case 0: return &VWeightExportCD;
  45. case 1: return &VWeightImportCD;
  46. default: return 0;
  47. }
  48. }
  49. EXPORT_THIS const TCHAR *LibDescription()
  50. {
  51. return _T("Valve VVW Plug-in.");
  52. }
  53. EXPORT_THIS ULONG LibVersion()
  54. {
  55. return VERSION_3DSMAX;
  56. }
  57. //===================================================================
  58. // Utility functions
  59. //
  60. int AssertFailedFunc(char *sz)
  61. {
  62. MessageBox(GetActiveWindow(), sz, "Assert failure", MB_OK);
  63. int Set_Your_Breakpoint_Here = 1;
  64. return 1;
  65. }
  66. //=================================================================
  67. // Methods for CollectModelTEP
  68. //
  69. Modifier *FindPhysiqueModifier (INode *nodePtr)
  70. {
  71. // Get object from node. Abort if no object.
  72. Object *ObjectPtr = nodePtr->GetObjectRef();
  73. if (!ObjectPtr) return NULL;
  74. // Is derived object ?
  75. if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID)
  76. {
  77. // Yes -> Cast.
  78. IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr);
  79. // Iterate over all entries of the modifier stack.
  80. int ModStackIndex = 0;
  81. while (ModStackIndex < DerivedObjectPtr->NumModifiers())
  82. {
  83. // Get current modifier.
  84. Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
  85. // Is this Physique ?
  86. if (ModifierPtr->ClassID() == Class_ID( PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B) )
  87. {
  88. // Yes -> Exit.
  89. return ModifierPtr;
  90. }
  91. // Next modifier stack entry.
  92. ModStackIndex++;
  93. }
  94. }
  95. // Not found.
  96. return NULL;
  97. }
  98. Modifier *FindBonesProModifier (INode *nodePtr)
  99. {
  100. // Get object from node. Abort if no object.
  101. Object *ObjectPtr = nodePtr->GetObjectRef();
  102. if (!ObjectPtr) return NULL;
  103. // Is derived object ?
  104. if (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID)
  105. {
  106. // Yes -> Cast.
  107. IDerivedObject *DerivedObjectPtr = static_cast<IDerivedObject*>(ObjectPtr);
  108. // Iterate over all entries of the modifier stack.
  109. int ModStackIndex = 0;
  110. while (ModStackIndex < DerivedObjectPtr->NumModifiers())
  111. {
  112. // Get current modifier.
  113. Modifier *ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
  114. // Is this Bones Pro OSM?
  115. if (ModifierPtr->ClassID() == BP_CLASS_ID_OSM )
  116. {
  117. // Yes -> Exit.
  118. return ModifierPtr;
  119. }
  120. // Is this Bones Pro WSM?
  121. if (ModifierPtr->ClassID() == BP_CLASS_ID_WSM )
  122. {
  123. // Yes -> Exit.
  124. return ModifierPtr;
  125. }
  126. // Next modifier stack entry.
  127. ModStackIndex++;
  128. }
  129. }
  130. // Not found.
  131. return NULL;
  132. }
  133. //========================================================================
  134. // Utility functions for getting/setting the personal "node index" property.
  135. // NOTE: I'm storing a string-property because I hit a 3DSMax bug in v1.2 when I
  136. // NOTE: tried using an integer property.
  137. // FURTHER NOTE: those properties seem to change randomly sometimes, so I'm
  138. // implementing my own.
  139. typedef struct
  140. {
  141. char szNodeName[MAX_NAME_CHARS];
  142. } NAMEMAP;
  143. const int MAX_NAMEMAP = 512;
  144. static NAMEMAP g_NameMap[MAX_NAMEMAP];
  145. static int g_cNameMap = 0;
  146. void ResetINodeMap( void )
  147. {
  148. g_cNameMap = 0;
  149. }
  150. int BuildINodeMap(INode *pnode)
  151. {
  152. if (!FUndesirableNode(pnode))
  153. {
  154. AddINode(pnode);
  155. }
  156. // For each child of this node, we recurse into ourselves
  157. // until no more children are found.
  158. for (int c = 0; c < pnode->NumberOfChildren(); c++)
  159. {
  160. BuildINodeMap(pnode->GetChildNode(c));
  161. }
  162. return g_cNameMap;
  163. }
  164. int GetIndexOfNodeName(char *szNodeName, BOOL fAssertPropExists)
  165. {
  166. for (int inm = 0; inm < g_cNameMap; inm++)
  167. {
  168. if (FStrEq(g_NameMap[inm].szNodeName, szNodeName))
  169. {
  170. return inm;
  171. }
  172. }
  173. return -1;
  174. }
  175. int GetIndexOfINode( INode *pnode, BOOL fAssertPropExists )
  176. {
  177. return GetIndexOfNodeName( pnode->GetName(), fAssertPropExists );
  178. }
  179. void AddINode( INode *pnode )
  180. {
  181. TSTR strNodeName(pnode->GetName());
  182. for (int inm = 0; inm < g_cNameMap; inm++)
  183. {
  184. if (FStrEq(g_NameMap[inm].szNodeName, (char*)strNodeName))
  185. {
  186. return;
  187. }
  188. }
  189. ASSERT_MBOX(g_cNameMap < MAX_NAMEMAP, "NAMEMAP is full");
  190. strcpy(g_NameMap[g_cNameMap++].szNodeName, (char*)strNodeName);
  191. }
  192. //=============================================================
  193. // Returns TRUE if a node should be ignored during tree traversal.
  194. //
  195. BOOL FUndesirableNode(INode *pnode)
  196. {
  197. // Get Node's underlying object, and object class name
  198. Object *pobj = pnode->GetObjectRef();
  199. if (!pobj)
  200. return TRUE;
  201. // Don't care about lights, dummies, and cameras
  202. if (pobj->SuperClassID() == CAMERA_CLASS_ID)
  203. return TRUE;
  204. if (pobj->SuperClassID() == LIGHT_CLASS_ID)
  205. return TRUE;
  206. if (!strstr(pnode->GetName(), "Bip01" ))
  207. return TRUE;
  208. return FALSE;
  209. // Actually, if it's not selected, pretend it doesn't exist!
  210. //if (!pnode->Selected())
  211. // return TRUE;
  212. //return FALSE;
  213. }
  214. //=============================================================
  215. // Returns TRUE if a node has been marked as skippable
  216. //
  217. BOOL FNodeMarkedToSkip(INode *pnode)
  218. {
  219. return (::GetIndexOfINode(pnode) == UNDESIRABLE_NODE_MARKER);
  220. }
  221. //=============================================================
  222. // gets a weighted value for the current system of nodes
  223. //
  224. void GetUnifiedCoord( Point3 &p1, MaxVertWeight pweight[], MaxNode maxNode[], int cMaxNode )
  225. {
  226. float flMin = 1E20f;
  227. for (int iNode = 0; iNode < cMaxNode; iNode++)
  228. {
  229. float f = (p1 - maxNode[iNode].mat3NodeTM.GetTrans()).LengthSquared();
  230. if (f > 0 && f < flMin)
  231. flMin = f;
  232. pweight[iNode].flDist = f;
  233. }
  234. float flTotal = 0;
  235. float flInvMin = 1.0 / flMin;
  236. for (iNode = 0; iNode < cMaxNode; iNode++)
  237. {
  238. if (pweight[iNode].flDist > 0)
  239. {
  240. pweight[iNode].flDist = flInvMin / pweight[iNode].flDist;
  241. }
  242. else
  243. {
  244. pweight[iNode].flDist = 10.0;
  245. }
  246. flTotal += pweight[iNode].flDist;
  247. }
  248. float flInvTotal;
  249. if (flTotal > 0)
  250. {
  251. flInvTotal = 1.0 / flTotal;
  252. }
  253. else
  254. {
  255. flInvTotal = 1.0;
  256. }
  257. for (iNode = 0; iNode < cMaxNode; iNode++)
  258. {
  259. pweight[iNode].flDist = pweight[iNode].flDist * flInvTotal;
  260. // fprintf(m_pfile, "%8.4f ", pweight[iNode].flDist );
  261. }
  262. }
  263. int GetBoneWeights( IPhyContextExport *mcExport, int iVertex, MaxVertWeight *pweight)
  264. {
  265. float fTotal = 0;
  266. IPhyVertexExport *vtxExport = mcExport->GetVertexInterface(iVertex);
  267. if (vtxExport)
  268. {
  269. if (vtxExport->GetVertexType() & BLENDED_TYPE)
  270. {
  271. IPhyBlendedRigidVertex *pBlend = ((IPhyBlendedRigidVertex *)vtxExport);
  272. for (int i = 0; i < pBlend->GetNumberNodes(); i++)
  273. {
  274. int index = GetIndexOfINode( pBlend->GetNode( i ) );
  275. if (index >= 0)
  276. {
  277. pweight[index].flWeight = pBlend->GetWeight( i );
  278. fTotal += pweight[index].flWeight;
  279. }
  280. }
  281. }
  282. else
  283. {
  284. INode *Bone = ((IPhyRigidVertex *)vtxExport)->GetNode();
  285. int index = GetIndexOfINode(Bone);
  286. if (index >= 0)
  287. {
  288. pweight[index].flWeight = 100.0;
  289. }
  290. }
  291. mcExport->ReleaseVertexInterface(vtxExport);
  292. }
  293. return (fTotal > 0);
  294. }
  295. int GetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight)
  296. {
  297. int iTotal = 0;
  298. int nb = bonesProMod->SetProperty( BP_PROPID_GET_N_BONES, NULL );
  299. for ( int iBone = 0; iBone < nb; iBone++)
  300. {
  301. BonesPro_BoneVertex bv;
  302. bv.bindex = iBone;
  303. bv.vindex = iVertex;
  304. bonesProMod->SetProperty( BP_PROPID_GET_BV, &bv );
  305. if (bv.included > 0 && bv.forced_weight >= 0)
  306. {
  307. BonesPro_Bone bone;
  308. bone.t = BP_TIME_ATTACHED;
  309. bone.index = iBone;
  310. bonesProMod->SetProperty( BP_PROPID_GET_BONE_STAT, &bone );
  311. if (bone.node != NULL)
  312. {
  313. int index = GetIndexOfINode( bone.node );
  314. if (index >= 0)
  315. {
  316. pweight[index].flWeight = bv.forced_weight;
  317. iTotal++;
  318. }
  319. }
  320. }
  321. }
  322. return iTotal;
  323. }
  324. void SetBoneWeights( Modifier * bonesProMod, int iVertex, MaxVertWeight *pweight)
  325. {
  326. int nb = bonesProMod->SetProperty( BP_PROPID_GET_N_BONES, NULL );
  327. // FILE *fp = fopen("bone2.txt", "w");
  328. for ( int iBone = 0; iBone < nb; iBone++)
  329. {
  330. BonesPro_Bone bone;
  331. bone.t = BP_TIME_ATTACHED;
  332. bone.index = iBone;
  333. bonesProMod->SetProperty( BP_PROPID_GET_BONE_STAT, &bone );
  334. /*
  335. if (GetIndexOfINode( bone.node ) >= 0)
  336. {
  337. fprintf( fp, "\"%s\" %d\n", bone.name, GetIndexOfINode( bone.node ) );
  338. }
  339. else
  340. {
  341. fprintf( fp, "\"%s\"\n", bone.name );
  342. }
  343. */
  344. BonesPro_BoneVertex bv;
  345. bv.bindex = iBone;
  346. bv.vindex = iVertex;
  347. bv.included = 0;
  348. bv.forced_weight = -1;
  349. if (bone.node != NULL)
  350. {
  351. int index = GetIndexOfINode( bone.node );
  352. if (index >= 0 && pweight[index].flWeight >= 0)
  353. {
  354. bv.included = 1;
  355. bv.forced_weight = pweight[index].flWeight;
  356. }
  357. }
  358. bonesProMod->SetProperty( BP_PROPID_SET_BV, &bv );
  359. }
  360. //fclose(fp);
  361. //exit(1);
  362. }