1/*
2 * vp_compA.m4
3 *
4 * Compositing routine for affine viewing transformations.
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.7 $
29 */
30
31#include "vp_global.h"
32
33dnl Description:
34dnl    This is an m4 source file which defines a C procedure to resample
35dnl    and composite one slice of a volume.  The macro definitions allow
36dnl    the procedure to be specialized for a particular volume data
37dnl    structure (run-length encoded classified volume, or unclassified
38dnl    volume with or without a min-max octree), a particular number of
39dnl    color channels (1 or 3), and a particular number of material types.
40dnl    The definitions are a bit messy, but they keep the body of the
41dnl    procedure pretty clean.  Inlined procedures would be better but
42dnl    many compilers do not support them.
43dnl
44dnl    To produce a C source file, run this file through m4 with the
45dnl    following m4 macros defined:
46dnl
47dnl    FuncName			name of the C function to produce
48dnl    VolumeType		"rlevolume" or "rawvolume"
49dnl    ColorChannels		number of color channels (1 or 3)
50dnl    NumMaterials		number of materials (a small integer or "n"
51dnl				for a routine which handles any number)
52dnl
53dnl    OR, define "SourceFile" to be a file name of the form
54dnl         vp_compA????.c
55dnl    where the four wildcard characters (call them W, X, Y and Z)
56dnl    can have the following values:
57dnl         W: volume type ("C" for classified volumes, "R" for raw volumes)
58dnl         X: number of color channels ("1" for grayscale, "3" for RGB)
59dnl	    Y: number of materials ("1", "2", "N" for any number, "P" for
60dnl            callback procedure to replace the material shading model)
61dnl         Z: special options ("S" for rendering shadows, "G" for
62dnl            generating shadow buffer, "N" for nearest-neighbor filter,
63dnl	       "I" to use index volume, "B" for normal case (bilinear
64dnl            filter, no shadows, no index volume)
65dnl
66
67ifdef(`SourceFile', `
68    define(FuncNameStr,		`substr(SourceFile, 7, 5)')
69    define(VolumeTypeChar,	`substr(SourceFile, 8, 1)')
70    define(ColorChannels,	`substr(SourceFile, 9, 1)')
71    define(NumMaterials,	`substr(SourceFile, 10, 1)')
72    define(SpecialChar,		`substr(SourceFile, 11, 1)')
73
74    define(FuncName,		`VPComp'FuncNameStr())
75    ifelse(VolumeTypeChar, `C',
76	    `define(VolumeType,	`rlevolume')',
77	   VolumeTypeChar, `R',
78	    `define(VolumeType,	`rawvolume')')
79    ifelse(SpecialChar, `S', `
80#define USE_SHADOW_BUFFER
81	    define(ShadowBuffer)')
82    ifelse(SpecialChar, `G', `
83#define COMPUTE_SHADOW_BUFFER')
84    ifelse(SpecialChar, `I', `
85	    define(`IndexVolume')')
86')
87
88dnl Turn off unrolling of the run loop for the non-specialized routines.
89ifelse(NumMaterials, `N', `#undef UNROLL_RUN_LOOP',
90       NumMaterials, `P', `#undef UNROLL_RUN_LOOP')
91
92dnl
93dnl LoadTopLeft()
94dnl
95dnl Load, classify and shade the voxel above and left of the current pixel.
96dnl
97define(LoadTopLeft, `
98    ClassifyVox(top_opc, topRLEdata - voxel_istride);
99    ShadeVox(top, topRLEdata - voxel_istride)')
100
101dnl
102dnl LoadTopRight()
103dnl
104dnl Load, classify and shade the voxel above and right of the current pixel.
105dnl
106define(LoadTopRight, `
107    ClassifyVox(top_opc, topRLEdata);
108    ShadeVox(top, topRLEdata)')
109
110dnl
111dnl LoadBotLeft()
112dnl
113dnl Load, classify and shade the voxel below and left of the current pixel.
114dnl
115define(LoadBotLeft, `
116    ClassifyVox(bot_opc, botRLEdata - voxel_istride);
117    ShadeVox(bot, botRLEdata - voxel_istride)')
118
119dnl
120dnl LoadBotRight()
121dnl
122dnl Load, classify and shade the voxel below and right of the current pixel.
123dnl
124define(LoadBotRight, `
125    ClassifyVox(bot_opc, botRLEdata);
126    ShadeVox(bot, botRLEdata)')
127
128dnl
129dnl ShadeVox(scan, voxel)
130dnl
131dnl Shade the voxel pointed to by "voxel" and store the result in the
132dnl color variables for scanline scan (either "top" or "bot").
133dnl
134define(ShadeVox, `
135    ifelse(ColorChannels, 0, `', `
136    ComputeShadeIndex($2);
137    ComputeWeightIndex($2);
138    CallShader($1, $2);
139    shade_factor = $1_opc * slice_depth_cueing;
140    AttenuateColor($1);
141    AttenuateShadowColor($1)')')
142
143dnl
144dnl ComputeShadeIndex(voxel)
145dnl
146dnl Compute the offset into the shade and shadow tables for the specified
147dnl voxel.
148dnl
149define(ComputeShadeIndex,
150    ifelse(NumMaterials, `P', `',
151    `shade_index=MaterialCount()*ColorChannels()*ShortField($1,norm_offset)'))
152
153dnl
154dnl ComputeWeightIndex(voxel)
155dnl
156dnl Compute the offset into the material weight table for the specified
157dnl voxel.
158dnl
159define(ComputeWeightIndex,
160    ifelse(NumMaterials, `P', `', NumMaterials, `1', `',
161    `weight_index = MaterialCount() * ByteField($1, wgt_offset)'))
162
163dnl
164dnl MaterialCount()
165dnl
166dnl Return the number of materials, as a constant if possible.
167dnl
168define(MaterialCount,
169       `ifelse(NumMaterials, `N', `num_materials', NumMaterials)')
170
171dnl
172dnl CallShader(scan, voxel)
173dnl
174dnl Invoke the appropriate shader code to compute the color of the
175dnl voxel pointed to by "voxel". Store the result in the
176dnl color variables for scanline scan (either "top" or "bot").
177dnl
178ifelse(NumMaterials, `P',
179    `ifelse(ColorChannels, 1,
180	`define(CallShader, `shade_func($2, &($1_clr), client_data)')',
181	`define(CallShader, `shade_func($2, &($1_rclr), &($1_gclr), &($1_bclr),
182			     client_data)')')',
183    NumMaterials, `1',
184    `define(CallShader, `ShadeMaterial($1, 0, =)')',
185    NumMaterials, `2',
186    `define(CallShader, `
187	ShadeMaterial($1, 0, =);
188	ShadeMaterial($1, 1, +=)')',
189    `define(CallShader, `
190        ShadeMaterial($1, 0, =);
191        for (m = 1; m < num_materials; m++) {
192	     ShadeMaterial($1, m, +=);
193	}')')
194
195dnl Preprocessor definitions that cause local variables specific to the
196dnl shader to be allocated.
197ifelse(NumMaterials, 1, ,
198       NumMaterials, `P', `
199#define CALLBACK', `
200#define MULTIPLE_MATERIALS')
201
202dnl
203dnl ShadeMaterial(scan, material, op)
204dnl
205dnl Compute the contribution of material number "material" to the
206dnl color of the current voxel.  The result is stored in the color
207dnl variables for scanline scan (either "top" or "bot") using
208dnl operation op ("=" or "+=").
209dnl
210ifelse(ColorChannels, 1,
211    `define(ShadeMaterial, `
212	ShadeComponent($1_clr, $2, $3, 0);
213	ShadeShadowComponent($1_sclr, $2, $3, 0)')',
214    `define(ShadeMaterial, `
215	ShadeComponent($1_rclr, $2, $3, 0);
216	ShadeComponent($1_gclr, $2, $3, 1);
217	ShadeComponent($1_bclr, $2, $3, 2);
218	ShadeShadowComponent($1_rsclr, $2, $3, 0);
219	ShadeShadowComponent($1_gsclr, $2, $3, 1);
220	ShadeShadowComponent($1_bsclr, $2, $3, 2)')')
221
222dnl
223dnl ShadeComponent(dst, material, op, component)
224dnl
225dnl Compute the contribution of material number "material" to channel
226dnl number "component" (0 = red, 1 = green, 2 = blue) of the
227dnl color of the current voxel.  The result is stored in dst using
228dnl operator "op" ("=" or "+=").  This macro uses non-shadow lighting only.
229dnl
230define(ShadeComponent, `
231    $1 $3 ShadeLookup($2, $4) * MaterialWeight($2)')
232
233dnl
234dnl ShadeLookup(material, component)
235dnl
236dnl Compute the contribution of material number "material" to channel
237dnl number "component" (0 = red, 1 = green, 2 = blue) of the current
238dnl voxel (which determines the contents of shade_index).  Use the
239dnl value in the shading lookup table (which does not contain the
240dnl contribution of lights that may produce shadows).  The result is
241dnl returned.
242dnl
243define(ShadeLookup, `
244    shade_table[shade_index + ColorChannels*$1 + $2]')
245
246dnl
247dnl ShadeShadowComponent(dst, material, op, component)
248dnl
249dnl Compute the contribution of material number "material" to channel
250dnl number "component" (0 = red, 1 = green, 2 = blue) of the
251dnl color of the current voxel.  The result is stored in dst using
252dnl operator "op" ("=" or "+=").  This macro uses shadow lighting only.
253dnl
254ifdef(`ShadowBuffer',
255    `define(ShadeShadowComponent, `
256        $1 $3 ShadowLookup($2, $4) * MaterialWeight($2)')',
257    `define(ShadeShadowComponent, `')')
258
259dnl
260dnl ShadowLookup(material, component)
261dnl
262dnl Compute the contribution of material number "material" to channel
263dnl number "component" (0 = red, 1 = green, 2 = blue) of the current
264dnl voxel (which determines the contents of shade_index).  Use the
265dnl value in the shadow lookup table (which contains only the
266dnl contribution of lights that may produce shadows).  The result is
267dnl returned.
268dnl
269define(ShadowLookup, `
270    shadow_table[shade_index + ColorChannels*$1 + $2]')
271
272dnl
273dnl MaterialWeight(material)
274dnl
275dnl Return the weight associated with the specified material number
276dnl for the current voxel.
277dnl
278ifelse(
279    NumMaterials, 1,
280    `define(MaterialWeight, `(float)1.0')',
281
282    NumMaterials, `N',
283    `define(MaterialWeight, `
284	ifelse($1, 0,
285	`((num_materials > 1) ? weight_table[weight_index] : (float)1.0)',
286	`weight_table[weight_index + $1]')')',
287
288    `define(MaterialWeight, `weight_table[weight_index + $1]')')
289
290dnl
291dnl AttenuateColor(scan)
292dnl
293dnl Scale the color for the current voxel in scanline scan ("top" or "bot")
294dnl by the current shading factor (the voxel's opacity multiplied by
295dnl the depth cueing factor).  This macro uses non-shadow lighting only.
296dnl
297ifelse(ColorChannels, 1,
298    `define(AttenuateColor, `
299	$1_clr *= shade_factor')',
300    `define(AttenuateColor, `
301        $1_rclr *= shade_factor;
302	$1_gclr *= shade_factor;
303	$1_bclr *= shade_factor')')
304
305dnl
306dnl AttenuateShadowColor(scan)
307dnl
308dnl Scale the color for the current voxel in scanline scan ("top" or "bot")
309dnl by the current shading factor (the voxel's opacity multiplied by
310dnl the depth cueing factor).  This macro uses shadow lighting only.
311dnl
312ifdef(`ShadowBuffer',
313    `ifelse(ColorChannels, 1,
314        `define(AttenuateShadowColor, `
315	    $1_sclr *= shade_factor')',
316        `define(AttenuateShadowColor, `
317            $1_rsclr *= shade_factor;
318	    $1_gsclr *= shade_factor;
319	    $1_bsclr *= shade_factor')')',
320    `define(AttenuateShadowColor, `')')
321
322dnl
323dnl ClearAccum()
324dnl
325dnl Clear the voxel opacity/color accumulator.
326dnl
327define(ClearAccum, `
328       acc_opc = 0;
329       ClearColorAccum()')
330
331dnl
332dnl Accum(scan, wgt, op)
333dnl
334dnl Accumulate opacity and color for scan (either "top" or "bot")
335dnl weighted by one of the four weights ("TL", "BL", "TR" or "BR") using
336dnl operation op ("+=" or "=").
337dnl
338define(Accum, `
339       acc_opc $3 $1_opc * wgt$2;
340       AccumColor($1, $2, $3);
341       Trace($1, $2)')
342
343dnl
344dnl Composite()
345dnl
346dnl Composite the current resampled voxel.
347dnl
348define(Composite, `
349	COUNT_RESAMPLE;
350	if (acc_opc > min_opacity) {
351	    COUNT_COMPOSITE;
352	    iopc = ipixel->opcflt;
353#           ifndef SKIP_ERT
354	        ASSERT(iopc < max_opacity);
355#           endif
356	    iopc_inv = (float)1. - iopc;
357	    CompositeColor();
358	    iopc += acc_opc * iopc_inv;
359	    ipixel->opcflt = iopc;
360	    PrintTrace();
361#           ifndef SKIP_ERT
362	        if (iopc >= max_opacity) {
363		    ASSERT(ipixel->lnk == 0);
364		    ipixel->lnk = 1;
365	        }
366#           endif
367	}')
368
369dnl
370dnl NextIntPixel(c)
371dnl
372dnl Increment intermediate image pointer by c pixels.
373dnl
374ifdef(`ShadowBuffer',
375    `define(NextIntPixel, `ipixel += $1; shadow_pixel += $1')',
376    `define(NextIntPixel, `ipixel += $1')')
377
378dnl
379dnl Macros that depend on the number of color channels:
380dnl    IntPixelType		type of an intermediate image pixel
381dnl				(GrayIntPixel or RGBIntPixel)
382dnl    ClearColorAccum		clear the pixel color accumulator
383dnl    AccumColor(scan, wgt, op)
384dnl				accumulate color for scan (either "top"
385dnl				or "bot") weighted by one of the four
386dnl				weights ("TL", "BL", "TR" or "BR") using
387dnl				operation op ("+=" or "=")
388dnl    CompositeColor		composite color for current resampled voxel
389
390dnl shadow buffer (0 color channels)
391ifelse(ColorChannels, 0, `
392    define(IntPixelType, `GrayIntPixel')
393    define(ClearColorAccum, `')
394    define(AccumColor, `')
395    define(CompositeColor, `')')
396
397dnl grayscale image (1 color channel)
398ifelse(ColorChannels, 1, `
399#define GRAYSCALE
400    define(IntPixelType, `GrayIntPixel')
401    define(ClearColorAccum, `acc_clr = 0')
402    ifdef(`ShadowBuffer',
403        `define(AccumColor, `acc_clr $3 ($1_clr + $1_sclr *
404			    ((float)1.0 - shadow_pixel->opcflt)) * wgt$2')',
405        `define(AccumColor, `acc_clr $3 $1_clr * wgt$2')')
406    define(CompositeColor, `ipixel->clrflt += acc_clr * iopc_inv')')
407
408dnl RGB image (3 color channels)
409ifelse(ColorChannels, 3, `
410#define RGB
411    define(IntPixelType, `RGBIntPixel')
412    define(ClearColorAccum, `acc_rclr = acc_gclr = acc_bclr = 0')
413    ifdef(`ShadowBuffer',
414        `define(AccumColor, `
415	    acc_rclr $3 ($1_rclr + $1_rsclr *
416			 ((float)1.0 - shadow_pixel->opcflt)) * wgt$2;
417	    acc_gclr $3 ($1_gclr + $1_gsclr *
418			 ((float)1.0 - shadow_pixel->opcflt)) * wgt$2;
419	    acc_bclr $3 ($1_bclr + $1_bsclr *
420			 ((float)1.0 - shadow_pixel->opcflt)) * wgt$2')',
421        `define(AccumColor, `
422	    acc_rclr $3 $1_rclr * wgt$2;
423	    acc_gclr $3 $1_gclr * wgt$2;
424	    acc_bclr $3 $1_bclr * wgt$2')')
425    define(CompositeColor, `
426	ipixel->rclrflt += acc_rclr * iopc_inv;
427	ipixel->gclrflt += acc_gclr * iopc_inv;
428	ipixel->bclrflt += acc_bclr * iopc_inv')')
429
430dnl
431dnl Macros that depend on the type of volume data structure:
432dnl    VolumeArgs		list of function arguments for volume data
433dnl    VolumeArgsDecl		declaration of VolumeArgs
434dnl    NextNonZeroTopVoxel(c)	increment top voxel ptr. by c nonzero voxels
435dnl    NextZeroTopVoxel(c)	increment top voxel ptr. by c zero voxels
436dnl    NextNonZeroBotVoxel(c)	increment bot voxel ptr. by c nonzero voxels
437dnl    NextZeroBotVoxel(c)	increment bot voxel ptr. by c zero voxels
438dnl    ClassifyVox(opc, vox)	classify a voxel and store the result in opc
439dnl
440
441dnl rlevolume (run-length encoded volume)
442ifelse(VolumeType, `rlevolume', `
443#define RLEVOLUME
444	define(VolumeArgs, `run_lengths, voxel_data')
445	define(VolumeArgsDecl, `
446		unsigned char *run_lengths;	/* run lengths for slice */
447		void *voxel_data;		/* voxel data for slice */')
448	define(NextNonZeroTopVoxel, `topRLEdata += $1 * voxel_istride')
449	define(NextZeroTopVoxel, `')
450	define(NextNonZeroBotVoxel, `botRLEdata += $1 * voxel_istride')
451	define(NextZeroBotVoxel, `')
452	define(ClassifyVox,
453	       `$1 = opac_correct[ByteField($2, voxel_istride-1)]')')
454
455dnl rawvolume (3D volume array, optionally with a min-max octree)
456ifelse(VolumeType, `rawvolume', `
457#define RAWVOLUME
458	define(VolumeArgs, `voxel_data, voxel_istride, voxel_jstride')
459	define(VolumeArgsDecl, `
460		void *voxel_data;		/* voxel data for slice */
461		int voxel_istride;		/* strides for voxel data */
462		int voxel_jstride;')
463	define(NextNonZeroTopVoxel, `topRLEdata += $1 * voxel_istride')
464	define(NextZeroTopVoxel,    `topRLEdata += $1 * voxel_istride')
465	define(NextNonZeroBotVoxel, `botRLEdata += $1 * voxel_istride')
466	define(NextZeroBotVoxel,    `botRLEdata += $1 * voxel_istride')
467	define(ClassifyVox, `
468	    opac_param = VoxelField($2, param0_offset, param0_size);
469	    opacity = param0_table[opac_param];
470	    if (param1_size != 0) {
471		opac_param = VoxelField($2, param1_offset, param1_size);
472		opacity *= param1_table[opac_param];
473		if (param2_size != 0) {
474		    opac_param = VoxelField($2, param2_offset, param2_size);
475		    opacity *= param2_table[opac_param];
476		}
477	    }
478	    if (opacity > min_opacity) {
479		opacity_int = opacity*255.;
480		$1 = opac_correct[opacity_int];
481	    } else {
482		$1 = (float)0.;
483	    }')')
484
485dnl rlevolume + IndexVolume (experimental data structure that contains
486dnl a mapping from voxel coordinates to location of voxel in rlevolume)
487ifdef(`IndexVolume', `
488#define INDEX_VOLUME
489	define(`VolumeArgs', `run_lengths, voxel_data, voxel_index')
490	define(`VolumeArgsDecl', `
491		unsigned char *run_lengths;	/* run lengths for slice */
492		void *voxel_data;		/* voxel data for slice */
493		VoxelLocation *voxel_index;	/* index for ERT */')',
494
495	`
496#undef INDEX_VOLUME')
497
498dnl
499dnl Macros for rendering shadows:
500dnl    ShadowArgs		list of function arguments for shadow buffer
501dnl    ShadowArgsDecl		declaration of ShadowArgs
502dnl
503ifdef(`ShadowBuffer', `
504    define(ShadowArgs, `, shadow_buffer')
505    define(ShadowArgsDecl, `GrayIntPixel *shadow_buffer;')',`
506
507    define(ShadowArgs, `')
508    define(ShadowArgsDecl, `')')
509
510dnl
511dnl Macros for pixel tracing (a printout of all of the voxels and
512dnl filter weights that contribute to one intermediate image pixel).
513dnl
514
515dnl
516dnl NewPixel()
517dnl
518dnl Prepare to process a new pixel by clearing tracing buffers.
519dnl
520define(NewPixel, `
521#ifdef DEBUG
522    if (ipixel == trace_pixel_ptr) {
523	trace_opcTL = 0.; trace_opcBL = 0.; trace_opcTR = 0.; trace_opcBR = 0.;
524	trace_rsclrTL=0.; trace_rsclrBL=0.; trace_rsclrTR=0.; trace_rsclrBR=0.;
525	trace_rclrTL= 0.; trace_rclrBL= 0.; trace_rclrTR= 0.; trace_rclrBR= 0.;
526	trace_gclrTL= 0.; trace_gclrBL= 0.; trace_gclrTR= 0.; trace_gclrBR= 0.;
527	trace_bclrTL= 0.; trace_bclrBL= 0.; trace_bclrTR= 0.; trace_bclrBR= 0.;
528    }
529#endif
530')
531
532dnl
533dnl Trace(scan, wgt)
534dnl
535dnl Store voxel opacity and color from the specified scanline ("top" or "bot")
536dnl in the tracing buffer associated with the specified weight ("TR", "BR",
537dnl "TL", "BL").
538dnl
539define(Trace, `
540#ifdef DEBUG
541    if (ipixel == trace_pixel_ptr) {
542	trace_opc$2 = $1_opc;
543        ifelse(ColorChannels, 1,
544                    `trace_rclr$2 = $1_clr;',
545               ColorChannels, 3,
546                    `trace_rclr$2 = $1_rclr;
547                     trace_gclr$2 = $1_gclr;
548                     trace_bclr$2 = $1_bclr;')
549	ifdef(`ShadowBuffer',
550              `ifelse(ColorChannels, 1, `trace_rsclr$2 = $1_sclr;')')
551    }
552#endif
553')
554
555dnl
556dnl PrintTrace()
557dnl
558dnl Print one line of the trace.
559dnl
560define(PrintTrace, `
561#ifdef DEBUG
562    if (ipixel == trace_pixel_ptr) {
563#ifdef COMPUTE_SHADOW_BUFFER
564	printf("{%3d}  %3d %3d", k, icount-i-count, j);
565#else
566	printf("[%3d]  %3d %3d", k, icount-i-count, j);
567#endif
568	printf("  %3.0f %3.0f %3.0f",trace_opcTL*255.,trace_rclrTL,wgtTL*100.);
569	printf("  %3.0f %3.0f %3.0f",trace_opcBL*255.,trace_rclrBL,wgtBL*100.);
570	printf("  %3.0f %3.0f %3.0f",trace_opcTR*255.,trace_rclrTR,wgtTR*100.);
571	printf("  %3.0f %3.0f %3.0f",trace_opcBR*255.,trace_rclrBR,wgtBR*100.);
572	printf("  %3.0f %3.0f\n", iopc*255.,
573	       ifelse(ColorChannels, 3, `ipixel->rclrflt',
574		      ColorChannels, 1, `ipixel->clrflt',
575		      `0'));
576        ifdef(`ShadowBuffer', `
577	printf("              ");
578	printf("      %3.0f    ",trace_rsclrTL);
579	printf("      %3.0f    ",trace_rsclrBL);
580	printf("      %3.0f    ",trace_rsclrTR);
581	printf("      %3.0f    ",trace_rsclrBR);
582	printf("  %3.0f\n", shadow_pixel->opcflt * 255.);')
583        ifelse(ColorChannels, 3, `
584	printf("              ");
585	printf("      %3.0f    ",trace_gclrTL);
586	printf("      %3.0f    ",trace_gclrBL);
587	printf("      %3.0f    ",trace_gclrTR);
588	printf("      %3.0f    ",trace_gclrBR);
589	printf("      %3.0f\n", ipixel->gclrflt);
590	printf("              ");
591	printf("      %3.0f    ",trace_bclrTL);
592	printf("      %3.0f    ",trace_bclrBL);
593	printf("      %3.0f    ",trace_bclrTR);
594	printf("      %3.0f    ",trace_bclrBR);
595	printf("      %3.0f\n", ipixel->bclrflt);')
596    }
597#endif /* DEBUG */
598')
599
600/* codes indicating the types of a pair of runs in adjacent scanlines */
601#define ALL_ZERO	0	/* both runs are runs of zeros */
602#define TOP_NONZERO	1	/* run for top scanline has nonzero data */
603#define BOT_NONZERO	2	/* run for bottom scanline has nonzero data */
604#define ALL_NONZERO	3	/* both runs have nonzero data */
605
606/* codes indicating the types for the current left and right voxel pairs */
607#define ALL_ZERO__ALL_ZERO		((ALL_ZERO << 2) | ALL_ZERO)
608#define ALL_ZERO__TOP_NONZERO		((ALL_ZERO << 2) | TOP_NONZERO)
609#define ALL_ZERO__BOT_NONZERO		((ALL_ZERO << 2) | BOT_NONZERO)
610#define ALL_ZERO__ALL_NONZERO		((ALL_ZERO << 2) | ALL_NONZERO)
611#define TOP_NONZERO__ALL_ZERO		((TOP_NONZERO << 2) | ALL_ZERO)
612#define TOP_NONZERO__TOP_NONZERO	((TOP_NONZERO << 2) | TOP_NONZERO)
613#define TOP_NONZERO__BOT_NONZERO	((TOP_NONZERO << 2) | BOT_NONZERO)
614#define TOP_NONZERO__ALL_NONZERO	((TOP_NONZERO << 2) | ALL_NONZERO)
615#define BOT_NONZERO__ALL_ZERO		((BOT_NONZERO << 2) | ALL_ZERO)
616#define BOT_NONZERO__TOP_NONZERO	((BOT_NONZERO << 2) | TOP_NONZERO)
617#define BOT_NONZERO__BOT_NONZERO	((BOT_NONZERO << 2) | BOT_NONZERO)
618#define BOT_NONZERO__ALL_NONZERO	((BOT_NONZERO << 2) | ALL_NONZERO)
619#define ALL_NONZERO__ALL_ZERO		((ALL_NONZERO << 2) | ALL_ZERO)
620#define ALL_NONZERO__TOP_NONZERO	((ALL_NONZERO << 2) | TOP_NONZERO)
621#define ALL_NONZERO__BOT_NONZERO	((ALL_NONZERO << 2) | BOT_NONZERO)
622#define ALL_NONZERO__ALL_NONZERO	((ALL_NONZERO << 2) | ALL_NONZERO)
623
624#ifdef SKIP_ERT
625#define PIXEL_IS_OPAQUE(ipixel)	0
626#else
627#define PIXEL_IS_OPAQUE(ipixel)	((ipixel)->lnk != 0)
628#endif
629
630#ifdef STATISTICS
631extern int vpResampleCount;
632extern int vpCompositeCount;
633extern int vpERTSkipCount;
634extern int vpERTSkipAgainCount;
635extern int vpERTUpdateCount;
636extern int vpSpecialZeroSkipCount;
637extern int vpRunFragmentCount;
638#define COUNT_RESAMPLE		vpResampleCount++
639#define COUNT_COMPOSITE		vpCompositeCount++
640#define COUNT_ERT_SKIP		vpERTSkipCount++
641#define COUNT_ERT_SKIP_AGAIN	vpERTSkipAgainCount++
642#define COUNT_ERT_UPDATE	vpERTUpdateCount++
643#define COUNT_SPECIAL_ZERO_SKIP	vpSpecialZeroSkipCount++
644#define COUNT_RUN_FRAGMENT	vpRunFragmentCount++
645#else
646#define COUNT_RESAMPLE
647#define COUNT_COMPOSITE
648#define COUNT_ERT_SKIP
649#define COUNT_ERT_SKIP_AGAIN
650#define COUNT_ERT_UPDATE
651#define COUNT_SPECIAL_ZERO_SKIP
652#define COUNT_RUN_FRAGMENT
653#endif /* STATISTICS */
654
655/*
656 * FuncName
657 *
658 * Compositing routine for run-length encoded volume data slices.
659 * Decode and resample one slice of volume data, and composite
660 * it into the intermediate image.  The resampling filter is a bilirp.
661 */
662
663void
664FuncName (vpc, icount, jcount, k, slice_depth_cueing_dbl, intimage,
665	  weightTLdbl, weightBLdbl, weightTRdbl, weightBRdbl,
666	  VolumeArgs ShadowArgs)
667vpContext *vpc;			/* context */
668int icount;			/* slice size */
669int jcount;
670int k;				/* slice number */
671double slice_depth_cueing_dbl;	/* depth cueing factor for slice */
672IntPixelType *intimage;		/* intermediate image pixels */
673double weightTLdbl;		/* resampling weights */
674double weightBLdbl;
675double weightTRdbl;
676double weightBRdbl;
677VolumeArgsDecl
678ShadowArgsDecl
679{
680    int i, j;			/* voxel index in rotated object space */
681    IntPixelType *ipixel;	/* current intermediate image pixel */
682    IntPixelType *ipixel2;	/* another intermediate image pixel */
683    int update_interval;	/* # of pixels to skip when updating links */
684    float iopc;			/* intermediate pixel opacity (0-1) */
685    float iopc_inv;		/* 1-iopc */
686    float acc_opc;		/* accumulator for resampled voxel opacity */
687    float top_opc, bot_opc;	/* voxel opacity (top and bottom scanlines) */
688#ifdef NO_REUSE_VOXEL
689#define voxels_loaded	0
690#define CLEAR_VOXELS_LOADED
691#define SET_VOXELS_LOADED
692#else
693    int voxels_loaded;		/* if true, top/bot_opc contain valid
694				   data loaded during the last resample */
695#define CLEAR_VOXELS_LOADED	voxels_loaded = 0
696#define SET_VOXELS_LOADED	voxels_loaded = 1
697#endif
698    float wgtTL, wgtBL,		/* weights in the range 0..1 which give the */
699	  wgtTR, wgtBR;		/*   fractional contribution of the */
700    				/*   neighboring voxels to the current */
701    			        /*   intermediate image pixel */
702    unsigned char *topRLElen;	/* length of current run in top scanline */
703    unsigned char *botRLElen;	/* length of current run in bottom scanline */
704    char *topRLEdata;		/* data for current run in top scanline */
705    char *botRLEdata;		/* data for current run in bottom scanline */
706    int toprun_count;		/* number of voxels left in top run */
707    int botrun_count;		/* number of voxels left in bottom run */
708    int last_run_state;		/* run state code for last resample */
709    int run_state;		/* run state code for this resample */
710    int final_run_state;	/* run state code for end of scanline */
711    float min_opacity;		/* low opacity threshold */
712    float max_opacity;		/* high opacity threshold */
713    float slice_depth_cueing;	/* depth cueing factor for slice */
714    float *opac_correct;	/* opacity correction table */
715    int ert_skip_count;		/* number of pixels to skip for ERT */
716    int intermediate_width;	/* width of intermediate image in pixels */
717    int count;			/* voxels left in current run */
718    float *shade_table;		/* shade lookup table */
719    int norm_offset;		/* byte offset to shade table index in voxel */
720    int shade_index;		/* shade index */
721    float shade_factor;		/* attenuation factor for color
722				   (voxel opacity * depth cueing) */
723
724#ifdef MULTIPLE_MATERIALS
725    float *weight_table;	/* weight lookup table */
726    int wgt_offset;		/* byte offset to weight table index */
727    int weight_index;		/* weight index */
728    int m, num_materials;
729    float weight1, weight2;
730#endif /* MULTIPLE_MATERIALS */
731
732#ifdef GRAYSCALE
733    float acc_clr;		/* accumulator for resampled color */
734    float top_clr, bot_clr;	/* voxel color (top and bottom scanlines) */
735#endif /* GRAYSCALE */
736
737#ifdef RGB
738    float acc_rclr;		/* accumulator for resampled color */
739    float acc_gclr;
740    float acc_bclr;
741    float top_rclr;		/* voxel color (top and bottom scanlines) */
742    float bot_rclr;
743    float top_gclr;
744    float bot_gclr;
745    float top_bclr;
746    float bot_bclr;
747#endif
748
749#ifdef RLEVOLUME
750    int voxel_istride;		/* size of a voxel in bytes */
751#endif
752
753#ifdef RAWVOLUME
754    int use_octree;		/* if true then use the min-max octree */
755    MMOctreeLevel level_stack[VP_MAX_OCTREE_LEVELS];
756				/* stack for traversal of min-max octree */
757    int scans_left;		/* scanlines until next octree traversal */
758    int best_view_axis;		/* viewing axis */
759    unsigned char runlen_buf1[VP_MAX_VOLUME_DIM]; /* buffers for run lengths */
760    unsigned char runlen_buf2[VP_MAX_VOLUME_DIM];
761    unsigned char *top_len_base;/* first run length for top scanline */
762    unsigned char *bot_len_base;/* first run length for bottom scanline */
763    int opac_param;		/* parameter to opacity transfer function */
764    float opacity;		/* voxel opacity */
765    int opacity_int;		/* voxel opacity truncated to an integer */
766    int param0_offset;		/* offset to first parameter in voxel */
767    int param0_size;		/* size of first parameter in bytes */
768    float *param0_table;	/* lookup table for first parameter */
769    int param1_offset;		/* offset to second parameter in voxel */
770    int param1_size;		/* size of second parameter in bytes */
771    float *param1_table;	/* lookup table for second parameter */
772    int param2_offset;		/* offset to third parameter in voxel */
773    int param2_size;		/* size of third parameter in bytes */
774    float *param2_table;	/* lookup table for third parameter */
775#endif /* RAWVOLUME */
776
777#ifdef INDEX_VOLUME
778    unsigned char *scanline_topRLElen; /* first topRLElen in scanline */
779    unsigned char *scanline_botRLElen; /* first botRLElen in scanline */
780    char *scanline_topRLEdata;	/* first topRLEdata in scanline */
781    char *scanline_botRLEdata;	/* first botRLEdata in scanline */
782    VoxelLocation *top_voxel_index; /* voxel indexes for top scanline */
783    VoxelLocation *bot_voxel_index; /* voxel indexes for bot scanline */
784    VoxelLocation *vindex;
785    int next_i;			/* i coordinate of voxel to skip to */
786    int next_scan;		/* true if skipped to next scanline */
787#endif /* INDEX_VOLUME */
788
789#ifdef CALLBACK
790				/* shading callback function */
791#ifdef GRAYSCALE
792    void (*shade_func) ANSI_ARGS((void *, float *, void *));
793#endif
794#ifdef RGB
795    void (*shade_func) ANSI_ARGS((void *, float *, float *, float *, void *));
796#endif
797    void *client_data;		/* client data handle */
798#endif /* CALLBACK */
799
800#ifdef USE_SHADOW_BUFFER
801    float *shadow_table;	/* color lookup table for shadows */
802    int shadow_width;		/* width of shadow buffer */
803    GrayIntPixel *shadow_pixel; /* current shadow buffer pixel */
804#ifdef GRAYSCALE
805    float top_sclr, bot_sclr;	/* shadow color (top and bottom scanlines) */
806#endif /* GRAYSCALE */
807#ifdef RGB
808    float top_rsclr;		/* shadow color (top and bottom scanlines) */
809    float bot_rsclr;
810    float top_gsclr;
811    float bot_gsclr;
812    float top_bsclr;
813    float bot_bsclr;
814#endif
815#endif /* SHADOW_BUFFER */
816
817#ifdef DEBUG
818    float trace_opcTL, trace_opcBL, trace_opcTR, trace_opcBR;
819    float trace_rsclrTL, trace_rsclrBL, trace_rsclrTR, trace_rsclrBR;
820    float trace_rclrTL, trace_rclrBL, trace_rclrTR, trace_rclrBR;
821    float trace_gclrTL, trace_gclrBL, trace_gclrTR, trace_gclrBR;
822    float trace_bclrTL, trace_bclrBL, trace_bclrTR, trace_bclrBR;
823    IntPixelType *trace_pixel_ptr;
824
825#ifdef COMPUTE_SHADOW_BUFFER
826    int slice_u_int, shadow_slice_u_int;
827    int slice_v_int, shadow_slice_v_int;
828#endif
829#endif /* DEBUG */
830
831    DECLARE_HIRES_TIME(t0);
832    DECLARE_HIRES_TIME(t1);
833
834    /*******************************************************************
835     * Copy parameters from the rendering context into local variables.
836     *******************************************************************/
837
838    GET_HIRES_TIME(vpc, t0);
839
840    wgtTL = weightTLdbl;
841    wgtBL = weightBLdbl;
842    wgtTR = weightTRdbl;
843    wgtBR = weightBRdbl;
844    slice_depth_cueing = slice_depth_cueing_dbl;
845    min_opacity = vpc->min_opacity;
846    max_opacity = vpc->max_opacity;
847#ifdef USE_SHADOW_BUFFER
848    opac_correct = vpc->shadow_opac_correct;
849#else
850    opac_correct = vpc->affine_opac_correct;
851#endif
852#ifdef COMPUTE_SHADOW_BUFFER
853    intermediate_width = vpc->shadow_width;
854#else
855    intermediate_width = vpc->intermediate_width;
856#endif
857#ifdef USE_SHADOW_BUFFER
858    shadow_table = vpc->shadow_color_table;
859    shadow_width = vpc->shadow_width;
860    shadow_pixel = shadow_buffer;
861#endif
862    ipixel = intimage;
863    shade_table = vpc->shade_color_table;
864    norm_offset = vpc->field_offset[vpc->color_field];
865
866#ifdef MULTIPLE_MATERIALS
867    weight_table = vpc->shade_weight_table;
868    wgt_offset = vpc->field_offset[vpc->weight_field];
869    num_materials = vpc->num_materials;
870#endif /* MULTIPLE_MATERIALS */
871
872#ifdef RLEVOLUME
873    topRLEdata = voxel_data;
874    botRLEdata = voxel_data;
875    topRLElen = run_lengths;
876    botRLElen = run_lengths;
877    voxel_istride = vpc->rle_bytes_per_voxel;
878#endif /* RLEVOLUME */
879
880#ifdef RAWVOLUME
881    ASSERT(vpc->num_clsfy_params > 0);
882    ASSERT(vpc->num_clsfy_params < 3);
883    param0_offset = vpc->field_offset[vpc->param_field[0]];
884    param0_size = vpc->field_size[vpc->param_field[0]];
885    param0_table = vpc->clsfy_table[0];
886    if (vpc->num_clsfy_params > 1) {
887	param1_offset = vpc->field_offset[vpc->param_field[1]];
888	param1_size = vpc->field_size[vpc->param_field[1]];
889	param1_table = vpc->clsfy_table[1];
890    } else {
891	param1_offset = 0;
892	param1_size = 0;
893	param1_table = NULL;
894    }
895    if (vpc->num_clsfy_params > 2) {
896	param2_offset = vpc->field_offset[vpc->param_field[2]];
897	param2_size = vpc->field_size[vpc->param_field[2]];
898	param2_table = vpc->clsfy_table[2];
899    } else {
900	param2_offset = 0;
901	param2_size = 0;
902	param2_table = NULL;
903    }
904    if (vpc->mm_octree == NULL) {
905	use_octree = 0;
906    } else {
907	use_octree = 1;
908	best_view_axis = vpc->best_view_axis;
909	VPInitOctreeLevelStack(vpc, level_stack, best_view_axis, k);
910	scans_left = 0;
911	bot_len_base = runlen_buf1;
912    }
913#endif /* RAWVOLUME */
914
915#ifdef CALLBACK
916    shade_func = vpc->shade_func;
917    client_data = vpc->client_data;
918    ASSERT(shade_func != NULL);
919#endif
920
921#ifdef DEBUG
922    trace_pixel_ptr = 0;
923    if (vpc->trace_u >= 0 && vpc->trace_v >= 0) {
924#ifdef GRAYSCALE
925	trace_pixel_ptr = &vpc->int_image.gray_intim[vpc->trace_u +
926		      vpc->trace_v*vpc->intermediate_width];
927#endif
928#ifdef RGB
929	trace_pixel_ptr = &vpc->int_image.rgb_intim[vpc->trace_u +
930		      vpc->trace_v*vpc->intermediate_width];
931#endif
932#ifdef COMPUTE_SHADOW_BUFFER
933	slice_u_int = (int)ceil(vpc->shear_i * vpc->trace_shadow_k +
934				vpc->trans_i) - 1;
935	shadow_slice_u_int = (int)ceil(vpc->shadow_shear_i *
936			     vpc->trace_shadow_k + vpc->shadow_trans_i) - 1;
937	slice_v_int = (int)ceil(vpc->shear_j * vpc->trace_shadow_k
938				+ vpc->trans_j) - 1;
939	shadow_slice_v_int = (int)ceil(vpc->shadow_shear_j *
940			     vpc->trace_shadow_k + vpc->shadow_trans_j) - 1;
941	trace_pixel_ptr = &vpc->shadow_buffer[vpc->trace_u +
942		shadow_slice_u_int - slice_u_int +
943		(vpc->trace_v + shadow_slice_v_int -
944		slice_v_int)*vpc->shadow_width];
945#endif
946    }
947#endif /* DEBUG */
948
949    /*******************************************************************
950     * Loop over voxel scanlines.
951     *******************************************************************/
952
953    for (j = 0; j <= jcount; j++) {
954
955	/***************************************************************
956	 * Initialize counters and flags.
957	 ***************************************************************/
958
959	i = icount;
960	CLEAR_VOXELS_LOADED;
961	last_run_state = ALL_ZERO;
962
963#ifdef RAWVOLUME
964	botRLEdata = (char *)voxel_data + j*voxel_jstride;
965	topRLEdata = botRLEdata - voxel_jstride;
966	if (!use_octree) {
967	    if (j == 0) {
968		run_state = BOT_NONZERO;
969		toprun_count = icount+2;
970		botrun_count = icount;
971	    } else if (j == jcount) {
972		run_state = TOP_NONZERO;
973		toprun_count = icount;
974		botrun_count = icount+2;
975	    } else {
976		run_state = ALL_NONZERO;
977		toprun_count = icount;
978		botrun_count = icount;
979	    }
980	} else
981#endif /* RAWVOLUME */
982	if (j == 0) {
983	    run_state = BOT_NONZERO;
984	    toprun_count = icount+2;
985	    botrun_count = 0;
986	} else if (j == jcount) {
987	    run_state = TOP_NONZERO;
988	    toprun_count = 0;
989	    botrun_count = icount+2;
990	} else {
991	    run_state = ALL_NONZERO;
992	    toprun_count = 0;
993	    botrun_count = 0;
994	}
995
996#ifdef INDEX_VOLUME
997	scanline_topRLElen = topRLElen;
998	scanline_botRLElen = botRLElen;
999	scanline_topRLEdata = topRLEdata;
1000	scanline_botRLEdata = botRLEdata;
1001	if (j == 0) {
1002	    top_voxel_index = voxel_index;
1003	    bot_voxel_index = voxel_index;
1004	} else {
1005	    top_voxel_index = bot_voxel_index;
1006	    bot_voxel_index += icount;
1007	}
1008#endif /* INDEX_VOLUME */
1009
1010	/***************************************************************
1011	 * If the volume is not run-length encoded, use the min-max
1012	 * to find run lengths for the current voxel scanline.
1013	 ***************************************************************/
1014
1015#ifdef RAWVOLUME
1016	if (use_octree) {
1017	    top_len_base = bot_len_base;
1018	    if (scans_left == 0) {
1019		if (bot_len_base == runlen_buf1)
1020		    bot_len_base = runlen_buf2;
1021		else
1022		    bot_len_base = runlen_buf1;
1023
1024		GET_HIRES_TIME(vpc, t1);
1025		STORE_HIRES_TIME(vpc, VPTIMER_TRAVERSE_RUNS, t0, t1);
1026		COPY_HIRES_TIME(t0, t1);
1027
1028		scans_left = VPComputeScanRuns(vpc, level_stack, bot_len_base,
1029					       best_view_axis, j, icount);
1030
1031		GET_HIRES_TIME(vpc, t1);
1032		STORE_HIRES_TIME(vpc, VPTIMER_TRAVERSE_OCTREE, t0, t1);
1033		COPY_HIRES_TIME(t0, t1);
1034	    }
1035#ifdef DEBUG
1036	    if (j > 0)
1037		VPCheckRuns(vpc, top_len_base, best_view_axis, k, j-1);
1038	    if (j < jcount)
1039		VPCheckRuns(vpc, bot_len_base, best_view_axis, k, j);
1040#endif
1041	    scans_left--;
1042	    topRLElen = top_len_base;
1043	    botRLElen = bot_len_base;
1044	}
1045#endif /* RAWVOLUME */
1046
1047	/***************************************************************
1048	 * Loop over runs in the voxel scanline.
1049	 ***************************************************************/
1050
1051	Debug((vpc, VPDEBUG_COMPOSITE, "StartIScan(u=%d,v=%d)\n",
1052	       (((int)ipixel - (int)vpc->int_image.gray_intim) /
1053		sizeof(IntPixelType)) % vpc->intermediate_width,
1054	       (((int)ipixel - (int)vpc->int_image.gray_intim) /
1055		sizeof(IntPixelType)) / vpc->intermediate_width));
1056
1057#ifdef UNROLL_RUN_LOOP
1058	while (i > 0) {
1059#else
1060	while (i >= 0) {
1061#endif
1062	    /***********************************************************
1063	     * Skip over any empty runs at beginning of scanline.
1064	     ***********************************************************/
1065
1066	    if (last_run_state == ALL_ZERO) {
1067#ifndef UNROLL_RUN_LOOP
1068		if (i == 0) {
1069		    Debug((vpc, VPDEBUG_COMPOSITE, "ZeroSkip(1)End\n"));
1070		    NextIntPixel(1);
1071		    final_run_state = ALL_ZERO;
1072		    i = -1;
1073		    break;	/* scanline is done */
1074		}
1075#endif
1076
1077		/* check if this is the start of a new run */
1078		while (toprun_count == 0) {
1079		    toprun_count = *topRLElen++;
1080		    run_state ^= 1;
1081		}
1082		while (botrun_count == 0) {
1083		    botrun_count = *botRLElen++;
1084		    run_state ^= 2;
1085		}
1086		if (run_state == ALL_ZERO) {
1087		    COUNT_SPECIAL_ZERO_SKIP;
1088
1089		    /* find the union of the two runs of voxels */
1090		    count = MIN(toprun_count, botrun_count);
1091		    toprun_count -= count;
1092		    botrun_count -= count;
1093		    NextIntPixel(count);
1094		    NextZeroTopVoxel(count);
1095		    NextZeroBotVoxel(count);
1096		    i -= count;
1097		    ASSERT(i >= 0);
1098		    Debug((vpc, VPDEBUG_COMPOSITE, "ZeroSkip(%d)\n", count));
1099		    continue;
1100		}
1101	    }
1102
1103#ifndef SKIP_ERT
1104	    /***********************************************************
1105	     * Skip over opaque pixels (early-ray termination).
1106	     ***********************************************************/
1107
1108	    if ((ert_skip_count = ipixel->lnk) != 0) {
1109
1110		GET_HIRES_TIME(vpc, t1);
1111		STORE_HIRES_TIME(vpc, VPTIMER_TRAVERSE_RUNS, t0, t1);
1112		COPY_HIRES_TIME(t0, t1);
1113
1114		COUNT_ERT_SKIP;
1115
1116#ifndef UNROLL_RUN_LOOP
1117		if (i == 0) {
1118		    NextIntPixel(1);
1119		    final_run_state = last_run_state;
1120		    i = -1;
1121		    Debug((vpc, VPDEBUG_COMPOSITE, "ERTSkip(1)End\n"));
1122		    break;	/* scanline is done */
1123		}
1124#endif
1125
1126		/* find out how many pixels to skip */
1127		if (ert_skip_count < i &&
1128				(count = ipixel[ert_skip_count].lnk) != 0) {
1129		    /* follow pointer chain */
1130		    do {
1131			COUNT_ERT_SKIP_AGAIN;
1132			ert_skip_count += count;
1133		    } while (ert_skip_count < i &&
1134				 (count = ipixel[ert_skip_count].lnk) != 0);
1135
1136		    /* update some of the lnk pointers in the run of opaque
1137		       pixels; the more links we update the longer it will
1138		       take to perform the update, but we will potentially
1139		       save time in future slices by not having to follow
1140		       long pointer chains */
1141		    ipixel2 = ipixel;
1142		    update_interval = 1;
1143		    count = ert_skip_count - 1;
1144		    while (count > 0) {
1145			COUNT_ERT_UPDATE;
1146			ipixel2 += update_interval;
1147			if (count > 255)
1148			    ipixel2->lnk = 255;
1149			else
1150			    ipixel2->lnk = count;
1151			update_interval *= 2;
1152			count -= update_interval;
1153		    }
1154
1155		    /* update the current link */
1156		    COUNT_ERT_UPDATE;
1157		    if (ert_skip_count > 255)
1158			ert_skip_count = 255;
1159		    ipixel->lnk = ert_skip_count;
1160		}
1161
1162		/* skip over the opaque pixels */
1163		if (ert_skip_count > i)
1164		    ert_skip_count = i;
1165		Debug((vpc, VPDEBUG_COMPOSITE,"ERTSkip(%d)\n",ert_skip_count));
1166		NextIntPixel(ert_skip_count);
1167		CLEAR_VOXELS_LOADED;
1168
1169#ifdef INDEX_VOLUME
1170		/* compute i coordinate of voxel to skip to */
1171		next_i = icount - i + ert_skip_count;
1172		if (next_i == icount) {
1173		    next_i--;
1174		    next_scan = 1;
1175		} else {
1176		    next_scan = 0;
1177		}
1178
1179		/* skip over voxels in top scanline */
1180		vindex = &top_voxel_index[next_i];
1181		toprun_count = vindex->run_count;
1182		topRLElen = scanline_topRLElen + vindex->len_offset;
1183		if (vindex->data_offset & INDEX_RUN_IS_ZERO) {
1184		    run_state &= ~1;
1185		    topRLEdata = scanline_topRLEdata +
1186			(vindex->data_offset & ~INDEX_RUN_IS_ZERO);
1187		} else {
1188		    run_state |= 1;
1189		    topRLEdata = scanline_topRLEdata + vindex->data_offset;
1190		}
1191
1192		/* skip over voxels in bottom scanline */
1193		vindex = &bot_voxel_index[next_i];
1194		botrun_count = vindex->run_count;
1195		botRLElen = scanline_botRLElen + vindex->len_offset;
1196		if (vindex->data_offset & INDEX_RUN_IS_ZERO) {
1197		    run_state &= ~2;
1198		    botRLEdata = scanline_botRLEdata +
1199			(vindex->data_offset & ~INDEX_RUN_IS_ZERO);
1200		} else {
1201		    run_state |= 2;
1202		    botRLEdata = scanline_botRLEdata + vindex->data_offset;
1203		}
1204
1205		/* special case to skip over last voxel in scanline */
1206		if (next_scan) {
1207		    /* advance to beginning of next top scanline */
1208		    while (toprun_count == 0) {
1209			toprun_count = *topRLElen++;
1210			run_state ^= 1;
1211		    }
1212		    toprun_count--;
1213		    if (run_state & 1) {
1214			NextNonZeroTopVoxel(1);
1215		    } else {
1216			NextZeroTopVoxel(1);
1217		    }
1218
1219		    /* advance to beginning of next bottom scanline */
1220		    while (botrun_count == 0) {
1221			botrun_count = *botRLElen++;
1222			run_state ^= 2;
1223		    }
1224		    botrun_count--;
1225		    if (run_state & 2) {
1226			NextNonZeroBotVoxel(1);
1227		    } else {
1228			NextZeroBotVoxel(1);
1229		    }
1230		}
1231
1232#else /* !INDEX_VOLUME */
1233		/* skip over voxels in top scanline */
1234		count = ert_skip_count;
1235		for (;;) {
1236		    if (toprun_count >= count) {
1237			toprun_count -= count;
1238			if (run_state & 1) {
1239			    NextNonZeroTopVoxel(count);
1240			} else {
1241			    NextZeroTopVoxel(count);
1242			}
1243			break;
1244		    } else {
1245			count -= toprun_count;
1246			if (run_state & 1) {
1247			    NextNonZeroTopVoxel(toprun_count);
1248			} else {
1249			    NextZeroTopVoxel(toprun_count);
1250			}
1251			toprun_count = *topRLElen++;
1252			if (toprun_count == 0)
1253			    toprun_count = *topRLElen++;
1254			else
1255			    run_state ^= 1;
1256		    }
1257		}
1258
1259		/* skip over voxels in bottom scanline */
1260		count = ert_skip_count;
1261		for (;;) {
1262		    if (botrun_count >= count) {
1263			botrun_count -= count;
1264			if (run_state & 2) {
1265			    NextNonZeroBotVoxel(count);
1266			} else {
1267			    NextZeroBotVoxel(count);
1268			}
1269			break;
1270		    } else {
1271			count -= botrun_count;
1272			if (run_state & 2) {
1273			    NextNonZeroBotVoxel(botrun_count);
1274			} else {
1275			    NextZeroBotVoxel(botrun_count);
1276			}
1277			botrun_count = *botRLElen++;
1278			if (botrun_count == 0)
1279			    botrun_count = *botRLElen++;
1280			else
1281			    run_state ^= 2;
1282		    }
1283		}
1284#endif /* INDEX_VOLUME */
1285		i -= ert_skip_count;
1286		last_run_state = run_state;
1287		if (i == 0) {
1288#ifdef UNROLL_RUN_LOOP
1289		    break;
1290#else
1291		    if (last_run_state == ALL_ZERO) {
1292			NextIntPixel(1);
1293			final_run_state = ALL_ZERO;
1294			i = -1;
1295			Debug((vpc, VPDEBUG_COMPOSITE, "ZeroSkip(1)End\n"));
1296			break;	/* scanline is done */
1297		    }
1298		    if (ipixel->lnk != 0) {
1299			NextIntPixel(1);
1300			final_run_state = last_run_state;
1301			i = -1;
1302			Debug((vpc, VPDEBUG_COMPOSITE, "ERTSkip(1)End\n"));
1303			break;	/* scanline is done */
1304		    }
1305#endif /* UNROLL_RUN_LOOP */
1306		}
1307
1308		GET_HIRES_TIME(vpc, t1);
1309		STORE_HIRES_TIME(vpc, VPTIMER_ERT, t0, t1);
1310		COPY_HIRES_TIME(t0, t1);
1311	    }
1312	    ASSERT(ipixel->opcflt < max_opacity);
1313#endif /* SKIP_ERT */
1314
1315	    /***********************************************************
1316	     * Compute the length of the current run.
1317	     ***********************************************************/
1318
1319#ifndef UNROLL_RUN_LOOP
1320	    if (i == 0) {
1321		final_run_state = last_run_state;
1322		run_state = ALL_ZERO;
1323		i = -1;
1324		count = 1;
1325		Debug((vpc, VPDEBUG_COMPOSITE, "Run(1)End\n"));
1326	    } else {
1327#endif
1328		/* check if this is the start of a new run */
1329		while (toprun_count == 0) {
1330		    toprun_count = *topRLElen++;
1331		    run_state ^= 1;
1332		}
1333		while (botrun_count == 0) {
1334		    botrun_count = *botRLElen++;
1335		    run_state ^= 2;
1336		}
1337
1338		/* find the union of the two runs of voxels */
1339		count = MIN(toprun_count, botrun_count);
1340		toprun_count -= count;
1341		botrun_count -= count;
1342		i -= count;
1343		Debug((vpc, VPDEBUG_COMPOSITE, "Run(%d)\n", count));
1344		ASSERT(i >= 0);
1345#ifndef UNROLL_RUN_LOOP
1346	    }
1347#endif
1348	    COUNT_RUN_FRAGMENT;
1349
1350	    /***********************************************************
1351	     * composite the voxels in the current run.
1352	     ***********************************************************/
1353
1354	    GET_HIRES_TIME(vpc, t1);
1355	    STORE_HIRES_TIME(vpc, VPTIMER_TRAVERSE_RUNS, t0, t1);
1356	    COPY_HIRES_TIME(t0, t1);
1357
1358#ifdef SKIP_COMPOSITE
1359	    switch (run_state) {
1360	    case ALL_ZERO:
1361		NextIntPixel(count);
1362		NextZeroTopVoxel(count);
1363		NextZeroBotVoxel(count);
1364		count = 0;
1365		break;
1366	    case TOP_NONZERO:
1367		NextIntPixel(count);
1368		NextNonZeroTopVoxel(count);
1369		NextZeroBotVoxel(count);
1370		count = 0;
1371		break;
1372	    case BOT_NONZERO:
1373		NextIntPixel(count);
1374		NextZeroTopVoxel(count);
1375		NextNonZeroBotVoxel(count);
1376		count = 0;
1377		break;
1378	    case ALL_NONZERO:
1379		NextIntPixel(count);
1380		NextNonZeroTopVoxel(count);
1381		NextNonZeroBotVoxel(count);
1382		count = 0;
1383		break;
1384	    }
1385#else /* !SKIP_COMPOSITE */
1386#ifdef UNROLL_RUN_LOOP
1387	    /* this run contains pixels, so process them */
1388	    switch ((last_run_state << 2) | run_state) {
1389	    case ALL_ZERO__ALL_ZERO:
1390		/* no voxels contribute to the pixels in this run */
1391		NextIntPixel(count);
1392		NextZeroTopVoxel(count);
1393		NextZeroBotVoxel(count);
1394		count = 0;
1395		break;
1396	    case TOP_NONZERO__ALL_ZERO:
1397		/* only the top-left voxel contributes to the first
1398		   pixel of the run, and the rest are zero */
1399		if (!voxels_loaded) {
1400		    LoadTopLeft();
1401		}
1402		NewPixel();
1403		Accum(top, TL, =);
1404		Composite();
1405		NextIntPixel(count);
1406		NextZeroTopVoxel(count);
1407		NextZeroBotVoxel(count);
1408		count = 0;
1409		break;
1410	    case BOT_NONZERO__ALL_ZERO:
1411		/* only the bottom left voxel contributes to the first
1412		   pixel of the run, and the rest are zero */
1413		if (!voxels_loaded) {
1414		    LoadBotLeft();
1415		}
1416		NewPixel();
1417		Accum(bot, BL, =);
1418		Composite();
1419		NextIntPixel(count);
1420		NextZeroTopVoxel(count);
1421		NextZeroBotVoxel(count);
1422		count = 0;
1423		break;
1424	    case ALL_NONZERO__ALL_ZERO:
1425		/* the top and bottom left voxels contribute to the
1426		   first pixel of the run, and the rest are zero */
1427		if (!voxels_loaded) {
1428		    LoadTopLeft();
1429		    LoadBotLeft();
1430		}
1431		NewPixel();
1432		Accum(top, TL, =);
1433		Accum(bot, BL, +=);
1434		Composite();
1435		NextIntPixel(count);
1436		NextZeroTopVoxel(count);
1437		NextZeroBotVoxel(count);
1438		count = 0;
1439		break;
1440	    case ALL_ZERO__TOP_NONZERO:
1441		/* first pixel: only the top-right voxel contributes */
1442		LoadTopRight();
1443		NewPixel();
1444		Accum(top, TR, =);
1445		Composite();
1446		NextIntPixel(1);
1447		NextNonZeroTopVoxel(1);
1448		NextZeroBotVoxel(1);
1449		count--;
1450		SET_VOXELS_LOADED;
1451
1452		/* do the rest of the pixels in this run;
1453		   the top-left and top-right voxels contribute */
1454		while (count > 0) {
1455		    if (PIXEL_IS_OPAQUE(ipixel))
1456			break;
1457		    if (!voxels_loaded) {
1458			LoadTopLeft();
1459		    }
1460		    NewPixel();
1461		    Accum(top, TL, =);
1462		    LoadTopRight();
1463		    Accum(top, TR, +=);
1464		    Composite();
1465		    NextIntPixel(1);
1466		    NextNonZeroTopVoxel(1);
1467		    NextZeroBotVoxel(1);
1468		    count--;
1469		    SET_VOXELS_LOADED;
1470		}
1471		break;
1472	    case TOP_NONZERO__TOP_NONZERO:
1473		/* do the pixels in this run; the top-left and
1474		   top-right voxels contribute */
1475		while (count > 0) {
1476		    if (PIXEL_IS_OPAQUE(ipixel))
1477			break;
1478		    if (!voxels_loaded) {
1479			LoadTopLeft();
1480		    }
1481		    NewPixel();
1482		    Accum(top, TL, =);
1483		    LoadTopRight();
1484		    Accum(top, TR, +=);
1485		    Composite();
1486		    NextIntPixel(1);
1487		    NextNonZeroTopVoxel(1);
1488		    NextZeroBotVoxel(1);
1489		    count--;
1490		    SET_VOXELS_LOADED;
1491		}
1492		break;
1493	    case BOT_NONZERO__TOP_NONZERO:
1494		/* first pixel: bottom-left and top-right voxels
1495		   contribute */
1496		if (!voxels_loaded) {
1497		    LoadBotLeft();
1498		}
1499		NewPixel();
1500		Accum(bot, BL, =);
1501		LoadTopRight();
1502		Accum(top, TR, +=);
1503		Composite();
1504		NextIntPixel(1);
1505		NextNonZeroTopVoxel(1);
1506		NextZeroBotVoxel(1);
1507		count--;
1508		SET_VOXELS_LOADED;
1509
1510		/* do the rest of the pixels in this run;
1511		   the top-left and top-right voxels contribute */
1512		while (count > 0) {
1513		    if (PIXEL_IS_OPAQUE(ipixel))
1514			break;
1515		    if (!voxels_loaded) {
1516			LoadTopLeft();
1517		    }
1518		    NewPixel();
1519		    Accum(top, TL, =);
1520		    LoadTopRight();
1521		    Accum(top, TR, +=);
1522		    Composite();
1523		    NextIntPixel(1);
1524		    NextNonZeroTopVoxel(1);
1525		    NextZeroBotVoxel(1);
1526		    count--;
1527		    SET_VOXELS_LOADED;
1528		}
1529		break;
1530	    case ALL_NONZERO__TOP_NONZERO:
1531		/* first pixel: top-left, bottom-left and top-right voxels
1532		   contribute */
1533		if (!voxels_loaded) {
1534		    LoadTopLeft();
1535		    LoadBotLeft();
1536		}
1537		NewPixel();
1538		Accum(top, TL, =);
1539		Accum(bot, BL, +=);
1540		LoadTopRight();
1541		Accum(top, TR, +=);
1542		Composite();
1543		NextIntPixel(1);
1544		NextNonZeroTopVoxel(1);
1545		NextZeroBotVoxel(1);
1546		count--;
1547		SET_VOXELS_LOADED;
1548
1549		/* do the rest of the pixels in this run;
1550		   the top-left and top-right voxels contribute */
1551		while (count > 0) {
1552		    if (PIXEL_IS_OPAQUE(ipixel))
1553			break;
1554		    if (!voxels_loaded) {
1555			LoadTopLeft();
1556		    }
1557		    NewPixel();
1558		    Accum(top, TL, =);
1559		    LoadTopRight();
1560		    Accum(top, TR, +=);
1561		    Composite();
1562		    NextIntPixel(1);
1563		    NextNonZeroTopVoxel(1);
1564		    NextZeroBotVoxel(1);
1565		    count--;
1566		    SET_VOXELS_LOADED;
1567		}
1568		break;
1569	    case ALL_ZERO__BOT_NONZERO:
1570		/* first pixel: only the bottom-right voxel contributes */
1571		LoadBotRight();
1572		NewPixel();
1573		Accum(bot, BR, =);
1574		Composite();
1575		NextIntPixel(1);
1576		NextZeroTopVoxel(1);
1577		NextNonZeroBotVoxel(1);
1578		count--;
1579		SET_VOXELS_LOADED;
1580
1581		/* do the rest of the pixels in this run;
1582		   bottom-left and bottom-right voxels contribute */
1583		while (count > 0) {
1584		    if (PIXEL_IS_OPAQUE(ipixel))
1585			break;
1586		    if (!voxels_loaded) {
1587			LoadBotLeft();
1588		    }
1589		    NewPixel();
1590		    Accum(bot, BL, =);
1591		    LoadBotRight();
1592		    Accum(bot, BR, +=);
1593		    Composite();
1594		    NextIntPixel(1);
1595		    NextZeroTopVoxel(1);
1596		    NextNonZeroBotVoxel(1);
1597		    count--;
1598		    SET_VOXELS_LOADED;
1599		}
1600		break;
1601	    case TOP_NONZERO__BOT_NONZERO:
1602		/* first pixel: top-left and bottom-right voxels contribute */
1603		if (!voxels_loaded) {
1604		    LoadTopLeft();
1605		}
1606		NewPixel();
1607		Accum(top, TL, =);
1608		LoadBotRight();
1609		Accum(bot, BR, +=);
1610		Composite();
1611		NextIntPixel(1);
1612		NextZeroTopVoxel(1);
1613		NextNonZeroBotVoxel(1);
1614		count--;
1615		SET_VOXELS_LOADED;
1616
1617		/* do the rest of the pixels in this run;
1618		   bottom-left and bottom-right voxels contribute */
1619		while (count > 0) {
1620		    if (PIXEL_IS_OPAQUE(ipixel))
1621			break;
1622		    if (!voxels_loaded) {
1623			LoadBotLeft();
1624		    }
1625		    NewPixel();
1626		    Accum(bot, BL, =);
1627		    LoadBotRight();
1628		    Accum(bot, BR, +=);
1629		    Composite();
1630		    NextIntPixel(1);
1631		    NextZeroTopVoxel(1);
1632		    NextNonZeroBotVoxel(1);
1633		    count--;
1634		    SET_VOXELS_LOADED;
1635		}
1636		break;
1637	    case BOT_NONZERO__BOT_NONZERO:
1638		/* do the pixels in this run; bottom-left and
1639		   bottom-right voxels contribute */
1640		while (count > 0) {
1641		    if (PIXEL_IS_OPAQUE(ipixel))
1642			break;
1643		    if (!voxels_loaded) {
1644			LoadBotLeft();
1645		    }
1646		    NewPixel();
1647		    Accum(bot, BL, =);
1648		    LoadBotRight();
1649		    Accum(bot, BR, +=);
1650		    Composite();
1651		    NextIntPixel(1);
1652		    NextZeroTopVoxel(1);
1653		    NextNonZeroBotVoxel(1);
1654		    count--;
1655		    SET_VOXELS_LOADED;
1656		}
1657		break;
1658	    case ALL_NONZERO__BOT_NONZERO:
1659		/* first pixel: top-left, bottom-left and bottom-right
1660		   voxels contribute */
1661		if (!voxels_loaded) {
1662		    LoadTopLeft();
1663		    LoadBotLeft();
1664		}
1665		NewPixel();
1666		Accum(top, TL, =);
1667		Accum(bot, BL, +=);
1668		LoadBotRight();
1669		Accum(bot, BR, +=);
1670		Composite();
1671		NextIntPixel(1);
1672		NextZeroTopVoxel(1);
1673		NextNonZeroBotVoxel(1);
1674		count--;
1675		SET_VOXELS_LOADED;
1676
1677		/* do the rest of the pixels in this run;
1678		   bottom-left and bottom-right voxels contribute */
1679		while (count > 0) {
1680		    if (PIXEL_IS_OPAQUE(ipixel))
1681			break;
1682		    if (!voxels_loaded) {
1683			LoadBotLeft();
1684		    }
1685		    NewPixel();
1686		    Accum(bot, BL, =);
1687		    LoadBotRight();
1688		    Accum(bot, BR, +=);
1689		    Composite();
1690		    NextIntPixel(1);
1691		    NextZeroTopVoxel(1);
1692		    NextNonZeroBotVoxel(1);
1693		    count--;
1694		    SET_VOXELS_LOADED;
1695		}
1696		break;
1697	    case ALL_ZERO__ALL_NONZERO:
1698		/* first pixel: top-right and bottom-right voxels contribute */
1699		LoadTopRight();
1700		LoadBotRight();
1701		NewPixel();
1702		Accum(top, TR, =);
1703		Accum(bot, BR, +=);
1704		Composite();
1705		NextIntPixel(1);
1706		NextNonZeroTopVoxel(1);
1707		NextNonZeroBotVoxel(1);
1708		count--;
1709		SET_VOXELS_LOADED;
1710
1711		/* do the rest of the pixels in this run;
1712		   all four voxels contribute */
1713		while (count > 0) {
1714		    if (PIXEL_IS_OPAQUE(ipixel))
1715			break;
1716		    if (!voxels_loaded) {
1717			LoadTopLeft();
1718			LoadBotLeft();
1719		    }
1720		    NewPixel();
1721		    Accum(top, TL, =);
1722		    Accum(bot, BL, +=);
1723		    LoadTopRight();
1724		    LoadBotRight();
1725		    Accum(top, TR, +=);
1726		    Accum(bot, BR, +=);
1727		    Composite();
1728		    NextIntPixel(1);
1729		    NextNonZeroTopVoxel(1);
1730		    NextNonZeroBotVoxel(1);
1731		    count--;
1732		    SET_VOXELS_LOADED;
1733		}
1734		break;
1735	    case TOP_NONZERO__ALL_NONZERO:
1736		/* first pixel: top-left, top-right and bottom-right
1737		   voxels contribute */
1738		if (!voxels_loaded) {
1739		    LoadTopLeft();
1740		}
1741		NewPixel();
1742		Accum(top, TL, =);
1743		LoadTopRight();
1744		LoadBotRight();
1745		Accum(top, TR, +=);
1746		Accum(bot, BR, +=);
1747		Composite();
1748		NextIntPixel(1);
1749		NextNonZeroTopVoxel(1);
1750		NextNonZeroBotVoxel(1);
1751		count--;
1752		SET_VOXELS_LOADED;
1753
1754		/* do the rest of the pixels in this run;
1755		   all four voxels contribute */
1756		while (count > 0) {
1757		    if (PIXEL_IS_OPAQUE(ipixel))
1758			break;
1759		    if (!voxels_loaded) {
1760			LoadTopLeft();
1761			LoadBotLeft();
1762		    }
1763		    NewPixel();
1764		    Accum(top, TL, =);
1765		    Accum(bot, BL, +=);
1766		    LoadTopRight();
1767		    LoadBotRight();
1768		    Accum(top, TR, +=);
1769		    Accum(bot, BR, +=);
1770		    Composite();
1771		    NextIntPixel(1);
1772		    NextNonZeroTopVoxel(1);
1773		    NextNonZeroBotVoxel(1);
1774		    count--;
1775		    SET_VOXELS_LOADED;
1776		}
1777		break;
1778	    case BOT_NONZERO__ALL_NONZERO:
1779		/* first pixel: bottom-left, top-right and bottom-right
1780		   voxels contribute */
1781		if (!voxels_loaded) {
1782		    LoadBotLeft();
1783		}
1784		NewPixel();
1785		Accum(bot, BL, =);
1786		LoadTopRight();
1787		LoadBotRight();
1788		Accum(top, TR, +=);
1789		Accum(bot, BR, +=);
1790		Composite();
1791		NextIntPixel(1);
1792		NextNonZeroTopVoxel(1);
1793		NextNonZeroBotVoxel(1);
1794		count--;
1795		SET_VOXELS_LOADED;
1796
1797		/* do the rest of the pixels in this run;
1798		   all four voxels contribute */
1799		while (count > 0) {
1800		    if (PIXEL_IS_OPAQUE(ipixel))
1801			break;
1802		    if (!voxels_loaded) {
1803			LoadTopLeft();
1804			LoadBotLeft();
1805		    }
1806		    NewPixel();
1807		    Accum(top, TL, =);
1808		    Accum(bot, BL, +=);
1809		    LoadTopRight();
1810		    LoadBotRight();
1811		    Accum(top, TR, +=);
1812		    Accum(bot, BR, +=);
1813		    Composite();
1814		    NextIntPixel(1);
1815		    NextNonZeroTopVoxel(1);
1816		    NextNonZeroBotVoxel(1);
1817		    count--;
1818		    SET_VOXELS_LOADED;
1819		}
1820		break;
1821	    case ALL_NONZERO__ALL_NONZERO:
1822		/* do the pixels in this run; all four voxels contribute */
1823		while (count > 0) {
1824		    if (PIXEL_IS_OPAQUE(ipixel))
1825			break;
1826		    if (!voxels_loaded) {
1827			LoadTopLeft();
1828			LoadBotLeft();
1829		    }
1830		    NewPixel();
1831		    Accum(top, TL, =);
1832		    Accum(bot, BL, +=);
1833		    LoadTopRight();
1834		    LoadBotRight();
1835		    Accum(top, TR, +=);
1836		    Accum(bot, BR, +=);
1837		    Composite();
1838		    NextIntPixel(1);
1839		    NextNonZeroTopVoxel(1);
1840		    NextNonZeroBotVoxel(1);
1841		    count--;
1842		    SET_VOXELS_LOADED;
1843		}
1844		break;
1845	    default:
1846		VPBug("illegal value for run states in compositing loop");
1847	    }
1848#else /* UNROLL_RUN_LOOP */
1849	    /* this run contains pixels, so process them */
1850	    while (count > 0) {
1851		if (last_run_state == ALL_ZERO && run_state == ALL_ZERO) {
1852		    NextIntPixel(count);
1853		    if (i != -1) {
1854			NextZeroTopVoxel(count);
1855			NextZeroBotVoxel(count);
1856		    }
1857		    count = 0;
1858		    break;
1859		}
1860		if (ipixel->lnk != 0)
1861		    break;
1862		NewPixel();
1863		ClearAccum();
1864		if (last_run_state & TOP_NONZERO) {
1865		    if (!voxels_loaded) {
1866			LoadTopLeft();
1867		    }
1868		    Accum(top, TL, +=);
1869		}
1870		if (last_run_state & BOT_NONZERO) {
1871		    if (!voxels_loaded) {
1872			LoadBotLeft();
1873		    }
1874		    Accum(bot, BL, +=);
1875		}
1876		if (run_state & TOP_NONZERO) {
1877		    LoadTopRight();
1878		    Accum(top, TR, +=);
1879		    NextNonZeroTopVoxel(1);
1880		} else {
1881		    if (i != -1) {
1882			NextZeroTopVoxel(1);
1883		    }
1884		}
1885		if (run_state & BOT_NONZERO) {
1886		    LoadBotRight();
1887		    Accum(bot, BR, +=);
1888		    NextNonZeroBotVoxel(1);
1889		} else {
1890		    if (i != -1) {
1891			NextZeroBotVoxel(1);
1892		    }
1893		}
1894		Composite();
1895		NextIntPixel(1);
1896		count--;
1897		SET_VOXELS_LOADED;
1898		last_run_state = run_state;
1899	    }
1900#endif /* UNROLL_RUN_LOOP */
1901
1902	    GET_HIRES_TIME(vpc, t1);
1903	    STORE_HIRES_TIME(vpc, VPTIMER_PROCESS_VOXELS, t0, t1);
1904	    COPY_HIRES_TIME(t0, t1);
1905
1906	    if (count > 0) {
1907		Debug((vpc, VPDEBUG_COMPOSITE, "Backup(%d)\n", count));
1908		toprun_count += count;
1909		botrun_count += count;
1910		i += count;
1911	    }
1912#endif /* SKIP_COMPOSITE */
1913
1914	    /***********************************************************
1915	     * Go on to next voxel run.
1916	     ***********************************************************/
1917
1918	    last_run_state = run_state;
1919	} /* while (i > 0) */
1920
1921	/***************************************************************
1922	 * Finish processing voxel scanline and go on to next one.
1923	 ***************************************************************/
1924
1925#ifdef UNROLL_RUN_LOOP
1926	ASSERT(i == 0);
1927#else
1928	ASSERT(i == -1);
1929#endif
1930
1931#ifndef SKIP_COMPOSITE
1932#ifdef UNROLL_RUN_LOOP
1933	/* do the last pixel (to the right of the last voxel) */
1934	if (last_run_state != ALL_ZERO && !PIXEL_IS_OPAQUE(ipixel)) {
1935	    /* last voxels are nonzero and the pixel is not opaque yet
1936	       so there is work to be done */
1937	    Debug((vpc, VPDEBUG_COMPOSITE, "Run(1)End\n"));
1938	    switch (last_run_state) {
1939	    case TOP_NONZERO:
1940		/* only the top-left voxel contributes */
1941		if (!voxels_loaded) {
1942		    LoadTopLeft();
1943		}
1944		NewPixel();
1945		Accum(top, TL, =);
1946		Composite();
1947		break;
1948	    case BOT_NONZERO:
1949		/* only the bottom left voxel contributes */
1950		if (!voxels_loaded) {
1951		    LoadBotLeft();
1952		}
1953		NewPixel();
1954		Accum(bot, BL, =);
1955		Composite();
1956		break;
1957	    case ALL_NONZERO:
1958		/* the top and bottom left voxels contribute */
1959		if (!voxels_loaded) {
1960		    LoadTopLeft();
1961		    LoadBotLeft();
1962		}
1963		NewPixel();
1964		Accum(top, TL, =);
1965		Accum(bot, BL, +=);
1966		Composite();
1967		break;
1968	    default:
1969		VPBug("illegal value for run state at end of scanline");
1970	    }
1971	} else if (last_run_state == ALL_ZERO) {
1972	    Debug((vpc, VPDEBUG_COMPOSITE, "ZeroSkip(1)End\n"));
1973	} else {
1974	    Debug((vpc, VPDEBUG_COMPOSITE, "ERTSkip(1)End\n"));
1975	}
1976#endif /* UNROLL_RUN_LOOP */
1977#endif /* SKIP_COMPOSITE */
1978
1979#ifndef UNROLL_RUN_LOOP
1980	run_state = final_run_state;
1981#endif
1982	/* skip over any zero-length runs remaining in this scanline */
1983	if (j != 0 && ((run_state & 1) == 0)) {
1984	    toprun_count = *topRLElen++;
1985	    ASSERT(toprun_count == 0);
1986	}
1987	if (j != jcount && ((run_state & 2) == 0)) {
1988	    botrun_count = *botRLElen++;
1989	    ASSERT(botrun_count == 0);
1990	}
1991
1992	/* go to next intermediate image scanline */
1993#ifdef UNROLL_RUN_LOOP
1994	ipixel += intermediate_width - icount;
1995#ifdef USE_SHADOW_BUFFER
1996	shadow_pixel += shadow_width - icount;
1997#endif
1998#else /* UNROLL_RUN_LOOP */
1999	ipixel += intermediate_width - (icount+1);
2000#ifdef USE_SHADOW_BUFFER
2001	shadow_pixel += shadow_width - (icount+1);
2002#endif
2003#endif /* UNROLL_RUN_LOOP */
2004
2005	Debug((vpc, VPDEBUG_COMPOSITE, "ScanDone\n"));
2006    } /* for j */
2007
2008    /***************************************************************
2009     * Finish processing the voxel slice.
2010     ***************************************************************/
2011
2012    GET_HIRES_TIME(vpc, t1);
2013    STORE_HIRES_TIME(vpc, VPTIMER_TRAVERSE_RUNS, t0, t1);
2014
2015    Debug((vpc, VPDEBUG_COMPOSITE, "SliceDone\n"));
2016}
2017