PageRenderTime 74ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/model_alias.c

https://gitlab.com/madscientist159/darkplaces
C | 1293 lines | 1136 code | 70 blank | 87 comment | 232 complexity | 673d2e87cb31149da3728c4034cdf042 MD5 | raw file
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "quakedef.h"
  16. #include "image.h"
  17. #include "r_shadow.h"
  18. #include "mod_skeletal_animatevertices_generic.h"
  19. #ifdef SSE_POSSIBLE
  20. #include "mod_skeletal_animatevertices_sse.h"
  21. #endif
  22. #ifdef SSE_POSSIBLE
  23. static qboolean r_skeletal_use_sse_defined = false;
  24. cvar_t r_skeletal_use_sse = {0, "r_skeletal_use_sse", "1", "use SSE for skeletal model animation"};
  25. #endif
  26. cvar_t r_skeletal_debugbone = {0, "r_skeletal_debugbone", "-1", "development cvar for testing skeletal model code"};
  27. cvar_t r_skeletal_debugbonecomponent = {0, "r_skeletal_debugbonecomponent", "3", "development cvar for testing skeletal model code"};
  28. cvar_t r_skeletal_debugbonevalue = {0, "r_skeletal_debugbonevalue", "100", "development cvar for testing skeletal model code"};
  29. cvar_t r_skeletal_debugtranslatex = {0, "r_skeletal_debugtranslatex", "1", "development cvar for testing skeletal model code"};
  30. cvar_t r_skeletal_debugtranslatey = {0, "r_skeletal_debugtranslatey", "1", "development cvar for testing skeletal model code"};
  31. cvar_t r_skeletal_debugtranslatez = {0, "r_skeletal_debugtranslatez", "1", "development cvar for testing skeletal model code"};
  32. cvar_t mod_alias_supporttagscale = {0, "mod_alias_supporttagscale", "1", "support scaling factors in bone/tag attachment matrices as supported by MD3"};
  33. cvar_t mod_alias_force_animated = {0, "mod_alias_force_animated", "", "if set to an non-empty string, overrides the is-animated flag of any alias models (for benchmarking)"};
  34. float mod_md3_sin[320];
  35. static size_t Mod_Skeletal_AnimateVertices_maxbonepose = 0;
  36. static void *Mod_Skeletal_AnimateVertices_bonepose = NULL;
  37. void Mod_Skeletal_FreeBuffers(void)
  38. {
  39. if(Mod_Skeletal_AnimateVertices_bonepose)
  40. Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
  41. Mod_Skeletal_AnimateVertices_maxbonepose = 0;
  42. Mod_Skeletal_AnimateVertices_bonepose = NULL;
  43. }
  44. void *Mod_Skeletal_AnimateVertices_AllocBuffers(size_t nbytes)
  45. {
  46. if(Mod_Skeletal_AnimateVertices_maxbonepose < nbytes)
  47. {
  48. if(Mod_Skeletal_AnimateVertices_bonepose)
  49. Mem_Free(Mod_Skeletal_AnimateVertices_bonepose);
  50. Mod_Skeletal_AnimateVertices_bonepose = Z_Malloc(nbytes);
  51. Mod_Skeletal_AnimateVertices_maxbonepose = nbytes;
  52. }
  53. return Mod_Skeletal_AnimateVertices_bonepose;
  54. }
  55. void Mod_Skeletal_BuildTransforms(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT bonepose, float * RESTRICT boneposerelative)
  56. {
  57. int i, blends;
  58. float m[12];
  59. if (!bonepose)
  60. bonepose = (float * RESTRICT) Mod_Skeletal_AnimateVertices_AllocBuffers(sizeof(float[12]) * model->num_bones);
  61. if (skeleton && !skeleton->relativetransforms)
  62. skeleton = NULL;
  63. // interpolate matrices
  64. if (skeleton)
  65. {
  66. for (i = 0;i < model->num_bones;i++)
  67. {
  68. Matrix4x4_ToArray12FloatD3D(&skeleton->relativetransforms[i], m);
  69. if (model->data_bones[i].parent >= 0)
  70. R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
  71. else
  72. memcpy(bonepose + i * 12, m, sizeof(m));
  73. // create a relative deformation matrix to describe displacement
  74. // from the base mesh, which is used by the actual weighting
  75. R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
  76. }
  77. }
  78. else
  79. {
  80. for (i = 0;i < model->num_bones;i++)
  81. {
  82. // blend by transform each quaternion/translation into a dual-quaternion first, then blending
  83. const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[0].subframe * model->num_bones + i);
  84. float lerp = frameblend[0].lerp,
  85. tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
  86. rx = pose7s[3] * lerp,
  87. ry = pose7s[4] * lerp,
  88. rz = pose7s[5] * lerp,
  89. rw = pose7s[6] * lerp,
  90. dx = tx*rw + ty*rz - tz*ry,
  91. dy = -tx*rz + ty*rw + tz*rx,
  92. dz = tx*ry - ty*rx + tz*rw,
  93. dw = -tx*rx - ty*ry - tz*rz,
  94. scale, sx, sy, sz, sw;
  95. for (blends = 1;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
  96. {
  97. const short * RESTRICT pose7s = model->data_poses7s + 7 * (frameblend[blends].subframe * model->num_bones + i);
  98. float lerp = frameblend[blends].lerp,
  99. tx = pose7s[0], ty = pose7s[1], tz = pose7s[2],
  100. qx = pose7s[3], qy = pose7s[4], qz = pose7s[5], qw = pose7s[6];
  101. if(rx*qx + ry*qy + rz*qz + rw*qw < 0) lerp = -lerp;
  102. qx *= lerp;
  103. qy *= lerp;
  104. qz *= lerp;
  105. qw *= lerp;
  106. rx += qx;
  107. ry += qy;
  108. rz += qz;
  109. rw += qw;
  110. dx += tx*qw + ty*qz - tz*qy;
  111. dy += -tx*qz + ty*qw + tz*qx;
  112. dz += tx*qy - ty*qx + tz*qw;
  113. dw += -tx*qx - ty*qy - tz*qz;
  114. }
  115. // generate a matrix from the dual-quaternion, implicitly normalizing it in the process
  116. scale = 1.0f / (rx*rx + ry*ry + rz*rz + rw*rw);
  117. sx = rx * scale;
  118. sy = ry * scale;
  119. sz = rz * scale;
  120. sw = rw * scale;
  121. m[0] = sw*rw + sx*rx - sy*ry - sz*rz;
  122. m[1] = 2*(sx*ry - sw*rz);
  123. m[2] = 2*(sx*rz + sw*ry);
  124. m[3] = model->num_posescale*(dx*sw - dy*sz + dz*sy - dw*sx);
  125. m[4] = 2*(sx*ry + sw*rz);
  126. m[5] = sw*rw + sy*ry - sx*rx - sz*rz;
  127. m[6] = 2*(sy*rz - sw*rx);
  128. m[7] = model->num_posescale*(dx*sz + dy*sw - dz*sx - dw*sy);
  129. m[8] = 2*(sx*rz - sw*ry);
  130. m[9] = 2*(sy*rz + sw*rx);
  131. m[10] = sw*rw + sz*rz - sx*rx - sy*ry;
  132. m[11] = model->num_posescale*(dy*sx + dz*sw - dx*sy - dw*sz);
  133. if (i == r_skeletal_debugbone.integer)
  134. m[r_skeletal_debugbonecomponent.integer % 12] += r_skeletal_debugbonevalue.value;
  135. m[3] *= r_skeletal_debugtranslatex.value;
  136. m[7] *= r_skeletal_debugtranslatey.value;
  137. m[11] *= r_skeletal_debugtranslatez.value;
  138. if (model->data_bones[i].parent >= 0)
  139. R_ConcatTransforms(bonepose + model->data_bones[i].parent * 12, m, bonepose + i * 12);
  140. else
  141. memcpy(bonepose + i * 12, m, sizeof(m));
  142. // create a relative deformation matrix to describe displacement
  143. // from the base mesh, which is used by the actual weighting
  144. R_ConcatTransforms(bonepose + i * 12, model->data_baseboneposeinverse + i * 12, boneposerelative + i * 12);
  145. }
  146. }
  147. }
  148. static void Mod_Skeletal_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
  149. {
  150. if (!model->surfmesh.num_vertices)
  151. return;
  152. if (!model->num_bones)
  153. {
  154. if (vertex3f) memcpy(vertex3f, model->surfmesh.data_vertex3f, model->surfmesh.num_vertices*sizeof(float[3]));
  155. if (normal3f) memcpy(normal3f, model->surfmesh.data_normal3f, model->surfmesh.num_vertices*sizeof(float[3]));
  156. if (svector3f) memcpy(svector3f, model->surfmesh.data_svector3f, model->surfmesh.num_vertices*sizeof(float[3]));
  157. if (tvector3f) memcpy(tvector3f, model->surfmesh.data_tvector3f, model->surfmesh.num_vertices*sizeof(float[3]));
  158. return;
  159. }
  160. #ifdef SSE_POSSIBLE
  161. if(r_skeletal_use_sse_defined)
  162. if(r_skeletal_use_sse.integer)
  163. {
  164. Mod_Skeletal_AnimateVertices_SSE(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
  165. return;
  166. }
  167. #endif
  168. Mod_Skeletal_AnimateVertices_Generic(model, frameblend, skeleton, vertex3f, normal3f, svector3f, tvector3f);
  169. }
  170. void Mod_AliasInit (void)
  171. {
  172. int i;
  173. Cvar_RegisterVariable(&r_skeletal_debugbone);
  174. Cvar_RegisterVariable(&r_skeletal_debugbonecomponent);
  175. Cvar_RegisterVariable(&r_skeletal_debugbonevalue);
  176. Cvar_RegisterVariable(&r_skeletal_debugtranslatex);
  177. Cvar_RegisterVariable(&r_skeletal_debugtranslatey);
  178. Cvar_RegisterVariable(&r_skeletal_debugtranslatez);
  179. Cvar_RegisterVariable(&mod_alias_supporttagscale);
  180. Cvar_RegisterVariable(&mod_alias_force_animated);
  181. for (i = 0;i < 320;i++)
  182. mod_md3_sin[i] = sin(i * M_PI * 2.0f / 256.0);
  183. #ifdef SSE_POSSIBLE
  184. if(Sys_HaveSSE())
  185. {
  186. Con_Printf("Skeletal animation uses SSE code path\n");
  187. r_skeletal_use_sse_defined = true;
  188. Cvar_RegisterVariable(&r_skeletal_use_sse);
  189. }
  190. else
  191. Con_Printf("Skeletal animation uses generic code path (SSE disabled or not detected)\n");
  192. #else
  193. Con_Printf("Skeletal animation uses generic code path (SSE not compiled in)\n");
  194. #endif
  195. }
  196. static int Mod_Skeletal_AddBlend(dp_model_t *model, const blendweights_t *newweights)
  197. {
  198. int i;
  199. blendweights_t *weights;
  200. if(!newweights->influence[1])
  201. return newweights->index[0];
  202. weights = model->surfmesh.data_blendweights;
  203. for (i = 0;i < model->surfmesh.num_blends;i++, weights++)
  204. {
  205. if (!memcmp(weights, newweights, sizeof(blendweights_t)))
  206. return model->num_bones + i;
  207. }
  208. model->surfmesh.num_blends++;
  209. memcpy(weights, newweights, sizeof(blendweights_t));
  210. return model->num_bones + i;
  211. }
  212. static int Mod_Skeletal_CompressBlend(dp_model_t *model, const int *newindex, const float *newinfluence)
  213. {
  214. int i, total;
  215. float scale;
  216. blendweights_t newweights;
  217. if(!newinfluence[1])
  218. return newindex[0];
  219. scale = 0;
  220. for (i = 0;i < 4;i++)
  221. scale += newinfluence[i];
  222. scale = 255.0f / scale;
  223. total = 0;
  224. for (i = 0;i < 4;i++)
  225. {
  226. newweights.index[i] = newindex[i];
  227. newweights.influence[i] = (unsigned char)(newinfluence[i] * scale);
  228. total += newweights.influence[i];
  229. }
  230. while (total > 255)
  231. {
  232. for (i = 0;i < 4;i++)
  233. {
  234. if(newweights.influence[i] > 0 && total > 255)
  235. {
  236. newweights.influence[i]--;
  237. total--;
  238. }
  239. }
  240. }
  241. while (total < 255)
  242. {
  243. for (i = 0; i < 4;i++)
  244. {
  245. if(newweights.influence[i] < 255 && total < 255)
  246. {
  247. newweights.influence[i]++;
  248. total++;
  249. }
  250. }
  251. }
  252. return Mod_Skeletal_AddBlend(model, &newweights);
  253. }
  254. static void Mod_MD3_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
  255. {
  256. // vertex morph
  257. int i, numblends, blendnum;
  258. int numverts = model->surfmesh.num_vertices;
  259. numblends = 0;
  260. for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
  261. {
  262. //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
  263. if (frameblend[blendnum].lerp > 0)
  264. numblends = blendnum + 1;
  265. }
  266. // special case for the first blend because it avoids some adds and the need to memset the arrays first
  267. for (blendnum = 0;blendnum < numblends;blendnum++)
  268. {
  269. const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
  270. if (vertex3f)
  271. {
  272. float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
  273. if (blendnum == 0)
  274. {
  275. for (i = 0;i < numverts;i++)
  276. {
  277. vertex3f[i * 3 + 0] = verts[i].origin[0] * scale;
  278. vertex3f[i * 3 + 1] = verts[i].origin[1] * scale;
  279. vertex3f[i * 3 + 2] = verts[i].origin[2] * scale;
  280. }
  281. }
  282. else
  283. {
  284. for (i = 0;i < numverts;i++)
  285. {
  286. vertex3f[i * 3 + 0] += verts[i].origin[0] * scale;
  287. vertex3f[i * 3 + 1] += verts[i].origin[1] * scale;
  288. vertex3f[i * 3 + 2] += verts[i].origin[2] * scale;
  289. }
  290. }
  291. }
  292. // the yaw and pitch stored in md3 models are 8bit quantized angles
  293. // (0-255), and as such a lookup table is very well suited to
  294. // decoding them, and since cosine is equivalent to sine with an
  295. // extra 45 degree rotation, this uses one lookup table for both
  296. // sine and cosine with a +64 bias to get cosine.
  297. if (normal3f)
  298. {
  299. float lerp = frameblend[blendnum].lerp;
  300. if (blendnum == 0)
  301. {
  302. for (i = 0;i < numverts;i++)
  303. {
  304. normal3f[i * 3 + 0] = mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
  305. normal3f[i * 3 + 1] = mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
  306. normal3f[i * 3 + 2] = mod_md3_sin[verts[i].pitch + 64] * lerp;
  307. }
  308. }
  309. else
  310. {
  311. for (i = 0;i < numverts;i++)
  312. {
  313. normal3f[i * 3 + 0] += mod_md3_sin[verts[i].yaw + 64] * mod_md3_sin[verts[i].pitch ] * lerp;
  314. normal3f[i * 3 + 1] += mod_md3_sin[verts[i].yaw ] * mod_md3_sin[verts[i].pitch ] * lerp;
  315. normal3f[i * 3 + 2] += mod_md3_sin[verts[i].pitch + 64] * lerp;
  316. }
  317. }
  318. }
  319. if (svector3f)
  320. {
  321. const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
  322. float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
  323. if (blendnum == 0)
  324. {
  325. for (i = 0;i < numverts;i++, texvecvert++)
  326. {
  327. VectorScale(texvecvert->svec, f, svector3f + i*3);
  328. VectorScale(texvecvert->tvec, f, tvector3f + i*3);
  329. }
  330. }
  331. else
  332. {
  333. for (i = 0;i < numverts;i++, texvecvert++)
  334. {
  335. VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
  336. VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
  337. }
  338. }
  339. }
  340. }
  341. }
  342. static void Mod_MDL_AnimateVertices(const dp_model_t * RESTRICT model, const frameblend_t * RESTRICT frameblend, const skeleton_t *skeleton, float * RESTRICT vertex3f, float * RESTRICT normal3f, float * RESTRICT svector3f, float * RESTRICT tvector3f)
  343. {
  344. // vertex morph
  345. int i, numblends, blendnum;
  346. int numverts = model->surfmesh.num_vertices;
  347. float translate[3];
  348. VectorClear(translate);
  349. numblends = 0;
  350. // blend the frame translates to avoid redundantly doing so on each vertex
  351. // (a bit of a brain twister but it works)
  352. for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
  353. {
  354. if (model->surfmesh.data_morphmd2framesize6f)
  355. VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
  356. else
  357. VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
  358. if (frameblend[blendnum].lerp > 0)
  359. numblends = blendnum + 1;
  360. }
  361. // special case for the first blend because it avoids some adds and the need to memset the arrays first
  362. for (blendnum = 0;blendnum < numblends;blendnum++)
  363. {
  364. const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
  365. if (vertex3f)
  366. {
  367. float scale[3];
  368. if (model->surfmesh.data_morphmd2framesize6f)
  369. VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
  370. else
  371. VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
  372. if (blendnum == 0)
  373. {
  374. for (i = 0;i < numverts;i++)
  375. {
  376. vertex3f[i * 3 + 0] = translate[0] + verts[i].v[0] * scale[0];
  377. vertex3f[i * 3 + 1] = translate[1] + verts[i].v[1] * scale[1];
  378. vertex3f[i * 3 + 2] = translate[2] + verts[i].v[2] * scale[2];
  379. }
  380. }
  381. else
  382. {
  383. for (i = 0;i < numverts;i++)
  384. {
  385. vertex3f[i * 3 + 0] += verts[i].v[0] * scale[0];
  386. vertex3f[i * 3 + 1] += verts[i].v[1] * scale[1];
  387. vertex3f[i * 3 + 2] += verts[i].v[2] * scale[2];
  388. }
  389. }
  390. }
  391. // the vertex normals in mdl models are an index into a table of
  392. // 162 unique values, this very crude quantization reduces the
  393. // vertex normal to only one byte, which saves a lot of space but
  394. // also makes lighting pretty coarse
  395. if (normal3f)
  396. {
  397. float lerp = frameblend[blendnum].lerp;
  398. if (blendnum == 0)
  399. {
  400. for (i = 0;i < numverts;i++)
  401. {
  402. const float *vn = m_bytenormals[verts[i].lightnormalindex];
  403. VectorScale(vn, lerp, normal3f + i*3);
  404. }
  405. }
  406. else
  407. {
  408. for (i = 0;i < numverts;i++)
  409. {
  410. const float *vn = m_bytenormals[verts[i].lightnormalindex];
  411. VectorMA(normal3f + i*3, lerp, vn, normal3f + i*3);
  412. }
  413. }
  414. }
  415. if (svector3f)
  416. {
  417. const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
  418. float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
  419. if (blendnum == 0)
  420. {
  421. for (i = 0;i < numverts;i++, texvecvert++)
  422. {
  423. VectorScale(texvecvert->svec, f, svector3f + i*3);
  424. VectorScale(texvecvert->tvec, f, tvector3f + i*3);
  425. }
  426. }
  427. else
  428. {
  429. for (i = 0;i < numverts;i++, texvecvert++)
  430. {
  431. VectorMA(svector3f + i*3, f, texvecvert->svec, svector3f + i*3);
  432. VectorMA(tvector3f + i*3, f, texvecvert->tvec, tvector3f + i*3);
  433. }
  434. }
  435. }
  436. }
  437. }
  438. int Mod_Alias_GetTagMatrix(const dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, matrix4x4_t *outmatrix)
  439. {
  440. matrix4x4_t temp;
  441. matrix4x4_t parentbonematrix;
  442. matrix4x4_t tempbonematrix;
  443. matrix4x4_t bonematrix;
  444. matrix4x4_t blendmatrix;
  445. int blendindex;
  446. int parenttagindex;
  447. int k;
  448. float lerp;
  449. const float *input;
  450. float blendtag[12];
  451. *outmatrix = identitymatrix;
  452. if (skeleton && skeleton->relativetransforms)
  453. {
  454. if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
  455. return 4;
  456. *outmatrix = skeleton->relativetransforms[tagindex];
  457. while ((tagindex = model->data_bones[tagindex].parent) >= 0)
  458. {
  459. temp = *outmatrix;
  460. Matrix4x4_Concat(outmatrix, &skeleton->relativetransforms[tagindex], &temp);
  461. }
  462. }
  463. else if (model->num_bones)
  464. {
  465. if (tagindex < 0 || tagindex >= model->num_bones)
  466. return 4;
  467. Matrix4x4_Clear(&blendmatrix);
  468. for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
  469. {
  470. lerp = frameblend[blendindex].lerp;
  471. Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
  472. parenttagindex = tagindex;
  473. while ((parenttagindex = model->data_bones[parenttagindex].parent) >= 0)
  474. {
  475. Matrix4x4_FromBonePose7s(&parentbonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + parenttagindex));
  476. tempbonematrix = bonematrix;
  477. Matrix4x4_Concat(&bonematrix, &parentbonematrix, &tempbonematrix);
  478. }
  479. Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
  480. }
  481. *outmatrix = blendmatrix;
  482. }
  483. else if (model->num_tags)
  484. {
  485. if (tagindex < 0 || tagindex >= model->num_tags)
  486. return 4;
  487. for (k = 0;k < 12;k++)
  488. blendtag[k] = 0;
  489. for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
  490. {
  491. lerp = frameblend[blendindex].lerp;
  492. input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
  493. for (k = 0;k < 12;k++)
  494. blendtag[k] += input[k] * lerp;
  495. }
  496. Matrix4x4_FromArray12FloatGL(outmatrix, blendtag);
  497. }
  498. if(!mod_alias_supporttagscale.integer)
  499. Matrix4x4_Normalize3(outmatrix, outmatrix);
  500. return 0;
  501. }
  502. int Mod_Alias_GetExtendedTagInfoForIndex(const dp_model_t *model, unsigned int skin, const frameblend_t *frameblend, const skeleton_t *skeleton, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
  503. {
  504. int blendindex;
  505. int k;
  506. float lerp;
  507. matrix4x4_t bonematrix;
  508. matrix4x4_t blendmatrix;
  509. const float *input;
  510. float blendtag[12];
  511. if (skeleton && skeleton->relativetransforms)
  512. {
  513. if (tagindex < 0 || tagindex >= skeleton->model->num_bones)
  514. return 1;
  515. *parentindex = skeleton->model->data_bones[tagindex].parent;
  516. *tagname = skeleton->model->data_bones[tagindex].name;
  517. *tag_localmatrix = skeleton->relativetransforms[tagindex];
  518. return 0;
  519. }
  520. else if (model->num_bones)
  521. {
  522. if (tagindex < 0 || tagindex >= model->num_bones)
  523. return 1;
  524. *parentindex = model->data_bones[tagindex].parent;
  525. *tagname = model->data_bones[tagindex].name;
  526. Matrix4x4_Clear(&blendmatrix);
  527. for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
  528. {
  529. lerp = frameblend[blendindex].lerp;
  530. Matrix4x4_FromBonePose7s(&bonematrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + tagindex));
  531. Matrix4x4_Accumulate(&blendmatrix, &bonematrix, lerp);
  532. }
  533. *tag_localmatrix = blendmatrix;
  534. return 0;
  535. }
  536. else if (model->num_tags)
  537. {
  538. if (tagindex < 0 || tagindex >= model->num_tags)
  539. return 1;
  540. *parentindex = -1;
  541. *tagname = model->data_tags[tagindex].name;
  542. for (k = 0;k < 12;k++)
  543. blendtag[k] = 0;
  544. for (blendindex = 0;blendindex < MAX_FRAMEBLENDS && frameblend[blendindex].lerp > 0;blendindex++)
  545. {
  546. lerp = frameblend[blendindex].lerp;
  547. input = model->data_tags[frameblend[blendindex].subframe * model->num_tags + tagindex].matrixgl;
  548. for (k = 0;k < 12;k++)
  549. blendtag[k] += input[k] * lerp;
  550. }
  551. Matrix4x4_FromArray12FloatGL(tag_localmatrix, blendtag);
  552. return 0;
  553. }
  554. return 2;
  555. }
  556. int Mod_Alias_GetTagIndexForName(const dp_model_t *model, unsigned int skin, const char *tagname)
  557. {
  558. int i;
  559. if(skin >= (unsigned int)model->numskins)
  560. skin = 0;
  561. if (model->num_bones)
  562. for (i = 0;i < model->num_bones;i++)
  563. if (!strcasecmp(tagname, model->data_bones[i].name))
  564. return i + 1;
  565. if (model->num_tags)
  566. for (i = 0;i < model->num_tags;i++)
  567. if (!strcasecmp(tagname, model->data_tags[i].name))
  568. return i + 1;
  569. return 0;
  570. }
  571. static void Mod_BuildBaseBonePoses(void)
  572. {
  573. int boneindex;
  574. matrix4x4_t *basebonepose;
  575. float *outinvmatrix = loadmodel->data_baseboneposeinverse;
  576. matrix4x4_t bonematrix;
  577. matrix4x4_t tempbonematrix;
  578. if (!loadmodel->num_bones)
  579. return;
  580. basebonepose = (matrix4x4_t *)Mem_Alloc(tempmempool, loadmodel->num_bones * sizeof(matrix4x4_t));
  581. for (boneindex = 0;boneindex < loadmodel->num_bones;boneindex++)
  582. {
  583. Matrix4x4_FromBonePose7s(&bonematrix, loadmodel->num_posescale, loadmodel->data_poses7s + 7 * boneindex);
  584. if (loadmodel->data_bones[boneindex].parent >= 0)
  585. {
  586. tempbonematrix = bonematrix;
  587. Matrix4x4_Concat(&bonematrix, basebonepose + loadmodel->data_bones[boneindex].parent, &tempbonematrix);
  588. }
  589. basebonepose[boneindex] = bonematrix;
  590. Matrix4x4_Invert_Simple(&tempbonematrix, basebonepose + boneindex);
  591. Matrix4x4_ToArray12FloatD3D(&tempbonematrix, outinvmatrix + 12*boneindex);
  592. }
  593. Mem_Free(basebonepose);
  594. }
  595. static qboolean Mod_Alias_CalculateBoundingBox(void)
  596. {
  597. int vnum;
  598. qboolean firstvertex = true;
  599. float dist, yawradius, radius;
  600. float *v;
  601. qboolean isanimated = false;
  602. VectorClear(loadmodel->normalmins);
  603. VectorClear(loadmodel->normalmaxs);
  604. yawradius = 0;
  605. radius = 0;
  606. if (loadmodel->AnimateVertices)
  607. {
  608. float *vertex3f, *refvertex3f;
  609. frameblend_t frameblend[MAX_FRAMEBLENDS];
  610. memset(frameblend, 0, sizeof(frameblend));
  611. frameblend[0].lerp = 1;
  612. vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]) * 2);
  613. refvertex3f = NULL;
  614. for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
  615. {
  616. loadmodel->AnimateVertices(loadmodel, frameblend, NULL, vertex3f, NULL, NULL, NULL);
  617. if (!refvertex3f)
  618. {
  619. // make a copy of the first frame for comparing all others
  620. refvertex3f = vertex3f + loadmodel->surfmesh.num_vertices * 3;
  621. memcpy(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
  622. }
  623. else
  624. {
  625. if (!isanimated && memcmp(refvertex3f, vertex3f, loadmodel->surfmesh.num_vertices * sizeof(float[3])))
  626. isanimated = true;
  627. }
  628. for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
  629. {
  630. if (firstvertex)
  631. {
  632. firstvertex = false;
  633. VectorCopy(v, loadmodel->normalmins);
  634. VectorCopy(v, loadmodel->normalmaxs);
  635. }
  636. else
  637. {
  638. if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
  639. if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
  640. if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
  641. if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
  642. if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
  643. if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
  644. }
  645. dist = v[0] * v[0] + v[1] * v[1];
  646. if (yawradius < dist)
  647. yawradius = dist;
  648. dist += v[2] * v[2];
  649. if (radius < dist)
  650. radius = dist;
  651. }
  652. }
  653. if (vertex3f)
  654. Mem_Free(vertex3f);
  655. }
  656. else
  657. {
  658. for (vnum = 0, v = loadmodel->surfmesh.data_vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
  659. {
  660. if (firstvertex)
  661. {
  662. firstvertex = false;
  663. VectorCopy(v, loadmodel->normalmins);
  664. VectorCopy(v, loadmodel->normalmaxs);
  665. }
  666. else
  667. {
  668. if (loadmodel->normalmins[0] > v[0]) loadmodel->normalmins[0] = v[0];
  669. if (loadmodel->normalmins[1] > v[1]) loadmodel->normalmins[1] = v[1];
  670. if (loadmodel->normalmins[2] > v[2]) loadmodel->normalmins[2] = v[2];
  671. if (loadmodel->normalmaxs[0] < v[0]) loadmodel->normalmaxs[0] = v[0];
  672. if (loadmodel->normalmaxs[1] < v[1]) loadmodel->normalmaxs[1] = v[1];
  673. if (loadmodel->normalmaxs[2] < v[2]) loadmodel->normalmaxs[2] = v[2];
  674. }
  675. dist = v[0] * v[0] + v[1] * v[1];
  676. if (yawradius < dist)
  677. yawradius = dist;
  678. dist += v[2] * v[2];
  679. if (radius < dist)
  680. radius = dist;
  681. }
  682. }
  683. radius = sqrt(radius);
  684. yawradius = sqrt(yawradius);
  685. loadmodel->yawmins[0] = loadmodel->yawmins[1] = -yawradius;
  686. loadmodel->yawmaxs[0] = loadmodel->yawmaxs[1] = yawradius;
  687. loadmodel->yawmins[2] = loadmodel->normalmins[2];
  688. loadmodel->yawmaxs[2] = loadmodel->normalmaxs[2];
  689. loadmodel->rotatedmins[0] = loadmodel->rotatedmins[1] = loadmodel->rotatedmins[2] = -radius;
  690. loadmodel->rotatedmaxs[0] = loadmodel->rotatedmaxs[1] = loadmodel->rotatedmaxs[2] = radius;
  691. loadmodel->radius = radius;
  692. loadmodel->radius2 = radius * radius;
  693. return isanimated;
  694. }
  695. static void Mod_Alias_MorphMesh_CompileFrames(void)
  696. {
  697. int i, j;
  698. frameblend_t frameblend[MAX_FRAMEBLENDS];
  699. unsigned char *datapointer;
  700. memset(frameblend, 0, sizeof(frameblend));
  701. frameblend[0].lerp = 1;
  702. datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
  703. loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
  704. loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
  705. loadmodel->surfmesh.data_tvector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
  706. loadmodel->surfmesh.data_normal3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
  707. loadmodel->surfmesh.data_morphtexvecvertex = (texvecvertex_t *)datapointer;datapointer += loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices * sizeof(texvecvertex_t);
  708. // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
  709. for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
  710. {
  711. frameblend[0].subframe = i;
  712. loadmodel->AnimateVertices(loadmodel, frameblend, NULL, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
  713. Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0);
  714. // encode the svector and tvector in 3 byte format for permanent storage
  715. for (j = 0;j < loadmodel->surfmesh.num_vertices;j++)
  716. {
  717. VectorScaleCast(loadmodel->surfmesh.data_svector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].svec);
  718. VectorScaleCast(loadmodel->surfmesh.data_tvector3f + j * 3, 127.0f, signed char, loadmodel->surfmesh.data_morphtexvecvertex[i*loadmodel->surfmesh.num_vertices+j].tvec);
  719. }
  720. }
  721. }
  722. static void Mod_MDLMD2MD3_TraceLine(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask)
  723. {
  724. int i;
  725. float segmentmins[3], segmentmaxs[3];
  726. msurface_t *surface;
  727. float vertex3fbuf[1024*3];
  728. float *vertex3f = vertex3fbuf;
  729. memset(trace, 0, sizeof(*trace));
  730. trace->fraction = 1;
  731. trace->hitsupercontentsmask = hitsupercontentsmask;
  732. if (model->surfmesh.num_vertices > 1024)
  733. vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
  734. segmentmins[0] = min(start[0], end[0]) - 1;
  735. segmentmins[1] = min(start[1], end[1]) - 1;
  736. segmentmins[2] = min(start[2], end[2]) - 1;
  737. segmentmaxs[0] = max(start[0], end[0]) + 1;
  738. segmentmaxs[1] = max(start[1], end[1]) + 1;
  739. segmentmaxs[2] = max(start[2], end[2]) + 1;
  740. model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
  741. for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
  742. Collision_TraceLineTriangleMeshFloat(trace, start, end, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
  743. if (vertex3f != vertex3fbuf)
  744. Mem_Free(vertex3f);
  745. }
  746. static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
  747. {
  748. int i;
  749. vec3_t shiftstart, shiftend;
  750. float segmentmins[3], segmentmaxs[3];
  751. msurface_t *surface;
  752. float vertex3fbuf[1024*3];
  753. float *vertex3f = vertex3fbuf;
  754. colboxbrushf_t thisbrush_start, thisbrush_end;
  755. vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
  756. if (VectorCompare(boxmins, boxmaxs))
  757. {
  758. VectorAdd(start, boxmins, shiftstart);
  759. VectorAdd(end, boxmins, shiftend);
  760. Mod_MDLMD2MD3_TraceLine(model, frameblend, skeleton, trace, shiftstart, shiftend, hitsupercontentsmask);
  761. VectorSubtract(trace->endpos, boxmins, trace->endpos);
  762. return;
  763. }
  764. // box trace, performed as brush trace
  765. memset(trace, 0, sizeof(*trace));
  766. trace->fraction = 1;
  767. trace->hitsupercontentsmask = hitsupercontentsmask;
  768. if (model->surfmesh.num_vertices > 1024)
  769. vertex3f = (float *)Mem_Alloc(tempmempool, model->surfmesh.num_vertices * sizeof(float[3]));
  770. segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1;
  771. segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1;
  772. segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1;
  773. segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1;
  774. segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1;
  775. segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1;
  776. VectorAdd(start, boxmins, boxstartmins);
  777. VectorAdd(start, boxmaxs, boxstartmaxs);
  778. VectorAdd(end, boxmins, boxendmins);
  779. VectorAdd(end, boxmaxs, boxendmaxs);
  780. Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
  781. Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
  782. model->AnimateVertices(model, frameblend, skeleton, vertex3f, NULL, NULL, NULL);
  783. for (i = 0, surface = model->data_surfaces;i < model->num_surfaces;i++, surface++)
  784. Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, model->surfmesh.num_triangles, model->surfmesh.data_element3i, vertex3f, 0, NULL, SUPERCONTENTS_SOLID | (surface->texture->basematerialflags & MATERIALFLAGMASK_TRANSLUCENT ? 0 : SUPERCONTENTS_OPAQUE), 0, surface->texture, segmentmins, segmentmaxs);
  785. if (vertex3f != vertex3fbuf)
  786. Mem_Free(vertex3f);
  787. }
  788. static void Mod_ConvertAliasVerts (int inverts, trivertx_t *v, trivertx_t *out, int *vertremap)
  789. {
  790. int i, j;
  791. for (i = 0;i < inverts;i++)
  792. {
  793. if (vertremap[i] < 0 && vertremap[i+inverts] < 0) // only used vertices need apply...
  794. continue;
  795. j = vertremap[i]; // not onseam
  796. if (j >= 0)
  797. out[j] = v[i];
  798. j = vertremap[i+inverts]; // onseam
  799. if (j >= 0)
  800. out[j] = v[i];
  801. }
  802. }
  803. static void Mod_MDL_LoadFrames (unsigned char* datapointer, int inverts, int *vertremap)
  804. {
  805. int i, f, pose, groupframes;
  806. float interval;
  807. daliasframetype_t *pframetype;
  808. daliasframe_t *pinframe;
  809. daliasgroup_t *group;
  810. daliasinterval_t *intervals;
  811. animscene_t *scene;
  812. pose = 0;
  813. scene = loadmodel->animscenes;
  814. for (f = 0;f < loadmodel->numframes;f++)
  815. {
  816. pframetype = (daliasframetype_t *)datapointer;
  817. datapointer += sizeof(daliasframetype_t);
  818. if (LittleLong (pframetype->type) == ALIAS_SINGLE)
  819. {
  820. // a single frame is still treated as a group
  821. interval = 0.1f;
  822. groupframes = 1;
  823. }
  824. else
  825. {
  826. // read group header
  827. group = (daliasgroup_t *)datapointer;
  828. datapointer += sizeof(daliasgroup_t);
  829. groupframes = LittleLong (group->numframes);
  830. // intervals (time per frame)
  831. intervals = (daliasinterval_t *)datapointer;
  832. datapointer += sizeof(daliasinterval_t) * groupframes;
  833. interval = LittleFloat (intervals->interval); // FIXME: support variable framerate groups
  834. if (interval < 0.01f)
  835. {
  836. Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
  837. interval = 0.1f;
  838. }
  839. }
  840. // get scene name from first frame
  841. pinframe = (daliasframe_t *)datapointer;
  842. strlcpy(scene->name, pinframe->name, sizeof(scene->name));
  843. scene->firstframe = pose;
  844. scene->framecount = groupframes;
  845. scene->framerate = 1.0f / interval;
  846. scene->loop = true;
  847. scene++;
  848. // read frames
  849. for (i = 0;i < groupframes;i++)
  850. {
  851. datapointer += sizeof(daliasframe_t);
  852. Mod_ConvertAliasVerts(inverts, (trivertx_t *)datapointer, loadmodel->surfmesh.data_morphmdlvertex + pose * loadmodel->surfmesh.num_vertices, vertremap);
  853. datapointer += sizeof(trivertx_t) * inverts;
  854. pose++;
  855. }
  856. }
  857. }
  858. static void Mod_BuildAliasSkinFromSkinFrame(texture_t *texture, skinframe_t *skinframe)
  859. {
  860. if (cls.state == ca_dedicated)
  861. return;
  862. // hack
  863. if (!skinframe)
  864. skinframe = R_SkinFrame_LoadMissing();
  865. memset(texture, 0, sizeof(*texture));
  866. texture->currentframe = texture;
  867. //texture->animated = false;
  868. texture->numskinframes = 1;
  869. texture->skinframerate = 1;
  870. texture->skinframes[0] = skinframe;
  871. texture->currentskinframe = skinframe;
  872. //texture->backgroundnumskinframes = 0;
  873. //texture->customblendfunc[0] = 0;
  874. //texture->customblendfunc[1] = 0;
  875. //texture->surfaceflags = 0;
  876. //texture->supercontents = 0;
  877. //texture->surfaceparms = 0;
  878. //texture->textureflags = 0;
  879. texture->basematerialflags = MATERIALFLAG_WALL;
  880. texture->basealpha = 1.0f;
  881. if (texture->currentskinframe->hasalpha)
  882. texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
  883. texture->currentmaterialflags = texture->basematerialflags;
  884. texture->offsetmapping = OFFSETMAPPING_DEFAULT;
  885. texture->offsetscale = 1;
  886. texture->offsetbias = 0;
  887. texture->specularscalemod = 1;
  888. texture->specularpowermod = 1;
  889. texture->surfaceflags = 0;
  890. texture->supercontents = SUPERCONTENTS_SOLID;
  891. if (!(texture->basematerialflags & MATERIALFLAG_BLENDED))
  892. texture->supercontents |= SUPERCONTENTS_OPAQUE;
  893. texture->transparentsort = TRANSPARENTSORT_DISTANCE;
  894. // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
  895. // JUST GREP FOR "specularscalemod = 1".
  896. }
  897. void Mod_BuildAliasSkinsFromSkinFiles(texture_t *skin, skinfile_t *skinfile, const char *meshname, const char *shadername)
  898. {
  899. int i;
  900. char stripbuf[MAX_QPATH];
  901. skinfileitem_t *skinfileitem;
  902. if(developer_extra.integer)
  903. Con_DPrintf("Looking up texture for %s (default: %s)\n", meshname, shadername);
  904. if (skinfile)
  905. {
  906. // the skin += loadmodel->num_surfaces part of this is because data_textures on alias models is arranged as [numskins][numsurfaces]
  907. for (i = 0;skinfile;skinfile = skinfile->next, i++, skin += loadmodel->num_surfaces)
  908. {
  909. memset(skin, 0, sizeof(*skin));
  910. // see if a mesh
  911. for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = skinfileitem->next)
  912. {
  913. // leave the skin unitialized (nodraw) if the replacement is "common/nodraw" or "textures/common/nodraw"
  914. if (!strcmp(skinfileitem->name, meshname))
  915. {
  916. Image_StripImageExtension(skinfileitem->replacement, stripbuf, sizeof(stripbuf));
  917. if(developer_extra.integer)
  918. Con_DPrintf("--> got %s from skin file\n", stripbuf);
  919. Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
  920. break;
  921. }
  922. }
  923. if (!skinfileitem)
  924. {
  925. // don't render unmentioned meshes
  926. Mod_BuildAliasSkinFromSkinFrame(skin, NULL);
  927. if(developer_extra.integer)
  928. Con_DPrintf("--> skipping\n");
  929. skin->basematerialflags = skin->currentmaterialflags = MATERIALFLAG_NOSHADOW | MATERIALFLAG_NODRAW;
  930. }
  931. }
  932. }
  933. else
  934. {
  935. if(developer_extra.integer)
  936. Con_DPrintf("--> using default\n");
  937. Image_StripImageExtension(shadername, stripbuf, sizeof(stripbuf));
  938. Mod_LoadTextureFromQ3Shader(skin, stripbuf, true, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS);
  939. }
  940. }
  941. #define BOUNDI(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%d exceeds %d - %d)", loadmodel->name, VALUE, MIN, MAX);
  942. #define BOUNDF(VALUE,MIN,MAX) if (VALUE < MIN || VALUE >= MAX) Host_Error("model %s has an invalid ##VALUE (%f exceeds %f - %f)", loadmodel->name, VALUE, MIN, MAX);
  943. void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
  944. {
  945. int i, j, version, totalskins, skinwidth, skinheight, groupframes, groupskins, numverts;
  946. float scales, scalet, interval;
  947. msurface_t *surface;
  948. unsigned char *data;
  949. mdl_t *pinmodel;
  950. stvert_t *pinstverts;
  951. dtriangle_t *pintriangles;
  952. daliasskintype_t *pinskintype;
  953. daliasskingroup_t *pinskingroup;
  954. daliasskininterval_t *pinskinintervals;
  955. daliasframetype_t *pinframetype;
  956. daliasgroup_t *pinframegroup;
  957. unsigned char *datapointer, *startframes, *startskins;
  958. char name[MAX_QPATH];
  959. skinframe_t *tempskinframe;
  960. animscene_t *tempskinscenes;
  961. texture_t *tempaliasskins;
  962. float *vertst;
  963. int *vertonseam, *vertremap;
  964. skinfile_t *skinfiles;
  965. char vabuf[1024];
  966. datapointer = (unsigned char *)buffer;
  967. pinmodel = (mdl_t *)datapointer;
  968. datapointer += sizeof(mdl_t);
  969. version = LittleLong (pinmodel->version);
  970. if (version != ALIAS_VERSION)
  971. Host_Error ("%s has wrong version number (%i should be %i)",
  972. loadmodel->name, version, ALIAS_VERSION);
  973. loadmodel->modeldatatypestring = "MDL";
  974. loadmodel->type = mod_alias;
  975. loadmodel->DrawSky = NULL;
  976. loadmodel->DrawAddWaterPlanes = NULL;
  977. loadmodel->Draw = R_Q1BSP_Draw;
  978. loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
  979. loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
  980. loadmodel->DrawPrepass = R_Q1BSP_DrawPrepass;
  981. loadmodel->CompileShadowMap = R_Q1BSP_CompileShadowMap;
  982. loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
  983. loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
  984. loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
  985. loadmodel->DrawLight = R_Q1BSP_DrawLight;
  986. loadmodel->TraceBox = Mod_MDLMD2MD3_TraceBox;
  987. loadmodel->TraceLine = Mod_MDLMD2MD3_TraceLine;
  988. // FIXME add TraceBrush!
  989. loadmodel->PointSuperContents = NULL;
  990. loadmodel->AnimateVertices = Mod_MDL_AnimateVertices;
  991. loadmodel->num_surfaces = 1;
  992. loadmodel->nummodelsurfaces = loadmodel->num_surfaces;
  993. data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int));
  994. loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t);
  995. loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int);
  996. loadmodel->sortedmodelsurfaces[0] = 0;
  997. loadmodel->numskins = LittleLong(pinmodel->numskins);
  998. BOUNDI(loadmodel->numskins,0,65536);
  999. skinwidth = LittleLong (pinmodel->skinwidth);
  1000. BOUNDI(skinwidth,0,65536);
  1001. skinheight = LittleLong (pinmodel->skinheight);
  1002. BOUNDI(skinheight,0,65536);
  1003. numverts = LittleLong(pinmodel->numverts);
  1004. BOUNDI(numverts,0,65536);
  1005. loadmodel->surfmesh.num_triangles = LittleLong(pinmodel->numtris);
  1006. BOUNDI(loadmodel->surfmesh.num_triangles,0,65536);
  1007. loadmodel->numframes = LittleLong(pinmodel->numframes);
  1008. BOUNDI(loadmodel->numframes,0,65536);
  1009. loadmodel->synctype = (synctype_t)LittleLong (pinmodel->synctype);
  1010. BOUNDI((int)loadmodel->synctype,0,2);
  1011. // convert model flags to EF flags (MF_ROCKET becomes EF_ROCKET, etc)
  1012. i = LittleLong (pinmodel->flags);
  1013. loadmodel->effects = ((i & 255) << 24) | (i & 0x00FFFF00);
  1014. for (i = 0;i < 3;i++)
  1015. {
  1016. loadmodel->surfmesh.num_morphmdlframescale[i] = LittleFloat (pinmodel->scale[i]);
  1017. loadmodel->surfmesh.num_morphmdlframetranslate[i] = LittleFloat (pinmodel->scale_origin[i]);
  1018. }
  1019. startskins = datapointer;
  1020. totalskins = 0;
  1021. for (i = 0;i < loadmodel->numskins;i++)
  1022. {
  1023. pinskintype = (daliasskintype_t *)datapointer;
  1024. datapointer += sizeof(daliasskintype_t);
  1025. if (LittleLong(pinskintype->type) == ALIAS_SKIN_SINGLE)
  1026. groupskins = 1;
  1027. else
  1028. {
  1029. pinskingroup = (daliasskingroup_t *)datapointer;
  1030. datapointer += sizeof(daliasskingroup_t);
  1031. groupskins = LittleLong(pinskingroup->numskins);
  1032. datapointer += sizeof(daliasskininterval_t) * groupskins;
  1033. }
  1034. for (j = 0;j < groupskins;j++)
  1035. {
  1036. datapointer += skinwidth * skinheight;
  1037. totalskins++;
  1038. }
  1039. }
  1040. pinstverts = (stvert_t *)datapointer;
  1041. datapointer += sizeof(stvert_t) * numverts;
  1042. pintriangles = (dtriangle_t *)datapointer;
  1043. datapointer += sizeof(dtriangle_t) * loadmodel->surfmesh.num_triangles;
  1044. startframes = datapointer;
  1045. loadmodel->surfmesh.num_morphframes = 0;
  1046. for (i = 0;i < loadmodel->numframes;i++)
  1047. {
  1048. pinframetype = (daliasframetype_t *)datapointer;
  1049. datapointer += sizeof(daliasframetype_t);
  1050. if (LittleLong (pinframetype->type) == ALIAS_SINGLE)
  1051. groupframes = 1;
  1052. else
  1053. {
  1054. pinframegroup = (daliasgroup_t *)datapointer;
  1055. datapointer += sizeof(daliasgroup_t);
  1056. groupframes = LittleLong(pinframegroup->numframes);
  1057. datapointer += sizeof(daliasinterval_t) * groupframes;
  1058. }
  1059. for (j = 0;j < groupframes;j++)
  1060. {
  1061. datapointer += sizeof(daliasframe_t);
  1062. datapointer += sizeof(trivertx_t) * numverts;
  1063. loadmodel->surfmesh.num_morphframes++;
  1064. }
  1065. }
  1066. loadmodel->num_poses = loadmodel->surfmesh.num_morphframes;
  1067. // store texture coordinates into temporary array, they will be stored
  1068. // after usage is determined (triangle data)
  1069. vertst = (float *)Mem_Alloc(tempmempool, numverts * 2 * sizeof(float[2]));
  1070. vertremap = (int *)Mem_Alloc(tempmempool, numverts * 3 * sizeof(int));
  1071. vertonseam = vertremap + numverts * 2;
  1072. scales = 1.0 / skinwidth;
  1073. scalet = 1.0 / skinheight;
  1074. for (i = 0;i < numverts;i++)
  1075. {
  1076. vertonseam[i] = LittleLong(pinstverts[i].onseam);
  1077. vertst[i*2+0] = LittleLong(pinstverts[i].s) * scales;
  1078. vertst[i*2+1] = LittleLong(pinstverts[i].t) * scalet;
  1079. vertst[(i+numverts)*2+0] = vertst[i*2+0] + 0.5;
  1080. vertst[(i+numverts)*2+1] = vertst[i*2+1];
  1081. }
  1082. // load triangle data
  1083. loadmodel->surfmesh.data_element3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * loadmodel->surfmesh.num_triangles);
  1084. // read the triangle elements
  1085. for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
  1086. for (j = 0;j < 3;j++)
  1087. loadmodel->surfmesh.data_element3i[i*3+j] = LittleLong(pintriangles[i].vertindex[j]);
  1088. // validate (note numverts is used because this is the original data)
  1089. Mod_ValidateElements(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles, 0, numverts, __FILE__, __LINE__);
  1090. // now butcher the elements according to vertonseam and tri->facesfront
  1091. // and then compact the vertex set to remove duplicates
  1092. for (i = 0;i < loadmodel->surfmesh.num_triangles;i++)
  1093. if (!LittleLong(pintriangles[i].facesfront)) // backface
  1094. for (j = 0;j < 3;j++)
  1095. if (vertonseam[loadmodel->surfmesh.data_element3i[i*3+j]])
  1096. loadmodel->surfmesh.data_element3i[i*3+j] += numverts;
  1097. // count the usage
  1098. // (this uses vertremap to count usage to save some memory)
  1099. for (i = 0;i < numverts*2;i++)
  1100. vertremap[i] = 0;
  1101. for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
  1102. vertremap[loadmodel->surfmesh.data_element3i[i]]++;
  1103. // build remapping table and compact array
  1104. loadmodel->surfmesh.num_vertices = 0;
  1105. for (i = 0;i < numverts*2;i++)
  1106. {
  1107. if (vertremap[i])
  1108. {
  1109. vertremap[i] = loadmodel->surfmesh.num_vertices;
  1110. vertst[loadmodel->surfmesh.num_vertices*2+0] = vertst[i*2+0];
  1111. vertst[loadmodel->surfmesh.num_vertices*2+1] = vertst[i*2+1];
  1112. loadmodel->surfmesh.num_vertices++;
  1113. }
  1114. else
  1115. vertremap[i] = -1; // not used at all
  1116. }
  1117. // remap the elements to the new vertex set
  1118. for (i = 0;i < loadmodel->surfmesh.num_triangles * 3;i++)
  1119. loadmodel->surfmesh.data_element3i[i] = vertremap[loadmodel->surfmesh.data_element3i[i]];
  1120. // store the texture coordinates
  1121. loadmodel->surfmesh.data_texcoordtexture2f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[2]) * loadmodel->surfmesh.num_vertices);
  1122. for (i = 0;i < loadmodel->surfmesh.num_vertices;i++)
  1123. {
  1124. loadmodel->surfmesh.data_texcoordtexture2f[i*2+0] = vertst[i*2+0];
  1125. loadmodel->surfmesh.data_texcoordtexture2f[i*2+1] = vertst[i*2+1];
  1126. }
  1127. // generate ushort elements array if possible
  1128. if (loadmodel->surfmesh.num_vertices <= 65536)
  1129. loadmodel->surfmesh.data_element3s = (unsigned short *)Mem_Alloc(loadmodel->mempool, sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles);
  1130. if (loadmodel->surfmesh.data_element3s)
  1131. for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
  1132. loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
  1133. // load the frames
  1134. loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes);
  1135. loadmodel->surfmesh.data_morphmdlvertex = (trivertx_t *)Mem_Alloc(loadmodel->mempool, sizeof(trivertx_t) * loadmodel->surfmesh.num_morphframes * loadmodel->surfmesh.num_vertices);
  1136. if (r_enableshadowvolumes.integer)
  1137. {
  1138. loadmodel->surfmesh.data_neighbor3i = (int *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_triangles * sizeof(int[3]));
  1139. }
  1140. Mod_MDL_LoadFrames (startframes, numverts, vertremap);
  1141. if (loadmodel->surfmesh.data_neighbor3i)
  1142. Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles);
  1143. loadmodel->surfmesh.isanimated = Mod_Alias_CalculateBoundingBox();
  1144. Mod_Alias_MorphMesh_CompileFrames();
  1145. Mem_Free(vertst);
  1146. Mem_Free(vertremap);
  1147. // load the skins
  1148. skinfiles = Mod_LoadSkinFiles();
  1149. if (skinfiles)
  1150. {
  1151. loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
  1152. loadmodel->num_textures = loadmodel->num_surfaces * loadmodel->numskins;
  1153. loadmodel->num_texturesperskin = loadmodel->num_surfaces;
  1154. loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t));
  1155. Mod_BuildAliasSkinsFromSkinFiles(loadmodel->data_textures, skinfiles, "default", "");
  1156. Mod_FreeSkinFiles(skinfiles);
  1157. for (i = 0;i < loadmodel->numskins;i++)
  1158. {
  1159. loadmodel->skinscenes[i].firstframe = i;
  1160. loadmodel->skinscenes[i].framecount = 1;
  1161. loadmodel->skinscenes[i].loop = true;
  1162. loadmodel->skinscenes[i].framerate = 10;
  1163. }
  1164. }
  1165. else
  1166. {
  1167. loadmodel->skinscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, loadmodel->numskins * sizeof(animscene_t));
  1168. loadmodel->num_textures = loadmodel->num_surfaces * totalskins;
  1169. loadmodel->num_texturesperskin = loadmodel->num_surfaces;
  1170. loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * totalskins * sizeof(texture_t));
  1171. totalskins = 0;
  1172. datapointer = startskins;
  1173. for (i = 0;i < loadmodel->numskins;i++)
  1174. {
  1175. pinskintype = (daliasskintype_t *)datapointer;
  1176. datapointer += sizeof(daliasskintype_t);
  1177. if (pinskintype->type == ALIAS_SKIN_SINGLE)
  1178. {
  1179. groupskins = 1;
  1180. interval = 0.1f;
  1181. }
  1182. else
  1183. {
  1184. pinskingroup = (daliasskingroup_t *)datapointer;
  1185. datapointer += sizeof(daliasskingroup_t);
  1186. groupskins = LittleLong (pinskingroup->numskins);
  1187. pinskinintervals = (daliasskininterval_t *)datapointer;
  1188. datapointer += sizeof(daliasskininterval_t) * groupskins;
  1189. interval = LittleFloat(pinskinintervals[0].interval);
  1190. if (interval < 0.01f)
  1191. {
  1192. Con_Printf("%s has an invalid interval %f, changing to 0.1\n", loadmodel->name, interval);
  1193. interval = 0.1f;
  1194. }
  1195. }
  1196. dpsnprintf(loadmodel->skinscenes[i].name, sizeof(loadmodel->skinscenes[i].name), "skin %i", i);
  1197. loadmodel->skinscenes[i].firstframe = totalskins;
  1198. loadmodel->skinscenes[i].framecount = groupskins;
  1199. loadmodel->skinscenes[i].framerate = 1.0f / interval;
  1200. loadmodel->skinscenes[i].loop = true;
  1201. for (j = 0;j < groupskins;j++)
  1202. {
  1203. if (groupskins > 1)
  1204. dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j);
  1205. else
  1206. dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i);
  1207. if (!Mod_LoadTextureFromQ3Shader(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, name, false, true, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS))
  1208. Mod_BuildAliasSkinFromSkinFrame(loadmodel->data_textures + totalskins * loadmodel->num_surfaces, R_SkinFrame_LoadInternalQuake(name, (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, true, r_fullbrights.integer, (unsigned char *)datapointer, skinwidth, skinheight));
  1209. datapointer += skinwidth * skinheight;
  1210. totalskins++;
  1211. }
  1212. }
  1213. // check for skins that don't exist in the model, but do exist as external images
  1214. // (this was added because yummyluv kept pestering me about support for it)
  1215. // TODO: support shaders here?
  1216. while ((tempskinframe = R_SkinFrame_LoadExternal(va(vabuf, sizeof(vabuf), "%s_%i", loadmodel->name, loadmodel->numskins), (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_ALPHA | TEXF_PICMIP | TEXF_COMPRESS, false)))
  1217. {
  1218. // expand the arrays to make room