/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkVolumeTextureMapper.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 "vtkVolumeTextureMapper.h" #include "vtkEncodedGradientShader.h" #include "vtkFiniteDifferenceGradientEstimator.h" #include "vtkGarbageCollector.h" #include "vtkImageData.h" #include "vtkPointData.h" #include "vtkRenderer.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" vtkCxxRevisionMacro(vtkVolumeTextureMapper, "$Revision: 1.2 $"); vtkVolumeTextureMapper::vtkVolumeTextureMapper() { this->GradientOpacityArray = NULL; this->RGBAArray = NULL; this->ArraySize = -1; this->SampleDistance = 1.0; this->GradientEstimator = vtkFiniteDifferenceGradientEstimator::New(); this->GradientShader = vtkEncodedGradientShader::New(); this->NumberOfComponents = 1; } vtkVolumeTextureMapper::~vtkVolumeTextureMapper() { this->SetGradientEstimator( NULL ); this->GradientShader->Delete(); if ( this->RGBAArray ) { delete [] this->RGBAArray; } if ( this->GradientOpacityArray ) { delete [] this->GradientOpacityArray; } } void vtkVolumeTextureMapper::SetGradientEstimator( vtkEncodedGradientEstimator *gradest ) { // If we are setting it to its current value, don't do anything if ( this->GradientEstimator == gradest ) { return; } // If we already have a gradient estimator, unregister it. if ( this->GradientEstimator ) { this->GradientEstimator->UnRegister(this); this->GradientEstimator = NULL; } // If we are passing in a non-NULL estimator, register it if ( gradest ) { gradest->Register( this ); } // Actually set the estimator, and consider the object Modified this->GradientEstimator = gradest; this->Modified(); } void vtkVolumeTextureMapper::Update() { if ( this->GetInput() ) { this->GetInput()->UpdateInformation(); this->GetInput()->SetUpdateExtentToWholeExtent(); this->GetInput()->Update(); } } void vtkVolumeTextureMapper::InitializeRender( vtkRenderer *ren, vtkVolume *vol ) { int size, i, j, k; float *AArray; float *RGBArray; float *GArray; int colorChannels; float gradientOpacityConstant; // Hang on to the render window - we'll need it to test for abort this->RenderWindow = ren->GetRenderWindow(); vol->UpdateTransferFunctions( ren ); vol->UpdateScalarOpacityforSampleSize( ren, this->SampleDistance ); size = (int) vol->GetArraySize(); int numComponents = this->GetInput()-> GetPointData()->GetScalars()->GetNumberOfComponents(); if ( this->ArraySize != size || this->NumberOfComponents != numComponents ) { if ( this->RGBAArray ) { delete [] this->RGBAArray; } if ( this->GradientOpacityArray ) { delete [] this->GradientOpacityArray; } this->RGBAArray = new unsigned char [4*size*numComponents]; this->GradientOpacityArray = new float [256*numComponents]; this->ArraySize = size; this->NumberOfComponents = numComponents; } float *goPtr; float *goArray; for ( int c = 0; c < numComponents; c++ ) { goPtr = vol->GetGradientOpacityArray(c); goArray = this->GradientOpacityArray + c; for ( i = 0; i < 256; i++ ) { *(goArray) = *(goPtr++); goArray += numComponents; } AArray = vol->GetCorrectedScalarOpacityArray(c); colorChannels = vol->GetProperty()->GetColorChannels(c); // Being less than 0.0 implies a transfer function, so just multiply by // 1.0 here since the transfer function will supply the true opacity // modulation value gradientOpacityConstant = vol->GetGradientOpacityConstant(c); if ( gradientOpacityConstant <= 0.0 ) { gradientOpacityConstant = 1.0; } if ( colorChannels == 3 ) { RGBArray = vol->GetRGBArray(c); for ( i=0, j=(c*4), k=0; i < size; i++ ) { this->RGBAArray[j++] = (unsigned char) (0.5 + (RGBArray[k++]*255.0)); this->RGBAArray[j++] = (unsigned char) (0.5 + (RGBArray[k++]*255.0)); this->RGBAArray[j++] = (unsigned char) (0.5 + (RGBArray[k++]*255.0)); this->RGBAArray[j++] = (unsigned char) (0.5 + AArray[i]*255.0*gradientOpacityConstant); j += 4*(numComponents-1); } } else if ( colorChannels == 1 ) { GArray = vol->GetGrayArray(c); for ( i=0, j=(c*4); i < size; i++ ) { this->RGBAArray[j++] = (unsigned char) (0.5 + (GArray[i]*255.0)); this->RGBAArray[j++] = (unsigned char) (0.5 + (GArray[i]*255.0)); this->RGBAArray[j++] = (unsigned char) (0.5 + (GArray[i]*255.0)); this->RGBAArray[j++] = (unsigned char) (0.5 + AArray[i]*255.0*gradientOpacityConstant); j += 4*(numComponents-1); } } } this->Shade = vol->GetProperty()->GetShade(); this->GradientEstimator->SetInput( this->GetInput() ); if ( this->Shade ) { this->GradientShader->UpdateShadingTable( ren, vol, this->GradientEstimator ); this->EncodedNormals = this->GradientEstimator->GetEncodedNormals(); this->RedDiffuseShadingTable = this->GradientShader->GetRedDiffuseShadingTable(vol); this->GreenDiffuseShadingTable = this->GradientShader->GetGreenDiffuseShadingTable(vol); this->BlueDiffuseShadingTable = this->GradientShader->GetBlueDiffuseShadingTable(vol); this->RedSpecularShadingTable = this->GradientShader->GetRedSpecularShadingTable(vol); this->GreenSpecularShadingTable = this->GradientShader->GetGreenSpecularShadingTable(vol); this->BlueSpecularShadingTable = this->GradientShader->GetBlueSpecularShadingTable(vol); } else { this->EncodedNormals = NULL; this->RedDiffuseShadingTable = NULL; this->GreenDiffuseShadingTable = NULL; this->BlueDiffuseShadingTable = NULL; this->RedSpecularShadingTable = NULL; this->GreenSpecularShadingTable = NULL; this->BlueSpecularShadingTable = NULL; } // If we have non-constant opacity on the gradient magnitudes, // we need to use the gradient magnitudes to look up the opacity if ( vol->GetGradientOpacityConstant() == -1.0 ) { this->GradientMagnitudes = this->GradientEstimator->GetGradientMagnitudes(); } else { this->GradientMagnitudes = NULL; } this->GetInput()->GetOrigin( this->DataOrigin ); this->GetInput()->GetSpacing( this->DataSpacing ); this->ConvertCroppingRegionPlanesToVoxels(); } float vtkVolumeTextureMapper::GetGradientMagnitudeScale() { if ( !this->GradientEstimator ) { vtkErrorMacro( "You must have a gradient estimator set to get the scale" ); return 1.0; } return this->GradientEstimator->GetGradientMagnitudeScale(); } float vtkVolumeTextureMapper::GetGradientMagnitudeBias() { if ( !this->GradientEstimator ) { vtkErrorMacro( "You must have a gradient estimator set to get the bias" ); return 1.0; } return this->GradientEstimator->GetGradientMagnitudeBias(); } // Print the vtkVolumeTextureMapper void vtkVolumeTextureMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if ( this->GradientEstimator ) { os << indent << "Gradient Estimator: " << (this->GradientEstimator) << endl; } else { os << indent << "Gradient Estimator: (none)" << endl; } if ( this->GradientShader ) { os << indent << "Gradient Shader: " << (this->GradientShader) << endl; } else { os << indent << "Gradient Shader: (none)" << endl; } // this->Shade is a temporary variable that should not be printed // this->RenderWindow is a temporary variable that should not be printed // this->DataSpacing is a temporary variable that should not be printed // this->DataOrigin is a temporary variable that should not be printed } //---------------------------------------------------------------------------- void vtkVolumeTextureMapper::ReportReferences(vtkGarbageCollector* collector) { this->Superclass::ReportReferences(collector); // These filters share our input and are therefore involved in a // reference loop. vtkGarbageCollectorReport(collector, this->GradientEstimator, "GradientEstimator"); }