Quake II RTX doxygen  1.0 dev
models.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2018 Christoph Schied
3 Copyright (C) 2018 Florian Simon
4 Copyright (C) 2003-2006 Andrey Nazarov
5 Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved.
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21 
22 /*
23 Copyright (C) 2003-2006 Andrey Nazarov
24 
25 This program is free software; you can redistribute it and/or modify
26 it under the terms of the GNU General Public License as published by
27 the Free Software Foundation; either version 2 of the License, or
28 (at your option) any later version.
29 
30 This program is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
34 
35 You should have received a copy of the GNU General Public License along
36 with this program; if not, write to the Free Software Foundation, Inc.,
37 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 */
39 
40 #include "vkpt.h"
41 
42 #include "format/md2.h"
43 #include "format/md3.h"
44 #include "format/sp2.h"
45 #include "material.h"
46 #include <assert.h>
47 
48 #if MAX_ALIAS_VERTS > TESS_MAX_VERTICES
49 #error TESS_MAX_VERTICES
50 #endif
51 
52 #if MD2_MAX_TRIANGLES > TESS_MAX_INDICES / 3
53 #error TESS_MAX_INDICES
54 #endif
55 
56 static void computeTangents(model_t * model)
57 {
58  for (int idx_mesh = 0; idx_mesh < model->nummeshes; ++idx_mesh)
59  {
60  maliasmesh_t * mesh = &model->meshes[idx_mesh];
61 
62  assert(mesh->tangents);
63  float * stangents = Z_Malloc(mesh->numverts * 2 * 3 * sizeof(float));
64  float * ttangents = stangents + (mesh->numverts * 3);
65 
66  for (int idx_frame = 0; idx_frame < model->numframes; ++idx_frame)
67  {
68  memset(stangents, 0, mesh->numverts * 2 * 3 * sizeof(float));
69 
70  uint32_t ntriangles = mesh->numindices / 3,
71  offset = idx_frame * mesh->numverts;
72 
73  for (int idx_tri = 0; idx_tri < mesh->numtris; ++idx_tri)
74  {
75  uint32_t iA = mesh->indices[idx_tri * 3 + 0];
76  uint32_t iB = mesh->indices[idx_tri * 3 + 1];
77  uint32_t iC = mesh->indices[idx_tri * 3 + 2];
78 
79  float const * pA = (float const *)mesh->positions + ((offset + iA) * 3);
80  float const * pB = (float const *)mesh->positions + ((offset + iB) * 3);
81  float const * pC = (float const *)mesh->positions + ((offset + iC) * 3);
82 
83  float const * tA = (float const *)mesh->tex_coords + ((offset + iA) * 2);
84  float const * tB = (float const *)mesh->tex_coords + ((offset + iB) * 2);
85  float const * tC = (float const *)mesh->tex_coords + ((offset + iC) * 2);
86 
87  vec3_t dP0, dP1;
88  VectorSubtract(pB, pA, dP0);
89  VectorSubtract(pC, pA, dP1);
90 
91  vec2_t dt0, dt1;
92  Vector2Subtract(tB, tA, dt0);
93  Vector2Subtract(tC, tA, dt1);
94 
95  float r = 1.f / (dt0[0] * dt1[1] - dt1[0] * dt0[1]);
96 
97  vec3_t sdir = {
98  (dt1[1] * dP0[0] - dt0[1] * dP1[0]) * r,
99  (dt1[1] * dP0[1] - dt0[1] * dP1[1]) * r,
100  (dt1[1] * dP0[2] - dt0[1] * dP1[2]) * r };
101 
102  vec3_t tdir = {
103  (dt0[0] * dP1[0] - dt1[0] * dP0[0]) * r,
104  (dt0[0] * dP1[1] - dt1[0] * dP0[1]) * r,
105  (dt0[0] * dP1[2] - dt1[0] * dP0[2]) * r };
106 
107  VectorAdd(stangents + (iA * 3), sdir, stangents + (iA * 3));
108  VectorAdd(stangents + (iB * 3), sdir, stangents + (iB * 3));
109  VectorAdd(stangents + (iC * 3), sdir, stangents + (iC * 3));
110 
111  VectorAdd(ttangents + (iA * 3), tdir, ttangents + (iA * 3));
112  VectorAdd(ttangents + (iB * 3), tdir, ttangents + (iB * 3));
113  VectorAdd(ttangents + (iC * 3), tdir, ttangents + (iC * 3));
114  }
115 
116  for (int idx_vert = 0; idx_vert < mesh->numverts; ++idx_vert)
117  {
118  float const * normal = (float const *)mesh->normals + ((offset + idx_vert) * 3);
119  float const * stan = stangents + (idx_vert * 3);
120  float const * ttan = ttangents + (idx_vert * 3);
121 
122  float * tangent = (float *)mesh->tangents + ((offset+idx_vert) * 4);
123 
124  vec3_t t;
125  VectorScale(normal, DotProduct(normal, stan), t);
126  VectorSubtract(stan, t, t);
127  VectorNormalize2(t, tangent); // Graham-Schmidt : t = normalize(t - n * (n.t))
128 
129  vec3_t cross;
130  CrossProduct(normal, t, cross);
131  float dot = DotProduct(cross, ttan);
132  tangent[3] = dot < 0.0f ? -1.0f : 1.0f; // handedness
133  }
134  }
135  Z_Free(stangents);
136  }
137 }
138 
139 static void export_obj_frames(model_t* model, const char* path_pattern)
140 {
141  for (int idx_frame = 0; idx_frame < model->numframes; ++idx_frame)
142  {
143  char path[MAX_OSPATH];
144  sprintf(path, path_pattern, idx_frame);
145  FILE* file = fopen(path, "w");
146 
147  if (!file)
148  continue;
149 
150  int mesh_vertex_offset = 1; // obj indexing starts at 1
151 
152  for (int idx_mesh = 0; idx_mesh < model->nummeshes; ++idx_mesh)
153  {
154  maliasmesh_t * mesh = &model->meshes[idx_mesh];
155  uint32_t ntriangles = mesh->numindices / 3,
156  offset = idx_frame * mesh->numverts;
157 
158  for (int idx_vert = 0; idx_vert < mesh->numverts; ++idx_vert)
159  {
160  float const * p = (float const*)mesh->positions + (offset + idx_vert) * 3;
161  float const * n = (float const*)mesh->normals + (offset + idx_vert) * 3;
162  float const * t = (float const*)mesh->tex_coords + (offset + idx_vert) * 2;
163  fprintf(file, "v %.3f %.3f %.3f\n", p[0], p[1], p[2]);
164  fprintf(file, "vn %.3f %.3f %.3f\n", n[0], n[1], n[2]);
165  fprintf(file, "vt %.3f %.3f\n", t[0], t[1]);
166  }
167 
168  fprintf(file, "g mesh_%d\n", idx_mesh);
169 
170  for (int idx_tri = 0; idx_tri < mesh->numtris; ++idx_tri)
171  {
172  int iA = mesh->indices[idx_tri * 3 + 0] + mesh_vertex_offset;
173  int iB = mesh->indices[idx_tri * 3 + 1] + mesh_vertex_offset;
174  int iC = mesh->indices[idx_tri * 3 + 2] + mesh_vertex_offset;
175 
176  fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", iA, iA, iA, iB, iB, iB, iC, iC, iC);
177  }
178 
179  mesh_vertex_offset += mesh->numverts;
180  }
181 
182  fclose(file);
183  }
184 }
185 
186 qerror_t MOD_LoadMD2_RTX(model_t *model, const void *rawdata, size_t length)
187 {
188  dmd2header_t header;
189  dmd2frame_t *src_frame;
190  dmd2trivertx_t *src_vert;
191  dmd2triangle_t *src_tri;
192  dmd2stvert_t *src_tc;
193  char *src_skin;
194  maliasframe_t *dst_frame;
195  maliasmesh_t *dst_mesh;
196  int val;
197  uint16_t remap[TESS_MAX_INDICES];
198  uint16_t vertIndices[TESS_MAX_INDICES];
199  uint16_t tcIndices[TESS_MAX_INDICES];
200  uint16_t finalIndices[TESS_MAX_INDICES];
201  int numverts, numindices;
202  char skinname[MAX_QPATH];
203  vec_t scale_s, scale_t;
204  vec3_t mins, maxs;
205  qerror_t ret;
206 
207  if (length < sizeof(header)) {
208  return Q_ERR_FILE_TOO_SMALL;
209  }
210 
211  // byte swap the header
212  header = *(dmd2header_t *)rawdata;
213  for (int i = 0; i < sizeof(header) / 4; i++) {
214  ((uint32_t *)&header)[i] = LittleLong(((uint32_t *)&header)[i]);
215  }
216 
217  // validate the header
218  ret = MOD_ValidateMD2(&header, length);
219  if (ret) {
220  if (ret == Q_ERR_TOO_FEW) {
221  // empty models draw nothing
222  model->type = MOD_EMPTY;
223  return Q_ERR_SUCCESS;
224  }
225  return ret;
226  }
227 
228  // load all triangle indices
229  numindices = 0;
230  src_tri = (dmd2triangle_t *)((byte *)rawdata + header.ofs_tris);
231  for (int i = 0; i < header.num_tris; i++) {
232  int good = 1;
233  for (int j = 0; j < 3; j++) {
234  uint16_t idx_xyz = LittleShort(src_tri->index_xyz[j]);
235  uint16_t idx_st = LittleShort(src_tri->index_st[j]);
236 
237  // some broken models have 0xFFFF indices
238  if (idx_xyz >= header.num_xyz || idx_st >= header.num_st) {
239  good = 0;
240  break;
241  }
242 
243  vertIndices[numindices + j] = idx_xyz;
244  tcIndices[numindices + j] = idx_st;
245  }
246  if (good) {
247  // only count good triangles
248  numindices += 3;
249  }
250  src_tri++;
251  }
252 
253  if (numindices < 3) {
254  return Q_ERR_TOO_FEW;
255  }
256 
257  qboolean all_normals_same = qtrue;
258  int same_normal = -1;
259 
260  src_frame = (dmd2frame_t *)((byte *)rawdata + header.ofs_frames);
261  for (int i = 0; i < numindices; i++)
262  {
263  int v = vertIndices[i];
264  int normal = src_frame->verts[v].lightnormalindex;
265 
266  // detect if the model has broken normals - they are all the same in that case
267  // it happens with players/w_<weapon>.md2 models for example
268  if (same_normal < 0)
269  same_normal = normal;
270  else if (normal != same_normal)
271  all_normals_same = qfalse;
272  }
273 
274  for (int i = 0; i < numindices; i++) {
275  remap[i] = 0xFFFF;
276  }
277 
278  // remap all triangle indices
279  numverts = 0;
280  src_tc = (dmd2stvert_t *)((byte *)rawdata + header.ofs_st);
281  for (int i = 0; i < numindices; i++) {
282  if (remap[i] != 0xFFFF) {
283  continue; // already remapped
284  }
285 
286  // only dedup vertices if we're not regenerating normals
287  if (!all_normals_same)
288  {
289  for (int j = i + 1; j < numindices; j++) {
290  if (vertIndices[i] == vertIndices[j] &&
291  (src_tc[tcIndices[i]].s == src_tc[tcIndices[j]].s &&
292  src_tc[tcIndices[i]].t == src_tc[tcIndices[j]].t)) {
293  // duplicate vertex
294  remap[j] = i;
295  finalIndices[j] = numverts;
296  }
297  }
298  }
299 
300  // new vertex
301  remap[i] = i;
302  finalIndices[i] = numverts++;
303  }
304 
305  Hunk_Begin(&model->hunk, 50u<<20);
306  model->type = MOD_ALIAS;
307  model->nummeshes = 1;
308  model->numframes = header.num_frames;
309  model->meshes = MOD_Malloc(sizeof(maliasmesh_t));
310  model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t));
311 
312  dst_mesh = model->meshes;
313  dst_mesh->numtris = numindices / 3;
314  dst_mesh->numindices = numindices;
315  dst_mesh->numverts = numverts;
316  dst_mesh->numskins = header.num_skins;
317  dst_mesh->positions = MOD_Malloc(numverts * header.num_frames * sizeof(vec3_t));
318  dst_mesh->normals = MOD_Malloc(numverts * header.num_frames * sizeof(vec3_t));
319  dst_mesh->tex_coords = MOD_Malloc(numverts * header.num_frames * sizeof(vec2_t));
320  dst_mesh->tangents = MOD_Malloc(numverts * header.num_frames * sizeof(vec4_t));
321  dst_mesh->indices = MOD_Malloc(numindices * sizeof(int));
322 
323  if (dst_mesh->numtris != header.num_tris) {
324  Com_DPrintf("%s has %d bad triangles\n", model->name, header.num_tris - dst_mesh->numtris);
325  }
326 
327  // store final triangle indices
328  for (int i = 0; i < numindices; i++) {
329  dst_mesh->indices[i] = finalIndices[i];
330  }
331 
332  // load all skins
333  src_skin = (char *)rawdata + header.ofs_skins;
334  for (int i = 0; i < header.num_skins; i++) {
335  if (!Q_memccpy(skinname, src_skin, 0, sizeof(skinname))) {
336  ret = Q_ERR_STRING_TRUNCATED;
337  goto fail;
338  }
339  FS_NormalizePath(skinname, skinname);
340 
341  pbr_material_t * mat = MAT_FindPBRMaterial(skinname);
342  if (!mat)
343  Com_EPrintf("error finding material '%s'\n", skinname);
344 
345  image_t* image_diffuse = IMG_Find(skinname, IT_SKIN, IF_SRGB);
346  image_t* image_normals = NULL;
347  image_t* image_emissive = NULL;
348 
349  if (image_diffuse != R_NOTEXTURE)
350  {
351  // attempt loading the normals texture
352  if (!Q_strlcpy(skinname, src_skin, strlen(src_skin) - 3))
353  return Q_ERR_STRING_TRUNCATED;
354 
355  Q_concat(skinname, sizeof(skinname), skinname, "_n.tga", NULL);
356  FS_NormalizePath(skinname, skinname);
357  image_normals = IMG_Find(skinname, IT_SKIN, IF_NONE);
358  if (image_normals == R_NOTEXTURE) image_normals = NULL;
359 
360  // attempt loading the emissive texture
361  if (!Q_strlcpy(skinname, src_skin, strlen(src_skin) - 3))
362  return Q_ERR_STRING_TRUNCATED;
363 
364  Q_concat(skinname, sizeof(skinname), skinname, "_light.tga", NULL);
365  FS_NormalizePath(skinname, skinname);
366  image_emissive = IMG_Find(skinname, IT_SKIN, IF_SRGB);
367  if (image_emissive == R_NOTEXTURE) image_emissive = NULL;
368  }
369 
370  MAT_RegisterPBRMaterial(mat, image_diffuse, image_normals, image_emissive);
371 
372  dst_mesh->materials[i] = mat;
373 
374  src_skin += MD2_MAX_SKINNAME;
375  }
376 
377  // load all tcoords
378  src_tc = (dmd2stvert_t *)((byte *)rawdata + header.ofs_st);
379  scale_s = 1.0f / header.skinwidth;
380  scale_t = 1.0f / header.skinheight;
381 
382  // load all frames
383  src_frame = (dmd2frame_t *)((byte *)rawdata + header.ofs_frames);
384  dst_frame = model->frames;
385  for (int j = 0; j < header.num_frames; j++) {
386  LittleVector(src_frame->scale, dst_frame->scale);
387  LittleVector(src_frame->translate, dst_frame->translate);
388 
389  // load frame vertices
390  ClearBounds(mins, maxs);
391 
392  for (int i = 0; i < numindices; i++) {
393  if (remap[i] != i) {
394  continue;
395  }
396  src_vert = &src_frame->verts[vertIndices[i]];
397  vec3_t *dst_pos = &dst_mesh->positions [j * numverts + finalIndices[i]];
398  vec3_t *dst_nrm = &dst_mesh->normals [j * numverts + finalIndices[i]];
399  vec2_t *dst_tc = &dst_mesh->tex_coords[j * numverts + finalIndices[i]];
400 
401  (*dst_tc)[0] = scale_s * src_tc[tcIndices[i]].s;
402  (*dst_tc)[1] = scale_t * src_tc[tcIndices[i]].t;
403 
404  (*dst_pos)[0] = src_vert->v[0] * dst_frame->scale[0] + dst_frame->translate[0];
405  (*dst_pos)[1] = src_vert->v[1] * dst_frame->scale[1] + dst_frame->translate[1];
406  (*dst_pos)[2] = src_vert->v[2] * dst_frame->scale[2] + dst_frame->translate[2];
407 
408  (*dst_nrm)[0] = 0.0f;
409  (*dst_nrm)[1] = 0.0f;
410  (*dst_nrm)[2] = 0.0f;
411 
412  val = src_vert->lightnormalindex;
413 
414  if (val < NUMVERTEXNORMALS) {
415  (*dst_nrm)[0] = bytedirs[val][0];
416  (*dst_nrm)[1] = bytedirs[val][1];
417  (*dst_nrm)[2] = bytedirs[val][2];
418  }
419 
420  for (int k = 0; k < 3; k++) {
421  val = (*dst_pos)[k];
422  if (val < mins[k])
423  mins[k] = val;
424  if (val > maxs[k])
425  maxs[k] = val;
426  }
427  }
428 
429  // if all normals are the same, rebuild them as flat triangle normals
430  if (all_normals_same)
431  {
432  for (int tri = 0; tri < numindices / 3; tri++)
433  {
434  int i0 = j * numverts + finalIndices[tri * 3 + 0];
435  int i1 = j * numverts + finalIndices[tri * 3 + 1];
436  int i2 = j * numverts + finalIndices[tri * 3 + 2];
437 
438  vec3_t *p0 = &dst_mesh->positions[i0];
439  vec3_t *p1 = &dst_mesh->positions[i1];
440  vec3_t *p2 = &dst_mesh->positions[i2];
441 
442  vec3_t e1, e2, n;
443  VectorSubtract(*p1, *p0, e1);
444  VectorSubtract(*p2, *p0, e2);
445  CrossProduct(e2, e1, n);
446  VectorNormalize(n);
447 
448  VectorCopy(n, dst_mesh->normals[i0]);
449  VectorCopy(n, dst_mesh->normals[i1]);
450  VectorCopy(n, dst_mesh->normals[i2]);
451  }
452  }
453 
454  VectorVectorScale(mins, dst_frame->scale, mins);
455  VectorVectorScale(maxs, dst_frame->scale, maxs);
456 
457  dst_frame->radius = RadiusFromBounds(mins, maxs);
458 
459  VectorAdd(mins, dst_frame->translate, dst_frame->bounds[0]);
460  VectorAdd(maxs, dst_frame->translate, dst_frame->bounds[1]);
461 
462  src_frame = (dmd2frame_t *)((byte *)src_frame + header.framesize);
463  dst_frame++;
464  }
465 
466  // fix winding order
467  for (int i = 0; i < dst_mesh->numindices; i += 3) {
468  int tmp = dst_mesh->indices[i + 1];
469  dst_mesh->indices[i + 1] = dst_mesh->indices[i + 2];
470  dst_mesh->indices[i + 2] = tmp;
471  }
472 
473  computeTangents(model);
474 
475  Hunk_End(&model->hunk);
476  return Q_ERR_SUCCESS;
477 
478 fail:
479  Hunk_Free(&model->hunk);
480  return ret;
481 }
482 
483 #if USE_MD3
484 
485 #define TAB_SIN(x) qvk.sintab[(x) & 255]
486 #define TAB_COS(x) qvk.sintab[((x) + 64) & 255]
487 
488 static qerror_t MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,
489  const byte *rawdata, size_t length, size_t *offset_p)
490 {
491  dmd3mesh_t header;
492  size_t end;
493  dmd3vertex_t *src_vert;
494  dmd3coord_t *src_tc;
495  dmd3skin_t *src_skin;
496  uint32_t *src_idx;
497  vec3_t *dst_vert;
498  vec3_t *dst_norm;
499  vec2_t *dst_tc;
500  vec4_t *dst_tan;
501  int *dst_idx;
502  char skinname[MAX_QPATH];
503  int i;
504 
505  if (length < sizeof(header))
506  return Q_ERR_BAD_EXTENT;
507 
508  // byte swap the header
509  header = *(dmd3mesh_t *)rawdata;
510  for (i = 0; i < sizeof(header) / 4; i++)
511  ((uint32_t *)&header)[i] = LittleLong(((uint32_t *)&header)[i]);
512 
513  if (header.meshsize < sizeof(header) || header.meshsize > length)
514  return Q_ERR_BAD_EXTENT;
515  if (header.num_verts < 3)
516  return Q_ERR_TOO_FEW;
517  if (header.num_verts > TESS_MAX_VERTICES)
518  return Q_ERR_TOO_MANY;
519  if (header.num_tris < 1)
520  return Q_ERR_TOO_FEW;
521  if (header.num_tris > TESS_MAX_INDICES / 3)
522  return Q_ERR_TOO_MANY;
523  if (header.num_skins > MAX_ALIAS_SKINS)
524  return Q_ERR_TOO_MANY;
525  end = header.ofs_skins + header.num_skins * sizeof(dmd3skin_t);
526  if (end < header.ofs_skins || end > length)
527  return Q_ERR_BAD_EXTENT;
528  end = header.ofs_verts + header.num_verts * model->numframes * sizeof(dmd3vertex_t);
529  if (end < header.ofs_verts || end > length)
530  return Q_ERR_BAD_EXTENT;
531  end = header.ofs_tcs + header.num_verts * sizeof(dmd3coord_t);
532  if (end < header.ofs_tcs || end > length)
533  return Q_ERR_BAD_EXTENT;
534  end = header.ofs_indexes + header.num_tris * 3 * sizeof(uint32_t);
535  if (end < header.ofs_indexes || end > length)
536  return Q_ERR_BAD_EXTENT;
537 
538  mesh->numtris = header.num_tris;
539  mesh->numindices = header.num_tris * 3;
540  mesh->numverts = header.num_verts;
541  mesh->numskins = header.num_skins;
542  mesh->positions = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec3_t));
543  mesh->normals = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec3_t));
544  mesh->tex_coords = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec2_t));
545  mesh->tangents = MOD_Malloc(header.num_verts * header.num_frames * sizeof(vec4_t));
546  mesh->indices = MOD_Malloc(sizeof(int) * header.num_tris * 3);
547 
548  // load all skins
549  src_skin = (dmd3skin_t *)(rawdata + header.ofs_skins);
550  for (i = 0; i < header.num_skins; i++) {
551  if (!Q_memccpy(skinname, src_skin->name, 0, sizeof(skinname)))
552  return Q_ERR_STRING_TRUNCATED;
553  FS_NormalizePath(skinname, skinname);
554 
555  pbr_material_t * mat = MAT_FindPBRMaterial(skinname);
556  if (!mat)
557  Com_EPrintf("error finding material '%s'\n", skinname);
558 
559  image_t* image_diffuse = IMG_Find(skinname, IT_SKIN, IF_SRGB);
560  image_t* image_normals = NULL;
561  image_t* image_emissive = NULL;
562 
563  if (image_diffuse != R_NOTEXTURE)
564  {
565  // attempt loading the normals texture
566  if (!Q_strlcpy(skinname, src_skin->name, strlen(src_skin->name) - 3))
567  return Q_ERR_STRING_TRUNCATED;
568 
569  Q_concat(skinname, sizeof(skinname), skinname, "_n.tga", NULL);
570  FS_NormalizePath(skinname, skinname);
571  image_normals = IMG_Find(skinname, IT_SKIN, IF_NONE);
572  if (image_normals == R_NOTEXTURE) image_normals = NULL;
573 
574  // attempt loading the emissive texture
575  if (!Q_strlcpy(skinname, src_skin->name, strlen(src_skin->name) - 3))
576  return Q_ERR_STRING_TRUNCATED;
577 
578  Q_concat(skinname, sizeof(skinname), skinname, "_light.tga", NULL);
579  FS_NormalizePath(skinname, skinname);
580  image_emissive = IMG_Find(skinname, IT_SKIN, IF_SRGB);
581  if (image_emissive == R_NOTEXTURE) image_emissive = NULL;
582  }
583 
584  MAT_RegisterPBRMaterial(mat, image_diffuse, image_normals, image_emissive);
585 
586  mesh->materials[i] = mat;
587  }
588 
589  // load all vertices
590  src_vert = (dmd3vertex_t *)(rawdata + header.ofs_verts);
591  dst_vert = mesh->positions;
592  dst_norm = mesh->normals;
593  dst_tc = mesh->tex_coords;
594  dst_tan = mesh->tangents;
595  for (int frame = 0; frame < header.num_frames; frame++)
596  {
597  src_tc = (dmd3coord_t *)(rawdata + header.ofs_tcs);
598 
599  for (i = 0; i < header.num_verts; i++)
600  {
601  (*dst_vert)[0] = (float)(src_vert->point[0]) / 64.f;
602  (*dst_vert)[1] = (float)(src_vert->point[1]) / 64.f;
603  (*dst_vert)[2] = (float)(src_vert->point[2]) / 64.f;
604 
605  unsigned int lat = src_vert->norm[0];
606  unsigned int lng = src_vert->norm[1];
607 
608  (*dst_norm)[0] = TAB_SIN(lat) * TAB_COS(lng);
609  (*dst_norm)[1] = TAB_SIN(lat) * TAB_SIN(lng);
610  (*dst_norm)[2] = TAB_COS(lat);
611 
612  VectorNormalize(*dst_norm);
613 
614  (*dst_tc)[0] = LittleFloat(src_tc->st[0]);
615  (*dst_tc)[1] = LittleFloat(src_tc->st[1]);
616 
617  (*dst_tan)[0] = 0.0f;
618  (*dst_tan)[1] = 0.0f;
619  (*dst_tan)[2] = 0.0f;
620  (*dst_tan)[3] = 0.0f;
621 
622  src_vert++; dst_vert++; dst_norm++;
623  src_tc++; dst_tc++; dst_tan++;
624  }
625  }
626 
627 
628  // load all triangle indices
629  src_idx = (uint32_t *)(rawdata + header.ofs_indexes);
630  dst_idx = mesh->indices;
631  for (i = 0; i < header.num_tris; i++)
632  {
633  dst_idx[0] = LittleLong(src_idx[2]);
634  dst_idx[1] = LittleLong(src_idx[1]);
635  dst_idx[2] = LittleLong(src_idx[0]);
636 
637  if (dst_idx[0] >= header.num_verts)
638  return Q_ERR_BAD_INDEX;
639 
640  src_idx += 3;
641  dst_idx += 3;
642  }
643 
644  *offset_p = header.meshsize;
645 
646  return Q_ERR_SUCCESS;
647 }
648 
649 qerror_t MOD_LoadMD3_RTX(model_t *model, const void *rawdata, size_t length)
650 {
651  dmd3header_t header;
652  size_t end, offset, remaining;
653  dmd3frame_t *src_frame;
654  maliasframe_t *dst_frame;
655  const byte *src_mesh;
656  int i;
657  qerror_t ret;
658 
659  if (length < sizeof(header))
660  return Q_ERR_FILE_TOO_SMALL;
661 
662  // byte swap the header
663  header = *(dmd3header_t *)rawdata;
664  for (i = 0; i < sizeof(header) / 4; i++)
665  ((uint32_t *)&header)[i] = LittleLong(((uint32_t *)&header)[i]);
666 
667  if (header.ident != MD3_IDENT)
668  return Q_ERR_UNKNOWN_FORMAT;
669  if (header.version != MD3_VERSION)
670  return Q_ERR_UNKNOWN_FORMAT;
671  if (header.num_frames < 1)
672  return Q_ERR_TOO_FEW;
673  if (header.num_frames > MD3_MAX_FRAMES)
674  return Q_ERR_TOO_MANY;
675  end = header.ofs_frames + sizeof(dmd3frame_t) * header.num_frames;
676  if (end < header.ofs_frames || end > length)
677  return Q_ERR_BAD_EXTENT;
678  if (header.num_meshes < 1)
679  return Q_ERR_TOO_FEW;
680  if (header.num_meshes > MD3_MAX_MESHES)
681  return Q_ERR_TOO_MANY;
682  if (header.ofs_meshes > length)
683  return Q_ERR_BAD_EXTENT;
684 
685  Hunk_Begin(&model->hunk, 0x4000000);
686  model->type = MOD_ALIAS;
687  model->numframes = header.num_frames;
688  model->nummeshes = header.num_meshes;
689  model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * header.num_meshes);
690  model->frames = MOD_Malloc(sizeof(maliasframe_t) * header.num_frames);
691 
692  // load all frames
693  src_frame = (dmd3frame_t *)((byte *)rawdata + header.ofs_frames);
694  dst_frame = model->frames;
695  for (i = 0; i < header.num_frames; i++) {
696  LittleVector(src_frame->translate, dst_frame->translate);
697  VectorSet(dst_frame->scale, MD3_XYZ_SCALE, MD3_XYZ_SCALE, MD3_XYZ_SCALE);
698 
699  LittleVector(src_frame->mins, dst_frame->bounds[0]);
700  LittleVector(src_frame->maxs, dst_frame->bounds[1]);
701  dst_frame->radius = LittleFloat(src_frame->radius);
702 
703  src_frame++; dst_frame++;
704  }
705 
706  // load all meshes
707  src_mesh = (const byte *)rawdata + header.ofs_meshes;
708  remaining = length - header.ofs_meshes;
709  for (i = 0; i < header.num_meshes; i++) {
710  ret = MOD_LoadMD3Mesh(model, &model->meshes[i], src_mesh, remaining, &offset);
711  if (ret)
712  goto fail;
713  src_mesh += offset;
714  remaining -= offset;
715  }
716 
717  computeTangents(model);
718 
719  //if (strstr(model->name, "v_blast"))
720  // export_obj_frames(model, "export/v_blast_%d.obj");
721 
722  Hunk_End(&model->hunk);
723  return Q_ERR_SUCCESS;
724 
725 fail:
726  Hunk_Free(&model->hunk);
727  return ret;
728 }
729 #endif
730 
731 void MOD_Reference_RTX(model_t *model)
732 {
733  int mesh_idx, skin_idx, frame_idx;
734 
735  // register any images used by the models
736  switch (model->type) {
737  case MOD_ALIAS:
738  for (mesh_idx = 0; mesh_idx < model->nummeshes; mesh_idx++) {
739  maliasmesh_t *mesh = &model->meshes[mesh_idx];
740  for (skin_idx = 0; skin_idx < mesh->numskins; skin_idx++) {
741  MAT_UpdateRegistration(mesh->materials[skin_idx]);
742  }
743  }
744  break;
745  case MOD_SPRITE:
746  for (frame_idx = 0; frame_idx < model->numframes; frame_idx++) {
747  model->spriteframes[frame_idx].image->registration_sequence = registration_sequence;
748  }
749  break;
750  case MOD_EMPTY:
751  break;
752  default:
753  Com_Error(ERR_FATAL, "%s: bad model type", __func__);
754  }
755 
756  model->registration_sequence = registration_sequence;
757 }
758 
759 // vim: shiftwidth=4 noexpandtab tabstop=4 cindent
RadiusFromBounds
vec_t RadiusFromBounds(const vec3_t mins, const vec3_t maxs)
Definition: shared.c:127
maliasmesh_s
Definition: gl.h:232
TESS_MAX_INDICES
#define TESS_MAX_INDICES
Definition: gl.h:460
maliasmesh_s::numindices
int numindices
Definition: gl.h:235
maliasframe_s::scale
vec3_t scale
Definition: gl.h:226
image_t
struct image_s image_t
Definition: material.h:27
Hunk_Begin
void Hunk_Begin(memhunk_t *hunk, size_t maxsize)
Definition: hunk.c:23
computeTangents
static void computeTangents(model_t *model)
Definition: models.c:56
MOD_LoadMD3_RTX
qerror_t MOD_LoadMD3_RTX(model_t *model, const void *rawdata, size_t length)
MAT_UpdateRegistration
void MAT_UpdateRegistration(pbr_material_t *mat)
Definition: material.c:421
vkpt.h
MOD_ValidateMD2
qerror_t MOD_ValidateMD2(dmd2header_t *header, size_t length)
Definition: models.c:142
maliasmesh_s::indices
QGL_INDEX_TYPE * indices
Definition: gl.h:236
TAB_COS
#define TAB_COS(x)
Definition: gl.h:55
MAT_RegisterPBRMaterial
qerror_t MAT_RegisterPBRMaterial(pbr_material_t *mat, image_t *image_diffuse, image_t *image_normals, image_t *image_emissive)
Definition: material.c:397
maliasmesh_s::tex_coords
vec2_t * tex_coords
Definition: vkpt.h:701
maliasframe_s::translate
vec3_t translate
Definition: gl.h:227
maliasmesh_s::numverts
int numverts
Definition: gl.h:233
Hunk_Free
void Hunk_Free(memhunk_t *hunk)
Definition: hunk.c:75
maliasmesh_s::positions
vec3_t * positions
Definition: vkpt.h:699
TESS_MAX_VERTICES
#define TESS_MAX_VERTICES
Definition: gl.h:459
TAB_SIN
#define TAB_SIN(x)
Definition: gl.h:54
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
maliasframe_s::bounds
vec3_t bounds[2]
Definition: gl.h:228
maliasframe_s::radius
vec_t radius
Definition: gl.h:229
material.h
pbr_material_s
Definition: material.h:33
maliasmesh_s::materials
struct pbr_material_s * materials[MAX_ALIAS_SKINS]
Definition: vkpt.h:703
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
ClearBounds
void ClearBounds(vec3_t mins, vec3_t maxs)
Definition: shared.c:91
Hunk_End
void Hunk_End(memhunk_t *hunk)
Definition: hunk.c:66
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
MOD_LoadMD2_RTX
qerror_t MOD_LoadMD2_RTX(model_t *model, const void *rawdata, size_t length)
Definition: models.c:186
maliasmesh_s::tangents
vec4_t * tangents
Definition: vkpt.h:702
VectorNormalize2
vec_t VectorNormalize2(vec3_t v, vec3_t out)
Definition: shared.c:73
IMG_Find
image_t * IMG_Find(const char *name, imagetype_t type, imageflags_t flags)
Definition: images.c:1122
registration_sequence
int registration_sequence
Definition: main.c:34
export_obj_frames
static void export_obj_frames(model_t *model, const char *path_pattern)
Definition: models.c:139
maliasmesh_s::numtris
int numtris
Definition: gl.h:234
maliasmesh_s::normals
vec3_t * normals
Definition: vkpt.h:700
MOD_Reference_RTX
void MOD_Reference_RTX(model_t *model)
Definition: models.c:731
Q_memccpy
void * Q_memccpy(void *dst, const void *src, int c, size_t size)
Definition: shared.c:895
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
bytedirs
const vec3_t bytedirs[NUMVERTEXNORMALS]
Definition: math.c:80
maliasframe_s
Definition: gl.h:225
VectorNormalize
vec_t VectorNormalize(vec3_t v)
Definition: shared.c:55
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
maliasmesh_s::numskins
int numskins
Definition: gl.h:240
MAT_FindPBRMaterial
pbr_material_t * MAT_FindPBRMaterial(char const *name)
Definition: material.c:465