nuclear@8: #include nuclear@8: #include nuclear@8: #include nuclear@8: #include nuclear@8: nuclear@8: #ifndef __APPLE__ nuclear@8: #include nuclear@8: #else nuclear@8: #include nuclear@8: #endif nuclear@8: nuclear@8: #include nuclear@9: #include "volume.h" nuclear@8: nuclear@8: struct slice { nuclear@8: char *name; nuclear@8: struct slice *next; nuclear@8: }; nuclear@8: nuclear@9: static void calc_gradients(float *voxels, int xsz, int ysz, int zsz); nuclear@8: static struct slice *read_voldesc(const char *fname, struct volume *vol); nuclear@8: static char *trim(char *str); nuclear@8: nuclear@8: struct volume *load_volume(const char *fname) nuclear@8: { nuclear@9: int i; nuclear@8: struct slice *slist; nuclear@8: struct volume *vol = 0; nuclear@9: float *voxels = 0, *vptr; nuclear@9: struct img_pixmap img; nuclear@8: nuclear@8: if(!(vol = malloc(sizeof *vol))) { nuclear@8: perror("failed to allocate volume"); nuclear@8: return 0; nuclear@8: } nuclear@8: memset(vol, 0, sizeof *vol); nuclear@8: vol->zaspect = 1; nuclear@8: nuclear@8: if(!(slist = read_voldesc(fname, vol))) { nuclear@8: goto err; nuclear@8: } nuclear@8: nuclear@9: /* load the first image to determine slice dimensions */ nuclear@9: img_init(&img); nuclear@9: if(img_load(&img, slist->name) == -1) { nuclear@9: fprintf(stderr, "failed to load volume slice: %s\n", slist->name); nuclear@9: goto err; nuclear@9: } nuclear@9: nuclear@9: vol->sz[0] = img.width; nuclear@9: vol->sz[1] = img.height; nuclear@9: printf("volume dimensions: %dx%dx%d\n", img.width, img.height, vol->sz[2]); nuclear@9: nuclear@9: /* allocate the whole volume at once */ nuclear@9: if(!(voxels = malloc(vol->sz[0] * vol->sz[1] * vol->sz[2] * 4 * sizeof *voxels))) { nuclear@9: img_destroy(&img); nuclear@9: goto err; nuclear@9: } nuclear@9: vptr = voxels; nuclear@9: img_destroy(&img); nuclear@9: nuclear@9: /* put the volume data into the alpha component */ nuclear@9: for(i=0; isz[2]; i++) { nuclear@9: int x, y, xsz, ysz; nuclear@9: float *pixels, *src; nuclear@9: struct slice *slice = slist; nuclear@9: slist = slist->next; nuclear@9: nuclear@9: if(!(pixels = img_load_pixels(slice->name, &xsz, &ysz, IMG_FMT_GREYF))) { nuclear@9: fprintf(stderr, "failed to load volume slice: %s\n", slice->name); nuclear@9: goto err; nuclear@9: } nuclear@9: nuclear@9: if(xsz != vol->sz[0] || ysz != vol->sz[1]) { nuclear@9: fprintf(stderr, "inconsistent dimensions for slice %s: %dx%d (%dx%d expected)\n", nuclear@9: slice->name, xsz, ysz, vol->sz[0], vol->sz[1]); nuclear@9: goto err; nuclear@9: } nuclear@9: free(slice->name); nuclear@9: free(slice); nuclear@9: nuclear@9: src = pixels; nuclear@9: for(y=0; ysz[0], vol->sz[1], vol->sz[2]); nuclear@9: nuclear@9: /* create the volume texture */ nuclear@8: glGenTextures(1, &vol->tex_vol); nuclear@8: glBindTexture(GL_TEXTURE_3D, vol->tex_vol); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); nuclear@10: glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F_ARB, vol->sz[0], vol->sz[1], vol->sz[2], 0, nuclear@9: GL_RGBA, GL_FLOAT, voxels); nuclear@8: nuclear@9: /* ... and destroy our copy */ nuclear@9: free(voxels); nuclear@9: return vol; nuclear@8: nuclear@8: err: nuclear@8: while(slist) { nuclear@8: struct slice *tmp = slist; nuclear@8: slist = slist->next; nuclear@8: free(tmp->name); nuclear@8: free(tmp); nuclear@8: } nuclear@9: free_volume(vol); nuclear@9: free(voxels); nuclear@9: return 0; nuclear@9: } nuclear@9: nuclear@9: void free_volume(struct volume *vol) nuclear@9: { nuclear@8: if(vol) { nuclear@9: if(vol->tex_vol) { nuclear@8: glDeleteTextures(1, &vol->tex_vol); nuclear@9: } nuclear@8: free(vol); nuclear@8: } nuclear@9: } nuclear@9: nuclear@9: struct vec4 { float x, y, z, w; }; nuclear@9: nuclear@9: static void calc_gradients(float *voxels, int xsz, int ysz, int zsz) nuclear@9: { nuclear@9: int x, y, z, slice_pixels = xsz * ysz; nuclear@9: struct vec4 *vptr = (struct vec4*)voxels; nuclear@9: nuclear@9: for(z=0; z 0 ? (vptr - 1)->w : vptr->w; nuclear@9: y0 = y > 0 ? (vptr - xsz)->w : vptr->w; nuclear@9: z0 = z > 0 ? (vptr - slice_pixels)->w : vptr->w; nuclear@9: x1 = x < xsz - 1 ? (vptr + 1)->w : vptr->w; nuclear@9: y1 = y < ysz - 1 ? (vptr + xsz)->w : vptr->w; nuclear@9: z1 = z < zsz - 1 ? (vptr + slice_pixels)->w : vptr->w; nuclear@9: nuclear@9: vptr->x = x1 - x0; nuclear@9: vptr->y = y1 - y0; nuclear@9: vptr->z = z1 - z0; nuclear@9: nuclear@9: vptr++; nuclear@9: } nuclear@9: } nuclear@9: } nuclear@8: } nuclear@8: nuclear@8: static struct slice *read_voldesc(const char *fname, struct volume *vol) nuclear@8: { nuclear@8: FILE *fp = 0; nuclear@9: char buf[512], *slash, *prefix = ""; nuclear@8: int mode_slices = 0; nuclear@8: struct slice *head = 0, *tail; nuclear@8: nuclear@8: if(!(fp = fopen(fname, "r"))) { nuclear@8: fprintf(stderr, "failed to open volume descriptor: %s\n", fname); nuclear@8: return 0; nuclear@8: } nuclear@8: fgets(buf, sizeof buf, fp); nuclear@8: if(strstr(buf, "VOLDESC") != buf) { nuclear@8: fprintf(stderr, "invalid file format while trying to read volume descriptor: %s\n", fname); nuclear@8: goto err; nuclear@8: } nuclear@8: nuclear@9: if((slash = strrchr(fname, '/'))) { nuclear@9: int len = slash - fname + 1; nuclear@9: prefix = alloca(len + 1); nuclear@9: memcpy(prefix, fname, len); nuclear@9: prefix[len] = 0; nuclear@9: } nuclear@9: nuclear@8: while(fgets(buf, sizeof buf, fp)) { nuclear@8: char *line = trim(buf); nuclear@8: nuclear@8: if(!*line || *line == '#') nuclear@8: continue; nuclear@8: nuclear@8: if(mode_slices) { nuclear@8: /* we're in the part that contains filenames... append to the list */ nuclear@8: struct slice *node = malloc(sizeof *node); nuclear@9: if(!node || !(node->name = malloc(strlen(prefix) + strlen(line) + 1))) { nuclear@8: perror("failed to allocate list node"); nuclear@8: free(node); nuclear@8: goto err; nuclear@8: } nuclear@9: sprintf(node->name, "%s%s", prefix, line); nuclear@8: node->next = 0; nuclear@8: nuclear@8: if(head) { nuclear@8: tail->next = node; nuclear@8: tail = node; nuclear@8: } else { nuclear@8: head = tail = node; nuclear@8: } nuclear@8: vol->sz[2]++; nuclear@8: } else { nuclear@8: /* TODO we're in the options part... parse */ nuclear@9: nuclear@9: if(strcmp(line, "SLICES") == 0) { nuclear@9: mode_slices = 1; nuclear@9: } nuclear@8: } nuclear@8: } nuclear@8: fclose(fp); nuclear@8: nuclear@8: if(!vol->sz[2]) { nuclear@8: fprintf(stderr, "file: %s contains no slices\n", fname); nuclear@8: goto err; nuclear@8: } nuclear@8: nuclear@8: return head; nuclear@8: nuclear@8: err: nuclear@8: while(head) { nuclear@8: struct slice *tmp = head; nuclear@8: head = head->next; nuclear@8: free(tmp->name); nuclear@8: free(tmp); nuclear@8: } nuclear@8: if(fp) { nuclear@8: fclose(fp); nuclear@8: } nuclear@8: return 0; nuclear@8: } nuclear@8: nuclear@8: static char *trim(char *str) nuclear@8: { nuclear@8: char *tmp = str + strlen(str) - 1; nuclear@8: nuclear@8: while(isspace(*tmp)) nuclear@8: tmp--; nuclear@8: tmp[1] = 0; nuclear@8: nuclear@8: tmp = str; nuclear@8: while(isspace(*tmp)) nuclear@8: tmp++; nuclear@8: return tmp; nuclear@8: }