Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1177 lines
34 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkVolumeTextureMapper2D.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkVolumeTextureMapper2D.h"
#include "vtkCamera.h"
#include "vtkVolumeRenderingFactory.h"
#include "vtkImageData.h"
#include "vtkLargeInteger.h"
#include "vtkMatrix4x4.h"
#include "vtkPointData.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkTransform.h"
#include "vtkVolumeProperty.h"
#define VTK_PLUS_X_MAJOR_DIRECTION 0
#define VTK_MINUS_X_MAJOR_DIRECTION 1
#define VTK_PLUS_Y_MAJOR_DIRECTION 2
#define VTK_MINUS_Y_MAJOR_DIRECTION 3
#define VTK_PLUS_Z_MAJOR_DIRECTION 4
#define VTK_MINUS_Z_MAJOR_DIRECTION 5
template <class T>
void vtkVolumeTextureMapper2D_TraverseVolume( T *data_ptr,
int size[3],
int axis,
int directionFlag,
vtkVolumeTextureMapper2D *me )
{
int i, j, k;
int kstart, kend, kinc;
unsigned char *tptr;
T *dptr;
unsigned short *nptr;
unsigned char *gptr = NULL;
float *v, *t;
unsigned char *rgbaArray = me->GetRGBAArray();
float *gradientOpacityArray;
unsigned char *gradientMagnitudes;
unsigned short *encodedNormals = NULL;
float *redDiffuseShadingTable = NULL;
float *greenDiffuseShadingTable = NULL;
float *blueDiffuseShadingTable = NULL;
float *redSpecularShadingTable = NULL;
float *greenSpecularShadingTable = NULL;
float *blueSpecularShadingTable = NULL;
int shade;
float tmpval;
int cropping, croppingFlags;
double *croppingBounds;
int flag[3], tmpFlag, index;
int clipLow = 0, clipHigh = 0;
vtkRenderWindow *renWin = me->GetRenderWindow();
double spacing[3], origin[3];
unsigned char zero[4];
unsigned char *texture;
int textureSize[2];
int xTile, yTile, xTotal, yTotal, tile, numTiles;
int *zAxis=0, *yAxis=0, *xAxis=0;
int loc, inc=0;
int saveTextures = me->GetSaveTextures();
int textureOffset=0;
int a0=0, a1=0, a2=0;
switch ( axis )
{
case 0:
a0 = 1;
a1 = 2;
a2 = 0;
xAxis = &k;
yAxis = &i;
zAxis = &j;
inc = size[0];
break;
case 1:
a0 = 0;
a1 = 2;
a2 = 1;
xAxis = &i;
yAxis = &k;
zAxis = &j;
inc = 1;
break;
case 2:
a0 = 0;
a1 = 1;
a2 = 2;
xAxis = &i;
yAxis = &j;
zAxis = &k;
inc = 1;
break;
}
int *axisTextureSize = me->GetAxisTextureSize();
textureSize[0] = axisTextureSize[a2*3+0];
textureSize[1] = axisTextureSize[a2*3+1];
if ( saveTextures )
{
texture = me->GetTexture();
switch ( axis )
{
case 0:
textureOffset = 0;
break;
case 1:
textureOffset =
4*axisTextureSize[0]*axisTextureSize[1]*axisTextureSize[2];
break;
case 2:
textureOffset =
4*axisTextureSize[0]*axisTextureSize[1]*axisTextureSize[2] +
4*axisTextureSize[3]*axisTextureSize[4]*axisTextureSize[5];
break;
}
}
else
{
// Create space for the texture
texture = new unsigned char[4*textureSize[0]*textureSize[1]];
textureOffset = 0;
}
// How many tiles are there in X? in Y? total?
xTotal = textureSize[0] / size[a0];
yTotal = textureSize[1] / size[a1];
numTiles = xTotal * yTotal;
// Create space for the vertices and texture coordinates. You need four vertices
// with three components each for each tile, and four texture coordinates with
// three components each for each texture coordinate
v = new float [12*numTiles];
t = new float [ 8*numTiles];
// Convenient for filling in the empty regions (due to clipping)
zero[0] = 0;
zero[1] = 0;
zero[2] = 0;
zero[3] = 0;
// We need to know the spacing and origin of the data to set up the coordinates
// correctly
me->GetDataSpacing( spacing );
me->GetDataOrigin( origin );
// What is the first plane, the increment to move to the next plane, and the plane
// that is just past the end?
if ( directionFlag )
{
kstart = 0;
kend = ((int)( (size[a2]-1) /
me->GetInternalSkipFactor())+1)*me->GetInternalSkipFactor();
// Offset the slices so that if we take just one it is in the middle
kstart += (size[a2]-1-kend+me->GetInternalSkipFactor())/2;
kend += (size[a2]-1-kend+me->GetInternalSkipFactor())/2;
kinc = me->GetInternalSkipFactor();
}
else
{
kstart = (int)((size[a2]-1) /
me->GetInternalSkipFactor()) * me->GetInternalSkipFactor();
kend = -me->GetInternalSkipFactor();
// Offset the slices so that if we take just one it is in the middle
kend += (size[a2]-1-kstart)/2;
kstart += (size[a2]-1-kstart)/2;
kinc = -me->GetInternalSkipFactor();
}
// Fill in the texture coordinates and most of the vertex information in advance
float offset[2];
offset[0] = 0.5 / (float)textureSize[0];
offset[1] = 0.5 / (float)textureSize[1];
for ( i = 0; i < numTiles; i++ )
{
yTile = i / xTotal;
xTile = i % xTotal;
t[i*8 + 0] = (float)((size[a0]*(xTile )) )/(float)textureSize[0] + offset[0];
t[i*8 + 1] = (float)((size[a1]*(yTile )) )/(float)textureSize[1] + offset[1];
t[i*8 + 2] = (float)((size[a0]*(xTile )) )/(float)textureSize[0] + offset[0];
t[i*8 + 3] = (float)((size[a1]*(yTile+1)) )/(float)textureSize[1] - offset[1];
t[i*8 + 4] = (float)((size[a0]*(xTile+1)) )/(float)textureSize[0] - offset[0];
t[i*8 + 5] = (float)((size[a1]*(yTile+1)) )/(float)textureSize[1] - offset[1];
t[i*8 + 6] = (float)((size[a0]*(xTile+1)) )/(float)textureSize[0] - offset[0];
t[i*8 + 7] = (float)((size[a1]*(yTile )) )/(float)textureSize[1] + offset[1];
v[i*12 + a0] = origin[a0];
v[i*12 + a1] = origin[a1];
v[i*12 + 3+a0] = origin[a0];
v[i*12 + 3+a1] = spacing[a1] * (float)(size[a1]-1) + origin[a1];
v[i*12 + 6+a0] = spacing[a0] * (float)(size[a0]-1) + origin[a0];
v[i*12 + 6+a1] = spacing[a1] * (float)(size[a1]-1) + origin[a1];
v[i*12 + 9+a0] = spacing[a0] * (float)(size[a0]-1) + origin[a0];
v[i*12 + 9+a1] = origin[a1];
}
cropping = me->GetCropping();
croppingFlags = me->GetCroppingRegionFlags();
croppingBounds = me->GetVoxelCroppingRegionPlanes();
if ( !cropping )
{
clipLow = 0;
clipHigh = size[a0];
flag[0] = 1;
flag[1] = 1;
flag[2] = 1;
}
shade = me->GetShade();
if ( shade )
{
encodedNormals = me->GetEncodedNormals();
redDiffuseShadingTable = me->GetRedDiffuseShadingTable();
greenDiffuseShadingTable = me->GetGreenDiffuseShadingTable();
blueDiffuseShadingTable = me->GetBlueDiffuseShadingTable();
redSpecularShadingTable = me->GetRedSpecularShadingTable();
greenSpecularShadingTable = me->GetGreenSpecularShadingTable();
blueSpecularShadingTable = me->GetBlueSpecularShadingTable();
}
gradientMagnitudes = me->GetGradientMagnitudes();
gradientOpacityArray = me->GetGradientOpacityArray();
tile = 0;
for ( k = kstart; k != kend; k+=kinc )
{
yTile = tile / xTotal;
xTile = tile % xTotal;
for ( j = 0; j < size[a1]; j++ )
{
i = 0;
tptr = texture + textureOffset +
4 * ( yTile*size[a1]*textureSize[0]+
j*textureSize[0] +
xTile*size[a0] );
loc = (*zAxis)*size[0]*size[1] + (*yAxis)*size[0] + (*xAxis);
dptr = data_ptr + loc;
// Given a Y and Z value, what are the cropping bounds
// on X.
if ( cropping )
{
switch ( axis )
{
case 0:
clipLow = (int) croppingBounds[2];
clipHigh = (int) croppingBounds[3];
tmpFlag = (*xAxis<croppingBounds[0])?(0):(1+(*xAxis>=croppingBounds[1]));
tmpFlag+= 9*((*zAxis<croppingBounds[4])?(0):(1+(*zAxis>=croppingBounds[5])));
flag[0] = croppingFlags&(1<<(tmpFlag));
flag[1] = croppingFlags&(1<<(tmpFlag+3));
flag[2] = croppingFlags&(1<<(tmpFlag+6));
break;
case 1:
clipLow = (int)croppingBounds[0];
clipHigh = (int)croppingBounds[1];
tmpFlag = 3*((*yAxis<croppingBounds[2])?(0):(1+(*yAxis>=croppingBounds[3])));
tmpFlag+= 9*((*zAxis<croppingBounds[4])?(0):(1+(*zAxis>=croppingBounds[5])));
flag[0] = croppingFlags&(1<<(tmpFlag));
flag[1] = croppingFlags&(1<<(tmpFlag+1));
flag[2] = croppingFlags&(1<<(tmpFlag+2));
break;
case 2:
clipLow = (int)croppingBounds[0];
clipHigh = (int)croppingBounds[1];
tmpFlag = 3*((*yAxis<croppingBounds[2])?(0):(1+(*yAxis>=croppingBounds[3])));
tmpFlag+= 9*((*zAxis<croppingBounds[4])?(0):(1+(*zAxis>=croppingBounds[5])));
flag[0] = croppingFlags&(1<<(tmpFlag));
flag[1] = croppingFlags&(1<<(tmpFlag+1));
flag[2] = croppingFlags&(1<<(tmpFlag+2));
break;
}
}
if ( shade )
{
nptr = encodedNormals + loc;
if ( gradientMagnitudes )
{
gptr = gradientMagnitudes + loc;
}
for ( i = 0; i < size[a0]; i++ )
{
index = 0;
index += ( i >= clipLow );
index += ( i >= clipHigh );
if ( flag[index] )
{
tmpval = rgbaArray[(*dptr)*4];
tmpval = tmpval * redDiffuseShadingTable[*nptr] +
redSpecularShadingTable[*nptr]*255.0;
if ( tmpval > 255.0 )
{
tmpval = 255.0;
}
*(tptr++) = (unsigned char) tmpval;
tmpval = rgbaArray[(*dptr)*4 + 1];
tmpval = tmpval * greenDiffuseShadingTable[*nptr] +
greenSpecularShadingTable[*nptr]*255.0;
if ( tmpval > 255.0 )
{
tmpval = 255.0;
}
*(tptr++) = (unsigned char) tmpval;
tmpval = rgbaArray[(*dptr)*4 + 2];
tmpval = tmpval * blueDiffuseShadingTable[*nptr] +
blueSpecularShadingTable[*nptr]*255.0;
if ( tmpval > 255.0 )
{
tmpval = 255.0;
}
*(tptr++) = (unsigned char) tmpval;
tmpval = rgbaArray[(*dptr)*4 + 3];
if ( gradientMagnitudes )
{
tmpval *= gradientOpacityArray[*gptr];
gptr += inc;
}
*(tptr++) = (unsigned char) tmpval;
}
else
{
memcpy( tptr, zero, 4 );
tptr += 4;
if ( gradientMagnitudes )
{
gptr += inc;
}
}
nptr += inc;
dptr += inc;
}
}
else
{
if ( gradientMagnitudes )
{
gptr = gradientMagnitudes + loc;
}
if ( cropping )
{
for ( i = 0; i < size[a0]; i++ )
{
index = 0;
index += ( i >= clipLow );
index += ( i >= clipHigh );
if ( flag[index] )
{
memcpy( tptr, rgbaArray + (*dptr)*4, 4 );
if ( gradientMagnitudes )
{
*(tptr+3) = (unsigned char)
((float)(*(tptr+3)) * gradientOpacityArray[*gptr]);
gptr += inc;
}
}
else
{
memcpy( tptr, zero, 4 );
if ( gradientMagnitudes )
{
gptr += inc;
}
}
tptr += 4;
dptr += inc;
}
}
else
{
if ( gradientMagnitudes )
{
for ( i = 0; i < size[a0]; i++ )
{
memcpy( tptr, rgbaArray + (*dptr)*4, 4 );
*(tptr+3) = (unsigned char)
((float)(*(tptr+3)) * gradientOpacityArray[*gptr]);
gptr += inc;
dptr += inc;
tptr += 4;
}
}
else
{
for ( i = 0; i < size[a0]; i++ )
{
memcpy( tptr, rgbaArray + (*dptr)*4, 4 );
tptr += 4;
dptr += inc;
}
}
}
}
}
if ( renWin->CheckAbortStatus() )
{
break;
}
v[12*tile + a2] =
v[12*tile + 3+a2] =
v[12*tile + 6+a2] =
v[12*tile + 9+a2] = spacing[a2] * (float)k + origin[a2];
tile++;
if ( tile == numTiles || (k+kinc == kend) )
{
if ( saveTextures )
{
textureOffset += 4*axisTextureSize[a2*3] * axisTextureSize[a2*3+1];
}
else
{
me->RenderQuads( tile, v, t, texture, textureSize, 0);
}
tile = 0;
}
}
if ( !saveTextures )
{
delete [] texture;
}
delete [] v;
delete [] t;
}
vtkCxxRevisionMacro(vtkVolumeTextureMapper2D, "$Revision: 1.2 $");
//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkVolumeTextureMapper2D);
//----------------------------------------------------------------------------
vtkVolumeTextureMapper2D::vtkVolumeTextureMapper2D()
{
this->TargetTextureSize[0] = 512;
this->TargetTextureSize[1] = 512;
this->MaximumNumberOfPlanes = 0;
this->MaximumStorageSize = 0;
this->Texture = NULL;
this->TextureSize = 0;
}
vtkVolumeTextureMapper2D::~vtkVolumeTextureMapper2D()
{
if ( this->Texture )
{
delete [] this->Texture;
}
}
vtkVolumeTextureMapper2D *vtkVolumeTextureMapper2D::New()
{
// First try to create the object from the vtkObjectFactory
vtkObject* ret =
vtkVolumeRenderingFactory::CreateInstance("vtkVolumeTextureMapper2D");
return (vtkVolumeTextureMapper2D*)ret;
}
void vtkVolumeTextureMapper2D::RenderSavedTexture()
{
int i, k;
int kstart, kend, kinc;
unsigned char *tptr;
float *v, *t;
vtkRenderWindow *renWin = this->GetRenderWindow();
double spacing[3], origin[3];
unsigned char *texture;
int textureSize[2];
int xTile, yTile, xTotal, yTotal, tile, numTiles;
int textureOffset=0;
int axis=0, directionFlag=0;
int size[3];
int a0=0, a1=0, a2=0;
this->GetInput()->GetDimensions( size );
switch ( this->MajorDirection )
{
case VTK_PLUS_X_MAJOR_DIRECTION:
axis = 0;
directionFlag = 1;
break;
case VTK_MINUS_X_MAJOR_DIRECTION:
axis = 0;
directionFlag = 0;
break;
case VTK_PLUS_Y_MAJOR_DIRECTION:
axis = 1;
directionFlag = 1;
break;
case VTK_MINUS_Y_MAJOR_DIRECTION:
axis = 1;
directionFlag = 0;
break;
case VTK_PLUS_Z_MAJOR_DIRECTION:
axis = 2;
directionFlag = 1;
break;
case VTK_MINUS_Z_MAJOR_DIRECTION:
axis = 2;
directionFlag = 0;
break;
}
switch ( axis )
{
case 0:
a0 = 1;
a1 = 2;
a2 = 0;
break;
case 1:
a0 = 0;
a1 = 2;
a2 = 1;
break;
case 2:
a0 = 0;
a1 = 1;
a2 = 2;
break;
}
textureSize[0] = this->AxisTextureSize[a2][0];
textureSize[1] = this->AxisTextureSize[a2][1];
texture = this->Texture;
switch ( axis )
{
case 0:
textureOffset = 0;
break;
case 1:
textureOffset =
4*(this->AxisTextureSize[0][0]*
this->AxisTextureSize[0][1]*
this->AxisTextureSize[0][2]);
break;
case 2:
textureOffset =
4*(this->AxisTextureSize[0][0]*
this->AxisTextureSize[0][1]*
this->AxisTextureSize[0][2]) +
4*(this->AxisTextureSize[1][0]*
this->AxisTextureSize[1][1]*
this->AxisTextureSize[1][2]);
break;
}
if ( directionFlag == 0 )
{
textureOffset +=
4*(this->AxisTextureSize[a2][0]*
this->AxisTextureSize[a2][1]*
(this->AxisTextureSize[a2][2]-1));
}
// How many tiles are there in X? in Y? total?
xTotal = textureSize[0] / size[a0];
yTotal = textureSize[1] / size[a1];
numTiles = xTotal * yTotal;
// Create space for the vertices and texture coordinates. You need four vertices
// with three components each for each tile, and four texture coordinates with
// three components each for each texture coordinate
v = new float [12*numTiles];
t = new float [ 8*numTiles];
// We need to know the spacing and origin of the data to set up the coordinates
// correctly
this->GetDataSpacing( spacing );
this->GetDataOrigin( origin );
// What is the first plane, the increment to move to the next plane, and the plane
// that is just past the end?
if ( directionFlag )
{
kstart = 0;
kend = ((int)( (size[a2]-1) /
this->InternalSkipFactor)+1)*this->InternalSkipFactor;
// Offset the slices so that if we take just one it is in the middle
kstart += (size[a2]-1-kend+this->InternalSkipFactor)/2;
kend += (size[a2]-1-kend+this->InternalSkipFactor)/2;
kinc = this->InternalSkipFactor;
}
else
{
kstart = (int)((size[a2]-1) /
this->InternalSkipFactor) * this->InternalSkipFactor;
kend = -this->InternalSkipFactor;
// Offset the slices so that if we take just one it is in the middle
kend += (size[a2]-1-kstart)/2;
kstart += (size[a2]-1-kstart)/2;
kinc = -this->InternalSkipFactor;
}
// Fill in the texture coordinates and most of the vertex information in advance
float offset[2];
offset[0] = 0.5 / (float)textureSize[0];
offset[1] = 0.5 / (float)textureSize[1];
int idx;
for ( idx = 0; idx < numTiles; idx++ )
{
i = ( directionFlag == 1 )?(idx):(numTiles-idx-1);
yTile = i / xTotal;
xTile = i % xTotal;
t[i*8 + 0] = (float)((size[a0]*(xTile )) )/(float)textureSize[0] + offset[0];
t[i*8 + 1] = (float)((size[a1]*(yTile )) )/(float)textureSize[1] + offset[1];
t[i*8 + 2] = (float)((size[a0]*(xTile )) )/(float)textureSize[0] + offset[0];
t[i*8 + 3] = (float)((size[a1]*(yTile+1)) )/(float)textureSize[1] - offset[1];
t[i*8 + 4] = (float)((size[a0]*(xTile+1)) )/(float)textureSize[0] - offset[0];
t[i*8 + 5] = (float)((size[a1]*(yTile+1)) )/(float)textureSize[1] - offset[1];
t[i*8 + 6] = (float)((size[a0]*(xTile+1)) )/(float)textureSize[0] - offset[0];
t[i*8 + 7] = (float)((size[a1]*(yTile )) )/(float)textureSize[1] + offset[1];
v[i*12 + a0] = origin[a0];
v[i*12 + a1] = origin[a1];
v[i*12 + 3+a0] = origin[a0];
v[i*12 + 3+a1] = spacing[a1] * (float)(size[a1]-1) + origin[a1];
v[i*12 + 6+a0] = spacing[a0] * (float)(size[a0]-1) + origin[a0];
v[i*12 + 6+a1] = spacing[a1] * (float)(size[a1]-1) + origin[a1];
v[i*12 + 9+a0] = spacing[a0] * (float)(size[a0]-1) + origin[a0];
v[i*12 + 9+a1] = origin[a1];
}
if ( directionFlag == 1 )
{
tile = 0;
}
else
{
tile = (((kend - kstart)/kinc)-1)%numTiles;
}
int tileCount = 0;
for ( k = kstart; k != kend; k+=kinc )
{
if ( renWin->CheckAbortStatus() )
{
break;
}
v[12*tile + a2] =
v[12*tile + 3+a2] =
v[12*tile + 6+a2] =
v[12*tile + 9+a2] = spacing[a2] * (float)k + origin[a2];
tileCount++;
if ( directionFlag == 1 )
{
tile++;
}
else
{
tile--;
}
if ( (directionFlag == 1 && tile == numTiles ) ||
(directionFlag == 0 && tile == -1) || (k+kinc == kend) )
{
tptr = texture + textureOffset;
if ( directionFlag == 1 )
{
textureOffset +=
4*this->AxisTextureSize[a2][0] * this->AxisTextureSize[a2][1];
}
else
{
textureOffset -=
4*this->AxisTextureSize[a2][0] * this->AxisTextureSize[a2][1];
}
this->RenderQuads( tileCount, v, t, tptr, textureSize, !directionFlag );
tile = (directionFlag == 1)?(0):(numTiles-1);
tileCount = 0;
}
}
delete [] v;
delete [] t;
}
void vtkVolumeTextureMapper2D::GenerateTexturesAndRenderQuads( vtkRenderer *ren, vtkVolume *vol )
{
vtkImageData *input = this->GetInput();
int size[3];
void *inputPointer;
int inputType;
inputPointer =
input->GetPointData()->GetScalars()->GetVoidPointer(0);
inputType =
input->GetPointData()->GetScalars()->GetDataType();
input->GetDimensions( size );
// Do we have a texture already, and nothing has changed? If so
// just render it.
if ( this->Texture && !this->Shade &&
this->GetMTime() < this->TextureMTime &&
this->GetInput()->GetMTime() < this->TextureMTime &&
vol->GetProperty()->GetMTime() < this->TextureMTime )
{
this->RenderSavedTexture();
return;
}
// Otherwise, we need to generate textures. We can throw away any
// saved textures
if ( this->Texture )
{
delete [] this->Texture;
this->Texture = NULL;
}
this->TextureSize = 0;
// Will all the textures fit in the allotted storage?
this->ComputeAxisTextureSize( 0, this->AxisTextureSize[0] );
this->ComputeAxisTextureSize( 1, this->AxisTextureSize[1] );
this->ComputeAxisTextureSize( 2, this->AxisTextureSize[2] );
vtkLargeInteger neededSize;
vtkLargeInteger tmpInt;
neededSize =
this->AxisTextureSize[0][0];
neededSize = neededSize *
this->AxisTextureSize[0][1] *
this->AxisTextureSize[0][2] ;
tmpInt =
this->AxisTextureSize[1][0];
tmpInt = tmpInt *
this->AxisTextureSize[1][1] *
this->AxisTextureSize[1][2];
neededSize = neededSize + tmpInt;
tmpInt =
this->AxisTextureSize[2][0];
tmpInt = tmpInt *
this->AxisTextureSize[2][1] *
this->AxisTextureSize[2][2];
neededSize = neededSize + tmpInt;
neededSize *= 4;
if ( neededSize.GetLength() > 31 )
{
this->SaveTextures = 0;
}
else
{
this->SaveTextures =
( neededSize.CastToLong() <= this->MaximumStorageSize &&
!this->Shade );
}
if ( this->SaveTextures )
{
this->Texture = new unsigned char [neededSize.CastToLong()];
this->TextureSize = neededSize.CastToLong();
int savedDirection = this->MajorDirection;
switch ( inputType )
{
case VTK_UNSIGNED_CHAR:
this->InitializeRender( ren, vol, VTK_PLUS_X_MAJOR_DIRECTION );
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 0, 1, this );
this->InitializeRender( ren, vol, VTK_PLUS_Y_MAJOR_DIRECTION );
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 1, 1, this );
this->InitializeRender( ren, vol, VTK_PLUS_Z_MAJOR_DIRECTION );
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 2, 1, this );
break;
case VTK_UNSIGNED_SHORT:
this->InitializeRender( ren, vol, VTK_PLUS_X_MAJOR_DIRECTION );
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 0, 1, this );
this->InitializeRender( ren, vol, VTK_PLUS_Y_MAJOR_DIRECTION );
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 1, 1, this );
this->InitializeRender( ren, vol, VTK_PLUS_Z_MAJOR_DIRECTION );
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 2, 1, this );
break;
}
this->MajorDirection = savedDirection;
if ( !ren->GetRenderWindow()->GetAbortRender() )
{
this->RenderSavedTexture();
this->TextureMTime.Modified();
}
}
else
{
switch ( inputType )
{
case VTK_UNSIGNED_CHAR:
switch ( this->MajorDirection )
{
case VTK_PLUS_X_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 0, 1, this );
break;
case VTK_MINUS_X_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 0, 0, this );
break;
case VTK_PLUS_Y_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 1, 1, this );
break;
case VTK_MINUS_Y_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 1, 0, this );
break;
case VTK_PLUS_Z_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 2, 1, this );
break;
case VTK_MINUS_Z_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned char *)inputPointer, size, 2, 0, this );
break;
}
break;
case VTK_UNSIGNED_SHORT:
switch ( this->MajorDirection )
{
case VTK_PLUS_X_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 0, 1, this );
break;
case VTK_MINUS_X_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 0, 0, this );
break;
case VTK_PLUS_Y_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 1, 1, this );
break;
case VTK_MINUS_Y_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 1, 0, this );
break;
case VTK_PLUS_Z_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 2, 1, this );
break;
case VTK_MINUS_Z_MAJOR_DIRECTION:
vtkVolumeTextureMapper2D_TraverseVolume
( (unsigned short *)inputPointer, size, 2, 0, this );
break;
}
break;
default:
vtkErrorMacro(
"vtkVolumeTextureMapper2D only works with unsigned short and unsigned char data.\n" <<
"Input type: " << inputType << " given.");
}
}
}
void vtkVolumeTextureMapper2D::InitializeRender( vtkRenderer *ren,
vtkVolume *vol,
int majorDirection )
{
if ( majorDirection >= 0)
{
this->MajorDirection = majorDirection;
}
else
{
double vpn[3];
// Take the vpn, convert it to volume coordinates, and find the
// major direction
vtkMatrix4x4 *volMatrix = vtkMatrix4x4::New();
volMatrix->DeepCopy( vol->GetMatrix() );
vtkTransform *worldToVolumeTransform = vtkTransform::New();
worldToVolumeTransform->SetMatrix( volMatrix );
// Create a transform that will account for the translation of
// the scalar data.
vtkTransform *volumeTransform = vtkTransform::New();
volumeTransform->Identity();
volumeTransform->Translate(this->GetInput()->GetOrigin());
// Now concatenate the volume's matrix with this scalar data matrix
worldToVolumeTransform->PreMultiply();
worldToVolumeTransform->Concatenate( volumeTransform->GetMatrix() );
worldToVolumeTransform->Inverse();
ren->GetActiveCamera()->GetViewPlaneNormal(vpn);
worldToVolumeTransform->TransformVector( vpn, vpn );
volMatrix->Delete();
volumeTransform->Delete();
worldToVolumeTransform->Delete();
if ( fabs(vpn[0]) >= fabs(vpn[1]) && fabs(vpn[0]) >= fabs(vpn[2]) )
{
this->MajorDirection = (vpn[0]<0.0)?
(VTK_MINUS_X_MAJOR_DIRECTION):(VTK_PLUS_X_MAJOR_DIRECTION);
}
else if ( fabs(vpn[1]) >= fabs(vpn[0]) && fabs(vpn[1]) >= fabs(vpn[2]) )
{
this->MajorDirection = (vpn[1]<0.0)?
(VTK_MINUS_Y_MAJOR_DIRECTION):(VTK_PLUS_Y_MAJOR_DIRECTION);
}
else
{
this->MajorDirection = (vpn[2]<0.0)?
(VTK_MINUS_Z_MAJOR_DIRECTION):(VTK_PLUS_Z_MAJOR_DIRECTION);
}
}
// Determine the internal skip factor - if there is a limit on the number
// of planes we can have (the MaximumNumberOfPlanes value is greater than
// 0) then increase this skip factor until we ensure the maximum condition.
this->InternalSkipFactor = 1;
if ( this->MaximumNumberOfPlanes > 0 )
{
int size[3];
this->GetInput()->GetDimensions( size );
while ( (float)size[this->MajorDirection/2] /
(float)this->InternalSkipFactor >
(float)this->MaximumNumberOfPlanes )
{
this->InternalSkipFactor++;
}
}
// Assume that the spacing between samples is 1/2 of the maximum - this
// could be computed accurately for parallel (but isn't right now). For
// perspective, this spacing changes across the image so no one number will
// be accurate. 1/2 the maximum is (1 + sqrt(2)) / 2 = 1.2071
// TODO: DataSpacing should be converted to double at some point
double *dspacing;
dspacing = this->GetInput()->GetSpacing();
this->DataSpacing[0] = (float)dspacing[0];
this->DataSpacing[1] = (float)dspacing[1];
this->DataSpacing[2] = (float)dspacing[2];
this->SampleDistance =
this->DataSpacing[this->MajorDirection/2]*this->InternalSkipFactor*1.2071;
this->vtkVolumeTextureMapper::InitializeRender( ren, vol );
}
void vtkVolumeTextureMapper2D::ComputeAxisTextureSize( int axis, int *textureSize )
{
int targetSize[2];
int a0=0, a1=0, a2=0;
switch ( axis )
{
case 0:
a0 = 1;
a1 = 2;
a2 = 0;
break;
case 1:
a0 = 0;
a1 = 2;
a2 = 1;
break;
case 2:
a0 = 0;
a1 = 1;
a2 = 2;
break;
}
// How big should the texture be?
// Start with the target size
targetSize[0] = this->TargetTextureSize[0];
targetSize[1] = this->TargetTextureSize[1];
int size[3];
this->GetInput()->GetDimensions( size );
// Increase the x dimension of the texture if the x dimension of the data
// is bigger than it (because these are x by y textures)
if ( size[a0] > targetSize[0] )
{
targetSize[0] = size[a0];
}
// Increase the y dimension of the texture if the y dimension of the data
// is bigger than it (because these are x by y textures)
if ( size[a1] > targetSize[1] )
{
targetSize[1] = size[a1];
}
// Make sure the x dimension of the texture is a power of 2
textureSize[0] = 32;
while( textureSize[0] < targetSize[0] )
{
textureSize[0] *= 2;
}
// Make sure the y dimension of the texture is a power of 2
textureSize[1] = 32;
while( textureSize[1] < targetSize[1] )
{
textureSize[1] *= 2;
}
// Our texture might be too big - shrink it carefully making
// sure that it is still big enough in the right dimensions to
// handle oddly shaped volumes
int volSize = size[0]*size[1]*size[2];
int done = (volSize > textureSize[0]*textureSize[1]);
int minSize[2];
// What is the minumum size the texture could be in X (along the X
// axis of the volume)?
minSize[0] = 32;
while ( minSize[0] < size[a0] )
{
minSize[0] *= 2;
}
// What is the minumum size the texture could be in Y (along the Y
// axis of the volume)?
minSize[1] = 32;
while ( minSize[1] < size[a1] )
{
minSize[1] *= 2;
}
// Keep reducing the texture size until it is just big enough
while (!done)
{
// Set done to 1. Reset to 0 if we make any changes.
done = 1;
// If the texture is bigger in some dimension that it needs to be
// and chopping that dimension in half would still fit the whole
// volume, then chop it in half.
if ( textureSize[0] > minSize[0] &&
( ((textureSize[0]/2) / size[a0]) *
(textureSize[1] / size[a1]) >= size[a2] ) )
{
textureSize[0] /= 2;
done = 0;
}
if ( textureSize[1] > minSize[1] &&
( (textureSize[0] / size[a0]) *
((textureSize[1]/2) / size[a1]) >= size[a2] ) )
{
textureSize[1] /= 2;
done = 0;
}
}
// This is how many texture planes would be necessary if one slice fit on a
// texture (taking into account the user defined maximum)
textureSize[2] =
(size[a2]<this->MaximumNumberOfPlanes||this->MaximumNumberOfPlanes<=0) ?
(size[a2]) : (this->MaximumNumberOfPlanes);
// How many slices can fit on a texture in X and Y?
int xTotal = textureSize[0] / size[a0];
int yTotal = textureSize[1] / size[a1];
// The number of textures we need is the number computed above divided by
// how many fit on a texture (plus one if they don't fit evenly)
textureSize[2] = (textureSize[2] / (xTotal*yTotal)) +
((textureSize[2] % (xTotal*yTotal))!=0);
}
// Print the vtkVolumeTextureMapper2D
void vtkVolumeTextureMapper2D::PrintSelf(ostream& os, vtkIndent indent)
{
os << indent << "Target Texture Size: "
<< this->TargetTextureSize[0] << ", "
<< this->TargetTextureSize[1] << endl;
os << indent << "Maximum Number Of Planes: ";
if ( this->MaximumNumberOfPlanes > 0 )
{
os << this->MaximumNumberOfPlanes << endl;
}
else
{
os << "<unlimited>" << endl;
}
os << indent << "Maximum Storage Size: "
<< this->MaximumStorageSize << endl;
this->Superclass::PrintSelf(os,indent);
}