Index: Modules/MitkExt/Rendering/vtkMitkOpenglXRAYVolumeTextureMapper2D.cxx =================================================================== --- Modules/MitkExt/Rendering/vtkMitkOpenglXRAYVolumeTextureMapper2D.cxx (revision 0) +++ Modules/MitkExt/Rendering/vtkMitkOpenglXRAYVolumeTextureMapper2D.cxx (revision 0) @@ -0,0 +1,1236 @@ +/*========================================================================= +* Copyright (c) 2009, +* Computational Image and Simulation Technologies in Biomedicine (CISTIB), +* Universitat Pompeu Fabra (UPF), Barcelona, Spain. All rights reserved. +* See license.txt file for details. +=========================================================================*/ + +#include "vtkMitkOpenglXRAYVolumeTextureMapper2D.h" +#include "vtkTimerLog.h" +#include "vtkPlaneCollection.h" + +#include "vtkCamera.h" +#include "vtkDataArray.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" +#include "vtkObjectFactory.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 +void vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume( T *data_ptr, + int size[3], + int axis, + int directionFlag, + vtkMitkOpenglXRAYVolumeTextureMapper2D *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; + } + + //****patch for x-ray + vtkOpenGLExtensionManager *extensions = vtkOpenGLExtensionManager::New(); + + int supports_GL_EXT_blend_minmax = extensions->ExtensionSupported( + "GL_EXT_blend_minmax" ); + + int supports_GL_EXT_blend_color = extensions->ExtensionSupported( + "GL_EXT_blend_color" ); + + if(supports_GL_EXT_blend_minmax && supports_GL_EXT_blend_color) + { + extensions->LoadExtension("GL_EXT_blend_minmax"); + extensions->LoadExtension("GL_EXT_blend_color"); + + extensions->SetRenderWindow(renWin); + + glPushAttrib (GL_COLOR_BUFFER_BIT); + glBlendFunc (GL_CONSTANT_ALPHA_EXT, GL_ONE); + vtkgl::BlendEquation (vtkgl::FUNC_REVERSE_SUBTRACT); + + //now calculate the inverse of the attenuation + float in_attenuation = me->GetXRayAttenuation(); + vtkgl::BlendColorEXT(1.0F, 1.0F, 1.0F, + in_attenuation/(static_cast((size[a2]-1) / me->GetInternalSkipFactor())+1)); + + glEnable (GL_BLEND); + std::cout << "Extensions to handle X-ray loaded" << std::endl; + } + else + { + std::cout << "Extensions to handle X-ray rendering are not supported" << std::endl; + return; + } + + + 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 = (static_cast( (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 = static_cast((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 / textureSize[0]; + offset[1] = 0.5 / textureSize[1]; + + for ( i = 0; i < numTiles; i++ ) + { + yTile = i / xTotal; + xTile = i % xTotal; + + t[i*8 + 0] = size[a0]*xTile/static_cast(textureSize[0]) + offset[0]; + t[i*8 + 1] = size[a1]*yTile/static_cast(textureSize[1]) + offset[1]; + t[i*8 + 2] = size[a0]*xTile/static_cast(textureSize[0]) + offset[0]; + t[i*8 + 3] = size[a1]*(yTile+1)/static_cast(textureSize[1]) - offset[1]; + t[i*8 + 4] = size[a0]*(xTile+1)/static_cast(textureSize[0]) - offset[0]; + t[i*8 + 5] = size[a1]*(yTile+1)/static_cast(textureSize[1]) - offset[1]; + t[i*8 + 6] = size[a0]*(xTile+1)/static_cast(textureSize[0]) - offset[0]; + t[i*8 + 7] = size[a1]*(yTile )/static_cast(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] * (size[a1]-1) + origin[a1]; + + v[i*12 + 6+a0] = spacing[a0] * (size[a0]-1) + origin[a0]; + v[i*12 + 6+a1] = spacing[a1] * (size[a1]-1) + origin[a1]; + + v[i*12 + 9+a0] = spacing[a0] * (size[a0]-1) + origin[a0]; + v[i*12 + 9+a1] = origin[a1]; + } + + 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; + + 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] * 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; + + //****patch for x-ray + glPopAttrib (); + extensions->Delete(); + //****end patch for x-ray + +} + +vtkCxxRevisionMacro(vtkMitkOpenglXRAYVolumeTextureMapper2D, "$Revision: 1.4 $"); + +//---------------------------------------------------------------------------- +// Needed when we don't use the vtkStandardNewMacro. +//vtkInstantiatorNewMacro(vtkMitkOpenglXRAYVolumeTextureMapper2D); +//---------------------------------------------------------------------------- + +vtkStandardNewMacro(vtkMitkOpenglXRAYVolumeTextureMapper2D); + +vtkMitkOpenglXRAYVolumeTextureMapper2D::vtkMitkOpenglXRAYVolumeTextureMapper2D() +{ + this->TargetTextureSize[0] = 512; + this->TargetTextureSize[1] = 512; + this->MaximumNumberOfPlanes = 0; + this->MaximumStorageSize = 0; + this->Texture = NULL; + this->TextureSize = 0; +} + +vtkMitkOpenglXRAYVolumeTextureMapper2D::~vtkMitkOpenglXRAYVolumeTextureMapper2D() +{ + if ( this->Texture ) + { + delete [] this->Texture; + } +} + + +//vtkMitkOpenglXRAYVolumeTextureMapper2D *vtkMitkOpenglXRAYVolumeTextureMapper2D::New() +//{ +// // First try to create the object from the vtkObjectFactory +// vtkObject* ret = +// vtkVolumeRenderingFactory::CreateInstance("vtkMitkOpenglXRAYVolumeTextureMapper2D"); +// return static_cast(ret); +//} + +void vtkMitkOpenglXRAYVolumeTextureMapper2D::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; + } + + + //****patch for x-ray + vtkOpenGLExtensionManager *extensions = vtkOpenGLExtensionManager::New(); + + int supports_GL_EXT_blend_minmax = extensions->ExtensionSupported( + "GL_EXT_blend_minmax" ); + + int supports_GL_EXT_blend_color = extensions->ExtensionSupported( + "GL_EXT_blend_color" ); + + if(supports_GL_EXT_blend_minmax && supports_GL_EXT_blend_color) + { + extensions->LoadExtension("GL_EXT_blend_minmax"); + extensions->LoadExtension("GL_EXT_blend_color"); + + extensions->SetRenderWindow(renWin); + + glPushAttrib (GL_COLOR_BUFFER_BIT); + glBlendFunc (GL_CONSTANT_ALPHA_EXT, GL_ONE); + vtkgl::BlendEquation(vtkgl::FUNC_REVERSE_SUBTRACT); + + float in_attenuation = GetXRayAttenuation(); + vtkgl::BlendColorEXT(1.0F, 1.0F, 1.0F, + in_attenuation/(static_cast((size[a2]-1) / this->GetInternalSkipFactor())+1)); + + glEnable (GL_BLEND); + std::cout << "Extensions to handle X-ray loaded" << std::endl; + } + else + { + std::cout << "Extensions to handle X-ray rendering are not supported" << std::endl; + return; + } + //****end patch for x-ray + + 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 = (static_cast( (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 = static_cast((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 / textureSize[0]; + offset[1] = 0.5 / 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] = size[a0]*xTile/static_cast(textureSize[0]) + offset[0]; + t[i*8 + 1] = size[a1]*yTile/static_cast(textureSize[1]) + offset[1]; + t[i*8 + 2] = size[a0]*xTile/static_cast(textureSize[0]) + offset[0]; + t[i*8 + 3] = size[a1]*(yTile+1)/static_cast(textureSize[1]) - offset[1]; + t[i*8 + 4] = size[a0]*(xTile+1)/static_cast(textureSize[0]) - offset[0]; + t[i*8 + 5] = size[a1]*(yTile+1)/static_cast(textureSize[1]) - offset[1]; + t[i*8 + 6] = size[a0]*(xTile+1)/static_cast(textureSize[0]) - offset[0]; + t[i*8 + 7] = size[a1]*yTile/static_cast(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] * (size[a1]-1) + origin[a1]; + + v[i*12 + 6+a0] = spacing[a0] * (size[a0]-1) + origin[a0]; + v[i*12 + 6+a1] = spacing[a1] * (size[a1]-1) + origin[a1]; + + v[i*12 + 9+a0] = spacing[a0] * (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] * 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; + + //****patch for x-ray + glPopAttrib (); + extensions->Delete(); + //****end patch for x-ray +} + +void vtkMitkOpenglXRAYVolumeTextureMapper2D::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; + + //****patch for x-ray + //rebuild the rgbaArray, since mtk transfer function create a mess for that! + int sz = vol->GetArraySize(); + int thr = (int) (sz*GetXRayThreshold()); + for(int i=0;iGetRGBAArray()[i] = 0; + else + this->GetRGBAArray()[i]= i >> 8; + + //****end patch for x-ray + + 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 ); + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 0, 1, this ); + + this->InitializeRender( ren, vol, VTK_PLUS_Y_MAJOR_DIRECTION ); + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 1, 1, this ); + + this->InitializeRender( ren, vol, VTK_PLUS_Z_MAJOR_DIRECTION ); + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 2, 1, this ); + break; + case VTK_UNSIGNED_SHORT: + this->InitializeRender( ren, vol, VTK_PLUS_X_MAJOR_DIRECTION ); + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 0, 1, this ); + + this->InitializeRender( ren, vol, VTK_PLUS_Y_MAJOR_DIRECTION ); + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 1, 1, this ); + + this->InitializeRender( ren, vol, VTK_PLUS_Z_MAJOR_DIRECTION ); + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(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: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 0, 1, this ); + break; + + case VTK_MINUS_X_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 0, 0, this ); + break; + + case VTK_PLUS_Y_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 1, 1, this ); + break; + + case VTK_MINUS_Y_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 1, 0, this ); + break; + + case VTK_PLUS_Z_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 2, 1, this ); + break; + + case VTK_MINUS_Z_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 2, 0, this ); + break; + } + break; + case VTK_UNSIGNED_SHORT: + switch ( this->MajorDirection ) + { + case VTK_PLUS_X_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 0, 1, this ); + break; + + case VTK_MINUS_X_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 0, 0, this ); + break; + + case VTK_PLUS_Y_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 1, 1, this ); + break; + + case VTK_MINUS_Y_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 1, 0, this ); + break; + + case VTK_PLUS_Z_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 2, 1, this ); + break; + + case VTK_MINUS_Z_MAJOR_DIRECTION: + vtkMitkOpenglXRAYVolumeTextureMapper2D_TraverseVolume + ( static_cast(inputPointer), size, 2, 0, this ); + break; + } + break; + default: + vtkErrorMacro( + "vtkMitkOpenglXRAYVolumeTextureMapper2D only works with unsigned short and unsigned char data.\n" << + "Input type: " << inputType << " given."); + } + } +} + +void vtkMitkOpenglXRAYVolumeTextureMapper2D::InitializeRender( vtkRenderer *ren, + vtkVolume *vol, + int majorDirection ) +{ + if ( majorDirection >= 0) + { + this->MajorDirection = majorDirection; + } + else + { + double vpn[3]; + + // Take the vpn, de 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 ( size[this->MajorDirection/2] / static_cast(this->InternalSkipFactor) > static_cast(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 + + double *dspacing; + dspacing = this->GetInput()->GetSpacing(); + this->DataSpacing[0] = dspacing[0]; + this->DataSpacing[1] = dspacing[1]; + this->DataSpacing[2] = dspacing[2]; + this->SampleDistance = + this->DataSpacing[this->MajorDirection/2]*this->InternalSkipFactor*1.2071; + this->vtkVolumeTextureMapper::InitializeRender( ren, vol ); +} + +void vtkMitkOpenglXRAYVolumeTextureMapper2D::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]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 vtkMitkOpenglXRAYVolumeTextureMapper2D +void vtkMitkOpenglXRAYVolumeTextureMapper2D::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 << "" << endl; + } + + os << indent << "Maximum Storage Size: " + << this->MaximumStorageSize << endl; + + this->Superclass::PrintSelf(os,indent); +} + + +void vtkMitkOpenglXRAYVolumeTextureMapper2D::Render(vtkRenderer *ren, vtkVolume *vol) +{ + vtkMatrix4x4 *matrix = vtkMatrix4x4::New(); + vtkPlaneCollection *clipPlanes; + vtkPlane *plane; + int i, numClipPlanes = 0; + double planeEquation[4]; + + this->Timer->StartTimer(); + + // Let the superclass take care of some initialization + this->InitializeRender( ren, vol ); + + // build transformation + vol->GetMatrix(matrix); + matrix->Transpose(); + + // Use the OpenGL clip planes + clipPlanes = this->ClippingPlanes; + if ( clipPlanes ) + { + numClipPlanes = clipPlanes->GetNumberOfItems(); + if (numClipPlanes > 6) + { + vtkErrorMacro(<< "OpenGL guarantees only 6 additional clipping planes"); + } + + for (i = 0; i < numClipPlanes; i++) + { + glEnable((GLenum)(GL_CLIP_PLANE0+i)); + + plane = (vtkPlane *)clipPlanes->GetItemAsObject(i); + + planeEquation[0] = plane->GetNormal()[0]; + planeEquation[1] = plane->GetNormal()[1]; + planeEquation[2] = plane->GetNormal()[2]; + planeEquation[3] = -(planeEquation[0]*plane->GetOrigin()[0]+ + planeEquation[1]*plane->GetOrigin()[1]+ + planeEquation[2]*plane->GetOrigin()[2]); + glClipPlane((GLenum)(GL_CLIP_PLANE0+i),planeEquation); + } + } + + + // insert model transformation + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glMultMatrixd(matrix->Element[0]); + + // Turn lighting off - the polygon textures already have illumination + glDisable( GL_LIGHTING ); + + // Turn texturing on so that we can draw the textured polygons + glEnable( GL_TEXTURE_2D ); + +#ifdef GL_VERSION_1_1 + GLuint tempIndex; + glGenTextures(1, &tempIndex); + glBindTexture(GL_TEXTURE_2D, tempIndex); +#endif + + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + glColor3f( 1.0, 1.0, 1.0 ); + + this->GenerateTexturesAndRenderQuads( ren, vol ); + + // pop transformation matrix + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + + matrix->Delete(); + + glDisable( GL_TEXTURE_2D ); + +#ifdef GL_VERSION_1_1 + glFlush(); + glDeleteTextures(1, &tempIndex); +#endif + + // Turn lighting back on + glEnable( GL_LIGHTING ); + + if ( clipPlanes ) + { + for (i = 0; i < numClipPlanes; i++) + { + glDisable((GLenum)(GL_CLIP_PLANE0+i)); + } + } + + this->Timer->StopTimer(); + + this->TimeToDraw = (float)this->Timer->GetElapsedTime(); + + // If the timer is not accurate enough, set it to a small + // time so that it is not zero + if ( this->TimeToDraw == 0.0 ) + { + this->TimeToDraw = 0.0001; + } +} + +void vtkMitkOpenglXRAYVolumeTextureMapper2D::RenderQuads( int numQuads, + float *v, + float *t, + unsigned char *texture, + int size[2], int reverseFlag ) +{ +#ifdef GL_VERSION_1_1 + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, size[0], size[1], + 0, GL_RGBA, GL_UNSIGNED_BYTE, texture ); +#else + glTexImage2D( GL_TEXTURE_2D, 0, 4, size[0], size[1], + 0, GL_RGBA, GL_UNSIGNED_BYTE, texture ); +#endif + + glBegin( GL_QUADS ); + + float *tptr, *vptr; + int i, j; + + if ( reverseFlag ) + { + for ( i = 0; i < numQuads; i++ ) + { + tptr = t+2*4*(numQuads-i-1); + vptr = v+3*4*(numQuads-i-1); + for ( j = 0; j < 4; j++ ) + { + glTexCoord2fv( tptr ); + glVertex3fv( vptr ); + tptr += 2; + vptr += 3; + } + } + } + else + { + tptr = t; + vptr = v; + for ( i = 0; i < numQuads*4; i++ ) + { + glTexCoord2fv( tptr ); + glVertex3fv( vptr ); + tptr += 2; + vptr += 3; + } + } + + glEnd(); +} + + Property changes on: Modules\MitkExt\Rendering\vtkMitkOpenglXRAYVolumeTextureMapper2D.cxx ___________________________________________________________________ Added: svn:eol-style + native Index: Modules/MitkExt/Rendering/vtkMitkOpenglXRAYVolumeTextureMapper2D.h =================================================================== --- Modules/MitkExt/Rendering/vtkMitkOpenglXRAYVolumeTextureMapper2D.h (revision 0) +++ Modules/MitkExt/Rendering/vtkMitkOpenglXRAYVolumeTextureMapper2D.h (revision 0) @@ -0,0 +1,155 @@ +/*========================================================================= +/* +* Copyright (c) 2009, +* Computational Image and Simulation Technologies in Biomedicine (CISTIB), +* Universitat Pompeu Fabra (UPF), Barcelona, Spain. All rights reserved. +* See license.txt file for details. +*/ + + +/*=========================================================================*/ +// .NAME vtkMitkOpenglXRAYVolumeTextureMapper2D - class for a volume mapper for XRay Rendering with 2D Textures +// this class is derived directly by vtkVolumeTexture2D and vtkOpenglVolumeTexture2d + +// .SECTION Description +// vtkMitkOpenglXRAYVolumeTextureMapper2D renders a volume using 2D texture mapping. + + +// .SECTION see also +// vtkVolumeMapper + +#ifndef __vtkMitkOpenglXRAYVolumeTextureMapper2D_h +#define __vtkMitkOpenglXRAYVolumeTextureMapper2D_h + +//****patch for x-ray +#include "vtkOpenGLExtensionManager.h" +#include "vtkgl.h" // vtkgl namespace +#include "ParseOGLExt/headers/glext.h" +//****end of patch for x-ray + +#include "vtkVolumeTextureMapper.h" + +#include "mitkCommon.h" + +class MITKEXT_CORE_EXPORT vtkMitkOpenglXRAYVolumeTextureMapper2D : public vtkVolumeTextureMapper +{ +public: + vtkTypeRevisionMacro(vtkMitkOpenglXRAYVolumeTextureMapper2D,vtkVolumeTextureMapper); + void PrintSelf( ostream& os, vtkIndent indent ); + + static vtkMitkOpenglXRAYVolumeTextureMapper2D *New(); + + // Description: + // Target size in pixels of each size of the texture for downloading. Default is + // 512x512 - so a 512x512 texture will be tiled with as many slices of the volume + // as possible, then all the quads will be rendered. This can be set to optimize + // for a particular architecture. This must be set with numbers that are a power + // of two. + vtkSetVector2Macro( TargetTextureSize, int ); + vtkGetVector2Macro( TargetTextureSize, int ); + + // Description: + // This is the maximum number of planes that will be created for texture mapping + // the volume. If the volume has more voxels than this along the viewing direction, + // then planes of the volume will be skipped to ensure that this maximum is not + // violated. A skip factor is used, and is incremented until the maximum condition + // is satisfied. + vtkSetMacro( MaximumNumberOfPlanes, int ); + vtkGetMacro( MaximumNumberOfPlanes, int ); + + // Description: + // This is the maximum size of saved textures in bytes. If this size is large + // enough to hold the RGBA textures for all three directions (XxYxZx3x4 is + // the approximate value - it is actually a bit larger due to wasted space in + // the textures) then the textures will be saved. + vtkSetMacro( MaximumStorageSize, int ); + vtkGetMacro( MaximumStorageSize, int ); + + + // Description: + // Set/Get the xRayAttenuation factor. + vtkSetMacro( XRayAttenuation, double ); + void SetXRayAttenuationDefault() + { this->SetXRayAttenuation(1.0); } + vtkGetMacro( XRayAttenuation, double ); + + // Description: + // Set/Get the xRayThreshold factor. + vtkSetMacro( XRayThreshold, double ); + void SetXRayThresholdDefault() + { this->SetXRayThreshold(0.5); } + vtkGetMacro( XRayThreshold, double ); + +//BTX + + // Description: + // WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE + // DO NOT USE THIS METHOD OUTSIDE OF THE RENDERING PROCESS + // Render the volume + + // Description: + // WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE + // DO NOT USE THIS METHOD OUTSIDE OF THE RENDERING PROCESS + // Render the volume + + virtual void Render(vtkRenderer *ren, vtkVolume *vol); + + + void RenderQuads( int count, float *v, float *t, + unsigned char *texture, int size[2], int reverseFlag); + + + // Description: + // Made public only for access from the templated method. Not a vtkGetMacro + // to avoid the PrintSelf defect. + int GetInternalSkipFactor() {return this->InternalSkipFactor;}; + + int *GetAxisTextureSize() {return &(this->AxisTextureSize[0][0]);}; + + int GetSaveTextures() {return this->SaveTextures;}; + + unsigned char *GetTexture() {return this->Texture;}; + +//ETX + + +protected: + vtkMitkOpenglXRAYVolumeTextureMapper2D(); + ~vtkMitkOpenglXRAYVolumeTextureMapper2D(); + + void InitializeRender( vtkRenderer *ren, vtkVolume *vol ) + {this->InitializeRender( ren, vol, -1 );} + + void InitializeRender( vtkRenderer *ren, vtkVolume *vol, int majorDirection ); + + void GenerateTexturesAndRenderQuads( vtkRenderer *ren, vtkVolume *vol ); + + int MajorDirection; + int TargetTextureSize[2]; + + int MaximumNumberOfPlanes; + int InternalSkipFactor; + int MaximumStorageSize; + + double XRayAttenuation; + double XRayThreshold; + + unsigned char *Texture; + int TextureSize; + int SaveTextures; + vtkTimeStamp TextureMTime; + + int AxisTextureSize[3][3]; + void ComputeAxisTextureSize( int axis, int *size ); + + void RenderSavedTexture(); + +private: + vtkMitkOpenglXRAYVolumeTextureMapper2D(const vtkMitkOpenglXRAYVolumeTextureMapper2D&); // Not implemented. + void operator=(const vtkMitkOpenglXRAYVolumeTextureMapper2D&); // Not implemented. +}; + + +#endif + + Property changes on: Modules\MitkExt\Rendering\vtkMitkOpenglXRAYVolumeTextureMapper2D.h ___________________________________________________________________ Added: svn:eol-style + native Index: Core/Code/DataManagement/mitkTransferFunction.cpp =================================================================== --- Core/Code/DataManagement/mitkTransferFunction.cpp (revision 21081) +++ Core/Code/DataManagement/mitkTransferFunction.cpp (working copy) @@ -32,6 +32,9 @@ m_ScalarOpacityFunction = vtkPiecewiseFunction::New(); m_ColorTransferFunction = vtkColorTransferFunction::New(); m_GradientOpacityFunction = vtkPiecewiseFunction::New(); + + m_TF_XR_VRthreshold=0.5; //default threshold + m_Mode=-1; //unknown mode m_ScalarOpacityFunction->Initialize(); m_ScalarOpacityFunction->AddPoint(0,1); @@ -106,6 +109,16 @@ return true; } +void mitk::TransferFunction::SetXRVRThreshold(double thr) +{ + if((thr>=0.1)&&(thr<=0.9)) + m_TF_XR_VRthreshold=thr; +} + +double mitk::TransferFunction::GetXRVRThreshold() +{ + return m_TF_XR_VRthreshold; +} void TransferFunction::SetScalarOpacityPoints(TransferFunction::ControlPoints points) { @@ -300,20 +313,14 @@ m_Max = (int)GetHistogram()->GetBinMax(0, GetHistogram()->Size()-1); } -void TransferFunction::SetTransferFunctionMode( int mode ) +int mitk::TransferFunction::GetTransferFunctionMode( ) { - //Define Transfer Function - enum TransferFunctionMode{ - TF_CT_DEFAULT, - TF_CT_BLACK_WHITE, - TF_CT_THORAX_LARGE, - TF_CT_THORAX_SMALL, - TF_CT_BONE, - TF_CT_BONE_GRADIENT, - TF_CT_CARDIAC, - TF_MR_GENERIC - }; + return m_Mode; +} +void TransferFunction::SetTransferFunctionMode( int mode ) +{ + m_Mode=mode; //remove all old points m_ScalarOpacityFunction->RemoveAllPoints(); m_ColorTransferFunction->RemoveAllPoints(); @@ -550,7 +557,54 @@ m_GradientOpacityFunction->AddPoint( 255, 1); break; + + case ( TF_MR_MIP ): + //Set Opacity + m_ScalarOpacityFunction->Initialize(); + m_ScalarOpacityFunction->AddPoint( 0, 0 ); + m_ScalarOpacityFunction->AddPoint( 98.3725, 0 ); + m_ScalarOpacityFunction->AddPoint( 416.637, 1 ); + m_ScalarOpacityFunction->AddPoint( 2800, 0 ); + + //Set Color + m_ColorTransferFunction->RemoveAllPoints(); + m_ColorTransferFunction->AddRGBPoint( 0, 1, 1, 1 ); + m_ColorTransferFunction->AddRGBPoint( 98.3725, 1, 1, 1 ); + m_ColorTransferFunction->AddRGBPoint( 416.637, 1, 1, 1 ); + m_ColorTransferFunction->AddRGBPoint( 2800, 1, 1, 1 ); + + //Set Gradient + m_GradientOpacityFunction->Initialize(); + m_GradientOpacityFunction->AddPoint( 0, 1 ); + m_GradientOpacityFunction->AddPoint( 255, 1 ); + + break; + + case (TF_XR_VR): + //Set Opacity + m_ScalarOpacityFunction->Initialize(); + m_ScalarOpacityFunction->AddPoint(m_Min,0.0); + m_ScalarOpacityFunction->AddPoint(m_Max,1.0); + + double x0; + x0= m_Min+(m_TF_XR_VRthreshold* (m_Max-m_Min)); + m_ScalarOpacityFunction->AddPoint(x0,0.0,0.5, 0); + m_ScalarOpacityFunction->AddPoint(x0+1,(x0+1-m_Min)/(m_Max-m_Min), 0.5, 0); + + + //Set Color + m_ColorTransferFunction->RemoveAllPoints(); + m_ColorTransferFunction->AddRGBPoint(m_Min, 0, 0, 0); + m_ColorTransferFunction->AddRGBPoint(m_Max, 1, 1, 1); + + //Set Gradient + m_GradientOpacityFunction->Initialize(); + m_GradientOpacityFunction->AddPoint( 0, 1, 0.5, 0 ); + m_GradientOpacityFunction->AddPoint( 255, 1, 0.5, 0); + std::cout << "TF_XR_VR added" << std::endl; + break; + default: Index: Core/Code/DataManagement/mitkTransferFunction.h =================================================================== --- Core/Code/DataManagement/mitkTransferFunction.h (revision 21081) +++ Core/Code/DataManagement/mitkTransferFunction.h (working copy) @@ -55,6 +55,19 @@ typedef std::vector > ControlPoints; typedef std::vector > > RGBControlPoints; + + enum TransferFunctionMode{ + TF_CT_DEFAULT, + TF_CT_BLACK_WHITE, + TF_CT_THORAX_LARGE, + TF_CT_THORAX_SMALL, + TF_CT_BONE, + TF_CT_BONE_GRADIENT, + TF_CT_CARDIAC, + TF_MR_GENERIC, + TF_MR_MIP, + TF_XR_VR, + }; mitkClassMacro(TransferFunction, itk::DataObject); @@ -156,7 +169,15 @@ void ClearRGBPoints(); bool operator==(Self& other); - + + //! Return the current mode + int GetTransferFunctionMode( ); + + //! Set Threshold for TF_XR_VR mode (thr must be in the [0.1..0.9] range) + void SetXRVRThreshold( double thr ); + + //! Get Threshold for TF_XR_VR mode (thr is in the [0.1..0.9] range) + double GetXRVRThreshold( ); protected: TransferFunction(); @@ -190,6 +211,9 @@ /** Temporary STL style copy of VTK internal control points */ TransferFunction::RGBControlPoints m_RGBPoints; + double m_TF_XR_VRthreshold; + int m_Mode; //current mode + }; } Index: Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp =================================================================== --- Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp (revision 21149) +++ Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp (working copy) @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -179,6 +180,12 @@ m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); CreateDefaultTransferFunctions(); + + m_XR_T2DMapper = vtkMitkOpenglXRAYVolumeTextureMapper2D::New(); + m_ImageCast = vtkImageShiftScale::New(); + m_ImageCast->SetOutputScalarTypeToUnsignedShort(); + m_ImageCast->ClampOverflowOn(); + m_XR_T2DMapper->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); gpuInitialized=cpuInitialized=false; @@ -200,6 +207,9 @@ m_BinaryColorTransferFunction->Delete(); m_BinaryOpacityTransferFunction->Delete(); m_BinaryGradientTransferFunction->Delete(); + + m_XR_T2DMapper->Delete(); + m_ImageCast->Delete(); } vtkProp *mitk::GPUVolumeMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) @@ -302,6 +312,41 @@ m_MapperGPU->SetSampleDistance(1.0); } + bool isXRayVolumeRendering = false; + if ( dynamic_cast(GetDataTreeNode()->GetProperty("xrayvolumerendering",renderer))!=NULL && + dynamic_cast(GetDataTreeNode()->GetProperty("xrayvolumerendering",renderer))->GetValue() == true + ) + { + isXRayVolumeRendering = true; + m_VolumeGPU->SetMapper(m_XR_T2DMapper); + + mitk::DoubleProperty* xRayAttenuationProperty=dynamic_cast(GetDataTreeNode()->GetProperty("xrayattenuation",renderer)); + if(xRayAttenuationProperty==NULL) + { + xRayAttenuationProperty = mitk::DoubleProperty::New(m_XR_T2DMapper->GetXRayAttenuation()); + GetDataTreeNode()->SetProperty("xrayattenuation",xRayAttenuationProperty,renderer); + + } + mitk::DoubleProperty* xRayTFThresholdProperty=dynamic_cast(GetDataTreeNode()->GetProperty("xraythreshold",renderer)); + if(xRayTFThresholdProperty==NULL) + { + xRayTFThresholdProperty = mitk::DoubleProperty::New(m_XR_T2DMapper->GetXRayThreshold()); + GetDataTreeNode()->SetProperty("xraythreshold",xRayTFThresholdProperty,renderer); + } + m_XR_T2DMapper->SetXRayAttenuation(xRayAttenuationProperty->GetValue()); + m_XR_T2DMapper->SetXRayThreshold(xRayTFThresholdProperty->GetValue()); + } + else + { + mitk::BoolProperty* xRayVolProperty=dynamic_cast(GetDataTreeNode()->GetProperty("xrayvolumerendering",renderer)); + if(xRayVolProperty==NULL) + { + xRayVolProperty = mitk::BoolProperty::New(false); + GetDataTreeNode()->SetProperty("xrayvolumerendering",xRayVolProperty,renderer); + } + m_VolumeGPU->SetMapper(m_MapperGPU); + } + int timestep=0; ScalarType time = worldgeometry->GetTimeBounds()[0]; if (time> ScalarTypeNumericTraits::NonpositiveMin()) @@ -314,7 +359,13 @@ if(inputData==NULL) return; - m_UnitSpacingImageFilter->SetInput( inputData ); + if(isXRayVolumeRendering) + { + m_ImageCast->SetInput( inputData ); + m_UnitSpacingImageFilter->SetInput(m_ImageCast->GetOutput()); + } + else + m_UnitSpacingImageFilter->SetInput( inputData ); UpdateTransferFunctions( renderer ); @@ -390,6 +441,41 @@ m_MapperCPU->SetSampleDistance(1.0); } + bool isXRayVolumeRendering =false; + if ( dynamic_cast(GetDataTreeNode()->GetProperty("xrayvolumerendering",renderer))!=NULL && + dynamic_cast(GetDataTreeNode()->GetProperty("xrayvolumerendering",renderer))->GetValue() == true + ) + { + isXRayVolumeRendering = true; + m_VolumeCPU->SetMapper(m_XR_T2DMapper); + + mitk::DoubleProperty* xRayAttenuationProperty=dynamic_cast(GetDataTreeNode()->GetProperty("xrayattenuation",renderer)); + if(xRayAttenuationProperty==NULL) + { + xRayAttenuationProperty = mitk::DoubleProperty::New(m_XR_T2DMapper->GetXRayAttenuation()); + GetDataTreeNode()->SetProperty("xrayattenuation",xRayAttenuationProperty,renderer); + + } + mitk::DoubleProperty* xRayTFThresholdProperty=dynamic_cast(GetDataTreeNode()->GetProperty("xraythreshold",renderer)); + if(xRayTFThresholdProperty==NULL) + { + xRayTFThresholdProperty = mitk::DoubleProperty::New(m_XR_T2DMapper->GetXRayThreshold()); + GetDataTreeNode()->SetProperty("xraythreshold",xRayTFThresholdProperty,renderer); + } + m_XR_T2DMapper->SetXRayAttenuation(xRayAttenuationProperty->GetValue()); + m_XR_T2DMapper->SetXRayThreshold(xRayTFThresholdProperty->GetValue()); + } + else + { + mitk::BoolProperty* xRayVolProperty=dynamic_cast(GetDataTreeNode()->GetProperty("xrayvolumerendering",renderer)); + if(xRayVolProperty==NULL) + { + xRayVolProperty = mitk::BoolProperty::New(false); + GetDataTreeNode()->SetProperty("xrayvolumerendering",xRayVolProperty,renderer); + } + m_VolumeCPU->SetMapper(m_MapperCPU); + } + int timestep=0; ScalarType time = worldgeometry->GetTimeBounds()[0]; if (time> ScalarTypeNumericTraits::NonpositiveMin()) @@ -402,7 +488,13 @@ if(inputData==NULL) return; - m_UnitSpacingImageFilter->SetInput( inputData ); + if(isXRayVolumeRendering) + { + m_ImageCast->SetInput( inputData ); + m_UnitSpacingImageFilter->SetInput(m_ImageCast->GetOutput()); + } + else + m_UnitSpacingImageFilter->SetInput( inputData ); UpdateTransferFunctions( renderer ); Index: Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h =================================================================== --- Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h (revision 21149) +++ Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.h (working copy) @@ -49,6 +49,7 @@ class vtkPolyDataMapper; class vtkActor; +class vtkMitkOpenglXRAYVolumeTextureMapper2D; namespace mitk { @@ -108,7 +109,9 @@ vtkMitkVolumeTextureMapper3D* m_MapperGPU; vtkFixedPointVolumeRayCastMapper* m_MapperCPU; - + vtkMitkOpenglXRAYVolumeTextureMapper2D* m_XR_T2DMapper; + vtkImageShiftScale* m_ImageCast; + vtkVolume * m_VolumeGPU; vtkVolume * m_VolumeCPU;