1 /*
2  * vp_file.c
3  *
4  * Routines for loading and storing volume data in disk files.
5  *
6  * Copyright (c) 1994 The Board of Trustees of The Leland Stanford
7  * Junior University.  All rights reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation for any purpose is hereby granted without fee, provided
11  * that the above copyright notice and this permission notice appear in
12  * all copies of this software and that you do not sell the software.
13  * Commercial licensing is available by contacting the author.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * Author:
20  *    Phil Lacroute
21  *    Computer Systems Laboratory
22  *    Electrical Engineering Dept.
23  *    Stanford University
24  */
25 
26 /*
27  * $Date: 1994/12/30 23:52:38 $
28  * $Revision: 1.26 $
29  */
30 
31 #include "vp_global.h"
32 
33 static int StoreRLEVoxels ANSI_ARGS((vpContext *vpc, int fd,
34     RLEVoxels *rle_voxels));
35 static int LoadRLEVoxels ANSI_ARGS((vpContext *vpc, int fd,
36     RLEVoxels *rle_voxels, int offsets, int swab));
37 static void SwapWords ANSI_ARGS((void *data, unsigned size));
38 static void SwapVoxels ANSI_ARGS((vpContext *vpc, void *voxels,
39     int num_voxels, int fields, int bytes_per_voxel));
40 #ifdef DEBUG
41 void VPCheckScanOffsets ANSI_ARGS((RLEVoxels *rle_voxels,
42     int rle_bytes_per_voxel));
43 #endif
44 static void SwapOctreeNode ANSI_ARGS((vpContext *vpc, int level, void *node));
45 static int StoreTable ANSI_ARGS((vpContext *vpc, int fd, float *ptr,
46     unsigned size));
47 static int LoadTable ANSI_ARGS((vpContext *vpc, int fd, float **ptr_ptr,
48     unsigned *size_ptr));
49 
50 /*******************************************************************
51  * Classified Volume Files.                                        *
52  *******************************************************************/
53 
54 /* file header structure */
55 typedef struct {
56     unsigned magic;		/* magic number for identification */
57     unsigned xlen;		/* voxels in each dimension */
58     unsigned ylen;
59     unsigned zlen;
60     unsigned bytes_per_voxel;	/* size of a classified voxel */
61     unsigned num_shade_fields;	/* number of fields in a classified voxel
62 				   (not including opacity) */
63     unsigned num_x_runs;	/* number of run lengths for X view */
64     unsigned num_x_voxels;	/* number of nonzero voxels for X view */
65     unsigned num_x_offsets;	/* number of offsets per slice for X view */
66     unsigned num_y_runs;	/* number of run lengths for Y view */
67     unsigned num_y_voxels;	/* number of nonzero voxels for Y view */
68     unsigned num_y_offsets;	/* number of offsets per slice for Y view */
69     unsigned num_z_runs;	/* number of run lengths for Z view */
70     unsigned num_z_voxels;	/* number of nonzero voxels for Z view */
71     unsigned num_z_offsets;	/* number of offsets per slice for Z view */
72     float min_opacity;		/* low opacity threshold */
73 } RLEVoxelHdr;
74 
75 /*
76  * File layout:
77  *   RLEVoxelHdr hdr;
78  *   unsigned field_size[hdr.num_shade_fields];	   (size of each voxel field)
79  *   unsigned field_offset[hdr.num_shade_fields];  (offset for each field)
80  *   unsigned field_max[hdr.num_shade_fields];     (max. value of each field)
81  *   padding to align to double word
82  *   unsigned char x_run_lengths[hdr.num_x_runs];  (run lengths for X view)
83  *   padding to align to double word
84  *   char x_data[hdr.num_x_voxels*hdr.bytes_per_voxel]; (voxel data for X view)
85  *   padding to align to double word
86  *   ScanOffset x_offsets[hdr.num_x_offsets];	   (scanline offset for X view)
87  *   padding to align to double word
88  *   unsigned char y_run_lengths[hdr.num_y_runs];  (run lengths for Y view)
89  *   padding to align to double word
90  *   char y_data[hdr.num_y_voxels*hdr.bytes_per_voxel]; (voxel data for Y view)
91  *   padding to align to double word
92  *   ScanOffset y_offsets[hdr.num_y_offsets];	   (scanline offset for Y view)
93  *   padding to align to double word
94  *   unsigned char z_run_lengths[hdr.num_z_runs];  (run lengths for Z view)
95  *   padding to align to double word
96  *   char z_data[hdr.num_z_voxels*hdr.bytes_per_voxel]; (voxel data for Z view)
97  *   padding to align to double word
98  *   ScanOffset z_offsets[hdr.num_z_offsets];	   (scanline offset for Z view)
99  *
100  * The padding ensures that voxel data can be mapped into memory
101  * without any word alignment problems.
102  */
103 
104 /*
105  * vpStoreClassifiedVolume
106  *
107  * Store a run-length encoded, classified volume to a file.
108  */
109 
110 vpResult
vpStoreClassifiedVolume(vpc,fd)111 vpStoreClassifiedVolume(vpc, fd)
112 vpContext *vpc;	/* context containing the volume */
113 int fd;		/* UNIX file descriptor open for writing */
114 {
115     RLEVoxelHdr header;
116     unsigned field_data[3*VP_MAX_FIELDS];
117     int nsf, c;
118     unsigned size;
119     char pad_data[8];
120     int pad_bytes;
121     int retcode;
122 
123     /* check for errors */
124     if ((retcode = VPCheckVoxelFields(vpc)) != VP_OK)
125 	return(retcode);
126 
127     /* write header */
128     header.magic = VP_CVFILE_MAGIC;
129     header.xlen = vpc->xlen;
130     header.ylen = vpc->ylen;
131     header.zlen = vpc->zlen;
132     header.bytes_per_voxel = vpc->rle_bytes_per_voxel;
133     header.num_shade_fields = vpc->num_shade_fields;
134     if (vpc->rle_x == NULL) {
135 	header.num_x_runs = 0;
136 	header.num_x_voxels = 0;
137 	header.num_x_offsets = 0;
138     } else {
139 	if ((retcode = VPCheckClassifiedVolume(vpc, VP_X_AXIS)) != VP_OK)
140 	    return(retcode);
141 	header.num_x_runs = vpc->rle_x->run_count;
142 	header.num_x_voxels = vpc->rle_x->data_count;
143 	header.num_x_offsets = vpc->rle_x->scan_offsets_per_slice;
144     }
145     if (vpc->rle_y == NULL) {
146 	header.num_y_runs = 0;
147 	header.num_y_voxels = 0;
148 	header.num_y_offsets = 0;
149     } else {
150 	if ((retcode = VPCheckClassifiedVolume(vpc, VP_Y_AXIS)) != VP_OK)
151 	    return(retcode);
152 	header.num_y_runs = vpc->rle_y->run_count;
153 	header.num_y_voxels = vpc->rle_y->data_count;
154 	header.num_y_offsets = vpc->rle_y->scan_offsets_per_slice;
155     }
156     if (vpc->rle_z == NULL) {
157 	header.num_z_runs = 0;
158 	header.num_z_voxels = 0;
159 	header.num_z_offsets = 0;
160     } else {
161 	if ((retcode = VPCheckClassifiedVolume(vpc, VP_Z_AXIS)) != VP_OK)
162 	    return(retcode);
163 	header.num_z_runs = vpc->rle_z->run_count;
164 	header.num_z_voxels = vpc->rle_z->data_count;
165 	header.num_z_offsets = vpc->rle_z->scan_offsets_per_slice;
166     }
167     header.min_opacity = vpc->min_opacity;
168     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
169 	return(VPSetError(vpc, VPERROR_IO));
170 
171     /* write voxel layout information */
172     nsf = vpc->num_shade_fields;
173     for (c = 0; c < nsf; c++) {
174 	field_data[c] = vpc->field_size[c];
175 	field_data[nsf + c] = vpc->field_offset[c];
176 	field_data[2*nsf + c] = vpc->field_max[c];
177     }
178     size = 3*nsf*sizeof(unsigned);
179     if (vpc->write_func(fd, field_data, size) != size)
180 	return(VPSetError(vpc, VPERROR_IO));
181 
182     /* padding after header */
183     pad_bytes = (8 - ((sizeof(header) + size) % 8)) & 0x7;
184     if (pad_bytes > 0) {
185 	bzero(pad_data, pad_bytes);
186 	if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
187 	    return(VPSetError(vpc, VPERROR_IO));
188     }
189 
190     /* write data */
191     if (vpc->rle_x != NULL) {
192 	if ((c = StoreRLEVoxels(vpc, fd, vpc->rle_x)) != VP_OK)
193 	    return(c);
194     }
195     if (vpc->rle_y != NULL) {
196 	if ((c = StoreRLEVoxels(vpc, fd, vpc->rle_y)) != VP_OK)
197 	    return(c);
198     }
199     if (vpc->rle_z != NULL) {
200 	if ((c = StoreRLEVoxels(vpc, fd, vpc->rle_z)) != VP_OK)
201 	    return(c);
202     }
203 
204     return(VP_OK);
205 }
206 
207 /*
208  * StoreRLEVoxels
209  *
210  * Write an RLEVoxels structure to a file.
211  */
212 
213 static int
StoreRLEVoxels(vpc,fd,rle_voxels)214 StoreRLEVoxels(vpc, fd, rle_voxels)
215 vpContext *vpc;
216 int fd;
217 RLEVoxels *rle_voxels;
218 {
219     int size;
220     char pad_data[8];
221     int pad_bytes;
222 
223     bzero(pad_data, sizeof(pad_data));
224     if (rle_voxels->run_count > 0) {
225 	size = rle_voxels->run_count;
226 	if (vpc->write_func(fd, rle_voxels->run_lengths, size) != size)
227 	    return(VPSetError(vpc, VPERROR_IO));
228 
229 	pad_bytes = (8 - (size % 8)) & 0x7;
230 	if (pad_bytes > 0) {
231 	    if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
232 		return(VPSetError(vpc, VPERROR_IO));
233 	}
234     }
235     if (rle_voxels->data_count > 0) {
236 	size = rle_voxels->data_count * vpc->rle_bytes_per_voxel;
237 	if (vpc->write_func(fd, rle_voxels->data, size) != size)
238 	    return(VPSetError(vpc, VPERROR_IO));
239 
240 	pad_bytes = (8 - (size % 8)) & 0x7;
241 	if (pad_bytes > 0) {
242 	    if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
243 		return(VPSetError(vpc, VPERROR_IO));
244 	}
245     }
246     if (rle_voxels->scan_offsets_per_slice > 0) {
247 	size = rle_voxels->scan_offsets_per_slice * rle_voxels->klen *
248 	    sizeof(ScanOffset);
249 	if (vpc->write_func(fd, rle_voxels->scan_offsets, size) != size)
250 	    return(VPSetError(vpc, VPERROR_IO));
251 
252 	pad_bytes = (8 - (size % 8)) & 0x7;
253 	if (pad_bytes > 0) {
254 	    if (vpc->write_func(fd, pad_data, pad_bytes) != pad_bytes)
255 		return(VPSetError(vpc, VPERROR_IO));
256 	}
257     }
258     return(VP_OK);
259 }
260 
261 /*
262  * vpLoadClassifiedVolume
263  *
264  * Load a run-length encoded, classified volume from a file.
265  */
266 
267 vpResult
vpLoadClassifiedVolume(vpc,fd)268 vpLoadClassifiedVolume(vpc, fd)
269 vpContext *vpc;	/* context to store the volume into */
270 int fd;		/* UNIX file descriptor open for reading */
271 {
272     RLEVoxelHdr header;
273     unsigned field_data[3*VP_MAX_FIELDS];
274     int nsf, c, swab;
275     unsigned size;
276     unsigned char *data;
277     char pad_data[8];
278     int pad_bytes;
279     unsigned x_run_offset;
280     unsigned x_data_offset;
281     unsigned x_offset_offset;
282     unsigned y_run_offset;
283     unsigned y_data_offset;
284     unsigned y_offset_offset;
285     unsigned z_run_offset;
286     unsigned z_data_offset;
287     unsigned z_offset_offset;
288     int current_offset;
289     int destroy_old_volume;
290 
291     /* read header */
292     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
293 	return(VPSetError(vpc, VPERROR_IO));
294     swab = 0;
295     if (header.magic != VP_CVFILE_MAGIC) {
296 	SwapWords(&header, sizeof(header));
297 	if (header.magic != VP_CVFILE_MAGIC)
298 	    return(VPSetError(vpc, VPERROR_BAD_FILE));
299 	swab = 1;
300     }
301 
302     /* read voxel layout information */
303     size = 3 * header.num_shade_fields * sizeof(unsigned);
304     if (vpc->read_func(fd, field_data, size) != size)
305 	return(VPSetError(vpc, VPERROR_IO));
306     if (swab)
307 	SwapWords(field_data, size);
308 
309     /* padding after header */
310     pad_bytes = (8 - ((sizeof(header) + size) % 8)) & 0x7;
311     if (pad_bytes > 0) {
312 	if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
313 	    return(VPSetError(vpc, VPERROR_IO));
314     }
315 
316     /* check for consistency with old volume data */
317     destroy_old_volume = 0;
318     if (vpc->xlen != header.xlen || vpc->ylen != header.ylen ||
319 	vpc->zlen != header.zlen ||
320 	vpc->raw_bytes_per_voxel < header.bytes_per_voxel ||
321 	vpc->num_voxel_fields < header.num_shade_fields)
322 	destroy_old_volume = 1;
323     nsf = header.num_shade_fields;
324     for (c = 0; c < nsf; c++) {
325 	if (vpc->field_size[c] != field_data[c] ||
326 	    vpc->field_offset[c] != field_data[nsf + c] ||
327 	    vpc->field_max[c] != field_data[2*nsf + c])
328 	    destroy_old_volume = 1;
329     }
330     if (destroy_old_volume) {
331 	vpDestroyClassifiedVolume(vpc);
332 	vpDestroyMinMaxOctree(vpc);
333 	vpc->raw_voxels = NULL;
334 	vpc->raw_voxels_size = 0;
335 	vpc->xstride = 0;
336 	vpc->ystride = 0;
337 	vpc->zstride = 0;
338     }
339 
340     /* load new volume size */
341     if (destroy_old_volume) {
342 	vpc->xlen = header.xlen;
343 	vpc->ylen = header.ylen;
344 	vpc->zlen = header.zlen;
345 	vpc->raw_bytes_per_voxel = header.bytes_per_voxel;
346 	nsf = header.num_shade_fields;
347 	vpc->num_voxel_fields = nsf;
348 	for (c = 0; c < nsf; c++) {
349 	    vpc->field_size[c] = field_data[c];
350 	    vpc->field_offset[c] = field_data[nsf + c];
351 	    vpc->field_max[c] = field_data[2*nsf + c];
352 	}
353     }
354     vpc->num_shade_fields = nsf;
355     vpc->min_opacity = header.min_opacity;
356     vpc->rle_bytes_per_voxel = header.bytes_per_voxel;
357 
358     /* load new volume data */
359     if (vpc->mmap_func != NULL && !swab) {
360 	/* compute file offsets */
361 	current_offset = sizeof(header) + size;
362 	current_offset += (8 - (current_offset % 8)) & 0x7;
363 	x_run_offset = current_offset;
364 	current_offset += header.num_x_runs;
365 	current_offset += (8 - (current_offset % 8)) & 0x7;
366 	x_data_offset = current_offset;
367 	current_offset += header.num_x_voxels * header.bytes_per_voxel;
368 	current_offset += (8 - (current_offset % 8)) & 0x7;
369 	x_offset_offset = current_offset;
370 	current_offset += header.num_x_offsets * sizeof(ScanOffset);
371 	current_offset += (8 - (current_offset % 8)) & 0x7;
372 	y_run_offset = current_offset;
373 	current_offset += header.num_y_runs;
374 	current_offset += (8 - (current_offset % 8)) & 0x7;
375 	y_data_offset = current_offset;
376 	current_offset += header.num_y_voxels * header.bytes_per_voxel;
377 	current_offset += (8 - (current_offset % 8)) & 0x7;
378 	y_offset_offset = current_offset;
379 	current_offset += header.num_y_offsets * sizeof(ScanOffset);
380 	current_offset += (8 - (current_offset % 8)) & 0x7;
381 	z_run_offset = current_offset;
382 	current_offset += header.num_z_runs;
383 	current_offset += (8 - (current_offset % 8)) & 0x7;
384 	z_data_offset = current_offset;
385 	current_offset += header.num_z_voxels * header.bytes_per_voxel;
386 	current_offset += (8 - (current_offset % 8)) & 0x7;
387 	z_offset_offset = current_offset;
388 	current_offset += header.num_z_offsets * sizeof(ScanOffset);
389 
390 	/* memory-map the data */
391 	if ((data = vpc->mmap_func(fd, current_offset,
392 				   vpc->client_data)) == NULL)
393 	    return(VPSetError(vpc, VPERROR_IO));
394 
395 	/* assign pointers to x view data */
396 	vpc->rle_x = VPCreateRLEVoxels(vpc, header.ylen, header.zlen,
397 				       header.xlen, 0, 0, 0);
398 	vpc->rle_x->run_count = header.num_x_runs;
399 	if (header.num_x_runs > 0)
400 	    vpc->rle_x->run_lengths = (unsigned char *)(data + x_run_offset);
401 	vpc->rle_x->data_count = header.num_x_voxels;
402 	if (header.num_x_voxels > 0)
403 	    vpc->rle_x->data = (void *)(data + x_data_offset);
404 	vpc->rle_x->scan_offsets_per_slice = header.num_x_offsets;
405 	if (header.num_x_offsets > 0)
406 	    vpc->rle_x->scan_offsets = (ScanOffset *)(data + x_offset_offset);
407 	vpc->rle_x->mmapped = 1;
408 
409 	/* assign pointers to y view data */
410 	vpc->rle_y = VPCreateRLEVoxels(vpc, header.zlen, header.xlen,
411 				       header.ylen, 0, 0, 0);
412 	vpc->rle_y->run_count = header.num_y_runs;
413 	if (header.num_y_runs > 0)
414 	    vpc->rle_y->run_lengths = (unsigned char *)(data + y_run_offset);
415 	vpc->rle_y->data_count = header.num_y_voxels;
416 	if (header.num_y_voxels > 0)
417 	    vpc->rle_y->data = (void *)(data + y_data_offset);
418 	vpc->rle_y->scan_offsets_per_slice = header.num_y_offsets;
419 	if (header.num_y_offsets > 0)
420 	    vpc->rle_y->scan_offsets = (ScanOffset *)(data + y_offset_offset);
421 	vpc->rle_y->mmapped = 1;
422 
423 	/* assign pointers to z view data */
424 	vpc->rle_z = VPCreateRLEVoxels(vpc, header.xlen, header.ylen,
425 				       header.zlen, 0, 0, 0);
426 	vpc->rle_z->run_count = header.num_z_runs;
427 	if (header.num_z_runs > 0)
428 	    vpc->rle_z->run_lengths = (unsigned char *)(data + z_run_offset);
429 	vpc->rle_z->data_count = header.num_z_voxels;
430 	if (header.num_z_voxels > 0)
431 	    vpc->rle_z->data = (void *)(data + z_data_offset);
432 	vpc->rle_z->scan_offsets_per_slice = header.num_z_offsets;
433 	if (header.num_z_offsets > 0)
434 	    vpc->rle_z->scan_offsets = (ScanOffset *)(data + z_offset_offset);
435 	vpc->rle_z->mmapped = 1;
436     } else {
437 	/* read the x view data into memory */
438 	if (header.num_x_runs != 0) {
439 	    vpc->rle_x = VPCreateRLEVoxels(vpc, header.ylen, header.zlen,
440 		header.xlen, header.num_x_voxels, header.num_x_runs,
441 		header.bytes_per_voxel);
442 	    if ((c = LoadRLEVoxels(vpc, fd, vpc->rle_x, header.num_x_offsets,
443 				   swab)) != VP_OK)
444 		return(c);
445 	}
446 
447 	/* read the y view data into memory */
448 	if (header.num_y_runs != 0) {
449 	    vpc->rle_y = VPCreateRLEVoxels(vpc, header.zlen, header.xlen,
450 		header.ylen, header.num_y_voxels, header.num_y_runs,
451 		header.bytes_per_voxel);
452 	    if ((c = LoadRLEVoxels(vpc, fd, vpc->rle_y, header.num_y_offsets,
453 				   swab)) != VP_OK)
454 		return(c);
455 	}
456 
457 	/* read the z view data into memory */
458 	if (header.num_z_runs != 0) {
459 	    vpc->rle_z = VPCreateRLEVoxels(vpc, header.xlen, header.ylen,
460 		header.zlen, header.num_z_voxels, header.num_z_runs,
461 		header.bytes_per_voxel);
462 	    if ((c = LoadRLEVoxels(vpc, fd, vpc->rle_z, header.num_z_offsets,
463 				   swab)) != VP_OK)
464 		return(c);
465 	}
466     }
467 #ifdef DEBUG
468     if (vpc->rle_x != NULL) {
469 	printf("Checking X scanline offsets....\n");
470 	VPCheckScanOffsets(vpc->rle_x, vpc->rle_bytes_per_voxel);
471     }
472     if (vpc->rle_y != NULL) {
473 	printf("Checking Y scanline offsets....\n");
474 	VPCheckScanOffsets(vpc->rle_y, vpc->rle_bytes_per_voxel);
475     }
476     if (vpc->rle_z != NULL) {
477 	printf("Checking Z scanline offsets....\n");
478 	VPCheckScanOffsets(vpc->rle_z, vpc->rle_bytes_per_voxel);
479     }
480 #endif
481     return(VP_OK);
482 }
483 
484 /*
485  * LoadRLEVoxels
486  *
487  * Load an RLEVoxels structure from a file.
488  */
489 
490 static int
LoadRLEVoxels(vpc,fd,rle_voxels,offsets,swab)491 LoadRLEVoxels(vpc, fd, rle_voxels, offsets, swab)
492 vpContext *vpc;
493 int fd;
494 RLEVoxels *rle_voxels;
495 int offsets;
496 int swab;
497 {
498     int size;
499     char pad_data[8];
500     int pad_bytes;
501 
502     if (rle_voxels->run_count > 0) {
503 	size = rle_voxels->run_count;
504 	if (vpc->read_func(fd, rle_voxels->run_lengths, size) != size)
505 	    return(VPSetError(vpc, VPERROR_IO));
506 
507 	pad_bytes = (8 - (size % 8)) & 0x7;
508 	if (pad_bytes > 0) {
509 	    if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
510 		return(VPSetError(vpc, VPERROR_IO));
511 	}
512     }
513     if (rle_voxels->data_count > 0) {
514 	size = rle_voxels->data_count * vpc->rle_bytes_per_voxel;
515 	if (vpc->read_func(fd, rle_voxels->data, size) != size)
516 	    return(VPSetError(vpc, VPERROR_IO));
517 	if (swab)
518 	    SwapVoxels(vpc, rle_voxels->data, rle_voxels->data_count,
519 		       vpc->num_shade_fields, vpc->rle_bytes_per_voxel);
520 
521 	pad_bytes = (8 - (size % 8)) & 0x7;
522 	if (pad_bytes > 0) {
523 	    if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
524 		return(VPSetError(vpc, VPERROR_IO));
525 	}
526     }
527     if (offsets > 0) {
528 	rle_voxels->scan_offsets_per_slice = offsets;
529 	size = rle_voxels->klen * offsets * sizeof(ScanOffset);
530 	Alloc(vpc, rle_voxels->scan_offsets, ScanOffset *, size,
531 	      "scan_offsets");
532 	if (vpc->read_func(fd, rle_voxels->scan_offsets, size) != size)
533 	    return(VPSetError(vpc, VPERROR_IO));
534 	if (swab)
535 	    SwapWords(rle_voxels->scan_offsets, size);
536 
537 	pad_bytes = (8 - (size % 8)) & 0x7;
538 	if (pad_bytes > 0) {
539 	    if (vpc->read_func(fd, pad_data, pad_bytes) != pad_bytes)
540 		return(VPSetError(vpc, VPERROR_IO));
541 	}
542     }
543     return(VP_OK);
544 }
545 
546 /*
547  * SwapWords
548  *
549  * Byte-swap word data to change the endianess.
550  */
551 
552 static void
SwapWords(data,size)553 SwapWords(data, size)
554 void *data;
555 unsigned size;
556 {
557     unsigned char *ptr;
558     int tmp1, tmp2;
559 
560     ptr = data;
561     while (size >= 4) {
562 	tmp1 = ptr[0]; ptr[0] = ptr[3]; ptr[3] = tmp1;
563 	tmp2 = ptr[1]; ptr[1] = ptr[2]; ptr[2] = tmp2;
564 	size -= 4;
565 	ptr += 4;
566     }
567 }
568 
569 /*
570  * SwapVoxels
571  *
572  * Byte-swap voxel data to change the endianess.
573  */
574 
575 static void
SwapVoxels(vpc,voxels,num_voxels,fields,bytes_per_voxel)576 SwapVoxels(vpc, voxels, num_voxels, fields, bytes_per_voxel)
577 vpContext *vpc;		/* context */
578 void *voxels;		/* array of voxels */
579 int num_voxels;		/* number of voxels in the array */
580 int fields;		/* number of fields in voxel */
581 int bytes_per_voxel;	/* size of voxel in bytes */
582 {
583     int f, size, offset;
584     unsigned char *voxel_ptr;
585     int tmp1, tmp2;
586 
587     /* check if any of the fields of the voxel need swapping */
588     size = 0;
589     for (f = 0; f < fields; f++) {
590 	if (vpc->field_size[f] > size)
591 	    size = vpc->field_size[f];
592     }
593     if (size <= 1)
594 	return;
595 
596     /* do the swapping */
597     voxel_ptr = voxels;
598     while (num_voxels-- > 0) {
599 	for (f = 0; f < fields; f++) {
600 	    size = vpc->field_size[f];
601 	    if (size == 1)
602 		continue;
603 	    offset = vpc->field_offset[f];
604 	    if (size == 2) {
605 		tmp1 = voxel_ptr[offset];
606 		voxel_ptr[offset] = voxel_ptr[offset+1];
607 		voxel_ptr[offset+1] = tmp1;
608 	    } else {
609 		tmp1 = voxel_ptr[offset];
610 		voxel_ptr[offset] = voxel_ptr[offset+3];
611 		voxel_ptr[offset+3] = tmp1;
612 		tmp2 = voxel_ptr[offset+1];
613 		voxel_ptr[offset+1] = voxel_ptr[offset+2];
614 		voxel_ptr[offset+2] = tmp2;
615 	    }
616 	}
617 	voxel_ptr += bytes_per_voxel;
618     }
619 }
620 
621 /*******************************************************************
622  * Min-Max Octree Files.                                           *
623  *******************************************************************/
624 
625 /* file header structure */
626 typedef struct {
627     unsigned magic;		/* magic number for identification */
628     unsigned xlen;		/* voxels in each dimension */
629     unsigned ylen;
630     unsigned zlen;
631     int num_clsfy_params;	/* # of params for classification */
632     int levels;			/* number of levels in octree */
633     int root_node_size;		/* voxels/side for root level */
634     int base_node_size;		/* voxels/side for base level */
635     int range_bytes_per_node;	/* bytes/node for min/max data */
636     int base_bytes_per_node;	/* bytes/node for base level */
637     int nonbase_bytes_per_node; /* bytes/node for non-base level */
638     int status_offset;		/* offset to status field */
639     int child_offset;		/* offset to child field */
640     unsigned octree_bytes;	/* bytes of storage for the octree */
641 } MinMaxOctreeHdr;
642 
643 /*
644  * File layout:
645  *   MinMaxOctreeHdr hdr;
646  *   unsigned param_size[hdr.num_clsfy_params];	(size of each parameter, bytes)
647  *   unsigned param_max[hdr.num_clsfy_params];  (max. value of each parameter)
648  *   unsigned node_offset[hdr.num_clsfy_params];(node offset to min/max data)
649  *   char data[octree_bytes];	(octree data)
650  */
651 
652 /*
653  * vpStoreMinMaxOctree
654  *
655  * Store a min-max octree to a file.
656  */
657 
658 vpResult
vpStoreMinMaxOctree(vpc,fd)659 vpStoreMinMaxOctree(vpc, fd)
660 vpContext *vpc;	/* context containing the octree */
661 int fd;		/* UNIX file descriptor open for writing */
662 {
663     MinMaxOctreeHdr header;
664     unsigned field_data[3*VP_MAX_FIELDS];
665     int ncp, c;
666     unsigned size;
667 
668     if (vpc->mm_octree == NULL)
669 	return(VPSetError(vpc, VPERROR_BAD_SIZE));
670 
671     /* write header */
672     bzero(&header, sizeof(MinMaxOctreeHdr));
673     header.magic = VP_OCTFILE_MAGIC;
674     header.xlen = vpc->xlen;
675     header.ylen = vpc->ylen;
676     header.zlen = vpc->zlen;
677     header.num_clsfy_params = vpc->num_clsfy_params;
678     header.levels = vpc->mm_octree->levels;
679     header.root_node_size = vpc->mm_octree->root_node_size;
680     header.base_node_size = vpc->mm_octree->base_node_size;
681     header.range_bytes_per_node = vpc->mm_octree->range_bytes_per_node;
682     header.base_bytes_per_node = vpc->mm_octree->base_bytes_per_node;
683     header.nonbase_bytes_per_node = vpc->mm_octree->nonbase_bytes_per_node;
684     header.status_offset = vpc->mm_octree->status_offset;
685     header.child_offset = vpc->mm_octree->child_offset;
686     header.octree_bytes = vpc->mm_octree->octree_bytes;
687     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
688 	return(VPSetError(vpc, VPERROR_IO));
689 
690     /* write parameter size/offset information */
691     ncp = vpc->num_clsfy_params;
692     for (c = 0; c < ncp; c++) {
693 	field_data[c] = vpc->field_size[vpc->param_field[c]];
694 	field_data[ncp + c] = vpc->field_max[vpc->param_field[c]];
695 	field_data[2*ncp + c] = vpc->mm_octree->node_offset[c];
696     }
697     size = 3*ncp*sizeof(unsigned);
698     if (vpc->write_func(fd, field_data, size) != size)
699 	return(VPSetError(vpc, VPERROR_IO));
700 
701     /* write octree data */
702     size = vpc->mm_octree->octree_bytes;
703     if (vpc->write_func(fd, vpc->mm_octree->root, size) != size)
704 	return(VPSetError(vpc, VPERROR_IO));
705 
706     return(VP_OK);
707 }
708 
709 /*
710  * vpLoadMinMaxOctree
711  *
712  * Load a min-max octree from a file.
713  */
714 
715 vpResult
vpLoadMinMaxOctree(vpc,fd)716 vpLoadMinMaxOctree(vpc, fd)
717 vpContext *vpc;	/* context to store the octree into */
718 int fd;		/* UNIX file descriptor open for reading */
719 {
720     MinMaxOctreeHdr header;
721     unsigned field_data[3*VP_MAX_FIELDS];
722     int ncp, c, swab;
723     unsigned size;
724 
725     /* read header */
726     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
727 	return(VPSetError(vpc, VPERROR_IO));
728     swab = 0;
729     if (header.magic != VP_OCTFILE_MAGIC) {
730 	SwapWords(&header, sizeof(header));
731 	if (header.magic != VP_OCTFILE_MAGIC)
732 	    return(VPSetError(vpc, VPERROR_BAD_FILE));
733 	swab = 1;
734     }
735 
736     /* read parameter size/offset information */
737     size = 3 * header.num_clsfy_params * sizeof(unsigned);
738     if (vpc->read_func(fd, field_data, size) != size)
739 	return(VPSetError(vpc, VPERROR_IO));
740     if (swab)
741 	SwapWords(field_data, size);
742 
743     /* check for consistency with current volume data */
744     if ((c = VPCheckRawVolume(vpc)) != VP_OK)
745 	return(c);
746     if (header.xlen != vpc->xlen || header.ylen != vpc->ylen ||
747 	header.zlen != vpc->zlen ||
748 	header.num_clsfy_params != vpc->num_clsfy_params)
749 	return(VPSetError(vpc, VPERROR_BAD_VOLUME));
750     ncp = vpc->num_clsfy_params;
751     for (c = 0; c < ncp; c++) {
752 	if (field_data[c] != vpc->field_size[vpc->param_field[c]] ||
753 	    field_data[ncp + c] != vpc->field_max[vpc->param_field[c]])
754 	    return(VPSetError(vpc, VPERROR_BAD_VOXEL));
755     }
756 
757     /* clear old octree */
758     vpDestroyMinMaxOctree(vpc);
759 
760     /* initialize new octree */
761     Alloc(vpc, vpc->mm_octree, MinMaxOctree *, sizeof(MinMaxOctree),
762 	  "MinMaxOctree");
763     bzero(vpc->mm_octree, sizeof(MinMaxOctree));
764     vpc->mm_octree->levels = header.levels;
765     vpc->mm_octree->root_node_size = header.root_node_size;
766     vpc->mm_octree->base_node_size = header.base_node_size;
767     vpc->mm_octree->range_bytes_per_node = header.range_bytes_per_node;
768     vpc->mm_octree->base_bytes_per_node = header.base_bytes_per_node;
769     vpc->mm_octree->nonbase_bytes_per_node = header.nonbase_bytes_per_node;
770     vpc->mm_octree->status_offset = header.status_offset;
771     vpc->mm_octree->child_offset = header.child_offset;
772     vpc->mm_octree->octree_bytes = header.octree_bytes;
773     ncp = header.num_clsfy_params;
774     for (c = 0; c < ncp; c++)
775 	vpc->mm_octree->node_offset[c] = field_data[2*ncp + c];
776 
777     /* load octree data */
778     size = header.octree_bytes;
779     Alloc(vpc, vpc->mm_octree->root, void *, size, "mm_octree");
780     if (vpc->read_func(fd, vpc->mm_octree->root, size) != size)
781 	return(VPSetError(vpc, VPERROR_IO));
782     if (swab)
783 	SwapOctreeNode(vpc, 0, vpc->mm_octree->root);
784 
785     return(VP_OK);
786 }
787 
788 /*
789  * SwapOctreeNode
790  *
791  * Recursive depth-first traversal of an octree to byte-swap each node's
792  * data (in order to switch the endianess).
793  */
794 
795 static void
SwapOctreeNode(vpc,level,node)796 SwapOctreeNode(vpc, level, node)
797 vpContext *vpc;
798 int level;
799 void *node;
800 {
801     int p, field, size, offset, tmp1, tmp2;
802     int child_bytes_per_node;
803     char *node_ptr = node;
804 
805     /* byte swap min-max data */
806     for (p = 0; p < vpc->num_clsfy_params; p++) {
807 	field = vpc->param_field[p];
808 	size = vpc->field_size[field];
809 	if (size != 1) {
810 	    ASSERT(size == 2);
811 	    offset = vpc->mm_octree->node_offset[p];
812 	    tmp1 = node_ptr[offset];
813 	    node_ptr[offset] = node_ptr[offset+1];
814 	    node_ptr[offset+1] = tmp1;
815 	    tmp2 = node_ptr[offset+2];
816 	    node_ptr[offset+2] = node_ptr[offset+3];
817 	    node_ptr[offset+3] = tmp2;
818 	}
819     }
820 
821     /* byte swap child pointer and recurse */
822     if (level != vpc->mm_octree->levels-1) {
823 	offset = vpc->mm_octree->child_offset;
824 	tmp1 = node_ptr[offset];
825 	node_ptr[offset] = node_ptr[offset+3];
826 	node_ptr[offset+3] = tmp1;
827 	tmp2 = node_ptr[offset+1];
828 	node_ptr[offset+1] = node_ptr[offset+2];
829 	node_ptr[offset+2] = tmp2;
830 
831 	ASSERT(IntField(node, offset) != 0);
832 	node_ptr = (char *)vpc->mm_octree->root + IntField(node, offset);
833 	if (level == vpc->mm_octree->levels-2)
834 	    child_bytes_per_node = vpc->mm_octree->base_bytes_per_node;
835 	else
836 	    child_bytes_per_node = vpc->mm_octree->nonbase_bytes_per_node;
837 	SwapOctreeNode(vpc, level+1, node_ptr);
838 	node_ptr += child_bytes_per_node;
839 	SwapOctreeNode(vpc, level+1, node_ptr);
840 	node_ptr += child_bytes_per_node;
841 	SwapOctreeNode(vpc, level+1, node_ptr);
842 	node_ptr += child_bytes_per_node;
843 	SwapOctreeNode(vpc, level+1, node_ptr);
844 	node_ptr += child_bytes_per_node;
845 	SwapOctreeNode(vpc, level+1, node_ptr);
846 	node_ptr += child_bytes_per_node;
847 	SwapOctreeNode(vpc, level+1, node_ptr);
848 	node_ptr += child_bytes_per_node;
849 	SwapOctreeNode(vpc, level+1, node_ptr);
850 	node_ptr += child_bytes_per_node;
851 	SwapOctreeNode(vpc, level+1, node_ptr);
852     }
853 }
854 
855 /*******************************************************************
856  * Raw Volume Files.                                               *
857  *******************************************************************/
858 
859 /* file header structure */
860 typedef struct {
861     unsigned magic;		/* magic number for identification */
862     unsigned xlen;		/* voxels in each dimension */
863     unsigned ylen;
864     unsigned zlen;
865     unsigned bytes_per_voxel;	/* size of a raw voxel */
866     unsigned num_voxel_fields;	/* number of fields in a voxel */
867     unsigned num_shade_fields;	/* number of fields for shading */
868     unsigned num_clsfy_fields;	/* number of fields for classification */
869     int xstride;		/* strides for voxel data */
870     int ystride;
871     int zstride;
872 } RawVoxelHdr;
873 
874 /*
875  * File layout:
876  *   RawVoxelHdr hdr;
877  *   unsigned field_size[hdr.num_shade_fields];	   (size of each voxel field)
878  *   unsigned field_offset[hdr.num_shade_fields];  (offset for each field)
879  *   unsigned field_max[hdr.num_shade_fields];     (max. value of each field)
880  *   char data[hdr.xlen*hdr.ylen*hdr.zlen*hdr.bytes_per_voxel]; (volume data)
881  */
882 
883 /*
884  * vpStoreRawVolume
885  *
886  * Store an unclassified volume to a file.
887  */
888 
889 vpResult
vpStoreRawVolume(vpc,fd)890 vpStoreRawVolume(vpc, fd)
891 vpContext *vpc;	/* context containing the volume */
892 int fd;		/* UNIX file descriptor open for writing */
893 {
894     RawVoxelHdr header;
895     unsigned field_data[3*VP_MAX_FIELDS];
896     int nvf, c;
897     unsigned size;
898     int retcode;
899 
900     /* check for errors */
901     if ((retcode = VPCheckRawVolume(vpc)) != VP_OK)
902 	return(retcode);
903 
904     /* write header */
905     header.magic = VP_RVFILE_MAGIC;
906     header.xlen = vpc->xlen;
907     header.ylen = vpc->ylen;
908     header.zlen = vpc->zlen;
909     header.bytes_per_voxel = vpc->raw_bytes_per_voxel;
910     header.num_voxel_fields = vpc->num_voxel_fields;
911     header.num_shade_fields = vpc->num_shade_fields;
912     header.num_clsfy_fields = vpc->num_clsfy_params;
913     header.xstride = vpc->xstride;
914     header.ystride = vpc->ystride;
915     header.zstride = vpc->zstride;
916     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
917 	return(VPSetError(vpc, VPERROR_IO));
918 
919     /* write voxel layout information */
920     nvf = vpc->num_voxel_fields;
921     for (c = 0; c < nvf; c++) {
922 	field_data[c] = vpc->field_size[c];
923 	field_data[nvf + c] = vpc->field_offset[c];
924 	field_data[2*nvf + c] = vpc->field_max[c];
925     }
926     size = 3*nvf*sizeof(unsigned);
927     if (vpc->write_func(fd, field_data, size) != size)
928 	return(VPSetError(vpc, VPERROR_IO));
929 
930     /* write data */
931     if (vpc->write_func(fd, vpc->raw_voxels, vpc->raw_voxels_size) !=
932 	vpc->raw_voxels_size)
933 	return(VPSetError(vpc, VPERROR_IO));
934 
935     return(VP_OK);
936 }
937 
938 /*
939  * vpLoadRawVolume
940  *
941  * Load an unclassified volume from a file.
942  */
943 
944 vpResult
vpLoadRawVolume(vpc,fd)945 vpLoadRawVolume(vpc, fd)
946 vpContext *vpc;	/* context to store the volume into */
947 int fd;		/* UNIX file descriptor open for reading */
948 {
949     RawVoxelHdr header;
950     unsigned field_data[3*VP_MAX_FIELDS];
951     int nvf, c, swab;
952     unsigned size;
953     unsigned voxel_offset;
954     unsigned char *data;
955     int destroy_old_volume;
956 
957     /* read header */
958     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
959 	return(VPSetError(vpc, VPERROR_IO));
960     swab = 0;
961     if (header.magic != VP_RVFILE_MAGIC) {
962 	SwapWords(&header, sizeof(header));
963 	if (header.magic != VP_RVFILE_MAGIC)
964 	    return(VPSetError(vpc, VPERROR_BAD_FILE));
965 	swab = 1;
966     }
967 
968     /* read voxel layout information */
969     size = 3 * header.num_voxel_fields * sizeof(unsigned);
970     if (vpc->read_func(fd, field_data, size) != size)
971 	return(VPSetError(vpc, VPERROR_IO));
972     if (swab)
973 	SwapWords(field_data, size);
974     voxel_offset = sizeof(header) + size;
975 
976     /* destroy old volume data */
977     vpDestroyClassifiedVolume(vpc);
978     vpDestroyMinMaxOctree(vpc);
979 
980     /* load new volume size */
981     vpc->xlen = header.xlen;
982     vpc->ylen = header.ylen;
983     vpc->zlen = header.zlen;
984     vpc->raw_bytes_per_voxel = header.bytes_per_voxel;
985     vpc->num_voxel_fields = header.num_voxel_fields;
986     vpc->num_shade_fields = header.num_shade_fields;
987     vpc->num_clsfy_params = header.num_clsfy_fields;
988     vpc->xstride = header.xstride;
989     vpc->ystride = header.ystride;
990     vpc->zstride = header.zstride;
991     nvf = header.num_voxel_fields;
992     for (c = 0; c < nvf; c++) {
993 	vpc->field_size[c] = field_data[c];
994 	vpc->field_offset[c] = field_data[nvf + c];
995 	vpc->field_max[c] = field_data[2*nvf + c];
996     }
997 
998     /* load new volume data */
999     size = vpc->xlen*vpc->ylen*vpc->zlen*vpc->raw_bytes_per_voxel;
1000     vpc->raw_voxels_size = size;
1001     if (vpc->mmap_func != NULL && !swab) {
1002 	if ((vpc->raw_voxels = vpc->mmap_func(fd, voxel_offset,
1003 					      vpc->client_data)) == NULL)
1004 	    return(VPSetError(vpc, VPERROR_IO));
1005     } else {
1006 	Alloc(vpc, vpc->raw_voxels, void *, size, "raw_voxels");
1007 	if (vpc->read_func(fd, vpc->raw_voxels, size) != size)
1008 	    return(VPSetError(vpc, VPERROR_IO));
1009 	if (swab) {
1010 	    SwapVoxels(vpc, vpc->raw_voxels, vpc->xlen*vpc->ylen*vpc->zlen,
1011 		       vpc->num_voxel_fields, vpc->raw_bytes_per_voxel);
1012 	}
1013     }
1014 
1015     return(VP_OK);
1016 }
1017 
1018 /*******************************************************************
1019  * Rendering Context Dump Files.                                   *
1020  *******************************************************************/
1021 
1022 /* file header structure */
1023 typedef struct {
1024     unsigned magic;		/* magic number for identification */
1025     unsigned major_version;	/* major version number */
1026     unsigned minor_version;	/* minor version number */
1027     unsigned max_fields;	/* value of VP_MAX_FIELDS */
1028     unsigned max_material;	/* value of VP_MAX_MATERIAL */
1029     unsigned max_lights;	/* value of VP_MAX_LIGHTS */
1030 } VpcHdr;
1031 
1032 /*
1033  * File layout:
1034  *   VpcHdr hdr;
1035  *   vpContext vpc; --> truncated just before "end_of_parameters" field
1036  *   unsigned shade_color_table_size;
1037  *   float shade_color_table[shade_color_table_size];
1038  *   unsigned shade_weight_table_size;
1039  *   float shade_weight_table[shade_weight_table_size];
1040  *   for i = 1 to vpc.num_clsfy_params:
1041  *       int clsfy_table_size;
1042  *       float clsfy_table[clsfy_table_size];
1043  */
1044 
1045 /*
1046  * vpStoreContext
1047  *
1048  * Store the contents of a volpack context to a file.  All state parameters
1049  * stored directly in the vpContext structure are stored.  User-supplied
1050  * lookup tables are also stored.  Volume data and octrees are not stored
1051  * (use the routines specifically for storing those data structures), and
1052  * internal tables that can be computed from other state variables
1053  * (e.g. depth cueing lookup table) are not stored.
1054  */
1055 
1056 vpResult
vpStoreContext(vpc,fd)1057 vpStoreContext(vpc, fd)
1058 vpContext *vpc;
1059 int fd;
1060 {
1061     VpcHdr header;
1062     int i;
1063     unsigned vpc_size;
1064 
1065     header.magic = VP_VPCFILE_MAGIC;
1066     header.major_version = VP_MAJOR_VERSION;
1067     header.minor_version = VP_MINOR_VERSION;
1068     header.max_fields = VP_MAX_FIELDS;
1069     header.max_material = VP_MAX_MATERIAL;
1070     header.max_lights = VP_MAX_LIGHTS;
1071     vpc_size = vpFieldOffset(vpc, end_of_parameters);
1072     if (vpc->write_func(fd, &header, sizeof(header)) != sizeof(header))
1073 	return(VPSetError(vpc, VPERROR_IO));
1074     if (vpc->write_func(fd, vpc, vpc_size) != vpc_size)
1075 	return(VPSetError(vpc, VPERROR_IO));
1076     if (!StoreTable(vpc, fd, vpc->shade_color_table,
1077 		    vpc->shade_color_table_size))
1078 	return(VPSetError(vpc, VPERROR_IO));
1079     if (!StoreTable(vpc, fd, vpc->shade_weight_table,
1080 		    vpc->shade_weight_table_size))
1081 	return(VPSetError(vpc, VPERROR_IO));
1082     for (i = 0; i < vpc->num_clsfy_params; i++) {
1083 	if (!StoreTable(vpc, fd, vpc->clsfy_table[i],
1084 			vpc->clsfy_table_size[i]))
1085 	    return(VPSetError(vpc, VPERROR_IO));
1086     }
1087     return(VP_OK);
1088 }
1089 
1090 /*
1091  * StoreTable
1092  *
1093  * Store a table to a file and check for errors.  Return value is 1 for
1094  * success, 0 for failure.
1095  */
1096 
1097 static int
StoreTable(vpc,fd,ptr,size)1098 StoreTable(vpc, fd, ptr, size)
1099 vpContext *vpc;
1100 int fd;
1101 float *ptr;
1102 unsigned size;
1103 {
1104     if (size == 0 || ptr == NULL) {
1105 	size = 0;
1106 	if (vpc->write_func(fd, &size, sizeof(size)) != sizeof(size))
1107 	    return(0);
1108     } else {
1109 	if (vpc->write_func(fd, &size, sizeof(size)) != sizeof(size))
1110 	    return(0);
1111 	if (vpc->write_func(fd, ptr, size) != size)
1112 	    return(0);
1113     }
1114     return(1);
1115 }
1116 
1117 /*
1118  * vpLoadContext
1119  *
1120  * Load a volpack context from a file.  The old contents of the context are
1121  * destroyed, including any volume data.  Lookup tables for shading and
1122  * classification that are loaded from the file are stored in newly-allocated
1123  * memory, but the application is responsible for freeing the tables;
1124  * existing tables in the context are not overwritten (since there is no
1125  * way for the application to predict the right table sizes), and the new
1126  * tables are not freed when vpDestroyContext is called (since volpack
1127  * normally does not manage the tables).  Byte swapping is not performed.
1128  */
1129 
1130 vpResult
vpLoadContext(vpc,fd)1131 vpLoadContext(vpc, fd)
1132 vpContext *vpc;
1133 int fd;
1134 {
1135     VpcHdr header;
1136     int swab, i;
1137     unsigned vpc_size;
1138 
1139     /* read header */
1140     if (vpc->read_func(fd, &header, sizeof(header)) != sizeof(header))
1141 	return(VPSetError(vpc, VPERROR_IO));
1142     swab = 0;
1143     if (header.magic != VP_VPCFILE_MAGIC)
1144 	return(VPSetError(vpc, VPERROR_BAD_FILE));
1145     if (header.major_version != VP_MAJOR_VERSION ||
1146 	header.minor_version != VP_MINOR_VERSION ||
1147 	header.max_fields != VP_MAX_FIELDS ||
1148 	header.max_material != VP_MAX_MATERIAL ||
1149 	header.max_lights != VP_MAX_LIGHTS) {
1150 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
1151     }
1152 
1153     /* destroy old data structures */
1154     vpDestroyMinMaxOctree(vpc);
1155     vpDestroyClassifiedVolume(vpc);
1156 
1157     /* load new context */
1158     vpc_size = vpFieldOffset(vpc, end_of_parameters);
1159     if (vpc->read_func(fd, vpc, vpc_size) != vpc_size)
1160 	return(VPSetError(vpc, VPERROR_IO));
1161     vpc->raw_voxels = NULL;
1162     for (i = 0; i < VP_MAX_FIELDS; i++)
1163 	vpc->clsfy_table[i] = NULL;
1164     vpc->shade_color_table = NULL;
1165     vpc->shade_weight_table = NULL;
1166     vpc->image = NULL;
1167     if (vpc->shade_func == NULL)
1168 	vpc->shading_mode = LOOKUP_SHADER;
1169     if (!LoadTable(vpc, fd, &vpc->shade_color_table,
1170 		   (unsigned *)&vpc->shade_color_table_size))
1171 	goto failed;
1172     if (!LoadTable(vpc, fd, &vpc->shade_weight_table,
1173 		   (unsigned *)&vpc->shade_weight_table_size))
1174 	goto failed;
1175     for (i = 0; i < vpc->num_clsfy_params; i++) {
1176 	if (!LoadTable(vpc, fd, &vpc->clsfy_table[i],
1177 		       (unsigned *)&vpc->clsfy_table_size[i]))
1178 	    goto failed;
1179     }
1180     return(VP_OK);
1181 
1182  failed:
1183     if (vpc->shade_color_table != NULL) {
1184 	Dealloc(vpc, vpc->shade_color_table);
1185 	vpc->shade_color_table = NULL;
1186     }
1187     if (vpc->shade_weight_table != NULL) {
1188 	Dealloc(vpc, vpc->shade_weight_table);
1189 	vpc->shade_weight_table = NULL;
1190     }
1191     for (i = 0; i < vpc->num_clsfy_params; i++) {
1192 	if (vpc->clsfy_table[i] != NULL) {
1193 	    Dealloc(vpc, vpc->clsfy_table[i]);
1194 	    vpc->clsfy_table[i] = NULL;
1195 	}
1196     }
1197     return(VPSetError(vpc, VPERROR_IO));
1198 }
1199 
1200 /*
1201  * LoadTable
1202  *
1203  * Load a table from a file and check for errors.  Return value is 1 for
1204  * success, 0 for failure.
1205  */
1206 
1207 static int
LoadTable(vpc,fd,ptr_ptr,size_ptr)1208 LoadTable(vpc, fd, ptr_ptr, size_ptr)
1209 vpContext *vpc;
1210 int fd;
1211 float **ptr_ptr;
1212 unsigned *size_ptr;
1213 {
1214     if (vpc->read_func(fd, size_ptr, sizeof(unsigned)) != sizeof(unsigned))
1215 	return(0);
1216     if (*size_ptr != 0) {
1217 	Alloc(vpc, *ptr_ptr, void *, *size_ptr, "lookup table");
1218 	if (vpc->read_func(fd, *ptr_ptr, *size_ptr) != *size_ptr)
1219 	    return(0);
1220     }
1221     return(1);
1222 }
1223