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.

477 lines
9.4 KiB

  1. //========= Copyright � 1996-2005, 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. int lookup_index( s_source_t *psource, int material, Vector& vertex, Vector& normal, Vector2D texcoord, int iCount, int bones[], float weights[], int iExtras, float extras[] )
  25. {
  26. int i, j, k;
  27. for (i = 0; i < g_numvlist; i++)
  28. {
  29. if (v_listdata[i].m == material
  30. && DotProduct( g_normal[i], normal ) > normal_blend
  31. && VectorCompare( g_vertex[i], vertex )
  32. && g_texcoord[0][i][0] == texcoord[0]
  33. && g_texcoord[0][i][1] == texcoord[1])
  34. {
  35. if (g_bone[i].numbones == iCount)
  36. {
  37. for (j = 0; j < iCount; j++)
  38. {
  39. if (g_bone[i].bone[j] != bones[j] || g_bone[i].weight[j] != weights[j])
  40. break;
  41. }
  42. if (j == iCount)
  43. {
  44. // Assume extra floats are additional texcoords
  45. for (k = 0; k < (iExtras / 2); k++)
  46. {
  47. if (v_listdata[i].t[k + 1] == -1) // Texcoord not set
  48. break;
  49. if (g_texcoord[k + 1][i][0] != extras[k * 2])
  50. break;
  51. if (g_texcoord[k + 1][i][1] != extras[k * 2 + 1])
  52. break;
  53. }
  54. if (k == (iExtras/2))
  55. {
  56. v_listdata[i].lastref = g_numvlist;
  57. return i;
  58. }
  59. }
  60. }
  61. }
  62. }
  63. if (i >= MAXSTUDIOSRCVERTS) {
  64. MdlError( "too many indices in source: \"%s\"\n", psource->filename);
  65. }
  66. VectorCopy( vertex, g_vertex[i] );
  67. VectorCopy( normal, g_normal[i] );
  68. Vector2Copy( texcoord, g_texcoord[0][i] );
  69. g_bone[i].numbones = iCount;
  70. for ( j = 0; j < iCount; j++)
  71. {
  72. g_bone[i].bone[j] = bones[j];
  73. g_bone[i].weight[j] = weights[j];
  74. }
  75. v_listdata[i].v = i;
  76. v_listdata[i].m = material;
  77. v_listdata[i].n = i;
  78. v_listdata[i].t[0] = i;
  79. // Set default indices for additional texcoords to -1
  80. for (j = 1; j < (MAXSTUDIOTEXCOORDS); ++j)
  81. {
  82. v_listdata[i].t[j] = -1;
  83. }
  84. // Populate additional texcoords with any extra floats
  85. for (j = 0; j < (iExtras / 2); j++)
  86. {
  87. g_texcoord[j + 1][i][0] = extras[j * 2];
  88. g_texcoord[j + 1][i][1] = extras[j * 2 + 1];
  89. v_listdata[i].t[j+1] = i;
  90. }
  91. v_listdata[i].lastref = g_numvlist;
  92. g_numvlist = i + 1;
  93. return i;
  94. }
  95. // GetNextFaceItem
  96. // Get next item from string of space separated data
  97. static char* GetNextFaceItem(char* pCurrentItem)
  98. {
  99. if (!pCurrentItem)
  100. {
  101. return NULL;
  102. }
  103. char* pChar = pCurrentItem;
  104. //Skip any leading spaces
  105. while (*pChar == ' ')
  106. {
  107. pChar++;
  108. }
  109. pChar = strchr(pChar, ' ');
  110. if (!pChar)
  111. {
  112. return NULL;
  113. }
  114. while (*pChar == ' ')
  115. {
  116. pChar++;
  117. }
  118. if ((*pChar == 0) || (*pChar == '\n'))
  119. {
  120. return NULL;
  121. }
  122. return pChar;
  123. }
  124. void ParseFaceData( s_source_t *psource, int material, s_face_t *pFace )
  125. {
  126. int index[3];
  127. int i, j;
  128. Vector p;
  129. Vector normal;
  130. Vector2D t;
  131. int iCount, bones[MAXSTUDIOSRCBONES];
  132. float weights[MAXSTUDIOSRCBONES];
  133. int iExtras;
  134. float extras[(MAXSTUDIOTEXCOORDS-1)*2];
  135. int bone;
  136. for (j = 0; j < 3; j++)
  137. {
  138. memset( g_szLine, 0, sizeof( g_szLine ) );
  139. if (!GetLineInput())
  140. {
  141. MdlError("%s: error on g_szLine %d: %s", g_szFilename, g_iLinecount, g_szLine );
  142. }
  143. iCount = 0;
  144. iExtras = 0;
  145. i = sscanf(g_szLine, "%d %f %f %f %f %f %f %f %f",
  146. &bone,
  147. &p[0], &p[1], &p[2],
  148. &normal[0], &normal[1], &normal[2],
  149. &t[0], &t[1]);
  150. if (i < 9)
  151. continue;
  152. if (bone < 0 || bone >= psource->numbones)
  153. {
  154. MdlError("bogus bone index\n%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
  155. }
  156. //Scale face pos
  157. scale_vertex( p );
  158. // Parse bones.
  159. int k;
  160. char *pItem = g_szLine;
  161. // Skip first 9 items already parsed via sscanf above
  162. for (k = 0; k < 9; k++)
  163. {
  164. pItem = GetNextFaceItem(pItem);
  165. }
  166. // Read bone count
  167. if (pItem)
  168. {
  169. iCount = atoi(pItem);
  170. if (iCount > 0)
  171. {
  172. for (k = 0; k < iCount && k < MAXSTUDIOSRCBONES; k++)
  173. {
  174. pItem = GetNextFaceItem(pItem);
  175. if (!pItem)
  176. {
  177. MdlError("Bone ID %d not found\n%d %s :\n%s", k, g_iLinecount, g_szFilename, g_szLine);
  178. }
  179. bones[k] = atoi(pItem);
  180. pItem = GetNextFaceItem(pItem);
  181. if (!pItem)
  182. {
  183. MdlError("Bone weight %d not found\n%d %s :\n%s", k, g_iLinecount, g_szFilename, g_szLine);
  184. }
  185. weights[k] = atof(pItem);
  186. }
  187. }
  188. if (psource->version >= 3)
  189. {
  190. pItem = GetNextFaceItem(pItem);
  191. if (pItem)
  192. {
  193. iExtras = atoi(pItem);
  194. if (iExtras > 0)
  195. {
  196. iExtras = MIN(iExtras, (MAXSTUDIOTEXCOORDS - 1) * 2);
  197. for (int e = 0; e < iExtras; e++)
  198. {
  199. pItem = GetNextFaceItem(pItem);
  200. if (!pItem)
  201. {
  202. MdlError("Extra data item %d not found\n%d %s :\n%s", e, g_iLinecount, g_szFilename, g_szLine);
  203. }
  204. extras[e] = atof(pItem);
  205. }
  206. }
  207. }
  208. }
  209. // printf("%d ", iCount );
  210. //printf("\n");
  211. //exit(1);
  212. }
  213. // adjust_vertex( p );
  214. // scale_vertex( p );
  215. // move vertex position to object space.
  216. // VectorSubtract( p, psource->bonefixup[bone].worldorg, tmp );
  217. // VectorTransform(tmp, psource->bonefixup[bone].im, p );
  218. // move normal to object space.
  219. // VectorCopy( normal, tmp );
  220. // VectorTransform(tmp, psource->bonefixup[bone].im, normal );
  221. // VectorNormalize( normal );
  222. // invert v
  223. t[1] = 1.0 - t[1];
  224. if (iCount == 0)
  225. {
  226. iCount = 1;
  227. bones[0] = bone;
  228. weights[0] = 1.0;
  229. }
  230. else
  231. {
  232. iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
  233. }
  234. index[j] = lookup_index( psource, material, p, normal, t, iCount, bones, weights, iExtras, extras );
  235. }
  236. // pFace->material = material; // BUG
  237. pFace->a = index[0];
  238. pFace->b = index[2];
  239. pFace->c = index[1];
  240. Assert( ((pFace->a & 0xF0000000) == 0) && ((pFace->b & 0xF0000000) == 0) &&
  241. ((pFace->c & 0xF0000000) == 0) );
  242. }
  243. void Grab_Triangles( s_source_t *psource )
  244. {
  245. int i;
  246. Vector vmin, vmax;
  247. vmin[0] = vmin[1] = vmin[2] = 99999;
  248. vmax[0] = vmax[1] = vmax[2] = -99999;
  249. g_numfaces = 0;
  250. g_numvlist = 0;
  251. //
  252. // load the base triangles
  253. //
  254. int texture;
  255. int material;
  256. char texturename[MAX_PATH];
  257. while (1)
  258. {
  259. if (!GetLineInput())
  260. break;
  261. // check for end
  262. if (IsEnd( g_szLine ))
  263. break;
  264. // Look for extra junk that we may want to avoid...
  265. int nLineLength = strlen( g_szLine );
  266. if (nLineLength >= sizeof( texturename ))
  267. {
  268. MdlWarning("Unexpected data at line %d, (need a texture name) ignoring...\n", g_iLinecount );
  269. continue;
  270. }
  271. // strip off trailing smag
  272. strncpy( texturename, g_szLine, sizeof( texturename ) - 1 );
  273. for (i = strlen( texturename ) - 1; i >= 0 && ! V_isgraph( texturename[i] ); i--)
  274. {
  275. }
  276. texturename[i + 1] = '\0';
  277. // funky texture overrides
  278. for (i = 0; i < numrep; i++)
  279. {
  280. if (sourcetexture[i][0] == '\0')
  281. {
  282. strcpy( texturename, defaulttexture[i] );
  283. break;
  284. }
  285. if (stricmp( texturename, sourcetexture[i]) == 0)
  286. {
  287. strcpy( texturename, defaulttexture[i] );
  288. break;
  289. }
  290. }
  291. if (texturename[0] == '\0')
  292. {
  293. // weird source problem, skip them
  294. GetLineInput();
  295. GetLineInput();
  296. GetLineInput();
  297. continue;
  298. }
  299. if (stricmp( texturename, "null.bmp") == 0 || stricmp( texturename, "null.tga") == 0 || stricmp( texturename, "debug/debugempty" ) == 0)
  300. {
  301. // skip all faces with the null texture on them.
  302. GetLineInput();
  303. GetLineInput();
  304. GetLineInput();
  305. continue;
  306. }
  307. texture = LookupTexture( texturename, ( psource->version == 2 ) );
  308. psource->texmap[texture] = texture; // hack, make it 1:1
  309. material = UseTextureAsMaterial( texture );
  310. s_face_t f;
  311. ParseFaceData( psource, material, &f );
  312. // remove degenerate triangles
  313. if (f.a == f.b || f.b == f.c || f.a == f.c)
  314. {
  315. // printf("Degenerate triangle %d %d %d\n", f.a, f.b, f.c );
  316. continue;
  317. }
  318. g_src_uface[g_numfaces] = f;
  319. g_face[g_numfaces].material = material;
  320. g_numfaces++;
  321. }
  322. for (int i = 0; i < MAXSTUDIOTEXCOORDS; ++i)
  323. {
  324. if (g_texcoord[i].Count())
  325. {
  326. g_numtexcoords[i] = g_numvlist;
  327. }
  328. }
  329. BuildIndividualMeshes( psource );
  330. }
  331. int Load_SMD ( s_source_t *psource )
  332. {
  333. char cmd[1024];
  334. int option;
  335. // Reset smdVersion
  336. psource->version = 1;
  337. if (!OpenGlobalFile( psource->filename ))
  338. return 0;
  339. if( !g_quiet )
  340. {
  341. printf ("SMD MODEL %s\n", psource->filename);
  342. }
  343. g_iLinecount = 0;
  344. while (GetLineInput())
  345. {
  346. int numRead = sscanf( g_szLine, "%s %d", cmd, &option );
  347. // Blank line
  348. if ((numRead == EOF) || (numRead == 0))
  349. continue;
  350. if (stricmp( cmd, "version" ) == 0)
  351. {
  352. if (option < 1 || option > 3)
  353. {
  354. MdlError("bad version\n");
  355. }
  356. psource->version = option;
  357. }
  358. else if (stricmp( cmd, "nodes" ) == 0)
  359. {
  360. psource->numbones = Grab_Nodes( psource->localBone );
  361. }
  362. else if (stricmp( cmd, "skeleton" ) == 0)
  363. {
  364. Grab_Animation( psource, "BindPose" );
  365. }
  366. else if (stricmp( cmd, "triangles" ) == 0)
  367. {
  368. Grab_Triangles( psource );
  369. }
  370. else if (stricmp( cmd, "vertexanimation" ) == 0)
  371. {
  372. Grab_Vertexanimation( psource, "BindPose" );
  373. }
  374. else if ((strncmp( cmd, "//", 2 ) == 0) || (strncmp( cmd, ";", 1 ) == 0) || (strncmp( cmd, "#", 1 ) == 0))
  375. {
  376. ProcessSourceComment( psource, cmd );
  377. continue;
  378. }
  379. else
  380. {
  381. MdlWarning("unknown studio command \"%s\"\n", cmd );
  382. }
  383. }
  384. fclose( g_fpInput );
  385. return 1;
  386. }