nuclear@16: #include nuclear@16: #include nuclear@16: #include nuclear@16: #include nuclear@16: #include nuclear@16: #include "scene.h" nuclear@16: #include "cvec.h" nuclear@16: #include "mingl.h" nuclear@16: nuclear@16: nuclear@16: struct face { nuclear@16: int v[3], n[3], t[3]; nuclear@16: }; nuclear@16: nuclear@16: static int load_materials(struct scene *scn, const char *fname); nuclear@16: static int parse_face(struct face *face, char *buf); nuclear@16: nuclear@16: nuclear@16: /* --- scene --- */ nuclear@16: int scn_init(struct scene *scn) nuclear@16: { nuclear@16: memset(scn, 0, sizeof *scn); nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: void scn_destroy(struct scene *scn) nuclear@16: { nuclear@16: while(scn->matlist) { nuclear@16: struct material *tmp = scn->matlist; nuclear@16: scn->matlist = scn->matlist->next; nuclear@16: nuclear@16: mtl_destroy(tmp); nuclear@16: free(tmp); nuclear@16: } nuclear@16: while(scn->meshlist) { nuclear@16: struct mesh *tmp = scn->meshlist; nuclear@16: scn->meshlist = scn->meshlist->next; nuclear@16: nuclear@16: mesh_destroy(tmp); nuclear@16: free(tmp); nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: nuclear@16: void scn_add_mesh(struct scene *scn, struct mesh *m) nuclear@16: { nuclear@16: printf("adding mesh: %d faces\n", m->nface); nuclear@16: m->next = scn->meshlist; nuclear@16: scn->meshlist = m; nuclear@16: } nuclear@16: nuclear@16: void scn_add_material(struct scene *scn, struct material *m) nuclear@16: { nuclear@16: printf("adding material: %s\n", m->name); nuclear@16: m->next = scn->matlist; nuclear@16: scn->matlist = m; nuclear@16: } nuclear@16: nuclear@16: struct material *scn_find_material(struct scene *scn, const char *name) nuclear@16: { nuclear@16: struct material *mtl = scn->matlist; nuclear@16: nuclear@16: while(mtl) { nuclear@16: if(strcmp(mtl->name, name) == 0) { nuclear@16: break; nuclear@16: } nuclear@16: mtl = mtl->next; nuclear@16: } nuclear@16: return mtl; nuclear@16: } nuclear@16: nuclear@16: #define SEP " \t\n\r" nuclear@16: int scn_load(struct scene *scn, const char *fname) nuclear@16: { nuclear@16: FILE *fp; nuclear@16: char buf[256]; nuclear@16: struct mesh *m; nuclear@16: vec3_t *varr, *vnarr; nuclear@16: vec2_t *vtarr; nuclear@16: nuclear@16: if(!(fp = fopen(fname, "rb"))) { nuclear@16: fprintf(stderr, "failed to open scene file: %s: %s\n", fname, strerror(errno)); nuclear@16: return -1; nuclear@16: } nuclear@16: nuclear@16: varr = cvec_alloc(0, sizeof *varr); nuclear@16: vnarr = cvec_alloc(0, sizeof *vnarr); nuclear@16: vtarr = cvec_alloc(0, sizeof *vtarr); nuclear@16: nuclear@16: if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) { nuclear@16: fprintf(stderr, "meshed up\n"); nuclear@16: fclose(fp); nuclear@16: return -1; nuclear@16: } nuclear@16: nuclear@16: while(fgets(buf, sizeof buf, fp)) { nuclear@16: char *line = buf; nuclear@16: char *tok, *rest, *tmp; nuclear@16: nuclear@16: while(*line && isspace(*line)) { nuclear@16: line++; nuclear@16: } nuclear@16: if(*line == 0 || *line == '#') { nuclear@16: continue; nuclear@16: } nuclear@16: nuclear@16: if(!(tok = strtok(line, SEP))) { nuclear@16: continue; nuclear@16: } nuclear@16: rest = tok + strlen(tok) + 1; nuclear@16: nuclear@16: if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) { nuclear@16: *tmp = 0; nuclear@16: } nuclear@16: nuclear@16: if(strcmp(tok, "mtllib") == 0) { nuclear@16: if(!rest) { nuclear@16: fprintf(stderr, "invalid mtllib directive\n"); nuclear@16: continue; nuclear@16: } nuclear@16: load_materials(scn, rest); nuclear@16: nuclear@16: } else if(strcmp(tok, "usemtl") == 0) { nuclear@16: if(rest) { nuclear@16: m->mtl = scn_find_material(scn, rest); nuclear@16: } nuclear@16: nuclear@16: } else if(strcmp(tok, "o") == 0 || strcmp(tok, "g") == 0) { nuclear@16: if(cvec_size(m->vert) > 0) { nuclear@16: scn_add_mesh(scn, m); nuclear@16: nuclear@16: if(!(m = malloc(sizeof *m)) || mesh_init(m) == -1) { nuclear@16: fprintf(stderr, "meshed up\n"); nuclear@16: fclose(fp); nuclear@16: return -1; nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: } else if(strcmp(tok, "v") == 0) { nuclear@16: vec3_t v; nuclear@16: nuclear@16: if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) { nuclear@16: continue; nuclear@16: } nuclear@16: varr = cvec_append(varr, &v); nuclear@16: nuclear@16: } else if(strcmp(tok, "vn") == 0) { nuclear@16: vec3_t v; nuclear@16: nuclear@16: if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) { nuclear@16: continue; nuclear@16: } nuclear@16: vnarr = cvec_append(vnarr, &v); nuclear@16: nuclear@16: } else if(strcmp(tok, "vt") == 0) { nuclear@16: vec3_t v; nuclear@16: nuclear@16: if(!rest || sscanf(rest, "%f %f %f\n", &v.x, &v.y, &v.z) != 3) { nuclear@16: continue; nuclear@16: } nuclear@16: vtarr = cvec_append(vtarr, &v); nuclear@16: nuclear@16: } else if(strcmp(tok, "f") == 0) { nuclear@16: int i; nuclear@16: struct face face; nuclear@16: nuclear@16: if(!rest || parse_face(&face, rest) == -1) { nuclear@16: continue; nuclear@16: } nuclear@16: nuclear@16: for(i=0; i<3; i++) { nuclear@16: int vidx = face.v[i]; nuclear@16: int nidx = face.n[i]; nuclear@16: int tidx = face.t[i]; nuclear@16: nuclear@16: mesh_add_vertex(m, varr[vidx]); nuclear@16: if(nidx >= 0) { nuclear@16: mesh_add_normal(m, vnarr[nidx]); nuclear@16: } nuclear@16: if(tidx >= 0) { nuclear@16: mesh_add_texcoord(m, vtarr[tidx]); nuclear@16: } nuclear@16: m->nface++; nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: } nuclear@16: fclose(fp); nuclear@16: nuclear@16: if(cvec_size(m->vert) > 0) { nuclear@16: scn_add_mesh(scn, m); nuclear@16: } nuclear@16: nuclear@16: cvec_free(varr); nuclear@16: cvec_free(vnarr); nuclear@16: cvec_free(vtarr); nuclear@16: nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: static int load_materials(struct scene *scn, const char *fname) nuclear@16: { nuclear@16: FILE *fp; nuclear@16: struct material *m = 0; nuclear@16: char buf[256]; nuclear@16: nuclear@16: if(!(fp = fopen(fname, "r"))) { nuclear@16: fprintf(stderr, "failed to load material file: %s: %s\n", fname, strerror(errno)); nuclear@16: return -1; nuclear@16: } nuclear@16: nuclear@16: while(fgets(buf, sizeof buf, fp)) { nuclear@16: char *line = buf; nuclear@16: char *tok, *rest, *tmp; nuclear@16: nuclear@16: while(*line && isspace(*line)) { nuclear@16: line++; nuclear@16: } nuclear@16: if(*line == 0 || *line == '#') { nuclear@16: continue; nuclear@16: } nuclear@16: nuclear@16: if(!(tok = strtok(line, SEP))) { nuclear@16: continue; nuclear@16: } nuclear@16: rest = tok + strlen(tok) + 1; nuclear@16: nuclear@16: if((tmp = strchr(rest, '\r')) || (tmp = strchr(rest, '\n'))) { nuclear@16: *tmp = 0; nuclear@16: } nuclear@16: nuclear@16: if(strcmp(tok, "newmtl") == 0) { nuclear@16: if(m) { nuclear@16: scn_add_material(scn, m); nuclear@16: } nuclear@16: if(!(m = malloc(sizeof *m)) || mtl_init(m) == -1) { nuclear@16: continue; nuclear@16: } nuclear@16: mtl_set_name(m, rest); nuclear@16: nuclear@16: } else if(strcmp(tok, "Kd") == 0) { nuclear@16: if(sscanf(rest, "%f %f %f", &m->kd.x, &m->kd.y, &m->kd.z) != 3) { nuclear@16: continue; nuclear@16: } nuclear@16: } else if(strcmp(tok, "map_Kd") == 0) { nuclear@16: printf("ignoring texture: `%s'\n", rest); nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: if(m) { nuclear@16: scn_add_material(scn, m); nuclear@16: } nuclear@16: nuclear@16: fclose(fp); nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: static int parse_face(struct face *face, char *buf) nuclear@16: { nuclear@16: int i, found; nuclear@16: char *tok; nuclear@16: nuclear@16: for(i=0; i<3; i++) { nuclear@16: tok = strtok(i > 0 ? 0 : buf, SEP); nuclear@16: found = sscanf(tok, "%d/%d/%d", &face->v[i], &face->t[i], &face->n[i]); nuclear@16: nuclear@16: face->v[i]--; nuclear@16: nuclear@16: if(found > 1) { nuclear@16: face->t[i]--; nuclear@16: } else { nuclear@16: face->t[i] = -1; nuclear@16: } nuclear@16: if(found > 2) { nuclear@16: face->n[i]--; nuclear@16: } else { nuclear@16: face->n[i] = -1; nuclear@16: } nuclear@16: } nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: void scn_render(struct scene *scn) nuclear@16: { nuclear@16: struct mesh *m = scn->meshlist; nuclear@16: nuclear@16: while(m) { nuclear@16: mesh_draw(m); nuclear@16: m = m->next; nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: /* --- material --- */ nuclear@16: int mtl_init(struct material *mtl) nuclear@16: { nuclear@16: memset(mtl, 0, sizeof *mtl); nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: void mtl_destroy(struct material *mtl) nuclear@16: { nuclear@16: free(mtl->name); nuclear@16: nuclear@16: if(mtl->tex) { nuclear@16: free_texture(mtl->tex); nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: nuclear@16: int mtl_set_name(struct material *mtl, const char *name) nuclear@16: { nuclear@16: char *tmp; nuclear@16: int len = strlen(name); nuclear@16: nuclear@16: if(!(tmp = malloc(len + 1))) { nuclear@16: perror("failed to allocate material name"); nuclear@16: return -1; nuclear@16: } nuclear@16: memcpy(tmp, name, len); nuclear@16: tmp[len] = 0; nuclear@16: nuclear@16: free(mtl->name); nuclear@16: mtl->name = tmp; nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: nuclear@16: /* --- mesh --- */ nuclear@16: int mesh_init(struct mesh *m) nuclear@16: { nuclear@16: memset(m, 0, sizeof *m); nuclear@16: nuclear@16: m->vert = cvec_alloc(0, sizeof *m->vert); nuclear@16: m->norm = cvec_alloc(0, sizeof *m->norm); nuclear@16: m->texcoord = cvec_alloc(0, sizeof *m->texcoord); nuclear@16: nuclear@16: if(!m->vert || !m->norm || !m->texcoord) { nuclear@16: return -1; nuclear@16: } nuclear@16: return 0; nuclear@16: } nuclear@16: nuclear@16: void mesh_destroy(struct mesh *m) nuclear@16: { nuclear@16: cvec_free(m->vert); nuclear@16: cvec_free(m->norm); nuclear@16: cvec_free(m->texcoord); nuclear@16: } nuclear@16: nuclear@16: void mesh_add_vertex(struct mesh *m, vec3_t v) nuclear@16: { nuclear@16: m->vert = cvec_append(m->vert, &v); nuclear@16: } nuclear@16: nuclear@16: void mesh_add_normal(struct mesh *m, vec3_t n) nuclear@16: { nuclear@16: m->norm = cvec_append(m->norm, &n); nuclear@16: } nuclear@16: nuclear@16: void mesh_add_texcoord(struct mesh *m, vec2_t tc) nuclear@16: { nuclear@16: m->texcoord = cvec_append(m->texcoord, &tc); nuclear@16: } nuclear@16: nuclear@16: void mesh_draw(struct mesh *m) nuclear@16: { nuclear@16: int i, numv; nuclear@16: nuclear@16: mgl_begin(MGL_TRIANGLES); nuclear@16: nuclear@16: numv = cvec_size(m->vert); nuclear@16: for(i=0; inorm[i].x, m->norm[i].y, m->norm[i].z); nuclear@16: mgl_texcoord2f(m->texcoord[i].x, m->texcoord[i].y); nuclear@16: mgl_vertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z); nuclear@16: } nuclear@16: nuclear@16: mgl_end(); nuclear@16: }