vtkFixedPointVolumeRayCastCompositeGOHelper.cxx 30 KB
Newer Older
1 2 3 4 5 6
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkFixedPointVolumeRayCastCompositeGOHelper.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 "vtkFixedPointVolumeRayCastCompositeGOHelper.h"

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

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

vtkStandardNewMacro(vtkFixedPointVolumeRayCastCompositeGOHelper);

// Construct a new vtkFixedPointVolumeRayCastCompositeGOHelper with default values
34 35
vtkFixedPointVolumeRayCastCompositeGOHelper::vtkFixedPointVolumeRayCastCompositeGOHelper() =
  default;
36 37

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

// This method is used when the interpolation type is nearest neighbor and
42 43 44
// 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
45 46 47 48
// 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>
49 50
void vtkFixedPointCompositeGOHelperGenerateImageOneSimpleNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
51 52 53 54 55
{
  VTKKWRCHelper_InitializationAndLoopStartGONN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();
56

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

64
    VTKKWRCHelper_SpaceLeapCheck();
65
    VTKKWRCHelper_CroppingCheckNN(pos);
66 67

    unsigned short val = static_cast<unsigned short>(((*dptr)));
68
    unsigned char mag = *magPtr;
69

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

73
    if (tmp[3])
74
    {
75
      VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
76
    }
77
  }
78

79
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
80 81 82 83 84 85 86 87 88 89 90
  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>
91 92
void vtkFixedPointCompositeGOHelperGenerateImageOneNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
93 94 95 96 97
{
  VTKKWRCHelper_InitializationAndLoopStartGONN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();
98

99
  for (k = 0; k < numSteps; k++)
100
  {
101
    if (k)
102
    {
103
      VTKKWRCHelper_MoveToNextSampleGONN();
104
    }
105

106
    VTKKWRCHelper_SpaceLeapCheck();
107
    VTKKWRCHelper_CroppingCheckNN(pos);
108

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

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

115
    if (tmp[3])
116
    {
117
      VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
118
    }
119
  }
120

121
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
122 123 124 125 126 127 128
  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,
129 130
// 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
131 132 133
// 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>
134 135
void vtkFixedPointCompositeGOHelperGenerateImageTwoDependentNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
136 137 138 139 140
{
  VTKKWRCHelper_InitializationAndLoopStartGONN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();
141

142
  for (k = 0; k < numSteps; k++)
143
  {
144
    if (k)
145
    {
146
      VTKKWRCHelper_MoveToNextSampleGONN();
147
    }
148

149
    VTKKWRCHelper_SpaceLeapCheck();
150
    VTKKWRCHelper_CroppingCheckNN(pos);
151 152

    unsigned short val[2];
153 154 155
    val[0] = static_cast<unsigned short>(((*(dptr)) + shift[0]) * scale[0]);
    val[1] = static_cast<unsigned short>(((*(dptr + 1)) + shift[1]) * scale[1]);
    unsigned char mag = *magPtr;
156

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

164 165 166 167 168 169
    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));
170

171
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
172
  }
173

174
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
175 176 177 178 179 180 181 182 183 184
  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
185 186
// color we have accumulated so far along the ray, and check if we can
// terminate here (if our accumulated opacity has exceed some threshold).
187 188
// Finally we move onto the next sample along the ray.
template <class T>
189 190
void vtkFixedPointCompositeGOHelperGenerateImageFourDependentNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
191 192 193 194 195 196
{
  VTKKWRCHelper_InitializationAndLoopStartGONN();
  VTKKWRCHelper_InitializeCompositeOneNN();
  VTKKWRCHelper_InitializeCompositeGONN();
  VTKKWRCHelper_SpaceLeapSetup();

197
  for (k = 0; k < numSteps; k++)
198
  {
199
    if (k)
200
    {
201
      VTKKWRCHelper_MoveToNextSampleGONN();
202
    }
203

204
    VTKKWRCHelper_SpaceLeapCheck();
205
    VTKKWRCHelper_CroppingCheckNN(pos);
206 207

    unsigned short val[4];
208 209 210 211
    val[0] = *(dptr);
    val[1] = *(dptr + 1);
    val[2] = *(dptr + 2);
    val[3] = static_cast<unsigned short>(((*(dptr + 3)) + shift[3]) * scale[3]);
212

213
    unsigned char mag = *magPtr;
214

215 216 217
    tmp[3] =
      (scalarOpacityTable[0][val[3]] * gradientOpacityTable[0][mag] + 0x3fff) >> (VTKKW_FP_SHIFT);
    if (!tmp[3])
218
    {
219
      continue;
220
    }
221

222 223 224
    tmp[0] = (val[0] * tmp[3] + 0x7f) >> (8);
    tmp[1] = (val[1] * tmp[3] + 0x7f) >> (8);
    tmp[2] = (val[2] * tmp[3] + 0x7f) >> (8);
225

226
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
227
  }
228

229
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
230 231 232 233 234 235 236 237 238 239
  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
240
// whether we can terminate here (if the accumulated opacity exceeds some
241 242
// threshold). Finally we increment to the next sample on the ray.
template <class T>
243 244
void vtkFixedPointCompositeGOHelperGenerateImageIndependentNN(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
245
{
246
  VTKKWRCHelper_InitializeWeights();
247 248 249
  VTKKWRCHelper_InitializationAndLoopStartGONN();
  VTKKWRCHelper_InitializeCompositeMultiNN();
  VTKKWRCHelper_InitializeCompositeGONN();
250

251
  for (k = 0; k < numSteps; k++)
252
  {
253
    if (k)
254
    {
255
      VTKKWRCHelper_MoveToNextSampleGONN();
256
    }
257

258
    VTKKWRCHelper_CroppingCheckNN(pos);
259

260
    unsigned char mag[4] = { 1, 1, 1, 1 };
261
    for (c = 0; c < components; c++)
262
    {
263 264
      val[c] = static_cast<unsigned short>(((*(dptr + c)) + shift[c]) * scale[c]);
      mag[c] = static_cast<unsigned short>(*(magPtr + c));
265
    }
266

267 268
    VTKKWRCHelper_LookupAndCombineIndependentColorsGOUS(
      colorTable, scalarOpacityTable, gradientOpacityTable, val, mag, weights, components, tmp);
269

270
    if (tmp[3])
271
    {
272
      VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
273
    }
274
  }
275

276
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
277 278 279
  VTKKWRCHelper_IncrementAndLoopEnd();
}

280 281
// 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
282
// get the data value for the eight cell corners (if we have changed cells)
283 284
// 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
285
// fractional position within the cell, apply trilinear interpolation to
286 287 288 289
// 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
290 291
// sample along the ray.
template <class T>
292 293
void vtkFixedPointCompositeGOHelperGenerateImageOneSimpleTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
294 295 296 297 298 299 300
{
  VTKKWRCHelper_InitializationAndLoopStartGOTrilin();
  VTKKWRCHelper_InitializeCompositeOneTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();

  int needToSampleGO = 0;
301
  for (k = 0; k < numSteps; k++)
302
  {
303
    if (k)
304
    {
305
      mapper->FixedPointIncrement(pos, dir);
306
    }
307 308

    VTKKWRCHelper_SpaceLeapCheck();
309
    VTKKWRCHelper_CroppingCheckTrilin(pos);
310

311 312
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
313
    {
314 315 316
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
317

318 319 320 321
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellScalarValuesSimple(dptr);
      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];
322
      needToSampleGO = 1;
323
    }
324

325 326 327 328
    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalar(val);

    tmp[3] = scalarOpacityTable[0][val];
329
    if (!tmp[3])
330
    {
331
      continue;
332
    }
333

334
    if (needToSampleGO)
335
    {
336
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
337
      needToSampleGO = 0;
338
    }
339

340
    VTKKWRCHelper_InterpolateMagnitude(mag);
341 342
    tmp[3] = (tmp[3] * gradientOpacityTable[0][mag] + 0x7fff) >> VTKKW_FP_SHIFT;
    if (!tmp[3])
343
    {
344
      continue;
345
    }
346

347 348 349 350 351 352
    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));
353

354
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
355
  }
356

357
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
358 359 360
  VTKKWRCHelper_IncrementAndLoopEnd();
}

361 362
// 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
363
// get the data value for the eight cell corners (if we have changed cells)
364 365 366 367 368 369
// 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
370 371
// threshold). Finally we move on to the next sample along the ray.
template <class T>
372 373
void vtkFixedPointCompositeGOHelperGenerateImageOneTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
374 375 376 377 378
{
  VTKKWRCHelper_InitializationAndLoopStartGOTrilin();
  VTKKWRCHelper_InitializeCompositeOneTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
379 380

  int needToSampleGO = 0;
381
  for (k = 0; k < numSteps; k++)
382
  {
383
    if (k)
384
    {
385
      mapper->FixedPointIncrement(pos, dir);
386
    }
387

388
    VTKKWRCHelper_SpaceLeapCheck();
389
    VTKKWRCHelper_CroppingCheckTrilin(pos);
390

391 392
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
393
    {
394 395 396
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
397

398 399 400 401
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellScalarValues(dptr, scale[0], shift[0]);
      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];
402
      needToSampleGO = 1;
403
    }
404

405 406 407 408
    VTKKWRCHelper_ComputeWeights(pos);
    VTKKWRCHelper_InterpolateScalar(val);

    tmp[3] = scalarOpacityTable[0][val];
409
    if (!tmp[3])
410
    {
411
      continue;
412
    }
413

414
    if (needToSampleGO)
415
    {
416
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
417
      needToSampleGO = 0;
418
    }
419
    VTKKWRCHelper_InterpolateMagnitude(mag);
420

421 422
    tmp[3] = (tmp[3] * gradientOpacityTable[0][mag] + 0x7fff) >> VTKKW_FP_SHIFT;
    if (!tmp[3])
423
    {
424
      continue;
425
    }
426

427 428 429 430 431 432
    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));
433

434
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
435
  }
436

437
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
438 439 440
  VTKKWRCHelper_IncrementAndLoopEnd();
}

441
// This method is used when the interpolation type is linear, the data has
442
// two components and the components are not considered independent. In the
443 444 445 446 447 448 449 450 451
// 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
452 453
// the ray.
template <class T>
454 455
void vtkFixedPointCompositeGOHelperGenerateImageTwoDependentTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
456 457 458 459 460
{
  VTKKWRCHelper_InitializationAndLoopStartGOTrilin();
  VTKKWRCHelper_InitializeCompositeMultiTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
461 462

  int needToSampleGO = 0;
463
  for (k = 0; k < numSteps; k++)
464
  {
465
    if (k)
466
    {
467
      mapper->FixedPointIncrement(pos, dir);
468
    }
469

470
    VTKKWRCHelper_SpaceLeapCheck();
471
    VTKKWRCHelper_CroppingCheckTrilin(pos);
472

473 474
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
475
    {
476 477 478
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
479

480 481
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 0, scale[0], shift[0]);
482

483
      dptr++;
484
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 1, scale[1], shift[1]);
485

486 487
      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];
488
      needToSampleGO = 1;
489
    }
490

491
    VTKKWRCHelper_ComputeWeights(pos);
492
    VTKKWRCHelper_InterpolateScalarComponent(val, c, 2);
493

494
    tmp[3] = scalarOpacityTable[0][val[1]];
495
    if (!tmp[3])
496
    {
497
      continue;
498
    }
499

500
    if (needToSampleGO)
501
    {
502
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
503
      needToSampleGO = 0;
504
    }
505

506
    VTKKWRCHelper_InterpolateMagnitude(mag);
507 508
    tmp[3] = (tmp[3] * gradientOpacityTable[0][mag] + 0x7fff) >> VTKKW_FP_SHIFT;
    if (!tmp[3])
509
    {
510
      continue;
511
    }
512

513 514 515 516 517 518
    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));
519

520
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
521
  }
522

523
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
524 525 526
  VTKKWRCHelper_IncrementAndLoopEnd();
}

527
// This method is used when the interpolation type is linear, the data has
528
// four components and the components are not considered independent. In the
529
// inner loop we get the data value for the eight cell corners (if we have
530 531
// 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
532 533 534
// 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
535
// use the first three directly as the color of the sample, and the fourth is
536 537 538
// 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
539 540
// move on to the next sample along the ray.
template <class T>
541 542
void vtkFixedPointCompositeGOHelperGenerateImageFourDependentTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
543 544 545 546 547
{
  VTKKWRCHelper_InitializationAndLoopStartGOTrilin();
  VTKKWRCHelper_InitializeCompositeMultiTrilin();
  VTKKWRCHelper_InitializeCompositeOneGOTrilin();
  VTKKWRCHelper_SpaceLeapSetup();
548

549
  int needToSampleGO = 0;
550
  for (k = 0; k < numSteps; k++)
551
  {
552
    if (k)
553
    {
554
      mapper->FixedPointIncrement(pos, dir);
555
    }
556

557
    VTKKWRCHelper_SpaceLeapCheck();
558
    VTKKWRCHelper_CroppingCheckTrilin(pos);
559

560 561
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
562
    {
563 564 565
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
566

567 568
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, 0);
569

570
      dptr++;
571
      VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, 1);
572

573
      dptr++;
574
      VTKKWRCHelper_GetCellComponentRawScalarValues(dptr, 2);
575

576
      dptr++;
577
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 3, scale[3], shift[3]);
578

579 580
      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];
581
      needToSampleGO = 1;
582
    }
583

584
    VTKKWRCHelper_ComputeWeights(pos);
585
    VTKKWRCHelper_InterpolateScalarComponent(val, c, 4);
586

587
    tmp[3] = scalarOpacityTable[0][val[3]];
588
    if (!tmp[3])
589
    {
590
      continue;
591
    }
592

593
    if (needToSampleGO)
594
    {
595
      VTKKWRCHelper_GetCellMagnitudeValues(magPtrABCD, magPtrEFGH);
596
      needToSampleGO = 0;
597
    }
598

599
    VTKKWRCHelper_InterpolateMagnitude(mag);
600 601
    tmp[3] = (tmp[3] * gradientOpacityTable[0][mag] + 0x7fff) >> VTKKW_FP_SHIFT;
    if (!tmp[3])
602
    {
603
      continue;
604
    }
605

606 607 608
    tmp[0] = (val[0] * tmp[3] + 0x7f) >> 8;
    tmp[1] = (val[1] * tmp[3] + 0x7f) >> 8;
    tmp[2] = (val[2] * tmp[3] + 0x7f) >> 8;
609

610
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
611
  }
612

613
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
614 615 616
  VTKKWRCHelper_IncrementAndLoopEnd();
}

617 618 619
// 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
620
// changed cells) for all components as an unsigned shorts (we have to use the
621 622 623 624 625 626 627
// 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
628 629
// move on to the next sample along the ray.
template <class T>
630 631
void vtkFixedPointCompositeGOHelperGenerateImageIndependentTrilin(
  T* data, int threadID, int threadCount, vtkFixedPointVolumeRayCastMapper* mapper, vtkVolume* vol)
632
{
633
  VTKKWRCHelper_InitializeWeights();
634 635 636 637
  VTKKWRCHelper_InitializationAndLoopStartGOTrilin();
  VTKKWRCHelper_InitializeCompositeMultiTrilin();
  VTKKWRCHelper_InitializeCompositeMultiGOTrilin();

638
  for (k = 0; k < numSteps; k++)
639
  {
640
    if (k)
641
    {
642
      mapper->FixedPointIncrement(pos, dir);
643
    }
644

645
    VTKKWRCHelper_CroppingCheckTrilin(pos);
646

647 648
    mapper->ShiftVectorDown(pos, spos);
    if (spos[0] != oldSPos[0] || spos[1] != oldSPos[1] || spos[2] != oldSPos[2])
649
    {
650 651 652
      oldSPos[0] = spos[0];
      oldSPos[1] = spos[1];
      oldSPos[2] = spos[2];
653

654 655
      dptr = data + spos[0] * inc[0] + spos[1] * inc[1] + spos[2] * inc[2];
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 0, scale[0], shift[0]);
656

657
      dptr++;
658
      VTKKWRCHelper_GetCellComponentScalarValues(dptr, 1, scale[1], shift[1]);
659

660
      if (components > 2)
661
      {
662
        dptr++;
663 664
        VTKKWRCHelper_GetCellComponentScalarValues(dptr, 2, scale[2], shift[2]);
        if (components > 3)
665
        {
666
          dptr++;
667
          VTKKWRCHelper_GetCellComponentScalarValues(dptr, 3, scale[3], shift[3]);
668
        }
669
      }
670

671 672 673
      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);
674

675 676
      magPtrABCD++;
      magPtrEFGH++;
677
      VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 1);
678

679
      if (components > 2)
680
      {
681 682
        magPtrABCD++;
        magPtrEFGH++;
683 684
        VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 2);
        if (components > 3)
685
        {
686 687
          magPtrABCD++;
          magPtrEFGH++;
688
          VTKKWRCHelper_GetCellComponentMagnitudeValues(magPtrABCD, magPtrEFGH, 3);
689 690
        }
      }
691
    }
692

693
    VTKKWRCHelper_ComputeWeights(pos);
694 695
    VTKKWRCHelper_InterpolateScalarComponent(val, c, components);
    VTKKWRCHelper_InterpolateMagnitudeComponent(mag, c, components);
696

697 698
    VTKKWRCHelper_LookupAndCombineIndependentColorsGOUS(
      colorTable, scalarOpacityTable, gradientOpacityTable, val, mag, weights, components, tmp);
699

700
    VTKKWRCHelper_CompositeColorAndCheckEarlyTermination(color, tmp, remainingOpacity);
701
  }
702

703
  VTKKWRCHelper_SetPixelColor(imagePtr, color, remainingOpacity);
704 705 706
  VTKKWRCHelper_IncrementAndLoopEnd();
}

707 708
void vtkFixedPointVolumeRayCastCompositeGOHelper::GenerateImage(
  int threadID, int threadCount, vtkVolume* vol, vtkFixedPointVolumeRayCastMapper* mapper)
709
{
710
  void* data = mapper->GetCurrentScalars()->GetVoidPointer(0);
711
  int scalarType = mapper->GetCurrentScalars()->GetDataType();
712 713

  // Nearest Neighbor interpolate
714
  if (mapper->ShouldUseNearestNeighborInterpolation(vol))
715
  {
716
    // One component data
717
    if (mapper->GetCurrentScalars()->GetNumberOfComponents() == 1)