UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
r_model_obj.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 1997-2009 Quake2World
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 /* object model memory representation */
27 typedef struct mobjvert_s {
28  int vert;
29  int normal;
30  int texcoord;
31 } mobjvert_t;
32 
33 typedef struct mobjtri_s {
35 } mobjtri_t;
36 
37 typedef struct mobj_s {
38  int num_verts;
40  float* verts;
41 
44  float* normals;
45 
48  float* texcoords;
49 
50  int num_tris;
53 } mobj_t;
54 
55 #include "r_local.h"
56 #include "../../shared/parse.h"
57 
58 static void R_LoadObjModelVertexArrays (mobj_t* obj, model_t* mod)
59 {
60  mAliasMesh_t* mesh = mod->alias.meshes;
61  const int v = obj->num_tris * 3 * 3;
62  const int st = obj->num_tris * 3 * 2;
63  const mobjtri_t* t = obj->tris;
64 
65  mesh->num_tris = obj->num_tris;
66  mesh->num_verts = obj->num_verts;
67 
68  mesh->verts = Mem_PoolAllocTypeN(float, v, vid_modelPool);
69  mesh->normals = Mem_PoolAllocTypeN(float, v, vid_modelPool);
70  mesh->texcoords = Mem_PoolAllocTypeN(float, st, vid_modelPool);
71 
72  /* fill the arrays */
73  int vertind = 0, coordind = 0;
74  for (int i = 0; i < obj->num_tris; i++, t++) {
75  const mobjvert_t* v = t->verts;
76 
77  /* each vert */
78  for (int j = 0; j < 3; j++, v++) {
79  assert(v->vert - 1 >= 0);
80  VectorCopy((&obj->verts[(v->vert - 1) * 3]), (&mesh->verts[vertind + j * 3]));
81 
82  if (v->normal) {
83  assert(v->normal - 1 >= 0);
84  VectorCopy((&obj->normals[(v->normal - 1) * 3]), (&mesh->normals[vertind + j * 3]));
85  }
86 
87  if (v->texcoord) {
88  assert(v->texcoord - 1 >= 0);
89  memcpy(&mesh->texcoords[coordind + j * 2], &obj->texcoords[(v->texcoord - 1) * 2], sizeof(vec2_t));
90  }
91  }
92 
93  coordind += 6;
94  vertind += 9;
95  }
96 }
97 
98 #define MAX_OBJ_FACE_VERTS 128
99 
103 static void R_LoadObjModelTris (mobj_t* obj, const mobjvert_t* verts, int count)
104 {
105  if (!obj->tris)
106  return;
107 
108  assert(count < MAX_OBJ_FACE_VERTS);
109 
110  for (int i = 0; i < count; i++) { /* walk around the polygon */
111  const int v0 = 0;
112  const int v1 = 1 + i;
113  const int v2 = 2 + i;
114 
115  mobjtri_t* t = &obj->tris[obj->num_tris_parsed + i];
116  assert(obj->num_tris_parsed + i < obj->num_tris);
117 
118  t->verts[0] = verts[v0];
119  t->verts[1] = verts[v1];
120  t->verts[2] = verts[v2];
121  }
122 }
123 
134 static int R_LoadObjModelFace (const model_t* mod, mobj_t* obj, const char* line)
135 {
137  const char* d;
138  char* e;
139  char tok[32];
140  int i, tris;
141 
142  OBJZERO(verts);
143  i = 0;
144 
145  while (true) {
146  const char* c = Com_Parse(&line);
147 
148  if (c[0] == '\0') /* done */
149  break;
150 
151  if (i == MAX_OBJ_FACE_VERTS)
152  Com_Error(ERR_DROP, "R_LoadObjModelFace: too many vertexes: %s.", mod->name);
153 
154  /* simply count verts */
155  if (!obj->tris) {
156  i++;
157  continue;
158  }
159 
160  d = c;
161  v = &verts[i++];
162 
163  OBJZERO(tok);
164  e = tok;
165 
166  /* parse the vertex definition */
167  while (d[0] != '\0') {
168  /* index delimiter, parse the token */
169  if (d[0] == '/') {
170  if (!v->vert)
171  v->vert = atoi(tok);
172  else if (!v->texcoord)
173  v->texcoord = atoi(tok);
174  else if (!v->normal)
175  v->normal = atoi(tok);
176 
177  OBJZERO(tok);
178  e = tok;
179 
180  d++;
181  continue;
182  }
183 
184  *e++ = *d++;
185  }
186 
187  /* parse whatever is left in the token */
188  if (!v->vert)
189  v->vert = atoi(tok);
190  else if (!v->texcoord)
191  v->texcoord = atoi(tok);
192  else if (!v->normal)
193  v->normal = atoi(tok);
194 
195  if (v->vert < 0 || v->texcoord < 0 || v->normal < 0)
196  Com_Error(ERR_DROP, "R_LoadObjModelFace: bad indices: %s (%i:%i:%i).",
197  mod->name, v->vert, v->texcoord, v->normal);
198  }
199 
200  /* number of triangles from parsed verts */
201  tris = i - 2;
202 
203  if (tris < 1)
204  Com_Error(ERR_DROP, "R_LoadObjModelFace: too few vertexes: %s.", mod->name);
205 
206  /* break verts up into tris */
207  R_LoadObjModelTris(obj, verts, tris);
208 
209  return tris;
210 }
211 
212 
217 static void R_LoadObjModelLine (model_t* mod, mobj_t* obj, char* line)
218 {
219  if (Q_strnull(line)) /* don't bother */
220  return;
221 
222  if (!strncmp(line, "v ", 2)) { /* vertex */
223  if (obj->verts) { /* parse it */
224  float* f = obj->verts + obj->num_verts_parsed * 3;
225 
226  if (sscanf(line + 2, "%f %f %f", &f[0], &f[2], &f[1]) != 3)
227  Com_Error(ERR_DROP, "R_LoadObjModelLine: Malformed vertex for %s: %s.",
228  mod->name, line);
229 
230  obj->num_verts_parsed++;
231  } else /* or just count it */
232  obj->num_verts++;
233  } else if (!strncmp(line, "vn ", 3)) { /* normal */
234  if (obj->normals) { /* parse it */
235  float* f = obj->normals + obj->num_normals_parsed * 3;
236 
237  if (sscanf(line + 3, "%f %f %f", &f[0], &f[1], &f[2]) != 3)
238  Com_Error(ERR_DROP, "R_LoadObjModelLine: Malformed normal for %s: %s.",
239  mod->name, line);
240 
241  obj->num_normals_parsed++;
242  } else /* or just count it */
243  obj->num_normals++;
244  } else if (!strncmp(line, "vt ", 3)) { /* texcoord */
245  if (obj->texcoords) { /* parse it */
246  float* f = obj->texcoords + obj->num_texcoords_parsed * 2;
247 
248  if (sscanf(line + 3, "%f %f", &f[0], &f[1]) != 2)
249  Com_Error(ERR_DROP, "R_LoadObjModelLine: Malformed texcoord for %s: %s.",
250  mod->name, line);
251 
252  f[1] = -f[1];
253  obj->num_texcoords_parsed++;
254  } else /* or just count it */
255  obj->num_texcoords++;
256  } else if (!strncmp(line, "f ", 2)) { /* face */
257  if (obj->tris) /* parse it */
258  obj->num_tris_parsed += R_LoadObjModelFace(mod, obj, line + 2);
259  else /* or just count it */
260  obj->num_tris += R_LoadObjModelFace(mod, obj, line + 2);
261  } else {
262  Com_DPrintf(DEBUG_RENDERER, "R_LoadObjModelLine: Unsupported line for %s: %s.\n",
263  mod->name, line);
264  }
265 }
266 
267 static void R_LoadObjSkin (model_t* mod)
268 {
269  char skinPath[MAX_QPATH];
270  mAliasMesh_t* mesh = &mod->alias.meshes[0];
271 
272  Com_StripExtension(mod->name, skinPath, sizeof(skinPath));
273  if (FS_CheckFile("%s.mtl", skinPath) != -1) {
274  const char* buffer;
275  byte* buf;
276  int i;
277 
278  FS_LoadFile(va("%s.mtl", skinPath), &buf);
279 
280  buffer = (const char*)buf;
281  for (;;) {
282  const char* token = Com_Parse(&buffer);
283  if (token[0] == '\0')
284  break;
285 
286  if (Q_streq(token, "map_Kd")) {
287  mesh->num_skins++;
288  }
289  }
291 
292  buffer = (const char*)buf;
293  i = 0;
294  for (;;) {
295  const char* token = Com_Parse(&buffer);
296  if (token[0] == '\0')
297  break;
298 
299  if (Q_streq(token, "map_Kd")) {
300  const char* skin = Com_Parse(&buffer);
301  mAliasSkin_t* aliasSkin = &mesh->skins[i++];
302 
303  Com_sprintf(skinPath, sizeof(skinPath), ".%s", skin);
304 
305  aliasSkin->skin = R_AliasModelGetSkin(mod->name, skinPath);
306  Q_strncpyz(aliasSkin->name, aliasSkin->skin->name, sizeof(aliasSkin->name));
307  }
308  }
309 
310  FS_FreeFile(buf);
311  } else {
312  mesh->num_skins = 1;
314  mesh->skins[0].skin = R_AliasModelGetSkin(mod->name, skinPath);
315  Q_strncpyz(mesh->skins[0].name, mesh->skins[0].skin->name, sizeof(mesh->skins[0].name));
316  }
317 }
318 
323 static void R_LoadObjModel_ (model_t* mod, mobj_t* obj, const byte* buffer, int bufSize)
324 {
325  const byte* c = buffer;
326  bool comment = false;
327  int i = 0;
328  char line[MAX_STRING_CHARS];
329 
330  while (c[0] != '\0') {
331  if (c[0] == '#') {
332  comment = true;
333  c++;
334  continue;
335  }
336 
337  if (c[0] == '\r' || c[0] == '\n') {
338  line[i] = 0;
339  i = 0;
340 
341  if (!comment)
342  R_LoadObjModelLine(mod, obj, Com_Trim(line));
343 
344  comment = false;
345  c++;
346  continue;
347  }
348 
349  line[i++] = *c++;
350  }
351 }
352 
353 void R_LoadObjModel (model_t* mod, byte* buffer, int bufSize)
354 {
355  mobj_t obj;
356 
357  mod->type = mod_obj;
358 
359  mod->alias.num_frames = 1;
360  mod->alias.num_meshes = 1;
361 
362  OBJZERO(obj);
363 
364  /* resolve primitive counts */
365  R_LoadObjModel_(mod, &obj, buffer, bufSize);
366 
367  if (!obj.num_verts || !obj.num_texcoords || !obj.num_tris)
368  Com_Error(ERR_DROP, "R_LoadObjModel: Failed to resolve model data: %s (%i %i %i %i)\n",
369  mod->name, obj.num_verts, obj.num_texcoords, obj.num_tris, obj.num_normals);
370 
371  /* allocate the primitives */
372  obj.verts = Mem_PoolAllocTypeN(float, obj.num_verts * 3, vid_modelPool);
373  if (obj.num_normals)
374  obj.normals = Mem_PoolAllocTypeN(float, obj.num_normals * 3, vid_modelPool);
377 
378  /* load the primitives */
379  R_LoadObjModel_(mod, &obj, buffer, bufSize);
380 
381  const float* v = obj.verts;
382  /* resolve mins/maxs */
383  for (int i = 0; i < obj.num_verts; i++, v += 3)
384  mod->modBox.add(v);
385 
386  /* we only have one mesh in obj files */
388 
389  /* load the skin */
390  R_LoadObjSkin(mod);
391 
392  /* and finally the arrays */
393  R_LoadObjModelVertexArrays(&obj, mod);
394 
395  /* this is no longer needed - we loaded everything into the generic model structs */
396  Mem_Free(obj.verts);
397  Mem_Free(obj.normals);
398  Mem_Free(obj.texcoords);
399  Mem_Free(obj.tris);
400 }
bool Q_strnull(const char *string)
Definition: shared.h:138
float * verts
Definition: r_model_obj.cpp:40
mobjvert_t verts[3]
Definition: r_model_obj.cpp:34
int num_texcoords_parsed
Definition: r_model_obj.cpp:47
#define VectorCopy(src, dest)
Definition: vector.h:51
mAliasModel_t alias
Definition: r_model.h:63
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition: files.cpp:298
memPool_t * vid_modelPool
Definition: cl_main.cpp:90
image_t * R_AliasModelGetSkin(const char *modelFileName, const char *skin)
AABB modBox
Definition: r_model.h:51
void R_LoadObjModel(model_t *mod, byte *buffer, int bufSize)
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition: shared.cpp:410
float * normals
Definition: r_model_obj.cpp:44
int num_tris_parsed
Definition: r_model_obj.cpp:51
vec_t * normals
mAliasSkin_t * skins
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition: shared.cpp:259
mobjtri_t * tris
Definition: r_model_obj.cpp:52
image_t * skin
Definition: r_model_alias.h:92
local graphics definitions
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
static int R_LoadObjModelFace(const model_t *mod, mobj_t *obj, const char *line)
Each line consists of 3 or more vertex definitions, e.g.
static void R_LoadObjModelLine(model_t *mod, mobj_t *obj, char *line)
Parse the object file line. If the structures have been allocated, populate them. Otherwise simply ac...
vec_t * texcoords
int num_texcoords
Definition: r_model_obj.cpp:46
char * Com_Trim(char *s)
Removed leading and trailing whitespaces.
Definition: shared.cpp:65
voidpf void * buf
Definition: ioapi.h:42
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
char name[MODEL_MAX_PATH]
Definition: r_model_alias.h:90
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void add(const vec3_t point)
If the point is outside the box, expand the box to accommodate it.
Definition: aabb.cpp:57
#define ERR_DROP
Definition: common.h:211
struct mobjtri_s mobjtri_t
struct mobj_s mobj_t
#define OBJZERO(obj)
Definition: shared.h:178
modtype_t type
Definition: r_model.h:46
char name[MAX_QPATH]
Definition: r_image.h:62
int num_normals
Definition: r_model_obj.cpp:42
char name[MAX_QPATH]
Definition: r_model.h:44
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
int num_verts
Definition: r_model_obj.cpp:38
#define MAX_OBJ_FACE_VERTS
Definition: r_model_obj.cpp:98
static void R_LoadObjModel_(model_t *mod, mobj_t *obj, const byte *buffer, int bufSize)
Drives the actual parsing of the object file. The file is read twice: once to acquire primitive count...
QGL_EXTERN GLuint count
Definition: r_gl.h:99
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
mAliasMesh_t * meshes
float * texcoords
Definition: r_model_obj.cpp:48
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 num_normals_parsed
Definition: r_model_obj.cpp:43
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define MAX_STRING_CHARS
Definition: defines.h:90
int num_tris
Definition: r_model_obj.cpp:50
static void R_LoadObjModelTris(mobj_t *obj, const mobjvert_t *verts, int count)
Assembles count tris on the model from the specified array of verts.
static void R_LoadObjModelVertexArrays(mobj_t *obj, model_t *mod)
Definition: r_model_obj.cpp:58
#define Mem_Free(ptr)
Definition: mem.h:35
vec_t vec2_t[2]
Definition: ufotypes.h:38
static void R_LoadObjSkin(model_t *mod)
int num_verts_parsed
Definition: r_model_obj.cpp:39
struct mobjvert_s mobjvert_t
#define Q_streq(a, b)
Definition: shared.h:136
int32_t num_verts
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
uint8_t byte
Definition: ufotypes.h:34
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
QGL_EXTERN GLuint GLsizei bufSize
Definition: r_gl.h:110
#define DEBUG_RENDERER
Definition: defines.h:62
void FS_FreeFile(void *buffer)
Definition: files.cpp:411