r_model_obj.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2009 Quake2World
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 /* object model memory representation */
00027 typedef struct mobjvert_s {
00028     int vert;
00029     int normal;
00030     int texcoord;
00031 } mobjvert_t;
00032 
00033 typedef struct mobjtri_s {
00034     mobjvert_t verts[3];
00035 } mobjtri_t;
00036 
00037 typedef struct mobj_s {
00038     int num_verts;
00039     int num_verts_parsed;
00040     float *verts;
00041 
00042     int num_normals;
00043     int num_normals_parsed;
00044     float *normals;
00045 
00046     int num_texcoords;
00047     int num_texcoords_parsed;
00048     float *texcoords;
00049 
00050     int num_tris;
00051     int num_tris_parsed;
00052     mobjtri_t *tris;
00053 } mobj_t;
00054 
00055 #include "r_local.h"
00056 #include "../../shared/parse.h"
00057 
00058 static void R_LoadObjModelVertexArrays (mobj_t *obj, model_t *mod)
00059 {
00060     const mobjtri_t *t;
00061     int i, j, vertind, coordind;
00062     mAliasMesh_t *mesh = mod->alias.meshes;
00063     const int v = obj->num_tris * 3 * 3;
00064     const int st = obj->num_tris * 3 * 2;
00065 
00066     vertind = coordind = 0;
00067 
00068     t = obj->tris;
00069 
00070     mesh->num_tris = obj->num_tris;
00071     mesh->num_verts = obj->num_verts;
00072 
00073     mesh->verts = (float *)Mem_PoolAlloc(sizeof(float) * v, vid_modelPool, 0);
00074     mesh->normals = (float *)Mem_PoolAlloc(sizeof(float) * v, vid_modelPool, 0);
00075     mesh->texcoords = (float *)Mem_PoolAlloc(sizeof(float) * st, vid_modelPool, 0);
00076 
00077     /* fill the arrays */
00078     for (i = 0; i < obj->num_tris; i++, t++) {
00079         const mobjvert_t *v = t->verts;
00080 
00081         /* each vert */
00082         for (j = 0; j < 3; j++, v++) {
00083             assert(v->vert - 1 >= 0);
00084             VectorCopy((&obj->verts[(v->vert - 1) * 3]), (&mesh->verts[vertind + j * 3]));
00085 
00086             if (v->normal) {
00087                 assert(v->normal - 1 >= 0);
00088                 VectorCopy((&obj->normals[(v->normal - 1) * 3]), (&mesh->normals[vertind + j * 3]));
00089             }
00090 
00091             if (v->texcoord) {
00092                 assert(v->texcoord - 1 >= 0);
00093                 memcpy(&mesh->texcoords[coordind + j * 2], &obj->texcoords[(v->texcoord - 1) * 2], sizeof(vec2_t));
00094             }
00095         }
00096 
00097         coordind += 6;
00098         vertind += 9;
00099     }
00100 }
00101 
00102 #define MAX_OBJ_FACE_VERTS 128
00103 
00107 static void R_LoadObjModelTris (mobj_t *obj, const mobjvert_t *verts, int count)
00108 {
00109     int i;
00110 
00111     if (!obj->tris)
00112         return;
00113 
00114     assert(count < MAX_OBJ_FACE_VERTS);
00115 
00116     for (i = 0; i < count; i++) {  /* walk around the polygon */
00117         const int v0 = 0;
00118         const int v1 = 1 + i;
00119         const int v2 = 2 + i;
00120 
00121         mobjtri_t *t = &obj->tris[obj->num_tris_parsed + i];
00122         assert(obj->num_tris_parsed + i < obj->num_tris);
00123 
00124         t->verts[0] = verts[v0];
00125         t->verts[1] = verts[v1];
00126         t->verts[2] = verts[v2];
00127     }
00128 }
00129 
00140 static int R_LoadObjModelFace (const model_t *mod, mobj_t *obj, const char *line)
00141 {
00142     mobjvert_t *v, verts[MAX_OBJ_FACE_VERTS];
00143     const char *d;
00144     char *e;
00145     char tok[32];
00146     int i, tris;
00147 
00148     memset(verts, 0, sizeof(verts));
00149     i = 0;
00150 
00151     while (qtrue) {
00152         const char *c = Com_Parse(&line);
00153 
00154         if (c[0] == '\0')  /* done */
00155             break;
00156 
00157         if (i == MAX_OBJ_FACE_VERTS)
00158             Com_Error(ERR_DROP, "R_LoadObjModelFace: too many vertexes: %s.", mod->name);
00159 
00160         /* simply count verts */
00161         if (!obj->tris) {
00162             i++;
00163             continue;
00164         }
00165 
00166         d = c;
00167         v = &verts[i++];
00168 
00169         memset(tok, 0, sizeof(tok));
00170         e = tok;
00171 
00172         /* parse the vertex definition */
00173         while (d[0] != '\0') {
00174             /* index delimiter, parse the token */
00175             if (d[0] == '/') {
00176                 if (!v->vert)
00177                     v->vert = atoi(tok);
00178                 else if (!v->texcoord)
00179                     v->texcoord = atoi(tok);
00180                 else if (!v->normal)
00181                     v->normal = atoi(tok);
00182 
00183                 memset(tok, 0, sizeof(tok));
00184                 e = tok;
00185 
00186                 d++;
00187                 continue;
00188             }
00189 
00190             *e++ = *d++;
00191         }
00192 
00193         /* parse whatever is left in the token */
00194         if (!v->vert)
00195             v->vert = atoi(tok);
00196         else if (!v->texcoord)
00197             v->texcoord = atoi(tok);
00198         else if (!v->normal)
00199             v->normal = atoi(tok);
00200 
00201         if (v->vert < 0 || v->texcoord < 0 || v->normal < 0)
00202             Com_Error(ERR_DROP, "R_LoadObjModelFace: bad indices: %s (%i:%i:%i).",
00203                 mod->name, v->vert, v->texcoord, v->normal);
00204     }
00205 
00206     /* number of triangles from parsed verts */
00207     tris = i - 2;
00208 
00209     if (tris < 1)
00210         Com_Error(ERR_DROP, "R_LoadObjModelFace: too few vertexes: %s.", mod->name);
00211 
00212     /* break verts up into tris */
00213     R_LoadObjModelTris(obj, verts, tris);
00214 
00215     return tris;
00216 }
00217 
00218 
00223 static void R_LoadObjModelLine (model_t *mod, mobj_t *obj, char *line)
00224 {
00225     if (!line || line[0] == '\0')  /* don't bother */
00226         return;
00227 
00228     if (!strncmp(line, "v ", 2)) {  /* vertex */
00229         if (obj->verts) {  /* parse it */
00230             float *f = obj->verts + obj->num_verts_parsed * 3;
00231 
00232             if (sscanf(line + 2, "%f %f %f", &f[0], &f[2], &f[1]) != 3)
00233                 Com_Error(ERR_DROP, "R_LoadObjModelLine: Malformed vertex for %s: %s.",
00234                         mod->name, line);
00235 
00236             obj->num_verts_parsed++;
00237         } else  /* or just count it */
00238             obj->num_verts++;
00239     } else if (!strncmp(line, "vn ", 3)) {  /* normal */
00240         if (obj->normals) {  /* parse it */
00241             float *f = obj->normals + obj->num_normals_parsed * 3;
00242 
00243             if (sscanf(line + 3, "%f %f %f", &f[0], &f[1], &f[2]) != 3)
00244                 Com_Error(ERR_DROP, "R_LoadObjModelLine: Malformed normal for %s: %s.",
00245                         mod->name, line);
00246 
00247             obj->num_normals_parsed++;
00248         } else  /* or just count it */
00249             obj->num_normals++;
00250     } else if (!strncmp(line, "vt ", 3)) {  /* texcoord */
00251         if (obj->texcoords) {  /* parse it */
00252             float *f = obj->texcoords + obj->num_texcoords_parsed * 2;
00253 
00254             if (sscanf(line + 3, "%f %f", &f[0], &f[1]) != 2)
00255                 Com_Error(ERR_DROP, "R_LoadObjModelLine: Malformed texcoord for %s: %s.",
00256                         mod->name, line);
00257 
00258             f[1] = -f[1];
00259             obj->num_texcoords_parsed++;
00260         } else  /* or just count it */
00261             obj->num_texcoords++;
00262     } else if (!strncmp(line, "f ", 2)) {  /* face */
00263         if (obj->tris)  /* parse it */
00264             obj->num_tris_parsed += R_LoadObjModelFace(mod, obj, line + 2);
00265         else  /* or just count it */
00266             obj->num_tris += R_LoadObjModelFace(mod, obj, line + 2);
00267     } else {
00268         Com_DPrintf(DEBUG_RENDERER, "R_LoadObjModelLine: Unsupported line for %s: %s.\n",
00269                 mod->name, line);
00270     }
00271 }
00272 
00273 static void R_LoadObjSkin (model_t *mod)
00274 {
00275     char skinPath[MAX_QPATH];
00276     mAliasMesh_t *mesh = &mod->alias.meshes[0];
00277 
00278     Com_StripExtension(mod->name, skinPath, sizeof(skinPath));
00279 
00280     mesh->num_skins = 1;
00281     mesh->skins = Mem_PoolAlloc(sizeof(mAliasSkin_t), vid_modelPool, 0);
00282     mesh->skins[0].skin = R_AliasModelGetSkin(mod->name, skinPath);
00283     Q_strncpyz(mesh->skins[0].name, mesh->skins[0].skin->name, sizeof(mesh->skins[0].name));
00284 }
00285 
00290 static void R_LoadObjModel_ (model_t *mod, mobj_t *obj, const byte *buffer, int bufSize)
00291 {
00292     char line[MAX_STRING_CHARS];
00293     const byte *c;
00294     qboolean comment;
00295     int i;
00296 
00297     c = buffer;
00298     comment = qfalse;
00299     i = 0;
00300 
00301     while (c[0] != '\0') {
00302         if (c[0] == '#') {
00303             comment = qtrue;
00304             c++;
00305             continue;
00306         }
00307 
00308         if (c[0] == '\r' || c[0] == '\n') {
00309             line[i++] = 0;
00310             i = 0;
00311 
00312             if (!comment)
00313                 R_LoadObjModelLine(mod, obj, Com_Trim(line));
00314 
00315             comment = qfalse;
00316             c++;
00317             continue;
00318         }
00319 
00320         line[i++] = *c++;
00321     }
00322 }
00323 
00324 void R_LoadObjModel (model_t *mod, byte *buffer, int bufSize)
00325 {
00326     mobj_t obj;
00327     const float *v;
00328     int i;
00329 
00330     mod->type = mod_obj;
00331 
00332     mod->alias.num_frames = 1;
00333     mod->alias.num_meshes = 1;
00334 
00335     memset(&obj, 0, sizeof(obj));
00336 
00337     /* resolve primitive counts */
00338     R_LoadObjModel_(mod, &obj, buffer, bufSize);
00339 
00340     if (!obj.num_verts || !obj.num_texcoords || !obj.num_tris)
00341         Com_Error(ERR_DROP, "R_LoadObjModel: Failed to resolve model data: %s (%i %i %i %i)\n",
00342             mod->name, obj.num_verts, obj.num_texcoords, obj.num_tris, obj.num_normals);
00343 
00344     /* allocate the primitives */
00345     obj.verts = (float *)Mem_PoolAlloc(obj.num_verts * sizeof(float) * 3, vid_modelPool, 0);
00346     if (obj.num_normals)
00347         obj.normals = (float *)Mem_PoolAlloc(obj.num_normals * sizeof(float) * 3, vid_modelPool, 0);
00348     obj.texcoords = (float *)Mem_PoolAlloc(obj.num_texcoords * sizeof(float) * 2, vid_modelPool, 0);
00349     obj.tris = (mobjtri_t *)Mem_PoolAlloc(obj.num_tris * sizeof(mobjtri_t), vid_modelPool, 0);
00350 
00351     /* load the primitives */
00352     R_LoadObjModel_(mod, &obj, buffer, bufSize);
00353 
00354     v = obj.verts;
00355     /* resolve mins/maxs */
00356     for (i = 0; i < obj.num_verts; i++, v += 3)
00357         AddPointToBounds(v, mod->mins, mod->maxs);
00358 
00359     /* we only have one mesh in obj files */
00360     mod->alias.meshes = Mem_PoolAlloc(sizeof(mAliasMesh_t), vid_modelPool, 0);
00361 
00362     /* load the skin */
00363     R_LoadObjSkin(mod);
00364 
00365     /* and finally the arrays */
00366     R_LoadObjModelVertexArrays(&obj, mod);
00367 
00368     /* this is no longer needed - we loaded everything into the generic model structs */
00369     Mem_Free(obj.verts);
00370     Mem_Free(obj.normals);
00371     Mem_Free(obj.texcoords);
00372     Mem_Free(obj.tris);
00373 }

Generated by  doxygen 1.6.2