5 #include "cgmath/cgmath.h"
15 cgm_vec3 ka, kd, ks, ke;
19 char *map_kd, *map_ke, *map_alpha;
23 static int proc_facevert(struct mesh *mesh, struct facevertex *fv,
24 cgm_vec3 *varr, cgm_vec3 *narr, cgm_vec2 *tarr, struct rbtree *rbtree);
26 static char *cleanline(char *s);
27 static char *parse_idx(char *ptr, int *idx, int arrsz);
28 static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn);
30 static int load_mtllib(struct scenefile *scn, const char *path_prefix, const char *mtlfname);
31 static void free_mtllist(struct material *mtl);
32 static void conv_mtl(struct material *mm, struct objmtl *om, const char *path_prefix);
34 static int cmp_facevert(const void *ap, const void *bp);
35 static void free_rbnode_key(struct rbnode *n, void *cls);
37 #define GROW_ARRAY(arr, sz) \
39 int newsz = (sz) ? (sz) * 2 : 16; \
40 void *tmp = realloc(arr, newsz * sizeof *(arr)); \
42 fprintf(stderr, "failed to grow array to %d\n", newsz); \
50 int load_scenefile(struct scenefile *scn, const char *fname)
52 int i, nlines, res = -1;
54 char buf[256], *line, *ptr, *path_prefix;
55 int varr_size, varr_max, narr_size, narr_max, tarr_size, tarr_max;
56 cgm_vec3 v, *varr = 0, *narr = 0;
58 struct facevertex fv[4];
60 struct material *mtl = 0;
62 struct rbtree *rbtree = 0;
64 memset(scn, 0, sizeof *scn);
66 varr_size = varr_max = narr_size = narr_max = tarr_size = tarr_max = 0;
70 if(!(fp = fopen(fname, "rb"))) {
71 fprintf(stderr, "load_scenefile: failed to open %s\n", fname);
75 if(!(rbtree = rb_create(cmp_facevert))) {
76 fprintf(stderr, "load_scenefile: failed to create facevertex search tree\n");
79 rb_set_delete_func(rbtree, free_rbnode_key, 0);
82 if((sep = strrchr(buf, '/'))) {
87 path_prefix = alloca(strlen(buf) + 1);
88 strcpy(path_prefix, buf);
91 sep = (char*)fname + (sep - buf);
93 if(!(scn->fname = strdup(sep ? sep + 1 : fname))) {
94 fprintf(stderr, "failed to allocate scenefile name buffer\n");
98 if(!(mesh = malloc(sizeof *mesh))) {
99 fprintf(stderr, "failed to allocate mesh\n");
109 while(fgets(buf, sizeof buf, fp)) {
111 if(!(line = cleanline(buf))) {
117 v.x = v.y = v.z = 0.0f;
118 if(sscanf(line + 2, "%f %f %f", &v.x, &v.y, &v.z) < 2) {
121 if(isspace(line[1])) {
122 if(varr_size >= varr_max) {
123 GROW_ARRAY(varr, varr_max);
125 varr[varr_size++] = v;
126 } else if(line[1] == 't' && isspace(line[2])) {
127 if(tarr_size >= tarr_max) {
128 GROW_ARRAY(tarr, tarr_max);
130 tarr[tarr_size++] = *(cgm_vec2*)&v;
131 } else if(line[1] == 'n' && isspace(line[2])) {
132 if(narr_size >= narr_max) {
133 GROW_ARRAY(narr, narr_max);
135 narr[narr_size++] = v;
140 if(!isspace(line[1])) break;
145 if(!(ptr = parse_face_vert(ptr, fv + i, varr_size, tarr_size, narr_size))) {
148 if(proc_facevert(mesh, fv + i, varr, narr, tarr, rbtree) == -1) {
153 if(parse_face_vert(ptr, fv + 3, varr_size, tarr_size, narr_size)) {
154 proc_facevert(mesh, fv, varr, narr, tarr, rbtree);
155 proc_facevert(mesh, fv + 2, varr, narr, tarr, rbtree);
156 proc_facevert(mesh, fv + 3, varr, narr, tarr, rbtree);
162 if(mesh->num_verts) {
164 mesh->next = scn->meshlist;
165 scn->meshlist = mesh;
168 if(!(mesh = malloc(sizeof *mesh))) {
169 fprintf(stderr, "failed to allocate mesh\n");
173 mesh->name = strdup(cleanline(line + 2));
178 if(memcmp(line, "mtllib", 6) == 0 && (line = cleanline(line + 6))) {
179 free_mtllist(scn->mtllist);
180 load_mtllib(scn, path_prefix, line);
185 if(memcmp(line, "usemtl", 6) == 0 && (line = cleanline(line + 6))) {
188 if(strcmp(mtl->name, line) == 0) {
201 if(mesh->num_verts) {
203 mesh->next = scn->meshlist;
204 scn->meshlist = mesh;
211 printf("load_scenefile %s: loaded %d meshes, %d vertices\n", scn->fname,
212 scn->num_meshes, varr_size);
230 static int proc_facevert(struct mesh *mesh, struct facevertex *fv,
231 cgm_vec3 *varr, cgm_vec3 *narr, cgm_vec2 *tarr, struct rbtree *rbtree)
234 unsigned int idx, newidx;
235 struct facevertex *newfv;
238 if((node = rb_find(rbtree, &fv))) {
239 idx = (unsigned int)node->data;
240 assert(idx < mesh->num_verts);
242 newidx = mesh->num_verts;
244 v.pos = varr[fv->vidx];
246 v.norm = narr[fv->nidx];
249 v.tex = tarr[fv->tidx];
251 add_mesh_vertex(mesh, &v);
252 add_mesh_index(mesh, newidx);
255 if((newfv = malloc(sizeof *newfv))) {
258 if(!newfv || rb_insert(rbtree, newfv, (void*)newidx) == -1) {
259 fprintf(stderr, "load_scenefile: failed to insert facevertex to rbtree\n");
266 void destroy_scenefile(struct scenefile *scn)
269 while(scn->meshlist) {
271 scn->meshlist = scn->meshlist->next;
276 static char *cleanline(char *s)
280 if((ptr = strchr(s, '#'))) *ptr = 0;
282 while(*s && isspace(*s)) s++;
283 ptr = s + strlen(s) - 1;
284 while(ptr >= s && isspace(*ptr)) *ptr-- = 0;
289 static char *parse_idx(char *ptr, int *idx, int arrsz)
292 int val = strtol(ptr, &endp, 10);
293 if(endp == ptr) return 0;
295 if(val < 0) { /* convert negative indices */
298 *idx = val - 1; /* indices in obj are 1-based */
303 /* possible face-vertex definitions:
307 * 4. vertex/texcoord/normal
309 static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn)
311 fv->tidx = fv->nidx = -1;
313 if(!(ptr = parse_idx(ptr, &fv->vidx, numv)))
315 if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
317 if(*++ptr == '/') { /* no texcoord */
320 if(!(ptr = parse_idx(ptr, &fv->tidx, numt)))
322 if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
326 if(!(ptr = parse_idx(ptr, &fv->nidx, numn)))
328 return (!*ptr || isspace(*ptr)) ? ptr : 0;
331 static int load_mtllib(struct scenefile *scn, const char *path_prefix, const char *mtlfname)
334 char buf[256], *line;
336 struct material *mtl = 0;
338 if(path_prefix && *path_prefix) {
339 sprintf(buf, "%s/%s", path_prefix, mtlfname);
341 strcpy(buf, mtlfname);
344 if(!(fp = fopen(buf, "rb"))) {
348 while(fgets(buf, sizeof buf, fp)) {
349 if(!(line = cleanline(buf))) {
353 if(memcmp(line, "newmtl", 6) == 0) {
355 conv_mtl(mtl, &om, path_prefix);
356 mtl->next = scn->mtllist;
359 mtl = calloc(1, sizeof *mtl);
361 memset(&om, 0, sizeof om);
363 if((line = cleanline(line + 6))) {
364 om.name = strdup(line);
367 } else if(memcmp(line, "Kd", 2) == 0) {
368 sscanf(line + 3, "%f %f %f", &om.kd.x, &om.kd.y, &om.kd.z);
369 } else if(memcmp(line, "Ks", 2) == 0) {
370 sscanf(line + 3, "%f %f %f", &om.ks.x, &om.ks.y, &om.ks.z);
371 } else if(memcmp(line, "Ke", 2) == 0) {
372 sscanf(line + 3, "%f %f %f", &om.ke.x, &om.ke.y, &om.ke.z);
373 } else if(memcmp(line, "Ni", 2) == 0) {
374 om.ior = atof(line + 3);
375 } else if(line[0] == 'd' && isspace(line[1])) {
376 om.alpha = atof(line + 2);
377 } else if(memcmp(line, "map_Kd", 6) == 0) {
378 if((line = cleanline(line + 6))) {
379 om.map_kd = strdup(line);
381 } else if(memcmp(line, "map_Ke", 6) == 0) {
382 if((line = cleanline(line + 6))) {
383 om.map_ke = strdup(line);
385 } else if(memcmp(line, "map_d", 5) == 0) {
386 if((line = cleanline(line + 5))) {
387 om.map_alpha = strdup(line);
393 conv_mtl(mtl, &om, path_prefix);
394 mtl->next = scn->mtllist;
402 static void free_mtllist(struct material *mtl)
411 static void conv_mtl(struct material *mm, struct objmtl *om, const char *path_prefix)
413 char *fname = 0, *suffix = 0;
414 int len, prefix_len, maxlen = 0;
416 memset(mm, 0, sizeof *mm);
420 mm->shininess = om->shin;
422 if(om->map_kd && (len = strlen(om->map_kd)) > maxlen) maxlen = len;
423 if(om->map_ke && (len = strlen(om->map_ke)) > maxlen) maxlen = len;
424 if(om->map_alpha && (len = strlen(om->map_alpha)) > maxlen) maxlen = len;
427 prefix_len = strlen(path_prefix);
428 fname = alloca(maxlen + prefix_len + 2);
429 suffix = fname + prefix_len;
430 strcpy(fname, path_prefix);
435 strcpy(suffix, om->map_kd);
436 mm->tex[TEX_DIFFUSE] = get_image(fname);
441 static int cmp_facevert(const void *ap, const void *bp)
443 const struct facevertex *a = ap;
444 const struct facevertex *b = bp;
446 if(a->vidx == b->vidx) {
447 if(a->tidx == b->tidx) {
448 return a->nidx - b->nidx;
450 return a->tidx - b->tidx;
452 return a->vidx - b->vidx;
455 static void free_rbnode_key(struct rbnode *n, void *cls)