labyrinth
diff src/objfile.c @ 0:8ba79034e8a6
labyrinth example initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 15 Jan 2015 14:59:38 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/objfile.c Thu Jan 15 14:59:38 2015 +0200 1.3 @@ -0,0 +1,308 @@ 1.4 +/* version 2: does not crash when there are no texture coordinates or normals */ 1.5 +#include <stdio.h> 1.6 +#include <stdlib.h> 1.7 +#include <string.h> 1.8 +#include <errno.h> 1.9 +#include <limits.h> 1.10 +#include <ctype.h> 1.11 +#include "objfile.h" 1.12 + 1.13 +#define INVALID_IDX INT_MIN 1.14 + 1.15 +struct objfile { 1.16 + float *verts, *normals, *texcoords; 1.17 + int num_faces; 1.18 +}; 1.19 + 1.20 +struct vec3 { 1.21 + float x, y, z; 1.22 +}; 1.23 + 1.24 +struct face { 1.25 + int vidx[4]; 1.26 + int nidx[4]; 1.27 + int tidx[4]; 1.28 +}; 1.29 + 1.30 +static int objf_read(struct objfile *obj, FILE *fp, const char *fname); 1.31 +static int count_elem(FILE *fp, const char *elem); 1.32 +static char *strip(char *s); 1.33 +static int mkface(char *line, struct face *face); 1.34 +static int parse_face(char *s, int *vidx, int *nidx, int *tidx); 1.35 +static int is_int(const char *str); 1.36 + 1.37 + 1.38 +struct objfile *objf_load(const char *fname) 1.39 +{ 1.40 + FILE *fp; 1.41 + struct objfile *obj; 1.42 + 1.43 + if(!(fp = fopen(fname, "rb"))) { 1.44 + fprintf(stderr, "objf_load: failed to open file: %s: %s\n", fname, strerror(errno)); 1.45 + return 0; 1.46 + } 1.47 + 1.48 + if(!(obj = malloc(sizeof *obj))) { 1.49 + perror("failed to allocate objfile structure\n"); 1.50 + fclose(fp); 1.51 + return 0; 1.52 + } 1.53 + 1.54 + if(objf_read(obj, fp, fname) == -1) { 1.55 + free(obj); 1.56 + obj = 0; 1.57 + } 1.58 + fclose(fp); 1.59 + return obj; 1.60 +} 1.61 + 1.62 +void objf_free(struct objfile *obj) 1.63 +{ 1.64 + if(obj) { 1.65 + free(obj->verts); 1.66 + free(obj->normals); 1.67 + free(obj->texcoords); 1.68 + free(obj); 1.69 + } 1.70 +} 1.71 + 1.72 +int objf_vertex_count(struct objfile *obj) 1.73 +{ 1.74 + return obj->num_faces * 3; 1.75 +} 1.76 + 1.77 +int objf_face_count(struct objfile *obj) 1.78 +{ 1.79 + return obj->num_faces; 1.80 +} 1.81 + 1.82 +float *objf_vertices(struct objfile *obj) 1.83 +{ 1.84 + return obj->verts; 1.85 +} 1.86 + 1.87 +float *objf_normals(struct objfile *obj) 1.88 +{ 1.89 + return obj->normals; 1.90 +} 1.91 + 1.92 +float *objf_texcoords(struct objfile *obj) 1.93 +{ 1.94 + return obj->texcoords; 1.95 +} 1.96 + 1.97 + 1.98 +float *objf_vertex(struct objfile *obj, int idx) 1.99 +{ 1.100 + return obj->verts + idx * 3; 1.101 +} 1.102 + 1.103 +float *objf_normal(struct objfile *obj, int idx) 1.104 +{ 1.105 + return obj->normals + idx * 3; 1.106 +} 1.107 + 1.108 +float *objf_texcoord(struct objfile *obj, int idx) 1.109 +{ 1.110 + return obj->texcoords + idx * 2; 1.111 +} 1.112 + 1.113 +static int objf_read(struct objfile *obj, FILE *fp, const char *fname) 1.114 +{ 1.115 + int i, j, res = -1; 1.116 + int vcount, ncount, tcount, fcount; 1.117 + int num_verts; 1.118 + struct vec3 *varr, *narr, *tarr; 1.119 + struct vec3 *vptr, *nptr, *tptr; 1.120 + struct vec3 dummy_vec = {0, 0, 0}; 1.121 + struct face *faces, *fptr; 1.122 + float *vdest, *ndest, *tdest; 1.123 + char buf[512]; 1.124 + 1.125 + vcount = count_elem(fp, "v"); 1.126 + rewind(fp); 1.127 + ncount = count_elem(fp, "vn"); 1.128 + rewind(fp); 1.129 + tcount = count_elem(fp, "vt"); 1.130 + rewind(fp); 1.131 + fcount = count_elem(fp, "f"); 1.132 + rewind(fp); 1.133 + 1.134 + obj->num_faces = fcount; 1.135 + 1.136 + if(!vcount || !fcount) { 1.137 + fprintf(stderr, "invalid or corrupted obj file: %s\n", fname); 1.138 + return -1; 1.139 + } 1.140 + 1.141 + printf("Reading obj file: %s (%d vertices, %d faces)\n", fname, vcount, fcount); 1.142 + 1.143 + vptr = varr = malloc(vcount * sizeof *varr); 1.144 + nptr = narr = ncount ? malloc(ncount * sizeof *narr) : &dummy_vec; 1.145 + tptr = tarr = tcount ? malloc(tcount * sizeof *tarr) : &dummy_vec; 1.146 + fptr = faces = malloc(fcount * sizeof *faces); 1.147 + 1.148 + if(!varr || !narr || !tarr || !faces) { 1.149 + perror("can't allocate enough memory for the geometry"); 1.150 + goto cleanup; 1.151 + } 1.152 + 1.153 + while(fgets(buf, sizeof buf, fp)) { 1.154 + char *line; 1.155 + 1.156 + if(!(line = strip(buf)) || *line == '#') { 1.157 + continue; /* ignore empty lines and comments */ 1.158 + } 1.159 + 1.160 + if(sscanf(line, "v %f %f %f", &vptr->x, &vptr->y, &vptr->z) == 3) { 1.161 + vptr++; 1.162 + } else if(sscanf(line, "vn %f %f %f", &nptr->x, &nptr->y, &nptr->z) == 3) { 1.163 + nptr++; 1.164 + } else if(sscanf(line, "vt %f %f", &tptr->x, &tptr->y) == 2) { 1.165 + tptr++; 1.166 + } else if(mkface(line, fptr) == 0) { 1.167 + fptr++; 1.168 + } 1.169 + } 1.170 + 1.171 + /* now go forth and create the straight-up 3-vert-per-face vertex arrays */ 1.172 + num_verts = obj->num_faces * 3; 1.173 + 1.174 + vdest = obj->verts = malloc(num_verts * 3 * sizeof *obj->verts); 1.175 + ndest = obj->normals = malloc(num_verts * 3 * sizeof *obj->normals); 1.176 + tdest = obj->texcoords = malloc(num_verts * 2 * sizeof *obj->texcoords); 1.177 + 1.178 + if(!obj->verts || !obj->normals || !obj->texcoords) { 1.179 + free(obj->verts); 1.180 + free(obj->normals); 1.181 + goto cleanup; 1.182 + } 1.183 + 1.184 + /* for all faces */ 1.185 + for(i=0; i<fcount; i++) { 1.186 + /* for the 3 vertices of each face */ 1.187 + for(j=0; j<3; j++) { 1.188 + *vdest++ = varr[faces[i].vidx[j]].x; 1.189 + *vdest++ = varr[faces[i].vidx[j]].y; 1.190 + *vdest++ = varr[faces[i].vidx[j]].z; 1.191 + 1.192 + *ndest++ = narr[faces[i].nidx[j]].x; 1.193 + *ndest++ = narr[faces[i].nidx[j]].y; 1.194 + *ndest++ = narr[faces[i].nidx[j]].z; 1.195 + 1.196 + *tdest++ = tarr[faces[i].tidx[j]].x; 1.197 + *tdest++ = tarr[faces[i].tidx[j]].y; 1.198 + } 1.199 + } 1.200 + res = 0; /* success */ 1.201 + 1.202 +cleanup: 1.203 + free(varr); 1.204 + if(narr != &dummy_vec) { 1.205 + free(narr); 1.206 + } 1.207 + if(tarr != &dummy_vec) { 1.208 + free(tarr); 1.209 + } 1.210 + free(faces); 1.211 + return res; 1.212 +} 1.213 + 1.214 +static int count_elem(FILE *fp, const char *elem) 1.215 +{ 1.216 + int count = 0; 1.217 + char buf[512]; 1.218 + 1.219 + while(fgets(buf, sizeof buf, fp)) { 1.220 + if(buf[0] == elem[0] && (!elem[1] || buf[1] == elem[1])) { 1.221 + count++; 1.222 + } 1.223 + } 1.224 + return count; 1.225 +} 1.226 + 1.227 + 1.228 +static char *strip(char *s) 1.229 +{ 1.230 + while(*s && isspace(*s)) { 1.231 + s++; 1.232 + } 1.233 + return s; 1.234 +} 1.235 + 1.236 +static int mkface(char *s, struct face *face) 1.237 +{ 1.238 + int nverts; 1.239 + 1.240 + if(s[0] != 'f') { 1.241 + return -1; 1.242 + } 1.243 + 1.244 + if((nverts = parse_face(s + 2, face->vidx, face->nidx, face->tidx)) == -1) { 1.245 + return -1; 1.246 + } 1.247 + if(nverts > 3) { 1.248 + fprintf(stderr, "warning face with more than 3 vertices found\n"); 1.249 + } 1.250 + return 0; 1.251 +} 1.252 + 1.253 +#define SEP " \t\v\n\r" 1.254 +/* returns the number of vertices on this face, or -1 on error. */ 1.255 +static int parse_face(char *s, int *vidx, int *nidx, int *tidx) 1.256 +{ 1.257 + int i, num_verts = 0; 1.258 + char *tok[] = {0, 0, 0, 0}; 1.259 + char *subtok; 1.260 + 1.261 + for(i=0; i<4; i++) { 1.262 + if((!(tok[i] = strtok(i == 0 ? s : 0, SEP)) || !is_int(tok[i]))) { 1.263 + if(i < 3) return -1; 1.264 + } else { 1.265 + num_verts++; 1.266 + } 1.267 + } 1.268 + 1.269 + for(i=0; i<4; i++) { 1.270 + subtok = tok[i]; 1.271 + if(!subtok || !*subtok || !is_int(subtok)) { 1.272 + if(i < 3) { 1.273 + return -1; 1.274 + } 1.275 + vidx[i] = INVALID_IDX; 1.276 + } else { 1.277 + vidx[i] = atoi(subtok); 1.278 + if(vidx[i] > 0) vidx[i]--; /* convert to 0-based */ 1.279 + } 1.280 + 1.281 + while(subtok && *subtok && *subtok != '/') { 1.282 + subtok++; 1.283 + } 1.284 + if(subtok && *subtok && *++subtok && is_int(subtok)) { 1.285 + tidx[i] = atoi(subtok); 1.286 + if(tidx[i] > 0) tidx[i]--; /* convert to 0-based */ 1.287 + } else { 1.288 + tidx[i] = 0; 1.289 + } 1.290 + 1.291 + while(subtok && *subtok && *subtok != '/') { 1.292 + subtok++; 1.293 + } 1.294 + if(subtok && *subtok && *++subtok && is_int(subtok)) { 1.295 + nidx[i] = atoi(subtok); 1.296 + if(nidx[i] > 0) nidx[i]--; /* convert to 0-based */ 1.297 + } else { 1.298 + nidx[i] = 0; 1.299 + } 1.300 + } 1.301 + 1.302 + return num_verts; 1.303 +} 1.304 + 1.305 + 1.306 +static int is_int(const char *str) 1.307 +{ 1.308 + return isdigit(str[0]) || 1.309 + (str[0] == '-' && isdigit(str[1])) || 1.310 + (str[0] == '+' && isdigit(str[1])); 1.311 +}