dbf_amiga

annotate src/scnload_obj.cc @ 0:87dfe0e10235

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 31 Aug 2015 07:38:37 +0300
parents
children
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <string.h>
nuclear@0 3 #include <ctype.h>
nuclear@0 4 #include <limits.h>
nuclear@0 5 #include <errno.h>
nuclear@0 6 #include <vector>
nuclear@0 7 #include "mesh.h"
nuclear@0 8 #include "scene.h"
nuclear@0 9 #include "scnload.h"
nuclear@0 10
nuclear@0 11 enum {
nuclear@0 12 CMD_VERTEX,
nuclear@0 13 CMD_NORMAL,
nuclear@0 14 CMD_TEXCOORD,
nuclear@0 15 CMD_FACE,
nuclear@0 16 CMD_OBJECT,
nuclear@0 17 CMD_GROUP,
nuclear@0 18 CMD_MTLLIB
nuclear@0 19 };
nuclear@0 20
nuclear@0 21 static struct {
nuclear@0 22 const char *s;
nuclear@0 23 int cmd;
nuclear@0 24 } commands[] = {
nuclear@0 25 {"v", CMD_VERTEX},
nuclear@0 26 {"vn", CMD_NORMAL},
nuclear@0 27 {"vt", CMD_TEXCOORD},
nuclear@0 28 {"f", CMD_FACE},
nuclear@0 29 {"o", CMD_OBJECT},
nuclear@0 30 {"g", CMD_GROUP},
nuclear@0 31 {"mtllib", CMD_MTLLIB},
nuclear@0 32 {0, -1}
nuclear@0 33 };
nuclear@0 34
nuclear@0 35 struct Face {
nuclear@0 36 int vnum;
nuclear@0 37 int vidx[4];
nuclear@0 38 int nidx[4];
nuclear@0 39 int tidx[4];
nuclear@0 40 };
nuclear@0 41
nuclear@0 42 struct ObjMesh {
nuclear@0 43 std::vector<Vector3> varr;
nuclear@0 44 std::vector<Vector3> narr;
nuclear@0 45 std::vector<Vector2> tarr;
nuclear@0 46 std::vector<Face> faces;
nuclear@0 47 };
nuclear@0 48
nuclear@0 49 struct ParserState {
nuclear@0 50 FILE *fp;
nuclear@0 51 Scene *scn;
nuclear@0 52 const char *fname;
nuclear@0 53
nuclear@0 54 unsigned int voffs, noffs, toffs;
nuclear@0 55 ObjMesh omesh;
nuclear@0 56 };
nuclear@0 57
nuclear@0 58 static bool parse_line(ParserState *ps, char *line);
nuclear@0 59 static void flush_mesh(ParserState *ps);
nuclear@0 60 static char *clean_input(char *s);
nuclear@0 61
nuclear@0 62 bool load_obj(Scene *scn, const char *fname)
nuclear@0 63 {
nuclear@0 64 FILE *fp;
nuclear@0 65 char buf[256];
nuclear@0 66 bool result = false;
nuclear@0 67 ParserState ps;
nuclear@0 68
nuclear@0 69 if(!(fp = fopen(fname, "r"))) {
nuclear@0 70 fprintf(stderr, "failed to open obj file: %s: %s\n", fname, strerror(errno));
nuclear@0 71 return false;
nuclear@0 72 }
nuclear@0 73 ps.fp = fp;
nuclear@0 74 ps.scn = scn;
nuclear@0 75 ps.fname = fname;
nuclear@0 76 ps.voffs = ps.noffs = ps.toffs = 0;
nuclear@0 77
nuclear@0 78 int nline = 0;
nuclear@0 79 while(fgets(buf, sizeof buf, fp)) {
nuclear@0 80 ++nline;
nuclear@0 81 char *line = clean_input(buf);
nuclear@0 82 if(!*line) continue;
nuclear@0 83
nuclear@0 84 if(!parse_line(&ps, line)) {
nuclear@0 85 fprintf(stderr, "[obj] %s:%d: failed to parse\n", fname, nline);
nuclear@0 86 goto done;
nuclear@0 87 }
nuclear@0 88 }
nuclear@0 89 flush_mesh(&ps);
nuclear@0 90 result = true;
nuclear@0 91
nuclear@0 92 done:
nuclear@0 93 fclose(fp);
nuclear@0 94 return result;
nuclear@0 95 }
nuclear@0 96
nuclear@0 97 static int parse_cmd(char *line, char **endp)
nuclear@0 98 {
nuclear@0 99 char *end = line;
nuclear@0 100 while(*end && !isspace(*end)) end++;
nuclear@0 101 *end = 0;
nuclear@0 102 *endp = end;
nuclear@0 103
nuclear@0 104 for(int i=0; commands[i].s; i++) {
nuclear@0 105 if(strcmp(commands[i].s, line) == 0) {
nuclear@0 106 return commands[i].cmd;
nuclear@0 107 }
nuclear@0 108 }
nuclear@0 109 return -1;
nuclear@0 110 }
nuclear@0 111
nuclear@0 112 static bool parse_vec3(Vector3 *vp, char *line)
nuclear@0 113 {
nuclear@0 114 return sscanf(line, "%f %f %f", &vp->x, &vp->y, &vp->z) == 3;
nuclear@0 115 }
nuclear@0 116
nuclear@0 117 static bool parse_vec2(Vector2 *vp, char *line)
nuclear@0 118 {
nuclear@0 119 return sscanf(line, "%f %f", &vp->x, &vp->y) == 2;
nuclear@0 120 }
nuclear@0 121
nuclear@0 122 #define INVAL_IDX INT_MIN
nuclear@0 123
nuclear@0 124 static bool parse_face(Face *fp, char *line)
nuclear@0 125 {
nuclear@0 126 fp->vnum = 0;
nuclear@0 127
nuclear@0 128 int res;
nuclear@0 129 char *tok, *ptr = line;
nuclear@0 130 for(int i=0; i<4; i++) {
nuclear@0 131 while(*ptr && isspace(*ptr)) ptr++;
nuclear@0 132 if(!*ptr) break;
nuclear@0 133 tok = ptr;
nuclear@0 134
nuclear@0 135 fp->vnum++;
nuclear@0 136
nuclear@0 137 while(*ptr && !isspace(*ptr)) ptr++;
nuclear@0 138 if(*ptr) *ptr++ = 0;
nuclear@0 139
nuclear@0 140 // parse the index descriptor vidx[/[tidx]/[nidx]]
nuclear@0 141 if(sscanf(tok, "%d//%d", &fp->vidx[i], &fp->nidx[i]) == 2) {
nuclear@0 142 fp->tidx[i] = INVAL_IDX;
nuclear@0 143 continue;
nuclear@0 144 }
nuclear@0 145 res = sscanf(tok, "%d/%d/%d", &fp->vidx[i], &fp->tidx[i], &fp->nidx[i]);
nuclear@0 146 if(res > 2) {
nuclear@0 147 if(res != 3) {
nuclear@0 148 fp->nidx[i] = INVAL_IDX;
nuclear@0 149 }
nuclear@0 150 continue;
nuclear@0 151 }
nuclear@0 152 char *endp;
nuclear@0 153 fp->vidx[i] = strtol(tok, &endp, 10);
nuclear@0 154 if(endp == tok) {
nuclear@0 155 return false;
nuclear@0 156 }
nuclear@0 157 fp->nidx[i] = fp->tidx[i] = INVAL_IDX;
nuclear@0 158 }
nuclear@0 159 return fp->vnum >= 3 ? true : false;
nuclear@0 160 }
nuclear@0 161
nuclear@0 162 static bool parse_line(ParserState *ps, char *line)
nuclear@0 163 {
nuclear@0 164 char *endp;
nuclear@0 165 int cmd = parse_cmd(line, &endp);
nuclear@0 166 if(cmd == -1) return true; // ignore unknown commands
nuclear@0 167 line = endp + 1;
nuclear@0 168 while(*line && isspace(*line)) line++;
nuclear@0 169
nuclear@0 170 Vector3 v;
nuclear@0 171 Vector2 v2;
nuclear@0 172 Face f;
nuclear@0 173
nuclear@0 174 switch(cmd) {
nuclear@0 175 case CMD_VERTEX:
nuclear@0 176 if(!parse_vec3(&v, line)) return false;
nuclear@0 177 ps->omesh.varr.push_back(v);
nuclear@0 178 break;
nuclear@0 179
nuclear@0 180 case CMD_NORMAL:
nuclear@0 181 if(!parse_vec3(&v, line)) return false;
nuclear@0 182 ps->omesh.narr.push_back(v);
nuclear@0 183 break;
nuclear@0 184
nuclear@0 185 case CMD_TEXCOORD:
nuclear@0 186 if(!parse_vec2(&v2, line)) return false;
nuclear@0 187 ps->omesh.tarr.push_back(v2);
nuclear@0 188 break;
nuclear@0 189
nuclear@0 190 case CMD_FACE:
nuclear@0 191 if(!parse_face(&f, line)) return false;
nuclear@0 192 ps->omesh.faces.push_back(f);
nuclear@0 193 break;
nuclear@0 194
nuclear@0 195 case CMD_OBJECT:
nuclear@0 196 case CMD_GROUP:
nuclear@0 197 flush_mesh(ps);
nuclear@0 198 break;
nuclear@0 199
nuclear@0 200 default:
nuclear@0 201 break;
nuclear@0 202 }
nuclear@0 203 return true;
nuclear@0 204 }
nuclear@0 205
nuclear@0 206 static void flush_mesh(ParserState *ps)
nuclear@0 207 {
nuclear@0 208 if(!ps->omesh.varr.empty() && !ps->omesh.faces.empty()) {
nuclear@0 209 int num_verts = (int)ps->omesh.varr.size();
nuclear@0 210 int num_faces = (int)ps->omesh.faces.size();
nuclear@0 211
nuclear@0 212 Mesh *m = new Mesh;
nuclear@0 213 m->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, (float*)&ps->omesh.varr[0]);
nuclear@0 214
nuclear@0 215 if(!ps->omesh.narr.empty()) {
nuclear@0 216 m->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, (float*)&ps->omesh.narr[0]);
nuclear@0 217 }
nuclear@0 218 if(!ps->omesh.tarr.empty()) {
nuclear@0 219 m->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, (float*)&ps->omesh.tarr[0]);
nuclear@0 220 }
nuclear@0 221
nuclear@0 222 unsigned int *idxarr = m->set_index_data(num_faces * 3);
nuclear@0 223 for(int i=0; i<num_faces; i++) {
nuclear@0 224 for(int j=0; j<3; j++) {
nuclear@0 225 int idx = ps->omesh.faces[i].vidx[j] - ps->voffs - 1; // TODO normalize indices
nuclear@0 226 *idxarr++ = idx;
nuclear@0 227 }
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 Object *o = new Object;
nuclear@0 231 o->set_mesh(m);
nuclear@0 232
nuclear@0 233 // TODO material & textures
nuclear@0 234
nuclear@0 235 ps->scn->add_object(o);
nuclear@0 236
nuclear@0 237 printf("added object with %d vertices and %d faces\n", num_verts, num_faces);
nuclear@0 238 }
nuclear@0 239
nuclear@0 240 ps->voffs += ps->omesh.varr.size();
nuclear@0 241 ps->noffs += ps->omesh.narr.size();
nuclear@0 242 ps->toffs += ps->omesh.tarr.size();
nuclear@0 243
nuclear@0 244 ps->omesh.varr.clear();
nuclear@0 245 ps->omesh.narr.clear();
nuclear@0 246 ps->omesh.tarr.clear();
nuclear@0 247 ps->omesh.faces.clear();
nuclear@0 248 }
nuclear@0 249
nuclear@0 250 static char *clean_input(char *s)
nuclear@0 251 {
nuclear@0 252 while(*s && isspace(*s)) s++;
nuclear@0 253 if(!*s) return s;
nuclear@0 254
nuclear@0 255 char *end = strchr(s, '#');
nuclear@0 256 if(end) *end = 0;
nuclear@0 257
nuclear@0 258 end = s + strlen(s) - 1;
nuclear@0 259 while(end > s && isspace(*end)) end--;
nuclear@0 260 end[1] = 0;
nuclear@0 261
nuclear@0 262 return s;
nuclear@0 263 }