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.

350 lines
6.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // tristrip - convert triangle list into tristrips and fans
  9. #pragma warning( disable : 4244 )
  10. #pragma warning( disable : 4237 )
  11. #pragma warning( disable : 4305 )
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <sys/stat.h>
  15. #include "cmdlib.h"
  16. #include "lbmlib.h"
  17. #include "scriplib.h"
  18. #include "mathlib/mathlib.h"
  19. #include "..\..\engine\studio.h"
  20. #include "studiomdl.h"
  21. int used[MAXSTUDIOTRIANGLES];
  22. // the command list holds counts and s/t values that are valid for
  23. // every frame
  24. short commands[MAXSTUDIOTRIANGLES * 13];
  25. int numcommands;
  26. // all frames will have their vertexes rearranged and expanded
  27. // so they are in the order expected by the command list
  28. int allverts, alltris;
  29. int stripverts[MAXSTUDIOTRIANGLES+2];
  30. int striptris[MAXSTUDIOTRIANGLES+2];
  31. int stripcount;
  32. int neighbortri[MAXSTUDIOTRIANGLES][3];
  33. int neighboredge[MAXSTUDIOTRIANGLES][3];
  34. s_trianglevert_t (*triangles)[3];
  35. s_mesh_t *pmesh;
  36. void FindNeighbor (int starttri, int startv)
  37. {
  38. s_trianglevert_t m1, m2;
  39. int j;
  40. s_trianglevert_t *last, *check;
  41. int k;
  42. // used[starttri] |= (1 << startv);
  43. last = &triangles[starttri][0];
  44. m1 = last[(startv+1)%3];
  45. m2 = last[(startv+0)%3];
  46. for (j=starttri+1, check=&triangles[starttri+1][0] ; j<pmesh->numtris ; j++, check += 3)
  47. {
  48. if (used[j] == 7)
  49. continue;
  50. for (k=0 ; k<3 ; k++)
  51. {
  52. if (memcmp(&check[k],&m1,sizeof(m1)))
  53. continue;
  54. if (memcmp(&check[ (k+1)%3 ],&m2,sizeof(m2)))
  55. continue;
  56. neighbortri[starttri][startv] = j;
  57. neighboredge[starttri][startv] = k;
  58. neighbortri[j][k] = starttri;
  59. neighboredge[j][k] = startv;
  60. used[starttri] |= (1 << startv);
  61. used[j] |= (1 << k);
  62. return;
  63. }
  64. }
  65. }
  66. /*
  67. ================
  68. StripLength
  69. ================
  70. */
  71. int StripLength (int starttri, int startv)
  72. {
  73. int j;
  74. int k;
  75. used[starttri] = 2;
  76. stripverts[0] = (startv)%3;
  77. stripverts[1] = (startv+1)%3;
  78. stripverts[2] = (startv+2)%3;
  79. striptris[0] = starttri;
  80. striptris[1] = starttri;
  81. striptris[2] = starttri;
  82. stripcount = 3;
  83. while( 1 )
  84. {
  85. if (stripcount & 1)
  86. {
  87. j = neighbortri[starttri][(startv+1)%3];
  88. k = neighboredge[starttri][(startv+1)%3];
  89. }
  90. else
  91. {
  92. j = neighbortri[starttri][(startv+2)%3];
  93. k = neighboredge[starttri][(startv+2)%3];
  94. }
  95. if (j == -1 || used[j])
  96. goto done;
  97. stripverts[stripcount] = (k+2)%3;
  98. striptris[stripcount] = j;
  99. stripcount++;
  100. used[j] = 2;
  101. starttri = j;
  102. startv = k;
  103. }
  104. done:
  105. // clear the temp used flags
  106. for (j=0 ; j<pmesh->numtris ; j++)
  107. if (used[j] == 2)
  108. used[j] = 0;
  109. return stripcount;
  110. }
  111. /*
  112. ===========
  113. FanLength
  114. ===========
  115. */
  116. int FanLength (int starttri, int startv)
  117. {
  118. int j;
  119. int k;
  120. used[starttri] = 2;
  121. stripverts[0] = (startv)%3;
  122. stripverts[1] = (startv+1)%3;
  123. stripverts[2] = (startv+2)%3;
  124. striptris[0] = starttri;
  125. striptris[1] = starttri;
  126. striptris[2] = starttri;
  127. stripcount = 3;
  128. while( 1 )
  129. {
  130. j = neighbortri[starttri][(startv+2)%3];
  131. k = neighboredge[starttri][(startv+2)%3];
  132. if (j == -1 || used[j])
  133. goto done;
  134. stripverts[stripcount] = (k+2)%3;
  135. striptris[stripcount] = j;
  136. stripcount++;
  137. used[j] = 2;
  138. starttri = j;
  139. startv = k;
  140. }
  141. done:
  142. // clear the temp used flags
  143. for (j=0 ; j<pmesh->numtris ; j++)
  144. if (used[j] == 2)
  145. used[j] = 0;
  146. return stripcount;
  147. }
  148. /*
  149. ================
  150. BuildTris
  151. Generate a list of trifans or strips
  152. for the model, which holds for all frames
  153. ================
  154. */
  155. int numcommandnodes;
  156. int BuildTris (s_trianglevert_t (*x)[3], s_mesh_t *y, byte **ppdata )
  157. {
  158. int i, j, k, m;
  159. int startv;
  160. int len, bestlen, besttype;
  161. int bestverts[MAXSTUDIOTRIANGLES];
  162. int besttris[MAXSTUDIOTRIANGLES];
  163. int peak[MAXSTUDIOTRIANGLES];
  164. int type;
  165. int total = 0;
  166. long t;
  167. int maxlen;
  168. triangles = x;
  169. pmesh = y;
  170. t = time( NULL );
  171. for (i=0 ; i<pmesh->numtris ; i++)
  172. {
  173. neighbortri[i][0] = neighbortri[i][1] = neighbortri[i][2] = -1;
  174. used[i] = 0;
  175. peak[i] = pmesh->numtris;
  176. }
  177. // printf("finding neighbors\n");
  178. for (i=0 ; i<pmesh->numtris; i++)
  179. {
  180. for (k = 0; k < 3; k++)
  181. {
  182. if (used[i] & (1 << k))
  183. continue;
  184. FindNeighbor( i, k );
  185. }
  186. // printf("%d", used[i] );
  187. }
  188. // printf("\n");
  189. //
  190. // build tristrips
  191. //
  192. numcommandnodes = 0;
  193. numcommands = 0;
  194. memset (used, 0, sizeof(used));
  195. for (i=0 ; i<pmesh->numtris ;)
  196. {
  197. // pick an unused triangle and start the trifan
  198. if (used[i])
  199. {
  200. i++;
  201. continue;
  202. }
  203. maxlen = 9999;
  204. bestlen = 0;
  205. m = 0;
  206. for (k = i; k < pmesh->numtris && bestlen < 127; k++)
  207. {
  208. int localpeak = 0;
  209. if (used[k])
  210. continue;
  211. if (peak[k] <= bestlen)
  212. continue;
  213. m++;
  214. for (type = 0 ; type < 2 ; type++)
  215. {
  216. for (startv =0 ; startv < 3 ; startv++)
  217. {
  218. if (type == 1)
  219. len = FanLength (k, startv);
  220. else
  221. len = StripLength (k, startv);
  222. if (len > 127)
  223. {
  224. // skip these, they are too long to encode
  225. }
  226. else if (len > bestlen)
  227. {
  228. besttype = type;
  229. bestlen = len;
  230. for (j=0 ; j<bestlen ; j++)
  231. {
  232. besttris[j] = striptris[j];
  233. bestverts[j] = stripverts[j];
  234. }
  235. // printf("%d %d\n", k, bestlen );
  236. }
  237. if (len > localpeak)
  238. localpeak = len;
  239. }
  240. }
  241. peak[k] = localpeak;
  242. if (localpeak == maxlen)
  243. break;
  244. }
  245. total += (bestlen - 2);
  246. // printf("%d (%d) %d\n", bestlen, pmesh->numtris - total, i );
  247. maxlen = bestlen;
  248. // mark the tris on the best strip as used
  249. for (j=0 ; j<bestlen ; j++)
  250. used[besttris[j]] = 1;
  251. if (besttype == 1)
  252. commands[numcommands++] = -bestlen;
  253. else
  254. commands[numcommands++] = bestlen;
  255. for (j=0 ; j<bestlen ; j++)
  256. {
  257. s_trianglevert_t *tri;
  258. tri = &triangles[besttris[j]][bestverts[j]];
  259. commands[numcommands++] = tri->vertindex;
  260. commands[numcommands++] = tri->normindex;
  261. commands[numcommands++] = tri->s;
  262. commands[numcommands++] = tri->t;
  263. }
  264. // printf("%d ", bestlen - 2 );
  265. numcommandnodes++;
  266. if (t != time(NULL))
  267. {
  268. printf("%2d%%\r", (total * 100) / pmesh->numtris );
  269. t = time(NULL);
  270. }
  271. }
  272. commands[numcommands++] = 0; // end of list marker
  273. *ppdata = (byte *)commands;
  274. // printf("%d %d %d\n", numcommandnodes, numcommands, pmesh->numtris );
  275. return numcommands * sizeof( short );
  276. }