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.

356 lines
8.1 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. //===================================================================
  18. // Global variable definitions
  19. //
  20. // For OutputDebugString and misc sprintf's
  21. static char st_szDBG[300];
  22. //=====================================================================
  23. // Methods for VWeightExportClass
  24. //
  25. CONSTRUCTOR VWeightExportClass::VWeightExportClass(void)
  26. {
  27. m_cMaxNode = 0;
  28. m_cMaxVertex = 0;
  29. }
  30. DESTRUCTOR VWeightExportClass::~VWeightExportClass(void)
  31. {
  32. for (int i = 0; i < m_cMaxVertex; i++)
  33. {
  34. delete[] m_MaxVertex[i];
  35. }
  36. }
  37. int VWeightExportClass::DoExport(const TCHAR *name, ExpInterface *ei, Interface *pi, BOOL suppressPrompts, DWORD options)
  38. {
  39. ExpInterface *pexpiface = ei; // Hungarian
  40. Interface *piface = pi; // Hungarian
  41. // Reset the name-map property manager
  42. ResetINodeMap();
  43. // Break up filename, re-assemble longer versions
  44. TSTR strPath, strFile, strExt;
  45. TCHAR szFile[MAX_PATH];
  46. SplitFilename(TSTR(name), &strPath, &strFile, &strExt);
  47. sprintf(szFile, "%s\\%s.%s", (char*)strPath, (char*)strFile, DEFAULT_EXT);
  48. // Get animation metrics
  49. m_intervalOfAnimation = piface->GetAnimRange();
  50. m_tvStart = m_intervalOfAnimation.Start();
  51. m_tvEnd = m_intervalOfAnimation.End();
  52. m_tpf = ::GetTicksPerFrame();
  53. Interface *ip = GetCOREInterface();
  54. ResetINodeMap( );
  55. m_cMaxNode = BuildINodeMap( ip->GetRootNode() );
  56. // Count nodes, label them, collect into array
  57. CollectNodes( ip->GetRootNode() );
  58. CollectModel( pexpiface );
  59. #if 1
  60. FILE *pFile;
  61. if ((pFile = fopen(szFile, "wb")) == NULL)
  62. return FALSE/*failure*/;
  63. int version = 1;
  64. fwrite( &version, 1, sizeof( int ), pFile );
  65. int i, j;
  66. fwrite( &m_cMaxNode, 1, sizeof( int ), pFile );
  67. fwrite( &m_cMaxVertex, 1, sizeof( int ), pFile );
  68. for (i = 0; i < m_cMaxNode; i++)
  69. {
  70. fwrite( &m_MaxNode[i], 1, sizeof(m_MaxNode[i]), pFile );
  71. }
  72. for (j = 0; j < m_cMaxVertex; j++)
  73. {
  74. fwrite( m_MaxVertex[j], m_cMaxNode, sizeof(MaxVertWeight), pFile );
  75. }
  76. fclose( pFile );
  77. #else
  78. FILE *pFile;
  79. if ((pFile = fopen(szFile, "w")) == NULL)
  80. return FALSE/*failure*/;
  81. fprintf( pFile, "version %d\n", 1 );
  82. int i, j;
  83. fprintf(pFile, "%d\n", m_cMaxNode );
  84. fprintf(pFile, "%d\n", m_cMaxVertex );
  85. for (i = 0; i < m_cMaxNode; i++)
  86. {
  87. fprintf(pFile, "%5d \"%s\" %3d\n",
  88. i, m_MaxNode[i].szNodeName, m_MaxNode[i].imaxnodeParent );
  89. }
  90. for (j = 0; j < m_cMaxVertex; j++)
  91. {
  92. fprintf( pFile, "%d ", j );
  93. for (int i = 0; i < m_cMaxNode; i++)
  94. {
  95. // if (strstr(m_MaxNode[i].szNodeName, "Bip01 R Finger"))
  96. // if (m_MaxNode[i].szNodeName[0] == 'D')
  97. {
  98. fprintf(pFile, " %5.3f", m_MaxVertex[j][i].flDist );
  99. fprintf(pFile, " %3.0f", m_MaxVertex[j][i].flWeight );
  100. }
  101. }
  102. fprintf(pFile, "\n" );
  103. }
  104. fclose( pFile );
  105. #endif
  106. // Tell user that exporting is finished (it can take a while with no feedback)
  107. char szExportComplete[300];
  108. sprintf(szExportComplete, "Exported %s.", szFile);
  109. MessageBox(GetActiveWindow(), szExportComplete, "Status", MB_OK);
  110. return 1/*success*/;
  111. }
  112. void VWeightExportClass::CollectNodes( INode *pnode )
  113. {
  114. // Get pre-stored "index"
  115. int index = ::GetIndexOfINode(pnode);
  116. if (index >= 0)
  117. {
  118. // Get name, store name in array
  119. TSTR strNodeName(pnode->GetName());
  120. strcpy(m_MaxNode[index].szNodeName, (char*)strNodeName);
  121. // Get Node's time-zero Transformation Matrices
  122. m_MaxNode[index].mat3NodeTM = pnode->GetNodeTM(0);
  123. m_MaxNode[index].mat3ObjectTM = pnode->GetObjectTM(0);
  124. }
  125. for (int c = 0; c < pnode->NumberOfChildren(); c++)
  126. {
  127. CollectNodes(pnode->GetChildNode(c));
  128. }
  129. return;
  130. }
  131. BOOL VWeightExportClass::CollectModel( ExpInterface *pexpiface)
  132. {
  133. // Dump mesh info: vertices, normals, UV texture map coords, bone assignments
  134. CollectModelTEP procCollectModel;
  135. // init data
  136. m_cMaxVertex = 0;
  137. procCollectModel.m_phec = this;
  138. //fprintf(pFile, "triangles\n" );
  139. procCollectModel.m_tvToDump = m_tvStart;
  140. (void) pexpiface->theScene->EnumTree(&procCollectModel);
  141. //fprintf(pFile, "end\n" );
  142. return TRUE;
  143. }
  144. // #define DEBUG_MESH_DUMP
  145. //=================================================================
  146. // Methods for CollectModelTEP
  147. //
  148. int CollectModelTEP::callback(INode *pnode)
  149. {
  150. if (::FNodeMarkedToSkip(pnode))
  151. return TREE_CONTINUE;
  152. if ( !pnode->Selected())
  153. return TREE_CONTINUE;
  154. // clear physique export parameters
  155. m_mcExport = NULL;
  156. m_phyExport = NULL;
  157. m_phyMod = NULL;
  158. m_bonesProMod = NULL;
  159. ASSERT_MBOX(!(pnode)->IsRootNode(), "Encountered a root node!");
  160. int iNode = ::GetIndexOfINode(pnode);
  161. TSTR strNodeName(pnode->GetName());
  162. // The Footsteps node apparently MUST have a dummy mesh attached! Ignore it explicitly.
  163. if (FStrEq((char*)strNodeName, "Bip01 Footsteps"))
  164. return TREE_CONTINUE;
  165. // Helper nodes don't have meshes
  166. Object *pobj = pnode->GetObjectRef();
  167. if (pobj->SuperClassID() == HELPER_CLASS_ID)
  168. return TREE_CONTINUE;
  169. // Get Node's object, convert to a triangle-mesh object, so I can access the Faces
  170. ObjectState os = pnode->EvalWorldState(m_tvToDump);
  171. pobj = os.obj;
  172. // Shouldn't have gotten this far if it's a helper object
  173. if (pobj->SuperClassID() == HELPER_CLASS_ID)
  174. {
  175. sprintf(st_szDBG, "ERROR--Helper node %s has an attached mesh, and it shouldn't.", (char*)strNodeName);
  176. ASSERT_AND_ABORT(FALSE, st_szDBG);
  177. }
  178. // convert mesh to triobject
  179. if (!pobj->CanConvertToType(triObjectClassID))
  180. return TREE_CONTINUE;
  181. TriObject *ptriobj = (TriObject*)pobj->ConvertToType(m_tvToDump, triObjectClassID);
  182. if (ptriobj == NULL)
  183. return TREE_CONTINUE;
  184. Mesh *pmesh = &ptriobj->mesh;
  185. // We want the vertex coordinates in World-space, not object-space
  186. Matrix3 mat3ObjectTM = pnode->GetObjectTM(m_tvToDump);
  187. // initialize physique export parameters
  188. m_phyMod = FindPhysiqueModifier(pnode);
  189. if (m_phyMod)
  190. {
  191. // Physique Modifier exists for given Node
  192. m_phyExport = (IPhysiqueExport *)m_phyMod->GetInterface(I_PHYINTERFACE);
  193. if (m_phyExport)
  194. {
  195. // create a ModContext Export Interface for the specific node of the Physique Modifier
  196. m_mcExport = (IPhyContextExport *)m_phyExport->GetContextInterface(pnode);
  197. if (m_mcExport)
  198. {
  199. // convert all vertices to Rigid
  200. m_mcExport->ConvertToRigid(TRUE);
  201. }
  202. }
  203. }
  204. // initialize bones pro export parameters
  205. m_wa = NULL;
  206. m_bonesProMod = FindBonesProModifier(pnode);
  207. if (m_bonesProMod)
  208. {
  209. m_bonesProMod->SetProperty( BP_PROPID_GET_WEIGHTS, &m_wa );
  210. }
  211. int cVerts = pmesh->getNumVerts();
  212. // Dump the triangle face info
  213. int cFaces = pmesh->getNumFaces();
  214. int *iUsed = new int[cVerts];
  215. for (int iVert = 0; iVert < cVerts; iVert++)
  216. {
  217. iUsed[iVert] = 0;
  218. }
  219. for (int iFace = 0; iFace < cFaces; iFace++)
  220. {
  221. if (pmesh->faces[iFace].flags & HAS_TVERTS)
  222. {
  223. iUsed[pmesh->faces[iFace].getVert(0)] = 1;
  224. iUsed[pmesh->faces[iFace].getVert(1)] = 1;
  225. iUsed[pmesh->faces[iFace].getVert(2)] = 1;
  226. }
  227. }
  228. for (iVert = 0; iVert < cVerts; iVert++)
  229. {
  230. MaxVertWeight *pweight = m_phec->m_MaxVertex[m_phec->m_cMaxVertex] = new MaxVertWeight [m_phec->m_cMaxNode];
  231. Point3 pt3Vertex1 = pmesh->getVert(iVert);
  232. Point3 v1 = pt3Vertex1 * mat3ObjectTM;
  233. GetUnifiedCoord( v1, pweight, m_phec->m_MaxNode, m_phec->m_cMaxNode );
  234. if (CollectWeights( iVert, pweight ))
  235. {
  236. m_phec->m_cMaxVertex++;
  237. }
  238. }
  239. // fflush( m_pfile );
  240. return TREE_CONTINUE;
  241. }
  242. int CollectModelTEP::CollectWeights(int iVertex, MaxVertWeight *pweight)
  243. {
  244. for (int index = 0; index < m_phec->m_cMaxNode; index++)
  245. {
  246. pweight[index].flWeight = -1;
  247. }
  248. if (m_mcExport)
  249. {
  250. return GetBoneWeights( m_mcExport, iVertex, pweight );
  251. }
  252. else
  253. {
  254. return GetBoneWeights( m_bonesProMod, iVertex, pweight );
  255. }
  256. }
  257. void CollectModelTEP::cleanup(void)
  258. {
  259. if (m_phyMod && m_phyExport)
  260. {
  261. if (m_mcExport)
  262. {
  263. m_phyExport->ReleaseContextInterface(m_mcExport);
  264. m_mcExport = NULL;
  265. }
  266. m_phyMod->ReleaseInterface(I_PHYINTERFACE, m_phyExport);
  267. m_phyExport = NULL;
  268. m_phyMod = NULL;
  269. }
  270. }