/*
* vp_rle.c
*
* Routines for run-length encoding classified volume data.
*
* Copyright (c) 1994 The Board of Trustees of The Leland Stanford
* Junior University. All rights reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice and this permission notice appear in
* all copies of this software and that you do not sell the software.
* Commercial licensing is available by contacting the author.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* Author:
* Phil Lacroute
* Computer Systems Laboratory
* Electrical Engineering Dept.
* Stanford University
*/
/*
* $Date: 2001/12/17 16:16:23 $
* $Revision: 1.1 $
*/
#include "vp_global.h"
static void EncodeScanline ANSI_ARGS((vpContext *vpc, void *voxels,
MinMaxOctree *octree, MMOctreeLevel level_stack[VP_MAX_OCTREE_LEVELS]));
static void InitRLE ANSI_ARGS((vpContext *vpc));
static void CacheVoxel ANSI_ARGS((vpContext *vpc, double opacity,
void *rawvoxel));
static void CacheLength ANSI_ARGS((vpContext *vpc, int length));
static void CountNonZeroVoxel ANSI_ARGS((RunData *rundata, int index,
int end_of_scan, vpContext *vpc));
static void RepackClassifiedVolume ANSI_ARGS((vpContext *vpc));
static RLEVoxels *CreateEmptyRLEVoxels ANSI_ARGS((vpContext *vpc,
int ilen, int jlen, int klen));
static RLEVoxels *CreateRLEVoxelsFromRunData ANSI_ARGS((vpContext *vpc,
int ilen, int jlen, int klen, int non_zero_count, RunData *run_data,
int rle_bytes_per_voxel));
static void StoreNonZeroVoxel ANSI_ARGS((void *voxel, int rle_bytes_per_voxel,
void *data, unsigned char *lengths, RunData *rundata, int index));
static void PadScanlines ANSI_ARGS((int ilen, int jlen, int klen,
RunData *run_data, unsigned char *lengths));
static ConstructionBuffer *CreateConstructionBuffer ANSI_ARGS((
vpContext *vpc));
static void DestroyConstructionBuffer ANSI_ARGS((vpContext *vpc,
ConstructionBuffer *cbuf));
static GBuffer *CreateGBuffer ANSI_ARGS((vpContext *vpc));
static void DestroyGBuffer ANSI_ARGS((vpContext *vpc, GBuffer *gbuf));
#ifdef INDEX_VOLUME
static vpResult ComputeIndex ANSI_ARGS((vpContext *vpc,
RLEVoxels *rle_voxels));
#endif
static vpResult ComputeScanOffsets ANSI_ARGS((vpContext *vpc,
RLEVoxels *rle_voxels));
#ifdef DEBUG
static void ValidateRLEVoxels ANSI_ARGS((vpContext *vpc, RLEVoxels *rle,
int istride, int jstride, int kstride, int axis));
#endif
/*
* vpClassifyScalars
*
* Classify an array of scalars and store the result in the classified volume.
*/
vpResult
vpClassifyScalars(vpc, scalar_data, length, scalar_field, grad_field,
norm_field)
vpContext *vpc; /* context */
unsigned char *scalar_data; /* 3D array of scalar data */
int length; /* number of scalars in scalar_data */
int scalar_field; /* voxel field for scalar, or VP_SKIP_FIELD */
int grad_field; /* voxel field for gradient, or VP_SKIP_FIELD */
int norm_field; /* voxel field for normal, or VP_SKIP_FIELD */
{
int xlen, ylen, zlen; /* volume dimensions */
int y, z; /* loop indices */
unsigned char *scalar; /* pointer to current scalar */
int scalar_ystride; /* stride to next scalar scanline */
int scalar_zstride; /* stride to next scalar slice */
char *voxel; /* pointer to current voxel */
unsigned char *s_py, *s_my, *s_pz, *s_mz; /* ptrs to adjacent scans */
int retcode; /* return code from vpScanlineNormals */
void *voxel_scan; /* buffer for storing one scan of raw voxels */
/* check for errors */
xlen = vpc->xlen;
ylen = vpc->ylen;
zlen = vpc->zlen;
if (xlen == 0 || ylen == 0 || zlen == 0 || vpc->raw_bytes_per_voxel == 0)
return(VPSetError(vpc, VPERROR_BAD_VOLUME));
if (xlen * ylen * zlen != length)
return(VPSetError(vpc, VPERROR_BAD_SIZE));
/* initialize */
scalar = scalar_data;
scalar_ystride = xlen;
scalar_zstride = xlen*ylen;
Alloc(vpc, voxel_scan, void *, xlen*vpc->raw_bytes_per_voxel,"voxel_scan");
/* compute volume data */
for (z = 0; z < zlen; z++) {
ReportStatus(vpc, (double)z / (double)zlen);
for (y = 0; y < ylen; y++) {
s_my = (y == 0) ? NULL : scalar - scalar_ystride;
s_py = (y == ylen-1) ? NULL : scalar + scalar_ystride;
s_mz = (z == 0) ? NULL : scalar - scalar_zstride;
s_pz = (z == zlen-1) ? NULL : scalar + scalar_zstride;
voxel = voxel_scan;
retcode = vpScanlineNormals(vpc, xlen, scalar, s_my, s_py,
s_mz, s_pz, voxel, scalar_field,
grad_field, norm_field);
if (retcode != VP_OK) {
Dealloc(vpc, voxel_scan);
return(retcode);
}
retcode = vpClassifyScanline(vpc, voxel_scan);
if (retcode != VP_OK) {
Dealloc(vpc, voxel_scan);
return(retcode);
}
scalar += scalar_ystride;
}
scalar += scalar_zstride - ylen*scalar_ystride;
}
ReportStatus(vpc, 1.0);
Dealloc(vpc, voxel_scan);
return(VP_OK);
}
/*
* vpClassifyVolume
*
* Classify the current raw volume and store the result in the
* classified volume.
*/
vpResult
vpClassifyVolume(vpc)
vpContext *vpc; /* context */
{
int xlen, ylen, zlen; /* volume dimensions */
int y, z; /* loop indices */
char *voxel; /* pointer to current voxel */
int voxel_ystride; /* stride to next voxel scanline */
int voxel_zstride; /* stride to next voxel slice */
int retcode; /* return code */
MinMaxOctree *octree; /* octree for fast classification */
MMOctreeLevel level_stack[VP_MAX_OCTREE_LEVELS]; /* stack for octree */
/* check for errors */
if ((retcode = VPCheckRawVolume(vpc)) != VP_OK)
return(retcode);
if ((retcode = VPCheckClassifier(vpc)) != VP_OK)
return(retcode);
/* initialize */
vpDestroyClassifiedVolume(vpc);
InitRLE(vpc);
xlen = vpc->xlen;
ylen = vpc->ylen;
zlen = vpc->zlen;
voxel = vpc->raw_voxels;
voxel_ystride = vpc->ystride;
voxel_zstride = vpc->zstride;
octree = vpc->mm_octree;
if (octree != NULL) {
VPComputeSummedAreaTable(vpc);
VPClassifyOctree(vpc);
}
/* compute volume data */
for (z = 0; z < zlen; z++) {
ReportStatus(vpc, (double)z / (double)zlen);
if (octree != NULL)
VPInitOctreeLevelStack(vpc, level_stack, VP_Z_AXIS, z);
for (y = 0; y < ylen; y++) {
EncodeScanline(vpc, voxel, octree, level_stack);
voxel += voxel_ystride;
}
voxel += voxel_zstride - ylen*voxel_ystride;
}
ReportStatus(vpc, 1.0);
return(VP_OK);
}
/*
* vpClassifyScanline
*
* Apply the classification function to a scanline of raw voxels and append
* it to the classified volume.
*/
vpResult
vpClassifyScanline(vpc, voxels)
vpContext *vpc; /* context */
void *voxels; /* voxel scanline */
{
int retcode;
/* initialize if this is the first scanline */
if (vpc->cbuf == NULL) {
if ((retcode = VPCheckClassifier(vpc)) != VP_OK)
return(retcode);
vpDestroyClassifiedVolume(vpc);
InitRLE(vpc);
}
/* encode scanline */
EncodeScanline(vpc, voxels, NULL, NULL);
return(VP_OK);
}
/*
* EncodeScanline
*
* Classify and run-length encode one scanline of voxels.
*/
static void
EncodeScanline(vpc, voxels, octree, level_stack)
vpContext *vpc; /* context */
void *voxels; /* voxel scanline */
MinMaxOctree *octree; /* octree for fast classification */
MMOctreeLevel level_stack[VP_MAX_OCTREE_LEVELS]; /* stack for octree */
{
ConstructionBuffer *cbuf; /* state preserved between calls */
RunData rundata_x; /* statistics for current x-axis run */
RunData *rundata_y; /* statistics for all y-axis runs */
RunData *rundata_z; /* statistics for all z-axis runs */
int skip_rle_x; /* if true, do not compute rle_x */
int skip_rle_y; /* if true, do not compute rle_y */
int skip_rle_z; /* if true, do not compute rle_z */
int y, z; /* y and z coordinates of scanline */
int x; /* index of current voxel in scanline */
int xlen, ylen, zlen; /* volume dimensions */
float opacity; /* current value of the opacity (0.0-1.0) */
float min_opacity; /* low opacity threshold */
int raw_bytes_per_voxel; /* bytes in unclassified voxel */
int run_length; /* length of last run */
char *rawvoxel; /* current unclassified voxel */
unsigned char *octree_run_ptr; /* pointer to current run */
int voxel_count; /* voxels remaining in current run */
int retcode;
/* initialize */
cbuf = vpc->cbuf;
xlen = vpc->xlen;
ylen = vpc->ylen;
zlen = vpc->zlen;
bzero(&rundata_x, sizeof(RunData));
rundata_y = &cbuf->rundata_y[cbuf->next_z];
rundata_z = &cbuf->rundata_z[cbuf->next_y * xlen];
skip_rle_x = vpc->skip_rle_x;
skip_rle_y = vpc->skip_rle_y;
skip_rle_z = vpc->skip_rle_z;
min_opacity = vpc->min_opacity;
raw_bytes_per_voxel = vpc->raw_bytes_per_voxel;
rawvoxel = voxels;
y = cbuf->next_y;
z = cbuf->next_z;
if (octree != NULL) {
if (cbuf->octree_scans_left == 0) {
cbuf->octree_scans_left = VPComputeScanRuns(vpc, level_stack,
cbuf->octree_runs, VP_Z_AXIS, y, xlen);
}
cbuf->octree_scans_left--;
octree_run_ptr = cbuf->octree_runs;
}
/* loop over voxels in the scanline */
x = 0;
while (x < xlen) {
if (octree == NULL) {
/* no octree available, so process all of the voxels in the scan */
voxel_count = xlen;
} else do {
/* skip over a run of zero voxels */
voxel_count = *octree_run_ptr++;
rundata_y += zlen * voxel_count;
rundata_z += voxel_count;
rawvoxel += raw_bytes_per_voxel * voxel_count;
x += voxel_count;
/* get length of nonzero voxel run */
voxel_count = *octree_run_ptr++;
} while (voxel_count == 0 && x < xlen);
/* process the voxels in the nonzero run */
while (voxel_count-- > 0) {
/* compute opacity */
opacity = VPClassifyVoxel(vpc, rawvoxel);
/* compare opacity to threshold */
if (opacity > min_opacity) {
/* voxel is non-transparent, so save it */
CacheVoxel(vpc, opacity, rawvoxel);
if (!skip_rle_x) {
rundata_y->p.p1.non_zero_count++;
CountNonZeroVoxel(rundata_y, y, 0, NULL);
}
if (!skip_rle_y) {
rundata_z->p.p1.non_zero_count++;
CountNonZeroVoxel(rundata_z, z, 0, NULL);
}
rundata_x.p.p1.non_zero_count++;
CountNonZeroVoxel(&rundata_x, x, 0, vpc);
}
rundata_y += zlen;
rundata_z++;
rawvoxel += raw_bytes_per_voxel;
x++;
} /* while (voxel_count) */
} /* for x */
/* finish off the statistics for the scanline */
CountNonZeroVoxel(&rundata_x, x, 1, vpc);
/* update saved state */
cbuf->non_zero_count += rundata_x.p.p1.non_zero_count;
cbuf->x_run_count += rundata_x.p.p1.run_count;
/* check if this is the last scanline in the volume */
if (++cbuf->next_y == ylen) {
cbuf->next_y = 0;
cbuf->octree_scans_left = 0;
if (++cbuf->next_z == zlen) {
RepackClassifiedVolume(vpc);
DestroyConstructionBuffer(vpc, vpc->cbuf);
vpc->cbuf = NULL;
#ifdef DEBUG
printf("\r");
if (!skip_rle_x) {
printf("Checking X scanline offsets....\n");
VPCheckScanOffsets(vpc->rle_x, vpc->rle_bytes_per_voxel);
}
if (!skip_rle_y) {
printf("Checking Y scanline offsets....\n");
VPCheckScanOffsets(vpc->rle_y, vpc->rle_bytes_per_voxel);
}
if (!skip_rle_z) {
printf("Checking Z scanline offsets....\n");
VPCheckScanOffsets(vpc->rle_z, vpc->rle_bytes_per_voxel);
}
VPValidateClassifiedVolume(vpc);
#endif
}
}
}
/*
* InitRLE
*
* Initialize in preparation for creating a new run-length encoded volume.
*/
static void
InitRLE(vpc)
vpContext *vpc;
{
int f;
int rle_bytes_per_voxel, size, offset;
int maxsize = 0;
/* find out how many bytes of the raw voxel are used for shading */
rle_bytes_per_voxel = 0;
for (f = 0; f < vpc->num_shade_fields; f++) {
size = vpc->field_size[f];
offset = vpc->field_offset[f] + size;
if (offset > rle_bytes_per_voxel)
rle_bytes_per_voxel = offset;
if (size > maxsize)
maxsize = size;
}
/* add one byte for opacity and then pad to the byte boundary of
the largest field in the voxel; this ensures alignment; the
opacity is always stored in the last byte (so the padding
is in between the shading fields and the opacity field) */
rle_bytes_per_voxel++;
rle_bytes_per_voxel = (rle_bytes_per_voxel + maxsize-1) & ~(maxsize-1);
vpc->rle_bytes_per_voxel = rle_bytes_per_voxel;
/* initialize construction buffer */
vpc->cbuf = CreateConstructionBuffer(vpc);
}
/*
* CacheVoxel
*
* Cache one voxel's data in the ConstructionBuffer.
*/
static void
CacheVoxel(vpc, opacity, rawvoxel)
vpContext *vpc; /* context */
double opacity; /* voxel's opacity */
void *rawvoxel; /* raw voxel data */
{
ConstructionBuffer *cbuf; /* state during construction of volume */
GBuffer *data_buf; /* storage for cached voxels */
void *data_ptr; /* pointer to current voxel's storage */
int rle_bytes_per_voxel; /* bytes per voxel after classification */
int opc_int; /* quantized opacity */
/* initialize */
cbuf = vpc->cbuf;
data_buf = cbuf->data_buf_tail;
rle_bytes_per_voxel = vpc->rle_bytes_per_voxel;
/* allocate more memory if necessary */
if (data_buf->bytes_left < rle_bytes_per_voxel) {
/* allocate more memory */
data_buf->next = CreateGBuffer(vpc);
data_buf = data_buf->next;
cbuf->data_buf_tail = data_buf;
}
data_ptr = data_buf->data_ptr;
/* copy the voxel fields required for shading */
bcopy(rawvoxel, data_ptr, rle_bytes_per_voxel-1);
/* quantize and store the opacity */
opc_int = opacity*255.;
if (opc_int > 255)
opc_int = 255;
else if (opc_int < 0)
opc_int = 0;
ByteField(data_ptr, rle_bytes_per_voxel-1) = opc_int;
data_buf->data_ptr += rle_bytes_per_voxel;
data_buf->bytes_left -= rle_bytes_per_voxel;
}
/*
* CacheLength
*
* Cache one run length in the ConstructionBuffer.
*/
static void
CacheLength(vpc, length)
vpContext *vpc;
int length;
{
GBuffer *lengths_buf;
lengths_buf = vpc->cbuf->lengths_buf_tail;
if (lengths_buf->bytes_left == 0) {
/* allocate more memory */
lengths_buf->next = CreateGBuffer(vpc);
lengths_buf = lengths_buf->next;
vpc->cbuf->lengths_buf_tail = lengths_buf;
}
*(lengths_buf->data_ptr)++ = length;
lengths_buf->bytes_left--;
}
/*
* CountNonZeroVoxel
*
* Update the run count and nonzero voxel count for a voxel scanline.
* This routine adds one non-zero voxel to the scanline. Index
* indicates the position of the voxel in the scanline. If that
* position is not immediately adjacent to the last non-zero voxel then
* a run of zero voxels is added as well.
*
* If the vpc argument is non-NULL then the lengths of any completed
* runs are written out to the run length buffer.
*/
static void
CountNonZeroVoxel(rundata, index, end_of_scan, vpc)
RunData *rundata; /* statistics for the scanline */
int index; /* index of voxel in scanline */
int end_of_scan; /* if true then finish the scanline instead of
adding a voxel */
vpContext *vpc; /* context in which run lengths should be stored */
{
int run_length;
if (rundata->next_index != index) {
/* a run of zero voxels intervenes between the current index
and the last nonzero voxel that was processed */
if (rundata->next_index != 0) {
/* add the last nonzero run to the statistics */
run_length = rundata->run_length;
while (run_length > 255) {
/* run is too long, so split it */
run_length -= 255;
rundata->p.p1.run_count += 2;
if (vpc != NULL) {
CacheLength(vpc, 255);
CacheLength(vpc, 0);
}
}
rundata->p.p1.run_count++;
if (vpc != NULL)
CacheLength(vpc, run_length);
}
/* add the last zero run to the statistics */
run_length = index - rundata->next_index;
while (run_length > 255) {
/* run is too long, so split it */
run_length -= 255;
rundata->p.p1.run_count += 2;
if (vpc != NULL) {
CacheLength(vpc, 255);
CacheLength(vpc, 0);
}
}
rundata->p.p1.run_count++;
if (vpc != NULL)
CacheLength(vpc, run_length);
if (end_of_scan) {
/* add a zero-length nonzero run to finish the scanline */
rundata->p.p1.run_count++;
if (vpc != NULL)
CacheLength(vpc, 0);
} else {
/* start the new run */
rundata->run_length = 1;
rundata->next_index = index + 1;
}
} else if (!end_of_scan) {
/* add a nonzero voxel to the current run */
if (rundata->next_index == 0) {
rundata->p.p1.run_count++; /* count initial zero run */
if (vpc != NULL)
CacheLength(vpc, 0);
}
rundata->run_length++;
rundata->next_index = index + 1;
} else {
/* scanline ends with a nonzero voxel run */
run_length = rundata->run_length;
while (run_length > 255) {
/* run is too long, so split it */
run_length -= 255;
rundata->p.p1.run_count += 2;
if (vpc != NULL) {
CacheLength(vpc, 255);
CacheLength(vpc, 0);
}
}
rundata->p.p1.run_count++;
if (vpc != NULL)
CacheLength(vpc, run_length);
}
}
/*
* RepackClassifiedVolume
*
* Repack the data in the ConstructionBuffer after the last call to
* vpClassifyScanline. This procedure creates the three run-length
* encoded copies of the classified voxels.
*/
static void
RepackClassifiedVolume(vpc)
vpContext *vpc;
{
int xlen, ylen, zlen; /* volume dimensions */
int x, y, z; /* voxel coordinates */
int non_zero_count; /* number of nonzero voxels in volume */
int rle_bytes_per_voxel; /* bytes per classified voxel */
int skip_rle_x; /* if true, compute rle_x */
int skip_rle_y; /* if true, compute rle_y */
int skip_rle_z; /* if true, compute rle_z */
char *x_data; /* voxel data for x viewpoint */
char *y_data; /* voxel data for y viewpoint */
char *z_data; /* voxel data for z viewpoint */
unsigned char *x_lengths; /* run length for x viewpoint */
unsigned char *y_lengths; /* run length for y viewpoint */
unsigned char *z_lengths; /* run length for z viewpoint */
int z_data_offset; /* offset to current data value in z volume */
int z_length_offset; /* offset to current length value in z volume*/
GBuffer *data_buf; /* next GBuffer containing voxel data */
char *data; /* pointer to next voxel */
int data_bytes_left; /* bytes of data left in data buffer */
GBuffer *lengths_buf; /* next GBuffer containing length data */
unsigned char *lengths; /* pointer to next length */
int lengths_bytes_left; /* bytes of data left in lengths buffer */
int x_run_length; /* length of current x-scanline run */
int is_non_zero; /* true if current x-scanline run is nonzero */
RunData *rundata_y; /* statistics for y-axis runs */
RunData *rundata_z; /* statistics for z-axis runs */
/* initialize */
xlen = vpc->xlen;
ylen = vpc->ylen;
zlen = vpc->zlen;
non_zero_count = vpc->cbuf->non_zero_count;
rle_bytes_per_voxel = vpc->rle_bytes_per_voxel;
skip_rle_x = vpc->skip_rle_x;
skip_rle_y = vpc->skip_rle_y;
skip_rle_z = vpc->skip_rle_z;
/* check for empty volume */
if (non_zero_count == 0) {
if (!skip_rle_x)
vpc->rle_x = CreateEmptyRLEVoxels(vpc, ylen, zlen, xlen);
if (!skip_rle_y)
vpc->rle_y = CreateEmptyRLEVoxels(vpc, zlen, xlen, ylen);
if (!skip_rle_z)
vpc->rle_z = CreateEmptyRLEVoxels(vpc, xlen, ylen, zlen);
return;
}
/* allocate space for y-axis runs (used for the x viewing axis) */
if (!skip_rle_x) {
vpc->rle_x = CreateRLEVoxelsFromRunData(vpc, ylen, zlen, xlen,
non_zero_count, vpc->cbuf->rundata_y, rle_bytes_per_voxel);
x_data = vpc->rle_x->data;
x_lengths = vpc->rle_x->run_lengths;
}
/* allocate space for z-axis runs (used for the y viewing axis) */
if (!skip_rle_y) {
vpc->rle_y = CreateRLEVoxelsFromRunData(vpc, zlen, xlen, ylen,
non_zero_count, vpc->cbuf->rundata_z, rle_bytes_per_voxel);
y_data = vpc->rle_y->data;
y_lengths = vpc->rle_y->run_lengths;
}
/* allocate space for x-axis runs (used for the z viewing axis) */
if (!skip_rle_z) {
vpc->rle_z = VPCreateRLEVoxels(vpc, xlen, ylen, zlen, non_zero_count,
vpc->cbuf->x_run_count, rle_bytes_per_voxel);
Alloc(vpc, vpc->rle_z->scan_offsets, ScanOffset *,
zlen*sizeof(ScanOffset), "scan_offsets");
vpc->rle_z->scan_offsets_per_slice = 1;
z_data = vpc->rle_z->data;
z_lengths = vpc->rle_z->run_lengths;
z_data_offset = 0;
z_length_offset = 0;
}
/* copy data into the three RLEVoxels structures */
data_buf = vpc->cbuf->data_buf_head;
data = NULL;
data_bytes_left = 0;
lengths_buf = vpc->cbuf->lengths_buf_head;
lengths = NULL;
lengths_bytes_left = 0;
x_run_length = 0;
is_non_zero = 1;
for (z = 0; z < zlen; z++) {
ReportStatus(vpc, (double)z / (double)zlen);
if (!skip_rle_z) {
vpc->rle_z->scan_offsets[z].first_data = z_data_offset;
vpc->rle_z->scan_offsets[z].first_len =
(z_length_offset & 0x1) ? z_length_offset + 1 :
z_length_offset;
}
rundata_z = vpc->cbuf->rundata_z;
for (y = 0; y < ylen; y++) {
rundata_y = &vpc->cbuf->rundata_y[z];
for (x = 0; x < xlen; x++) {
while (x_run_length == 0) {
/* find length of next run */
if (lengths_bytes_left <= 0) {
/* go to next lengths buffer */
lengths = (unsigned char *)lengths_buf->data;
lengths_bytes_left = GBUFFER_SIZE -
lengths_buf->bytes_left;
lengths_buf = lengths_buf->next;
if (!skip_rle_z) {
bcopy(lengths, z_lengths, lengths_bytes_left);
z_lengths += lengths_bytes_left;
}
}
x_run_length = *lengths++;
lengths_bytes_left--;
is_non_zero = !is_non_zero;
z_length_offset++;
}
x_run_length--; /* consume one voxel */
if (is_non_zero) {
/* find the data for this voxel */
if (data_bytes_left <= 0) {
data = data_buf->data;
data_bytes_left = GBUFFER_SIZE - data_buf->bytes_left;
data_buf = data_buf->next;
if (!skip_rle_z) {
bcopy(data, z_data, data_bytes_left);
z_data = (char *)z_data + data_bytes_left;
}
}
/* store voxel */
if (!skip_rle_x) {
StoreNonZeroVoxel(data, rle_bytes_per_voxel, x_data,
x_lengths, rundata_y, y);
}
if (!skip_rle_y) {
StoreNonZeroVoxel(data, rle_bytes_per_voxel, y_data,
y_lengths, rundata_z, z);
}
data += rle_bytes_per_voxel;
data_bytes_left -= rle_bytes_per_voxel;
z_data_offset += rle_bytes_per_voxel;
}
rundata_y += zlen;
rundata_z++;
} /* for x */
} /* for y */
} /* for z */
ReportStatus(vpc, 1.0);
if (!skip_rle_x)
PadScanlines(ylen, zlen, xlen, vpc->cbuf->rundata_y, x_lengths);
if (!skip_rle_y)
PadScanlines(zlen, xlen, ylen, vpc->cbuf->rundata_z, y_lengths);
}
/*
* CreateEmptyRLEVoxels
*
* Create an empty RLEVoxels object (all voxels transparent).
*/
static RLEVoxels *
CreateEmptyRLEVoxels(vpc, ilen, jlen, klen)
vpContext *vpc;
int ilen, jlen, klen;
{
RLEVoxels *rle_voxels;
int j, k;
unsigned char *run_lengths;
ScanOffset *scan_offsets;
rle_voxels = VPCreateRLEVoxels(vpc, ilen, jlen, klen, 1, 2*jlen*klen, 1);
Alloc(vpc, rle_voxels->scan_offsets, ScanOffset *, klen*sizeof(ScanOffset),
"scan_offsets");
rle_voxels->scan_offsets_per_slice = 1;
run_lengths = rle_voxels->run_lengths;
scan_offsets = rle_voxels->scan_offsets;
for (k = 0; k < klen; k++) {
scan_offsets->first_len = k*jlen*2;
scan_offsets->first_data = 0;
scan_offsets++;
for (j = 0; j < jlen; j++) {
*run_lengths++ = ilen;
*run_lengths++ = 0;
}
}
return(rle_voxels);
}
/*
* CreateRLEVoxelsFromRunData
*
* Allocate an RLEVoxels structure using the data in a RunData array
* in order to determine the required size. Also reinitialize the RunData
* array with pointers to the RLEVoxels data for the beginning of
* each scanline.
*/
static RLEVoxels *
CreateRLEVoxelsFromRunData(vpc, ilen, jlen, klen, non_zero_count, run_data,
rle_bytes_per_voxel)
vpContext *vpc; /* context */
int ilen, jlen, klen; /* size of volume in rotated object space */
int non_zero_count; /* number of nonzero voxels in volume */
RunData *run_data; /* array of run statistics (jlen*klen entries) */
int rle_bytes_per_voxel;/* number of bytes to allocate for each voxel */
{
int j, k; /* scanline and slice number */
int scan_run_count; /* runs in current scanline */
int run_count; /* runs in entire volume */
int scan_non_zero_count; /* nonzero voxels in scanline */
int data_offset; /* scanline's offset in RLEVoxels->data */
int length_offset; /* scanline's offset in
RLEVoxels->run_lengths */
ScanOffset *slice_offset; /* offsets for each slice */
RLEVoxels *rle_voxels; /* return value */
Alloc(vpc, slice_offset, ScanOffset *, klen*sizeof(ScanOffset),
"scan_offsets");
/* accumulate the statistics for the last run in each scanline,
count the total number of runs, and store the data and length
offsets for the beginning of the scanline */
data_offset = 0;
length_offset = 0;
run_count = 0;
for (k = 0; k < klen; k++) {
slice_offset[k].first_data = data_offset;
slice_offset[k].first_len = length_offset;
for (j = 0; j < jlen; j++) {
CountNonZeroVoxel(run_data, ilen, 1, NULL);
scan_non_zero_count = run_data->p.p1.non_zero_count;
scan_run_count = run_data->p.p1.run_count;
run_data->run_length = 0;
run_data->next_index = 0;
run_data->p.p2.data_offset = data_offset;
run_data->p.p2.length_offset = length_offset;
data_offset += scan_non_zero_count * rle_bytes_per_voxel;
length_offset += scan_run_count * sizeof(unsigned char);
run_count += scan_run_count;
run_data++;
}
}
/* allocate space */
rle_voxels = VPCreateRLEVoxels(vpc, ilen, jlen, klen, non_zero_count,
run_count, rle_bytes_per_voxel);
rle_voxels->scan_offsets_per_slice = 1;
rle_voxels->scan_offsets = slice_offset;
return(rle_voxels);
}
/*
* StoreNonZeroVoxel
*
* Store a nonzero voxel in an RLEVoxels object. This function is
* just like CountNonZeroVoxel except that it actually stores voxel data.
*/
static void
StoreNonZeroVoxel(voxel, rle_bytes_per_voxel, data, lengths, rundata, index)
void *voxel; /* input voxel data */
int rle_bytes_per_voxel;/* size of voxel */
void *data; /* location to store voxel */
unsigned char *lengths; /* location to store run lengths */
RunData *rundata; /* run length statistics for current voxel scanline */
int index; /* index of voxel in scanline */
{
int run_length;
/* store the voxel */
if (voxel != NULL) {
bcopy(voxel, (char *)data + rundata->p.p2.data_offset,
rle_bytes_per_voxel);
rundata->p.p2.data_offset += rle_bytes_per_voxel;
}
/* update run lengths */
if (rundata->next_index != index) {
/* a run of zero voxels intervenes between the current index
and the last nonzero voxel that was processed */
if (rundata->next_index != 0) {
/* add the last nonzero run to the statistics */
run_length = rundata->run_length;
while (run_length > 255) {
/* run is too long, so split it */
run_length -= 255;
lengths[rundata->p.p2.length_offset++] = 255;
lengths[rundata->p.p2.length_offset++] = 0;
}
lengths[rundata->p.p2.length_offset++] = run_length;
}
/* add the last zero run to the statistics */
run_length = index - rundata->next_index;
while (run_length > 255) {
/* run is too long, so split it */
run_length -= 255;
lengths[rundata->p.p2.length_offset++] = 255;
lengths[rundata->p.p2.length_offset++] = 0;
}
lengths[rundata->p.p2.length_offset++] = run_length;
if (voxel == NULL) {
/* add a zero-length nonzero run to finish the scanline */
lengths[rundata->p.p2.length_offset++] = 0;
} else {
/* start the new run */
rundata->run_length = 1;
rundata->next_index = index + 1;
}
} else if (voxel != NULL) {
/* add a nonzero voxel to the current run */
if (rundata->next_index == 0) {
lengths[rundata->p.p2.length_offset++] = 0;
}
rundata->run_length++;
rundata->next_index = index + 1;
} else {
/* scanline ends with a nonzero voxel run */
run_length = rundata->run_length;
while (run_length > 255) {
/* run is too long, so split it */
run_length -= 255;
lengths[rundata->p.p2.length_offset++] = 255;
lengths[rundata->p.p2.length_offset++] = 0;
}
lengths[rundata->p.p2.length_offset++] = run_length;
}
}
/*
* PadScanlines
*
* Make sure each scanline has an even number of runs.
*/
static void
PadScanlines(ilen, jlen, klen, run_data, lengths)
int ilen, jlen, klen; /* size of volume in rotated object space */
RunData *run_data; /* array of run statistics (jlen*klen entries) */
unsigned char *lengths; /* beginning of run lengths array */
{
int scan_count; /* number of scanlines */
int scan_run_count; /* number of runs in scanline */
int scan; /* current scanline number */
scan_count = jlen * klen;
for (scan = 0; scan < scan_count; scan++) {
StoreNonZeroVoxel(NULL, 0, NULL, lengths, run_data, ilen);
run_data++;
}
}
/*
* VPCreateRLEVoxels
*
*
* Allocate a new RLEVoxels object.
*/
RLEVoxels *
VPCreateRLEVoxels(vpc, ilen, jlen, klen, data_count, run_count,
rle_bytes_per_voxel)
vpContext *vpc; /* context */
int ilen, jlen, klen; /* dimensions in rotated object space */
int data_count; /* number of nonzero voxels */
int run_count; /* number of runs */
int rle_bytes_per_voxel;/* bytes of storage for one voxel */
{
RLEVoxels *rle_voxels;
Alloc(vpc, rle_voxels, RLEVoxels *, sizeof(RLEVoxels), "RLEVoxels");
rle_voxels->ilen = ilen;
rle_voxels->jlen = jlen;
rle_voxels->klen = klen;
rle_voxels->run_count = run_count;
if (run_count > 0) {
Alloc(vpc, rle_voxels->run_lengths, unsigned char *, run_count,
"run_lengths");
} else {
rle_voxels->run_lengths = NULL;
}
rle_voxels->data_count = data_count;
if (data_count > 0) {
Alloc(vpc, rle_voxels->data, void *, data_count * rle_bytes_per_voxel,
"voxeldata");
} else {
rle_voxels->data = NULL;
}
rle_voxels->scan_offsets_per_slice = 0;
rle_voxels->scan_offsets = NULL;
rle_voxels->mmapped = 0;
#ifdef INDEX_VOLUME
rle_voxels->voxel_index = NULL;
#endif
return(rle_voxels);
}
/*
* VPDestroyRLEVoxels
*
* Destroy an RLEVoxels object.
*/
void
VPDestroyRLEVoxels(vpc, rle_voxels)
vpContext *vpc;
RLEVoxels *rle_voxels;
{
if (!rle_voxels->mmapped) {
if (rle_voxels->run_lengths != NULL)
Dealloc(vpc, rle_voxels->run_lengths);
if (rle_voxels->data != NULL)
Dealloc(vpc, rle_voxels->data);
if (rle_voxels->scan_offsets != NULL)
Dealloc(vpc, rle_voxels->scan_offsets);
}
#ifdef INDEX_VOLUME
if (rle_voxels->voxel_index != NULL)
Dealloc(vpc, rle_voxels->voxel_index);
#endif
Dealloc(vpc, rle_voxels);
}
/*
* CreateConstructionBuffer
*
* Create a ConstructionBuffer object.
*/
static ConstructionBuffer *
CreateConstructionBuffer(vpc)
vpContext *vpc;
{
ConstructionBuffer *cbuf;
int xlen, ylen, zlen;
xlen = vpc->xlen;
ylen = vpc->ylen;
zlen = vpc->zlen;
Alloc(vpc, cbuf, ConstructionBuffer *, sizeof(ConstructionBuffer),
"ConstructionBuffer");
Alloc(vpc, cbuf->rundata_y, RunData *, xlen*zlen*sizeof(RunData),
"rundata_y");
Alloc(vpc, cbuf->rundata_z, RunData *, ylen*xlen*sizeof(RunData),
"rundata_z");
bzero(cbuf->rundata_y, xlen*zlen*sizeof(RunData));
bzero(cbuf->rundata_z, ylen*xlen*sizeof(RunData));
cbuf->data_buf_head = CreateGBuffer(vpc);
cbuf->data_buf_tail = cbuf->data_buf_head;
cbuf->lengths_buf_head = CreateGBuffer(vpc);
cbuf->lengths_buf_tail = cbuf->lengths_buf_head;
cbuf->non_zero_count = 0;
cbuf->x_run_count = 0;
cbuf->octree_scans_left = 0;
cbuf->next_z = 0;
cbuf->next_y = 0;
return(cbuf);
}
/*
* DestroyConstructionBuffer
*
* Destroy a ConstructionBuffer object.
*/
static void
DestroyConstructionBuffer(vpc, cbuf)
vpContext *vpc;
ConstructionBuffer *cbuf;
{
GBuffer *gbuf, *next_gbuf;
Dealloc(vpc, cbuf->rundata_y);
Dealloc(vpc, cbuf->rundata_z);
for (gbuf = cbuf->data_buf_head; gbuf != NULL; gbuf = next_gbuf) {
next_gbuf = gbuf->next;
DestroyGBuffer(vpc, gbuf);
}
for (gbuf = cbuf->lengths_buf_head; gbuf != NULL; gbuf = next_gbuf) {
next_gbuf = gbuf->next;
DestroyGBuffer(vpc, gbuf);
}
Dealloc(vpc, cbuf);
}
/*
* CreateGBuffer
*
* Create a GBuffer object.
*/
static GBuffer *
CreateGBuffer(vpc)
vpContext *vpc;
{
GBuffer *gbuf;
Alloc(vpc, gbuf, GBuffer *, sizeof(GBuffer), "GBuffer");
gbuf->bytes_left = GBUFFER_SIZE;
gbuf->data_ptr = gbuf->data;
gbuf->next = NULL;
return(gbuf);
}
/*
* DestroyGBuffer
*
* Destroy a GBuffer.
*/
static void
DestroyGBuffer(vpc, gbuf)
vpContext *vpc;
GBuffer *gbuf;
{
Dealloc(vpc, gbuf);
}
/*
* vpDestroyClassifiedVolume
*
* Free all memory associated with a classified volume.
*/
vpResult
vpDestroyClassifiedVolume(vpc)
vpContext *vpc;
{
if (vpc->cbuf != NULL) {
DestroyConstructionBuffer(vpc, vpc->cbuf);
vpc->cbuf = NULL;
}
if (vpc->rle_x != NULL) {
VPDestroyRLEVoxels(vpc, vpc->rle_x);
vpc->rle_x = NULL;
}
if (vpc->rle_y != NULL) {
VPDestroyRLEVoxels(vpc, vpc->rle_y);
vpc->rle_y = NULL;
}
if (vpc->rle_z != NULL) {
VPDestroyRLEVoxels(vpc, vpc->rle_z);
vpc->rle_z = NULL;
}
return(VP_OK);
}
#ifdef INDEX_VOLUME
/*
* vpComputeRLEIndex
*
* Compute indexes for the classified volume data in a context.
*/
vpResult
vpComputeRLEIndex(vpc)
vpContext *vpc;
{
vpResult result;
if ((result = VPComputeRLEScanOffsets(vpc)) != VP_OK)
return(result);
if (vpc->rle_x != NULL) {
if ((result = ComputeIndex(vpc, vpc->rle_x)) != VP_OK)
return(result);
}
if (vpc->rle_y != NULL) {
if ((result = ComputeIndex(vpc, vpc->rle_y)) != VP_OK)
return(result);
}
if (vpc->rle_z != NULL) {
if ((result = ComputeIndex(vpc, vpc->rle_z)) != VP_OK)
return(result);
}
return(VP_OK);
}
/*
* ComputeIndex
*
* Compute an index that maps 3D voxel coordinates to the RLE run data
* for the corresponding voxel. The values stored in the index are
* byte offsets to the beginning of the run containing the voxel,
* plus a count indicating the position of the voxel in the run.
* Return value is a result code.
*/
static vpResult
ComputeIndex(vpc, rle_voxels)
vpContext *vpc;
RLEVoxels *rle_voxels;
{
int ilen, jlen, klen; /* size of volume */
unsigned char *RLElen; /* pointer to current run length */
VoxelLocation *index; /* pointer to current index entry */
int i, j, k; /* current voxel coordinates */
unsigned len_offset; /* offset in bytes from beginning of
scanline to current run length */
unsigned data_offset; /* offset in bytes from beginning of
scanline to current voxel data */
int run_is_zero; /* true if current run is a zero run */
int run_count; /* voxels left in current run */
int voxel_size; /* size of a voxel in bytes */
ilen = rle_voxels->ilen;
jlen = rle_voxels->jlen;
klen = rle_voxels->klen;
RLElen = rle_voxels->run_lengths;
if (rle_voxels->scan_offsets_per_slice != jlen)
return(VPERROR_BAD_VOLUME);
if (rle_voxels->voxel_index == NULL) {
Alloc(vpc, rle_voxels->voxel_index, VoxelLocation *,
ilen * jlen * klen * sizeof(VoxelLocation), "voxel_index");
}
index = rle_voxels->voxel_index;
voxel_size = vpc->rle_bytes_per_voxel;
run_is_zero = 0;
run_count = 0;
for (k = 0; k < klen; k++) {
for (j = 0; j < jlen; j++) {
ASSERT(run_is_zero == 0);
ASSERT(run_count == 0);
len_offset = 0;
data_offset = 0;
for (i = 0; i < ilen; i++) {
/* record index for current voxel */
if (len_offset > 256) {
Dealloc(vpc, rle_voxels->voxel_index);
rle_voxels->voxel_index = NULL;
return(VPERROR_LIMIT_EXCEEDED);
}
index->run_count = run_count;
index->len_offset = len_offset;
if (run_is_zero)
index->data_offset = data_offset | INDEX_RUN_IS_ZERO;
else
index->data_offset = data_offset;
index++;
/* go on to next voxel */
while (run_count == 0) {
run_count = *RLElen++;
run_is_zero = !run_is_zero;
len_offset++;
}
run_count--;
if (!run_is_zero)
data_offset += voxel_size;
}
ASSERT(run_count == 0);
if (run_is_zero) {
run_count = *RLElen++;
run_is_zero = !run_is_zero;
len_offset++;
}
}
}
return(VP_OK);
}
#endif /* INDEX_VOLUME */
/*
* VPComputeRLEScanOffsets
*
* Recompute the scan_offsets arrays for the classified volume data in
* a context. Return value is a result code.
*/
vpResult
VPComputeRLEScanOffsets(vpc)
vpContext *vpc;
{
vpResult result;
if (vpc->rle_x != NULL) {
if ((result = ComputeScanOffsets(vpc, vpc->rle_x)) != VP_OK)
return(result);
#ifdef DEBUG
VPCheckScanOffsets(vpc->rle_x, vpc->rle_bytes_per_voxel);
#endif
}
if (vpc->rle_y != NULL) {
if ((result = ComputeScanOffsets(vpc, vpc->rle_y)) != VP_OK)
return(result);
#ifdef DEBUG
VPCheckScanOffsets(vpc->rle_y, vpc->rle_bytes_per_voxel);
#endif
}
if (vpc->rle_z != NULL) {
if ((result = ComputeScanOffsets(vpc, vpc->rle_z)) != VP_OK)
return(result);
#ifdef DEBUG
VPCheckScanOffsets(vpc->rle_z, vpc->rle_bytes_per_voxel);
#endif
}
return(VP_OK);
}
/*
* ComputeScanOffsets
*
* Recompute the scan_offsets array for a classified volume.
* Return value is a result code.
*/
static vpResult
ComputeScanOffsets(vpc, rle_voxels)
vpContext *vpc;
RLEVoxels *rle_voxels;
{
int ilen, jlen, klen; /* size of volume */
unsigned char *RLElen; /* pointer to current run length */
ScanOffset *scan_offset; /* pointer to current scanline offset */
int i, j, k; /* current voxel coordinates */
unsigned len_offset; /* offset in bytes from beginning of
run lengths to current run length */
unsigned data_offset; /* offset in bytes from beginning of
voxel data to current voxel data */
int voxel_size; /* size of a voxel in bytes */
int zerocount, nonzerocount;
if (rle_voxels->mmapped)
return(VPERROR_IO);
ilen = rle_voxels->ilen;
jlen = rle_voxels->jlen;
klen = rle_voxels->klen;
RLElen = rle_voxels->run_lengths;
if (rle_voxels->scan_offsets_per_slice != jlen) {
if (rle_voxels->scan_offsets != NULL)
Dealloc(vpc, rle_voxels->scan_offsets);
Alloc(vpc, rle_voxels->scan_offsets, ScanOffset *,
klen * jlen * sizeof(ScanOffset), "scan_offsets");
rle_voxels->scan_offsets_per_slice = jlen;
}
scan_offset = rle_voxels->scan_offsets;
len_offset = 0;
data_offset = 0;
voxel_size = vpc->rle_bytes_per_voxel;
for (k = 0; k < klen; k++) {
for (j = 0; j < jlen; j++) {
scan_offset->first_len = len_offset;
scan_offset->first_data = data_offset;
scan_offset++;
for (i = 0; i < ilen; ) {
zerocount = *RLElen++; /* get length of run of zeros */
nonzerocount = *RLElen++;/* get length of run of non-zeros */
len_offset += 2;
data_offset += nonzerocount * voxel_size;
i += zerocount + nonzerocount;
}
ASSERT(i == ilen);
}
}
return(VP_OK);
}
#ifdef DEBUG
/*
* VPCheckScanOffsets
*
* Check the scan_offsets field of an RLEVolume for internal consistency.
*/
void
VPCheckScanOffsets(rle_voxels, rle_bytes_per_voxel)
RLEVoxels *rle_voxels;
{
int i, j, k;
int ilen, jlen, klen;
int run_length;
int is_non_zero;
unsigned char *run_length_ptr;
int length_offset;
int data_offset;
int scan_offsets_per_slice;
ScanOffset *scan_offset;
scan_offsets_per_slice = rle_voxels->scan_offsets_per_slice;
if (scan_offsets_per_slice == 0)
return;
ilen = rle_voxels->ilen;
jlen = rle_voxels->jlen;
klen = rle_voxels->klen;
run_length_ptr = rle_voxels->run_lengths;
run_length = 0;
is_non_zero = 1;
length_offset = 0;
data_offset = 0;
for (k = 0; k < klen; k++) {
for (j = 0; j < jlen; j++) {
if (j < scan_offsets_per_slice) {
scan_offset = &rle_voxels->scan_offsets[
k*scan_offsets_per_slice + j];
if (scan_offset->first_len != length_offset) {
printf("Bad length offset on slice %d, scanline %d: ",k,j);
printf("%d should be %d\n", scan_offset->first_len,
length_offset);
}
if (scan_offset->first_data != data_offset) {
printf("Bad data offset on slice %d, scanline %d: ",k,j);
printf("%d should be %d\n", scan_offset->first_data,
data_offset);
}
}
for (i = 0; i < ilen; i++) {
while (run_length == 0) {
run_length = *run_length_ptr++;
is_non_zero = !is_non_zero;
length_offset++;
}
run_length--;
if (is_non_zero)
data_offset += rle_bytes_per_voxel;
}
if (run_length != 0) {
printf("Run did not terminate at end of scanline ");
printf("on slice %d, scanline %d\n", k, j);
}
if (!is_non_zero) {
if (*run_length_ptr++ != 0) {
printf("Missing zero run at end of scanline ");
printf("on slice %d, scanline %d\n", k, j);
}
is_non_zero = !is_non_zero;
length_offset++;
}
}
}
}
/*
* VPValidateClassifiedVolume
*
* Compare the classified volume to the unclassified volume.
*/
void
VPValidateClassifiedVolume(vpc)
vpContext *vpc;
{
if (vpc->raw_voxels == NULL)
return;
if (vpc->rle_z != NULL) {
printf("Checking Z view....\n");
ValidateRLEVoxels(vpc, vpc->rle_z, vpc->xstride, vpc->ystride,
vpc->zstride, VP_Z_AXIS);
}
if (vpc->rle_y != NULL) {
printf("Checking Y view....\n");
ValidateRLEVoxels(vpc, vpc->rle_y, vpc->zstride, vpc->xstride,
vpc->ystride, VP_Y_AXIS);
}
if (vpc->rle_x != NULL) {
printf("Checking X view....\n");
ValidateRLEVoxels(vpc, vpc->rle_x, vpc->ystride, vpc->zstride,
vpc->xstride, VP_X_AXIS);
}
}
static void
ValidateRLEVoxels(vpc, rle, istride, jstride, kstride, axis)
vpContext *vpc;
RLEVoxels *rle;
int istride, jstride, kstride;
int axis;
{
char *rawvoxel;
char *rlevoxel;
unsigned char *lengths;
int i, j, k;
int count;
int is_non_zero;
int num_runs;
float opacity;
int ilen, jlen, klen;
int founderror;
int raw_opc_int;
int rle_opc_int;
int rle_bytes_per_voxel;
rawvoxel = (char *)vpc->raw_voxels;
rlevoxel = (char *)rle->data;
lengths = rle->run_lengths;
ilen = rle->ilen;
jlen = rle->jlen;
klen = rle->klen;
rle_bytes_per_voxel = vpc->rle_bytes_per_voxel;
founderror = 0;
for (k = 0; k < klen; k++) {
for (j = 0; j < jlen; j++) {
count = 0;
is_non_zero = 1;
num_runs = 0;
for (i = 0; i < ilen; i++) {
while (count == 0) {
count = *lengths++;
is_non_zero = !is_non_zero;
if (++num_runs > rle->ilen)
VPBug("runaway scan detected by ValidateRLEVoxels");
}
opacity = VPClassifyVoxel(vpc, rawvoxel);
if (is_non_zero) {
if (opacity <= vpc->min_opacity &&
fabs(opacity - vpc->min_opacity) > 0.001) {
printf("\n");
printf("**** zero rawvoxel in nonzero rlerun ****\n");
printf("voxel (i,j,k)=(%d,%d,%d), viewaxis %d\n",
i, j, k, axis);
printf("Actual opacity: %17.15f\n", opacity);
printf("Threshold: %17.15f\n", vpc->min_opacity);
founderror = 1;
}
raw_opc_int = (int)rint(opacity*255.);
rle_opc_int = ByteField(rlevoxel, rle_bytes_per_voxel-1);
if (abs(raw_opc_int - rle_opc_int) > 1) {
printf("\n");
printf("**** rawvoxel and rlevoxel disagree ****\n");
printf("voxel (i,j,k)=(%d,%d,%d), viewaxis %d\n",
i, j, k, axis);
printf("Raw opacity: %3d\n", raw_opc_int);
printf("RLE opacity: %3d\n", rle_opc_int);
founderror = 1;
}
rlevoxel += rle_bytes_per_voxel;
} else {
if (opacity > vpc->min_opacity &&
fabs(opacity - vpc->min_opacity) > 0.001) {
printf("\n");
printf("**** nonzero rawvoxel in zero rlerun ****\n");
printf("voxel (i,j,k)=(%d,%d,%d), viewaxis %d\n",
i, j, k, axis);
printf("Actual opacity: %17.15f\n", opacity);
printf("Threshold: %17.15f\n", vpc->min_opacity);
founderror = 1;
}
}
if (founderror) {
VPDumpClassifier(vpc);
VPBug("ValidateRLEVoxels found a problem");
}
rawvoxel += istride;
count--;
}
if (count != 0)
VPBug("Run did not terminate at end of scanline");
if (!is_non_zero) {
if (*lengths++ != 0)
VPBug("Missing zero run at end of scanline");
is_non_zero = !is_non_zero;
}
rawvoxel += jstride - ilen*istride;
}
rawvoxel += kstride - jlen*jstride;
}
}
#endif
void
VPDumpView(vpc)
vpContext *vpc;
{
int c;
printf("MODEL:\n");
for (c = 0; c < 4; c++) {
printf(" %12.6f %12.6f %12.6f %12.6f\n",
vpc->transforms[VP_MODEL][c][0],
vpc->transforms[VP_MODEL][c][1],
vpc->transforms[VP_MODEL][c][2],
vpc->transforms[VP_MODEL][c][3]);
}
printf("VIEW:\n");
for (c = 0; c < 4; c++) {
printf(" %12.6f %12.6f %12.6f %12.6f\n",
vpc->transforms[VP_MODEL][c][0],
vpc->transforms[VP_MODEL][c][1],
vpc->transforms[VP_MODEL][c][2],
vpc->transforms[VP_MODEL][c][3]);
}
printf("PROJECT:\n");
for (c = 0; c < 4; c++) {
printf(" %12.6f %12.6f %12.6f %12.6f\n",
vpc->transforms[VP_MODEL][c][0],
vpc->transforms[VP_MODEL][c][1],
vpc->transforms[VP_MODEL][c][2],
vpc->transforms[VP_MODEL][c][3]);
}
}
void
VPDumpClassifier(vpc)
vpContext *vpc;
{
int c, d;
for (d = 0; d < vpc->num_clsfy_params; d++) {
printf("CLASSIFIER PARAM %d:\n ", d);
for (c = 0; c < vpc->field_max[vpc->param_field[d]]; c++) {
printf(" %8.6f", vpc->clsfy_table[d][c]);
if (c % 8 == 7)
printf("\n ");
}
printf("\n");
}
}
syntax highlighted by Code2HTML, v. 0.9.1