Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

vp_file.c

Go to the documentation of this file.
00001 /*
00002  * vp_file.c
00003  *
00004  * Routines for loading and storing volume data in disk files.
00005  *
00006  * Copyright (c) 1994 The Board of Trustees of The Leland Stanford
00007  * Junior University.  All rights reserved.
00008  *
00009  * Permission to use, copy, modify and distribute this software and its
00010  * documentation for any purpose is hereby granted without fee, provided
00011  * that the above copyright notice and this permission notice appear in
00012  * all copies of this software and that you do not sell the software.
00013  * Commercial licensing is available by contacting the author.
00014  * 
00015  * THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
00016  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
00017  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00018  *
00019  * Author:
00020  *    Phil Lacroute
00021  *    Computer Systems Laboratory
00022  *    Electrical Engineering Dept.
00023  *    Stanford University
00024  */
00025 
00026 /*
00027  * $Date: 2001/12/17 16:16:22 $
00028  * $Revision: 1.1 $
00029  */
00030 
00031 #include "vp_global.h"
00032 
00033 static int StoreRLEVoxels ANSI_ARGS((vpContext *vpc, int fd,
00034     RLEVoxels *rle_voxels));
00035 static int LoadRLEVoxels ANSI_ARGS((vpContext *vpc, int fd,
00036     RLEVoxels *rle_voxels, int offsets, int swab));
00037 static void SwapWords ANSI_ARGS((void *data, unsigned size));
00038 static void SwapVoxels ANSI_ARGS((vpContext *vpc, void *voxels,
00039     int num_voxels, int fields, int bytes_per_voxel));
00040 #ifdef DEBUG
00041 void VPCheckScanOffsets ANSI_ARGS((RLEVoxels *rle_voxels,
00042     int rle_bytes_per_voxel));
00043 #endif
00044 static void SwapOctreeNode ANSI_ARGS((vpContext *vpc, int level, void *node));
00045 static int StoreTable ANSI_ARGS((vpContext *vpc, int fd, float *ptr,
00046     unsigned size));
00047 static int LoadTable ANSI_ARGS((vpContext *vpc, int fd, float **ptr_ptr,
00048     unsigned *size_ptr));
00049 
00050 /*******************************************************************
00051  * Classified Volume Files.                                        *
00052  *******************************************************************/
00053 
00054 /* file header structure */
00055 typedef struct {
00056     unsigned magic;             /* magic number for identification */
00057     unsigned xlen;              /* voxels in each dimension */
00058     unsigned ylen;
00059     unsigned zlen;
00060     unsigned bytes_per_voxel;   /* size of a classified voxel */
00061     unsigned num_shade_fields;  /* number of fields in a classified voxel
00062                                    (not including opacity) */
00063     unsigned num_x_runs;        /* number of run lengths for X view */
00064     unsigned num_x_voxels;      /* number of nonzero voxels for X view */
00065     unsigned num_x_offsets;     /* number of offsets per slice for X view */
00066     unsigned num_y_runs;        /* number of run lengths for Y view */
00067     unsigned num_y_voxels;      /* number of nonzero voxels for Y view */
00068     unsigned num_y_offsets;     /* number of offsets per slice for Y view */
00069     unsigned num_z_runs;        /* number of run lengths for Z view */
00070     unsigned num_z_voxels;      /* number of nonzero voxels for Z view */
00071     unsigned num_z_offsets;     /* number of offsets per slice for Z view */
00072     float min_opacity;          /* low opacity threshold */
00073 } RLEVoxelHdr;
00074 
00075 /*
00076  * File layout:
00077  *   RLEVoxelHdr hdr;
00078  *   unsigned field_size[hdr.num_shade_fields];    (size of each voxel field)
00079  *   unsigned field_offset[hdr.num_shade_fields];  (offset for each field)
00080  *   unsigned field_max[hdr.num_shade_fields];     (max. value of each field)
00081  *   padding to align to double word
00082  *   unsigned char x_run_lengths[hdr.num_x_runs];  (run lengths for X view)
00083  *   padding to align to double word
00084  *   char x_data[hdr.num_x_voxels*hdr.bytes_per_voxel]; (voxel data for X view)
00085  *   padding to align to double word
00086  *   ScanOffset x_offsets[hdr.num_x_offsets];      (scanline offset for X view)
00087  *   padding to align to double word
00088  *   unsigned char y_run_lengths[hdr.num_y_runs];  (run lengths for Y view)
00089  *   padding to align to double word
00090  *   char y_data[hdr.num_y_voxels*hdr.bytes_per_voxel]; (voxel data for Y view)
00091  *   padding to align to double word
00092  *   ScanOffset y_offsets[hdr.num_y_offsets];      (scanline offset for Y view)
00093  *   padding to align to double word
00094  *   unsigned char z_run_lengths[hdr.num_z_runs];  (run lengths for Z view)
00095  *   padding to align to double word
00096  *   char z_data[hdr.num_z_voxels*hdr.bytes_per_voxel]; (voxel data for Z view)
00097  *   padding to align to double word
00098  *   ScanOffset z_offsets[hdr.num_z_offsets];      (scanline offset for Z view)
00099  *
00100  * The padding ensures that voxel data can be mapped into memory
00101  * without any word alignment problems.
00102  */
00103 
00104 /*
00105  * vpStoreClassifiedVolume
00106  *
00107  * Store a run-length encoded, classified volume to a file.
00108  */
00109 
00110 vpResult
00111 vpStoreClassifiedVolume(vpc, fd)
00112 vpContext *vpc; /* context containing the volume */
00113 int fd;         /* UNIX file descriptor open for writing */
00114 {
00115     RLEVoxelHdr header;
00116     unsigned field_data[3*VP_MAX_FIELDS];
00117     int nsf, c;
00118     unsigned size;
00119     char pad_data[8];
00120     int pad_bytes;
00121     int retcode;
00122 
00123     /* check for errors */
00124     if ((retcode = VPCheckVoxelFields(vpc)) != VP_OK)
00125         return(retcode);
00126 
00127     /* write header */
00128     header.magic = VP_CVFILE_MAGIC;
00129     header.xlen = vpc->xlen;
00130     header.ylen = vpc->ylen;
00131     header.zlen = vpc->zlen;
00132     header.bytes_per_voxel = vpc->rle_bytes_per_voxel;
00133     header.num_shade_fields = vpc->num_shade_fields;
00134     if (vpc->rle_x == NULL) {
00135         header.num_x_runs = 0;
00136         header.num_x_voxels = 0;
00137         header.num_x_offsets = 0;
00138     } else {
00139         if ((retcode = VPCheckClassifiedVolume(vpc, VP_X_AXIS)) != VP_OK)
00140             return(retcode);
00141         header.num_x_runs = vpc->rle_x->run_count;
00142         header.num_x_voxels = vpc->rle_x->data_count;
00143         header.num_x_offsets = vpc->rle_x->scan_offsets_per_slice;
00144     }
00145     if (vpc->rle_y == NULL) {
00146         header.num_y_runs = 0;
00147         header.num_y_voxels = 0;
00148         header.num_y_offsets = 0;
00149     } else {
00150         if ((retcode = VPCheckClassifiedVolume(vpc, VP_Y_AXIS)) != VP_OK)
00151             return(retcode);
00152         header.num_y_runs = vpc->rle_y->run_count;
00153         header.num_y_voxels = vpc->rle_y->data_count;
00154         header.num_y_offsets = vpc->rle_y->scan_offsets_per_slice;
00155     }
00156     if (vpc->rle_z == NULL) {
00157         header.num_z_runs = 0;
00158         header.num_z_voxels = 0;
00159         header.num_z_offsets = 0;
00160     } else {
00161         if ((retcode = VPCheckClassifiedVolume(vpc, VP_Z_AXIS)) != VP_OK)
00162             return(retcode);
00163         header.num_z_runs = vpc->rle_z->run_count;
00164         header.num_z_voxels = vpc->rle_z->data_count;
00165         header.num_z_offsets = vpc->rle_z->scan_offsets_per_slice;
00166     }
00167     header.min_opacity = vpc->min_opacity;
00168     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
00169         return(VPSetError(vpc, VPERROR_IO));
00170 
00171     /* write voxel layout information */
00172     nsf = vpc->num_shade_fields;
00173     for (c = 0; c < nsf; c++) {
00174         field_data[c] = vpc->field_size[c];
00175         field_data[nsf + c] = vpc->field_offset[c];
00176         field_data[2*nsf + c] = vpc->field_max[c];
00177     }
00178     size = 3*nsf*sizeof(unsigned);
00179     if (vpc->write_func(fd, field_data, size) != size)
00180         return(VPSetError(vpc, VPERROR_IO));
00181 
00182     /* padding after header */
00183     pad_bytes = (8 - ((sizeof(header) + size) % 8)) & 0x7;
00184     if (pad_bytes > 0) {
00185         bzero(pad_data, pad_bytes);
00186         if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
00187             return(VPSetError(vpc, VPERROR_IO));
00188     }
00189 
00190     /* write data */
00191     if (vpc->rle_x != NULL) {
00192         if ((c = StoreRLEVoxels(vpc, fd, vpc->rle_x)) != VP_OK)
00193             return(c);
00194     }
00195     if (vpc->rle_y != NULL) {
00196         if ((c = StoreRLEVoxels(vpc, fd, vpc->rle_y)) != VP_OK)
00197             return(c);
00198     }
00199     if (vpc->rle_z != NULL) {
00200         if ((c = StoreRLEVoxels(vpc, fd, vpc->rle_z)) != VP_OK)
00201             return(c);
00202     }
00203 
00204     return(VP_OK);
00205 }
00206 
00207 /*
00208  * StoreRLEVoxels
00209  *
00210  * Write an RLEVoxels structure to a file.
00211  */
00212 
00213 static int
00214 StoreRLEVoxels(vpc, fd, rle_voxels)
00215 vpContext *vpc;
00216 int fd;
00217 RLEVoxels *rle_voxels;
00218 {
00219     int size;
00220     char pad_data[8];
00221     int pad_bytes;
00222 
00223     bzero(pad_data, sizeof(pad_data));
00224     if (rle_voxels->run_count > 0) {
00225         size = rle_voxels->run_count;
00226         if (vpc->write_func(fd, rle_voxels->run_lengths, size) != size)
00227             return(VPSetError(vpc, VPERROR_IO));
00228 
00229         pad_bytes = (8 - (size % 8)) & 0x7;
00230         if (pad_bytes > 0) {
00231             if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
00232                 return(VPSetError(vpc, VPERROR_IO));
00233         }
00234     }
00235     if (rle_voxels->data_count > 0) {
00236         size = rle_voxels->data_count * vpc->rle_bytes_per_voxel;
00237         if (vpc->write_func(fd, rle_voxels->data, size) != size)
00238             return(VPSetError(vpc, VPERROR_IO));
00239 
00240         pad_bytes = (8 - (size % 8)) & 0x7;
00241         if (pad_bytes > 0) {
00242             if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
00243                 return(VPSetError(vpc, VPERROR_IO));
00244         }
00245     }
00246     if (rle_voxels->scan_offsets_per_slice > 0) {
00247         size = rle_voxels->scan_offsets_per_slice * rle_voxels->klen *
00248             sizeof(ScanOffset);
00249         if (vpc->write_func(fd, rle_voxels->scan_offsets, size) != size)
00250             return(VPSetError(vpc, VPERROR_IO));
00251 
00252         pad_bytes = (8 - (size % 8)) & 0x7;
00253         if (pad_bytes > 0) {
00254             if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
00255                 return(VPSetError(vpc, VPERROR_IO));
00256         }
00257     }
00258     return(VP_OK);
00259 }
00260 
00261 /*
00262  * vpLoadClassifiedVolume
00263  *
00264  * Load a run-length encoded, classified volume from a file.
00265  */
00266 
00267 vpResult
00268 vpLoadClassifiedVolume(vpc, fd)
00269 vpContext *vpc; /* context to store the volume into */
00270 int fd;         /* UNIX file descriptor open for reading */
00271 {
00272     RLEVoxelHdr header;
00273     unsigned field_data[3*VP_MAX_FIELDS];
00274     int nsf, c, swab;
00275     unsigned size;
00276     unsigned char *data;
00277     char pad_data[8];
00278     int pad_bytes;
00279     unsigned x_run_offset;
00280     unsigned x_data_offset;
00281     unsigned x_offset_offset;
00282     unsigned y_run_offset;
00283     unsigned y_data_offset;
00284     unsigned y_offset_offset;
00285     unsigned z_run_offset;
00286     unsigned z_data_offset;
00287     unsigned z_offset_offset;
00288     int current_offset;
00289     int destroy_old_volume;
00290 
00291     /* read header */
00292     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
00293         return(VPSetError(vpc, VPERROR_IO));
00294     swab = 0;
00295     if (header.magic != VP_CVFILE_MAGIC) {
00296         SwapWords(&header, sizeof(header));
00297         if (header.magic != VP_CVFILE_MAGIC)
00298             return(VPSetError(vpc, VPERROR_BAD_FILE));
00299         swab = 1;
00300     }
00301 
00302     /* read voxel layout information */
00303     size = 3 * header.num_shade_fields * sizeof(unsigned);
00304     if (vpc->read_func(fd, field_data, size) != size)
00305         return(VPSetError(vpc, VPERROR_IO));
00306     if (swab)
00307         SwapWords(field_data, size);
00308 
00309     /* padding after header */
00310     pad_bytes = (8 - ((sizeof(header) + size) % 8)) & 0x7;
00311     if (pad_bytes > 0) {
00312         if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
00313             return(VPSetError(vpc, VPERROR_IO));
00314     }
00315 
00316     /* check for consistency with old volume data */
00317     destroy_old_volume = 0;
00318     if (vpc->xlen != header.xlen || vpc->ylen != header.ylen ||
00319         vpc->zlen != header.zlen ||
00320         vpc->raw_bytes_per_voxel < header.bytes_per_voxel ||
00321         vpc->num_voxel_fields < header.num_shade_fields)
00322         destroy_old_volume = 1;
00323     nsf = header.num_shade_fields;
00324     for (c = 0; c < nsf; c++) {
00325         if (vpc->field_size[c] != field_data[c] ||
00326             vpc->field_offset[c] != field_data[nsf + c] ||
00327             vpc->field_max[c] != field_data[2*nsf + c])
00328             destroy_old_volume = 1;
00329     }
00330     if (destroy_old_volume) {
00331         vpDestroyClassifiedVolume(vpc);
00332         vpDestroyMinMaxOctree(vpc);
00333         vpc->raw_voxels = NULL;
00334         vpc->raw_voxels_size = 0;
00335         vpc->xstride = 0;
00336         vpc->ystride = 0;
00337         vpc->zstride = 0;
00338     }
00339 
00340     /* load new volume size */
00341     if (destroy_old_volume) {
00342         vpc->xlen = header.xlen;
00343         vpc->ylen = header.ylen;
00344         vpc->zlen = header.zlen;
00345         vpc->raw_bytes_per_voxel = header.bytes_per_voxel;
00346         nsf = header.num_shade_fields;
00347         vpc->num_voxel_fields = nsf;
00348         for (c = 0; c < nsf; c++) {
00349             vpc->field_size[c] = field_data[c];
00350             vpc->field_offset[c] = field_data[nsf + c];
00351             vpc->field_max[c] = field_data[2*nsf + c];
00352         }
00353     }
00354     vpc->num_shade_fields = nsf;
00355     vpc->min_opacity = header.min_opacity;
00356     vpc->rle_bytes_per_voxel = header.bytes_per_voxel;
00357 
00358     /* load new volume data */
00359     if (vpc->mmap_func != NULL && !swab) {
00360         /* compute file offsets */
00361         current_offset = sizeof(header) + size;
00362         current_offset += (8 - (current_offset % 8)) & 0x7;
00363         x_run_offset = current_offset;
00364         current_offset += header.num_x_runs;
00365         current_offset += (8 - (current_offset % 8)) & 0x7;
00366         x_data_offset = current_offset;
00367         current_offset += header.num_x_voxels * header.bytes_per_voxel;
00368         current_offset += (8 - (current_offset % 8)) & 0x7;
00369         x_offset_offset = current_offset;
00370         current_offset += header.num_x_offsets * sizeof(ScanOffset);
00371         current_offset += (8 - (current_offset % 8)) & 0x7;
00372         y_run_offset = current_offset;
00373         current_offset += header.num_y_runs;
00374         current_offset += (8 - (current_offset % 8)) & 0x7;
00375         y_data_offset = current_offset;
00376         current_offset += header.num_y_voxels * header.bytes_per_voxel;
00377         current_offset += (8 - (current_offset % 8)) & 0x7;
00378         y_offset_offset = current_offset;
00379         current_offset += header.num_y_offsets * sizeof(ScanOffset);
00380         current_offset += (8 - (current_offset % 8)) & 0x7;
00381         z_run_offset = current_offset;
00382         current_offset += header.num_z_runs;
00383         current_offset += (8 - (current_offset % 8)) & 0x7;
00384         z_data_offset = current_offset;
00385         current_offset += header.num_z_voxels * header.bytes_per_voxel;
00386         current_offset += (8 - (current_offset % 8)) & 0x7;
00387         z_offset_offset = current_offset;
00388         current_offset += header.num_z_offsets * sizeof(ScanOffset);
00389 
00390         /* memory-map the data */
00391         if ((data = vpc->mmap_func(fd, current_offset,
00392                                    vpc->client_data)) == NULL)
00393             return(VPSetError(vpc, VPERROR_IO));
00394 
00395         /* assign pointers to x view data */
00396         vpc->rle_x = VPCreateRLEVoxels(vpc, header.ylen, header.zlen,
00397                                        header.xlen, 0, 0, 0);
00398         vpc->rle_x->run_count = header.num_x_runs;
00399         if (header.num_x_runs > 0)
00400             vpc->rle_x->run_lengths = (unsigned char *)(data + x_run_offset);
00401         vpc->rle_x->data_count = header.num_x_voxels;
00402         if (header.num_x_voxels > 0)
00403             vpc->rle_x->data = (void *)(data + x_data_offset);
00404         vpc->rle_x->scan_offsets_per_slice = header.num_x_offsets;
00405         if (header.num_x_offsets > 0)
00406             vpc->rle_x->scan_offsets = (ScanOffset *)(data + x_offset_offset);
00407         vpc->rle_x->mmapped = 1;
00408 
00409         /* assign pointers to y view data */
00410         vpc->rle_y = VPCreateRLEVoxels(vpc, header.zlen, header.xlen,
00411                                        header.ylen, 0, 0, 0);
00412         vpc->rle_y->run_count = header.num_y_runs;
00413         if (header.num_y_runs > 0)
00414             vpc->rle_y->run_lengths = (unsigned char *)(data + y_run_offset);
00415         vpc->rle_y->data_count = header.num_y_voxels;
00416         if (header.num_y_voxels > 0)
00417             vpc->rle_y->data = (void *)(data + y_data_offset);
00418         vpc->rle_y->scan_offsets_per_slice = header.num_y_offsets;
00419         if (header.num_y_offsets > 0)
00420             vpc->rle_y->scan_offsets = (ScanOffset *)(data + y_offset_offset);
00421         vpc->rle_y->mmapped = 1;
00422 
00423         /* assign pointers to z view data */
00424         vpc->rle_z = VPCreateRLEVoxels(vpc, header.xlen, header.ylen,
00425                                        header.zlen, 0, 0, 0);
00426         vpc->rle_z->run_count = header.num_z_runs;
00427         if (header.num_z_runs > 0)
00428             vpc->rle_z->run_lengths = (unsigned char *)(data + z_run_offset);
00429         vpc->rle_z->data_count = header.num_z_voxels;
00430         if (header.num_z_voxels > 0)
00431             vpc->rle_z->data = (void *)(data + z_data_offset);
00432         vpc->rle_z->scan_offsets_per_slice = header.num_z_offsets;
00433         if (header.num_z_offsets > 0)
00434             vpc->rle_z->scan_offsets = (ScanOffset *)(data + z_offset_offset);
00435         vpc->rle_z->mmapped = 1;
00436     } else {
00437         /* read the x view data into memory */
00438         if (header.num_x_runs != 0) {
00439             vpc->rle_x = VPCreateRLEVoxels(vpc, header.ylen, header.zlen,
00440                 header.xlen, header.num_x_voxels, header.num_x_runs,
00441                 header.bytes_per_voxel);
00442             if ((c = LoadRLEVoxels(vpc, fd, vpc->rle_x, header.num_x_offsets,
00443                                    swab)) != VP_OK)
00444                 return(c);
00445         }
00446 
00447         /* read the y view data into memory */
00448         if (header.num_y_runs != 0) {
00449             vpc->rle_y = VPCreateRLEVoxels(vpc, header.zlen, header.xlen,
00450                 header.ylen, header.num_y_voxels, header.num_y_runs,
00451                 header.bytes_per_voxel);
00452             if ((c = LoadRLEVoxels(vpc, fd, vpc->rle_y, header.num_y_offsets,
00453                                    swab)) != VP_OK)
00454                 return(c);
00455         }
00456 
00457         /* read the z view data into memory */
00458         if (header.num_z_runs != 0) {
00459             vpc->rle_z = VPCreateRLEVoxels(vpc, header.xlen, header.ylen,
00460                 header.zlen, header.num_z_voxels, header.num_z_runs,
00461                 header.bytes_per_voxel);
00462             if ((c = LoadRLEVoxels(vpc, fd, vpc->rle_z, header.num_z_offsets,
00463                                    swab)) != VP_OK)
00464                 return(c);
00465         }
00466     }
00467 #ifdef DEBUG
00468     if (vpc->rle_x != NULL) {
00469         printf("Checking X scanline offsets....\n");
00470         VPCheckScanOffsets(vpc->rle_x, vpc->rle_bytes_per_voxel);
00471     }
00472     if (vpc->rle_y != NULL) {
00473         printf("Checking Y scanline offsets....\n");
00474         VPCheckScanOffsets(vpc->rle_y, vpc->rle_bytes_per_voxel);
00475     }
00476     if (vpc->rle_z != NULL) {
00477         printf("Checking Z scanline offsets....\n");
00478         VPCheckScanOffsets(vpc->rle_z, vpc->rle_bytes_per_voxel);
00479     }
00480 #endif
00481     return(VP_OK);
00482 }
00483 
00484 /*
00485  * LoadRLEVoxels
00486  *
00487  * Load an RLEVoxels structure from a file.
00488  */
00489 
00490 static int
00491 LoadRLEVoxels(vpc, fd, rle_voxels, offsets, swab)
00492 vpContext *vpc;
00493 int fd;
00494 RLEVoxels *rle_voxels;
00495 int offsets;
00496 int swab;
00497 {
00498     int size;
00499     char pad_data[8];
00500     int pad_bytes;
00501 
00502     if (rle_voxels->run_count > 0) {
00503         size = rle_voxels->run_count;
00504         if (vpc->read_func(fd, rle_voxels->run_lengths, size) != size)
00505             return(VPSetError(vpc, VPERROR_IO));
00506 
00507         pad_bytes = (8 - (size % 8)) & 0x7;
00508         if (pad_bytes > 0) {
00509             if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
00510                 return(VPSetError(vpc, VPERROR_IO));
00511         }
00512     }
00513     if (rle_voxels->data_count > 0) {
00514         size = rle_voxels->data_count * vpc->rle_bytes_per_voxel;
00515         if (vpc->read_func(fd, rle_voxels->data, size) != size)
00516             return(VPSetError(vpc, VPERROR_IO));
00517         if (swab)
00518             SwapVoxels(vpc, rle_voxels->data, rle_voxels->data_count,
00519                        vpc->num_shade_fields, vpc->rle_bytes_per_voxel);
00520 
00521         pad_bytes = (8 - (size % 8)) & 0x7;
00522         if (pad_bytes > 0) {
00523             if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
00524                 return(VPSetError(vpc, VPERROR_IO));
00525         }
00526     }
00527     if (offsets > 0) {
00528         rle_voxels->scan_offsets_per_slice = offsets;
00529         size = rle_voxels->klen * offsets * sizeof(ScanOffset);
00530         Alloc(vpc, rle_voxels->scan_offsets, ScanOffset *, size,
00531               "scan_offsets");
00532         if (vpc->read_func(fd, rle_voxels->scan_offsets, size) != size)
00533             return(VPSetError(vpc, VPERROR_IO));
00534         if (swab)
00535             SwapWords(rle_voxels->scan_offsets, size);
00536 
00537         pad_bytes = (8 - (size % 8)) & 0x7;
00538         if (pad_bytes > 0) {
00539             if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
00540                 return(VPSetError(vpc, VPERROR_IO));
00541         }
00542     }
00543     return(VP_OK);
00544 }
00545 
00546 /*
00547  * SwapWords
00548  *
00549  * Byte-swap word data to change the endianess.
00550  */
00551 
00552 static void
00553 SwapWords(data, size)
00554 void *data;
00555 unsigned size;
00556 {
00557     unsigned char *ptr;
00558     int tmp1, tmp2;
00559 
00560     ptr = data;
00561     while (size >= 4) {
00562         tmp1 = ptr[0]; ptr[0] = ptr[3]; ptr[3] = tmp1;
00563         tmp2 = ptr[1]; ptr[1] = ptr[2]; ptr[2] = tmp2;
00564         size -= 4;
00565         ptr += 4;
00566     }
00567 }
00568 
00569 /*
00570  * SwapVoxels
00571  *
00572  * Byte-swap voxel data to change the endianess.
00573  */
00574 
00575 static void
00576 SwapVoxels(vpc, voxels, num_voxels, fields, bytes_per_voxel)
00577 vpContext *vpc;         /* context */
00578 void *voxels;           /* array of voxels */
00579 int num_voxels;         /* number of voxels in the array */
00580 int fields;             /* number of fields in voxel */
00581 int bytes_per_voxel;    /* size of voxel in bytes */
00582 {
00583     int f, size, offset;
00584     unsigned char *voxel_ptr;
00585     int tmp1, tmp2;
00586 
00587     /* check if any of the fields of the voxel need swapping */
00588     size = 0;
00589     for (f = 0; f < fields; f++) {
00590         if (vpc->field_size[f] > size)
00591             size = vpc->field_size[f];
00592     }
00593     if (size <= 1)
00594         return;
00595 
00596     /* do the swapping */
00597     voxel_ptr = voxels;
00598     while (num_voxels-- > 0) {
00599         for (f = 0; f < fields; f++) {
00600             size = vpc->field_size[f];
00601             if (size == 1)
00602                 continue;
00603             offset = vpc->field_offset[f];
00604             if (size == 2) {
00605                 tmp1 = voxel_ptr[offset];
00606                 voxel_ptr[offset] = voxel_ptr[offset+1];
00607                 voxel_ptr[offset+1] = tmp1;
00608             } else {
00609                 tmp1 = voxel_ptr[offset];
00610                 voxel_ptr[offset] = voxel_ptr[offset+3];
00611                 voxel_ptr[offset+3] = tmp1;
00612                 tmp2 = voxel_ptr[offset+1];
00613                 voxel_ptr[offset+1] = voxel_ptr[offset+2];
00614                 voxel_ptr[offset+2] = tmp2;
00615             }
00616         }
00617         voxel_ptr += bytes_per_voxel;
00618     }
00619 }
00620 
00621 /*******************************************************************
00622  * Min-Max Octree Files.                                           *
00623  *******************************************************************/
00624 
00625 /* file header structure */
00626 typedef struct {
00627     unsigned magic;             /* magic number for identification */
00628     unsigned xlen;              /* voxels in each dimension */
00629     unsigned ylen;
00630     unsigned zlen;
00631     int num_clsfy_params;       /* # of params for classification */
00632     int levels;                 /* number of levels in octree */
00633     int root_node_size;         /* voxels/side for root level */
00634     int base_node_size;         /* voxels/side for base level */
00635     int range_bytes_per_node;   /* bytes/node for min/max data */
00636     int base_bytes_per_node;    /* bytes/node for base level */
00637     int nonbase_bytes_per_node; /* bytes/node for non-base level */
00638     int status_offset;          /* offset to status field */
00639     int child_offset;           /* offset to child field */
00640     unsigned octree_bytes;      /* bytes of storage for the octree */
00641 } MinMaxOctreeHdr;
00642 
00643 /*
00644  * File layout:
00645  *   MinMaxOctreeHdr hdr;
00646  *   unsigned param_size[hdr.num_clsfy_params]; (size of each parameter, bytes)
00647  *   unsigned param_max[hdr.num_clsfy_params];  (max. value of each parameter)
00648  *   unsigned node_offset[hdr.num_clsfy_params];(node offset to min/max data)
00649  *   char data[octree_bytes];   (octree data)
00650  */
00651 
00652 /*
00653  * vpStoreMinMaxOctree
00654  *
00655  * Store a min-max octree to a file.
00656  */
00657 
00658 vpResult
00659 vpStoreMinMaxOctree(vpc, fd)
00660 vpContext *vpc; /* context containing the octree */
00661 int fd;         /* UNIX file descriptor open for writing */
00662 {
00663     MinMaxOctreeHdr header;
00664     unsigned field_data[3*VP_MAX_FIELDS];
00665     int ncp, c;
00666     unsigned size;
00667 
00668     if (vpc->mm_octree == NULL)
00669         return(VPSetError(vpc, VPERROR_BAD_SIZE));
00670 
00671     /* write header */
00672     bzero(&header, sizeof(MinMaxOctreeHdr));
00673     header.magic = VP_OCTFILE_MAGIC;
00674     header.xlen = vpc->xlen;
00675     header.ylen = vpc->ylen;
00676     header.zlen = vpc->zlen;
00677     header.num_clsfy_params = vpc->num_clsfy_params;
00678     header.levels = vpc->mm_octree->levels;
00679     header.root_node_size = vpc->mm_octree->root_node_size;
00680     header.base_node_size = vpc->mm_octree->base_node_size;
00681     header.range_bytes_per_node = vpc->mm_octree->range_bytes_per_node;
00682     header.base_bytes_per_node = vpc->mm_octree->base_bytes_per_node;
00683     header.nonbase_bytes_per_node = vpc->mm_octree->nonbase_bytes_per_node;
00684     header.status_offset = vpc->mm_octree->status_offset;
00685     header.child_offset = vpc->mm_octree->child_offset;
00686     header.octree_bytes = vpc->mm_octree->octree_bytes;
00687     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
00688         return(VPSetError(vpc, VPERROR_IO));
00689 
00690     /* write parameter size/offset information */
00691     ncp = vpc->num_clsfy_params;
00692     for (c = 0; c < ncp; c++) {
00693         field_data[c] = vpc->field_size[vpc->param_field[c]];
00694         field_data[ncp + c] = vpc->field_max[vpc->param_field[c]];
00695         field_data[2*ncp + c] = vpc->mm_octree->node_offset[c];
00696     }
00697     size = 3*ncp*sizeof(unsigned);
00698     if (vpc->write_func(fd, field_data, size) != size)
00699         return(VPSetError(vpc, VPERROR_IO));
00700 
00701     /* write octree data */
00702     size = vpc->mm_octree->octree_bytes;
00703     if (vpc->write_func(fd, vpc->mm_octree->root, size) != size)
00704         return(VPSetError(vpc, VPERROR_IO));
00705 
00706     return(VP_OK);
00707 }
00708 
00709 /*
00710  * vpLoadMinMaxOctree
00711  *
00712  * Load a min-max octree from a file.
00713  */
00714 
00715 vpResult
00716 vpLoadMinMaxOctree(vpc, fd)
00717 vpContext *vpc; /* context to store the octree into */
00718 int fd;         /* UNIX file descriptor open for reading */
00719 {
00720     MinMaxOctreeHdr header;
00721     unsigned field_data[3*VP_MAX_FIELDS];
00722     int ncp, c, swab;
00723     unsigned size;
00724 
00725     /* read header */
00726     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
00727         return(VPSetError(vpc, VPERROR_IO));
00728     swab = 0;
00729     if (header.magic != VP_OCTFILE_MAGIC) {
00730         SwapWords(&header, sizeof(header));
00731         if (header.magic != VP_OCTFILE_MAGIC)
00732             return(VPSetError(vpc, VPERROR_BAD_FILE));
00733         swab = 1;
00734     }
00735 
00736     /* read parameter size/offset information */
00737     size = 3 * header.num_clsfy_params * sizeof(unsigned);
00738     if (vpc->read_func(fd, field_data, size) != size)
00739         return(VPSetError(vpc, VPERROR_IO));
00740     if (swab)
00741         SwapWords(field_data, size);
00742 
00743     /* check for consistency with current volume data */
00744     if ((c = VPCheckRawVolume(vpc)) != VP_OK)
00745         return(c);
00746     if (header.xlen != vpc->xlen || header.ylen != vpc->ylen ||
00747         header.zlen != vpc->zlen ||
00748         header.num_clsfy_params != vpc->num_clsfy_params)
00749         return(VPSetError(vpc, VPERROR_BAD_VOLUME));
00750     ncp = vpc->num_clsfy_params;
00751     for (c = 0; c < ncp; c++) {
00752         if (field_data[c] != vpc->field_size[vpc->param_field[c]] ||
00753             field_data[ncp + c] != vpc->field_max[vpc->param_field[c]])
00754             return(VPSetError(vpc, VPERROR_BAD_VOXEL));
00755     }
00756 
00757     /* clear old octree */
00758     vpDestroyMinMaxOctree(vpc);
00759 
00760     /* initialize new octree */
00761     Alloc(vpc, vpc->mm_octree, MinMaxOctree *, sizeof(MinMaxOctree),
00762           "MinMaxOctree");
00763     bzero(vpc->mm_octree, sizeof(MinMaxOctree));
00764     vpc->mm_octree->levels = header.levels;
00765     vpc->mm_octree->root_node_size = header.root_node_size;
00766     vpc->mm_octree->base_node_size = header.base_node_size;
00767     vpc->mm_octree->range_bytes_per_node = header.range_bytes_per_node;
00768     vpc->mm_octree->base_bytes_per_node = header.base_bytes_per_node;
00769     vpc->mm_octree->nonbase_bytes_per_node = header.nonbase_bytes_per_node;
00770     vpc->mm_octree->status_offset = header.status_offset;
00771     vpc->mm_octree->child_offset = header.child_offset;
00772     vpc->mm_octree->octree_bytes = header.octree_bytes;
00773     ncp = header.num_clsfy_params;
00774     for (c = 0; c < ncp; c++)
00775         vpc->mm_octree->node_offset[c] = field_data[2*ncp + c];
00776 
00777     /* load octree data */
00778     size = header.octree_bytes;
00779     Alloc(vpc, vpc->mm_octree->root, void *, size, "mm_octree");
00780     if (vpc->read_func(fd, vpc->mm_octree->root, size) != size)
00781         return(VPSetError(vpc, VPERROR_IO));
00782     if (swab)
00783         SwapOctreeNode(vpc, 0, vpc->mm_octree->root);
00784 
00785     return(VP_OK);
00786 }
00787 
00788 /*
00789  * SwapOctreeNode
00790  *
00791  * Recursive depth-first traversal of an octree to byte-swap each node's
00792  * data (in order to switch the endianess).
00793  */
00794 
00795 static void
00796 SwapOctreeNode(vpc, level, node)
00797 vpContext *vpc;
00798 int level;
00799 void *node;
00800 {
00801     int p, field, size, offset, tmp1, tmp2;
00802     int child_bytes_per_node;
00803     char *node_ptr = node;
00804 
00805     /* byte swap min-max data */
00806     for (p = 0; p < vpc->num_clsfy_params; p++) {
00807         field = vpc->param_field[p];
00808         size = vpc->field_size[field];
00809         if (size != 1) {
00810             ASSERT(size == 2);
00811             offset = vpc->mm_octree->node_offset[p];
00812             tmp1 = node_ptr[offset];
00813             node_ptr[offset] = node_ptr[offset+1];
00814             node_ptr[offset+1] = tmp1;
00815             tmp2 = node_ptr[offset+2];
00816             node_ptr[offset+2] = node_ptr[offset+3];
00817             node_ptr[offset+3] = tmp2;
00818         }
00819     }
00820 
00821     /* byte swap child pointer and recurse */
00822     if (level != vpc->mm_octree->levels-1) {
00823         offset = vpc->mm_octree->child_offset;
00824         tmp1 = node_ptr[offset];
00825         node_ptr[offset] = node_ptr[offset+3];
00826         node_ptr[offset+3] = tmp1;
00827         tmp2 = node_ptr[offset+1];
00828         node_ptr[offset+1] = node_ptr[offset+2];
00829         node_ptr[offset+2] = tmp2;
00830 
00831         ASSERT(IntField(node, offset) != 0);
00832         node_ptr = (char *)vpc->mm_octree->root + IntField(node, offset);
00833         if (level == vpc->mm_octree->levels-2)
00834             child_bytes_per_node = vpc->mm_octree->base_bytes_per_node;
00835         else
00836             child_bytes_per_node = vpc->mm_octree->nonbase_bytes_per_node;
00837         SwapOctreeNode(vpc, level+1, node_ptr);
00838         node_ptr += child_bytes_per_node;
00839         SwapOctreeNode(vpc, level+1, node_ptr);
00840         node_ptr += child_bytes_per_node;
00841         SwapOctreeNode(vpc, level+1, node_ptr);
00842         node_ptr += child_bytes_per_node;
00843         SwapOctreeNode(vpc, level+1, node_ptr);
00844         node_ptr += child_bytes_per_node;
00845         SwapOctreeNode(vpc, level+1, node_ptr);
00846         node_ptr += child_bytes_per_node;
00847         SwapOctreeNode(vpc, level+1, node_ptr);
00848         node_ptr += child_bytes_per_node;
00849         SwapOctreeNode(vpc, level+1, node_ptr);
00850         node_ptr += child_bytes_per_node;
00851         SwapOctreeNode(vpc, level+1, node_ptr);
00852     }
00853 }
00854 
00855 /*******************************************************************
00856  * Raw Volume Files.                                               *
00857  *******************************************************************/
00858 
00859 /* file header structure */
00860 typedef struct {
00861     unsigned magic;             /* magic number for identification */
00862     unsigned xlen;              /* voxels in each dimension */
00863     unsigned ylen;
00864     unsigned zlen;
00865     unsigned bytes_per_voxel;   /* size of a raw voxel */
00866     unsigned num_voxel_fields;  /* number of fields in a voxel */
00867     unsigned num_shade_fields;  /* number of fields for shading */
00868     unsigned num_clsfy_fields;  /* number of fields for classification */
00869     int xstride;                /* strides for voxel data */
00870     int ystride;
00871     int zstride;
00872 } RawVoxelHdr;
00873 
00874 /*
00875  * File layout:
00876  *   RawVoxelHdr hdr;
00877  *   unsigned field_size[hdr.num_shade_fields];    (size of each voxel field)
00878  *   unsigned field_offset[hdr.num_shade_fields];  (offset for each field)
00879  *   unsigned field_max[hdr.num_shade_fields];     (max. value of each field)
00880  *   char data[hdr.xlen*hdr.ylen*hdr.zlen*hdr.bytes_per_voxel]; (volume data)
00881  */
00882 
00883 /*
00884  * vpStoreRawVolume
00885  *
00886  * Store an unclassified volume to a file.
00887  */
00888 
00889 vpResult
00890 vpStoreRawVolume(vpc, fd)
00891 vpContext *vpc; /* context containing the volume */
00892 int fd;         /* UNIX file descriptor open for writing */
00893 {
00894     RawVoxelHdr header;
00895     unsigned field_data[3*VP_MAX_FIELDS];
00896     int nvf, c;
00897     unsigned size;
00898     int retcode;
00899 
00900     /* check for errors */
00901     if ((retcode = VPCheckRawVolume(vpc)) != VP_OK)
00902         return(retcode);
00903 
00904     /* write header */
00905     header.magic = VP_RVFILE_MAGIC;
00906     header.xlen = vpc->xlen;
00907     header.ylen = vpc->ylen;
00908     header.zlen = vpc->zlen;
00909     header.bytes_per_voxel = vpc->raw_bytes_per_voxel;
00910     header.num_voxel_fields = vpc->num_voxel_fields;
00911     header.num_shade_fields = vpc->num_shade_fields;
00912     header.num_clsfy_fields = vpc->num_clsfy_params;
00913     header.xstride = vpc->xstride;
00914     header.ystride = vpc->ystride;
00915     header.zstride = vpc->zstride;
00916     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
00917         return(VPSetError(vpc, VPERROR_IO));
00918 
00919     /* write voxel layout information */
00920     nvf = vpc->num_voxel_fields;
00921     for (c = 0; c < nvf; c++) {
00922         field_data[c] = vpc->field_size[c];
00923         field_data[nvf + c] = vpc->field_offset[c];
00924         field_data[2*nvf + c] = vpc->field_max[c];
00925     }
00926     size = 3*nvf*sizeof(unsigned);
00927     if (vpc->write_func(fd, field_data, size) != size)
00928         return(VPSetError(vpc, VPERROR_IO));
00929 
00930     /* write data */
00931     if (vpc->write_func(fd, vpc->raw_voxels, vpc->raw_voxels_size) !=
00932         vpc->raw_voxels_size)
00933         return(VPSetError(vpc, VPERROR_IO));
00934 
00935     return(VP_OK);
00936 }
00937 
00938 /*
00939  * vpLoadRawVolume
00940  *
00941  * Load an unclassified volume from a file.
00942  */
00943 
00944 vpResult
00945 vpLoadRawVolume(vpc, fd)
00946 vpContext *vpc; /* context to store the volume into */
00947 int fd;         /* UNIX file descriptor open for reading */
00948 {
00949     RawVoxelHdr header;
00950     unsigned field_data[3*VP_MAX_FIELDS];
00951     int nvf, c, swab;
00952     unsigned size;
00953     unsigned voxel_offset;
00954     unsigned char *data;
00955     int destroy_old_volume;
00956 
00957     /* read header */
00958     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
00959         return(VPSetError(vpc, VPERROR_IO));
00960     swab = 0;
00961     if (header.magic != VP_RVFILE_MAGIC) {
00962         SwapWords(&header, sizeof(header));
00963         if (header.magic != VP_RVFILE_MAGIC)
00964             return(VPSetError(vpc, VPERROR_BAD_FILE));
00965         swab = 1;
00966     }
00967 
00968     /* read voxel layout information */
00969     size = 3 * header.num_voxel_fields * sizeof(unsigned);
00970     if (vpc->read_func(fd, field_data, size) != size)
00971         return(VPSetError(vpc, VPERROR_IO));
00972     if (swab)
00973         SwapWords(field_data, size);
00974     voxel_offset = sizeof(header) + size;
00975 
00976     /* destroy old volume data */
00977     vpDestroyClassifiedVolume(vpc);
00978     vpDestroyMinMaxOctree(vpc);
00979 
00980     /* load new volume size */
00981     vpc->xlen = header.xlen;
00982     vpc->ylen = header.ylen;
00983     vpc->zlen = header.zlen;
00984     vpc->raw_bytes_per_voxel = header.bytes_per_voxel;
00985     vpc->num_voxel_fields = header.num_voxel_fields;
00986     vpc->num_shade_fields = header.num_shade_fields;
00987     vpc->num_clsfy_params = header.num_clsfy_fields;
00988     vpc->xstride = header.xstride;
00989     vpc->ystride = header.ystride;
00990     vpc->zstride = header.zstride;
00991     nvf = header.num_voxel_fields;
00992     for (c = 0; c < nvf; c++) {
00993         vpc->field_size[c] = field_data[c];
00994         vpc->field_offset[c] = field_data[nvf + c];
00995         vpc->field_max[c] = field_data[2*nvf + c];
00996     }
00997 
00998     /* load new volume data */
00999     size = vpc->xlen*vpc->ylen*vpc->zlen*vpc->raw_bytes_per_voxel;
01000     vpc->raw_voxels_size = size;
01001     if (vpc->mmap_func != NULL && !swab) {
01002         if ((vpc->raw_voxels = vpc->mmap_func(fd, voxel_offset,
01003                                               vpc->client_data)) == NULL)
01004             return(VPSetError(vpc, VPERROR_IO));
01005     } else {
01006         Alloc(vpc, vpc->raw_voxels, void *, size, "raw_voxels");
01007         if (vpc->read_func(fd, vpc->raw_voxels, size) != size)
01008             return(VPSetError(vpc, VPERROR_IO));
01009         if (swab) {
01010             SwapVoxels(vpc, vpc->raw_voxels, vpc->xlen*vpc->ylen*vpc->zlen,
01011                        vpc->num_voxel_fields, vpc->raw_bytes_per_voxel);
01012         }
01013     }
01014 
01015     return(VP_OK);
01016 }
01017 
01018 /*******************************************************************
01019  * Rendering Context Dump Files.                                   *
01020  *******************************************************************/
01021 
01022 /* file header structure */
01023 typedef struct {
01024     unsigned magic;             /* magic number for identification */
01025     unsigned major_version;     /* major version number */
01026     unsigned minor_version;     /* minor version number */
01027     unsigned max_fields;        /* value of VP_MAX_FIELDS */
01028     unsigned max_material;      /* value of VP_MAX_MATERIAL */
01029     unsigned max_lights;        /* value of VP_MAX_LIGHTS */
01030 } VpcHdr;
01031 
01032 /*
01033  * File layout:
01034  *   VpcHdr hdr;
01035  *   vpContext vpc; --> truncated just before "end_of_parameters" field
01036  *   unsigned shade_color_table_size;
01037  *   float shade_color_table[shade_color_table_size];
01038  *   unsigned shade_weight_table_size;
01039  *   float shade_weight_table[shade_weight_table_size];
01040  *   for i = 1 to vpc.num_clsfy_params:
01041  *       int clsfy_table_size;
01042  *       float clsfy_table[clsfy_table_size];
01043  */
01044 
01045 /*
01046  * vpStoreContext
01047  *
01048  * Store the contents of a volpack context to a file.  All state parameters
01049  * stored directly in the vpContext structure are stored.  User-supplied
01050  * lookup tables are also stored.  Volume data and octrees are not stored
01051  * (use the routines specifically for storing those data structures), and
01052  * internal tables that can be computed from other state variables
01053  * (e.g. depth cueing lookup table) are not stored.
01054  */
01055 
01056 vpResult
01057 vpStoreContext(vpc, fd)
01058 vpContext *vpc;
01059 int fd;
01060 {
01061     VpcHdr header;
01062     int i;
01063     unsigned vpc_size;
01064 
01065     header.magic = VP_VPCFILE_MAGIC;
01066     header.major_version = VP_MAJOR_VERSION;
01067     header.minor_version = VP_MINOR_VERSION;
01068     header.max_fields = VP_MAX_FIELDS;
01069     header.max_material = VP_MAX_MATERIAL;
01070     header.max_lights = VP_MAX_LIGHTS;
01071     vpc_size = vpFieldOffset(vpc, end_of_parameters);
01072     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
01073         return(VPSetError(vpc, VPERROR_IO));
01074     if (vpc->write_func(fd, vpc, vpc_size) != vpc_size)
01075         return(VPSetError(vpc, VPERROR_IO));
01076     if (!StoreTable(vpc, fd, vpc->shade_color_table,
01077                     vpc->shade_color_table_size))
01078         return(VPSetError(vpc, VPERROR_IO));
01079     if (!StoreTable(vpc, fd, vpc->shade_weight_table,
01080                     vpc->shade_weight_table_size))
01081         return(VPSetError(vpc, VPERROR_IO));
01082     for (i = 0; i < vpc->num_clsfy_params; i++) {
01083         if (!StoreTable(vpc, fd, vpc->clsfy_table[i],
01084                         vpc->clsfy_table_size[i]))
01085             return(VPSetError(vpc, VPERROR_IO));
01086     }
01087     return(VP_OK);
01088 }
01089 
01090 /*
01091  * StoreTable
01092  *
01093  * Store a table to a file and check for errors.  Return value is 1 for
01094  * success, 0 for failure.
01095  */
01096 
01097 static int
01098 StoreTable(vpc, fd, ptr, size)
01099 vpContext *vpc;
01100 int fd;
01101 float *ptr;
01102 unsigned size;
01103 {
01104     if (size == 0 || ptr == NULL) {
01105         size = 0;
01106         if (vpc->write_func(fd, &size, sizeof(size)) != sizeof(size))
01107             return(0);
01108     } else {
01109         if (vpc->write_func(fd, &size, sizeof(size)) != sizeof(size))
01110             return(0);
01111         if (vpc->write_func(fd, ptr, size) != size)
01112             return(0);
01113     }
01114     return(1);
01115 }
01116 
01117 /*
01118  * vpLoadContext
01119  *
01120  * Load a volpack context from a file.  The old contents of the context are
01121  * destroyed, including any volume data.  Lookup tables for shading and
01122  * classification that are loaded from the file are stored in newly-allocated
01123  * memory, but the application is responsible for freeing the tables;
01124  * existing tables in the context are not overwritten (since there is no
01125  * way for the application to predict the right table sizes), and the new
01126  * tables are not freed when vpDestroyContext is called (since volpack
01127  * normally does not manage the tables).  Byte swapping is not performed.
01128  */
01129 
01130 vpResult
01131 vpLoadContext(vpc, fd)
01132 vpContext *vpc;
01133 int fd;
01134 {
01135     VpcHdr header;
01136     int swab, i;
01137     unsigned vpc_size;
01138 
01139     /* read header */
01140     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
01141         return(VPSetError(vpc, VPERROR_IO));
01142     swab = 0;
01143     if (header.magic != VP_VPCFILE_MAGIC)
01144         return(VPSetError(vpc, VPERROR_BAD_FILE));
01145     if (header.major_version != VP_MAJOR_VERSION || 
01146         header.minor_version != VP_MINOR_VERSION ||
01147         header.max_fields != VP_MAX_FIELDS ||
01148         header.max_material != VP_MAX_MATERIAL ||
01149         header.max_lights != VP_MAX_LIGHTS) {
01150         return(VPSetError(vpc, VPERROR_BAD_VALUE));
01151     }
01152 
01153     /* destroy old data structures */
01154     vpDestroyMinMaxOctree(vpc);
01155     vpDestroyClassifiedVolume(vpc);
01156 
01157     /* load new context */
01158     vpc_size = vpFieldOffset(vpc, end_of_parameters);
01159     if (vpc->read_func(fd, vpc, vpc_size) != vpc_size)
01160         return(VPSetError(vpc, VPERROR_IO));
01161     vpc->raw_voxels = NULL;
01162     for (i = 0; i < VP_MAX_FIELDS; i++)
01163         vpc->clsfy_table[i] = NULL;
01164     vpc->shade_color_table = NULL;
01165     vpc->shade_weight_table = NULL;
01166     vpc->image = NULL;
01167     if (vpc->shade_func == NULL)
01168         vpc->shading_mode = LOOKUP_SHADER;
01169     if (!LoadTable(vpc, fd, &vpc->shade_color_table,
01170                    (unsigned *)&vpc->shade_color_table_size))
01171         goto failed;
01172     if (!LoadTable(vpc, fd, &vpc->shade_weight_table,
01173                    (unsigned *)&vpc->shade_weight_table_size))
01174         goto failed;
01175     for (i = 0; i < vpc->num_clsfy_params; i++) {
01176         if (!LoadTable(vpc, fd, &vpc->clsfy_table[i],
01177                        (unsigned *)&vpc->clsfy_table_size[i]))
01178             goto failed;
01179     }
01180     return(VP_OK);
01181 
01182  failed:
01183     if (vpc->shade_color_table != NULL) {
01184         Dealloc(vpc, vpc->shade_color_table);
01185         vpc->shade_color_table = NULL;
01186     }
01187     if (vpc->shade_weight_table != NULL) {
01188         Dealloc(vpc, vpc->shade_weight_table);
01189         vpc->shade_weight_table = NULL;
01190     }
01191     for (i = 0; i < vpc->num_clsfy_params; i++) {
01192         if (vpc->clsfy_table[i] != NULL) {
01193             Dealloc(vpc, vpc->clsfy_table[i]);
01194             vpc->clsfy_table[i] = NULL;
01195         }
01196     }
01197     return(VPSetError(vpc, VPERROR_IO));
01198 }
01199 
01200 /*
01201  * LoadTable
01202  *
01203  * Load a table from a file and check for errors.  Return value is 1 for
01204  * success, 0 for failure.
01205  */
01206 
01207 static int
01208 LoadTable(vpc, fd, ptr_ptr, size_ptr)
01209 vpContext *vpc;
01210 int fd;
01211 float **ptr_ptr;
01212 unsigned *size_ptr;
01213 {
01214     if (vpc->read_func(fd, size_ptr, sizeof(unsigned)) != sizeof(unsigned))
01215         return(0);
01216     if (*size_ptr != 0) {
01217         Alloc(vpc, *ptr_ptr, void *, *size_ptr, "lookup table");
01218         if (vpc->read_func(fd, *ptr_ptr, *size_ptr) != *size_ptr)
01219             return(0);
01220     }
01221     return(1);
01222 }
 

Powered by Plone

This site conforms to the following standards: