deepstone
diff src/scene.c @ 16:cb676ff89e69
added missing cvec and scene files
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 29 Nov 2011 07:23:57 +0200 |
parents | |
children | 1e9f0b3616fa |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/scene.c Tue Nov 29 07:23:57 2011 +0200 1.3 @@ -0,0 +1,379 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <ctype.h> 1.8 +#include <errno.h> 1.9 +#include "scene.h" 1.10 +#include "cvec.h" 1.11 +#include "mingl.h" 1.12 + 1.13 + 1.14 +struct face { 1.15 + int v[3], n[3], t[3]; 1.16 +}; 1.17 + 1.18 +static int load_materials(struct scene *scn, const char *fname); 1.19 +static int parse_face(struct face *face, char *buf); 1.20 + 1.21 + 1.22 +/* --- scene --- */ 1.23 +int scn_init(struct scene *scn) 1.24 +{ 1.25 + memset(scn, 0, sizeof *scn); 1.26 + return 0; 1.27 +} 1.28 + 1.29 +void scn_destroy(struct scene *scn) 1.30 +{ 1.31 + while(scn->matlist) { 1.32 + struct material *tmp = scn->matlist; 1.33 + scn->matlist = scn->matlist->next; 1.34 + 1.35 + mtl_destroy(tmp); 1.36 + free(tmp); 1.37 + } 1.38 + while(scn->meshlist) { 1.39 + struct mesh *tmp = scn->meshlist; 1.40 + scn->meshlist = scn->meshlist->next; 1.41 + 1.42 + mesh_destroy(tmp); 1.43 + free(tmp); 1.44 + } 1.45 +} 1.46 + 1.47 + 1.48 +void scn_add_mesh(struct scene *scn, struct mesh *m) 1.49 +{ 1.50 + printf("adding mesh: %d faces\n", m->nface); 1.51 + m->next = scn->meshlist; 1.52 + scn->meshlist = m; 1.53 +} 1.54 + 1.55 +void scn_add_material(struct scene *scn, struct material *m) 1.56 +{ 1.57 + printf("adding material: %s\n", m->name); 1.58 + m->next = scn->matlist; 1.59 + scn->matlist = m; 1.60 +} 1.61 + 1.62 +struct material *scn_find_material(struct scene *scn, const char *name) 1.63 +{ 1.64 + struct material *mtl = scn->matlist; 1.65 + 1.66 + while(mtl) { 1.67 + if(strcmp(mtl->name, name) == 0) { 1.68 + break; 1.69 + } 1.70 + mtl = mtl->next; 1.71 + } 1.72 + return mtl; 1.73 +} 1.74 + 1.75 +#define SEP " \t\n\r" 1.76 +int scn_load(struct scene *scn, const char *fname) 1.77 +{ 1.78 + FILE *fp; 1.79 + char buf[256]; 1.80 + struct mesh *m; 1.81 + vec3_t *varr, *vnarr; 1.82 + vec2_t *vtarr; 1.83 + 1.84 + if(!(fp = fopen(fname, "rb"))) { 1.85 + fprintf(stderr, "failed to open scene file: %s: %s\n", fname, strerror(errno)); 1.86 + return -1; 1.87 + } 1.88 + 1.89 + varr = cvec_alloc(0, sizeof *varr); 1.90 + vnarr = cvec_alloc(0, sizeof *vnarr); 1.91 + vtarr = cvec_alloc(0, sizeof *vtarr); 1.92 + 1.93 + if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) { 1.94 + fprintf(stderr, "meshed up\n"); 1.95 + fclose(fp); 1.96 + return -1; 1.97 + } 1.98 + 1.99 + while(fgets(buf, sizeof buf, fp)) { 1.100 + char *line = buf; 1.101 + char *tok, *rest, *tmp; 1.102 + 1.103 + while(*line && isspace(*line)) { 1.104 + line++; 1.105 + } 1.106 + if(*line == 0 || *line == '#') { 1.107 + continue; 1.108 + } 1.109 + 1.110 + if(!(tok = strtok(line, SEP))) { 1.111 + continue; 1.112 + } 1.113 + rest = tok + strlen(tok) + 1; 1.114 + 1.115 + if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) { 1.116 + *tmp = 0; 1.117 + } 1.118 + 1.119 + if(strcmp(tok, "mtllib") == 0) { 1.120 + if(!rest) { 1.121 + fprintf(stderr, "invalid mtllib directive\n"); 1.122 + continue; 1.123 + } 1.124 + load_materials(scn, rest); 1.125 + 1.126 + } else if(strcmp(tok, "usemtl") == 0) { 1.127 + if(rest) { 1.128 + m->mtl = scn_find_material(scn, rest); 1.129 + } 1.130 + 1.131 + } else if(strcmp(tok, "o") == 0 || strcmp(tok, "g") == 0) { 1.132 + if(cvec_size(m->vert) > 0) { 1.133 + scn_add_mesh(scn, m); 1.134 + 1.135 + if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) { 1.136 + fprintf(stderr, "meshed up\n"); 1.137 + fclose(fp); 1.138 + return -1; 1.139 + } 1.140 + } 1.141 + 1.142 + } else if(strcmp(tok, "v") == 0) { 1.143 + vec3_t v; 1.144 + 1.145 + if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) { 1.146 + continue; 1.147 + } 1.148 + varr = cvec_append(varr, &v); 1.149 + 1.150 + } else if(strcmp(tok, "vn") == 0) { 1.151 + vec3_t v; 1.152 + 1.153 + if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) { 1.154 + continue; 1.155 + } 1.156 + vnarr = cvec_append(vnarr, &v); 1.157 + 1.158 + } else if(strcmp(tok, "vt") == 0) { 1.159 + vec3_t v; 1.160 + 1.161 + if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) { 1.162 + continue; 1.163 + } 1.164 + vtarr = cvec_append(vtarr, &v); 1.165 + 1.166 + } else if(strcmp(tok, "f") == 0) { 1.167 + int i; 1.168 + struct face face; 1.169 + 1.170 + if(!rest || parse_face(&face, rest) == -1) { 1.171 + continue; 1.172 + } 1.173 + 1.174 + for(i=0; i<3; i++) { 1.175 + int vidx = face.v[i]; 1.176 + int nidx = face.n[i]; 1.177 + int tidx = face.t[i]; 1.178 + 1.179 + mesh_add_vertex(m, varr[vidx]); 1.180 + if(nidx >= 0) { 1.181 + mesh_add_normal(m, vnarr[nidx]); 1.182 + } 1.183 + if(tidx >= 0) { 1.184 + mesh_add_texcoord(m, vtarr[tidx]); 1.185 + } 1.186 + m->nface++; 1.187 + } 1.188 + } 1.189 + 1.190 + } 1.191 + fclose(fp); 1.192 + 1.193 + if(cvec_size(m->vert) > 0) { 1.194 + scn_add_mesh(scn, m); 1.195 + } 1.196 + 1.197 + cvec_free(varr); 1.198 + cvec_free(vnarr); 1.199 + cvec_free(vtarr); 1.200 + 1.201 + return 0; 1.202 +} 1.203 + 1.204 +static int load_materials(struct scene *scn, const char *fname) 1.205 +{ 1.206 + FILE *fp; 1.207 + struct material *m = 0; 1.208 + char buf[256]; 1.209 + 1.210 + if(!(fp = fopen(fname, "r"))) { 1.211 + fprintf(stderr, "failed to load material file: %s: %s\n", fname, strerror(errno)); 1.212 + return -1; 1.213 + } 1.214 + 1.215 + while(fgets(buf, sizeof buf, fp)) { 1.216 + char *line = buf; 1.217 + char *tok, *rest, *tmp; 1.218 + 1.219 + while(*line && isspace(*line)) { 1.220 + line++; 1.221 + } 1.222 + if(*line == 0 || *line == '#') { 1.223 + continue; 1.224 + } 1.225 + 1.226 + if(!(tok = strtok(line, SEP))) { 1.227 + continue; 1.228 + } 1.229 + rest = tok + strlen(tok) + 1; 1.230 + 1.231 + if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) { 1.232 + *tmp = 0; 1.233 + } 1.234 + 1.235 + if(strcmp(tok, "newmtl") == 0) { 1.236 + if(m) { 1.237 + scn_add_material(scn, m); 1.238 + } 1.239 + if(!(m = malloc(sizeof *m)) || mtl_init(m) == -1) { 1.240 + continue; 1.241 + } 1.242 + mtl_set_name(m, rest); 1.243 + 1.244 + } else if(strcmp(tok, "Kd") == 0) { 1.245 + if(sscanf(rest, "%f %f %f", &m->kd.x, &m->kd.y, &m->kd.z) != 3) { 1.246 + continue; 1.247 + } 1.248 + } else if(strcmp(tok, "map_Kd") == 0) { 1.249 + printf("ignoring texture: `%s'\n", rest); 1.250 + } 1.251 + } 1.252 + 1.253 + if(m) { 1.254 + scn_add_material(scn, m); 1.255 + } 1.256 + 1.257 + fclose(fp); 1.258 + return 0; 1.259 +} 1.260 + 1.261 +static int parse_face(struct face *face, char *buf) 1.262 +{ 1.263 + int i, found; 1.264 + char *tok; 1.265 + 1.266 + for(i=0; i<3; i++) { 1.267 + tok = strtok(i > 0 ? 0 : buf, SEP); 1.268 + found = sscanf(tok, "%d/%d/%d", &face->v[i], &face->t[i], &face->n[i]); 1.269 + 1.270 + face->v[i]--; 1.271 + 1.272 + if(found > 1) { 1.273 + face->t[i]--; 1.274 + } else { 1.275 + face->t[i] = -1; 1.276 + } 1.277 + if(found > 2) { 1.278 + face->n[i]--; 1.279 + } else { 1.280 + face->n[i] = -1; 1.281 + } 1.282 + } 1.283 + return 0; 1.284 +} 1.285 + 1.286 +void scn_render(struct scene *scn) 1.287 +{ 1.288 + struct mesh *m = scn->meshlist; 1.289 + 1.290 + while(m) { 1.291 + mesh_draw(m); 1.292 + m = m->next; 1.293 + } 1.294 +} 1.295 + 1.296 +/* --- material --- */ 1.297 +int mtl_init(struct material *mtl) 1.298 +{ 1.299 + memset(mtl, 0, sizeof *mtl); 1.300 + return 0; 1.301 +} 1.302 + 1.303 +void mtl_destroy(struct material *mtl) 1.304 +{ 1.305 + free(mtl->name); 1.306 + 1.307 + if(mtl->tex) { 1.308 + free_texture(mtl->tex); 1.309 + } 1.310 +} 1.311 + 1.312 + 1.313 +int mtl_set_name(struct material *mtl, const char *name) 1.314 +{ 1.315 + char *tmp; 1.316 + int len = strlen(name); 1.317 + 1.318 + if(!(tmp = malloc(len + 1))) { 1.319 + perror("failed to allocate material name"); 1.320 + return -1; 1.321 + } 1.322 + memcpy(tmp, name, len); 1.323 + tmp[len] = 0; 1.324 + 1.325 + free(mtl->name); 1.326 + mtl->name = tmp; 1.327 + return 0; 1.328 +} 1.329 + 1.330 + 1.331 +/* --- mesh --- */ 1.332 +int mesh_init(struct mesh *m) 1.333 +{ 1.334 + memset(m, 0, sizeof *m); 1.335 + 1.336 + m->vert = cvec_alloc(0, sizeof *m->vert); 1.337 + m->norm = cvec_alloc(0, sizeof *m->norm); 1.338 + m->texcoord = cvec_alloc(0, sizeof *m->texcoord); 1.339 + 1.340 + if(!m->vert || !m->norm || !m->texcoord) { 1.341 + return -1; 1.342 + } 1.343 + return 0; 1.344 +} 1.345 + 1.346 +void mesh_destroy(struct mesh *m) 1.347 +{ 1.348 + cvec_free(m->vert); 1.349 + cvec_free(m->norm); 1.350 + cvec_free(m->texcoord); 1.351 +} 1.352 + 1.353 +void mesh_add_vertex(struct mesh *m, vec3_t v) 1.354 +{ 1.355 + m->vert = cvec_append(m->vert, &v); 1.356 +} 1.357 + 1.358 +void mesh_add_normal(struct mesh *m, vec3_t n) 1.359 +{ 1.360 + m->norm = cvec_append(m->norm, &n); 1.361 +} 1.362 + 1.363 +void mesh_add_texcoord(struct mesh *m, vec2_t tc) 1.364 +{ 1.365 + m->texcoord = cvec_append(m->texcoord, &tc); 1.366 +} 1.367 + 1.368 +void mesh_draw(struct mesh *m) 1.369 +{ 1.370 + int i, numv; 1.371 + 1.372 + mgl_begin(MGL_TRIANGLES); 1.373 + 1.374 + numv = cvec_size(m->vert); 1.375 + for(i=0; i<numv; i++) { 1.376 + mgl_normal(m->norm[i].x, m->norm[i].y, m->norm[i].z); 1.377 + mgl_texcoord2f(m->texcoord[i].x, m->texcoord[i].y); 1.378 + mgl_vertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z); 1.379 + } 1.380 + 1.381 + mgl_end(); 1.382 +}