vtkFixedPointVolumeRayCastCompositeGOShadeHelper.cxx 34.1 KB
Newer Older
1 2 3 4 5 6
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkFixedPointVolumeRayCastCompositeGOShadeHelper.cxx
  Language:  C++

7
  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
8 9 10
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

11 12
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 14 15 16 17 18
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkFixedPointVolumeRayCastCompositeGOShadeHelper.h"

#include "vtkCommand.h"
19 20
#include "vtkDataArray.h"
#include "vtkFixedPointRayCastImage.h"
21
#include "vtkFixedPointVolumeRayCastMapper.h"
22
#include "vtkImageData.h"
23 24 25 26 27
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkVolume.h"
#include "vtkVolumeProperty.h"

Sean McBride's avatar
Sean McBride committed
28
#include <cmath>
29 30 31 32

vtkStandardNewMacro(vtkFixedPointVolumeRayCastCompositeGOShadeHelper);

// Construct a new vtkFixedPointVolumeRayCastCompositeGOShadeHelper with default values
33 34
vtkFixedPointVolumeRayCastCompositeGOShadeHelper::
  vtkFixedPointVolumeRayCastCompositeGOShadeHelper() = default;
35 36

// Destruct a vtkFixedPointVolumeRayCastCompositeGOShadeHelper - clean up any memory used
37 38
vtkFixedPointVolumeRayCastCompositeGOShadeHelper::
  ~vtkFixedPointVolumeRayCastCompositeGOShadeHelper() = default;
39 40

// This method is used when the interpolation type is nearest neighbor and
41 42 43
// the data has one component and scale == 1.0 and shift == 0.0. In the inner
// loop we get the data value as an unsigned short, and use this index to
// lookup a color and opacity for this sample. We then composite this into
44 45 46 47
// the color computed so far along the ray, and check if we can terminate at
// this point (if the accumulated opacity is higher than some threshold).
// Finally we move on to the next sample along the ray.
template <class T>
48 49
void vtkFixedPointCompositeGOShadeHelperGenerateImageOneSimpleNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
50 51 52 53 54 55 56
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeNN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeShadeNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();

57
  for (k = 0; k < numSteps; k++)
58
  {
59
    if (k)
60
    {
61
      VTKKWRCHelper_MoveToNextSampleGOShadeNN();
62
    }
63

64
    VTKKWRCHelper_SpaceLeapCheck();
65 66 67
    VTKKWRCHelper_CroppingCheckNN(pos);
    unsigned short val = static_cast<unsigned short>(((*dptr)));
    unsigned char mag = *magPtr;
68

69 70
    VTKKWRCHelper_LookupColorGOUS(
      colorTable[0], scalarOpacityTable[0], gradientOpacityTable[0], val, mag, tmp);
71

72
    if (tmp[3])
73
    {
74
      unsigned short normal = *dirPtr;
75 76
      VTKKWRCHelper_LookupShading(diffuseShadingTable[0], specularShadingTable[0], normal, tmp);
      VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
77
    }
78
  }
79

80
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
81 82 83 84 85 86 87 88 89 90 91
  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is used when the interpolation type is nearest neighbor and
// the data has one component. In the inner loop we get the data value as
// an unsigned short using the scale/shift, and use this index to lookup
// a color and opacity for this sample. We then composite this into the
// color computed so far along the ray, and check if we can terminate at
// this point (if the accumulated opacity is higher than some threshold).
// Finally we move on to the next sample along the ray.
template <class T>
92 93
void vtkFixedPointCompositeGOShadeHelperGenerateImageOneNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
94 95 96 97 98 99
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeNN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeShadeNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();
100

101
  for (k = 0; k < numSteps; k++)
102
  {
103
    if (k)
104
    {
105
      VTKKWRCHelper_MoveToNextSampleGOShadeNN();
106
    }
107

108
    VTKKWRCHelper_SpaceLeapCheck();
109 110 111
    VTKKWRCHelper_CroppingCheckNN(pos);
    unsigned short val = static_cast<unsigned short>(((*dptr) + shift[0]) * scale[0]);
    unsigned char mag = *magPtr;
112

113 114
    VTKKWRCHelper_LookupColorGOUS(
      colorTable[0], scalarOpacityTable[0], gradientOpacityTable[0], val, mag, tmp);
115

116
    if (tmp[3])
117
    {
118
      unsigned short normal = *dirPtr;
119 120
      VTKKWRCHelper_LookupShading(diffuseShadingTable[0], specularShadingTable[0], normal, tmp);
      VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
121
    }
122
  }
123

124
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
125 126 127 128 129 130 131
  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is used when the interpolation type is nearest neighbor and
// the data has two components which are not considered independent. In the
// inner loop we compute the two unsigned short index values from the data
// values (using the scale/shift). We use the first index to lookup a color,
132 133
// and we use the second index to look up the opacity. We then composite
// the color into the color computed so far along this ray, and check to
134 135 136
// see if we can terminate here (if the opacity accumulated exceed some
// threshold). Finally we move to the next sample along the ray.
template <class T>
137 138
void vtkFixedPointCompositeGOShadeHelperGenerateImageTwoDependentNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
139 140 141 142 143 144
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeNN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeShadeNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();
145

146
  for (k = 0; k < numSteps; k++)
147
  {
148
    if (k)
149
    {
150
      VTKKWRCHelper_MoveToNextSampleGOShadeNN();
151
    }
152 153

    VTKKWRCHelper_SpaceLeapCheck();
154
    VTKKWRCHelper_CroppingCheckNN(pos);
155
    unsigned short val[2];
156

157 158
    val[1] = static_cast<unsigned short>(((*(dptr + 1)) + shift[1]) * scale[1]);
    unsigned char mag = *magPtr;
159

160 161 162
    tmp[3] =
      (scalarOpacityTable[0][val[1]] * gradientOpacityTable[0][mag] + 0x3fff) >> (VTKKW_FP_SHIFT);
    if (!tmp[3])
163
    {
164
      continue;
165
    }
166

167 168
    val[0] = static_cast<unsigned short>(((*(dptr)) + shift[0]) * scale[0]);
    unsigned short normal = *dirPtr;
169

170 171 172 173 174 175
    tmp[0] = static_cast<unsigned short>(
      (colorTable[0][3 * val[0]] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[1] = static_cast<unsigned short>(
      (colorTable[0][3 * val[0] + 1] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[2] = static_cast<unsigned short>(
      (colorTable[0][3 * val[0] + 2] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
176

177
    VTKKWRCHelper_LookupShading(diffuseShadingTable[0], specularShadingTable[0], normal, tmp);
178

179
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
180
  }
181

182
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
183 184 185 186 187 188 189 190 191 192
  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is used when the interpolation type is nearest neighbor and
// the data has four components which are not considered independent . This
// means that the first three components directly represent color, and this
// data must be of unsigned char type. In the inner loop we directly access
// the four data values (no scale/shift is needed). The first three are the
// color of this sample and the fourth is used to look up an opacity in the
// scalar opacity transfer function. We then composite this color into the
193 194
// color we have accumulated so far along the ray, and check if we can
// terminate here (if our accumulated opacity has exceed some threshold).
195 196
// Finally we move onto the next sample along the ray.
template <class T>
197 198
void vtkFixedPointCompositeGOShadeHelperGenerateImageFourDependentNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
199 200 201 202 203 204 205
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeNN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeShadeNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();

206
  for (k = 0; k < numSteps; k++)
207
  {
208
    if (k)
209
    {
210
      VTKKWRCHelper_MoveToNextSampleGOShadeNN();
211
    }
212 213

    VTKKWRCHelper_SpaceLeapCheck();
214
    VTKKWRCHelper_CroppingCheckNN(pos);
215
    unsigned short val[4];
216

217
    val[3] = static_cast<unsigned short>(((*(dptr + 3)) + shift[3]) * scale[3]);
218

219
    unsigned char mag = *magPtr;
220

221 222 223
    tmp[3] =
      (scalarOpacityTable[0][val[3]] * gradientOpacityTable[0][mag] + 0x3fff) >> (VTKKW_FP_SHIFT);
    if (!tmp[3])
224
    {
225
      continue;
226
    }
227

228 229 230
    val[0] = *(dptr);
    val[1] = *(dptr + 1);
    val[2] = *(dptr + 2);
231
    unsigned short normal = *dirPtr;
232

233 234 235
    tmp[0] = (val[0] * tmp[3] + 0x7f) >> (8);
    tmp[1] = (val[1] * tmp[3] + 0x7f) >> (8);
    tmp[2] = (val[2] * tmp[3] + 0x7f) >> (8);
236

237
    VTKKWRCHelper_LookupShading(diffuseShadingTable[0], specularShadingTable[0], normal, tmp);
238

239
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
240
  }
241

242
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
243 244 245 246 247 248 249 250 251 252
  VTKKWRCHelper_IncrementAndLoopEnd();
}

// This method is used when the interpolation type is nearest neighbor and
// the data has more than one component and the components are considered to
// be independent. In the inner loop we access each component value, using
// the scale/shift to turn the data value into an unsigned short index. We
// then lookup the color/opacity for each component and combine them according
// to the weighting value for each component. We composite this resulting
// color into the color already accumulated for this ray, and we check
luz.paz's avatar
luz.paz committed
253
// whether we can terminate here (if the accumulated opacity exceeds some
254 255
// threshold). Finally we increment to the next sample on the ray.
template <class T>
256 257
void vtkFixedPointCompositeGOShadeHelperGenerateImageIndependentNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
258
{
259
  VTKKWRCHelper_InitializeWeights();
260 261 262 263
  VTKKWRCHelper_InitializationAndLoopStartGOShadeNN();
  VTKKWRCHelper_InitializeCompositeMultiNN();
  VTKKWRCHelper_InitializeCompositeShadeNN();
  VTKKWRCHelper_InitializeCompositeGONN();
264

265
  for (k = 0; k < numSteps; k++)
266
  {
267
    if (k)
268
    {
269
      VTKKWRCHelper_MoveToNextSampleGOShadeNN();
270
    }
271

272
    VTKKWRCHelper_CroppingCheckNN(pos);
273
    unsigned short normal[4];
274 275
    unsigned char mag[4] = { 1, 1, 1, 1 };
    for (c = 0; c < components; c++)
276
    {
277 278 279
      val[c] = static_cast<unsigned short>(((*(dptr + c)) + shift[c]) * scale[c]);
      mag[c] = static_cast<unsigned short>(*(magPtr + c));
      normal[c] = *(dirPtr + c);
280
    }
281

282 283 284
    VTKKWRCHelper_LookupAndCombineIndependentColorsGOShadeUS(colorTable, scalarOpacityTable,
      gradientOpacityTable, diffuseShadingTable, specularShadingTable, val, mag, normal, weights,
      components, tmp);
285

286
    if (tmp[3])
287
    {
288
      VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
289
    }
290
  }
291

292
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
293 294 295
  VTKKWRCHelper_IncrementAndLoopEnd();
}

296 297
// This method is used when the interpolation type is linear and the data
// has one component and scale = 1.0 and shift = 0.0. In the inner loop we
298
// get the data value for the eight cell corners (if we have changed cells)
299 300
// as an unsigned short (the range must be right and we don't need the
// scale/shift). We compute our weights within the cell according to our
301
// fractional position within the cell, apply trilinear interpolation to
302 303 304 305
// compute the index, and use this index to lookup a color and opacity for
// this sample. We then composite this into the color computed so far along
// the ray, and check if we can terminate at this point (if the accumulated
// opacity is higher than some threshold). Finally we move on to the next
306 307
// sample along the ray.
template <class T>
308 309
void vtkFixedPointCompositeGOShadeHelperGenerateImageOneSimpleTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
310 311 312 313 314 315
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeTrilin();
  VTKKWRCHelper_InitializeCompositeOneTrilin();
  VTKKWRCHelper_InitializeCompositeOneShadeTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
316

317 318
  int needToSampleDirection = 0;
  int needToSampleMagnitude = 0;
319
  for (k = 0; k < numSteps; k++)
320
  {
321
    if (k)
322
    {
323
      mapper->FixedPointIncrement(pos, dir);
324
    }
325 326

    VTKKWRCHelper_SpaceLeapCheck();
327
    VTKKWRCHelper_CroppingCheckTrilin(pos);
328

329 330
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
331
    {
332 333 334
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
335

336 337
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellScalarValuesSimple(dptr);
338

339 340
      magPtrABCD = gradientMag[spos[2]] + spos[0] * mInc[0] + spos[1] * mInc[1];
      magPtrEFGH = gradientMag[spos[2] + 1] + spos[0] * mInc[0] + spos[1] * mInc[1];
341
      needToSampleMagnitude = 1;
342

343 344
      dirPtrABCD = gradientDir[spos[2]] + spos[0] * dInc[0] + spos[1] * dInc[1];
      dirPtrEFGH = gradientDir[spos[2] + 1] + spos[0] * dInc[0] + spos[1] * dInc[1];
345
      needToSampleDirection = 1;
346
    }
347

348 349
    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalar(val);
350

351
    tmp[3] = scalarOpacityTable[0][val];
352
    if (!tmp[3])
353
    {
354
      continue;
355
    }
356

357
    if (needToSampleMagnitude)
358
    {
359
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
360
      needToSampleMagnitude = 0;
361
    }
362
    VTKKWRCHelper_InterpolateMagnitude(mag);
363 364
    tmp[3] = (tmp[3] * gradientOpacityTable[0][mag] + 0x7fff) >> VTKKW_FP_SHIFT;
    if (!tmp[3])
365
    {
366
      continue;
367
    }
368

369 370 371 372 373 374
    tmp[0] =
      static_cast<unsigned short>((colorTable[0][3 * val] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[1] = static_cast<unsigned short>(
      (colorTable[0][3 * val + 1] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[2] = static_cast<unsigned short>(
      (colorTable[0][3 * val + 2] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
375

376
    if (needToSampleDirection)
377
    {
378
      VTKKWRCHelper_GetCellDirectionValues(dirPtrABCD, dirPtrEFGH);
379
      needToSampleDirection = 0;
380
    }
381

382 383
    VTKKWRCHelper_InterpolateShading(diffuseShadingTable[0], specularShadingTable[0], tmp);
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
384
  }
385

386
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
387 388 389
  VTKKWRCHelper_IncrementAndLoopEnd();
}

390 391
// This method is used when the interpolation type is linear and the data
// has one component and scale != 1.0 or shift != 0.0. In the inner loop we
392
// get the data value for the eight cell corners (if we have changed cells)
393 394 395 396 397 398
// as an unsigned short (we use the scale/shift to ensure the correct range).
// We compute our weights within the cell according to our fractional position
// within the cell, apply trilinear interpolation to compute the index, and use
// this index to lookup a color and opacity for this sample. We then composite
// this into the color computed so far along the ray, and check if we can
// terminate at this point (if the accumulated opacity is higher than some
399 400
// threshold). Finally we move on to the next sample along the ray.
template <class T>
401 402
void vtkFixedPointCompositeGOShadeHelperGenerateImageOneTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
403 404 405 406 407 408
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeTrilin();
  VTKKWRCHelper_InitializeCompositeOneTrilin();
  VTKKWRCHelper_InitializeCompositeOneShadeTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
409

410 411
  int needToSampleDirection = 0;
  int needToSampleMagnitude = 0;
412
  for (k = 0; k < numSteps; k++)
413
  {
414
    if (k)
415
    {
416
      mapper->FixedPointIncrement(pos, dir);
417
    }
418

419
    VTKKWRCHelper_SpaceLeapCheck();
420
    VTKKWRCHelper_CroppingCheckTrilin(pos);
421

422 423
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
424
    {
425 426 427
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
428

429 430
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellScalarValues(dptr, scale[0], shift[0]);
431

432 433
      magPtrABCD = gradientMag[spos[2]] + spos[0] * mInc[0] + spos[1] * mInc[1];
      magPtrEFGH = gradientMag[spos[2] + 1] + spos[0] * mInc[0] + spos[1] * mInc[1];
434
      needToSampleMagnitude = 1;
435

436 437
      dirPtrABCD = gradientDir[spos[2]] + spos[0] * dInc[0] + spos[1] * dInc[1];
      dirPtrEFGH = gradientDir[spos[2] + 1] + spos[0] * dInc[0] + spos[1] * dInc[1];
438
      needToSampleDirection = 1;
439
    }
440

441 442
    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalar(val);
443

444
    tmp[3] = scalarOpacityTable[0][val];
445
    if (!tmp[3])
446
    {
447
      continue;
448
    }
449

450
    if (needToSampleMagnitude)
451
    {
452
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
453
      needToSampleMagnitude = 0;
454
    }
455
    VTKKWRCHelper_InterpolateMagnitude(mag);
456 457
    tmp[3] = (tmp[3] * gradientOpacityTable[0][mag] + 0x7fff) >> VTKKW_FP_SHIFT;
    if (!tmp[3])
458
    {
459
      continue;
460
    }
461

462
    if (needToSampleDirection)
463
    {
464
      VTKKWRCHelper_GetCellDirectionValues(dirPtrABCD, dirPtrEFGH);
465
      needToSampleDirection = 0;
466
    }
467

468 469 470 471 472 473
    tmp[0] =
      static_cast<unsigned short>((colorTable[0][3 * val] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[1] = static_cast<unsigned short>(
      (colorTable[0][3 * val + 1] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[2] = static_cast<unsigned short>(
      (colorTable[0][3 * val + 2] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
474

475 476
    VTKKWRCHelper_InterpolateShading(diffuseShadingTable[0], specularShadingTable[0], tmp);
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
477
  }
478

479
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
480 481 482
  VTKKWRCHelper_IncrementAndLoopEnd();
}

483
// This method is used when the interpolation type is linear, the data has
484
// two components and the components are not considered independent. In the
485 486 487 488 489 490 491 492 493
// inner loop we get the data value for the eight cell corners (if we have
// changed cells) for both components as an unsigned shorts (we use the
// scale/shift to ensure the correct range). We compute our weights within
// the cell according to our fractional position within the cell, and apply
// trilinear interpolation to compute the two index value. We use the first
// index to lookup a color and the second to look up an opacity for this sample.
// We then composite this into the color computed so far along the ray, and
// check if we can terminate at this point (if the accumulated opacity is
// higher than some threshold). Finally we move on to the next sample along
494 495
// the ray.
template <class T>
496 497
void vtkFixedPointCompositeGOShadeHelperGenerateImageTwoDependentTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
498 499 500 501 502 503
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeTrilin();
  VTKKWRCHelper_InitializeCompositeMultiTrilin();
  VTKKWRCHelper_InitializeCompositeOneShadeTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
504

505 506
  int needToSampleDirection = 0;
  int needToSampleMagnitude = 0;
507
  for (k = 0; k < numSteps; k++)
508
  {
509
    if (k)
510
    {
511
      mapper->FixedPointIncrement(pos, dir);
512
    }
513

514
    VTKKWRCHelper_SpaceLeapCheck();
515
    VTKKWRCHelper_CroppingCheckTrilin(pos);
516

517 518
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
519
    {
520 521 522
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
523

524 525
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 0, scale[0], shift[0]);
526

527
      dptr++;
528
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 1, scale[1], shift[1]);
529

530 531
      magPtrABCD = gradientMag[spos[2]] + spos[0] * mInc[0] + spos[1] * mInc[1];
      magPtrEFGH = gradientMag[spos[2] + 1] + spos[0] * mInc[0] + spos[1] * mInc[1];
532
      needToSampleMagnitude = 1;
533

534 535
      dirPtrABCD = gradientDir[spos[2]] + spos[0] * dInc[0] + spos[1] * dInc[1];
      dirPtrEFGH = gradientDir[spos[2] + 1] + spos[0] * dInc[0] + spos[1] * dInc[1];
536
      needToSampleDirection = 1;
537
    }
538

539
    VTKKWRCHelper_ComputeWeights(pos);
540
    VTKKWRCHelper_InterpolateScalarComponent(val, c, 2);
541

542
    tmp[3] = scalarOpacityTable[0][val[1]];
543
    if (!tmp[3])
544
    {
545
      continue;
546
    }
547

548
    if (needToSampleMagnitude)
549
    {
550
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
551
      needToSampleMagnitude = 0;
552
    }
553
    VTKKWRCHelper_InterpolateMagnitude(mag);
554 555
    tmp[3] = (0x7fff + tmp[3] * gradientOpacityTable[0][mag]) >> (VTKKW_FP_SHIFT);
    if (!tmp[3])
556
    {
557
      continue;
558
    }
559

560
    if (needToSampleDirection)
561
    {
562
      VTKKWRCHelper_GetCellDirectionValues(dirPtrABCD, dirPtrEFGH);
563
      needToSampleDirection = 0;
564
    }
565

566 567 568 569 570 571
    tmp[0] = static_cast<unsigned short>(
      (colorTable[0][3 * val[0]] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[1] = static_cast<unsigned short>(
      (colorTable[0][3 * val[0] + 1] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
    tmp[2] = static_cast<unsigned short>(
      (colorTable[0][3 * val[0] + 2] * tmp[3] + 0x7fff) >> (VTKKW_FP_SHIFT));
572

573
    VTKKWRCHelper_InterpolateShading(diffuseShadingTable[0], specularShadingTable[0], tmp);
574

575
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
576
  }
577

578
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
579 580 581
  VTKKWRCHelper_IncrementAndLoopEnd();
}

582
// This method is used when the interpolation type is linear, the data has
583
// four components and the components are not considered independent. In the
584
// inner loop we get the data value for the eight cell corners (if we have
585 586
// changed cells) for all components as an unsigned shorts (we don't have to
// use the scale/shift because only unsigned char data is supported for four
587 588 589
// component data when the components are not independent). We compute our
// weights within the cell according to our fractional position within the cell,
// and apply trilinear interpolation to compute a value for each component. We
590
// use the first three directly as the color of the sample, and the fourth is
591 592 593
// used to look up an opacity for this sample. We then composite this into the
// color computed so far along the ray, and check if we can terminate at this
// point (if the accumulated opacity is higher than some threshold). Finally we
594 595
// move on to the next sample along the ray.
template <class T>
596 597
void vtkFixedPointCompositeGOShadeHelperGenerateImageFourDependentTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
598 599 600 601 602 603
{
  VTKKWRCHelper_InitializationAndLoopStartGOShadeTrilin();
  VTKKWRCHelper_InitializeCompositeMultiTrilin();
  VTKKWRCHelper_InitializeCompositeOneShadeTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
604

605 606
  int needToSampleDirection = 0;
  int needToSampleMagnitude = 0;
607
  for (k = 0; k < numSteps; k++)
608
  {
609
    if (k)
610
    {
611
      mapper->FixedPointIncrement(pos, dir);
612
    }
613

614
    VTKKWRCHelper_SpaceLeapCheck();
615
    VTKKWRCHelper_CroppingCheckTrilin(pos);
616

617 618
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
619
    {
620 621 622
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
623

624 625
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, 0);
626

627
      dptr++;
628
      VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, 1);
629

630
      dptr++;
631
      VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, 2);
632

633
      dptr++;
634
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 3, scale[3], shift[3]);
635

636 637
      magPtrABCD = gradientMag[spos[2]] + spos[0] * mInc[0] + spos[1] * mInc[1];
      magPtrEFGH = gradientMag[spos[2] + 1] + spos[0] * mInc[0] + spos[1] * mInc[1];
638
      needToSampleMagnitude = 1;
639

640 641
      dirPtrABCD = gradientDir[spos[2]] + spos[0] * dInc[0] + spos[1] * dInc[1];
      dirPtrEFGH = gradientDir[spos[2] + 1] + spos[0] * dInc[0] + spos[1] * dInc[1];
642
      needToSampleDirection = 1;
643
    }
644

645
    VTKKWRCHelper_ComputeWeights(pos);
646
    VTKKWRCHelper_InterpolateScalarComponent(val, c, components);
647

648
    tmp[3] = scalarOpacityTable[0][val[3]];
649
    if (!tmp[3])
650
    {
651
      continue;
652
    }
653

654
    if (needToSampleMagnitude)
655
    {
656
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
657
      needToSampleMagnitude = 0;
658
    }
659
    VTKKWRCHelper_InterpolateMagnitude(mag);
660 661
    tmp[3] = (0x7fff + tmp[3] * gradientOpacityTable[0][mag]) >> (VTKKW_FP_SHIFT);
    if (!tmp[3])
662
    {
663
      continue;
664
    }
665

666
    if (needToSampleDirection)
667
    {
668
      VTKKWRCHelper_GetCellDirectionValues(dirPtrABCD, dirPtrEFGH);
669
      needToSampleDirection = 0;
670
    }
671

672 673 674
    tmp[0] = (val[0] * tmp[3] + 0x7f) >> 8;
    tmp[1] = (val[1] * tmp[3] + 0x7f) >> 8;
    tmp[2] = (val[2] * tmp[3] + 0x7f) >> 8;
675

676 677
    VTKKWRCHelper_InterpolateShading(diffuseShadingTable[0], specularShadingTable[0], tmp);
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
678
  }
679

680
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
681 682 683
  VTKKWRCHelper_IncrementAndLoopEnd();
}

684 685 686
// This method is used when the interpolation type is linear, the data has
// more than one component and the components are considered independent. In
// the inner loop we get the data value for the eight cell corners (if we have
687
// changed cells) for all components as an unsigned shorts (we have to use the
688 689 690 691 692 693 694
// scale/shift to ensure that we obtained unsigned short indices) We compute our
// weights within the cell according to our fractional position within the cell,
// and apply trilinear interpolation to compute a value for each component. We
// look up a color/opacity for each component and blend them according to the
// component weights. We then composite this resulting color into the
// color computed so far along the ray, and check if we can terminate at this
// point (if the accumulated opacity is higher than some threshold). Finally we
695 696
// move on to the next sample along the ray.
template <class T>
697 698
void vtkFixedPointCompositeGOShadeHelperGenerateImageIndependentTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
699
{
700
  VTKKWRCHelper_InitializeWeights();
701 702 703 704 705
  VTKKWRCHelper_InitializationAndLoopStartGOShadeTrilin();
  VTKKWRCHelper_InitializeCompositeMultiTrilin();
  VTKKWRCHelper_InitializeCompositeMultiShadeTrilin();
  VTKKWRCHelper_InitializeCompositeMultiGOTrilin();

706
  for (k = 0; k < numSteps; k++)
707
  {
708
    if (k)
709
    {
710
      mapper->FixedPointIncrement(pos, dir);
711
    }
712

713
    VTKKWRCHelper_CroppingCheckTrilin(pos);
714

715 716
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
717
    {
718 719 720
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
721

722 723
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 0, scale[0], shift[0]);
724

725
      dptr++;
726
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 1, scale[1], shift[1]);
727

728
      if (components > 2)
729
      {
730
        dptr++;
731 732
        VTKKWRCHelper_GetCellComponentScalarValues(dptr, 2, scale[2], shift[2]);
        if (components > 3)
733
        {
734
          dptr++;
735
          VTKKWRCHelper_GetCellComponentScalarValues(dptr, 3, scale[3], shift[3]);
736
        }
737
      }
738

739 740 741
      magPtrABCD = gradientMag[spos[2]] + spos[0] * mInc[0] + spos[1] * mInc[1];
      magPtrEFGH = gradientMag[spos[2] + 1] + spos[0] * mInc[0] + spos[1] * mInc[1];
      VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 0);
742

743 744
      magPtrABCD++;
      magPtrEFGH++;
745
      VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 1);
746

747
      if (components > 2)
748
      {
749 750
        magPtrABCD++;
        magPtrEFGH++;
751 752
        VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 2);
        if (components > 3)
753
        {
754 755
          magPtrABCD++;
          magPtrEFGH++;
756
          VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 3);
757
        }
758
      }
759

760 761 762
      dirPtrABCD = gradientDir[spos[2]] + spos[0] * dInc[0] + spos[1] * dInc[1];
      dirPtrEFGH = gradientDir[spos[2] + 1] + spos[0] * dInc[0] + spos[1] * dInc[1];
      VTKKWRCHelper_GetCellComponentDirectionValues(dirPtrABCD, dirPtrEFGH, 0);
763 764 765

      dirPtrABCD++;
      dirPtrEFGH++;
766
      VTKKWRCHelper_GetCellComponentDirectionValues(dirPtrABCD, dirPtrEFGH, 1);
767