UFO: Alien Invasion
Loading...
Searching...
No Matches
r_model_obj.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 1997-2009 Quake2World
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/* object model memory representation */
27typedef struct mobjvert_s {
28 int vert;
29 int normal;
32
33typedef struct mobjtri_s {
35} mobjtri_t;
36
54
55#include "r_local.h"
56#include "../../shared/parse.h"
57
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);
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
103static 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
134static 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
217static 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];
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
267static 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
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
323static 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
353void 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)
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 */
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}
memPool_t * vid_modelPool
Definition cl_main.cpp:90
void add(const vec3_t point)
If the point is outside the box, expand the box to accommodate it.
Definition aabb.cpp:57
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
#define ERR_DROP
Definition common.h:211
#define DEBUG_RENDERER
Definition defines.h:62
#define MAX_STRING_CHARS
Definition defines.h:90
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn't found.
Definition files.cpp:298
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
#define Mem_PoolAllocTypeN(type, n, pool)
Definition mem.h:42
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_PoolAllocType(type, pool)
Definition mem.h:43
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
Shared parsing functions.
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei bufSize
Definition r_gl.h:110
local graphics definitions
image_t * R_AliasModelGetSkin(const char *modelFileName, const char *skin)
@ mod_obj
Definition r_model.h:41
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...
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_LoadObjModelVertexArrays(mobj_t *obj, model_t *mod)
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...
static void R_LoadObjSkin(model_t *mod)
void R_LoadObjModel(model_t *mod, byte *buffer, int bufSize)
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.
#define MAX_OBJ_FACE_VERTS
#define Q_streq(a, b)
Definition shared.h:136
bool Q_strnull(const char *string)
Definition shared.h:138
#define OBJZERO(obj)
Definition shared.h:178
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
char * Com_Trim(char *s)
Removed leading and trailing whitespaces.
Definition shared.cpp:65
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
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
char name[MAX_QPATH]
Definition r_image.h:62
mAliasSkin_t * skins
vec_t * texcoords
int32_t num_verts
mAliasMesh_t * meshes
char name[MODEL_MAX_PATH]
image_t * skin
int num_tris_parsed
int num_normals
int num_normals_parsed
int num_texcoords_parsed
float * normals
int num_verts_parsed
int num_texcoords
mobjtri_t * tris
float * texcoords
int num_tris
int num_verts
float * verts
mobjvert_t verts[3]
modtype_t type
Definition r_model.h:46
AABB modBox
Definition r_model.h:51
mAliasModel_t alias
Definition r_model.h:63
char name[MAX_QPATH]
Definition r_model.h:44
vec_t vec2_t[2]
Definition ufotypes.h:38
#define VectorCopy(src, dest)
Definition vector.h:51