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