nuclear@16: #include nuclear@16: #include nuclear@16: #include nuclear@16: #include nuclear@16: #include nuclear@19: #include nuclear@16: #include "scene.h" nuclear@16: #include "cvec.h" nuclear@17: #include "palman.h" nuclear@17: nuclear@17: #ifdef USE_GL nuclear@17: #include nuclear@17: #else nuclear@16: #include "mingl.h" nuclear@17: #endif 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@19: vec2_t v; nuclear@16: nuclear@19: if(!rest || sscanf(rest, "%f %f\n", &v.x, &v.y) != 2) { nuclear@16: continue; nuclear@16: } nuclear@19: v.y = 1.0 - v.y; 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@17: if(!m->tex) { nuclear@17: palm_add_color(m->kd[0], m->kd[1], m->kd[2]); nuclear@17: } 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@17: float r, g, b; nuclear@17: if(sscanf(rest, "%f %f %f", &r, &g, &b) != 3) { nuclear@16: continue; nuclear@16: } nuclear@17: m->kd[0] = (int)(r * 255.0); nuclear@17: m->kd[1] = (int)(g * 255.0); nuclear@17: m->kd[2] = (int)(b * 255.0); nuclear@17: nuclear@16: } else if(strcmp(tok, "map_Kd") == 0) { nuclear@17: if(!(m->tex = load_texture(rest))) { nuclear@17: fprintf(stderr, "failed to load texture: `%s'\n", rest); nuclear@17: } nuclear@16: } nuclear@16: } nuclear@16: nuclear@16: if(m) { nuclear@17: if(!m->tex) { nuclear@17: palm_add_color(m->kd[0], m->kd[1], m->kd[2]); nuclear@17: } 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@17: struct mesh *m; nuclear@16: nuclear@17: if(!scn->ready) { nuclear@17: struct material *mtl = scn->matlist; nuclear@17: while(mtl) { nuclear@17: if(mtl->tex) { nuclear@17: get_texture_pixels(mtl->tex); nuclear@17: #ifdef USE_GL nuclear@17: { nuclear@17: int i, npix = mtl->tex->width * mtl->tex->height; nuclear@17: int range = palm_color_range(); nuclear@17: unsigned char *rgb = malloc(npix * 3); nuclear@17: struct palm_color *pal = palm_palette(); nuclear@17: nuclear@17: for(i=0; itex->pixels[i] + range - 1; nuclear@17: rgb[i * 3] = pal[idx].r; nuclear@17: rgb[i * 3 + 1] = pal[idx].g; nuclear@17: rgb[i * 3 + 2] = pal[idx].b; nuclear@17: } nuclear@17: free(mtl->tex->pixels); nuclear@17: mtl->tex->pixels = rgb; nuclear@17: } nuclear@17: #endif /* USE_GL */ nuclear@17: } else { nuclear@17: mtl->kd_base = palm_color_base(mtl->kd[0], mtl->kd[1], mtl->kd[2]); nuclear@17: } nuclear@17: mtl = mtl->next; nuclear@17: } nuclear@17: scn->ready = 1; nuclear@17: } nuclear@17: nuclear@17: m = scn->meshlist; nuclear@16: while(m) { nuclear@16: mesh_draw(m); nuclear@16: m = m->next; nuclear@16: } nuclear@19: nuclear@19: #if 0 nuclear@19: { nuclear@19: int i; nuclear@19: struct palm_color *pal = palm_palette(); nuclear@19: float dx = 1.8 / 256; nuclear@19: struct material *mtl = scn->matlist; nuclear@19: nuclear@19: glMatrixMode(GL_MODELVIEW); nuclear@19: glPushMatrix(); nuclear@19: glLoadIdentity(); nuclear@19: glMatrixMode(GL_PROJECTION); nuclear@19: glPushMatrix(); nuclear@19: glLoadIdentity(); nuclear@19: nuclear@19: glPushAttrib(GL_ENABLE_BIT); nuclear@19: glDisable(GL_LIGHTING); nuclear@19: glDisable(GL_DEPTH_TEST); nuclear@19: nuclear@19: glBegin(GL_QUADS); nuclear@19: for(i=0; i<255; i++) { nuclear@19: float x = i * dx - 0.9; nuclear@19: glColor3ub(pal[i].r, pal[i].g, pal[i].b); nuclear@19: glVertex2f(x, 0.98); nuclear@19: glVertex2f(x, 0.9); nuclear@19: glColor3ub(pal[i + 1].r, pal[i + 1].g, pal[i + 1].b); nuclear@19: glVertex2f(x + dx, 0.9); nuclear@19: glVertex2f(x + dx, 0.98); nuclear@19: } nuclear@19: glEnd(); nuclear@19: nuclear@19: glPopAttrib(); nuclear@19: nuclear@19: glMatrixMode(GL_PROJECTION); nuclear@19: glPopMatrix(); nuclear@19: glMatrixMode(GL_MODELVIEW); nuclear@19: glPopMatrix(); nuclear@19: } nuclear@19: #endif 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@17: struct material *mtl = m->mtl; nuclear@17: nuclear@17: numv = cvec_size(m->vert); nuclear@17: nuclear@17: #ifdef USE_GL nuclear@17: if(mtl->tex) { nuclear@19: assert(mtl->tex->pixels); nuclear@17: glEnable(GL_TEXTURE_2D); nuclear@17: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); nuclear@17: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nuclear@17: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); nuclear@17: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); nuclear@17: nuclear@17: glTexImage2D(GL_TEXTURE_2D, 0, 3, mtl->tex->width, mtl->tex->height, 0, GL_RGB, GL_UNSIGNED_BYTE, mtl->tex->pixels); nuclear@17: } nuclear@17: nuclear@17: glBegin(GL_TRIANGLES); nuclear@17: for(i=0; inorm[i].x, m->norm[i].y, m->norm[i].z); nuclear@17: glTexCoord2f(m->texcoord[i].x, m->texcoord[i].y); nuclear@17: glVertex3f(m->vert[i].x, m->vert[i].y, m->vert[i].z); nuclear@17: } nuclear@17: glEnd(); nuclear@17: nuclear@17: if(mtl->tex) { nuclear@17: glDisable(GL_TEXTURE_2D); nuclear@17: } nuclear@17: #else nuclear@17: if(mtl->tex) { nuclear@19: mgl_enable(MGL_TEXTURE_2D); nuclear@17: mgl_teximage(mtl->tex->width, mtl->tex->height, mtl->tex->pixels); nuclear@17: } else { nuclear@17: mgl_index(mtl->kd_base); nuclear@17: } nuclear@16: nuclear@16: mgl_begin(MGL_TRIANGLES); nuclear@16: 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@17: mgl_end(); nuclear@16: nuclear@17: if(mtl->tex) { nuclear@17: mgl_disable(MGL_TEXTURE_2D); nuclear@17: } nuclear@17: #endif nuclear@16: }