UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
r_model_alias.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "r_local.h"
27 #include "../../shared/parse.h"
28 #include "r_state.h"
29 
30 /*
31 ==============================================================================
32 ALIAS MODELS
33 ==============================================================================
34 */
35 
36 void R_ModLoadAnims (mAliasModel_t* mod, const char* animname)
37 {
38  const char* text;
39  mAliasAnim_t* anim;
40  int n;
41  /* load the tags */
42  byte* animbuf = nullptr;
43  const char* buffer;
44 
45  FS_LoadFile(animname, &animbuf);
46 
47  buffer = (const char*)animbuf;
48 
49  /* count the animations */
50  n = Com_CountTokensInBuffer(buffer);
51 
52  if ((n % 4) != 0) {
53  FS_FreeFile(animbuf);
54  Com_Error(ERR_DROP, "invalid syntax: %s", animname);
55  }
56 
57  /* each animation definition is made out of 4 tokens */
58  n /= 4;
59  if (n > MAX_ANIMS)
60  n = MAX_ANIMS;
61 
63  anim = mod->animdata;
64  text = buffer;
65  mod->num_anims = 0;
66 
67  do {
68  /* get the name */
69  const char* token = Com_Parse(&text);
70  if (!text)
71  break;
72  Q_strncpyz(anim->name, token, sizeof(anim->name));
73 
74  /* get the start */
75  token = Com_Parse(&text);
76  if (!text)
77  break;
78  anim->from = atoi(token);
79  if (anim->from < 0)
80  Com_Error(ERR_FATAL, "R_ModLoadAnims: negative start frame for %s", animname);
81  else if (anim->from > mod->num_frames)
82  Com_Error(ERR_FATAL, "R_ModLoadAnims: start frame is higher than models frame count (%i) (model: %s)",
83  mod->num_frames, animname);
84 
85  /* get the end */
86  token = Com_Parse(&text);
87  if (!text)
88  break;
89  anim->to = atoi(token);
90  if (anim->to < 0)
91  Com_Error(ERR_FATAL, "R_ModLoadAnims: negative end frame for %s", animname);
92  else if (anim->to > mod->num_frames)
93  Com_Error(ERR_FATAL, "R_ModLoadAnims: end frame is higher than models frame count (%i) (model: %s)",
94  mod->num_frames, animname);
95 
96  /* get the fps */
97  token = Com_Parse(&text);
98  if (!text)
99  break;
100  anim->time = (atof(token) > 0.01) ? (1000.0 / atof(token)) : (1000.0 / 0.01);
101 
102  /* add it */
103  mod->num_anims++;
104  anim++;
105  } while (mod->num_anims < n);
106 
107  FS_FreeFile(animbuf);
108 }
109 
110 
119 static void R_ModCalcNormalsAndTangents (mAliasMesh_t* mesh, int framenum, const vec3_t translate, bool backlerp)
120 {
121  int i, j;
122  mAliasVertex_t* vertexes = &mesh->vertexes[framenum * mesh->num_verts];
123  mAliasCoord_t* stcoords = mesh->stcoords;
124  const int numIndexes = mesh->num_tris * 3;
125  const int32_t* indexArray = mesh->indexes;
126  vec3_t triangleNormals[MAX_ALIAS_TRIS];
127  vec3_t triangleTangents[MAX_ALIAS_TRIS];
128  vec3_t triangleBitangents[MAX_ALIAS_TRIS];
129  float* texcoords, *verts, *normals, *tangents;
130 
131  /* set up array pointers for either the previous keyframe or the next keyframe */
132  texcoords = mesh->texcoords;
133  if (backlerp) {
134  verts = mesh->verts;
135  normals = mesh->normals;
136  tangents = mesh->tangents;
137  } else {
138  verts = mesh->next_verts;
139  normals = mesh->next_normals;
140  tangents = mesh->next_tangents;
141  }
142 
143  /* calculate per-triangle surface normals and tangents*/
144  for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
145  vec3_t dir1, dir2;
146  vec2_t dir1uv, dir2uv;
147 
148  /* calculate two mostly perpendicular edge directions */
149  VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
150  VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
151  Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
152  Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);
153 
154  /* we have two edge directions, we can calculate a third vector from
155  * them, which is the direction of the surface normal */
156  CrossProduct(dir1, dir2, triangleNormals[j]);
157  /* normalize */
158  VectorNormalizeFast(triangleNormals[j]);
159 
160  /* then we use the texture coordinates to calculate a tangent space */
161  if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
162  const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
163  vec3_t tmp1, tmp2;
164 
165  /* calculate tangent */
166  VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
167  VectorMul(dir1uv[1] * frac, dir2, tmp2);
168  VectorAdd(tmp1, tmp2, triangleTangents[j]);
169 
170  /* calculate bitangent */
171  VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
172  VectorMul(dir1uv[0] * frac, dir2, tmp2);
173  VectorAdd(tmp1, tmp2, triangleBitangents[j]);
174 
175  /* normalize */
176  VectorNormalizeFast(triangleTangents[j]);
177  VectorNormalizeFast(triangleBitangents[j]);
178  } else {
179  VectorClear(triangleTangents[j]);
180  VectorClear(triangleBitangents[j]);
181  }
182  }
183 
184  /* for each vertex */
185  for (i = 0; i < mesh->num_verts; i++) {
186  vec3_t n, b, v;
187  vec4_t t;
188  const int len = mesh->revIndexes[i].length;
189  const int32_t* list = mesh->revIndexes[i].list;
190 
191  VectorClear(n);
192  VectorClear(t);
193  VectorClear(b);
194 
195  /* for each vertex that got mapped to this one (ie. for each triangle this vertex is a part of) */
196  for (j = 0; j < len; j++) {
197  const int32_t idx = list[j] / 3;
198  VectorAdd(n, triangleNormals[idx], n);
199  VectorAdd(t, triangleTangents[idx], t);
200  VectorAdd(b, triangleBitangents[idx], b);
201  }
202 
203  /* normalization here does shared-vertex smoothing */
207 
208  /* Grahm-Schmidt orthogonalization */
209  Orthogonalize(t, n);
210 
211  /* calculate handedness */
212  CrossProduct(n, t, v);
213  t[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;
214 
215  /* copy this vertex's info to all the right places in the arrays */
216  for (j = 0; j < len; j++) {
217  const int32_t idx = list[j];
218  const int meshIndex = mesh->indexes[list[j]];
219  Vector2Copy(stcoords[meshIndex], (texcoords + (2 * idx)));
220  VectorAdd(vertexes[meshIndex].point, translate, (verts + (3 * idx)));
221  VectorCopy(n, (normals + (3 * idx)));
222  Vector4Copy(t, (tangents + (4 * idx)));
223  }
224  }
225 }
226 
234 {
235  int i;
236  for (i = 0; i < mod->alias.num_meshes; i++) {
237  mAliasMesh_t* mesh = &mod->alias.meshes[i];
238  char mdxFileName[MAX_QPATH];
239  byte* buffer = nullptr, *buf;
240  const int32_t* intbuf;
241  uint32_t version;
242  int sharedTris[MAX_ALIAS_VERTS];
243 
244  Com_StripExtension(mod->name, mdxFileName, sizeof(mdxFileName));
245  Com_DefaultExtension(mdxFileName, sizeof(mdxFileName), ".mdx");
246 
247  if (FS_LoadFile(mdxFileName, &buffer) == -1)
248  return false;
249 
250  buf = buffer;
251  if (strncmp((const char*) buf, IDMDXHEADER, strlen(IDMDXHEADER))) {
252  FS_FreeFile(buf);
253  Com_Error(ERR_DROP, "No mdx file buffer given");
254  }
255  buffer += strlen(IDMDXHEADER) * sizeof(char);
256  version = LittleLong(*(uint32_t*) buffer);
257  if (version != MDX_VERSION) {
258  FS_FreeFile(buf);
259  Com_Error(ERR_DROP, "Invalid version of the mdx file, expected %i, found %i",
260  MDX_VERSION, version);
261  }
262  buffer += sizeof(uint32_t);
263 
264  intbuf = (const int32_t*) buffer;
265 
266  mesh->num_verts = LittleLong(*intbuf);
267  if (mesh->num_verts <= 0 || mesh->num_verts > MAX_ALIAS_VERTS) {
268  FS_FreeFile(buf);
269  Com_Error(ERR_DROP, "mdx file for %s has to many (or no) vertices: %i", mod->name, mesh->num_verts);
270  }
271  intbuf++;
272  mesh->num_indexes = LittleLong(*intbuf);
273  intbuf++;
274 
275  mesh->indexes = Mem_PoolAllocTypeN(int32_t, mesh->num_indexes, vid_modelPool);
278 
279  /* load index that maps triangle verts to Vertex objects */
280  for (i = 0; i < mesh->num_indexes; i++) {
281  mesh->indexes[i] = LittleLong(*intbuf);
282  intbuf++;
283  }
284 
285  for (i = 0; i < mesh->num_verts; i++)
286  sharedTris[i] = 0;
287 
288  /* set up reverse-index that maps Vertex objects to a list of triangle verts */
289  for (i = 0; i < mesh->num_indexes; i++)
290  sharedTris[mesh->indexes[i]]++;
291 
292  for (i = 0; i < mesh->num_verts; i++) {
293  mesh->revIndexes[i].length = 0;
294  mesh->revIndexes[i].list = Mem_PoolAllocTypeN(int32_t, sharedTris[i], vid_modelPool);
295  }
296 
297  for (i = 0; i < mesh->num_indexes; i++)
298  mesh->revIndexes[mesh->indexes[i]].list[mesh->revIndexes[mesh->indexes[i]].length++] = i;
299 
300  FS_FreeFile(buf);
301  }
302 
303  return true;
304 }
305 
313 void R_ModCalcUniqueNormalsAndTangents (mAliasMesh_t* mesh, int nFrames, float smoothness)
314 {
315  int i, j;
316  vec3_t triangleNormals[MAX_ALIAS_TRIS];
317  vec3_t triangleTangents[MAX_ALIAS_TRIS];
318  vec3_t triangleBitangents[MAX_ALIAS_TRIS];
319  const mAliasVertex_t* vertexes = mesh->vertexes;
320  mAliasCoord_t* stcoords = mesh->stcoords;
322  vec3_t tmpBitangents[MAX_ALIAS_VERTS];
323  const int numIndexes = mesh->num_tris * 3;
324  const int32_t* indexArray = mesh->indexes;
325  int indRemap[MAX_ALIAS_VERTS];
326  int sharedTris[MAX_ALIAS_VERTS];
327  int numVerts = 0;
328 
329  if (numIndexes >= MAX_ALIAS_VERTS)
330  Com_Error(ERR_DROP, "model %s has too many tris", mesh->name);
331 
332  int32_t* const newIndexArray = Mem_PoolAllocTypeN(int32_t, numIndexes, vid_modelPool);
333 
334  /* calculate per-triangle surface normals */
335  for (i = 0, j = 0; i < numIndexes; i += 3, j++) {
336  vec3_t dir1, dir2;
337  vec2_t dir1uv, dir2uv;
338 
339  /* calculate two mostly perpendicular edge directions */
340  VectorSubtract(vertexes[indexArray[i + 0]].point, vertexes[indexArray[i + 1]].point, dir1);
341  VectorSubtract(vertexes[indexArray[i + 2]].point, vertexes[indexArray[i + 1]].point, dir2);
342  Vector2Subtract(stcoords[indexArray[i + 0]], stcoords[indexArray[i + 1]], dir1uv);
343  Vector2Subtract(stcoords[indexArray[i + 2]], stcoords[indexArray[i + 1]], dir2uv);
344 
345  /* we have two edge directions, we can calculate a third vector from
346  * them, which is the direction of the surface normal */
347  CrossProduct(dir1, dir2, triangleNormals[j]);
348 
349  /* then we use the texture coordinates to calculate a tangent space */
350  if ((dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]) != 0.0) {
351  const float frac = 1.0 / (dir1uv[1] * dir2uv[0] - dir1uv[0] * dir2uv[1]);
352  vec3_t tmp1, tmp2;
353 
354  /* calculate tangent */
355  VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
356  VectorMul(dir1uv[1] * frac, dir2, tmp2);
357  VectorAdd(tmp1, tmp2, triangleTangents[j]);
358 
359  /* calculate bitangent */
360  VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
361  VectorMul(dir1uv[0] * frac, dir2, tmp2);
362  VectorAdd(tmp1, tmp2, triangleBitangents[j]);
363  } else {
364  const float frac = 1.0 / (0.00001);
365  vec3_t tmp1, tmp2;
366 
367  /* calculate tangent */
368  VectorMul(-1.0 * dir2uv[1] * frac, dir1, tmp1);
369  VectorMul(dir1uv[1] * frac, dir2, tmp2);
370  VectorAdd(tmp1, tmp2, triangleTangents[j]);
371 
372  /* calculate bitangent */
373  VectorMul(-1.0 * dir2uv[0] * frac, dir1, tmp1);
374  VectorMul(dir1uv[0] * frac, dir2, tmp2);
375  VectorAdd(tmp1, tmp2, triangleBitangents[j]);
376  }
377 
378  /* normalize */
379  VectorNormalizeFast(triangleNormals[j]);
380  VectorNormalizeFast(triangleTangents[j]);
381  VectorNormalizeFast(triangleBitangents[j]);
382 
383  Orthogonalize(triangleTangents[j], triangleBitangents[j]);
384  }
385 
386  /* do smoothing */
387  for (i = 0; i < numIndexes; i++) {
388  const int idx = (i - i % 3) / 3;
389  VectorCopy(triangleNormals[idx], tmpVertexes[i].normal);
390  VectorCopy(triangleTangents[idx], tmpVertexes[i].tangent);
391  VectorCopy(triangleBitangents[idx], tmpBitangents[i]);
392 
393  for (j = 0; j < numIndexes; j++) {
394  const int idx2 = (j - j % 3) / 3;
395  /* don't add a vertex with itself */
396  if (j == i)
397  continue;
398 
399  /* only average normals if vertices have the same position
400  * and the normals aren't too far apart to start with */
401  if (VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)
402  && DotProduct(triangleNormals[idx], triangleNormals[idx2]) > smoothness) {
403  /* average the normals */
404  VectorAdd(tmpVertexes[i].normal, triangleNormals[idx2], tmpVertexes[i].normal);
405 
406  /* if the tangents match as well, average them too.
407  * Note that having matching normals without matching tangents happens
408  * when the order of vertices in two triangles sharing the vertex
409  * in question is different. This happens quite frequently if the
410  * modeler does not go out of their way to avoid it. */
411 
412  if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])
413  && DotProduct(triangleTangents[idx], triangleTangents[idx2]) > smoothness
414  && DotProduct(triangleBitangents[idx], triangleBitangents[idx2]) > smoothness) {
415  /* average the tangents */
416  VectorAdd(tmpVertexes[i].tangent, triangleTangents[idx2], tmpVertexes[i].tangent);
417  VectorAdd(tmpBitangents[i], triangleBitangents[idx2], tmpBitangents[i]);
418  }
419  }
420  }
421 
422  VectorNormalizeFast(tmpVertexes[i].normal);
423  VectorNormalizeFast(tmpVertexes[i].tangent);
424  VectorNormalizeFast(tmpBitangents[i]);
425  }
426 
427  /* assume all vertices are unique until proven otherwise */
428  for (i = 0; i < numIndexes; i++)
429  indRemap[i] = -1;
430 
431  /* merge vertices that have become identical */
432  for (i = 0; i < numIndexes; i++) {
433  vec3_t n, b, t, v;
434  if (indRemap[i] != -1)
435  continue;
436 
437  for (j = i + 1; j < numIndexes; j++) {
438  if (Vector2Equal(stcoords[indexArray[i]], stcoords[indexArray[j]])
439  && VectorEqual(vertexes[indexArray[i]].point, vertexes[indexArray[j]].point)
440  && (DotProduct(tmpVertexes[i].normal, tmpVertexes[j].normal) > smoothness)
441  && (DotProduct(tmpVertexes[i].tangent, tmpVertexes[j].tangent) > smoothness)) {
442  indRemap[j] = i;
443  newIndexArray[j] = numVerts;
444  }
445  }
446 
447  VectorCopy(tmpVertexes[i].normal, n);
448  VectorCopy(tmpVertexes[i].tangent, t);
449  VectorCopy(tmpBitangents[i], b);
450 
451  /* normalization here does shared-vertex smoothing */
455 
456  /* Grahm-Schmidt orthogonalization */
457  VectorMul(DotProduct(t, n), n, v);
458  VectorSubtract(t, v, t);
460 
461  /* calculate handedness */
462  CrossProduct(n, t, v);
463  tmpVertexes[i].tangent[3] = (DotProduct(v, b) < 0.0) ? -1.0 : 1.0;
464  VectorCopy(n, tmpVertexes[i].normal);
465  VectorCopy(t, tmpVertexes[i].tangent);
466 
467  newIndexArray[i] = numVerts++;
468  indRemap[i] = i;
469  }
470 
471  for (i = 0; i < numVerts; i++)
472  sharedTris[i] = 0;
473 
474  for (i = 0; i < numIndexes; i++)
475  sharedTris[newIndexArray[i]]++;
476 
477  /* set up reverse-index that maps Vertex objects to a list of triangle verts */
479  for (i = 0; i < numVerts; i++) {
480  mesh->revIndexes[i].length = 0;
481  mesh->revIndexes[i].list = Mem_PoolAllocTypeN(int32_t, sharedTris[i], vid_modelPool);
482  }
483 
484  /* merge identical vertexes, storing only unique ones */
485  mAliasVertex_t* const newVertexes = Mem_PoolAllocTypeN(mAliasVertex_t, numVerts * nFrames, vid_modelPool);
486  mAliasCoord_t* const newStcoords = Mem_PoolAllocTypeN(mAliasCoord_t, numVerts, vid_modelPool);
487  for (i = 0; i < numIndexes; i++) {
488  const int idx = indexArray[indRemap[i]];
489  const int idx2 = newIndexArray[i];
490 
491  /* add vertex to new vertex array */
492  VectorCopy(vertexes[idx].point, newVertexes[idx2].point);
493  Vector2Copy(stcoords[idx], newStcoords[idx2]);
494  mesh->revIndexes[idx2].list[mesh->revIndexes[idx2].length++] = i;
495  }
496 
497  /* copy over the points from successive frames */
498  for (i = 1; i < nFrames; i++) {
499  for (j = 0; j < numIndexes; j++) {
500  const int idx = indexArray[indRemap[j]] + (mesh->num_verts * i);
501  const int idx2 = newIndexArray[j] + (numVerts * i);
502 
503  VectorCopy(vertexes[idx].point, newVertexes[idx2].point);
504  }
505  }
506 
507  /* copy new arrays back into original mesh */
508  Mem_Free(mesh->stcoords);
509  Mem_Free(mesh->indexes);
510  Mem_Free(mesh->vertexes);
511 
512  mesh->num_verts = numVerts;
513  mesh->vertexes = newVertexes;
514  mesh->stcoords = newStcoords;
515  mesh->indexes = newIndexArray;
516 }
517 
518 image_t* R_AliasModelGetSkin (const char* modelFileName, const char* skin)
519 {
520  image_t* result;
521  if (skin[0] != '.')
522  result = R_FindImage(skin, it_skin);
523  else {
524  char path[MAX_QPATH];
525  Com_ReplaceFilename(modelFileName, skin + 1, path, sizeof(path));
526  result = R_FindImage(path, it_skin);
527  }
528  return result;
529 }
530 
531 image_t* R_AliasModelState (const model_t* mod, int* mesh, int* frame, int* oldFrame, int* skin)
532 {
533  /* check animations */
534  if ((*frame >= mod->alias.num_frames) || *frame < 0) {
535  Com_Printf("R_AliasModelState %s: no such frame %d (# %i)\n", mod->name, *frame, mod->alias.num_frames);
536  *frame = 0;
537  }
538  if ((*oldFrame >= mod->alias.num_frames) || *oldFrame < 0) {
539  Com_Printf("R_AliasModelState %s: no such oldframe %d (# %i)\n", mod->name, *oldFrame, mod->alias.num_frames);
540  *oldFrame = 0;
541  }
542 
543  if (*mesh < 0 || *mesh >= mod->alias.num_meshes)
544  *mesh = 0;
545 
546  if (!mod->alias.meshes)
547  return nullptr;
548 
549  /* use default skin - this is never null - but maybe the placeholder texture */
550  if (*skin < 0 || *skin >= mod->alias.meshes[*mesh].num_skins)
551  *skin = 0;
552 
553  if (!mod->alias.meshes[*mesh].num_skins)
554  Com_Error(ERR_DROP, "Model with no skins");
555 
556  if (mod->alias.meshes[*mesh].skins[*skin].skin->texnum <= 0)
557  Com_Error(ERR_DROP, "Texture is already freed and no longer uploaded, texnum is invalid for model %s",
558  mod->name);
559 
560  return mod->alias.meshes[*mesh].skins[*skin].skin;
561 }
562 
576 void R_FillArrayData (mAliasModel_t* mod, mAliasMesh_t* mesh, float backlerp, int framenum, int oldframenum, bool prerender)
577 {
578  const mAliasFrame_t* frame, *oldframe;
579  const float frontlerp = 1.0 - backlerp;
580  vec_t* texcoord_array, *vertex_array_3d;
581 
582  frame = mod->frames + framenum;
583  oldframe = mod->frames + oldframenum;
584 
585  /* try to do keyframe-interpolation on the GPU if possible*/
587  /* we only need to change the array data if we've switched to a new keyframe */
588  if (mod->curFrame != framenum) {
589  /* if we're rendering frames in order, the "next" keyframe from the previous
590  * time through will be our "previous" keyframe now, so we can swap pointers
591  * instead of generating it again from scratch */
592  if (mod->curFrame == oldframenum) {
593  vec_t* tmp1 = mesh->verts;
594  vec_t* tmp2 = mesh->normals;
595  vec_t* tmp3 = mesh->tangents;
596 
597  mesh->verts = mesh->next_verts;
598  mesh->next_verts = tmp1;
599 
600  mesh->normals = mesh->next_normals;
601  mesh->next_normals = tmp2;
602 
603  mesh->tangents = mesh->next_tangents;
604  mesh->next_tangents = tmp3;
605 
606  /* if we're alternating between two keyframes, we don't need to generate
607  * anything; otherwise, generate the "next" keyframe*/
608  if (mod->oldFrame != framenum)
609  R_ModCalcNormalsAndTangents(mesh, framenum, frame->translate, false);
610  } else {
611  /* if we're starting a new animation or otherwise not rendering keyframes
612  * in order, we need to fill the arrays for both keyframes */
613  R_ModCalcNormalsAndTangents(mesh, oldframenum, oldframe->translate, true);
614  R_ModCalcNormalsAndTangents(mesh, framenum, frame->translate, false);
615  }
616  /* keep track of which keyframes are currently stored in our arrays */
617  mod->oldFrame = oldframenum;
618  mod->curFrame = framenum;
619  }
620  } else { /* otherwise, we have to do it on the CPU */
621  const mAliasVertex_t* v, *ov;
622  vec3_t r_mesh_verts[MAX_ALIAS_VERTS];
623  vec3_t move;
624  int i;
625  assert(mesh->num_verts < lengthof(r_mesh_verts));
626  v = &mesh->vertexes[framenum * mesh->num_verts];
627  ov = &mesh->vertexes[oldframenum * mesh->num_verts];
628 
629  if (prerender)
630  R_ModCalcNormalsAndTangents(mesh, 0, oldframe->translate, true);
631 
632  for (i = 0; i < 3; i++)
633  move[i] = backlerp * oldframe->translate[i] + frontlerp * frame->translate[i];
634 
635  for (i = 0; i < mesh->num_verts; i++, v++, ov++) { /* lerp the verts */
636  VectorSet(r_mesh_verts[i],
637  move[0] + ov->point[0] * backlerp + v->point[0] * frontlerp,
638  move[1] + ov->point[1] * backlerp + v->point[1] * frontlerp,
639  move[2] + ov->point[2] * backlerp + v->point[2] * frontlerp);
640  }
641 
644  texcoord_array = texunit_diffuse.texcoord_array;
645  vertex_array_3d = r_state.vertex_array_3d;
646 
648  for (i = 0; i < mesh->num_tris; i++) { /* draw the tris */
649  for (int j = 0; j < 3; j++) {
650  const int arrayIndex = 3 * i + j;
651  const int meshIndex = mesh->indexes[arrayIndex];
652  Vector2Copy(mesh->stcoords[meshIndex], texcoord_array);
653  VectorCopy(r_mesh_verts[meshIndex], vertex_array_3d);
654 
655  texcoord_array += 2;
656  vertex_array_3d += 3;
657  }
658  }
659  }
660 }
661 
665 void R_ModLoadArrayData (mAliasModel_t* mod, mAliasMesh_t* mesh, bool loadNormals)
666 {
667  const int v = mesh->num_tris * 3 * 3;
668  const int t = mesh->num_tris * 3 * 4;
669  const int st = mesh->num_tris * 3 * 2;
670 
671  assert(mesh->verts == nullptr);
672  assert(mesh->texcoords == nullptr);
673  assert(mesh->normals == nullptr);
674  assert(mesh->tangents == nullptr);
675  assert(mesh->next_verts == nullptr);
676  assert(mesh->next_normals == nullptr);
677  assert(mesh->next_tangents == nullptr);
678 
679  mesh->verts = Mem_PoolAllocTypeN(float, v, vid_modelPool);
680  mesh->normals = Mem_PoolAllocTypeN(float, v, vid_modelPool);
681  mesh->tangents = Mem_PoolAllocTypeN(float, t, vid_modelPool);
682  mesh->texcoords = Mem_PoolAllocTypeN(float, st, vid_modelPool);
683  if (mod->num_frames == 1) {
684  R_FillArrayData(mod, mesh, 0.0, 0, 0, loadNormals);
685  } else {
686  mesh->next_verts = Mem_PoolAllocTypeN(float, v, vid_modelPool);
687  mesh->next_normals = Mem_PoolAllocTypeN(float, v, vid_modelPool);
689 
690  mod->curFrame = -1;
691  mod->oldFrame = -1;
692  }
693 }
#define VectorCopy(src, dest)
Definition: vector.h:51
mAliasModel_t alias
Definition: r_model.h:63
#define Vector2Equal(a, b)
Definition: vector.h:67
bool R_ModLoadMDX(model_t *mod)
Tries to load a mdx file that contains the normals and the tangents for a model.
#define VectorSet(v, x, y, z)
Definition: vector.h:59
image_t * R_AliasModelGetSkin(const char *modelFileName, const char *skin)
memPool_t * vid_modelPool
Definition: cl_main.cpp:90
mAliasVertex_t * vertexes
int32_t * indexes
vec_t * normals
void R_FillArrayData(mAliasModel_t *mod, mAliasMesh_t *mesh, float backlerp, int framenum, int oldframenum, bool prerender)
Converts the model data into the opengl arrays.
mAliasSkin_t * skins
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
GLfloat * vertex_array_3d
Definition: r_state.h:100
float vec_t
Definition: ufotypes.h:37
image_t * skin
Definition: r_model_alias.h:92
int Com_CountTokensInBuffer(const char *buffer)
Counts the tokens in the given buffer that the Com_Parse function would extract.
Definition: parse.cpp:80
void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross)
binary operation on vectors in a three-dimensional space
Definition: mathlib.cpp:820
local graphics definitions
#define IDMDXHEADER
Definition: qfiles.h:33
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
static void R_ModCalcNormalsAndTangents(mAliasMesh_t *mesh, int framenum, const vec3_t translate, bool backlerp)
Calculates a per-vertex tangentspace basis and stores it in GL arrays attached to the mesh...
vec_t * texcoords
#define mAliasCoord_t
Definition: r_model_alias.h:32
int32_t num_indexes
void VectorNormalizeFast(vec3_t v)
fast vector normalize routine that does not check to make sure that length != 0, nor does it return l...
Definition: mathlib.cpp:762
#define MAX_ANIMS
vec3_t translate
Definition: r_model_alias.h:58
voidpf void * buf
Definition: ioapi.h:42
#define ERR_FATAL
Definition: common.h:210
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
bool lighting_enabled
Definition: r_state.h:154
image_t * R_FindImage(const char *pname, imagetype_t type)
Finds or loads the given image.
Definition: r_image.cpp:603
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define VectorMul(scalar, b, dest)
Definition: vector.h:48
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
#define ERR_DROP
Definition: common.h:211
void R_ReallocateTexunitArray(gltexunit_t *texunit, int size)
Reallocate texcoord array of the specified texunit, if needed.
Definition: r_state.cpp:1059
char name[MODEL_MAX_PATH]
vec_t * tangents
void R_ModCalcUniqueNormalsAndTangents(mAliasMesh_t *mesh, int nFrames, float smoothness)
Calculates normals and tangents for all frames and does vertex merging based on smoothness.
vec_t * next_verts
char name[MAX_QPATH]
Definition: r_model.h:44
#define MAX_ALIAS_TRIS
Definition: r_model_alias.h:29
void Orthogonalize(vec3_t out, const vec3_t in)
Grahm-Schmidt orthogonalization.
Definition: mathlib.cpp:1088
#define MDX_VERSION
Definition: qfiles.h:34
mIndexList_t * revIndexes
#define VectorClear(a)
Definition: vector.h:55
#define Vector2Subtract(a, b, dest)
Definition: vector.h:46
mAliasMesh_t * meshes
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
#define VectorAdd(a, b, dest)
Definition: vector.h:47
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
#define texunit_diffuse
Definition: r_state.h:68
void R_ModLoadAnims(mAliasModel_t *mod, const char *animname)
vec_t * next_tangents
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition: shared.cpp:297
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
image_t * R_AliasModelState(const model_t *mod, int *mesh, int *frame, int *oldFrame, int *skin)
#define Mem_Free(ptr)
Definition: mem.h:35
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define Vector2Copy(src, dest)
Definition: vector.h:52
vec_t vec2_t[2]
Definition: ufotypes.h:38
char name[MAX_ANIMNAME]
rstate_t r_state
Definition: r_main.cpp:48
void Com_ReplaceFilename(const char *inputPath, const char *expectedFileName, char *outputPath, size_t size)
Replaces the filename from one path with another one.
Definition: shared.cpp:239
#define lengthof(x)
Definition: shared.h:105
mAliasCoord_t * stcoords
int32_t num_verts
vec_t * next_normals
int32_t * list
Definition: r_model_alias.h:97
#define MAX_ALIAS_VERTS
Definition: r_model_alias.h:30
void R_ReallocateStateArrays(int size)
Reallocate arrays of GL primitives if needed.
Definition: r_state.cpp:1029
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
#define VectorEqual(a, b)
Definition: vector.h:65
mAliasAnim_t * animdata
#define Vector4Copy(src, dest)
Definition: vector.h:53
mAliasFrame_t * frames
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
void R_ModLoadArrayData(mAliasModel_t *mod, mAliasMesh_t *mesh, bool loadNormals)
Allocates data arrays for animated models. Only called once at loading time.
void FS_FreeFile(void *buffer)
Definition: files.cpp:411
#define LittleLong(X)
Definition: byte.h:37
GLuint texnum
Definition: r_image.h:66
vec_t vec4_t[4]
Definition: ufotypes.h:40