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