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.

393 lines
8.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // studiomdl.c: generates a studio .mdl file from a .qc script
  10. // sources/<scriptname>.mdl.
  11. //
  12. #pragma warning( disable : 4244 )
  13. #pragma warning( disable : 4237 )
  14. #pragma warning( disable : 4305 )
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <sys/stat.h>
  18. #include <math.h>
  19. #include "cmdlib.h"
  20. #include "scriplib.h"
  21. #include "mathlib/mathlib.h"
  22. #include "studio.h"
  23. #include "studiomdl.h"
  24. // The current version of the SMD file being parsed
  25. // Yes, I know this file is called 'v1support' and there's never actually
  26. // been a v > 1 but now there is
  27. // (actually, there was a while when we were using developing progressive mesh
  28. // stuff in the middle of HL2 development, but most all that code has long since
  29. // been deleted)
  30. int g_smdVersion = 1;
  31. int lookup_index( s_source_t *psource, int material, Vector& vertex, Vector& normal, Vector2D texcoord, int iCount, int bones[], float weights[] )
  32. {
  33. int i, j;
  34. for (i = 0; i < numvlist; i++)
  35. {
  36. if (v_listdata[i].m == material
  37. && DotProduct( g_normal[i], normal ) > normal_blend
  38. && VectorCompare( g_vertex[i], vertex )
  39. && g_texcoord[i][0] == texcoord[0]
  40. && g_texcoord[i][1] == texcoord[1])
  41. {
  42. if (g_bone[i].numbones == iCount)
  43. {
  44. for (j = 0; j < iCount; j++)
  45. {
  46. if (g_bone[i].bone[j] != bones[j] || g_bone[i].weight[j] != weights[j])
  47. break;
  48. }
  49. if (j == iCount)
  50. {
  51. v_listdata[i].lastref = numvlist;
  52. return i;
  53. }
  54. }
  55. }
  56. }
  57. if (i >= MAXSTUDIOVERTS) {
  58. MdlError( "too many indices in source: \"%s\"\n", psource->filename);
  59. }
  60. VectorCopy( vertex, g_vertex[i] );
  61. VectorCopy( normal, g_normal[i] );
  62. Vector2Copy( texcoord, g_texcoord[i] );
  63. g_bone[i].numbones = iCount;
  64. for ( j = 0; j < iCount; j++)
  65. {
  66. g_bone[i].bone[j] = bones[j];
  67. g_bone[i].weight[j] = weights[j];
  68. }
  69. v_listdata[i].v = i;
  70. v_listdata[i].m = material;
  71. v_listdata[i].n = i;
  72. v_listdata[i].t = i;
  73. v_listdata[i].firstref = numvlist;
  74. v_listdata[i].lastref = numvlist;
  75. numvlist = i + 1;
  76. return i;
  77. }
  78. void ParseFaceData( s_source_t *psource, int material, s_face_t *pFace )
  79. {
  80. int index[3] = {};
  81. int i, j;
  82. Vector p;
  83. Vector normal;
  84. Vector2D t;
  85. int iCount, bones[MAXSTUDIOSRCBONES];
  86. float weights[MAXSTUDIOSRCBONES];
  87. int bone;
  88. for (j = 0; j < 3; j++)
  89. {
  90. memset( g_szLine, 0, sizeof( g_szLine ) );
  91. if (!GetLineInput())
  92. {
  93. MdlError("%s: error on g_szLine %d: %s", g_szFilename, g_iLinecount, g_szLine );
  94. }
  95. iCount = 0;
  96. i = sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %d %d %f %d %f %d %f %d %f",
  97. &bone,
  98. &p[0], &p[1], &p[2],
  99. &normal[0], &normal[1], &normal[2],
  100. &t[0], &t[1],
  101. &iCount,
  102. &bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
  103. if (i < 9)
  104. continue;
  105. if (bone < 0 || bone >= psource->numbones)
  106. {
  107. MdlError("bogus bone index\n%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
  108. }
  109. //Scale face pos
  110. scale_vertex( p );
  111. // continue parsing more bones.
  112. // FIXME: don't we have a built in parser that'll do this?
  113. if (iCount > 4)
  114. {
  115. int k;
  116. int ctr = 0;
  117. char *token;
  118. for (k = 0; k < 18; k++)
  119. {
  120. while (g_szLine[ctr] == ' ')
  121. {
  122. ctr++;
  123. }
  124. token = strtok( &g_szLine[ctr], " " );
  125. ctr += strlen( token ) + 1;
  126. }
  127. for (k = 4; k < iCount && k < MAXSTUDIOSRCBONES; k++)
  128. {
  129. while (g_szLine[ctr] == ' ')
  130. {
  131. ctr++;
  132. }
  133. token = strtok( &g_szLine[ctr], " " );
  134. ctr += strlen( token ) + 1;
  135. bones[k] = atoi(token);
  136. token = strtok( &g_szLine[ctr], " " );
  137. ctr += strlen( token ) + 1;
  138. weights[k] = atof(token);
  139. }
  140. // printf("%d ", iCount );
  141. //printf("\n");
  142. //exit(1);
  143. }
  144. // adjust_vertex( p );
  145. // scale_vertex( p );
  146. // move vertex position to object space.
  147. // VectorSubtract( p, psource->bonefixup[bone].worldorg, tmp );
  148. // VectorTransform(tmp, psource->bonefixup[bone].im, p );
  149. // move normal to object space.
  150. // VectorCopy( normal, tmp );
  151. // VectorTransform(tmp, psource->bonefixup[bone].im, normal );
  152. // VectorNormalize( normal );
  153. // invert v
  154. t[1] = 1.0 - t[1];
  155. if (i == 9 || iCount == 0)
  156. {
  157. iCount = 1;
  158. bones[0] = bone;
  159. weights[0] = 1.0;
  160. }
  161. else
  162. {
  163. iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
  164. }
  165. index[j] = lookup_index( psource, material, p, normal, t, iCount, bones, weights );
  166. }
  167. // pFace->material = material; // BUG
  168. pFace->a = index[0];
  169. pFace->b = index[2];
  170. pFace->c = index[1];
  171. Assert( ((pFace->a & 0xF0000000) == 0) && ((pFace->b & 0xF0000000) == 0) &&
  172. ((pFace->c & 0xF0000000) == 0) );
  173. }
  174. void Grab_Triangles( s_source_t *psource )
  175. {
  176. int i;
  177. Vector vmin, vmax;
  178. vmin[0] = vmin[1] = vmin[2] = 99999;
  179. vmax[0] = vmax[1] = vmax[2] = -99999;
  180. g_numfaces = 0;
  181. numvlist = 0;
  182. //
  183. // load the base triangles
  184. //
  185. int texture;
  186. int material;
  187. char texturename[MAX_PATH];
  188. while (1)
  189. {
  190. if (!GetLineInput())
  191. break;
  192. // check for end
  193. if (IsEnd( g_szLine ))
  194. break;
  195. // Look for extra junk that we may want to avoid...
  196. int nLineLength = strlen( g_szLine );
  197. if (nLineLength >= sizeof( texturename ))
  198. {
  199. MdlWarning("Unexpected data at line %d, (need a texture name) ignoring...\n", g_iLinecount );
  200. continue;
  201. }
  202. // strip off trailing smag
  203. V_strcpy_safe( texturename, g_szLine );
  204. for (i = strlen( texturename ) - 1; i >= 0 && ! V_isgraph( texturename[i] ); i--)
  205. {
  206. }
  207. texturename[i + 1] = '\0';
  208. // funky texture overrides
  209. for (i = 0; i < numrep; i++)
  210. {
  211. if (sourcetexture[i][0] == '\0')
  212. {
  213. V_strcpy_safe( texturename, defaulttexture[i] );
  214. break;
  215. }
  216. if (stricmp( texturename, sourcetexture[i]) == 0)
  217. {
  218. V_strcpy_safe( texturename, defaulttexture[i] );
  219. break;
  220. }
  221. }
  222. if (texturename[0] == '\0')
  223. {
  224. // weird source problem, skip them
  225. GetLineInput();
  226. GetLineInput();
  227. GetLineInput();
  228. continue;
  229. }
  230. if (stricmp( texturename, "null.bmp") == 0 || stricmp( texturename, "null.tga") == 0 || stricmp( texturename, "debug/debugempty" ) == 0)
  231. {
  232. // skip all faces with the null texture on them.
  233. GetLineInput();
  234. GetLineInput();
  235. GetLineInput();
  236. continue;
  237. }
  238. texture = LookupTexture( texturename, ( g_smdVersion > 1 ) );
  239. psource->texmap[texture] = texture; // hack, make it 1:1
  240. material = UseTextureAsMaterial( texture );
  241. s_face_t f;
  242. ParseFaceData( psource, material, &f );
  243. // remove degenerate triangles
  244. if (f.a == f.b || f.b == f.c || f.a == f.c)
  245. {
  246. // printf("Degenerate triangle %d %d %d\n", f.a, f.b, f.c );
  247. continue;
  248. }
  249. g_src_uface[g_numfaces] = f;
  250. g_face[g_numfaces].material = material;
  251. g_numfaces++;
  252. }
  253. BuildIndividualMeshes( psource );
  254. }
  255. int Load_SMD ( s_source_t *psource )
  256. {
  257. char cmd[1024];
  258. int option;
  259. // Reset smdVersion
  260. g_smdVersion = 1;
  261. if (!OpenGlobalFile( psource->filename ))
  262. return 0;
  263. if( !g_quiet )
  264. {
  265. printf ("SMD MODEL %s\n", psource->filename);
  266. }
  267. g_iLinecount = 0;
  268. while (GetLineInput())
  269. {
  270. int numRead = sscanf( g_szLine, "%s %d", cmd, &option );
  271. // Blank line
  272. if ((numRead == EOF) || (numRead == 0))
  273. continue;
  274. if (stricmp( cmd, "version" ) == 0)
  275. {
  276. if (option < 1 || option > 2)
  277. {
  278. MdlError("bad version\n");
  279. }
  280. g_smdVersion = option;
  281. }
  282. else if (stricmp( cmd, "nodes" ) == 0)
  283. {
  284. psource->numbones = Grab_Nodes( psource->localBone );
  285. }
  286. else if (stricmp( cmd, "skeleton" ) == 0)
  287. {
  288. Grab_Animation( psource, "BindPose" );
  289. }
  290. else if (stricmp( cmd, "triangles" ) == 0)
  291. {
  292. Grab_Triangles( psource );
  293. }
  294. else if (stricmp( cmd, "vertexanimation" ) == 0)
  295. {
  296. Grab_Vertexanimation( psource, "BindPose" );
  297. }
  298. else if ((strncmp( cmd, "//", 2 ) == 0) || (strncmp( cmd, ";", 1 ) == 0) || (strncmp( cmd, "#", 1 ) == 0))
  299. {
  300. ProcessSourceComment( psource, cmd );
  301. continue;
  302. }
  303. else
  304. {
  305. MdlWarning("unknown studio command \"%s\"\n", cmd );
  306. }
  307. }
  308. fclose( g_fpInput );
  309. return 1;
  310. }