Quake II RTX doxygen  1.0 dev
models.c File Reference
#include "shared/shared.h"
#include "shared/list.h"
#include "common/common.h"
#include "common/files.h"
#include "system/hunk.h"
#include "format/md2.h"
#include "format/sp2.h"
#include "refresh/images.h"
#include "refresh/models.h"

Go to the source code of this file.

Macros

#define MAX_RMODELS   (MAX_MODELS * 2)
 

Functions

static model_t * MOD_Alloc (void)
 
static model_t * MOD_Find (const char *name)
 
static void MOD_List_f (void)
 
void MOD_FreeUnused (void)
 
void MOD_FreeAll (void)
 
qerror_t MOD_ValidateMD2 (dmd2header_t *header, size_t length)
 
static model_class_t get_model_class (const char *name)
 
static qerror_t MOD_LoadSP2 (model_t *model, const void *rawdata, size_t length)
 
qhandle_t R_RegisterModel (const char *name)
 
model_t * MOD_ForHandle (qhandle_t h)
 
void MOD_Init (void)
 
void MOD_Shutdown (void)
 

Variables

model_t r_models [MAX_RMODELS]
 
int r_numModels
 
cvar_t * vid_rtx
 

Macro Definition Documentation

◆ MAX_RMODELS

#define MAX_RMODELS   (MAX_MODELS * 2)

Definition at line 37 of file models.c.

Function Documentation

◆ get_model_class()

static model_class_t get_model_class ( const char *  name)
static

Definition at line 209 of file models.c.

210 {
211  if (!strcmp(name, "models/objects/explode/tris.md2"))
212  return MCLASS_EXPLOSION;
213  else if (!strcmp(name, "models/objects/r_explode/tris.md2"))
214  return MCLASS_EXPLOSION;
215  else if (!strcmp(name, "models/objects/flash/tris.md2"))
216  return MCLASS_SMOKE;
217  else if (!strcmp(name, "models/objects/smoke/tris.md2"))
218  return MCLASS_SMOKE;
219  else if (!strcmp(name, "models/objects/minelite/light2/tris.md2"))
220  return MCLASS_STATIC_LIGHT;
221  else if (!strcmp(name, "models/objects/flare/tris.md2"))
222  return MCLASS_FLARE;
223  else
224  return MCLASS_REGULAR;
225 }

Referenced by R_RegisterModel().

◆ MOD_Alloc()

static model_t* MOD_Alloc ( void  )
static

Definition at line 44 of file models.c.

45 {
46  model_t *model;
47  int i;
48 
49  for (i = 0, model = r_models; i < r_numModels; i++, model++) {
50  if (!model->type) {
51  break;
52  }
53  }
54 
55  if (i == r_numModels) {
56  if (r_numModels == MAX_RMODELS) {
57  return NULL;
58  }
59  r_numModels++;
60  }
61 
62  return model;
63 }

Referenced by R_RegisterModel().

◆ MOD_Find()

static model_t* MOD_Find ( const char *  name)
static

Definition at line 65 of file models.c.

66 {
67  model_t *model;
68  int i;
69 
70  for (i = 0, model = r_models; i < r_numModels; i++, model++) {
71  if (!model->type) {
72  continue;
73  }
74  if (!FS_pathcmp(model->name, name)) {
75  return model;
76  }
77  }
78 
79  return NULL;
80 }

Referenced by R_RegisterModel().

◆ MOD_ForHandle()

model_t* MOD_ForHandle ( qhandle_t  h)

Definition at line 430 of file models.c.

431 {
432  model_t *model;
433 
434  if (!h) {
435  return NULL;
436  }
437 
438  if (h < 0 || h > r_numModels) {
439  Com_Error(ERR_DROP, "%s: %d out of range", __func__, h);
440  }
441 
442  model = &r_models[h - 1];
443  if (!model->type) {
444  return NULL;
445  }
446 
447  return model;
448 }

Referenced by CL_AddPacketEntities(), CL_AddViewWeapon(), CL_PlainExplosion(), CL_RegisterTEntModels(), GL_DrawEntities(), prepare_entities(), R_DrawEntities(), update_transparency(), and write_sprite_geometry().

◆ MOD_FreeAll()

void MOD_FreeAll ( void  )

Definition at line 125 of file models.c.

126 {
127  model_t *model;
128  int i;
129 
130  for (i = 0, model = r_models; i < r_numModels; i++, model++) {
131  if (!model->type) {
132  continue;
133  }
134 
135  Hunk_Free(&model->hunk);
136  memset(model, 0, sizeof(*model));
137  }
138 
139  r_numModels = 0;
140 }

Referenced by MOD_Shutdown().

◆ MOD_FreeUnused()

void MOD_FreeUnused ( void  )

Definition at line 105 of file models.c.

106 {
107  model_t *model;
108  int i;
109 
110  for (i = 0, model = r_models; i < r_numModels; i++, model++) {
111  if (!model->type) {
112  continue;
113  }
114  if (model->registration_sequence == registration_sequence) {
115  // make sure it is paged in
116  Com_PageInMemory(model->hunk.base, model->hunk.cursize);
117  } else {
118  // don't need this model
119  Hunk_Free(&model->hunk);
120  memset(model, 0, sizeof(*model));
121  }
122  }
123 }

Referenced by R_EndRegistration(), R_EndRegistration_GL(), and R_EndRegistration_RTX().

◆ MOD_Init()

void MOD_Init ( void  )

Definition at line 450 of file models.c.

451 {
452  if (r_numModels) {
453  Com_Error(ERR_FATAL, "%s: %d models not freed", __func__, r_numModels);
454  }
455 
456  Cmd_AddCommand("modellist", MOD_List_f);
457 }

Referenced by GL_PostInit(), R_Init(), and R_Init_RTX().

◆ MOD_List_f()

static void MOD_List_f ( void  )
static

Definition at line 82 of file models.c.

83 {
84  static const char types[4] = "FASE";
85  int i, count;
86  model_t *model;
87  size_t bytes;
88 
89  Com_Printf("------------------\n");
90  bytes = count = 0;
91 
92  for (i = 0, model = r_models; i < r_numModels; i++, model++) {
93  if (!model->type) {
94  continue;
95  }
96  Com_Printf("%c %8"PRIz" : %s\n", types[model->type],
97  model->hunk.mapped, model->name);
98  bytes += model->hunk.mapped;
99  count++;
100  }
101  Com_Printf("Total models: %d (out of %d slots)\n", count, r_numModels);
102  Com_Printf("Total resident: %"PRIz"\n", bytes);
103 }

Referenced by MOD_Init().

◆ MOD_LoadSP2()

static qerror_t MOD_LoadSP2 ( model_t *  model,
const void rawdata,
size_t  length 
)
static

Definition at line 227 of file models.c.

228 {
229  dsp2header_t header;
230  dsp2frame_t *src_frame;
231  mspriteframe_t *dst_frame;
232  unsigned w, h, x, y;
233  char buffer[SP2_MAX_FRAMENAME];
234  int i;
235 
236  if (length < sizeof(header))
237  return Q_ERR_FILE_TOO_SMALL;
238 
239  // byte swap the header
240  header = *(dsp2header_t *)rawdata;
241  for (i = 0; i < sizeof(header) / 4; i++) {
242  ((uint32_t *)&header)[i] = LittleLong(((uint32_t *)&header)[i]);
243  }
244 
245  if (header.ident != SP2_IDENT)
246  return Q_ERR_UNKNOWN_FORMAT;
247  if (header.version != SP2_VERSION)
248  return Q_ERR_UNKNOWN_FORMAT;
249  if (header.numframes < 1) {
250  // empty models draw nothing
251  model->type = MOD_EMPTY;
252  return Q_ERR_SUCCESS;
253  }
254  if (header.numframes > SP2_MAX_FRAMES)
255  return Q_ERR_TOO_MANY;
256  if (sizeof(dsp2header_t) + sizeof(dsp2frame_t) * header.numframes > length)
257  return Q_ERR_BAD_EXTENT;
258 
259  Hunk_Begin(&model->hunk, 0x10000);
260  model->type = MOD_SPRITE;
261 
262  model->spriteframes = MOD_Malloc(sizeof(mspriteframe_t) * header.numframes);
263  model->numframes = header.numframes;
264 
265  src_frame = (dsp2frame_t *)((byte *)rawdata + sizeof(dsp2header_t));
266  dst_frame = model->spriteframes;
267  for (i = 0; i < header.numframes; i++) {
268  w = LittleLong(src_frame->width);
269  h = LittleLong(src_frame->height);
270  if (w < 1 || h < 1 || w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) {
271  Com_WPrintf("%s has bad frame dimensions\n", model->name);
272  w = 1;
273  h = 1;
274  }
275  dst_frame->width = w;
276  dst_frame->height = h;
277 
278  // FIXME: are these signed?
279  x = LittleLong(src_frame->origin_x);
280  y = LittleLong(src_frame->origin_y);
281  if (x > 8192 || y > 8192) {
282  Com_WPrintf("%s has bad frame origin\n", model->name);
283  x = y = 0;
284  }
285  dst_frame->origin_x = x;
286  dst_frame->origin_y = y;
287 
288  if (!Q_memccpy(buffer, src_frame->name, 0, sizeof(buffer))) {
289  Com_WPrintf("%s has bad frame name\n", model->name);
290  dst_frame->image = R_NOTEXTURE;
291  } else {
292  FS_NormalizePath(buffer, buffer);
293  dst_frame->image = IMG_Find(buffer, IT_SPRITE, IF_SRGB);
294  }
295 
296  src_frame++;
297  dst_frame++;
298  }
299 
300  Hunk_End(&model->hunk);
301 
302  return Q_ERR_SUCCESS;
303 }

Referenced by R_RegisterModel().

◆ MOD_Shutdown()

void MOD_Shutdown ( void  )

Definition at line 459 of file models.c.

460 {
461  MOD_FreeAll();
462  Cmd_RemoveCommand("modellist");
463 }

Referenced by R_Shutdown(), R_Shutdown_GL(), and R_Shutdown_RTX().

◆ MOD_ValidateMD2()

qerror_t MOD_ValidateMD2 ( dmd2header_t *  header,
size_t  length 
)

Definition at line 142 of file models.c.

143 {
144  size_t end;
145 
146  // check ident and version
147  if (header->ident != MD2_IDENT)
148  return Q_ERR_UNKNOWN_FORMAT;
149  if (header->version != MD2_VERSION)
150  return Q_ERR_UNKNOWN_FORMAT;
151 
152  // check triangles
153  if (header->num_tris < 1)
154  return Q_ERR_TOO_FEW;
155  if (header->num_tris > MD2_MAX_TRIANGLES)
156  return Q_ERR_TOO_MANY;
157 
158  end = header->ofs_tris + sizeof(dmd2triangle_t) * header->num_tris;
159  if (header->ofs_tris < sizeof(header) || end < header->ofs_tris || end > length)
160  return Q_ERR_BAD_EXTENT;
161 
162  // check st
163  if (header->num_st < 3)
164  return Q_ERR_TOO_FEW;
165  if (header->num_st > MAX_ALIAS_VERTS)
166  return Q_ERR_TOO_MANY;
167 
168  end = header->ofs_st + sizeof(dmd2stvert_t) * header->num_st;
169  if (header->ofs_st < sizeof(header) || end < header->ofs_st || end > length)
170  return Q_ERR_BAD_EXTENT;
171 
172  // check xyz and frames
173  if (header->num_xyz < 3)
174  return Q_ERR_TOO_FEW;
175  if (header->num_xyz > MAX_ALIAS_VERTS)
176  return Q_ERR_TOO_MANY;
177  if (header->num_frames < 1)
178  return Q_ERR_TOO_FEW;
179  if (header->num_frames > MD2_MAX_FRAMES)
180  return Q_ERR_TOO_MANY;
181 
182  end = sizeof(dmd2frame_t) + (header->num_xyz - 1) * sizeof(dmd2trivertx_t);
183  if (header->framesize < end || header->framesize > MD2_MAX_FRAMESIZE)
184  return Q_ERR_BAD_EXTENT;
185 
186  end = header->ofs_frames + (size_t)header->framesize * header->num_frames;
187  if (header->ofs_frames < sizeof(header) || end < header->ofs_frames || end > length)
188  return Q_ERR_BAD_EXTENT;
189 
190  // check skins
191  if (header->num_skins) {
192  if (header->num_skins > MAX_ALIAS_SKINS)
193  return Q_ERR_TOO_MANY;
194 
195  end = header->ofs_skins + (size_t)MD2_MAX_SKINNAME * header->num_skins;
196  if (header->ofs_skins < sizeof(header) || end < header->ofs_skins || end > length)
197  return Q_ERR_BAD_EXTENT;
198  }
199 
200  if (header->skinwidth < 1 || header->skinwidth > MD2_MAX_SKINWIDTH)
201  return Q_ERR_INVALID_FORMAT;
202  if (header->skinheight < 1 || header->skinheight > MD2_MAX_SKINHEIGHT)
203  return Q_ERR_INVALID_FORMAT;
204 
205  return Q_ERR_SUCCESS;
206 }

Referenced by MOD_LoadMD2(), MOD_LoadMD2_GL(), and MOD_LoadMD2_RTX().

◆ R_RegisterModel()

qhandle_t R_RegisterModel ( const char *  name)

Definition at line 305 of file models.c.

306 {
307  char normalized[MAX_QPATH];
308  qhandle_t index;
309  size_t namelen;
310  ssize_t filelen;
311  model_t *model;
312  byte *rawdata = NULL;
313  uint32_t ident;
314  mod_load_t load;
315  qerror_t ret;
316 
317  // empty names are legal, silently ignore them
318  if (!*name)
319  return 0;
320 
321  if (*name == '*') {
322  // inline bsp model
323  index = atoi(name + 1);
324  return ~index;
325  }
326 
327  // normalize the path
328  namelen = FS_NormalizePathBuffer(normalized, name, MAX_QPATH);
329 
330  // this should never happen
331  if (namelen >= MAX_QPATH)
332  Com_Error(ERR_DROP, "%s: oversize name", __func__);
333 
334  // normalized to empty name?
335  if (namelen == 0) {
336  Com_DPrintf("%s: empty name\n", __func__);
337  return 0;
338  }
339 
340  // see if it's already loaded
341  model = MOD_Find(normalized);
342  if (model) {
343  MOD_Reference(model);
344  goto done;
345  }
346 
347  char* extension = normalized + namelen - 4;
348  if (namelen > 4 && (strcmp(extension, ".md2") == 0) && vid_rtx->integer)
349  {
350  memcpy(extension, ".md3", 4);
351 
352  filelen = FS_LoadFile(normalized, (void **)&rawdata);
353 
354  memcpy(extension, ".md2", 4);
355  }
356 
357  if (!rawdata)
358  {
359  filelen = FS_LoadFile(normalized, (void **)&rawdata);
360  if (!rawdata) {
361  // don't spam about missing models
362  if (filelen == Q_ERR_NOENT) {
363  return 0;
364  }
365 
366  ret = filelen;
367  goto fail1;
368  }
369  }
370 
371  if (filelen < 4) {
372  ret = Q_ERR_FILE_TOO_SMALL;
373  goto fail2;
374  }
375 
376  // check ident
377  ident = LittleLong(*(uint32_t *)rawdata);
378  switch (ident) {
379  case MD2_IDENT:
380  load = MOD_LoadMD2;
381  break;
382 #if USE_MD3
383  case MD3_IDENT:
384  load = MOD_LoadMD3;
385  break;
386 #endif
387  case SP2_IDENT:
388  load = MOD_LoadSP2;
389  break;
390  default:
391  ret = Q_ERR_UNKNOWN_FORMAT;
392  goto fail2;
393  }
394 
395  model = MOD_Alloc();
396  if (!model) {
397  ret = Q_ERR_OUT_OF_SLOTS;
398  goto fail2;
399  }
400 
401  memcpy(model->name, normalized, namelen + 1);
402  model->registration_sequence = registration_sequence;
403 
404  ret = load(model, rawdata, filelen);
405 
406  FS_FreeFile(rawdata);
407 
408  if (ret) {
409  memset(model, 0, sizeof(*model));
410  goto fail1;
411  }
412 
413  model->model_class = get_model_class(model->name);
414 
415 done:
416  index = (model - r_models) + 1;
417 #if USE_REF == REF_VKPT
418  extern int register_model_dirty;
420 #endif
421  return index;
422 
423 fail2:
424  FS_FreeFile(rawdata);
425 fail1:
426  Com_EPrintf("Couldn't load %s: %s\n", normalized, Q_ErrorString(ret));
427  return 0;
428 }

Referenced by CL_LoadClientinfo(), CL_PrepRefresh(), CL_RegisterTEntModels(), CL_UpdateConfigstring(), LOC_AddLocationsToScene(), ReloadMedia(), and V_Gun_Model_f().

Variable Documentation

◆ r_models

◆ r_numModels

int r_numModels

◆ vid_rtx

MOD_Reference
void(* MOD_Reference)(model_t *model)
Definition: refresh.c:438
register_model_dirty
int register_model_dirty
Definition: main.c:431
vid_rtx
cvar_t * vid_rtx
Definition: refresh.c:30
Hunk_Begin
void Hunk_Begin(memhunk_t *hunk, size_t maxsize)
Definition: hunk.c:23
Cmd_AddCommand
void Cmd_AddCommand(const char *name, xcommand_t function)
Definition: cmd.c:1562
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
MOD_Alloc
static model_t * MOD_Alloc(void)
Definition: models.c:44
MOD_List_f
static void MOD_List_f(void)
Definition: models.c:82
MOD_Find
static model_t * MOD_Find(const char *name)
Definition: models.c:65
r_numModels
int r_numModels
Definition: models.c:40
Hunk_Free
void Hunk_Free(memhunk_t *hunk)
Definition: hunk.c:75
FS_NormalizePathBuffer
size_t FS_NormalizePathBuffer(char *out, const char *in, size_t size)
Definition: files.c:400
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
Cmd_RemoveCommand
void Cmd_RemoveCommand(const char *name)
Definition: cmd.c:1593
load
qerror_t(* load)(byte *, size_t, image_t *, byte **)
Definition: images.c:658
MOD_LoadMD2
qerror_t(* MOD_LoadMD2)(model_t *model, const void *rawdata, size_t length)
Definition: refresh.c:434
MOD_FreeAll
void MOD_FreeAll(void)
Definition: models.c:125
Hunk_End
void Hunk_End(memhunk_t *hunk)
Definition: hunk.c:66
IMG_Find
image_t * IMG_Find(const char *name, imagetype_t type, imageflags_t flags)
Definition: images.c:1122
MOD_LoadSP2
static qerror_t MOD_LoadSP2(model_t *model, const void *rawdata, size_t length)
Definition: models.c:227
MAX_RMODELS
#define MAX_RMODELS
Definition: models.c:37
registration_sequence
int registration_sequence
Definition: main.c:34
Q_memccpy
void * Q_memccpy(void *dst, const void *src, int c, size_t size)
Definition: shared.c:895
Com_PageInMemory
void Com_PageInMemory(void *buffer, size_t size)
Definition: utils.c:383
get_model_class
static model_class_t get_model_class(const char *name)
Definition: models.c:209
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
r_models
model_t r_models[MAX_RMODELS]
Definition: models.c:39