UFO: Alien Invasion
Loading...
Searching...
No Matches
r_model_alias.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 1997-2001 Id Software, Inc.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, 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==============================================================================
32ALIAS MODELS
33==============================================================================
34*/
35
36void 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
119static 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))) {
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) {
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) {
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
301 }
302
303 return true;
304}
305
313void 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
518image_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
531image_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
576void 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*/
586 if (r_state.lighting_enabled) {
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
665void 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 {
689
690 mod->curFrame = -1;
691 mod->oldFrame = -1;
692 }
693}
#define LittleLong(X)
Definition byte.h:37
memPool_t * vid_modelPool
Definition cl_main.cpp:90
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ERR_DROP
Definition common.h:211
#define ERR_FATAL
Definition common.h:210
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition files.cpp:384
void FS_FreeFile(void *buffer)
Definition files.cpp:411
#define MAX_QPATH
Definition filesys.h:40
voidpf void * buf
Definition ioapi.h:42
void Orthogonalize(vec3_t out, const vec3_t in)
Grahm-Schmidt orthogonalization.
Definition mathlib.cpp:1088
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
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 Mem_PoolAllocTypeN(type, n, pool)
Definition mem.h:42
#define Mem_Free(ptr)
Definition mem.h:35
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
int Com_CountTokensInBuffer(const char *buffer)
Counts the tokens in the given buffer that the Com_Parse function would extract.
Definition parse.cpp:80
Shared parsing functions.
#define IDMDXHEADER
Definition qfiles.h:33
#define MDX_VERSION
Definition qfiles.h:34
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLint i
Definition r_gl.h:113
image_t * R_FindImage(const char *pname, imagetype_t type)
Finds or loads the given image.
Definition r_image.cpp:603
@ it_skin
Definition r_image.h:47
local graphics definitions
rstate_t r_state
Definition r_main.cpp:48
image_t * R_AliasModelState(const model_t *mod, int *mesh, int *frame, int *oldFrame, int *skin)
bool R_ModLoadMDX(model_t *mod)
Tries to load a mdx file that contains the normals and the tangents for a model.
void R_ModCalcUniqueNormalsAndTangents(mAliasMesh_t *mesh, int nFrames, float smoothness)
Calculates normals and tangents for all frames and does vertex merging based on smoothness.
image_t * R_AliasModelGetSkin(const char *modelFileName, const char *skin)
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.
void R_ModLoadAnims(mAliasModel_t *mod, const char *animname)
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.
void R_ModLoadArrayData(mAliasModel_t *mod, mAliasMesh_t *mesh, bool loadNormals)
Allocates data arrays for animated models. Only called once at loading time.
#define MAX_ALIAS_VERTS
#define mAliasCoord_t
#define MAX_ANIMS
#define MAX_ALIAS_TRIS
void R_ReallocateTexunitArray(gltexunit_t *texunit, int size)
Reallocate texcoord array of the specified texunit, if needed.
Definition r_state.cpp:1059
void R_ReallocateStateArrays(int size)
Reallocate arrays of GL primitives if needed.
Definition r_state.cpp:1029
#define texunit_diffuse
Definition r_state.h:68
#define lengthof(x)
Definition shared.h:105
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
void Com_DefaultExtension(char *path, size_t len, const char *extension)
Sets a default extension if there is none.
Definition shared.cpp:297
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
GLuint texnum
Definition r_image.h:66
char name[MAX_ANIMNAME]
mAliasVertex_t * vertexes
int32_t * indexes
vec_t * next_normals
mAliasSkin_t * skins
mAliasCoord_t * stcoords
mIndexList_t * revIndexes
vec_t * texcoords
vec_t * next_tangents
char name[MODEL_MAX_PATH]
int32_t num_indexes
vec_t * next_verts
int32_t num_verts
mAliasAnim_t * animdata
mAliasFrame_t * frames
mAliasMesh_t * meshes
image_t * skin
int32_t * list
mAliasModel_t alias
Definition r_model.h:63
char name[MAX_QPATH]
Definition r_model.h:44
float vec_t
Definition ufotypes.h:37
vec_t vec3_t[3]
Definition ufotypes.h:39
vec_t vec4_t[4]
Definition ufotypes.h:40
vec_t vec2_t[2]
Definition ufotypes.h:38
#define VectorMul(scalar, b, dest)
Definition vector.h:48
#define VectorClear(a)
Definition vector.h:55
#define VectorEqual(a, b)
Definition vector.h:65
#define Vector4Copy(src, dest)
Definition vector.h:53
#define Vector2Equal(a, b)
Definition vector.h:67
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define Vector2Subtract(a, b, dest)
Definition vector.h:46
#define VectorAdd(a, b, dest)
Definition vector.h:47
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44
#define VectorSet(v, x, y, z)
Definition vector.h:59
#define Vector2Copy(src, dest)
Definition vector.h:52