diff --git a/Core/Code/Interactions/mitkVtkInteractorStyle.cxx b/Core/Code/Interactions/mitkVtkInteractorStyle.cxx index c8aab74d14..ce1ef689f2 100644 --- a/Core/Code/Interactions/mitkVtkInteractorStyle.cxx +++ b/Core/Code/Interactions/mitkVtkInteractorStyle.cxx @@ -1,50 +1,49 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVtkInteractorStyle.h" #include #include -vtkCxxRevisionMacro(mitkVtkInteractorStyle, "$Revision: 1.35 $"); vtkStandardNewMacro(mitkVtkInteractorStyle); mitkVtkInteractorStyle::mitkVtkInteractorStyle() : vtkInteractorStyleUser() { } mitkVtkInteractorStyle::~mitkVtkInteractorStyle() { } void mitkVtkInteractorStyle::OnMouseWheelForward() { if (this->HasObserver(vtkCommand::MouseWheelForwardEvent)) { this->InvokeEvent(vtkCommand::MouseWheelForwardEvent, NULL); } } void mitkVtkInteractorStyle::OnMouseWheelBackward() { if (this->HasObserver(vtkCommand::MouseWheelBackwardEvent)) { this->InvokeEvent(vtkCommand::MouseWheelBackwardEvent, NULL); } } diff --git a/Core/Code/Interactions/mitkVtkInteractorStyle.h b/Core/Code/Interactions/mitkVtkInteractorStyle.h index a7e4f68c6a..1eea8fea67 100644 --- a/Core/Code/Interactions/mitkVtkInteractorStyle.h +++ b/Core/Code/Interactions/mitkVtkInteractorStyle.h @@ -1,64 +1,64 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /** * \brief Implements the handling of events that are missing for MITK interaction. * * This class inherits from vtkInteractorStyleUser, a class that handles * VTK-Events and invokes callbacks by means of an observer pattern. * * Most event-types needed for typical MITK interaction have already * been implemented in vtkInteractorStyleUser (Mouse-Buttons + Keyboard). * However, wheel-events and widgetModifed-events (whatever these are) * have not been handled so far. This is the purpose of this class. */ #ifndef __mitkVtkInteractorStyle_h #define __mitkVtkInteractorStyle_h #include "MitkExports.h" #include class MITK_CORE_EXPORT mitkVtkInteractorStyle : public vtkInteractorStyleUser { public: // default VTK c'tor static mitkVtkInteractorStyle *New(); - vtkTypeRevisionMacro(mitkVtkInteractorStyle,vtkInteractorStyleUser); + vtkTypeMacro(mitkVtkInteractorStyle,vtkInteractorStyleUser); /** * \brief Called when scrolling forwards with the mouse-wheel. */ virtual void OnMouseWheelForward(); /** * \brief Called when scrolling backwards with the mouse-wheel. */ virtual void OnMouseWheelBackward(); protected: mitkVtkInteractorStyle(); ~mitkVtkInteractorStyle(); private: mitkVtkInteractorStyle(const mitkVtkInteractorStyle&); // Not implemented. void operator=(const mitkVtkInteractorStyle&); // Not implemented. }; #endif diff --git a/Core/Code/Rendering/mitkVtkEventProvider.cpp b/Core/Code/Rendering/mitkVtkEventProvider.cpp index 00afec82d7..42fd99274d 100644 --- a/Core/Code/Rendering/mitkVtkEventProvider.cpp +++ b/Core/Code/Rendering/mitkVtkEventProvider.cpp @@ -1,241 +1,240 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVtkEventProvider.h" #include "mitkVtkEventAdapter.h" #include #include #include #include #include #include "mitkInteractionEvent.h" #define VTKEVENTPROVIDER_INFO MBI_INFO("mitk.core.vtkeventprovider") #define VTKEVENTPROVIDER_WARN MBI_WARN("mitk.core.vtkeventprovider") #define VTKEVENTPROVIDER_ERROR MBI_ERROR("mitk.core.vtkeventprovider") #define VTKEVENTPROVIDER_DEBUG MBI_DEBUG("mitk.core.vtkeventprovider") namespace mitk { - vtkCxxRevisionMacro(vtkEventProvider, "$Revision: 1.18 $"); vtkStandardNewMacro(vtkEventProvider); } //---------------------------------------------------------------------------- mitk::vtkEventProvider::vtkEventProvider() { // priority of the observer/command; we want MITK events processed in the very beginning this->Priority = 99999.99; //take over the processing of delete and keypress events from the superclass this->EventCallbackCommand->SetCallback(vtkEventProvider::ProcessEvents); // Set/Get the passive observer flag. If this is set to true, this // indicates that this command does not change the state of the // system in any way. Passive observers are processed first, and // are not called even when another command has focus. this->EventCallbackCommand->SetPassiveObserver(1); // get events first // mouse move AddInteractionEvent(vtkCommand::MouseMoveEvent); // mouse press AddInteractionEvent(vtkCommand::LeftButtonPressEvent); AddInteractionEvent(vtkCommand::MiddleButtonPressEvent); AddInteractionEvent(vtkCommand::RightButtonPressEvent); // mouse release AddInteractionEvent(vtkCommand::LeftButtonReleaseEvent); AddInteractionEvent(vtkCommand::MiddleButtonReleaseEvent); AddInteractionEvent(vtkCommand::RightButtonReleaseEvent); // wheel event AddInteractionEvent(vtkCommand::MouseWheelBackwardEvent); AddInteractionEvent(vtkCommand::MouseWheelForwardEvent); // key press event AddInteractionEvent(vtkCommand::KeyPressEvent); } mitk::vtkEventProvider::~vtkEventProvider() { this->SetInteractor(0); } void mitk::vtkEventProvider::SetMitkRenderWindow(mitk::RenderWindow* renWin) { m_RenderWindow = renWin; } mitk::RenderWindow* mitk::vtkEventProvider::GetRenderWindow() { return m_RenderWindow; } void mitk::vtkEventProvider::SetEnabled(int enabling) { if (!this->Interactor) { VTKEVENTPROVIDER_ERROR <<"The interactor must be set prior to enabling/disabling widget"; return; } if ( enabling ) //---------------------------------------------------------- { VTKEVENTPROVIDER_DEBUG << "Enabling widget"; if ( this->Enabled ) //already enabled, just return { return; } this->Enabled = 1; // listen to all event types specified in m_InteractionEventsVector vtkRenderWindowInteractor *i = this->Interactor; InteractionEventsVectorType::iterator it; for(it = m_InteractionEventsVector.begin(); it != m_InteractionEventsVector.end(); it++) { // add observer to interactorStyle i->GetInteractorStyle()->AddObserver((vtkCommand::EventIds) (*it), this->EventCallbackCommand, this->Priority); } this->InvokeEvent(vtkCommand::EnableEvent,NULL); } else //disabling----------------------------------------------------------- { VTKEVENTPROVIDER_DEBUG <<"Disabling widget"; if ( ! this->Enabled ) //already disabled, just return { return; } this->Enabled = 0; // don't listen for events any more this->Interactor->RemoveObserver(this->EventCallbackCommand); //this->Interactor->HandleEventLoop = 0; this->InvokeEvent(vtkCommand::DisableEvent,NULL); } } //---------------------------------------------------------------------------- // This adds the keypress event observer and the delete event observer void mitk::vtkEventProvider::SetInteractor(vtkRenderWindowInteractor* i) { if (i == this->Interactor) { return; } // if we already have an Interactor then stop observing it if (this->Interactor) this->SetEnabled(0); //disable the old interactor this->Interactor = i; this->Modified(); } //---------------------------------------------------------------------------- void mitk::vtkEventProvider::ProcessEvents(vtkObject* object, unsigned long event, void* clientData, void* vtkNotUsed(callData)) { vtkEventProvider* self = reinterpret_cast(clientData); vtkRenderWindowInteractor* rwi = static_cast(object)->GetInteractor(); // base renderer mitk::BaseRenderer* baseRenderer = mitk::BaseRenderer::GetInstance(self->GetRenderWindow()->GetVtkRenderWindow()); switch (event) { // key press case vtkCommand::KeyPressEvent: { VTKEVENTPROVIDER_DEBUG << "key press event"; InteractionEvent::Pointer adaptedEvent = VtkEventAdapter::AdaptInteractionKeyEvent(baseRenderer, event, rwi).GetPointer(); self->GetRenderWindow()->HandleEvent(adaptedEvent.GetPointer()); break; } // mouse events case vtkCommand::MouseMoveEvent: { VTKEVENTPROVIDER_DEBUG << "mouse move event"; InteractionEvent::Pointer adaptedEvent = VtkEventAdapter::AdaptMouseMoveEvent(baseRenderer,event,rwi).GetPointer(); self->GetRenderWindow()->HandleEvent(adaptedEvent.GetPointer()); break; } case vtkCommand::LeftButtonPressEvent: case vtkCommand::MiddleButtonPressEvent: case vtkCommand::RightButtonPressEvent: { VTKEVENTPROVIDER_DEBUG << "mouse press event"; InteractionEvent::Pointer adaptedEvent = VtkEventAdapter::AdaptMousePressEvent(baseRenderer,event,rwi).GetPointer(); self->GetRenderWindow()->HandleEvent(adaptedEvent.GetPointer()); break; } case vtkCommand::LeftButtonReleaseEvent: case vtkCommand::MiddleButtonReleaseEvent: case vtkCommand::RightButtonReleaseEvent: { VTKEVENTPROVIDER_DEBUG << "mouse release event"; InteractionEvent::Pointer adaptedEvent = VtkEventAdapter::AdaptMouseReleaseEvent(baseRenderer,event,rwi).GetPointer(); self->GetRenderWindow()->HandleEvent(adaptedEvent.GetPointer()); break; } // mouse WHEEL case vtkCommand::MouseWheelForwardEvent: case vtkCommand::MouseWheelBackwardEvent: { VTKEVENTPROVIDER_DEBUG << "mouse wheel event"; InteractionEvent::Pointer adaptedEvent = VtkEventAdapter::AdaptMouseWheelEvent(baseRenderer,event,rwi).GetPointer(); self->GetRenderWindow()->HandleEvent(adaptedEvent.GetPointer()); break; } default: VTKEVENTPROVIDER_INFO << "VTK event not mapped properly."; break; } } void mitk::vtkEventProvider::RemoveInteractionEvent(unsigned long ievent) { InteractionEventsVectorType::iterator it; if (m_InteractionEventsVector.size() > 0) { it = std::find(m_InteractionEventsVector.begin(), m_InteractionEventsVector.end(), ievent); if (it != m_InteractionEventsVector.end()) { m_InteractionEventsVector.erase(it); return; } } } void mitk::vtkEventProvider::AddInteractionEvent(unsigned long ievent) { // Remove event if it already exists RemoveInteractionEvent(ievent); m_InteractionEventsVector.push_back(ievent); } diff --git a/Core/Code/Rendering/mitkVtkEventProvider.h b/Core/Code/Rendering/mitkVtkEventProvider.h index b4c605e05a..4cc0c7f7a1 100644 --- a/Core/Code/Rendering/mitkVtkEventProvider.h +++ b/Core/Code/Rendering/mitkVtkEventProvider.h @@ -1,77 +1,77 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef VTKMITKEVENTPROVIDER_H_HEADER_INCLUDED_C1C53723 #define VTKMITKEVENTPROVIDER_H_HEADER_INCLUDED_C1C53723 #include #include "mitkRenderWindow.h" #include "vtkInteractorObserver.h" namespace mitk { /** * \brief Integrates into the VTK event mechanism to generate MITK specific events. * This class is NON-QT dependent pandon to the current MITK event handling code in QmitkRenderWindow. * \ingroup Renderer */ class MITK_CORE_EXPORT vtkEventProvider : public vtkInteractorObserver { public: static vtkEventProvider *New(); - vtkTypeRevisionMacro(vtkEventProvider,vtkInteractorObserver); + vtkTypeMacro(vtkEventProvider,vtkInteractorObserver); // Satisfy the superclass API. Enable/disable listening for events. virtual void SetEnabled(int); virtual void SetInteractor(vtkRenderWindowInteractor* iren); // Interface to MITK virtual void SetMitkRenderWindow(mitk::RenderWindow* renWin); mitk::RenderWindow* GetRenderWindow(); protected: vtkEventProvider(); ~vtkEventProvider(); //methods for processing events - callback for the observer/command pattern of vtkCommand static void ProcessEvents(vtkObject* object, unsigned long event, void* clientdata, void* calldata); mitk::RenderWindow* m_RenderWindow; // adds the MITK interaction event types to the VTK observer/command pattern void AddInteractionEvent(unsigned long ievent); // removes the MITK interaction event types void RemoveInteractionEvent(unsigned long ievent); typedef std::vector InteractionEventsVectorType; InteractionEventsVectorType m_InteractionEventsVector; private: vtkEventProvider(const vtkEventProvider&); // Not implemented. void operator=(const vtkEventProvider&); // Not implemented. }; } #endif /* VTKMITKEVENTPROVIDER_H_HEADER_INCLUDED_C1C53723 */ diff --git a/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp b/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp index 4ff2b5df7e..3616215ec6 100644 --- a/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp +++ b/Core/Code/Rendering/vtkMitkThickSlicesFilter.cpp @@ -1,373 +1,372 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkMitkThickSlicesFilter.h" #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include #include -vtkCxxRevisionMacro(vtkMitkThickSlicesFilter, "$Revision: 1.00 $"); vtkStandardNewMacro(vtkMitkThickSlicesFilter); //---------------------------------------------------------------------------- // Construct an instance of vtkMitkThickSlicesFilter fitler. vtkMitkThickSlicesFilter::vtkMitkThickSlicesFilter() { this->HandleBoundaries = 1; this->Dimensionality = 2; this->m_CurrentMode = MIP; // by default process active point scalars this->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); } //---------------------------------------------------------------------------- void vtkMitkThickSlicesFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "HandleBoundaries: " << this->HandleBoundaries << "\n"; os << indent << "Dimensionality: " << this->Dimensionality << "\n"; } //---------------------------------------------------------------------------- int vtkMitkThickSlicesFilter::RequestInformation(vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // Get input and output pipeline information. vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); // Get the input whole extent. int extent[6]; inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent); // Reduce 3D to 2D output extent[4] = extent[5] = 0; // Store the new whole extent for the output. outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent, 6); /* // Set the number of point data componets to the number of // components in the gradient vector. vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_DOUBLE, this->Dimensionality); */ return 1; } //---------------------------------------------------------------------------- // This method computes the input extent necessary to generate the output. int vtkMitkThickSlicesFilter::RequestUpdateExtent(vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // Get input and output pipeline information. vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); // Get the input whole extent. int wholeExtent[6]; inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent); // Get the requested update extent from the output. int inUExt[6]; outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inUExt); /*inUExt[4] -= 5; inUExt[5] += 5; if (inUExt[4] < wholeExtent[4]) */inUExt[4] = wholeExtent[4]; /*if (inUExt[5] > wholeExtent[5]) */inUExt[5] = wholeExtent[5]; // Store the update extent needed from the intput. inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inUExt, 6); return 1; } //---------------------------------------------------------------------------- // This execute method handles boundaries. // it handles boundaries. Pixels are just replicated to get values // out of extent. template void vtkMitkThickSlicesFilterExecute(vtkMitkThickSlicesFilter *self, vtkImageData *inData, T *inPtr, vtkImageData *outData, T *outPtr, int outExt[6], int /*id*/) { int idxX, idxY; int maxX, maxY; vtkIdType inIncX, inIncY, inIncZ; vtkIdType outIncX, outIncY, outIncZ; //int axesNum; int *inExt = inData->GetExtent(); int *wholeExtent; vtkIdType *inIncs; //int useYMin, useYMax, useXMin, useXMax; // find the region to loop over maxX = outExt[1] - outExt[0]; maxY = outExt[3] - outExt[2]; // maxZ = outExt[5] - outExt[4]; // Get the dimensionality of the gradient. //axesNum = self->GetDimensionality(); // Get increments to march through data inData->GetContinuousIncrements(outExt, inIncX, inIncY, inIncZ); outData->GetContinuousIncrements(outExt, outIncX, outIncY, outIncZ); /* // The data spacing is important for computing the gradient. // central differences (2 * ratio). // Negative because below we have (min - max) for dx ... inData->GetSpacing(r); r[0] = -0.5 / r[0]; r[1] = -0.5 / r[1]; r[2] = -0.5 / r[2]; */ // get some other info we need inIncs = inData->GetIncrements(); wholeExtent = inData->GetExtent(); // Move the pointer to the correct starting position. inPtr += (outExt[0]-inExt[0])*inIncs[0] + (outExt[2]-inExt[2])*inIncs[1] + (outExt[4]-inExt[4])*inIncs[2]; // Loop through ouput pixels int _minZ = /*-5 + outExt[4]; if( _minZ < wholeExtent[4]) _minZ=*/wholeExtent[4]; int _maxZ = /* 5 + outExt[4]; if( _maxZ > wholeExtent[5]) _maxZ=*/wholeExtent[5]; if(_maxZ<_minZ) return; double invNum = 1.0 / (_maxZ-_minZ+1) ; switch(self->GetThickSliceMode()) { default: case vtkMitkThickSlicesFilter::MIP: { //MIP for (idxY = 0; idxY <= maxY; idxY++) { //useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1]; //useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1]; for (idxX = 0; idxX <= maxX; idxX++) { //useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0]; //useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0]; T mip = inPtr[_minZ*inIncs[2]]; for(int z = _minZ+1; z<= _maxZ;z++) { T value = inPtr[z*inIncs[2]]; if(value > mip) mip=value; } // do X axis *outPtr = mip; outPtr++; inPtr++; } outPtr += outIncY; inPtr += inIncY; } } break; case vtkMitkThickSlicesFilter::SUM: { //MIP for (idxY = 0; idxY <= maxY; idxY++) { //useYMin = ((idxY + outExt[2]) <= wholeExtent[2]) ? 0 : -inIncs[1]; //useYMax = ((idxY + outExt[2]) >= wholeExtent[3]) ? 0 : inIncs[1]; for (idxX = 0; idxX <= maxX; idxX++) { //useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0]; //useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0]; double sum = 0; for(int z = _minZ; z<= _maxZ;z++) { T value = inPtr[z*inIncs[2]]; sum += value; } // do X axis *outPtr = static_cast(invNum*sum); outPtr++; inPtr++; } outPtr += outIncY; inPtr += inIncY; } } break; case vtkMitkThickSlicesFilter::WEIGHTED: { const int size = _maxZ-_minZ; std::vector weights(size); double mean = 0.5 * double(_minZ + _maxZ); double sigma_sq = double(size) / 6.0; sigma_sq *= sigma_sq; double sum = 0; int i=0; for(int z = _minZ+1; z<= _maxZ;z++) { double val = exp(-(((double)z-mean)/sigma_sq)); weights[i++] = val; sum += val; } for(i=0; i= wholeExtent[3]) ? 0 : inIncs[1]; for (idxX = 0; idxX <= maxX; idxX++) { //useXMin = ((idxX + outExt[0]) <= wholeExtent[0]) ? 0 : -inIncs[0]; //useXMax = ((idxX + outExt[0]) >= wholeExtent[1]) ? 0 : inIncs[0]; T mip = inPtr[_minZ*inIncs[2]]; i=0; double mymip = 0; for(int z = _minZ+1; z<= _maxZ;z++) { double value = inPtr[z*inIncs[2]]; mymip+=value*weights[i++]; } mip = static_cast(mymip); // do X axis *outPtr = mip; outPtr++; inPtr++; } outPtr += outIncY; inPtr += inIncY; } } break; } } int vtkMitkThickSlicesFilter::RequestData( vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { if (!this->Superclass::RequestData(request, inputVector, outputVector)) { return 0; } vtkImageData* output = vtkImageData::GetData(outputVector); vtkDataArray* outArray = output->GetPointData()->GetScalars(); vtksys_ios::ostringstream newname; newname << (outArray->GetName()?outArray->GetName():"") << "Gradient"; outArray->SetName(newname.str().c_str()); // Why not pass the original array? if (this->GetInputArrayToProcess(0, inputVector)) { output->GetPointData()->AddArray( this->GetInputArrayToProcess(0, inputVector)); } return 1; } //---------------------------------------------------------------------------- // This method contains a switch statement that calls the correct // templated function for the input data type. This method does handle // boundary conditions. void vtkMitkThickSlicesFilter::ThreadedRequestData(vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector*, vtkImageData*** inData, vtkImageData** outData, int outExt[6], int threadId) { // Get the input and output data objects. vtkImageData* input = inData[0][0]; vtkImageData* output = outData[0]; // The ouptut scalar type must be double to store proper gradients. /* if(output->GetScalarType() != VTK_DOUBLE) { vtkErrorMacro("Execute: output ScalarType is " << output->GetScalarType() << "but must be double."); return; } */ vtkDataArray* inputArray = this->GetInputArrayToProcess(0, inputVector); if (!inputArray) { vtkErrorMacro("No input array was found. Cannot execute"); return; } // Gradient makes sense only with one input component. This is not // a Jacobian filter. if(inputArray->GetNumberOfComponents() != 1) { vtkErrorMacro( "Execute: input has more than one component. " "The input to gradient should be a single component image. " "Think about it. If you insist on using a color image then " "run it though RGBToHSV then ExtractComponents to get the V " "components. That's probably what you want anyhow."); return; } void* inPtr = inputArray->GetVoidPointer(0); void* outPtr = output->GetScalarPointerForExtent(outExt); switch(inputArray->GetDataType()) { vtkTemplateMacro( vtkMitkThickSlicesFilterExecute(this, input, static_cast(inPtr), output, static_cast(outPtr), outExt, threadId) ); default: vtkErrorMacro("Execute: Unknown ScalarType " << input->GetScalarType()); return; } } diff --git a/Core/Code/Rendering/vtkMitkThickSlicesFilter.h b/Core/Code/Rendering/vtkMitkThickSlicesFilter.h index a43cc8e928..10421a1d1f 100644 --- a/Core/Code/Rendering/vtkMitkThickSlicesFilter.h +++ b/Core/Code/Rendering/vtkMitkThickSlicesFilter.h @@ -1,108 +1,108 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // .NAME vtkMitkThickSlicesFilter - Computes the gradient vector. // .SECTION Description // vtkMitkThickSlicesFilter computes the gradient vector of an image. The // vector results are stored as scalar components. The Dimensionality // determines whether to perform a 2d or 3d gradient. The default is // two dimensional XY gradient. OutputScalarType is always // double. Gradient is computed using central differences. #ifndef __vtkMitkThickSlicesFilter_h #define __vtkMitkThickSlicesFilter_h #include #include "vtkThreadedImageAlgorithm.h" class MITK_CORE_EXPORT vtkMitkThickSlicesFilter : public vtkThreadedImageAlgorithm { public: static vtkMitkThickSlicesFilter *New(); - vtkTypeRevisionMacro(vtkMitkThickSlicesFilter,vtkThreadedImageAlgorithm); + vtkTypeMacro(vtkMitkThickSlicesFilter,vtkThreadedImageAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); // Description: // Determines how the input is interpreted (set of 2d slices ...) vtkSetClampMacro(Dimensionality,int,2,3); vtkGetMacro(Dimensionality,int); // Description: // Get/Set whether to handle boundaries. If enabled, boundary // pixels are treated as duplicated so that central differencing // works for the boundary pixels. If disabled, the output whole // extent of the image is reduced by one pixel. vtkSetMacro(HandleBoundaries, int); vtkGetMacro(HandleBoundaries, int); vtkBooleanMacro(HandleBoundaries, int); enum { MIP=0, SUM, WEIGHTED }; protected: vtkMitkThickSlicesFilter(); ~vtkMitkThickSlicesFilter() {}; int HandleBoundaries; int Dimensionality; virtual int RequestInformation (vtkInformation*, vtkInformationVector**, vtkInformationVector*); virtual int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*); virtual int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*); void ThreadedRequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*, vtkImageData*** inData, vtkImageData** outData, int outExt[6], int threadId); int m_CurrentMode; private: vtkMitkThickSlicesFilter(const vtkMitkThickSlicesFilter&); // Not implemented. void operator=(const vtkMitkThickSlicesFilter&); // Not implemented. public: void SetThickSliceMode( int mode) { m_CurrentMode = mode; } int GetThickSliceMode() { return m_CurrentMode; } }; #endif diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.cpp index 33401807a2..44fa3df9fa 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.cpp @@ -1,120 +1,119 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkMaskedProgrammableGlyphFilter.h" #include "vtkMaskPoints.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" vtkStandardNewMacro(vtkMaskedProgrammableGlyphFilter); -vtkCxxRevisionMacro(vtkMaskedProgrammableGlyphFilter, ""); vtkMaskedProgrammableGlyphFilter::vtkMaskedProgrammableGlyphFilter() { //this->SetColorModeToColorByScalar(); //this->SetScaleModeToScaleByVector(); this->MaskPoints = vtkMaskPoints::New(); this->MaximumNumberOfPoints = 5000; this->UseMaskPoints = 1; } vtkMaskedProgrammableGlyphFilter::~vtkMaskedProgrammableGlyphFilter() { if(this->MaskPoints) { this->MaskPoints->Delete(); } } void vtkMaskedProgrammableGlyphFilter::SetInput(vtkDataSet *input) { this->MaskPoints->SetInput(input); this->Superclass::SetInput(this->MaskPoints->GetOutput()); } void vtkMaskedProgrammableGlyphFilter::SetRandomMode(int mode) { this->MaskPoints->SetRandomMode(mode); } int vtkMaskedProgrammableGlyphFilter::GetRandomMode() { return this->MaskPoints->GetRandomMode(); } void vtkMaskedProgrammableGlyphFilter::Execute() { if (this->UseMaskPoints) { this->Superclass::SetInput(this->MaskPoints->GetOutput()); vtkIdType numPts = this->MaskPoints->GetPolyDataInput(0)->GetNumberOfPoints(); this->MaskPoints->SetMaximumNumberOfPoints(MaximumNumberOfPoints); double onRatio = MaximumNumberOfPoints != 0.0 ? numPts / MaximumNumberOfPoints : 1.0; this->MaskPoints->SetOnRatio(onRatio); this->MaskPoints->Update(); } else { this->Superclass::SetInput(this->MaskPoints->GetInput()); } this->Superclass::Execute(); } int vtkMaskedProgrammableGlyphFilter::RequestData( vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { if (this->UseMaskPoints) { this->Superclass::SetInput(this->MaskPoints->GetOutput()); vtkIdType numPts = this->MaskPoints->GetPolyDataInput(0)->GetNumberOfPoints(); this->MaskPoints->SetMaximumNumberOfPoints(MaximumNumberOfPoints); this->MaskPoints->SetOnRatio(numPts / MaximumNumberOfPoints); this->MaskPoints->Update(); } else { this->Superclass::SetInput(this->MaskPoints->GetInput()); } return this->Superclass::RequestData( request,inputVector,outputVector); } void vtkMaskedProgrammableGlyphFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); //os << indent << "InputScalarsSelection: " // << (this->InputScalarsSelection ? this->InputScalarsSelection : "(none)") // << endl; //os << indent << "InputVectorsSelection: " // << (this->InputVectorsSelection ? this->InputVectorsSelection : "(none)") // << endl; //os << indent << "InputNormalsSelection: " // << (this->InputNormalsSelection ? this->InputNormalsSelection : "(none)") // << endl; os << indent << "MaximumNumberOfPoints: " << this->GetMaximumNumberOfPoints() << endl; os << indent << "UseMaskPoints: " << (this->UseMaskPoints?"on":"off") << endl; } diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.h b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.h index f5203fd558..df5866cbe9 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.h +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkMaskedProgrammableGlyphFilter.h @@ -1,115 +1,115 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __vtkMaskedProgrammableGlyphFilter_h #define __vtkMaskedProgrammableGlyphFilter_h #include "DiffusionCoreExports.h" #include "vtkProgrammableGlyphFilter.h" #include "mitkGeometry3D.h" class vtkMaskPoints; /** * This class masked points of the input data set and glyphs * only the selected poitns. Points may be selected either by * random or by ratio. * Additionally, this class allows to set the InputScalars, * InputVectors and InputNormals by their field name in the * input dataset. */ class DiffusionCore_EXPORT vtkMaskedProgrammableGlyphFilter : public vtkProgrammableGlyphFilter { public: - vtkTypeRevisionMacro(vtkMaskedProgrammableGlyphFilter,vtkProgrammableGlyphFilter); + vtkTypeMacro(vtkMaskedProgrammableGlyphFilter,vtkProgrammableGlyphFilter); void PrintSelf(ostream& os, vtkIndent indent); /** * Constructor */ static vtkMaskedProgrammableGlyphFilter *New(); /** * Limit the number of points to glyph */ vtkSetMacro(MaximumNumberOfPoints, int); vtkGetMacro(MaximumNumberOfPoints, int); /** * Set the input to this filter. */ virtual void SetInput(vtkDataSet *input); /** * Set/get whether to mask points */ vtkSetMacro(UseMaskPoints, int); vtkGetMacro(UseMaskPoints, int); /** * Set/get flag to cause randomization of which points to mask. */ void SetRandomMode(int mode); int GetRandomMode(); ///** // * If you want to use an arbitrary scalars array, then set its name here. // * By default this in NULL and the filter will use the active scalar array. // */ //vtkGetStringMacro(InputScalarsSelection); //void SelectInputScalars(const char *fieldName) // {this->SetInputScalarsSelection(fieldName);} ///** // * If you want to use an arbitrary vectors array, then set its name here. // * By default this in NULL and the filter will use the active vector array. // */ //vtkGetStringMacro(InputVectorsSelection); //void SelectInputVectors(const char *fieldName) // {this->SetInputVectorsSelection(fieldName);} ///** // * If you want to use an arbitrary normals array, then set its name here. // * By default this in NULL and the filter will use the active normal array. // */ //vtkGetStringMacro(InputNormalsSelection); //void SelectInputNormals(const char *fieldName) // {this->SetInputNormalsSelection(fieldName);} void SetGeometry(mitk::Geometry3D::Pointer geo) { this->m_Geometry = geo; } mitk::Geometry3D::Pointer GetGeometry() { return this->m_Geometry; } protected: vtkMaskedProgrammableGlyphFilter(); ~vtkMaskedProgrammableGlyphFilter(); virtual void Execute(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkMaskPoints *MaskPoints; int MaximumNumberOfPoints; int UseMaskPoints; mitk::Geometry3D::Pointer m_Geometry; private: vtkMaskedProgrammableGlyphFilter(const vtkMaskedProgrammableGlyphFilter&); // Not implemented. void operator=(const vtkMaskedProgrammableGlyphFilter&); // Not implemented. }; #endif diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.cxx b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.cxx index 8c96d3a592..76f372b923 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.cxx +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.cxx @@ -1,119 +1,118 @@ #include "vtkOdfSource.h" #include "vtkCellArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkPoints.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkObjectFactory.h" #include "vtkDoubleArray.h" #include "vtkCellData.h" #include -vtkCxxRevisionMacro(vtkOdfSource, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkOdfSource); vtkOdfSource::vtkOdfSource() { Scale = 1; this->SetNumberOfInputPorts(0); } //---------------------------------------------------------------------------- int vtkOdfSource::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { vtkPolyData* TemplateOdf = OdfType::GetBaseMesh(); // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the ouptut vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); OdfType colorOdf; switch(Normalization) { case mitk::ODFN_MINMAX: Odf = Odf.MinMaxNormalize(); colorOdf = Odf; break; case mitk::ODFN_MAX: Odf = Odf.MaxNormalize(); colorOdf = Odf; break; case mitk::ODFN_NONE: colorOdf = Odf.MaxNormalize(); break; default: Odf = Odf.MinMaxNormalize(); colorOdf = Odf; } vtkIdType cellId = 0; vtkIdType npts; vtkIdType *pts; vtkPoints *newPoints; vtkCellArray* polys = TemplateOdf->GetPolys(); output->SetPolys(polys); vtkDoubleArray* colors = vtkDoubleArray::New(); int numCells = polys->GetNumberOfCells(); colors->Allocate(numCells); polys->InitTraversal(); newPoints = vtkPoints::New(); int numPoints = TemplateOdf->GetPoints()->GetNumberOfPoints(); newPoints->Allocate(numPoints); while(polys->GetNextCell(npts,pts)) { double val = 0; for(int i=0; iSetComponent(0,cellId++, 1-val); } for(int j=0; jGetPoints()->GetPoint(j,p); double val = Odf.GetElement(j); p[0] *= val*Scale*AdditionalScale*0.5; p[1] *= val*Scale*AdditionalScale*0.5; p[2] *= val*Scale*AdditionalScale*0.5; newPoints->InsertNextPoint(p); } output->SetPoints(newPoints); output->GetCellData()->SetScalars(colors); colors->Delete(); newPoints->Delete(); return 1; } //---------------------------------------------------------------------------- void vtkOdfSource::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } //---------------------------------------------------------------------------- int vtkOdfSource::RequestInformation( vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) { // get the info object vtkInformation *outInfo = outputVector->GetInformationObject(0); outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_BOUNDING_BOX(),1,1,1,1,1,1); return 1; } diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.h b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.h index 8fe65d752c..7d2226baa9 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.h +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkOdfSource.h @@ -1,69 +1,69 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __vtkOdfSource_h #define __vtkOdfSource_h #include "DiffusionCoreExports.h" #include "vtkPolyDataAlgorithm.h" #include "mitkCommon.h" #include #include #include class DiffusionCore_EXPORT vtkOdfSource : public vtkPolyDataAlgorithm { public: - vtkTypeRevisionMacro(vtkOdfSource,vtkPolyDataAlgorithm); + vtkTypeMacro(vtkOdfSource,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); typedef itk::OrientationDistributionFunction OdfType; // Description: // Construct sphere with radius=0.5 and default resolution 8 in both Phi // and Theta directions. Theta ranges from (0,360) and phi (0,180) degrees. static vtkOdfSource *New(); vtkSetMacro(Scale,double); vtkGetMacro(Scale,double); vtkSetMacro(AdditionalScale,double); vtkGetMacro(AdditionalScale,double); vtkSetMacro(Normalization,int); vtkGetMacro(Normalization,int); vtkSetMacro(Odf,OdfType); vtkGetMacro(Odf,OdfType); protected: vtkOdfSource(); ~vtkOdfSource() {} int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *); OdfType Odf; double Scale; double AdditionalScale; int Normalization; private: vtkOdfSource(const vtkOdfSource&); // Not implemented. void operator=(const vtkOdfSource&); // Not implemented. }; #endif //__vtkOdfSource_h diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.cxx b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.cxx index 61268af69c..1f4f54499d 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.cxx +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.cxx @@ -1,140 +1,139 @@ /*========================================================================= Program: Visualization Toolkit 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 "vtkThickPlane.h" #include "vtkMath.h" #include "vtkObjectFactory.h" -vtkCxxRevisionMacro(vtkThickPlane, "$Revision: 1.41 $"); vtkStandardNewMacro(vtkThickPlane); // Construct plane passing through origin and normal to z-axis. vtkThickPlane::vtkThickPlane() { this->Normal[0] = 0.0; this->Normal[1] = 0.0; this->Normal[2] = 1.0; this->Origin[0] = 0.0; this->Origin[1] = 0.0; this->Origin[2] = 0.0; } // Evaluate plane equation for point x[3]. double vtkThickPlane::EvaluateFunction(double x[3]) { return this->EvaluateFunction(x[0],x[1],x[2]); } // Evaluate plane equation for point x,y,z. double vtkThickPlane::EvaluateFunction(double x,double y,double z) { // PointPlaneDistance = Distance - Normal*Point double ppd = Distance - ( this->Normal[0]*x + this->Normal[1]*y + this->Normal[2]*z ); if( abs(ppd) <= Thickness ) { count++; return 0; } if( ppd >= 0 ) return ppd - Thickness; return abs(ppd + Thickness); } // Evaluate function gradient at point x[3]. void vtkThickPlane::EvaluateGradient(double vtkNotUsed(x)[3], double n[3]) { for (int i=0; i<3; i++) { n[i] = this->Normal[i]; } } void vtkThickPlane::SetPose (double _n1, double _n2, double _n3, double _o1, double _o2, double _o3) { SetNormal(_n1,_n2,_n3); SetOrigin(_o1,_o2,_o3); Distance = Normal[0]*Origin[0]+Normal[1]*Origin[1]+Normal[2]*Origin[2]; if(Distance < 0.0) { Distance = -Distance; Normal[0] = -Normal[0]; Normal[1] = -Normal[1]; Normal[2] = -Normal[2]; } } void vtkThickPlane::SetPose (double _n[3], double _o[3]) { SetPose(_n[0],_n[1],_n[2],_o[0],_o[1],_o[2]); } void vtkThickPlane::SetNormal (double _arg1, double _arg2, double _arg3) { vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting " << Normal << " to (" << _arg1 << "," << _arg2 << "," << _arg3 << ")"); if ((this->Normal[0] != _arg1)||(this->Normal[1] != _arg2)||(this->Normal[2] != _arg3)) { double length = sqrt(_arg1*_arg1+_arg2*_arg2+_arg3*_arg3); this->Normal[0] = _arg1/length; this->Normal[1] = _arg2/length; this->Normal[2] = _arg3/length; this->Modified(); } }; void vtkThickPlane::SetNormal (double _arg[3]) { this->SetNormal (_arg[0], _arg[1], _arg[2]); } void vtkThickPlane::SetOrigin (double _arg1, double _arg2, double _arg3) { vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting " << Origin << " to (" << _arg1 << "," << _arg2 << "," << _arg3 << ")"); if ((this->Normal[0] != _arg1)||(this->Normal[1] != _arg2)||(this->Normal[2] != _arg3)) { this->Origin[0] = _arg1; this->Origin[1] = _arg2; this->Origin[2] = _arg3; this->Modified(); } }; void vtkThickPlane::SetOrigin (double _arg[3]) { this->SetOrigin (_arg[0], _arg[1], _arg[2]); } void vtkThickPlane::SetThickness (double _arg) { Thickness = abs(_arg); } #define VTK_PLANE_TOL 1.0e-06 void vtkThickPlane::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Normal: (" << this->Normal[0] << ", " << this->Normal[1] << ", " << this->Normal[2] << ")\n"; os << indent << "Origin: (" << this->Origin[0] << ", " << this->Origin[1] << ", " << this->Origin[2] << ")\n"; os << indent << "Thickness: " << this->Thickness << "\n"; } diff --git a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.h b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.h index 6c2639de7d..2fcbc2715c 100644 --- a/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.h +++ b/Modules/DiffusionImaging/DiffusionCore/Rendering/vtkThickPlane.h @@ -1,95 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // .NAME vtkPlane - perform various plane computations // .SECTION Description // vtkPlane provides methods for various plane computations. These include // projecting points onto a plane, evaluating the plane equation, and // returning plane normal. vtkPlane is a concrete implementation of the // abstract class vtkImplicitFunction. #ifndef __vtkThickPlane_h #define __vtkThickPlane_h #include "DiffusionCoreExports.h" #include "vtkImplicitFunction.h" #include "mitkCommon.h" class DiffusionCore_EXPORT vtkThickPlane : public vtkImplicitFunction { public: // Description // Construct plane passing through origin and normal to z-axis. static vtkThickPlane *New(); - vtkTypeRevisionMacro(vtkThickPlane,vtkImplicitFunction); + vtkTypeMacro(vtkThickPlane,vtkImplicitFunction); void PrintSelf(ostream& os, vtkIndent indent); // Description // Evaluate plane equation for point x[3]. double EvaluateFunction(double x[3]); double EvaluateFunction(double x, double y, double z); // Description // Evaluate function gradient at point x[3]. void EvaluateGradient(double x[3], double g[3]); // Description: // Set/get plane normal. Plane is defined by point and normal. virtual void SetPose (double _n1, double _n2, double _n3, double _o1, double _o2, double _o3); virtual void SetPose (double _n[3], double _o[3]); vtkGetVectorMacro(Normal,double,3); vtkGetVectorMacro(Origin,double,3); // Description: // Set/get point through which plane passes. Plane is defined by point // and normal. virtual void SetThickness (double _arg); vtkGetMacro(Thickness,double); int count; protected: vtkThickPlane(); ~vtkThickPlane() {}; // Description: // Set/get plane normal. Plane is defined by point and normal. virtual void SetNormal (double _arg1, double _arg2, double _arg3); virtual void SetNormal (double _arg[3]); // Description: // Set/get point through which plane passes. Plane is defined by point // and normal. virtual void SetOrigin (double _arg1, double _arg2, double _arg3); virtual void SetOrigin (double _arg[3]); double Normal[3]; double Origin[3]; double Thickness; double Distance; private: vtkThickPlane(const vtkThickPlane&); // Not implemented. void operator=(const vtkThickPlane&); // Not implemented. }; #endif diff --git a/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.cpp b/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.cpp index 1496082bc3..5bccdf5ba1 100644 --- a/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.cpp +++ b/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.cpp @@ -1,96 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkMaskedGlyph2D.h" #include "vtkMaskPoints.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" vtkStandardNewMacro(vtkMaskedGlyph2D); -vtkCxxRevisionMacro(vtkMaskedGlyph2D, ""); vtkMaskedGlyph2D::vtkMaskedGlyph2D() { this->SetColorModeToColorByScalar(); this->SetScaleModeToScaleByVector(); this->MaskPoints = vtkMaskPoints::New(); this->MaximumNumberOfPoints = 5000; this->UseMaskPoints = 1; } vtkMaskedGlyph2D::~vtkMaskedGlyph2D() { if(this->MaskPoints) { this->MaskPoints->Delete(); } } void vtkMaskedGlyph2D::SetInput(vtkDataSet *input) { this->MaskPoints->SetInput(input); this->Superclass::SetInput(this->MaskPoints->GetOutput()); } void vtkMaskedGlyph2D::SetRandomMode(int mode) { this->MaskPoints->SetRandomMode(mode); } int vtkMaskedGlyph2D::GetRandomMode() { return this->MaskPoints->GetRandomMode(); } void vtkMaskedGlyph2D::Execute() { if (this->UseMaskPoints) { this->Superclass::SetInput(this->MaskPoints->GetOutput()); vtkIdType numPts = this->MaskPoints->GetPolyDataInput(0)->GetNumberOfPoints(); this->MaskPoints->SetMaximumNumberOfPoints(MaximumNumberOfPoints); this->MaskPoints->SetOnRatio(numPts / MaximumNumberOfPoints); this->MaskPoints->Update(); } else { this->Superclass::SetInput(this->MaskPoints->GetInput()); } this->Superclass::Execute(); } void vtkMaskedGlyph2D::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); //os << indent << "InputScalarsSelection: " // << (this->InputScalarsSelection ? this->InputScalarsSelection : "(none)") // << endl; //os << indent << "InputVectorsSelection: " // << (this->InputVectorsSelection ? this->InputVectorsSelection : "(none)") // << endl; //os << indent << "InputNormalsSelection: " // << (this->InputNormalsSelection ? this->InputNormalsSelection : "(none)") // << endl; os << indent << "MaximumNumberOfPoints: " << this->GetMaximumNumberOfPoints() << endl; os << indent << "UseMaskPoints: " << (this->UseMaskPoints?"on":"off") << endl; } diff --git a/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.h b/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.h index 0a96f30c83..e3314cb351 100644 --- a/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.h +++ b/Modules/MitkExt/Rendering/vtkMaskedGlyph2D.h @@ -1,107 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __vtkMaskedGlyph2D_h #define __vtkMaskedGlyph2D_h #include "MitkExtExports.h" #include "vtkGlyph2D.h" #include "mitkCommon.h" class vtkMaskPoints; /** * This class masked points of the input data set and glyphs * only the selected poitns. Points may be selected either by * random or by ratio. * Additionally, this class allows to set the InputScalars, * InputVectors and InputNormals by their field name in the * input dataset. */ class MitkExt_EXPORT vtkMaskedGlyph2D : public vtkGlyph2D { public: - vtkTypeRevisionMacro(vtkMaskedGlyph2D,vtkGlyph2D); + vtkTypeMacro(vtkMaskedGlyph2D,vtkGlyph2D); void PrintSelf(ostream& os, vtkIndent indent); /** * Constructor */ static vtkMaskedGlyph2D *New(); /** * Limit the number of points to glyph */ vtkSetMacro(MaximumNumberOfPoints, int); vtkGetMacro(MaximumNumberOfPoints, int); /** * Set the input to this filter. */ virtual void SetInput(vtkDataSet *input); /** * Set/get whether to mask points */ vtkSetMacro(UseMaskPoints, int); vtkGetMacro(UseMaskPoints, int); /** * Set/get flag to cause randomization of which points to mask. */ void SetRandomMode(int mode); int GetRandomMode(); ///** // * If you want to use an arbitrary scalars array, then set its name here. // * By default this in NULL and the filter will use the active scalar array. // */ //vtkGetStringMacro(InputScalarsSelection); //void SelectInputScalars(const char *fieldName) // {this->SetInputScalarsSelection(fieldName);} ///** // * If you want to use an arbitrary vectors array, then set its name here. // * By default this in NULL and the filter will use the active vector array. // */ //vtkGetStringMacro(InputVectorsSelection); //void SelectInputVectors(const char *fieldName) // {this->SetInputVectorsSelection(fieldName);} ///** // * If you want to use an arbitrary normals array, then set its name here. // * By default this in NULL and the filter will use the active normal array. // */ //vtkGetStringMacro(InputNormalsSelection); //void SelectInputNormals(const char *fieldName) // {this->SetInputNormalsSelection(fieldName);} protected: vtkMaskedGlyph2D(); ~vtkMaskedGlyph2D(); virtual void Execute(); vtkMaskPoints *MaskPoints; int MaximumNumberOfPoints; int UseMaskPoints; private: vtkMaskedGlyph2D(const vtkMaskedGlyph2D&); // Not implemented. void operator=(const vtkMaskedGlyph2D&); // Not implemented. }; #endif diff --git a/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.cpp b/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.cpp index f2ab71e0ef..2a91b34bb2 100644 --- a/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.cpp +++ b/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.cpp @@ -1,113 +1,112 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkMaskedGlyph3D.h" #include "vtkMaskPoints.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" vtkStandardNewMacro(vtkMaskedGlyph3D); -vtkCxxRevisionMacro(vtkMaskedGlyph3D, ""); vtkMaskedGlyph3D::vtkMaskedGlyph3D() { this->SetColorModeToColorByScalar(); this->SetScaleModeToScaleByVector(); this->MaskPoints = vtkMaskPoints::New(); this->MaximumNumberOfPoints = 5000; this->UseMaskPoints = 1; } vtkMaskedGlyph3D::~vtkMaskedGlyph3D() { if(this->MaskPoints) { this->MaskPoints->Delete(); } } void vtkMaskedGlyph3D::SetInput(vtkDataSet *input) { this->MaskPoints->SetInput(input); this->Superclass::SetInputConnection(this->MaskPoints->GetOutputPort()); } void vtkMaskedGlyph3D::SetInputConnection(vtkAlgorithmOutput* input) { this->MaskPoints->SetInputConnection(input); this->Superclass::SetInputConnection(this->MaskPoints->GetOutputPort()); } void vtkMaskedGlyph3D::SetRandomMode(int mode) { this->MaskPoints->SetRandomMode(mode); } int vtkMaskedGlyph3D::GetRandomMode() { return this->MaskPoints->GetRandomMode(); } void vtkMaskedGlyph3D::Execute() { if (this->UseMaskPoints) { vtkIdType numPts = this->MaskPoints->GetPolyDataInput(0)->GetNumberOfPoints(); this->MaskPoints->SetMaximumNumberOfPoints( MaximumNumberOfPoints ); this->MaskPoints->SetOnRatio( numPts / MaximumNumberOfPoints ); this->MaskPoints->Update(); this->Superclass::SetInput(this->MaskPoints->GetOutput()); } else { this->Superclass::SetInput(this->MaskPoints->GetInput()); } this->Superclass::Execute(); } int vtkMaskedGlyph3D::RequestData( vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { if (this->UseMaskPoints) { this->Superclass::SetInput(this->MaskPoints->GetOutput()); vtkIdType numPts = this->MaskPoints->GetPolyDataInput(0)->GetNumberOfPoints(); this->MaskPoints->SetMaximumNumberOfPoints( MaximumNumberOfPoints ); this->MaskPoints->SetOnRatio( numPts / MaximumNumberOfPoints ); this->MaskPoints->Update(); } else { this->Superclass::SetInput(this->MaskPoints->GetInput()); } return this->Superclass::RequestData( request,inputVector,outputVector); } void vtkMaskedGlyph3D::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "MaximumNumberOfPoints: " << this->GetMaximumNumberOfPoints() << endl; os << indent << "UseMaskPoints: " << (this->UseMaskPoints?"on":"off") << endl; } diff --git a/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.h b/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.h index 6975b2791c..b9734f6090 100644 --- a/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.h +++ b/Modules/MitkExt/Rendering/vtkMaskedGlyph3D.h @@ -1,87 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __vtkMaskedGlyph3D_h #define __vtkMaskedGlyph3D_h #include "MitkExtExports.h" #include "vtkGlyph3D.h" #include "mitkCommon.h" class vtkMaskPoints; /** * This class masked points of the input data set and glyphs * only the selected poitns. Points may be selected either by * random or by ratio. * Additionally, this class allows to set the InputScalars, * InputVectors and InputNormals by their field name in the * input dataset. */ class MitkExt_EXPORT vtkMaskedGlyph3D : public vtkGlyph3D { public: - vtkTypeRevisionMacro(vtkMaskedGlyph3D,vtkGlyph3D); + vtkTypeMacro(vtkMaskedGlyph3D,vtkGlyph3D); void PrintSelf(ostream& os, vtkIndent indent); /** * Constructor */ static vtkMaskedGlyph3D *New(); /** * Limit the number of points to glyph */ vtkSetMacro(MaximumNumberOfPoints, int); vtkGetMacro(MaximumNumberOfPoints, int); /** * Set the input to this filter. */ virtual void SetInput(vtkDataSet *input); /** * Set/get whether to mask points */ vtkSetMacro(UseMaskPoints, int); vtkGetMacro(UseMaskPoints, int); /** * Set/get flag to cause randomization of which points to mask. */ void SetRandomMode(int mode); int GetRandomMode(); virtual void SetInputConnection(vtkAlgorithmOutput* input); protected: vtkMaskedGlyph3D(); ~vtkMaskedGlyph3D(); virtual void Execute(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkMaskPoints *MaskPoints; int MaximumNumberOfPoints; int UseMaskPoints; private: vtkMaskedGlyph3D(const vtkMaskedGlyph3D&); // Not implemented. void operator=(const vtkMaskedGlyph3D&); // Not implemented. }; #endif diff --git a/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.cpp b/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.cpp index 923172a112..fcf3daaa56 100644 --- a/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.cpp +++ b/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.cpp @@ -1,667 +1,666 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkMitkGPUVolumeRayCastMapper.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 "vtkMitkGPUVolumeRayCastMapper.h" // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkVolumeRenderingFactory.h" #include "vtkImageData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkDataArray.h" #include "vtkTimerLog.h" #include "vtkImageResample.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include #include "vtkCommand.h" // for VolumeMapperRender{Start|End|Progress}Event #include "vtkCamera.h" #include "vtkRendererCollection.h" #include "vtkMultiThreader.h" #include "vtkGPUInfoList.h" #include "vtkGPUInfo.h" -vtkCxxRevisionMacro(vtkMitkGPUVolumeRayCastMapper, "$Revision: 1.7 $"); vtkInstantiatorNewMacro(vtkMitkGPUVolumeRayCastMapper); vtkCxxSetObjectMacro(vtkMitkGPUVolumeRayCastMapper, MaskInput, vtkImageData); vtkCxxSetObjectMacro(vtkMitkGPUVolumeRayCastMapper, TransformedInput, vtkImageData); vtkMitkGPUVolumeRayCastMapper::vtkMitkGPUVolumeRayCastMapper() { this->AutoAdjustSampleDistances = 1; this->ImageSampleDistance = 1.0; this->MinimumImageSampleDistance = 1.0; this->MaximumImageSampleDistance = 10.0; this->SampleDistance = 1.0; this->SmallVolumeRender = 0; this->BigTimeToDraw = 0.0; this->SmallTimeToDraw = 0.0; this->FinalColorWindow = 1.0; this->FinalColorLevel = 0.5; this->GeneratingCanonicalView = 0; this->CanonicalViewImageData = NULL; this->MaskInput = NULL; this->MaskBlendFactor=1.0f; this->AMRMode=0; this->ClippedCroppingRegionPlanes[0]=VTK_DOUBLE_MAX; this->ClippedCroppingRegionPlanes[1]=VTK_DOUBLE_MIN; this->ClippedCroppingRegionPlanes[2]=VTK_DOUBLE_MAX; this->ClippedCroppingRegionPlanes[3]=VTK_DOUBLE_MIN; this->ClippedCroppingRegionPlanes[4]=VTK_DOUBLE_MAX; this->ClippedCroppingRegionPlanes[5]=VTK_DOUBLE_MIN; this->MaxMemoryInBytes=0; vtkGPUInfoList *l=vtkGPUInfoList::New(); l->Probe(); if(l->GetNumberOfGPUs()>0) { vtkGPUInfo *info=l->GetGPUInfo(0); this->MaxMemoryInBytes=info->GetDedicatedVideoMemory(); if(this->MaxMemoryInBytes==0) { this->MaxMemoryInBytes=info->GetDedicatedSystemMemory(); } // we ignore info->GetSharedSystemMemory(); as this is very slow. } l->Delete(); if(this->MaxMemoryInBytes==0) // use some default value: 128MB. { this->MaxMemoryInBytes=128*1024*1024; } this->MaxMemoryFraction = 0.75; this->ReportProgress=true; this->TransformedInput = NULL; this->LastInput = NULL; } // ---------------------------------------------------------------------------- vtkMitkGPUVolumeRayCastMapper::~vtkMitkGPUVolumeRayCastMapper() { this->SetMaskInput(NULL); this->SetTransformedInput(NULL); this->LastInput = NULL; } // ---------------------------------------------------------------------------- vtkMitkGPUVolumeRayCastMapper *vtkMitkGPUVolumeRayCastMapper::New() { // First try to create the object from the vtkObjectFactory vtkObject* ret = vtkVolumeRenderingFactory::CreateInstance("vtkMitkGPUVolumeRayCastMapper"); return static_cast(ret); } // ---------------------------------------------------------------------------- // The render method that is called from the volume. If this is a canonical // view render, a specialized version of this method will be called instead. // Otherwise we will // - Invoke a start event // - Start timing // - Check that everything is OK for rendering // - Render // - Stop the timer and record results // - Invoke an end event // ---------------------------------------------------------------------------- void vtkMitkGPUVolumeRayCastMapper::Render( vtkRenderer *ren, vtkVolume *vol ) { // Catch renders that are happening due to a canonical view render and // handle them separately. if (this->GeneratingCanonicalView ) { this->CanonicalViewRender(ren, vol); return; } // Invoke a VolumeMapperRenderStartEvent this->InvokeEvent(vtkCommand::VolumeMapperRenderStartEvent,0); // Start the timer to time the length of this render vtkTimerLog *timer = vtkTimerLog::New(); timer->StartTimer(); // Make sure everything about this render is OK. // This is where the input is updated. if ( this->ValidateRender(ren, vol ) ) { // Everything is OK - so go ahead and really do the render this->GPURender( ren, vol); } // Stop the timer timer->StopTimer(); double t = timer->GetElapsedTime(); // cout << "Render Timer " << t << " seconds, " << 1.0/t << " frames per second" << endl; this->TimeToDraw = t; timer->Delete(); if ( vol->GetAllocatedRenderTime() < 1.0 ) { this->SmallTimeToDraw = t; } else { this->BigTimeToDraw = t; } // Invoke a VolumeMapperRenderEndEvent this->InvokeEvent(vtkCommand::VolumeMapperRenderEndEvent,0); } // ---------------------------------------------------------------------------- // Special version for rendering a canonical view - we don't do things like // invoke start or end events, and we don't capture the render time. // ---------------------------------------------------------------------------- void vtkMitkGPUVolumeRayCastMapper::CanonicalViewRender(vtkRenderer *ren, vtkVolume *vol ) { // Make sure everything about this render is OK if ( this->ValidateRender(ren, vol ) ) { // Everything is OK - so go ahead and really do the render this->GPURender( ren, vol); } } // ---------------------------------------------------------------------------- // This method us used by the render method to validate everything before // attempting to render. This method returns 0 if something is not right - // such as missing input, a null renderer or a null volume, no scalars, etc. // In some cases it will produce a vtkErrorMacro message, and in others // (for example, in the case of cropping planes that define a region with // a volume or 0 or less) it will fail silently. If everything is OK, it will // return with a value of 1. // ---------------------------------------------------------------------------- int vtkMitkGPUVolumeRayCastMapper::ValidateRender(vtkRenderer *ren, vtkVolume *vol) { // Check that we have everything we need to render. int goodSoFar = 1; // Check for a renderer - we MUST have one if ( !ren ) { goodSoFar = 0; vtkErrorMacro("Renderer cannot be null."); } // Check for the volume - we MUST have one if ( goodSoFar && !vol ) { goodSoFar = 0; vtkErrorMacro("Volume cannot be null."); } // Don't need to check if we have a volume property // since the volume will create one if we don't. Also // don't need to check for the scalar opacity function // or the RGB transfer function since the property will // create them if they do not yet exist. // However we must currently check that the number of // color channels is 3 // TODO: lift this restriction - should work with // gray functions as well. Right now turning off test // because otherwise 4 component rendering isn't working. // Will revisit. if ( goodSoFar && vol->GetProperty()->GetColorChannels() != 3 ) { // goodSoFar = 0; // vtkErrorMacro("Must have a color transfer function."); } // Check the cropping planes. If they are invalid, just silently // fail. This will happen when an interactive widget is dragged // such that it defines 0 or negative volume - this can happen // and should just not render the volume. // Check the cropping planes if( goodSoFar && this->Cropping && (this->CroppingRegionPlanes[0]>=this->CroppingRegionPlanes[1] || this->CroppingRegionPlanes[2]>=this->CroppingRegionPlanes[3] || this->CroppingRegionPlanes[4]>=this->CroppingRegionPlanes[5] )) { // No error message here - we want to be silent goodSoFar = 0; } // Check that we have input data vtkImageData *input=this->GetInput(); // If we have a timestamp change or data change then create a new clone. if(input != this->LastInput || input->GetMTime() > this->TransformedInput->GetMTime()) { this->LastInput = input; vtkImageData* clone; if(!this->TransformedInput) { clone = vtkImageData::New(); this->SetTransformedInput(clone); clone->Delete(); } else { clone = this->TransformedInput; } clone->ShallowCopy(input); // @TODO: This is the workaround to deal with GPUVolumeRayCastMapper // not able to handle extents starting from non zero values. // There is not a easy fix in the GPU volume ray cast mapper hence // this fix has been introduced. // Get the current extents. int extents[6], real_extents[6]; clone->GetExtent(extents); clone->GetExtent(real_extents); // Get the current origin and spacing. double origin[3], spacing[3]; clone->GetOrigin(origin); clone->GetSpacing(spacing); for (int cc=0; cc < 3; cc++) { // Transform the origin and the extents. origin[cc] = origin[cc] + extents[2*cc]*spacing[cc]; extents[2*cc+1] -= extents[2*cc]; extents[2*cc] -= extents[2*cc]; } clone->SetOrigin(origin); clone->SetExtent(extents); } if ( goodSoFar && !this->TransformedInput ) { vtkErrorMacro("Input is NULL but is required"); goodSoFar = 0; } // Update the date then make sure we have scalars. Note // that we must have point or cell scalars because field // scalars are not supported. vtkDataArray *scalars = NULL; if ( goodSoFar ) { // Here is where we update the input this->TransformedInput->UpdateInformation(); this->TransformedInput->SetUpdateExtentToWholeExtent(); this->TransformedInput->Update(); // Now make sure we can find scalars scalars=this->GetScalars(this->TransformedInput,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, this->CellFlag); // We couldn't find scalars if ( !scalars ) { vtkErrorMacro("No scalars found on input."); goodSoFar = 0; } // Even if we found scalars, if they are field data scalars that isn't good else if ( this->CellFlag == 2 ) { vtkErrorMacro("Only point or cell scalar support - found field scalars instead."); goodSoFar = 0; } } // Make sure the scalar type is actually supported. This mappers supports // almost all standard scalar types. if ( goodSoFar ) { switch(scalars->GetDataType()) { case VTK_CHAR: vtkErrorMacro(<< "scalar of type VTK_CHAR is not supported " << "because this type is platform dependent. " << "Use VTK_SIGNED_CHAR or VTK_UNSIGNED_CHAR instead."); goodSoFar = 0; break; case VTK_BIT: vtkErrorMacro("scalar of type VTK_BIT is not supported by this mapper."); goodSoFar = 0; break; case VTK_ID_TYPE: vtkErrorMacro("scalar of type VTK_ID_TYPE is not supported by this mapper."); goodSoFar = 0; break; case VTK_STRING: vtkErrorMacro("scalar of type VTK_STRING is not supported by this mapper."); goodSoFar = 0; break; default: // Don't need to do anything here break; } } // Check on the blending type - we support composite and min / max intensity if ( goodSoFar ) { if(this->BlendMode!=vtkVolumeMapper::COMPOSITE_BLEND && this->BlendMode!=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND && this->BlendMode!=vtkVolumeMapper::MINIMUM_INTENSITY_BLEND) { goodSoFar = 0; vtkErrorMacro(<< "Selected blend mode not supported. " << "Only Composite and MIP and MinIP modes " << "are supported by the current implementation."); } } // This mapper supports 1 component data, or 4 component if it is not independent // component (i.e. the four components define RGBA) int numberOfComponents = 0; if ( goodSoFar ) { numberOfComponents=scalars->GetNumberOfComponents(); if( !( numberOfComponents==1 || (numberOfComponents==4 && vol->GetProperty()->GetIndependentComponents()==0))) { goodSoFar = 0; vtkErrorMacro(<< "Only one component scalars, or four " << "component with non-independent components, " << "are supported by this mapper."); } } // If this is four component data, then it better be unsigned char (RGBA). if( goodSoFar && numberOfComponents == 4 && scalars->GetDataType() != VTK_UNSIGNED_CHAR) { goodSoFar = 0; vtkErrorMacro("Only unsigned char is supported for 4-component scalars!"); } // return our status return goodSoFar; } // ---------------------------------------------------------------------------- // Description: // Called by the AMR Volume Mapper. // Set the flag that tells if the scalars are on point data (0) or // cell data (1). void vtkMitkGPUVolumeRayCastMapper::SetCellFlag(int cellFlag) { this->CellFlag=cellFlag; } // ---------------------------------------------------------------------------- void vtkMitkGPUVolumeRayCastMapper::CreateCanonicalView( vtkRenderer *ren, vtkVolume *volume, vtkImageData *image, int vtkNotUsed(blend_mode), double viewDirection[3], double viewUp[3]) { this->GeneratingCanonicalView = 1; int oldSwap = ren->GetRenderWindow()->GetSwapBuffers(); ren->GetRenderWindow()->SwapBuffersOff(); int dim[3]; image->GetDimensions(dim); int *size = ren->GetRenderWindow()->GetSize(); vtkImageData *bigImage = vtkImageData::New(); bigImage->SetDimensions(size[0], size[1], 1); bigImage->SetScalarTypeToUnsignedChar(); bigImage->SetNumberOfScalarComponents(3); bigImage->AllocateScalars(); this->CanonicalViewImageData = bigImage; double scale[2]; scale[0] = dim[0] / static_cast(size[0]); scale[1] = dim[1] / static_cast(size[1]); // Save the visibility flags of the renderers and set all to false except // for the ren. vtkRendererCollection *renderers=ren->GetRenderWindow()->GetRenderers(); int numberOfRenderers=renderers->GetNumberOfItems(); bool *rendererVisibilities=new bool[numberOfRenderers]; renderers->InitTraversal(); int i=0; while(iGetNextItem(); rendererVisibilities[i]=r->GetDraw()==1; if(r!=ren) { r->SetDraw(false); } ++i; } // Save the visibility flags of the props and set all to false except // for the volume. vtkPropCollection *props=ren->GetViewProps(); int numberOfProps=props->GetNumberOfItems(); bool *propVisibilities=new bool[numberOfProps]; props->InitTraversal(); i=0; while(iGetNextProp(); propVisibilities[i]=p->GetVisibility()==1; if(p!=volume) { p->SetVisibility(false); } ++i; } vtkCamera *savedCamera=ren->GetActiveCamera(); savedCamera->Modified(); vtkCamera *canonicalViewCamera=vtkCamera::New(); // Code from vtkFixedPointVolumeRayCastMapper: double *center=volume->GetCenter(); double bounds[6]; volume->GetBounds(bounds); double d=sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) + (bounds[3]-bounds[2])*(bounds[3]-bounds[2]) + (bounds[5]-bounds[4])*(bounds[5]-bounds[4])); // For now use x distance - need to change this d=bounds[1]-bounds[0]; // Set up the camera in parallel canonicalViewCamera->SetFocalPoint(center); canonicalViewCamera->ParallelProjectionOn(); canonicalViewCamera->SetPosition(center[0] - d*viewDirection[0], center[1] - d*viewDirection[1], center[2] - d*viewDirection[2]); canonicalViewCamera->SetViewUp(viewUp); canonicalViewCamera->SetParallelScale(d/2); ren->SetActiveCamera(canonicalViewCamera); ren->GetRenderWindow()->Render(); ren->SetActiveCamera(savedCamera); canonicalViewCamera->Delete(); // Shrink to image to the desired size vtkImageResample *resample = vtkImageResample::New(); resample->SetInput( bigImage ); resample->SetAxisMagnificationFactor(0,scale[0]); resample->SetAxisMagnificationFactor(1,scale[1]); resample->SetAxisMagnificationFactor(2,1); resample->UpdateWholeExtent(); // Copy the pixels over image->DeepCopy(resample->GetOutput()); bigImage->Delete(); resample->Delete(); // Restore the visibility flags of the props props->InitTraversal(); i=0; while(iGetNextProp(); p->SetVisibility(propVisibilities[i]); ++i; } delete[] propVisibilities; // Restore the visibility flags of the renderers renderers->InitTraversal(); i=0; while(iGetNextItem(); r->SetDraw(rendererVisibilities[i]); ++i; } delete[] rendererVisibilities; ren->GetRenderWindow()->SetSwapBuffers(oldSwap); this->CanonicalViewImageData = NULL; this->GeneratingCanonicalView = 0; } // ---------------------------------------------------------------------------- // Print method for vtkMitkGPUVolumeRayCastMapper void vtkMitkGPUVolumeRayCastMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "AutoAdjustSampleDistances: " << this->AutoAdjustSampleDistances << endl; os << indent << "MinimumImageSampleDistance: " << this->MinimumImageSampleDistance << endl; os << indent << "MaximumImageSampleDistance: " << this->MaximumImageSampleDistance << endl; os << indent << "ImageSampleDistance: " << this->ImageSampleDistance << endl; os << indent << "SampleDistance: " << this->SampleDistance << endl; os << indent << "FinalColorWindow: " << this->FinalColorWindow << endl; os << indent << "FinalColorLevel: " << this->FinalColorLevel << endl; os << indent << "MaskInput: " << this->MaskInput << endl; os << indent << "MaskBlendFactor: " << this->MaskBlendFactor << endl; os << indent << "MaxMemoryInBytes: " << this->MaxMemoryInBytes << endl; os << indent << "MaxMemoryFraction: " << this->MaxMemoryFraction << endl; os << indent << "ReportProgress: " << this->ReportProgress << endl; } // ---------------------------------------------------------------------------- // Description: // Compute the cropping planes clipped by the bounds of the volume. // The result is put into this->ClippedCroppingRegionPlanes. // NOTE: IT WILL BE MOVED UP TO vtkVolumeMapper after bullet proof usage // in this mapper. Other subclasses will use the ClippedCroppingRegionsPlanes // members instead of CroppingRegionPlanes. // \pre volume_exists: this->GetInput()!=0 // \pre valid_cropping: this->Cropping && // this->CroppingRegionPlanes[0]CroppingRegionPlanes[1] && // this->CroppingRegionPlanes[2]CroppingRegionPlanes[3] && // this->CroppingRegionPlanes[4]CroppingRegionPlanes[5]) void vtkMitkGPUVolumeRayCastMapper::ClipCroppingRegionPlanes() { assert("pre: volume_exists" && this->GetInput()!=0); assert("pre: valid_cropping" && this->Cropping && this->CroppingRegionPlanes[0]CroppingRegionPlanes[1] && this->CroppingRegionPlanes[2]CroppingRegionPlanes[3] && this->CroppingRegionPlanes[4]CroppingRegionPlanes[5]); // vtkVolumeMapper::Render() will have something like: // if(this->Cropping && (this->CroppingRegionPlanes[0]>=this->CroppingRegionPlanes[1] || // this->CroppingRegionPlanes[2]>=this->CroppingRegionPlanes[3] || // this->CroppingRegionPlanes[4]>=this->CroppingRegionPlanes[5])) // { // // silentely stop because the cropping is not valid. // return; // } double volBounds[6]; this->GetInput()->GetBounds(volBounds); int i=0; while(i<6) { // max of the mins if(this->CroppingRegionPlanes[i]ClippedCroppingRegionPlanes[i]=volBounds[i]; } else { this->ClippedCroppingRegionPlanes[i]=this->CroppingRegionPlanes[i]; } ++i; // min of the maxs if(this->CroppingRegionPlanes[i]>volBounds[i]) { this->ClippedCroppingRegionPlanes[i]=volBounds[i]; } else { this->ClippedCroppingRegionPlanes[i]=this->CroppingRegionPlanes[i]; } ++i; } } #endif diff --git a/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.h b/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.h index 883b6d702b..67bd01bf96 100644 --- a/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.h +++ b/Modules/MitkExt/Rendering/vtkMitkGPUVolumeRayCastMapper.h @@ -1,312 +1,312 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkMitkGPUVolumeRayCastMapper.h,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. =========================================================================*/ // .NAME vtkMitkGPUVolumeRayCastMapper - Ray casting performed on the GPU. // .SECTION Description // vtkMitkGPUVolumeRayCastMapper is a volume mapper that performs ray casting on // the GPU using fragment programs. // #ifndef __vtkMitkGPUVolumeRayCastMapper_h #define __vtkMitkGPUVolumeRayCastMapper_h #include "vtkVolumeMapper.h" #include "mitkCommon.h" #include "MitkExtExports.h" // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) class vtkVolumeProperty; class vtkRenderWindow; //class vtkKWAMRVolumeMapper; // friend class. class MitkExt_EXPORT vtkMitkGPUVolumeRayCastMapper : public vtkVolumeMapper { public: static vtkMitkGPUVolumeRayCastMapper *New(); - vtkTypeRevisionMacro(vtkMitkGPUVolumeRayCastMapper,vtkVolumeMapper); + vtkTypeMacro(vtkMitkGPUVolumeRayCastMapper,vtkVolumeMapper); void PrintSelf( ostream& os, vtkIndent indent ); // Description: // If AutoAdjustSampleDistances is on, the the ImageSampleDistance // will be varied to achieve the allocated render time of this // prop (controlled by the desired update rate and any culling in // use). vtkSetClampMacro( AutoAdjustSampleDistances, int, 0, 1 ); vtkGetMacro( AutoAdjustSampleDistances, int ); vtkBooleanMacro( AutoAdjustSampleDistances, int ); // Description: // Set/Get the distance between samples used for rendering // when AutoAdjustSampleDistances is off, or when this mapper // has more than 1 second allocated to it for rendering. // Initial value is 1.0. vtkSetMacro( SampleDistance, float ); vtkGetMacro( SampleDistance, float ); // Description: // Sampling distance in the XY image dimensions. Default value of 1 meaning // 1 ray cast per pixel. If set to 0.5, 4 rays will be cast per pixel. If // set to 2.0, 1 ray will be cast for every 4 (2 by 2) pixels. This value // will be adjusted to meet a desired frame rate when AutoAdjustSampleDistances // is on. vtkSetClampMacro( ImageSampleDistance, float, 0.1f, 100.0f ); vtkGetMacro( ImageSampleDistance, float ); // Description: // This is the minimum image sample distance allow when the image // sample distance is being automatically adjusted. vtkSetClampMacro( MinimumImageSampleDistance, float, 0.1f, 100.0f ); vtkGetMacro( MinimumImageSampleDistance, float ); // Description: // This is the maximum image sample distance allow when the image // sample distance is being automatically adjusted. vtkSetClampMacro( MaximumImageSampleDistance, float, 0.1f, 100.0f ); vtkGetMacro( MaximumImageSampleDistance, float ); // Description: // Set/Get the window / level applied to the final color. // This allows brightness / contrast adjustments on the // final image. // window is the width of the window. // level is the center of the window. // Initial window value is 1.0 // Initial level value is 0.5 // window cannot be null but can be negative, this way // values will be reversed. // |window| can be larger than 1.0 // level can be any real value. vtkSetMacro( FinalColorWindow, float ); vtkGetMacro( FinalColorWindow, float ); vtkSetMacro( FinalColorLevel, float ); vtkGetMacro( FinalColorLevel, float ); // Description: // Maximum size of the 3D texture in GPU memory. // Will default to the size computed from the graphics // card. Can be adjusted by the user. vtkSetMacro( MaxMemoryInBytes, vtkIdType ); vtkGetMacro( MaxMemoryInBytes, vtkIdType ); // Description: // Maximum fraction of the MaxMemoryInBytes that should // be used to hold the texture. Valid values are 0.1 to // 1.0. vtkSetClampMacro( MaxMemoryFraction, float, 0.1f, 1.0f ); vtkGetMacro( MaxMemoryFraction, float ); // Description: // Tells if the mapper will report intermediate progress. // Initial value is true. As the progress works with a GL blocking // call (glFinish()), this can be useful for huge dataset but can // slow down rendering of small dataset. It should be set to true // for big dataset or complex shading and streaming but to false for // small datasets. vtkSetMacro(ReportProgress,bool); vtkGetMacro(ReportProgress,bool); // Description: // Based on hardware and properties, we may or may not be able to // render using 3D texture mapping. This indicates if 3D texture // mapping is supported by the hardware, and if the other extensions // necessary to support the specific properties are available. virtual int IsRenderSupported(vtkRenderWindow *vtkNotUsed(window), vtkVolumeProperty *vtkNotUsed(property)) { return 0; } void CreateCanonicalView( vtkRenderer *ren, vtkVolume *volume, vtkImageData *image, int blend_mode, double viewDirection[3], double viewUp[3] ); void SetMaskInput(vtkImageData *mask); vtkGetObjectMacro(MaskInput, vtkImageData); // Description: // Tells how much mask color transfer function is used compared to the // standard color transfer function when the mask is true. // 0.0 means only standard color transfer function. // 1.0 means only mask color tranfer function. // Initial value is 1.0. vtkSetClampMacro(MaskBlendFactor,float,0.0f,1.0f); vtkGetMacro(MaskBlendFactor,float); //BTX // Description: // WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE // Initialize rendering for this volume. void Render( vtkRenderer *, vtkVolume * ); // Description: // Handled in the subclass - the actual render method // \pre input is up-to-date. virtual void GPURender( vtkRenderer *, vtkVolume *) {} // Description: // WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE // Release any graphics resources that are being consumed by this mapper. // The parameter window could be used to determine which graphic // resources to release. // \deprecatedSince{2013_12} DEPRECATED(void ReleaseGraphicsResources(vtkWindow *)) { }; // Description: // Return how much the dataset has to be reduced in each dimension to // fit on the GPU. If the value is 1.0, there is no need to reduce the // dataset. // \pre the calling thread has a current OpenGL context. // \pre mapper_supported: IsRenderSupported(renderer->GetRenderWindow(),0) // The computation is based on hardware limits (3D texture indexable size) // and MaxMemoryInBytes. // \post valid_i_ratio: ratio[0]>0 && ratio[0]<=1.0 // \post valid_j_ratio: ratio[1]>0 && ratio[1]<=1.0 // \post valid_k_ratio: ratio[2]>0 && ratio[2]<=1.0 virtual void GetReductionRatio(double ratio[3])=0; //ETX protected: vtkMitkGPUVolumeRayCastMapper(); ~vtkMitkGPUVolumeRayCastMapper(); // Check to see that the render will be OK int ValidateRender( vtkRenderer *, vtkVolume * ); // Special version of render called during the creation // of a canonical view. void CanonicalViewRender( vtkRenderer *, vtkVolume * ); // Methods called by the AMR Volume Mapper. virtual void PreRender(vtkRenderer *ren, vtkVolume *vol, double datasetBounds[6], double scalarRange[2], int numberOfScalarComponents, unsigned int numberOfLevels)=0; // \pre input is up-to-date virtual void RenderBlock(vtkRenderer *ren, vtkVolume *vol, unsigned int level)=0; virtual void PostRender(vtkRenderer *ren, int numberOfScalarComponents)=0; // Description: // Called by the AMR Volume Mapper. // Set the flag that tells if the scalars are on point data (0) or // cell data (1). void SetCellFlag(int cellFlag); // The distance between sample points along the ray float SampleDistance; float ImageSampleDistance; float MinimumImageSampleDistance; float MaximumImageSampleDistance; int AutoAdjustSampleDistances; int SmallVolumeRender; double BigTimeToDraw; double SmallTimeToDraw; float FinalColorWindow; float FinalColorLevel; vtkIdType MaxMemoryInBytes; float MaxMemoryFraction; // 1 if we are generating the canonical image, 0 otherwise int GeneratingCanonicalView; vtkImageData *CanonicalViewImageData; // Description: // Set the mapper in AMR Mode or not. Initial value is false. // Called only by the vtkKWAMRVolumeMapper vtkSetClampMacro(AMRMode,int,0,1); vtkGetMacro(AMRMode,int); vtkBooleanMacro(AMRMode,int); int AMRMode; int CellFlag; // point data or cell data (or field data, not handled) ? // Description: // Compute the cropping planes clipped by the bounds of the volume. // The result is put into this->ClippedCroppingRegionPlanes. // NOTE: IT WILL BE MOVED UP TO vtkVolumeMapper after bullet proof usage // in this mapper. Other subclasses will use the ClippedCroppingRegionsPlanes // members instead of CroppingRegionPlanes. // \pre volume_exists: this->GetInput()!=0 // \pre valid_cropping: this->Cropping && // this->CroppingRegionPlanes[0]CroppingRegionPlanes[1] && // this->CroppingRegionPlanes[2]CroppingRegionPlanes[3] && // this->CroppingRegionPlanes[4]CroppingRegionPlanes[5]) virtual void ClipCroppingRegionPlanes(); double ClippedCroppingRegionPlanes[6]; bool ReportProgress; vtkImageData *MaskInput; float MaskBlendFactor; vtkGetObjectMacro(TransformedInput, vtkImageData); void SetTransformedInput(vtkImageData*); vtkImageData* TransformedInput; // Description: // This is needed only to check if the input data has been changed since the last // Render() call. vtkImageData* LastInput; private: vtkMitkGPUVolumeRayCastMapper(const vtkMitkGPUVolumeRayCastMapper&); // Not implemented. void operator=(const vtkMitkGPUVolumeRayCastMapper&); // Not implemented. }; #endif #endif diff --git a/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp b/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp index f5486a7af1..1b731f69f8 100644 --- a/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp +++ b/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp @@ -1,7494 +1,7493 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkMitkOpenGLGPUVolumeRayCastMapper.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 "vtkMitkOpenGLGPUVolumeRayCastMapper.h" // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkObjectFactory.h" #include "vtkVolume.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkCamera.h" #include "vtkMatrix4x4.h" #include "vtkImageData.h" #include "vtkTimerLog.h" #include "vtkVolumeProperty.h" #include "vtkColorTransferFunction.h" #include "vtkPiecewiseFunction.h" #include "vtkOpenGLExtensionManager.h" #include "vtkgl.h" #ifndef VTK_IMPLEMENT_MESA_CXX # include "vtkOpenGL.h" #endif #include #include #include #include #include #include "vtkClipDataSet.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkGeometryFilter.h" #include "vtkMath.h" #include "vtkPlane.h" #include "vtkPlaneCollection.h" #include "vtkPlanes.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPoints.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedShortArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkClipConvexPolyData.h" #include "vtkClipPolyData.h" #include "vtkDensifyPolyData.h" #include "vtkImageResample.h" #include #include // qsort() #include "vtkDataSetTriangleFilter.h" #include "vtkAbstractArray.h" // required if compiled against VTK 5.0 #include "vtkTessellatedBoxSource.h" #include "vtkCleanPolyData.h" #include "vtkCommand.h" // for VolumeMapperRender{Start|End|Progress}Event #include "vtkPerlinNoise.h" #include #include "vtkStdString.h" //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkUnsupportedRequiredExtensionsStringStream { public: vtkstd::ostringstream Stream; vtkUnsupportedRequiredExtensionsStringStream() { } private: // undefined copy constructor. vtkUnsupportedRequiredExtensionsStringStream(const vtkUnsupportedRequiredExtensionsStringStream &other); // undefined assignment operator. vtkUnsupportedRequiredExtensionsStringStream &operator=(const vtkUnsupportedRequiredExtensionsStringStream &other); }; class vtkMapDataArrayTextureId { public: vtkstd::map Map; vtkMapDataArrayTextureId() { } private: // undefined copy constructor. vtkMapDataArrayTextureId(const vtkMapDataArrayTextureId &other); // undefined assignment operator. vtkMapDataArrayTextureId &operator=(const vtkMapDataArrayTextureId &other); }; class vtkMapMaskTextureId { public: vtkstd::map Map; vtkMapMaskTextureId() { } private: // undefined copy constructor. vtkMapMaskTextureId(const vtkMapMaskTextureId &other); // undefined assignment operator. vtkMapMaskTextureId &operator=(const vtkMapMaskTextureId &other); }; //----------------------------------------------------------------------------- extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeFS; extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_HeaderFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFourDependentFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFourDependentCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFourDependentNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_ParallelProjectionFS; extern const char *vtkMitkGPUVolumeRayCastMapper_PerspectiveProjectionFS; extern const char *vtkMitkGPUVolumeRayCastMapper_ScaleBiasFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFourDependentFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFourDependentCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFourDependentNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeMaskFS; extern const char *vtkMitkGPUVolumeRayCastMapper_NoShadeFS; extern const char *vtkMitkGPUVolumeRayCastMapper_ShadeFS; extern const char *vtkMitkGPUVolumeRayCastMapper_OneComponentFS; extern const char *vtkMitkGPUVolumeRayCastMapper_FourComponentsFS; enum { vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized=-1, // not init vtkMitkOpenGLGPUVolumeRayCastMapperProjectionPerspective=0, // false vtkMitkOpenGLGPUVolumeRayCastMapperProjectionParallel=1 // true }; enum { vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIPFourDependent, vtkMitkOpenGLGPUVolumeRayCastMapperMethodComposite, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIP, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIPFourDependent, vtkMitkOpenGLGPUVolumeRayCastMapperMethodCompositeMask }; // component implementation enum { vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized=-1, // not init vtkMitkOpenGLGPUVolumeRayCastMapperComponentOne=0, // false vtkMitkOpenGLGPUVolumeRayCastMapperComponentFour=1, // true vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotUsed=2 // when not composite }; // Shade implementation enum { vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized=-1, // not init vtkMitkOpenGLGPUVolumeRayCastMapperShadeNo=0, // false vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes=1, // true vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotUsed=2 // when not composite }; // Cropping implementation enum { vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized, vtkMitkOpenGLGPUVolumeRayCastMapperCompositeCropping, vtkMitkOpenGLGPUVolumeRayCastMapperCompositeNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPFourDependentCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPFourDependentNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPFourDependentCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPFourDependentNoCropping }; enum { vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap=0, // 2d texture vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront // 2d texture }; const int vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects=vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+2; const int vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize=1024; //power of two #ifndef VTK_IMPLEMENT_MESA_CXX -vtkCxxRevisionMacro(vtkMitkOpenGLGPUVolumeRayCastMapper, "$Revision: 1.9 $"); vtkStandardNewMacro(vtkMitkOpenGLGPUVolumeRayCastMapper); #endif //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkOpacityTable { public: vtkOpacityTable() { this->TextureId=0; this->LastBlendMode=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND; this->LastSampleDistance=1.0; this->Table=0; this->Loaded=false; this->LastLinearInterpolation=false; } ~vtkOpacityTable() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } if(this->Table!=0) { delete[] this->Table; this->Table=0; } } bool IsLoaded() { return this->Loaded; } void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(GL_TEXTURE_1D,this->TextureId); } // \pre the active texture is set to TEXTURE2 void Update(vtkPiecewiseFunction *scalarOpacity, int blendMode, double sampleDistance, double range[2], double unitDistance, bool linearInterpolation) { assert("pre: scalarOpacity_exists" && scalarOpacity!=0); bool needUpdate=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(GL_TEXTURE_1D,this->TextureId); if(needUpdate) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); } if(scalarOpacity->GetMTime() > this->BuildTime || (this->LastBlendMode!=blendMode) || (blendMode==vtkVolumeMapper::COMPOSITE_BLEND && this->LastSampleDistance!=sampleDistance) || needUpdate || !this->Loaded) { this->Loaded=false; if(this->Table==0) { this->Table= new float[vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize]; } scalarOpacity->GetTable(range[0],range[1], vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize, this->Table); this->LastBlendMode=blendMode; // Correct the opacity array for the spacing between the planes if we // are using a composite blending operation if(blendMode==vtkVolumeMapper::COMPOSITE_BLEND) { float *ptr=this->Table; double factor=sampleDistance/unitDistance; int i=0; while(i0.0001f) { *ptr=static_cast(1.0-pow(1.0-static_cast(*ptr), factor)); } ++ptr; ++i; } this->LastSampleDistance=sampleDistance; } glTexImage1D(GL_TEXTURE_1D,0,GL_ALPHA16, vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize,0, GL_ALPHA,GL_FLOAT,this->Table); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("1d opacity texture is too large"); this->Loaded=true; this->BuildTime.Modified(); } needUpdate=needUpdate || this->LastLinearInterpolation!=linearInterpolation; if(needUpdate) { this->LastLinearInterpolation=linearInterpolation; GLint value; if(linearInterpolation) { value=GL_LINEAR; } else { value=GL_NEAREST; } glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,value); glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,value); } } protected: GLuint TextureId; int LastBlendMode; double LastSampleDistance; vtkTimeStamp BuildTime; float *Table; bool Loaded; bool LastLinearInterpolation; }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkOpacityTables { public: vtkstd::vector Vector; vtkOpacityTables(size_t numberOfLevels) : Vector(numberOfLevels) { } private: // undefined copy constructor. vtkOpacityTables(const vtkOpacityTables &other); // undefined assignment operator. vtkOpacityTables &operator=(const vtkOpacityTables &other); }; //----------------------------------------------------------------------------- class vtkRGBTable { public: vtkRGBTable() { this->TextureId=0; this->Table=0; this->Loaded=false; this->LastLinearInterpolation=false; } ~vtkRGBTable() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } if(this->Table!=0) { delete[] this->Table; this->Table=0; } } bool IsLoaded() { return this->Loaded; } void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(GL_TEXTURE_1D,this->TextureId); } // \pre the active texture is set properly. (default color, // mask1, mask2,..) void Update(vtkColorTransferFunction *scalarRGB, double range[2], bool linearInterpolation) { assert("pre: scalarRGB_exists" && scalarRGB!=0); bool needUpdate=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(GL_TEXTURE_1D,this->TextureId); if(needUpdate) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); } if(scalarRGB->GetMTime() > this->BuildTime || needUpdate || !this->Loaded) { this->Loaded=false; if(this->Table==0) { this->Table= new float[vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize*3]; } scalarRGB->GetTable(range[0],range[1], vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize, this->Table); glTexImage1D(GL_TEXTURE_1D,0,GL_RGB16, vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize,0, GL_RGB,GL_FLOAT,this->Table); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("1d RGB texture is too large"); this->Loaded=true; this->BuildTime.Modified(); } needUpdate=needUpdate || this->LastLinearInterpolation!=linearInterpolation; if(needUpdate) { this->LastLinearInterpolation=linearInterpolation; GLint value; if(linearInterpolation) { value=GL_LINEAR; } else { value=GL_NEAREST; } glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,value); glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,value); } } protected: GLuint TextureId; vtkTimeStamp BuildTime; float *Table; bool Loaded; bool LastLinearInterpolation; }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkKWScalarField { public: vtkKWScalarField() { this->TextureId=0; this->Loaded=false; this->Supports_GL_ARB_texture_float=false; this->LoadedTableRange[0]=0.0; this->LoadedTableRange[1]=1.0; this->LoadedExtent[0]=VTK_INT_MAX; this->LoadedExtent[1]=VTK_INT_MIN; this->LoadedExtent[2]=VTK_INT_MAX; this->LoadedExtent[3]=VTK_INT_MIN; this->LoadedExtent[4]=VTK_INT_MAX; this->LoadedExtent[5]=VTK_INT_MIN; } ~vtkKWScalarField() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } } vtkTimeStamp GetBuildTime() { return this->BuildTime; } void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); } void Update(vtkImageData *input, int cellFlag, int textureExtent[6], int scalarMode, int arrayAccessMode, int arrayId, const char *arrayName, bool linearInterpolation, double tableRange[2], int maxMemoryInBytes) { bool needUpdate=false; bool modified=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); int obsolete=needUpdate || !this->Loaded || input->GetMTime()>this->BuildTime; if(!obsolete) { obsolete=cellFlag!=this->LoadedCellFlag; int i=0; while(!obsolete && i<6) { obsolete=obsolete || this->LoadedExtent[i]>textureExtent[i]; ++i; obsolete=obsolete || this->LoadedExtent[i]LoadedTableRange[0]!=tableRange[0] || this->LoadedTableRange[1]!=tableRange[1]; } if(obsolete) { this->Loaded=false; int dim[3]; input->GetDimensions(dim); GLint internalFormat=0; GLenum format=0; GLenum type=0; // shift then scale: y:=(x+shift)*scale double shift=0.0; double scale=1.0; int needTypeConversion=0; vtkDataArray *sliceArray=0; vtkDataArray *scalars= vtkAbstractMapper::GetScalars(input,scalarMode,arrayAccessMode, arrayId,arrayName, this->LoadedCellFlag); // DONT USE GetScalarType() or GetNumberOfScalarComponents() on // ImageData as it deals only with point data... int scalarType=scalars->GetDataType(); if(scalars->GetNumberOfComponents()==4) { // this is RGBA, unsigned char only internalFormat=GL_RGBA16; format=GL_RGBA; type=GL_UNSIGNED_BYTE; } else { // input->GetNumberOfScalarComponents()==1 switch(scalarType) { case VTK_FLOAT: if(this->Supports_GL_ARB_texture_float) { internalFormat=vtkgl::INTENSITY16F_ARB; } else { internalFormat=GL_INTENSITY16; } format=GL_RED; type=GL_FLOAT; shift=-tableRange[0]; scale=1/(tableRange[1]-tableRange[0]); break; case VTK_UNSIGNED_CHAR: internalFormat=GL_INTENSITY8; format=GL_RED; type=GL_UNSIGNED_BYTE; shift=-tableRange[0]/VTK_UNSIGNED_CHAR_MAX; scale= VTK_UNSIGNED_CHAR_MAX/(tableRange[1]-tableRange[0]); break; case VTK_SIGNED_CHAR: internalFormat=GL_INTENSITY8; format=GL_RED; type=GL_BYTE; shift=-(2*tableRange[0]+1)/VTK_UNSIGNED_CHAR_MAX; scale=VTK_SIGNED_CHAR_MAX/(tableRange[1]-tableRange[0]); break; case VTK_CHAR: // not supported assert("check: impossible case" && 0); break; case VTK_BIT: // not supported assert("check: impossible case" && 0); break; case VTK_ID_TYPE: // not supported assert("check: impossible case" && 0); break; case VTK_INT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_INT; shift=-(2*tableRange[0]+1)/VTK_UNSIGNED_INT_MAX; scale=VTK_INT_MAX/(tableRange[1]-tableRange[0]); break; case VTK_DOUBLE: case VTK___INT64: case VTK_LONG: case VTK_LONG_LONG: case VTK_UNSIGNED___INT64: case VTK_UNSIGNED_LONG: case VTK_UNSIGNED_LONG_LONG: needTypeConversion=1; // to float if(this->Supports_GL_ARB_texture_float) { internalFormat=vtkgl::INTENSITY16F_ARB; } else { internalFormat=GL_INTENSITY16; } format=GL_RED; type=GL_FLOAT; shift=-tableRange[0]; scale=1/(tableRange[1]-tableRange[0]); sliceArray=vtkFloatArray::New(); break; case VTK_SHORT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_SHORT; shift=-(2*tableRange[0]+1)/VTK_UNSIGNED_SHORT_MAX; scale=VTK_SHORT_MAX/(tableRange[1]-tableRange[0]); break; case VTK_STRING: // not supported assert("check: impossible case" && 0); break; case VTK_UNSIGNED_SHORT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_UNSIGNED_SHORT; shift=-tableRange[0]/VTK_UNSIGNED_SHORT_MAX; scale= VTK_UNSIGNED_SHORT_MAX/(tableRange[1]-tableRange[0]); break; case VTK_UNSIGNED_INT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_UNSIGNED_INT; shift=-tableRange[0]/VTK_UNSIGNED_INT_MAX; scale=VTK_UNSIGNED_INT_MAX/(tableRange[1]-tableRange[0]); break; default: assert("check: impossible case" && 0); break; } } // Enough memory? int textureSize[3]; int i=0; while(i<3) { textureSize[i]=textureExtent[2*i+1]-textureExtent[2*i]+1; ++i; } GLint width; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&width); this->Loaded=textureSize[0]<=width && textureSize[1]<=width && textureSize[2]<=width; if(this->Loaded) { // so far, so good. the texture size is theorically small enough // for OpenGL vtkgl::TexImage3D(vtkgl::PROXY_TEXTURE_3D,0,internalFormat, textureSize[0],textureSize[1],textureSize[2],0, format,type,0); glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_3D,0,GL_TEXTURE_WIDTH, &width); this->Loaded=width!=0; if(this->Loaded) { // so far, so good but some cards always succeed with a proxy texture // let's try to actually allocate.. vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,internalFormat,textureSize[0], textureSize[1],textureSize[2],0,format,type,0); GLenum errorCode=glGetError(); this->Loaded=errorCode!=GL_OUT_OF_MEMORY; if(this->Loaded) { // so far, so good, actual allocation succeeded. if(errorCode!=GL_NO_ERROR) { cout<<"after try to load the texture"; cout<<" ERROR (x"<(errorCode)); cout<Loaded=textureSize[0]*textureSize[1]* textureSize[2]*vtkAbstractArray::GetDataTypeSize(scalarType)* scalars->GetNumberOfComponents()<=maxMemoryInBytes; if(this->Loaded) { // OK, we consider the allocation above succeeded... // If it actually didn't the only to fix it for the user // is to decrease the value of this->MaxMemoryInBytes. // enough memory! We can load the scalars! double bias=shift*scale; // we don't clamp to edge because for the computation of the // gradient on the border we need some external value. glTexParameterf(vtkgl::TEXTURE_3D,vtkgl::TEXTURE_WRAP_R,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_S,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_T,vtkgl::CLAMP_TO_EDGE); GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; glTexParameterfv(vtkgl::TEXTURE_3D,GL_TEXTURE_BORDER_COLOR, borderColor); if(needTypeConversion) { // Convert and send to the GPU, z-slice by z-slice. // Allocate memory on the GPU (NULL data pointer with the right // dimensions) // Here we are assuming that GL_ARB_texture_non_power_of_two is // available glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // memory allocation is already done. // Send the slices: // allocate CPU memory for a slice. sliceArray->SetNumberOfComponents(1); // FB TODO CHECK THAT sliceArray->SetNumberOfTuples(textureSize[0]*textureSize[1]); void *slicePtr=sliceArray->GetVoidPointer(0); int k=0; int kInc=(dim[0]-cellFlag)*(dim[1]-cellFlag); int kOffset=(textureExtent[4]*(dim[1]-cellFlag) +textureExtent[2])*(dim[0]-cellFlag) +textureExtent[0]; while(kSetTuple1(jDestOffset+i, (scalars->GetTuple1(kOffset+jOffset +i) +shift)*scale); ++i; } ++j; jOffset+=dim[0]-cellFlag; jDestOffset+=textureSize[0]; } // Here we are assuming that GL_ARB_texture_non_power_of_two is // available vtkgl::TexSubImage3D(vtkgl::TEXTURE_3D, 0, 0,0,k, textureSize[0],textureSize[1], 1, // depth is 1, not 0! format,type, slicePtr); ++k; kOffset+=kInc; } sliceArray->Delete(); } else { // One chunk of data to the GPU. // It works for the whole volume or for a subvolume. // Here we are assuming that GL_ARB_texture_non_power_of_two is // available // make sure any previous OpenGL call is executed and will not // be disturbed by our PixelTransfer value glFinish(); glPixelTransferf(GL_RED_SCALE,static_cast(scale)); glPixelTransferf(GL_RED_BIAS,static_cast(bias)); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); if(!(textureExtent[1]-textureExtent[0]+cellFlag==dim[0])) { glPixelStorei(GL_UNPACK_ROW_LENGTH,dim[0]-cellFlag); } if(!(textureExtent[3]-textureExtent[2]+cellFlag==dim[1])) { glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT, dim[1]-cellFlag); } void *dataPtr=scalars->GetVoidPointer( ((textureExtent[4]*(dim[1]-cellFlag)+textureExtent[2]) *(dim[0]-cellFlag)+textureExtent[0]) *scalars->GetNumberOfComponents()); if(1) // !this->SupportsPixelBufferObjects) { vtkgl::TexImage3D(vtkgl::TEXTURE_3D, 0, internalFormat, textureSize[0],textureSize[1],textureSize[2], 0,format,type,dataPtr); } else { GLuint pbo=0; vtkgl::GenBuffers(1,&pbo); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("genbuffer"); vtkgl::BindBuffer(vtkgl::PIXEL_UNPACK_BUFFER,pbo); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("binbuffer"); vtkgl::GLsizeiptr texSize= textureSize[0]*textureSize[1]*textureSize[2]* vtkAbstractArray::GetDataTypeSize(scalarType)* scalars->GetNumberOfComponents(); vtkgl::BufferData(vtkgl::PIXEL_UNPACK_BUFFER,texSize,dataPtr, vtkgl::STREAM_DRAW); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("bufferdata"); vtkgl::TexImage3D(vtkgl::TEXTURE_3D, 0, internalFormat, textureSize[0],textureSize[1],textureSize[2], 0,format,type,0); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("teximage3d"); vtkgl::BindBuffer(vtkgl::PIXEL_UNPACK_BUFFER,0); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("bindbuffer to 0"); vtkgl::DeleteBuffers(1,&pbo); } vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("3d texture is too large2"); // make sure TexImage3D is executed with our PixelTransfer mode glFinish(); // Restore the default values. glPixelStorei(GL_UNPACK_ROW_LENGTH,0); glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT,0); glPixelTransferf(GL_RED_SCALE,1.0); glPixelTransferf(GL_RED_BIAS,0.0); } this->LoadedCellFlag=cellFlag; i=0; while(i<6) { this->LoadedExtent[i]=textureExtent[i]; ++i; } double spacing[3]; double origin[3]; input->GetSpacing(spacing); input->GetOrigin(origin); int swapBounds[3]; swapBounds[0]=(spacing[0]<0); swapBounds[1]=(spacing[1]<0); swapBounds[2]=(spacing[2]<0); if(!this->LoadedCellFlag) // loaded extents represent points { // slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; // in general, x=o+i*spacing. // if spacing is positive min extent match the min of the // bounding box // and the max extent match the max of the bounding box // if spacing is negative min extent match the max of the // bounding box // and the max extent match the min of the bounding box // if spacing is negative, we may have to rethink the equation // between real point and texture coordinate... this->LoadedBounds[0]=origin[0]+ static_cast(this->LoadedExtent[0+swapBounds[0]])*spacing[0]; this->LoadedBounds[2]=origin[1]+ static_cast(this->LoadedExtent[2+swapBounds[1]])*spacing[1]; this->LoadedBounds[4]=origin[2]+ static_cast(this->LoadedExtent[4+swapBounds[2]])*spacing[2]; this->LoadedBounds[1]=origin[0]+ static_cast(this->LoadedExtent[1-swapBounds[0]])*spacing[0]; this->LoadedBounds[3]=origin[1]+ static_cast(this->LoadedExtent[3-swapBounds[1]])*spacing[1]; this->LoadedBounds[5]=origin[2]+ static_cast(this->LoadedExtent[5-swapBounds[2]])*spacing[2]; } else // loaded extents represent cells { int wholeTextureExtent[6]; input->GetExtent(wholeTextureExtent); i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } i=0; while(i<3) { if(this->LoadedExtent[2*i]==wholeTextureExtent[2*i]) { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]; } else { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i])+0.5)*spacing[i]; } if(this->LoadedExtent[2*i+1]==wholeTextureExtent[2*i+1]) { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+1.0)*spacing[i]; } else { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+0.5)*spacing[i]; } ++i; } } this->LoadedTableRange[0]=tableRange[0]; this->LoadedTableRange[1]=tableRange[1]; modified=true; } // if enough memory else { } } //load fail with out of memory else { } } // proxy ok else { // proxy failed } } else { // out of therical limitationa } } // if obsolete if(this->Loaded && (needUpdate || modified || linearInterpolation!=this->LinearInterpolation)) { this->LinearInterpolation=linearInterpolation; if(this->LinearInterpolation) { glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MAG_FILTER, GL_NEAREST ); } modified=true; } if(modified) { this->BuildTime.Modified(); } } double *GetLoadedBounds() { assert("pre: loaded" && this->Loaded); return this->LoadedBounds; } vtkIdType *GetLoadedExtent() { assert("pre: loaded" && this->Loaded); return this->LoadedExtent; } int GetLoadedCellFlag() { assert("pre: loaded" && this->Loaded); return this->LoadedCellFlag; } bool IsLoaded() { return this->Loaded; } bool GetSupports_GL_ARB_texture_float() { return this->Supports_GL_ARB_texture_float; } void SetSupports_GL_ARB_texture_float(bool value) { this->Supports_GL_ARB_texture_float=value; } protected: GLuint TextureId; vtkTimeStamp BuildTime; double LoadedBounds[6]; vtkIdType LoadedExtent[6]; int LoadedCellFlag; bool Loaded; bool LinearInterpolation; bool Supports_GL_ARB_texture_float; double LoadedTableRange[2]; }; //----------------------------------------------------------------------------- class vtkKWMask { public: vtkKWMask() { this->TextureId=0; this->Loaded=false; this->LoadedExtent[0]=VTK_INT_MAX; this->LoadedExtent[1]=VTK_INT_MIN; this->LoadedExtent[2]=VTK_INT_MAX; this->LoadedExtent[3]=VTK_INT_MIN; this->LoadedExtent[4]=VTK_INT_MAX; this->LoadedExtent[5]=VTK_INT_MIN; } ~vtkKWMask() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } } vtkTimeStamp GetBuildTime() { return this->BuildTime; } // \pre vtkgl::ActiveTexture(vtkgl::TEXTURE7) has to be called first. void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); } // \pre vtkgl::ActiveTexture(vtkgl::TEXTURE7) has to be called first. void Update(vtkImageData *input, int cellFlag, int textureExtent[6], int scalarMode, int arrayAccessMode, int arrayId, const char *arrayName, int maxMemoryInBytes) { bool needUpdate=false; bool modified=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); int obsolete=needUpdate || !this->Loaded || input->GetMTime()>this->BuildTime; if(!obsolete) { obsolete=cellFlag!=this->LoadedCellFlag; int i=0; while(!obsolete && i<6) { obsolete=obsolete || this->LoadedExtent[i]>textureExtent[i]; ++i; obsolete=obsolete || this->LoadedExtent[i]Loaded=false; int dim[3]; input->GetDimensions(dim); vtkDataArray *scalars= vtkAbstractMapper::GetScalars(input,scalarMode,arrayAccessMode, arrayId,arrayName, this->LoadedCellFlag); // DONT USE GetScalarType() or GetNumberOfScalarComponents() on // ImageData as it deals only with point data... int scalarType=scalars->GetDataType(); if(scalarType!=VTK_UNSIGNED_CHAR) { cout <<"mask should be VTK_UNSIGNED_CHAR." << endl; } if(scalars->GetNumberOfComponents()!=1) { cout <<"mask should be a one-component scalar field." << endl; } GLint internalFormat=GL_ALPHA8; GLenum format=GL_ALPHA; GLenum type=GL_UNSIGNED_BYTE; // Enough memory? int textureSize[3]; int i=0; while(i<3) { textureSize[i]=textureExtent[2*i+1]-textureExtent[2*i]+1; ++i; } GLint width; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&width); this->Loaded=textureSize[0]<=width && textureSize[1]<=width && textureSize[2]<=width; if(this->Loaded) { // so far, so good. the texture size is theorically small enough // for OpenGL vtkgl::TexImage3D(vtkgl::PROXY_TEXTURE_3D,0,internalFormat, textureSize[0],textureSize[1],textureSize[2],0, format,type,0); glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_3D,0,GL_TEXTURE_WIDTH, &width); this->Loaded=width!=0; if(this->Loaded) { // so far, so good but some cards always succeed with a proxy texture // let's try to actually allocate.. vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,internalFormat,textureSize[0], textureSize[1],textureSize[2],0,format,type,0); GLenum errorCode=glGetError(); this->Loaded=errorCode!=GL_OUT_OF_MEMORY; if(this->Loaded) { // so far, so good, actual allocation succeeded. if(errorCode!=GL_NO_ERROR) { cout<<"after try to load the texture"; cout<<" ERROR (x"<(errorCode)); cout<Loaded=textureSize[0]*textureSize[1]* textureSize[2]*vtkAbstractArray::GetDataTypeSize(scalarType)* scalars->GetNumberOfComponents()<=maxMemoryInBytes; if(this->Loaded) { // OK, we consider the allocation above succeeded... // If it actually didn't the only to fix it for the user // is to decrease the value of this->MaxMemoryInBytes. // enough memory! We can load the scalars! // we don't clamp to edge because for the computation of the // gradient on the border we need some external value. glTexParameterf(vtkgl::TEXTURE_3D,vtkgl::TEXTURE_WRAP_R,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_S,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_T,vtkgl::CLAMP_TO_EDGE); GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; glTexParameterfv(vtkgl::TEXTURE_3D,GL_TEXTURE_BORDER_COLOR, borderColor); glPixelTransferf(GL_ALPHA_SCALE,1.0); glPixelTransferf(GL_ALPHA_BIAS,0.0); glPixelStorei(GL_UNPACK_ALIGNMENT,1); if(!(textureExtent[1]-textureExtent[0]+cellFlag==dim[0])) { glPixelStorei(GL_UNPACK_ROW_LENGTH,dim[0]-cellFlag); } if(!(textureExtent[3]-textureExtent[2]+cellFlag==dim[1])) { glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT, dim[1]-cellFlag); } void *dataPtr=scalars->GetVoidPointer( ((textureExtent[4]*(dim[1]-cellFlag)+textureExtent[2]) *(dim[0]-cellFlag)+textureExtent[0]) *scalars->GetNumberOfComponents()); vtkgl::TexImage3D(vtkgl::TEXTURE_3D, 0, internalFormat, textureSize[0],textureSize[1],textureSize[2], 0,format,type,dataPtr); // Restore the default values. glPixelStorei(GL_UNPACK_ROW_LENGTH,0); glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT,0); glPixelTransferf(GL_ALPHA_SCALE,1.0); glPixelTransferf(GL_ALPHA_BIAS,0.0); this->LoadedCellFlag=cellFlag; i=0; while(i<6) { this->LoadedExtent[i]=textureExtent[i]; ++i; } double spacing[3]; double origin[3]; input->GetSpacing(spacing); input->GetOrigin(origin); int swapBounds[3]; swapBounds[0]=(spacing[0]<0); swapBounds[1]=(spacing[1]<0); swapBounds[2]=(spacing[2]<0); if(!this->LoadedCellFlag) // loaded extents represent points { // slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; // in general, x=o+i*spacing. // if spacing is positive min extent match the min of the // bounding box // and the max extent match the max of the bounding box // if spacing is negative min extent match the max of the // bounding box // and the max extent match the min of the bounding box // if spacing is negative, we may have to rethink the equation // between real point and texture coordinate... this->LoadedBounds[0]=origin[0]+ static_cast(this->LoadedExtent[0+swapBounds[0]])*spacing[0]; this->LoadedBounds[2]=origin[1]+ static_cast(this->LoadedExtent[2+swapBounds[1]])*spacing[1]; this->LoadedBounds[4]=origin[2]+ static_cast(this->LoadedExtent[4+swapBounds[2]])*spacing[2]; this->LoadedBounds[1]=origin[0]+ static_cast(this->LoadedExtent[1-swapBounds[0]])*spacing[0]; this->LoadedBounds[3]=origin[1]+ static_cast(this->LoadedExtent[3-swapBounds[1]])*spacing[1]; this->LoadedBounds[5]=origin[2]+ static_cast(this->LoadedExtent[5-swapBounds[2]])*spacing[2]; } else // loaded extents represent cells { int wholeTextureExtent[6]; input->GetExtent(wholeTextureExtent); i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } i=0; while(i<3) { if(this->LoadedExtent[2*i]==wholeTextureExtent[2*i]) { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]; } else { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i])+0.5)*spacing[i]; } if(this->LoadedExtent[2*i+1]==wholeTextureExtent[2*i+1]) { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+1.0)*spacing[i]; } else { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+0.5)*spacing[i]; } ++i; } } modified=true; } // if enough memory else { } } //load fail with out of memory else { } } // proxy ok else { // proxy failed } } else { // out of therical limitationa } } // if obsolete if(this->Loaded && (needUpdate || modified)) { glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MAG_FILTER, GL_NEAREST ); modified=true; } if(modified) { this->BuildTime.Modified(); } } double *GetLoadedBounds() { assert("pre: loaded" && this->Loaded); return this->LoadedBounds; } vtkIdType *GetLoadedExtent() { assert("pre: loaded" && this->Loaded); return this->LoadedExtent; } int GetLoadedCellFlag() { assert("pre: loaded" && this->Loaded); return this->LoadedCellFlag; } bool IsLoaded() { return this->Loaded; } protected: GLuint TextureId; vtkTimeStamp BuildTime; double LoadedBounds[6]; vtkIdType LoadedExtent[6]; int LoadedCellFlag; bool Loaded; }; //----------------------------------------------------------------------------- // Display the status of the current framebuffer on the standard output. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CheckFrameBufferStatus() { GLenum status; status = vtkgl::CheckFramebufferStatusEXT(vtkgl::FRAMEBUFFER_EXT); switch(status) { case 0: cout << "call to vtkgl::CheckFramebufferStatusEXT generates an error." << endl; break; case vtkgl::FRAMEBUFFER_COMPLETE_EXT: break; case vtkgl::FRAMEBUFFER_UNSUPPORTED_EXT: cout << "framebuffer is unsupported" << endl; break; case vtkgl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: cout << "framebuffer has an attachment error"<DisplayFrameBufferAttachments(); // this->DisplayReadAndDrawBuffers(); } //----------------------------------------------------------------------------- vtkStdString vtkMitkOpenGLGPUVolumeRayCastMapper::BufferToString(int buffer) { vtkStdString result; vtksys_ios::ostringstream ost; GLint size; GLint b=static_cast(buffer); switch(b) { case GL_NONE: ost << "GL_NONE"; break; case GL_FRONT_LEFT: ost << "GL_FRONT_LEFT"; break; case GL_FRONT_RIGHT: ost << "GL_FRONT_RIGHT"; break; case GL_BACK_LEFT: ost << "GL_BACK_LEFT"; break; case GL_BACK_RIGHT: ost << "GL_BACK_RIGHT"; break; case GL_FRONT: ost << "GL_FRONT"; break; case GL_BACK: ost << "GL_BACK"; break; case GL_LEFT: ost << "GL_LEFT"; break; case GL_RIGHT: ost << "GL_RIGHT"; break; case GL_FRONT_AND_BACK: ost << "GL_FRONT_AND_BACK"; break; default: glGetIntegerv(GL_AUX_BUFFERS,&size); if(buffer>=GL_AUX0 && buffer<(GL_AUX0+size)) { ost << "GL_AUX" << (buffer-GL_AUX0); } else { glGetIntegerv(vtkgl::MAX_COLOR_ATTACHMENTS_EXT,&size); if(static_cast(buffer)>=vtkgl::COLOR_ATTACHMENT0_EXT && static_cast(buffer)< (vtkgl::COLOR_ATTACHMENT0_EXT+static_cast(size))) { ost << "GL_COLOR_ATTACHMENT" << (static_cast(buffer)-vtkgl::COLOR_ATTACHMENT0_EXT) << "_EXT"; } else { ost << "unknown color buffer type=0x"<(value); vtkStdString s; GLenum i=0; while(iBufferToString(static_cast(value)); cout << "draw buffer " << i << "=" << s << endl; ++i; } glGetIntegerv(GL_READ_BUFFER,&value); s=this->BufferToString(static_cast(value)); cout << "read buffer=" << s << endl; } // ---------------------------------------------------------------------------- // Description: // Display all the attachments of the current framebuffer object. // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::DisplayFrameBufferAttachments() { GLint framebufferBinding; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&framebufferBinding); this->PrintError("after getting FRAMEBUFFER_BINDING_EXT"); if(framebufferBinding==0) { cout<<"Current framebuffer is bind to the system one"<(value); this->PrintError("after getting MAX_COLOR_ATTACHMENTS_EXT"); GLenum i=0; while(iDisplayFrameBufferAttachment(vtkgl::COLOR_ATTACHMENT0_EXT+i); ++i; } cout<<"depth attachement :"<DisplayFrameBufferAttachment(vtkgl::DEPTH_ATTACHMENT_EXT); cout<<"stencil attachement :"<DisplayFrameBufferAttachment(vtkgl::STENCIL_ATTACHMENT_EXT); } } // ---------------------------------------------------------------------------- // Description: // Display a given attachment for the current framebuffer object. //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::DisplayFrameBufferAttachment( unsigned int uattachment) { GLenum attachment=static_cast(uattachment); GLint params; vtkgl::GetFramebufferAttachmentParameterivEXT( vtkgl::FRAMEBUFFER_EXT,attachment, vtkgl::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,¶ms); this->PrintError("after getting FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT"); switch(params) { case GL_NONE: cout<<" this attachment is empty"<PrintError("after getting FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT"); cout<<" this attachment is a texture with name: "<PrintError( "after getting FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT"); cout<<" its mipmap level is: "<PrintError( "after getting FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT"); if(params==0) { cout<<" this is not a cube map texture."<PrintError( "after getting FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT"); if(params==0) { cout<<" this is not 3D texture."<PrintError("after getting FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT"); cout<<" this attachment is a renderbuffer with name: "<(params)); this->PrintError( "after getting binding the current RENDERBUFFER_EXT to params"); vtkgl::GetRenderbufferParameterivEXT(vtkgl::RENDERBUFFER_EXT, vtkgl::RENDERBUFFER_WIDTH_EXT, ¶ms); this->PrintError("after getting RENDERBUFFER_WIDTH_EXT"); cout<<" renderbuffer width="<PrintError("after getting RENDERBUFFER_HEIGHT_EXT"); cout<<" renderbuffer height="<PrintError("after getting RENDERBUFFER_INTERNAL_FORMAT_EXT"); cout<<" renderbuffer internal format=0x"<< hex<PrintError("after getting RENDERBUFFER_RED_SIZE_EXT"); cout<<" renderbuffer actual resolution for the red component="<PrintError("after getting RENDERBUFFER_GREEN_SIZE_EXT"); cout<<" renderbuffer actual resolution for the green component="<PrintError("after getting RENDERBUFFER_BLUE_SIZE_EXT"); cout<<" renderbuffer actual resolution for the blue component="<PrintError("after getting RENDERBUFFER_ALPHA_SIZE_EXT"); cout<<" renderbuffer actual resolution for the alpha component="<PrintError("after getting RENDERBUFFER_DEPTH_SIZE_EXT"); cout<<" renderbuffer actual resolution for the depth component="<PrintError("after getting RENDERBUFFER_STENCIL_SIZE_EXT"); cout<<" renderbuffer actual resolution for the stencil component=" <(errorCode)) { case GL_NO_ERROR: result="No error"; break; case GL_INVALID_ENUM: result="Invalid enum"; break; case GL_INVALID_VALUE: result="Invalid value"; break; case GL_INVALID_OPERATION: result="Invalid operation"; break; case GL_STACK_OVERFLOW: result="stack overflow"; break; case GL_STACK_UNDERFLOW: result="stack underflow"; break; case GL_OUT_OF_MEMORY: result="out of memory"; break; case vtkgl::TABLE_TOO_LARGE: // GL_ARB_imaging result="Table too large"; break; case vtkgl::INVALID_FRAMEBUFFER_OPERATION_EXT: // GL_EXT_framebuffer_object, 310 result="invalid framebuffer operation ext"; break; case vtkgl::TEXTURE_TOO_LARGE_EXT: // GL_EXT_texture result="Texture too large"; break; default: result="unknown error"; } assert("post: result_exists" && result!=0); return result; } //----------------------------------------------------------------------------- // Display headerMessage on the standard output and the last OpenGL error // message if any. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError(const char *headerMessage) { GLenum errorCode=glGetError(); if(errorCode!=GL_NO_ERROR) { if ( headerMessage ) { cout<(errorCode)); cout<UnsupportedRequiredExtensions=0; this->OpenGLObjectsCreated=0; this->LoadExtensionsSucceeded=0; this->NumberOfFrameBuffers=0; this->m_BindMax = false; // up to 2 frame buffer 2D textures (left/right) // 1 dataset 3D texture // 1 colormap 1D texture // 1 opacitymap 1d texture // 1 grabbed depth buffer 2d texture int i=0; while(iTextureObjects[i]=0; ++i; } this->DepthRenderBufferObject=0; this->FrameBufferObject=0; for ( int j = 0; j < 8; j++ ) { for (i = 0; i < 3; i++ ) { this->BoundingBox[j][i] = 0.0; } } this->LastSize[0]=0; this->LastSize[1]=0; this->ReductionFactor = 1.0; this->Supports_GL_ARB_texture_float=0; this->SupportsPixelBufferObjects=0; i=0; while(i<3) { this->TempMatrix[i]=vtkMatrix4x4::New(); ++i; } this->ErrorLine=0; this->ErrorColumn=0; this->ErrorString=0; this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; this->ClippedBoundingBox = NULL; this->SmallInput = NULL; this->MaxValueFrameBuffer=0; this->MaxValueFrameBuffer2=0; this->ReducedSize[0]=0; this->ReducedSize[1]=0; this->NumberOfCroppingRegions=0; this->PolyDataBoundingBox=0; this->Planes=0; this->NearPlane=0; this->Clip=0; this->Densify=0; this->InvVolumeMatrix=vtkMatrix4x4::New(); this->ScaleBiasProgramShader=0; this->UFrameBufferTexture=-1; this->UScale=-1; this->UBias=-1; this->SavedFrameBuffer=0; this->BoxSource=0; this->NoiseTexture=0; this->NoiseTextureSize=0; this->NoiseTextureId=0; this->IgnoreSampleDistancePerPixel=true; this->ScalarsTextures=new vtkMapDataArrayTextureId; this->MaskTextures=new vtkMapMaskTextureId; this->RGBTable=0; this->Mask1RGBTable=0; this->Mask2RGBTable=0; this->OpacityTables=0; this->CurrentScalar=0; this->CurrentMask=0; this->ActualSampleDistance=1.0; this->LastProgressEventTime=0.0; // date in seconds this->PreserveOrientation=true; } //----------------------------------------------------------------------------- // Destruct a vtkMitkOpenGLGPUVolumeRayCastMapper - clean up any memory used //----------------------------------------------------------------------------- vtkMitkOpenGLGPUVolumeRayCastMapper::~vtkMitkOpenGLGPUVolumeRayCastMapper() { if(this->UnsupportedRequiredExtensions!=0) { delete this->UnsupportedRequiredExtensions; this->UnsupportedRequiredExtensions=0; } int i=0; while(i<3) { this->TempMatrix[i]->Delete(); this->TempMatrix[i]=0; ++i; } if(this->ErrorString!=0) { delete[] this->ErrorString; this->ErrorString=0; } if ( this->SmallInput ) { this->SmallInput->UnRegister(this); } if(this->PolyDataBoundingBox!=0) { this->PolyDataBoundingBox->UnRegister(this); this->PolyDataBoundingBox=0; } if(this->Planes!=0) { this->Planes->UnRegister(this); this->Planes=0; } if(this->NearPlane!=0) { this->NearPlane->UnRegister(this); this->NearPlane=0; } if(this->Clip!=0) { this->Clip->UnRegister(this); this->Clip=0; } if(this->Densify!=0) { this->Densify->UnRegister(this); this->Densify=0; } if(this->BoxSource!=0) { this->BoxSource->UnRegister(this); this->BoxSource=0; } this->InvVolumeMatrix->UnRegister(this); this->InvVolumeMatrix=0; if(this->NoiseTexture!=0) { delete[] this->NoiseTexture; this->NoiseTexture=0; this->NoiseTextureSize=0; } if(this->ScalarsTextures!=0) { delete this->ScalarsTextures; this->ScalarsTextures=0; } if(this->MaskTextures!=0) { delete this->MaskTextures; this->MaskTextures=0; } } //----------------------------------------------------------------------------- // Based on hardware and properties, we may or may not be able to // render using 3D texture mapping. This indicates if 3D texture // mapping is supported by the hardware, and if the other extensions // necessary to support the specific properties are available. // //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::IsRenderSupported( vtkRenderWindow *window, vtkVolumeProperty *vtkNotUsed(property)) { window->MakeCurrent(); if(!this->LoadExtensionsSucceeded) { this->LoadExtensions(window); } if(!this->LoadExtensionsSucceeded) { vtkDebugMacro( "The following OpenGL extensions are required but not supported: " << (this->UnsupportedRequiredExtensions->Stream.str()).c_str()); return 0; } return 1; } //----------------------------------------------------------------------------- // Return if the required OpenGL extension `extensionName' is supported. // If not, its name is added to the string of unsupported but required // extensions. // \pre extensions_exist: extensions!=0 // \pre extensionName_exists: extensionName!=0 //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::TestRequiredExtension( vtkOpenGLExtensionManager *extensions, const char *extensionName) { assert("pre: extensions_exist" && extensions!=0); assert("pre: extensionName_exists" && extensionName!=0); int result=extensions->ExtensionSupported(extensionName); if(!result) { if(this->LoadExtensionsSucceeded) { this->UnsupportedRequiredExtensions->Stream<LoadExtensionsSucceeded=0; } else { this->UnsupportedRequiredExtensions->Stream<<", "<LoadExtensionsSucceeded will be set to 0 or 1 // - this->UnsupportedRequiredExtensions will have a message indicating // any failure codes //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::LoadExtensions( vtkRenderWindow *window) { // We may already have a string stream for the unsupported extensions // from the last time this method was called. If so, delete it. if(this->UnsupportedRequiredExtensions!=0) { delete this->UnsupportedRequiredExtensions; } // Create a string stream to hold the unsupported extensions so we can // report something meaningful back this->UnsupportedRequiredExtensions = new vtkUnsupportedRequiredExtensionsStringStream; // It does not work on Apple OS X Snow Leopard with nVidia. // There is a bug in the OpenGL driver with an error in the // Cg compiler about an infinite loop. #ifdef __APPLE__ this->LoadExtensionsSucceeded=0; return; #endif // Assume success this->LoadExtensionsSucceeded=1; const char *gl_vendor=reinterpret_cast(glGetString(GL_VENDOR)); /* if(strstr(gl_vendor,"ATI")!=0) { this->LoadExtensionsSucceeded=0; return; }*/ const char *gl_version=reinterpret_cast(glGetString(GL_VERSION)); if(strstr(gl_version,"Mesa")!=0) { // - GL_VENDOR cannot be used because it can be "Brian Paul" or // "Mesa project" // - GL_RENDERER cannot be used because it can be "Software Rasterizer" or // "Mesa X11" // - GL_VERSION is more robust. It has things like "2.0 Mesa 7.0.4" or // "2.1 Mesa 7.2" or "2.1 Mesa 7.3-devel" // Mesa does not work with multiple draw buffers: // "framebuffer has bad draw buffer" // "render clipped 1 ERROR (x506) invalid framebuffer operation ext" this->LoadExtensionsSucceeded=0; return; } // Create an extension manager vtkOpenGLExtensionManager *extensions=vtkOpenGLExtensionManager::New(); extensions->SetRenderWindow(window); // GL_ARB_draw_buffers requires OpenGL 1.3, so we must have OpenGL 1.3 // We don't need to check for some extensions that become part of OpenGL // core after 1.3. Among them: // - texture_3d is in core OpenGL since 1.2 // - texture_edge_clamp is in core OpenGL since 1.2 // (GL_SGIS_texture_edge_clamp or GL_EXT_texture_edge_clamp (nVidia) ) // - multitexture is in core OpenGL since 1.3 int supports_GL_1_3=extensions->ExtensionSupported("GL_VERSION_1_3"); int supports_GL_2_0=0; // No 1.3 support - give up if(!supports_GL_1_3) { this->LoadExtensionsSucceeded=0; this->UnsupportedRequiredExtensions->Stream<< " OpenGL 1.3 is required but not supported"; extensions->Delete(); return; } // Check for 2.0 support supports_GL_2_0=extensions->ExtensionSupported("GL_VERSION_2_0"); // Some extensions that are supported in 2.0, but if we don't // have 2.0 we'll need to check further int supports_shading_language_100 = 1; int supports_shader_objects = 1; int supports_fragment_shader = 1; int supports_texture_non_power_of_two = 1; int supports_draw_buffers = 1; if(!supports_GL_2_0) { supports_shading_language_100= extensions->ExtensionSupported("GL_ARB_shading_language_100"); supports_shader_objects= extensions->ExtensionSupported("GL_ARB_shader_objects"); supports_fragment_shader= extensions->ExtensionSupported("GL_ARB_fragment_shader"); supports_texture_non_power_of_two= extensions->ExtensionSupported("GL_ARB_texture_non_power_of_two"); supports_draw_buffers= extensions->ExtensionSupported("GL_ARB_draw_buffers"); } // We have to check for framebuffer objects int supports_GL_EXT_framebuffer_object= extensions->ExtensionSupported("GL_EXT_framebuffer_object" ); // Find out if we have OpenGL 1.4 support int supports_GL_1_4=extensions->ExtensionSupported("GL_VERSION_1_4"); // Find out if we have the depth texture ARB extension int supports_GL_ARB_depth_texture= extensions->ExtensionSupported("GL_ARB_depth_texture"); // Depth textures are support if we either have OpenGL 1.4 // or if the depth texture ARB extension is supported int supports_depth_texture = supports_GL_1_4 || supports_GL_ARB_depth_texture; // Now start adding messages to the UnsupportedRequiredExtensions string // Log message if shading language 100 is not supported if(!supports_shading_language_100) { this->UnsupportedRequiredExtensions->Stream<< " shading_language_100 (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } else { // We can query the GLSL version, we need >=1.20 const char *glsl_version= reinterpret_cast(glGetString(vtkgl::SHADING_LANGUAGE_VERSION)); int glslMajor, glslMinor; vtksys_ios::istringstream ist(glsl_version); ist >> glslMajor; char c; ist.get(c); // '.' ist >> glslMinor; //sscanf(version, "%d.%d", &glslMajor, &glslMinor); if(glslMajor<1 || (glslMajor==1 && glslMinor<20)) { this->LoadExtensionsSucceeded=0; } } // Log message if shader objects are not supported if(!supports_shader_objects) { this->UnsupportedRequiredExtensions->Stream<< " shader_objects (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if fragment shaders are not supported if(!supports_fragment_shader) { this->UnsupportedRequiredExtensions->Stream<< " fragment_shader (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if non power of two textures are not supported if(!supports_texture_non_power_of_two) { this->UnsupportedRequiredExtensions->Stream<< " texture_non_power_of_two (or OpenGL 2.0) is required but not " << "supported"; this->LoadExtensionsSucceeded=0; } // Log message if draw buffers are not supported if(!supports_draw_buffers) { this->UnsupportedRequiredExtensions->Stream<< " draw_buffers (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if depth textures are not supported if(!supports_depth_texture) { this->UnsupportedRequiredExtensions->Stream<< " depth_texture (or OpenGL 1.4) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if framebuffer objects are not supported if(!supports_GL_EXT_framebuffer_object) { this->UnsupportedRequiredExtensions->Stream<< " framebuffer_object is required but not supported"; this->LoadExtensionsSucceeded=0; } // Have we succeeded so far? If not, just return. if(!this->LoadExtensionsSucceeded) { extensions->Delete(); return; } // Now start loading the extensions // First load all 1.2 and 1.3 extensions (we know we // support at least up to 1.3) extensions->LoadExtension("GL_VERSION_1_2"); extensions->LoadExtension("GL_VERSION_1_3"); // Load the 2.0 extensions if supported if(supports_GL_2_0) { extensions->LoadExtension("GL_VERSION_2_0"); } // Otherwise, we'll need to specifically load the // shader objects, fragment shader, and draw buffers // extensions else { extensions->LoadCorePromotedExtension("GL_ARB_shader_objects"); extensions->LoadCorePromotedExtension("GL_ARB_fragment_shader"); extensions->LoadCorePromotedExtension("GL_ARB_draw_buffers"); } // Load the framebuffer object extension extensions->LoadExtension("GL_EXT_framebuffer_object"); // Optional extension (does not fail if not present) // Load it if supported which will allow us to store // textures as floats this->Supports_GL_ARB_texture_float= extensions->ExtensionSupported("GL_ARB_texture_float" ); if(this->Supports_GL_ARB_texture_float) { extensions->LoadExtension( "GL_ARB_texture_float" ); } // Optional extension (does not fail if not present) // Used to minimize memory footprint when loading large 3D textures // of scalars. // VBO or 1.5 is required by PBO or 2.1 int supports_GL_1_5=extensions->ExtensionSupported("GL_VERSION_1_5"); int supports_vertex_buffer_object=supports_GL_1_5 || extensions->ExtensionSupported("GL_ARB_vertex_buffer_object"); int supports_GL_2_1=extensions->ExtensionSupported("GL_VERSION_2_1"); this->SupportsPixelBufferObjects=supports_vertex_buffer_object && (supports_GL_2_1 || extensions->ExtensionSupported("GL_ARB_pixel_buffer_object")); if(this->SupportsPixelBufferObjects) { if(supports_GL_1_5) { extensions->LoadExtension("GL_VERSION_1_5"); } else { extensions->LoadCorePromotedExtension("GL_ARB_vertex_buffer_object"); } if(supports_GL_2_1) { extensions->LoadExtension("GL_VERSION_2_1"); } else { extensions->LoadCorePromotedExtension("GL_ARB_pixel_buffer_object"); } } // Ultimate test. Some old cards support OpenGL 2.0 but not while // statements in a fragment shader (example: nVidia GeForce FX 5200) // It does not fail when compiling each shader source but at linking // stage because the parser underneath only check for syntax during // compilation and the actual native code generation happens during // the linking stage. this->CreateGLSLObjects(); this->NumberOfCroppingRegions=1; this->BuildProgram(1,vtkMitkOpenGLGPUVolumeRayCastMapperMethodComposite, vtkMitkOpenGLGPUVolumeRayCastMapperShadeNo, vtkMitkOpenGLGPUVolumeRayCastMapperComponentOne); GLint params; vtkgl::GetProgramiv(static_cast(this->ProgramShader), vtkgl::LINK_STATUS,¶ms); if(params==GL_FALSE) { this->LoadExtensionsSucceeded=0; this->UnsupportedRequiredExtensions->Stream<< " this card does not support while statements in fragment shaders."; } // FB debug this->CheckLinkage(this->ProgramShader); // Release GLSL Objects. GLuint programShader=static_cast(this->ProgramShader); vtkgl::DeleteProgram(programShader); this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; extensions->Delete(); } //----------------------------------------------------------------------------- // Create GLSL OpenGL objects such fragment program Ids. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CreateGLSLObjects() { GLuint programShader; GLuint fragmentMainShader; programShader=vtkgl::CreateProgram(); fragmentMainShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentMainShader); vtkgl::DeleteShader(fragmentMainShader); // reference counting vtkgl::ShaderSource( fragmentMainShader,1, const_cast(&vtkMitkGPUVolumeRayCastMapper_HeaderFS),0); vtkgl::CompileShader(fragmentMainShader); this->CheckCompilation(static_cast(fragmentMainShader)); GLuint fragmentProjectionShader; GLuint fragmentTraceShader; GLuint fragmentCroppingShader; GLuint fragmentComponentShader; GLuint fragmentShadeShader; fragmentProjectionShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentProjectionShader); vtkgl::DeleteShader(fragmentProjectionShader); // reference counting fragmentTraceShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentTraceShader); vtkgl::DeleteShader(fragmentTraceShader); // reference counting fragmentCroppingShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentCroppingShader); vtkgl::DeleteShader(fragmentCroppingShader); // reference counting fragmentComponentShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); // don't delete it, it is optionally attached. fragmentShadeShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); // Save GL objects by static casting to standard C types. GL* types // are not allowed in VTK header files. this->ProgramShader=static_cast(programShader); this->FragmentMainShader=static_cast(fragmentMainShader); this->FragmentProjectionShader= static_cast(fragmentProjectionShader); this->FragmentTraceShader=static_cast(fragmentTraceShader); this->FragmentCroppingShader= static_cast(fragmentCroppingShader); this->FragmentComponentShader= static_cast(fragmentComponentShader); this->FragmentShadeShader= static_cast(fragmentShadeShader); } void vtkMitkOpenGLGPUVolumeRayCastMapper::BindFramebuffer() { vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront], 0); GLenum err = glGetError(); if(m_BindMax) { vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D,this->MaxValueFrameBuffer,0); } } //----------------------------------------------------------------------------- // Create OpenGL objects such as textures, buffers and fragment program Ids. // It only registers Ids, there is no actual initialization of textures or // fragment program. // // Pre-conditions: // This method assumes that this->LoadedExtensionsSucceeded is 1. // // Post-conditions: // When this method completes successfully, this->OpenGLObjectsCreated // will be 1. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CreateOpenGLObjects() { // Do nothing if the OpenGL objects have already been created if ( this->OpenGLObjectsCreated ) { return; } // We need only two color buffers (ping-pong) this->NumberOfFrameBuffers=2; // TODO: clean this up! // 2*Frame buffers(2d textures)+colorMap (1d texture) +dataset (3d texture) // + opacitymap (1d texture) + grabbed depthMap (2d texture) // Frame buffers(2d textures)+colorMap (1d texture) +dataset (3d texture) // + opacity (1d texture)+grabbed depth buffer (2d texture) GLuint frameBufferObject; GLuint depthRenderBufferObject; GLuint textureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects]; // Create the various objects we will need - one frame buffer // which will contain a render buffer for depth and a texture // for color. vtkgl::GenFramebuffersEXT(1, &frameBufferObject); // color vtkgl::GenRenderbuffersEXT(1, &depthRenderBufferObject); // depth glGenTextures(vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects,textureObjects); // Color buffers GLint value; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&value); GLuint savedFrameBuffer=static_cast(value); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT,frameBufferObject); // Depth buffer vtkgl::BindRenderbufferEXT(vtkgl::RENDERBUFFER_EXT, depthRenderBufferObject); vtkgl::FramebufferRenderbufferEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::DEPTH_ATTACHMENT_EXT, vtkgl::RENDERBUFFER_EXT, depthRenderBufferObject); // Restore default frame buffer. vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT,savedFrameBuffer); this->CreateGLSLObjects(); // Save GL objects by static casting to standard C types. GL* types // are not allowed in VTK header files. this->FrameBufferObject=static_cast(frameBufferObject); this->DepthRenderBufferObject=static_cast(depthRenderBufferObject); int i=0; while(iTextureObjects[i]=static_cast(textureObjects[i]); ++i; } this->OpenGLObjectsCreated=1; } //----------------------------------------------------------------------------- // Check the compilation status of some fragment shader source. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CheckCompilation( unsigned int fragmentShader) { GLuint fs=static_cast(fragmentShader); GLint params; vtkgl::GetShaderiv(fs,vtkgl::COMPILE_STATUS,¶ms); if(params==GL_TRUE) { vtkDebugMacro(<<"shader source compiled successfully"); } else { vtkErrorMacro(<<"shader source compile error"); // include null terminator vtkgl::GetShaderiv(fs,vtkgl::INFO_LOG_LENGTH,¶ms); if(params>0) { char *buffer=new char[params]; vtkgl::GetShaderInfoLog(fs,params,0,buffer); vtkErrorMacro(<<"log: "<(programShader); // info about the list of active uniform variables vtkgl::GetProgramiv(prog,vtkgl::ACTIVE_UNIFORMS,¶ms); cout<<"There are "<(params); vtkgl::GetProgramiv(prog,vtkgl::OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, ¶ms); GLint buffSize=params; char *name=new char[buffSize+1]; GLint size; GLenum type; while(i(programShader); vtkgl::GetProgramiv(prog,vtkgl::LINK_STATUS,¶ms); int status = 0; if(params==GL_TRUE) { status = 1; vtkDebugMacro(<<"program linked successfully"); } else { vtkErrorMacro(<<"program link error"); vtkgl::GetProgramiv(prog,vtkgl::INFO_LOG_LENGTH,¶ms); if(params>0) { char *buffer=new char[params]; vtkgl::GetProgramInfoLog(prog,params,0,buffer); vtkErrorMacro(<<"log: "<OpenGLObjectsCreated==0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources( vtkWindow *window) { if(this->OpenGLObjectsCreated) { window->MakeCurrent(); this->LastSize[0]=0; this->LastSize[1]=0; GLuint frameBufferObject=static_cast(this->FrameBufferObject); vtkgl::DeleteFramebuffersEXT(1,&frameBufferObject); GLuint depthRenderBufferObject= static_cast(this->DepthRenderBufferObject); vtkgl::DeleteRenderbuffersEXT(1,&depthRenderBufferObject); GLuint textureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects]; int i=0; while(i<(vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+this->NumberOfFrameBuffers)) { textureObjects[i]=static_cast(this->TextureObjects[i]); ++i; } glDeleteTextures(vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+this->NumberOfFrameBuffers,textureObjects); if(this->MaxValueFrameBuffer!=0) { GLuint maxValueFrameBuffer= static_cast(this->MaxValueFrameBuffer); glDeleteTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer=0; } if(this->MaxValueFrameBuffer2!=0) { GLuint maxValueFrameBuffer2= static_cast(this->MaxValueFrameBuffer2); glDeleteTextures(1,&maxValueFrameBuffer2); this->MaxValueFrameBuffer2=0; } GLuint programShader=static_cast(this->ProgramShader); vtkgl::DeleteProgram(programShader); this->ProgramShader=0; GLuint fragmentComponentShader= static_cast(this->FragmentComponentShader); vtkgl::DeleteShader(fragmentComponentShader); GLuint fragmentShadeShader= static_cast(this->FragmentShadeShader); vtkgl::DeleteShader(fragmentShadeShader); GLuint scaleBiasProgramShader= static_cast(this->ScaleBiasProgramShader); if(scaleBiasProgramShader!=0) { vtkgl::DeleteProgram(scaleBiasProgramShader); this->ScaleBiasProgramShader=0; } this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; this->OpenGLObjectsCreated=0; } if(this->NoiseTextureId!=0) { window->MakeCurrent(); GLuint noiseTextureObjects=static_cast(this->NoiseTextureId); glDeleteTextures(1,&noiseTextureObjects); this->NoiseTextureId=0; } if(this->ScalarsTextures!=0) { if(!this->ScalarsTextures->Map.empty()) { vtkstd::map::iterator it=this->ScalarsTextures->Map.begin(); while(it!=this->ScalarsTextures->Map.end()) { vtkKWScalarField *texture=(*it).second; delete texture; ++it; } this->ScalarsTextures->Map.clear(); } } if(this->MaskTextures!=0) { if(!this->MaskTextures->Map.empty()) { vtkstd::map::iterator it=this->MaskTextures->Map.begin(); while(it!=this->MaskTextures->Map.end()) { vtkKWMask *texture=(*it).second; delete texture; ++it; } this->MaskTextures->Map.clear(); } } if(this->RGBTable!=0) { delete this->RGBTable; this->RGBTable=0; } if(this->Mask1RGBTable!=0) { delete this->Mask1RGBTable; this->Mask1RGBTable=0; } if(this->Mask2RGBTable!=0) { delete this->Mask2RGBTable; this->Mask2RGBTable=0; } if(this->OpacityTables!=0) { delete this->OpacityTables; this->OpacityTables=0; } } //----------------------------------------------------------------------------- // Delete OpenGL objects. // \post done: this->OpenGLObjectsCreated==0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources( mitk::BaseRenderer * renderer) { if(this->OpenGLObjectsCreated) { vtkWindow * window = renderer->GetVtkRenderer()->GetRenderWindow(); window->MakeCurrent(); this->LastSize[0]=0; this->LastSize[1]=0; GLuint frameBufferObject=static_cast(this->FrameBufferObject); vtkgl::DeleteFramebuffersEXT(1,&frameBufferObject); GLuint depthRenderBufferObject= static_cast(this->DepthRenderBufferObject); vtkgl::DeleteRenderbuffersEXT(1,&depthRenderBufferObject); GLuint textureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects]; int i=0; while(i<(vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+this->NumberOfFrameBuffers)) { textureObjects[i]=static_cast(this->TextureObjects[i]); ++i; } glDeleteTextures(vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+this->NumberOfFrameBuffers,textureObjects); if(this->MaxValueFrameBuffer!=0) { GLuint maxValueFrameBuffer= static_cast(this->MaxValueFrameBuffer); glDeleteTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer=0; } if(this->MaxValueFrameBuffer2!=0) { GLuint maxValueFrameBuffer2= static_cast(this->MaxValueFrameBuffer2); glDeleteTextures(1,&maxValueFrameBuffer2); this->MaxValueFrameBuffer2=0; } GLuint programShader=static_cast(this->ProgramShader); vtkgl::DeleteProgram(programShader); this->ProgramShader=0; GLuint fragmentComponentShader= static_cast(this->FragmentComponentShader); vtkgl::DeleteShader(fragmentComponentShader); GLuint fragmentShadeShader= static_cast(this->FragmentShadeShader); vtkgl::DeleteShader(fragmentShadeShader); GLuint scaleBiasProgramShader= static_cast(this->ScaleBiasProgramShader); if(scaleBiasProgramShader!=0) { vtkgl::DeleteProgram(scaleBiasProgramShader); this->ScaleBiasProgramShader=0; } this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; this->OpenGLObjectsCreated=0; } if(this->NoiseTextureId!=0) { window->MakeCurrent(); GLuint noiseTextureObjects=static_cast(this->NoiseTextureId); glDeleteTextures(1,&noiseTextureObjects); this->NoiseTextureId=0; } if(this->ScalarsTextures!=0) { if(!this->ScalarsTextures->Map.empty()) { vtkstd::map::iterator it=this->ScalarsTextures->Map.begin(); while(it!=this->ScalarsTextures->Map.end()) { vtkKWScalarField *texture=(*it).second; delete texture; ++it; } this->ScalarsTextures->Map.clear(); } } if(this->MaskTextures!=0) { if(!this->MaskTextures->Map.empty()) { vtkstd::map::iterator it=this->MaskTextures->Map.begin(); while(it!=this->MaskTextures->Map.end()) { vtkKWMask *texture=(*it).second; delete texture; ++it; } this->MaskTextures->Map.clear(); } } if(this->RGBTable!=0) { delete this->RGBTable; this->RGBTable=0; } if(this->Mask1RGBTable!=0) { delete this->Mask1RGBTable; this->Mask1RGBTable=0; } if(this->Mask2RGBTable!=0) { delete this->Mask2RGBTable; this->Mask2RGBTable=0; } if(this->OpacityTables!=0) { delete this->OpacityTables; this->OpacityTables=0; } } //----------------------------------------------------------------------------- // Allocate memory on the GPU for the framebuffers according to the size of // the window or reallocate if the size has changed. Return true if // allocation succeeded. // \pre ren_exists: ren!=0 // \pre opengl_objects_created: this->OpenGLObjectsCreated // \post right_size: LastSize[]=window size. //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::AllocateFrameBuffers(vtkRenderer *ren) { assert("pre: ren_exists" && ren!=0); assert("pre: opengl_objects_created" && this->OpenGLObjectsCreated); int result=1; int size[2]; ren->GetTiledSize(&size[0],&size[1]); int sizeChanged=this->LastSize[0]!=size[0] || this->LastSize[1]!=size[1]; GLenum errorCode=glGetError(); // Need allocation? if(sizeChanged) { int i=0; GLenum errorCode=glGetError(); while(i NumberOfFrameBuffers && errorCode==GL_NO_ERROR) { glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+i])); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Here we are assuming that GL_ARB_texture_non_power_of_two is available if(this->Supports_GL_ARB_texture_float) { glTexImage2D(GL_TEXTURE_2D,0,vtkgl::RGBA16F_ARB,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } else { glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } errorCode=glGetError(); ++i; } if(errorCode==GL_NO_ERROR) { // grabbed depth buffer glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap])); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri(GL_TEXTURE_2D, vtkgl::DEPTH_TEXTURE_MODE, GL_LUMINANCE); glTexImage2D(GL_TEXTURE_2D, 0, vtkgl::DEPTH_COMPONENT32, size[0],size[1], 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); // Set up the depth render buffer GLint savedFrameBuffer; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&savedFrameBuffer); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->FrameBufferObject)); this->BindFramebuffer(); vtkgl::BindRenderbufferEXT( vtkgl::RENDERBUFFER_EXT, static_cast(this->DepthRenderBufferObject)); vtkgl::RenderbufferStorageEXT(vtkgl::RENDERBUFFER_EXT, vtkgl::DEPTH_COMPONENT24,size[0],size[1]); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(savedFrameBuffer)); errorCode=glGetError(); if(errorCode==GL_NO_ERROR) { this->LastSize[0]=size[0]; this->LastSize[1]=size[1]; } } result=errorCode==GL_NO_ERROR; } int needNewMaxValueBuffer=this->MaxValueFrameBuffer==0 && (this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND); if(needNewMaxValueBuffer) { // blend mode changed and need max value buffer. // create and bind second color buffer (we use only the red component // to store the max scalar). We cant use a one component color buffer // because all color buffer have to have the same format. // max scalar frame buffer GLuint maxValueFrameBuffer; glGenTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer= static_cast(maxValueFrameBuffer); // Color buffers this->m_BindMax = true; // max scalar frame buffer2 GLuint maxValueFrameBuffer2; glGenTextures(1,&maxValueFrameBuffer2); glBindTexture(GL_TEXTURE_2D,maxValueFrameBuffer2); this->MaxValueFrameBuffer2= static_cast(maxValueFrameBuffer2); } else { if(this->MaxValueFrameBuffer!=0 && (this->BlendMode!=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND && this->BlendMode!=vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND)) { // blend mode changed and does not need max value buffer anymore. GLint savedFrameBuffer; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&savedFrameBuffer); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->FrameBufferObject)); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D,0,0); // not scalar buffer vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(savedFrameBuffer)); GLuint maxValueFrameBuffer= static_cast(this->MaxValueFrameBuffer); glDeleteTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer=0; m_BindMax = false; GLuint maxValueFrameBuffer2= static_cast(this->MaxValueFrameBuffer2); glDeleteTextures(1,&maxValueFrameBuffer2); this->MaxValueFrameBuffer2=0; } } if((this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) && (sizeChanged || needNewMaxValueBuffer)) { // max scalar frame buffer GLuint maxValueFrameBuffer=static_cast(this->MaxValueFrameBuffer); glBindTexture(GL_TEXTURE_2D,maxValueFrameBuffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Here we are assuming that GL_ARB_texture_non_power_of_two is available if(this->Supports_GL_ARB_texture_float) { glTexImage2D(GL_TEXTURE_2D,0,vtkgl::RGBA16F_ARB,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } else { glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } // max scalar frame buffer 2 GLuint maxValueFrameBuffer2=static_cast(this->MaxValueFrameBuffer2); glBindTexture(GL_TEXTURE_2D,maxValueFrameBuffer2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Here we are assuming that GL_ARB_texture_non_power_of_two is available if(this->Supports_GL_ARB_texture_float) { glTexImage2D(GL_TEXTURE_2D,0,vtkgl::RGBA16F_ARB,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } else { glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } } PrintError("AllocateFrameBuffers"); return result; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::GetTextureFormat( vtkImageData *input, unsigned int *internalFormat, unsigned int *format, unsigned int *type, int *componentSize) { *internalFormat=0; *format=0; *type=0; *componentSize=0; vtkDataArray *scalars=this->GetScalars(input,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, this->CellFlag); int scalarType=scalars->GetDataType(); int components=scalars->GetNumberOfComponents(); *componentSize=vtkAbstractArray::GetDataTypeSize(scalarType)*components; if(components==4) { // this is RGBA, unsigned char only *internalFormat=GL_RGBA16; *format=GL_RGBA; *type=GL_UNSIGNED_BYTE; } else { // components==1 switch(scalarType) { case VTK_FLOAT: if(this->Supports_GL_ARB_texture_float) { *internalFormat=vtkgl::INTENSITY16F_ARB; } else { *internalFormat=GL_INTENSITY16; } *format=GL_RED; *type=GL_FLOAT; break; case VTK_UNSIGNED_CHAR: *internalFormat=GL_INTENSITY8; *format=GL_RED; *type=GL_UNSIGNED_BYTE; break; case VTK_SIGNED_CHAR: *internalFormat=GL_INTENSITY8; *format=GL_RED; *type=GL_BYTE; break; case VTK_CHAR: // not supported assert("check: impossible case" && 0); break; case VTK_BIT: // not supported assert("check: impossible case" && 0); break; case VTK_ID_TYPE: // not supported assert("check: impossible case" && 0); break; case VTK_INT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_INT; break; case VTK_DOUBLE: case VTK___INT64: case VTK_LONG: case VTK_LONG_LONG: case VTK_UNSIGNED___INT64: case VTK_UNSIGNED_LONG: case VTK_UNSIGNED_LONG_LONG: if(this->Supports_GL_ARB_texture_float) { *internalFormat=vtkgl::INTENSITY16F_ARB; } else { *internalFormat=GL_INTENSITY16; } *format=GL_RED; *type=GL_FLOAT; break; case VTK_SHORT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_SHORT; break; case VTK_STRING: // not supported assert("check: impossible case" && 0); break; case VTK_UNSIGNED_SHORT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_UNSIGNED_SHORT; break; case VTK_UNSIGNED_INT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_UNSIGNED_INT; break; default: assert("check: impossible case" && 0); break; } } } //----------------------------------------------------------------------------- // Assuming the textureSize[3] is less of equal to the maximum size of an // OpenGL 3D texture, try to see if the texture can fit on the card. //----------------------------------------------------------------------------- bool vtkMitkOpenGLGPUVolumeRayCastMapper::TestLoadingScalar( unsigned int internalFormat, unsigned int format, unsigned int type, int textureSize[3], int componentSize) { // componentSize=vtkAbstractArray::GetDataTypeSize(scalarType)*input->GetNumberOfScalarComponents() bool result; vtkgl::TexImage3D(vtkgl::PROXY_TEXTURE_3D,0, static_cast(internalFormat), textureSize[0],textureSize[1],textureSize[2],0, format, type,0); GLint width; glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_3D,0,GL_TEXTURE_WIDTH, &width); result=width!=0; if(result) { // so far, so good but some cards always succeed with a proxy texture // let's try to actually allocate.. vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,static_cast(internalFormat), textureSize[0], textureSize[1],textureSize[2],0, format, type,0); GLenum errorCode=glGetError(); result=errorCode!=GL_OUT_OF_MEMORY; if(result) { if(errorCode!=GL_NO_ERROR) { cout<<"after try to load the texture"; cout<<" ERROR (x"<(errorCode)); cout<(this->MaxMemoryInBytes)*this->MaxMemoryFraction; } } return result; } //----------------------------------------------------------------------------- // Load the scalar field (one or four component scalar field), cell or point // based for a given subextent of the whole extent (can be the whole extent) // as a 3D texture on the GPU. // Extents are expressed in point if the cell flag is false or in cells of // the cell flag is true. // It returns true if it succeeded, false if there is not enough memory on // the GPU. // If succeeded, it updates the LoadedExtent, LoadedBounds, LoadedCellFlag // and LoadedTime. It also succeed if the scalar field is already loaded // (ie since last load, input has not changed and cell flag has not changed // and requested texture extents are enclosed in the loaded extent). // \pre input_exists: input!=0 // \pre valid_point_extent: (this->CellFlag || // (textureExtent[0]CellFlag || // (textureExtent[0]<=textureExtent[1] && // textureExtent[2]<=textureExtent[3] && // textureExtent[4]<=textureExtent[5]))) //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::LoadScalarField(vtkImageData *input, vtkImageData *maskInput, int textureExtent[6], vtkVolume *volume) { assert("pre: input_exists" && input!=0); assert("pre: valid_point_extent" && (this->CellFlag || (textureExtent[0]CellFlag || (textureExtent[0]<=textureExtent[1] && textureExtent[2]<=textureExtent[3] && textureExtent[4]<=textureExtent[5]))); int result=1; // succeeded // make sure we rebind our texture object to texture0 even if we don't have // to load the data themselves because the binding might be changed by // another mapper between two rendering calls. vtkgl::ActiveTexture(vtkgl::TEXTURE0); // Find the texture. vtkstd::map::iterator it= this->ScalarsTextures->Map.find(input); vtkKWScalarField *texture; if(it==this->ScalarsTextures->Map.end()) { texture=new vtkKWScalarField; this->ScalarsTextures->Map[input]=texture; texture->SetSupports_GL_ARB_texture_float(this->Supports_GL_ARB_texture_float==1); } else { texture=(*it).second; } texture->Update(input,this->CellFlag,textureExtent,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, volume->GetProperty()->GetInterpolationType() ==VTK_LINEAR_INTERPOLATION, this->TableRange, static_cast(static_cast(this->MaxMemoryInBytes)*this->MaxMemoryFraction)); result=texture->IsLoaded(); this->CurrentScalar=texture; // Mask if(maskInput!=0) { vtkgl::ActiveTexture(vtkgl::TEXTURE7); // Find the texture. vtkstd::map::iterator it2= this->MaskTextures->Map.find(maskInput); vtkKWMask *mask; if(it2==this->MaskTextures->Map.end()) { mask=new vtkKWMask; this->MaskTextures->Map[maskInput]=mask; } else { mask=(*it2).second; } mask->Update(maskInput,this->CellFlag,textureExtent,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, static_cast(static_cast(this->MaxMemoryInBytes)*this->MaxMemoryFraction)); result=result && mask->IsLoaded(); this->CurrentMask=mask; vtkgl::ActiveTexture(vtkgl::TEXTURE0); } return result; } //----------------------------------------------------------------------------- // Allocate memory and load color table on the GPU or // reload it if the transfer function changed. // \pre vol_exists: vol!=0 // \pre valid_numberOfScalarComponents: numberOfScalarComponents==1 || numberOfScalarComponents==4 //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::UpdateColorTransferFunction( vtkVolume *vol, int numberOfScalarComponents) { assert("pre: vol_exists" && vol!=0); assert("pre: valid_numberOfScalarComponents" && (numberOfScalarComponents==1 || numberOfScalarComponents==4)); // Build the colormap in a 1D texture. // 1D RGB-texture=mapping from scalar values to color values // build the table if(numberOfScalarComponents==1) { vtkVolumeProperty *volumeProperty=vol->GetProperty(); vtkColorTransferFunction *colorTransferFunction=volumeProperty->GetRGBTransferFunction(0); vtkgl::ActiveTexture(vtkgl::TEXTURE1); this->RGBTable->Update( colorTransferFunction,this->TableRange, volumeProperty->GetInterpolationType()==VTK_LINEAR_INTERPOLATION); // Restore default vtkgl::ActiveTexture( vtkgl::TEXTURE0); } if(this->MaskInput!=0) { vtkVolumeProperty *volumeProperty=vol->GetProperty(); vtkColorTransferFunction *c=volumeProperty->GetRGBTransferFunction(1); vtkgl::ActiveTexture(vtkgl::TEXTURE8); this->Mask1RGBTable->Update(c,this->TableRange,false); c=volumeProperty->GetRGBTransferFunction(2); vtkgl::ActiveTexture(vtkgl::TEXTURE9); this->Mask2RGBTable->Update(c,this->TableRange,false); // Restore default vtkgl::ActiveTexture( vtkgl::TEXTURE0); } return 1; } //----------------------------------------------------------------------------- // Allocate memory and load opacity table on the GPU or // reload it if the transfert function changed. // \pre vol_exists: vol!=0 // \pre valid_numberOfScalarComponents: numberOfScalarComponents==1 || numberOfScalarComponents==4 //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::UpdateOpacityTransferFunction( vtkVolume *vol, int numberOfScalarComponents, unsigned int level) { assert("pre: vol_exists" && vol!=0); assert("pre: valid_numberOfScalarComponents" && (numberOfScalarComponents==1 || numberOfScalarComponents==4)); (void)numberOfScalarComponents; // remove warning in release mode. vtkVolumeProperty *volumeProperty=vol->GetProperty(); vtkPiecewiseFunction *scalarOpacity=volumeProperty->GetScalarOpacity(); vtkgl::ActiveTexture( vtkgl::TEXTURE2); //stay here this->OpacityTables->Vector[level].Update( scalarOpacity,this->BlendMode, this->ActualSampleDistance, this->TableRange, volumeProperty->GetScalarOpacityUnitDistance(0), volumeProperty->GetInterpolationType()==VTK_LINEAR_INTERPOLATION); // Restore default active texture vtkgl::ActiveTexture( vtkgl::TEXTURE0); return 1; } //----------------------------------------------------------------------------- // Prepare rendering in the offscreen framebuffer. // \pre ren_exists: ren!=0 // \pre vol_exists: vol!=0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::SetupRender(vtkRenderer *ren, vtkVolume *vol) { assert("pre: ren_exists" && ren!=0); assert("pre: vol_exists" && vol!=0); double aspect[2]; int lowerLeft[2]; int usize, vsize; ren->GetTiledSizeAndOrigin(&usize,&vsize,lowerLeft,lowerLeft+1); usize = static_cast(usize*this->ReductionFactor); vsize = static_cast(vsize*this->ReductionFactor); this->ReducedSize[0]=usize; this->ReducedSize[1]=vsize; // the FBO has the size of the renderer (not the renderwindow), // we always starts at 0,0. glViewport(0,0, usize, vsize); glEnable( GL_SCISSOR_TEST ); // scissor on the FBO, on the reduced part. glScissor(0,0, usize, vsize); glClearColor(0.0, 0.0, 0.0, 0.0); // maxvalue is 1 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ren->ComputeAspect(); ren->GetAspect(aspect); double aspect2[2]; ren->vtkViewport::ComputeAspect(); ren->vtkViewport::GetAspect(aspect2); double aspectModification = aspect[0]*aspect2[1]/(aspect[1]*aspect2[0]); vtkCamera *cam = ren->GetActiveCamera(); glMatrixMode( GL_PROJECTION); if(usize && vsize) { this->TempMatrix[0]->DeepCopy(cam->GetProjectionTransformMatrix( aspectModification*usize/vsize, -1,1)); this->TempMatrix[0]->Transpose(); glLoadMatrixd(this->TempMatrix[0]->Element[0]); } else { glLoadIdentity(); } // push the model view matrix onto the stack, make sure we // adjust the mode first glMatrixMode(GL_MODELVIEW); glPushMatrix(); this->TempMatrix[0]->DeepCopy(vol->GetMatrix()); this->TempMatrix[0]->Transpose(); // insert camera view transformation glMultMatrixd(this->TempMatrix[0]->Element[0]); glShadeModel(GL_SMOOTH); glDisable( GL_LIGHTING); glEnable (GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); // very important, otherwise the first image looks dark. this->PrintError("SetupRender"); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::DebugDisplayBox(vtkPolyData *box) { vtkPoints *points=box->GetPoints(); vtkCellArray *polys=box->GetPolys(); cout<<"npts="<GetNumberOfPoints()<GetNumberOfPoints()) { double coords[3]; points->GetPoint(pointId,coords); cout<<"pointId="<GetMatrix( this->InvVolumeMatrix ); this->InvVolumeMatrix->Invert(); if(this->BoxSource==0) { this->BoxSource=vtkTessellatedBoxSource::New(); } this->BoxSource->SetBounds(worldBounds); this->BoxSource->SetLevel(0); this->BoxSource->QuadsOn(); if(this->Planes==0) { this->Planes=vtkPlaneCollection::New(); } this->Planes->RemoveAllItems(); vtkCamera *cam = ren->GetActiveCamera(); double camWorldRange[2]; double camWorldPos[4]; double camFocalWorldPoint[4]; double camWorldDirection[3]; double range[2]; double camPos[4]; double focalPoint[4]; double direction[3]; cam->GetPosition(camWorldPos); camWorldPos[3] = 1.0; this->InvVolumeMatrix->MultiplyPoint( camWorldPos, camPos ); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } cam->GetFocalPoint(camFocalWorldPoint); camFocalWorldPoint[3]=1.0; this->InvVolumeMatrix->MultiplyPoint( camFocalWorldPoint,focalPoint ); if ( focalPoint[3] ) { focalPoint[0] /= focalPoint[3]; focalPoint[1] /= focalPoint[3]; focalPoint[2] /= focalPoint[3]; } // Compute the normalized view direction direction[0] = focalPoint[0] - camPos[0]; direction[1] = focalPoint[1] - camPos[1]; direction[2] = focalPoint[2] - camPos[2]; vtkMath::Normalize(direction); // The range (near/far) must also be transformed // into the local coordinate system. camWorldDirection[0] = camFocalWorldPoint[0] - camWorldPos[0]; camWorldDirection[1] = camFocalWorldPoint[1] - camWorldPos[1]; camWorldDirection[2] = camFocalWorldPoint[2] - camWorldPos[2]; vtkMath::Normalize(camWorldDirection); double camNearWorldPoint[4]; double camFarWorldPoint[4]; double camNearPoint[4]; double camFarPoint[4]; cam->GetClippingRange(camWorldRange); camNearWorldPoint[0] = camWorldPos[0] + camWorldRange[0]*camWorldDirection[0]; camNearWorldPoint[1] = camWorldPos[1] + camWorldRange[0]*camWorldDirection[1]; camNearWorldPoint[2] = camWorldPos[2] + camWorldRange[0]*camWorldDirection[2]; camNearWorldPoint[3] = 1.; camFarWorldPoint[0] = camWorldPos[0] + camWorldRange[1]*camWorldDirection[0]; camFarWorldPoint[1] = camWorldPos[1] + camWorldRange[1]*camWorldDirection[1]; camFarWorldPoint[2] = camWorldPos[2] + camWorldRange[1]*camWorldDirection[2]; camFarWorldPoint[3] = 1.; this->InvVolumeMatrix->MultiplyPoint( camNearWorldPoint, camNearPoint ); if (camNearPoint[3]) { camNearPoint[0] /= camNearPoint[3]; camNearPoint[1] /= camNearPoint[3]; camNearPoint[2] /= camNearPoint[3]; } this->InvVolumeMatrix->MultiplyPoint( camFarWorldPoint, camFarPoint ); if (camFarPoint[3]) { camFarPoint[0] /= camFarPoint[3]; camFarPoint[1] /= camFarPoint[3]; camFarPoint[2] /= camFarPoint[3]; } range[0] = sqrt(vtkMath::Distance2BetweenPoints(camNearPoint, camPos)); range[1] = sqrt(vtkMath::Distance2BetweenPoints(camFarPoint, camPos)); //double nearPoint[3], farPoint[3]; double dist = range[1] - range[0]; range[0] += dist / (2<<16); range[1] -= dist / (2<<16); if(this->NearPlane==0) { this->NearPlane= vtkPlane::New(); } //this->NearPlane->SetOrigin( nearPoint ); this->NearPlane->SetOrigin( camNearPoint ); this->NearPlane->SetNormal( direction ); this->Planes->AddItem(this->NearPlane); if ( this->ClippingPlanes ) { this->ClippingPlanes->InitTraversal(); vtkPlane *plane; while ( (plane = this->ClippingPlanes->GetNextItem()) ) { // Planes are in world coordinates, we need to // convert them in local coordinates double planeOrigin[4], planeNormal[4], planeP1[4]; plane->GetOrigin(planeOrigin); planeOrigin[3] = 1.; plane->GetNormal(planeNormal); planeP1[0] = planeOrigin[0] + planeNormal[0]; planeP1[1] = planeOrigin[1] + planeNormal[1]; planeP1[2] = planeOrigin[2] + planeNormal[2]; planeP1[3] = 1.; this->InvVolumeMatrix->MultiplyPoint(planeOrigin, planeOrigin); this->InvVolumeMatrix->MultiplyPoint(planeP1, planeP1); if( planeOrigin[3]) { planeOrigin[0] /= planeOrigin[3]; planeOrigin[1] /= planeOrigin[3]; planeOrigin[2] /= planeOrigin[3]; } if( planeP1[3]) { planeP1[0] /= planeP1[3]; planeP1[1] /= planeP1[3]; planeP1[2] /= planeP1[3]; } planeNormal[0] = planeP1[0] - planeOrigin[0]; planeNormal[1] = planeP1[1] - planeOrigin[1]; planeNormal[2] = planeP1[2] - planeOrigin[2]; vtkMath::Normalize(planeNormal); vtkPlane* localPlane = vtkPlane::New(); localPlane->SetOrigin(planeOrigin); localPlane->SetNormal(planeNormal); this->Planes->AddItem(localPlane); localPlane->Delete(); } } if(this->Clip==0) { this->Clip=vtkClipConvexPolyData::New(); this->Clip->SetInputConnection(this->BoxSource->GetOutputPort()); this->Clip->SetPlanes( this->Planes ); } this->Clip->Update(); if(this->Densify==0) { this->Densify=vtkDensifyPolyData::New(); this->Densify->SetInputConnection(this->Clip->GetOutputPort()); this->Densify->SetNumberOfSubdivisions(2); } this->Densify->Update(); this->ClippedBoundingBox = this->Densify->GetOutput(); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::RenderClippedBoundingBox( int tcoordFlag, size_t currentBlock, size_t numberOfBlocks, vtkRenderWindow *renWin ) { assert("pre: valid_currentBlock" && currentBlockClippedBoundingBox->GetPoints(); vtkCellArray *polys = this->ClippedBoundingBox->GetPolys(); vtkIdType npts; vtkIdType *pts; vtkIdType i, j; double center[3] = {0,0,0}; double min[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX}; double max[3] = {VTK_DOUBLE_MIN, VTK_DOUBLE_MIN, VTK_DOUBLE_MIN}; // First compute center point npts = points->GetNumberOfPoints(); for ( i = 0; i < npts; i++ ) { double pt[3]; points->GetPoint( i, pt ); for ( j = 0; j < 3; j++ ) { min[j] = (pt[j]max[j])?(pt[j]):(max[j]); } } center[0] = 0.5*(min[0]+max[0]); center[1] = 0.5*(min[1]+max[1]); center[2] = 0.5*(min[2]+max[2]); double *loadedBounds=0; vtkIdType *loadedExtent=0; if ( tcoordFlag ) { loadedBounds=this->CurrentScalar->GetLoadedBounds(); loadedExtent=this->CurrentScalar->GetLoadedExtent(); } double *spacing=this->GetInput()->GetSpacing(); double spacingSign[3]; i=0; while(i<3) { if(spacing[i]<0) { spacingSign[i]=-1.0; } else { spacingSign[i]=1.0; } ++i; } // make it double for the ratio of the progress. int polyId=0; double polyCount=static_cast(polys->GetNumberOfCells()); polys->InitTraversal(); int abort=0; while ( !abort && polys->GetNextCell(npts, pts) ) { vtkIdType start, end, inc; // Need to have at least a triangle if ( npts > 2 ) { // Check the cross product of the first two // vectors dotted with the vector from the // center to the second point. Is it positive or // negative? double p1[3], p2[3], p3[3]; double v1[3], v2[3], v3[3], v4[3]; points->GetPoint(pts[0], p1 ); points->GetPoint(pts[1], p2 ); points->GetPoint(pts[2], p3 ); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; v2[0] = p2[0] - p3[0]; v2[1] = p2[1] - p3[1]; v2[2] = p2[2] - p3[2]; vtkMath::Cross( v1, v2, v3 ); vtkMath::Normalize(v3); v4[0] = p2[0] - center[0]; v4[1] = p2[1] - center[1]; v4[2] = p2[2] - center[2]; vtkMath::Normalize(v4); double dot = vtkMath::Dot( v3, v4 ); if (( dot < 0) && this->PreserveOrientation) { start = 0; end = npts; inc = 1; } else { start = npts-1; end = -1; inc = -1; } glBegin( GL_TRIANGLE_FAN ); // GL_POLYGON -> GL_TRIANGLE_FAN double vert[3]; double tcoord[3]; for ( i = start; i != end; i += inc ) { points->GetPoint(pts[i], vert); if ( tcoordFlag ) { for ( j = 0; j < 3; j++ ) { // loaded bounds take both cell data and point date cases into // account if(this->CellFlag) // texcoords between 0 and 1. More complex // depends on the loaded texture { tcoord[j] = spacingSign[j]*(vert[j] - loadedBounds[j*2]) / (loadedBounds[j*2+1] - loadedBounds[j*2]); } else // texcoords between 1/2N and 1-1/2N. { double tmp; // between 0 and 1 tmp = spacingSign[j]*(vert[j] - loadedBounds[j*2]) / (loadedBounds[j*2+1] - loadedBounds[j*2]); double delta=static_cast( loadedExtent[j*2+1]-loadedExtent[j*2]+1); tcoord[j]=(tmp*(delta-1)+0.5)/delta; } } vtkgl::MultiTexCoord3dv(vtkgl::TEXTURE0, tcoord); } glVertex3dv(vert); } glEnd(); } if(tcoordFlag) { // otherwise, we are rendering back face to initialize the zbuffer. if (!this->GeneratingCanonicalView && this->ReportProgress) { glFinish(); // Only invoke an event at most one every second. double currentTime=vtkTimerLog::GetUniversalTime(); if(currentTime - this->LastProgressEventTime > 1.0) { double progress=(static_cast(currentBlock)+polyId/polyCount)/ static_cast(numberOfBlocks); this->InvokeEvent(vtkCommand::VolumeMapperRenderProgressEvent, &progress); renWin->MakeCurrent(); this->LastProgressEventTime = currentTime; } } abort=renWin->CheckAbortStatus(); } ++polyId; } return abort; } void vtkMitkOpenGLGPUVolumeRayCastMapper::CopyFBOToTexture() { // in OpenGL copy texture to texture does not exist but // framebuffer to texture exists (and our FB is an FBO). // we have to copy and not just to switch color textures because the // colorbuffer has to accumulate color or values step after step. // Switching would not work because two different steps can draw different // polygons that don't overlap vtkgl::ActiveTexture(vtkgl::TEXTURE4); glBindTexture( GL_TEXTURE_2D, this->TextureObjects[ vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+1]); glReadBuffer(vtkgl::COLOR_ATTACHMENT0_EXT); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,this->ReducedSize[0], this->ReducedSize[1]); if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { vtkgl::ActiveTexture(vtkgl::TEXTURE5); glBindTexture(GL_TEXTURE_2D,this->MaxValueFrameBuffer2); glReadBuffer(vtkgl::COLOR_ATTACHMENT0_EXT+1); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,this->ReducedSize[0], this->ReducedSize[1]); } vtkgl::ActiveTexture(vtkgl::TEXTURE0); } //----------------------------------------------------------------------------- // Restore OpenGL state after rendering of the dataset. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CleanupRender() { glPopMatrix(); glDisable(GL_CULL_FACE); } //----------------------------------------------------------------------------- // Build the fragment shader program that scale and bias a texture // for window/level purpose. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::BuildScaleBiasProgram() { if(this->ScaleBiasProgramShader==0) { GLuint programShader; GLuint fragmentShader; programShader=vtkgl::CreateProgram(); fragmentShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentShader); vtkgl::DeleteShader(fragmentShader); // reference counting vtkgl::ShaderSource( fragmentShader,1, const_cast(&vtkMitkGPUVolumeRayCastMapper_ScaleBiasFS),0); vtkgl::CompileShader(fragmentShader); this->CheckCompilation(static_cast(fragmentShader)); vtkgl::LinkProgram(programShader); this->CheckLinkage(static_cast(programShader)); this->ScaleBiasProgramShader=static_cast(programShader); this->UFrameBufferTexture= static_cast(vtkgl::GetUniformLocation(programShader, "frameBufferTexture")); this->UScale=static_cast(vtkgl::GetUniformLocation(programShader, "scale")); this->UBias=static_cast(vtkgl::GetUniformLocation(programShader, "bias")); } } //----------------------------------------------------------------------------- // Render the offscreen buffer to the screen. // \pre ren_exists: ren!=0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::RenderTextureToScreen(vtkRenderer *ren) { assert("pre: ren_exists" && ren!=0); if ( this->GeneratingCanonicalView ) { // We just need to copy of the data, not render it glBindTexture(GL_TEXTURE_2D, this->TextureObjects[ vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glPixelStorei( GL_PACK_ALIGNMENT, 1 ); unsigned char *outPtr = static_cast(this->CanonicalViewImageData->GetScalarPointer()); glGetTexImage( GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, outPtr ); return; } int lowerLeft[2]; int usize, vsize; ren->GetTiledSizeAndOrigin(&usize,&vsize,lowerLeft,lowerLeft+1); glViewport(lowerLeft[0],lowerLeft[1], usize, vsize); glEnable( GL_SCISSOR_TEST ); glScissor(lowerLeft[0],lowerLeft[1], usize, vsize); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, usize, 0.0, vsize, -1.0, 1.0 ); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glEnable(GL_BLEND); glBlendFunc( GL_ONE,GL_ONE_MINUS_SRC_ALPHA); // As we use replace mode, we don't need to set the color value. glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glDisable(GL_DEPTH_TEST); double xOffset = 1.0 / usize; double yOffset = 1.0 / vsize; glDepthMask(GL_FALSE); double scale=1.0/this->FinalColorWindow; double bias=0.5-this->FinalColorLevel/this->FinalColorWindow; if(scale!=1.0 || bias!=0.0) { this->BuildScaleBiasProgram(); vtkgl::UseProgram(this->ScaleBiasProgramShader); if(this->UFrameBufferTexture!=-1) { vtkgl::Uniform1i(this->UFrameBufferTexture,0); } else { vtkErrorMacro(<<"uFrameBufferTexture is not a uniform variable."); } if(this->UScale!=-1) { vtkgl::Uniform1f(this->UScale,static_cast(scale)); } else { vtkErrorMacro(<<"uScale is not a uniform variable."); } if(this->UBias!=-1) { vtkgl::Uniform1f(this->UBias,static_cast(bias)); } else { vtkErrorMacro(<<"uBias is not a uniform variable."); } } else { glEnable(GL_TEXTURE_2D); // fixed pipeline } glBegin(GL_QUADS); glTexCoord2f(static_cast(xOffset),static_cast(yOffset)); glVertex2f(0.0,0.0); glTexCoord2f(static_cast(this->ReductionFactor-xOffset), static_cast(yOffset)); glVertex2f(static_cast(usize),0.0); glTexCoord2f(static_cast(this->ReductionFactor-xOffset), static_cast(this->ReductionFactor-yOffset)); glVertex2f(static_cast(usize),static_cast(vsize)); glTexCoord2f(static_cast(xOffset), static_cast(this->ReductionFactor-yOffset)); glVertex2f(0.0,static_cast(vsize)); glEnd(); // Restore the default mode. Used in overlay. glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); if(scale!=1.0 || bias!=0.0) { vtkgl::UseProgram(0); } else { glDisable(GL_TEXTURE_2D); } glDepthMask(GL_TRUE); glDisable(GL_BLEND); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } //----------------------------------------------------------------------------- // Update the reduction factor of the render viewport (this->ReductionFactor) // according to the time spent in seconds to render the previous frame // (this->TimeToDraw) and a time in seconds allocated to render the next // frame (allocatedTime). // \pre valid_current_reduction_range: this->ReductionFactor>0.0 && this->ReductionFactor<=1.0 // \pre positive_TimeToDraw: this->TimeToDraw>=0.0 // \pre positive_time: allocatedTime>0.0 // \post valid_new_reduction_range: this->ReductionFactor>0.0 && this->ReductionFactor<=1.0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::ComputeReductionFactor( double allocatedTime) { assert("pre: valid_current_reduction_range" && this->ReductionFactor>0.0 && this->ReductionFactor<=1.0); assert("pre: positive_TimeToDraw" && this->TimeToDraw>=0.0); assert("pre: positive_time" && allocatedTime>0.0); if ( this->GeneratingCanonicalView ) { this->ReductionFactor = 1.0; return; } if ( !this->AutoAdjustSampleDistances ) { this->ReductionFactor = 1.0 / this->ImageSampleDistance; return; } if ( this->TimeToDraw ) { double oldFactor = this->ReductionFactor; double timeToDraw; if (allocatedTime < 1.0) { timeToDraw = this->SmallTimeToDraw; if ( timeToDraw == 0.0 ) { timeToDraw = this->BigTimeToDraw/3.0; } } else { timeToDraw = this->BigTimeToDraw; } if ( timeToDraw == 0.0 ) { timeToDraw = 10.0; } double fullTime = timeToDraw / this->ReductionFactor; double newFactor = allocatedTime / fullTime; if ( oldFactor == 1.0 || newFactor / oldFactor > 1.3 || newFactor / oldFactor < .95 ) { this->ReductionFactor = (newFactor+oldFactor)/2.0; this->ReductionFactor = (this->ReductionFactor > 5.0)?(1.00):(this->ReductionFactor); this->ReductionFactor = (this->ReductionFactor > 1.0)?(0.99):(this->ReductionFactor); this->ReductionFactor = (this->ReductionFactor < 0.1)?(0.10):(this->ReductionFactor); if ( 1.0/this->ReductionFactor > this->MaximumImageSampleDistance ) { this->ReductionFactor = 1.0 / this->MaximumImageSampleDistance; } if ( 1.0/this->ReductionFactor < this->MinimumImageSampleDistance ) { this->ReductionFactor = 1.0 / this->MinimumImageSampleDistance; } } } else { this->ReductionFactor = 1.0; } assert("post: valid_new_reduction_range" && this->ReductionFactor>0.0 && this->ReductionFactor<=1.0); } //----------------------------------------------------------------------------- // Rendering initialization including making the context current, loading // necessary extensions, allocating frame buffers, updating transfer function, // computing clipping regions, and building the fragment shader. // // Pre-conditions: // - ren != NULL // - vol != NULL // - ren->GetRenderWindow() != NULL // - 1 <= numberOfScalarComponents <= 4 // - numberOfLevels >= 1 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PreRender(vtkRenderer *ren, vtkVolume *vol, double datasetBounds[6], double scalarRange[2], int numberOfScalarComponents, unsigned int numberOfLevels) { // make sure our window is the current OpenGL context. ren->GetRenderWindow()->MakeCurrent(); // If we haven't already succeeded in loading the extensions, // try to load them if(!this->LoadExtensionsSucceeded) { this->LoadExtensions(ren->GetRenderWindow()); } // If we can't load the necessary extensions, provide // feedback on why it failed. if(!this->LoadExtensionsSucceeded) { vtkErrorMacro( "Rendering failed because the following OpenGL extensions " "are required but not supported: " << (this->UnsupportedRequiredExtensions->Stream.str()).c_str()); return; } // Create the OpenGL object that we need this->CreateOpenGLObjects(); // Compute the reduction factor that may be necessary to get // the interactive rendering rate that we want this->ComputeReductionFactor(vol->GetAllocatedRenderTime()); // Allocate the frame buffers if(!this->AllocateFrameBuffers(ren)) { vtkErrorMacro("Not enough GPU memory to create a framebuffer."); return; } // Save the scalar range - this is what we will use for the range // of the transfer functions this->TableRange[0]=scalarRange[0]; this->TableRange[1]=scalarRange[1]; if(this->RGBTable==0) { this->RGBTable=new vtkRGBTable; } if(this->MaskInput!=0) { if(this->Mask1RGBTable==0) { this->Mask1RGBTable=new vtkRGBTable; } if(this->Mask2RGBTable==0) { this->Mask2RGBTable=new vtkRGBTable; } } // Update the color transfer function this->UpdateColorTransferFunction(vol,numberOfScalarComponents); // Update the noise texture that will be used to jitter rays to // reduce alliasing artifacts this->UpdateNoiseTexture(); // We are going to change the blending mode and blending function - // so lets push here so we can pop later glPushAttrib(GL_COLOR_BUFFER_BIT); // If this is the canonical view - we don't want to intermix so we'll just // start by clearing the z buffer. if ( this->GeneratingCanonicalView ) { glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } // See if the volume transform is orientation-preserving vtkMatrix4x4 *m=vol->GetMatrix(); double det=vtkMath::Determinant3x3( m->GetElement(0,0),m->GetElement(0,1),m->GetElement(0,2), m->GetElement(1,0),m->GetElement(1,1),m->GetElement(1,2), m->GetElement(2,0),m->GetElement(2,1),m->GetElement(2,2)); this->PreserveOrientation=det>0; // If we have clipping planes, render the back faces of the clipped // bounding box of the whole dataset to set the zbuffer. if(this->ClippingPlanes && this->ClippingPlanes->GetNumberOfItems()!=0) { // push the model view matrix onto the stack, make sure we // adjust the mode first glMatrixMode(GL_MODELVIEW); glPushMatrix(); this->TempMatrix[0]->DeepCopy(vol->GetMatrix()); this->TempMatrix[0]->Transpose(); glMultMatrixd(this->TempMatrix[0]->Element[0]); this->ClipBoundingBox(ren,datasetBounds,vol); glEnable (GL_CULL_FACE); glCullFace (GL_FRONT); glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); this->RenderClippedBoundingBox(0,0,1,ren->GetRenderWindow()); glDisable (GL_CULL_FACE); glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); //glMatrixMode(GL_MODELVIEW); glPopMatrix(); } // Check if everything is OK this->CheckFrameBufferStatus(); // Intermixed geometry: Grab the depth buffer into a texture int size[2]; int lowerLeft[2]; ren->GetTiledSizeAndOrigin(size,size+1,lowerLeft,lowerLeft+1); vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glBindTexture(GL_TEXTURE_2D, static_cast( this->TextureObjects[ vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap])); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,lowerLeft[0],lowerLeft[1],size[0], size[1]); vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); int parallelProjection=ren->GetActiveCamera()->GetParallelProjection(); // initialize variables to prevent compiler warnings. int rayCastMethod=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP; int shadeMethod=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotUsed; int componentMethod=vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotUsed; switch(this->BlendMode) { case vtkVolumeMapper::COMPOSITE_BLEND: switch(numberOfScalarComponents) { case 1: componentMethod=vtkMitkOpenGLGPUVolumeRayCastMapperComponentOne; break; case 4: componentMethod=vtkMitkOpenGLGPUVolumeRayCastMapperComponentFour; break; default: assert("check: impossible case" && false); break; } if(this->MaskInput!=0) { rayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodCompositeMask; } else { //cout<<"program is composite+shade"<GetProperty()->GetShade() ) { shadeMethod=vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes; assert("check: only_1_component_todo" && numberOfScalarComponents==1); } else { shadeMethod=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNo; //cout<<"program is composite"<ComputeNumberOfCroppingRegions(); // TODO AMR vs single block if(this->AMRMode) { NumberOfCroppingRegions=2; // >1, means use do compositing between blocks } this->BuildProgram(parallelProjection,rayCastMethod,shadeMethod, componentMethod); this->CheckLinkage(this->ProgramShader); vtkgl::UseProgram(this->ProgramShader); // for active texture 0, dataset if(numberOfScalarComponents==1) { // colortable vtkgl::ActiveTexture(vtkgl::TEXTURE1); this->RGBTable->Bind(); if(this->MaskInput!=0) { vtkgl::ActiveTexture(vtkgl::TEXTURE8); this->Mask1RGBTable->Bind(); vtkgl::ActiveTexture(vtkgl::TEXTURE9); this->Mask2RGBTable->Bind(); } } GLint uDataSetTexture; uDataSetTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"dataSetTexture"); if(uDataSetTexture!=-1) { vtkgl::Uniform1i(uDataSetTexture,0); } else { vtkErrorMacro(<<"dataSetTexture is not a uniform variable."); } if ( this->MaskInput) { // Make the mask texture available on texture unit 7 GLint uMaskTexture; uMaskTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"maskTexture"); if(uMaskTexture!=-1) { vtkgl::Uniform1i(uMaskTexture,7); } else { vtkErrorMacro(<<"maskTexture is not a uniform variable."); } } if(numberOfScalarComponents==1) { GLint uColorTexture; uColorTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"colorTexture"); if(uColorTexture!=-1) { vtkgl::Uniform1i(uColorTexture,1); } else { vtkErrorMacro(<<"colorTexture is not a uniform variable."); } if(this->MaskInput!=0) { GLint uMask1ColorTexture; uMask1ColorTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"mask1ColorTexture"); if(uMask1ColorTexture!=-1) { vtkgl::Uniform1i(uMask1ColorTexture,8); } else { vtkErrorMacro(<<"mask1ColorTexture is not a uniform variable."); } GLint uMask2ColorTexture; uMask2ColorTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"mask2ColorTexture"); if(uMask2ColorTexture!=-1) { vtkgl::Uniform1i(uMask2ColorTexture,9); } else { vtkErrorMacro(<<"mask2ColorTexture is not a uniform variable."); } GLint uMaskBlendFactor; uMaskBlendFactor=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"maskBlendFactor"); if(uMaskBlendFactor!=-1) { vtkgl::Uniform1f(uMaskBlendFactor,this->MaskBlendFactor); } else { vtkErrorMacro(<<"maskBlendFactor is not a uniform variable."); } } } GLint uOpacityTexture; uOpacityTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"opacityTexture"); if(uOpacityTexture!=-1) { vtkgl::Uniform1i(uOpacityTexture,2); } else { vtkErrorMacro(<<"opacityTexture is not a uniform variable."); } // depthtexture vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap])); GLint uDepthTexture; uDepthTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"depthTexture"); if(uDepthTexture!=-1) { vtkgl::Uniform1i(uDepthTexture,3); } else { vtkErrorMacro(<<"depthTexture is not a uniform variable."); } // noise texture vtkgl::ActiveTexture( vtkgl::TEXTURE6 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->NoiseTextureId)); GLint uNoiseTexture; uNoiseTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"noiseTexture"); if(uNoiseTexture!=-1) { vtkgl::Uniform1i(uNoiseTexture,6); } else { vtkErrorMacro(<<"noiseTexture is not a uniform variable."); } this->CheckFrameBufferStatus(); if(this->NumberOfCroppingRegions>1) { // framebuffer texture if(rayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && rayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIP) { vtkgl::ActiveTexture( vtkgl::TEXTURE4 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront])); GLint uFrameBufferTexture; uFrameBufferTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"frameBufferTexture"); this->PrintError("framebuffertexture 1"); if(uFrameBufferTexture!=-1) { vtkgl::Uniform1i(uFrameBufferTexture,4); } else { vtkErrorMacro(<<"frameBufferTexture is not a uniform variable."); } this->PrintError("framebuffertexture 2"); } this->CheckFrameBufferStatus(); // max scalar value framebuffer texture if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { vtkgl::ActiveTexture( vtkgl::TEXTURE5 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->MaxValueFrameBuffer2)); GLint uScalarBufferTexture; uScalarBufferTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"scalarBufferTexture"); this->PrintError("scalarbuffertexture 1"); if(uScalarBufferTexture!=-1) { vtkgl::Uniform1i(uScalarBufferTexture,5); } else { vtkErrorMacro(<<"scalarBufferTexture is not a uniform variable."); } this->PrintError("scalarbuffertexture 2"); } } this->CheckFrameBufferStatus(); GLint uWindowLowerLeftCorner; uWindowLowerLeftCorner=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"windowLowerLeftCorner"); if(uWindowLowerLeftCorner!=-1) { vtkgl::Uniform2f(uWindowLowerLeftCorner,static_cast(lowerLeft[0]), static_cast(lowerLeft[1])); } else { vtkErrorMacro(<<"windowLowerLeftCorner is not a uniform variable."); } GLint uInvOriginalWindowSize; uInvOriginalWindowSize=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"invOriginalWindowSize"); if(uInvOriginalWindowSize!=-1) { vtkgl::Uniform2f(uInvOriginalWindowSize, static_cast(1.0/size[0]), static_cast(1.0/size[1])); } else { // yes it is not error. It is only actually used when there is some // complex cropping (this->NumberOfCroppingRegions>1). Some GLSL compilers // may remove the uniform variable for optimization when it is not used. vtkDebugMacro( <<"invOriginalWindowSize is not an active uniform variable."); } size[0] = static_cast(size[0]*this->ReductionFactor); size[1] = static_cast(size[1]*this->ReductionFactor); GLint uInvWindowSize; uInvWindowSize=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"invWindowSize"); if(uInvWindowSize!=-1) { vtkgl::Uniform2f(uInvWindowSize,static_cast(1.0/size[0]), static_cast(1.0/size[1])); } else { vtkErrorMacro(<<"invWindowSize is not a uniform variable."); } this->PrintError("after uniforms for textures"); this->CheckFrameBufferStatus(); GLint savedFrameBuffer; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&savedFrameBuffer); this->SavedFrameBuffer=static_cast(savedFrameBuffer); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->FrameBufferObject)); this->BindFramebuffer(); GLenum buffer[4]; buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; if(this->NumberOfCroppingRegions>1 && this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND) { // max scalar frame buffer buffer[1] = vtkgl::COLOR_ATTACHMENT1_EXT; } else { buffer[1] = GL_NONE; } vtkgl::DrawBuffers(2,buffer); this->CheckFrameBufferStatus(); // Use by the composite+shade program double shininess=vol->GetProperty()->GetSpecularPower(); if(shininess>128.0) { shininess=128.0; // upper limit for the OpenGL shininess. } glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,static_cast(shininess)); glDisable(GL_COLOR_MATERIAL); // other mapper may have enable that. GLfloat values[4]; values[3]=1.0; values[0]=0.0; values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,values); values[0]=static_cast(vol->GetProperty()->GetAmbient()); values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,values); values[0]=static_cast(vol->GetProperty()->GetDiffuse()); values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,values); values[0]=static_cast(vol->GetProperty()->GetSpecular()); values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,values); // cout << "pingpong=" << this->PingPongFlag << endl; // To initialize the second color buffer vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront], 0); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+1], 0); buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; buffer[1] = vtkgl::COLOR_ATTACHMENT1_EXT; vtkgl::DrawBuffers(2,buffer); // cout << "check before setup" << endl; this->CheckFrameBufferStatus(); this->SetupRender(ren,vol); // restore in case of composite with no cropping or streaming. buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; buffer[1] = GL_NONE; vtkgl::DrawBuffers(2,buffer); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D,0,0); // cout << "check after color init" << endl; this->CheckFrameBufferStatus(); if(this->NumberOfCroppingRegions>1 && (this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MAXIMUM_INTENSITY_BLEND)) { // cout << "this->MaxValueFrameBuffer="<< this->MaxValueFrameBuffer <MaxValueFrameBuffer2="<< this->MaxValueFrameBuffer2 <MaxValueFrameBuffer,0); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D, this->MaxValueFrameBuffer2,0); buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; buffer[1] = vtkgl::COLOR_ATTACHMENT1_EXT; vtkgl::DrawBuffers(2,buffer); if(this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { glClearColor(1.0, 0.0, 0.0, 0.0); } else { glClearColor(0.0, 0.0, 0.0, 0.0); // for MAXIMUM_INTENSITY_BLEND } // cout << "check before clear on max" << endl; this->CheckFrameBufferStatus(); glClear(GL_COLOR_BUFFER_BIT); } if(this->NumberOfCroppingRegions>1) { // color buffer target in the color attachement 0 vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront], 0); // color buffer input is on texture unit 4. vtkgl::ActiveTexture(vtkgl::TEXTURE4); glBindTexture(GL_TEXTURE_2D,this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+1]); if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { // max buffer target in the color attachment 1 vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D, this->MaxValueFrameBuffer,0); // max buffer input is on texture unit 5. vtkgl::ActiveTexture(vtkgl::TEXTURE5); glBindTexture(GL_TEXTURE_2D,this->MaxValueFrameBuffer2); } vtkgl::ActiveTexture(vtkgl::TEXTURE0); } this->CheckFrameBufferStatus(); if(this->OpacityTables!=0 && this->OpacityTables->Vector.size()!=numberOfLevels) { delete this->OpacityTables; this->OpacityTables=0; } if(this->OpacityTables==0) { this->OpacityTables=new vtkOpacityTables(numberOfLevels); } // debug code // DO NOT REMOVE the following commented line // this->ValidateProgram(); glCullFace (GL_BACK); // otherwise, we are rendering back face to initialize the zbuffer. if(!this->GeneratingCanonicalView && this->ReportProgress) { // initialize the time to avoid a progress event at the beginning. this->LastProgressEventTime=vtkTimerLog::GetUniversalTime(); } this->PrintError("PreRender end"); } //----------------------------------------------------------------------------- // Compute how each axis of a cell is projected on the viewport in pixel. // This requires to have information about the camera and about the volume. // It set the value of IgnoreSampleDistancePerPixel to true in case of // degenerated case (axes aligned with the view). //----------------------------------------------------------------------------- double vtkMitkOpenGLGPUVolumeRayCastMapper::ComputeMinimalSampleDistancePerPixel( vtkRenderer *renderer, vtkVolume *volume) { // For each of the 3 directions of a cell, compute the step in z // (world coordinate, not eye/camera coordinate) // to go to the next pixel in x. // Same for the next pixel in y. // Keep the minimum of both zstep // Then keep the minimum for the 3 directions. // in case of either the numerator or the denominator of each ratio is 0. this->IgnoreSampleDistancePerPixel=true; double result=0.0; vtkMatrix4x4 *worldToDataset=volume->GetMatrix(); vtkCamera *camera=renderer->GetActiveCamera(); vtkMatrix4x4 *eyeToWorld=camera->GetViewTransformMatrix(); vtkMatrix4x4 *eyeToDataset=vtkMatrix4x4::New(); vtkMatrix4x4::Multiply4x4(eyeToWorld,worldToDataset,eyeToDataset); int usize; int vsize; renderer->GetTiledSize(&usize,&vsize); vtkMatrix4x4 *viewportToEye=camera->GetProjectionTransformMatrix( usize/static_cast(vsize),0.0,1.0); double volBounds[6]; this->GetInput()->GetBounds(volBounds); int dims[3]; this->GetInput()->GetDimensions(dims); double v0[4]; v0[0]=volBounds[0]; v0[1]=volBounds[2]; v0[2]=volBounds[4]; v0[3]=1.0; double w0[4]; eyeToDataset->MultiplyPoint(v0,w0); double z0; if(w0[3]!=0.0) { z0=w0[2]/w0[3]; } else { z0=0.0; vtkGenericWarningMacro( "eyeToWorld transformation has some projective component." ); } double p0[4]; viewportToEye->MultiplyPoint(w0,p0); p0[0]/=p0[3]; p0[1]/=p0[3]; p0[2]/=p0[3]; bool inFrustum=p0[0]>=-1.0 && p0[0]<=1.0 && p0[1]>=-1.0 && p0[1]<=1.0 && p0[2]>=-1.0 && p0[2]<=1.0; if(inFrustum) { int dim=0; while(dim<3) { double v1[4]; int coord=0; while(coord<3) { if(coord==dim) { v1[coord]=volBounds[2*coord+1]; } else { v1[coord]=volBounds[2*coord]; // same as v0[coord]; } ++coord; } v1[3]=1.0; double w1[4]; eyeToDataset->MultiplyPoint(v1,w1); double z1; if(w1[3]!=0.0) { z1=w1[2]/w1[3]; } else { z1=0.0; vtkGenericWarningMacro( "eyeToWorld transformation has some projective component." ); } double p1[4]; viewportToEye->MultiplyPoint(w1,p1); p1[0]/=p1[3]; p1[1]/=p1[3]; p1[2]/=p1[3]; inFrustum=p1[0]>=-1.0 && p1[0]<=1.0 && p1[1]>=-1.0 && p1[1]<=1.0 && p1[2]>=-1.0 && p1[2]<=1.0; if(inFrustum) { double dx=fabs(p1[0]-p0[0]); double dy=fabs(p1[1]-p0[1]); double dz=fabs(z1-z0); dz=dz/(dims[dim]-1); dx=dx/(dims[dim]-1)*usize; dy=dy/(dims[dim]-1)*vsize; if(dz!=0.0) { if(dx!=0.0) { double d=dz/dx; if(!this->IgnoreSampleDistancePerPixel) { if(result>d) { result=d; } } else { this->IgnoreSampleDistancePerPixel=false; result=d; } } if(dy!=0.0) { double d=dz/dy; if(!this->IgnoreSampleDistancePerPixel) { if(result>d) { result=d; } } else { this->IgnoreSampleDistancePerPixel=false; result=d; } } } } ++dim; } } eyeToDataset->Delete(); if(this->IgnoreSampleDistancePerPixel) { // cout<<"ignore SampleDistancePerPixel"<ValidateProgram(); this->PrintError("before render"); if(!this->Cropping) { this->RenderWholeVolume(ren,vol); } else { this->ClipCroppingRegionPlanes(); this->RenderRegions(ren,vol); } this->PrintError("after render"); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PostRender( vtkRenderer *ren, int numberOfScalarComponents) { this->PrintError("PostRender1"); if(this->NumberOfCroppingRegions>1) { if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { vtkgl::ActiveTexture( vtkgl::TEXTURE5 ); glBindTexture(GL_TEXTURE_2D,0); } if(this->LastRayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && this->LastRayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIP) { vtkgl::ActiveTexture( vtkgl::TEXTURE4 ); glBindTexture(GL_TEXTURE_2D,0); } } // noisetexture vtkgl::ActiveTexture(vtkgl::TEXTURE6); glBindTexture(GL_TEXTURE_2D,0); // depthtexture vtkgl::ActiveTexture(vtkgl::TEXTURE3); glBindTexture(GL_TEXTURE_2D,0); // opacity vtkgl::ActiveTexture(vtkgl::TEXTURE2); glBindTexture(GL_TEXTURE_1D,0); if(numberOfScalarComponents==1) { vtkgl::ActiveTexture(vtkgl::TEXTURE1); glBindTexture(GL_TEXTURE_1D,0); } // mask, if any if(this->MaskInput!=0) { vtkgl::ActiveTexture(vtkgl::TEXTURE7); glBindTexture(vtkgl::TEXTURE_3D_EXT,0); } // back to active texture 0. vtkgl::ActiveTexture(vtkgl::TEXTURE0); glBindTexture(vtkgl::TEXTURE_3D_EXT,0); vtkgl::UseProgram(0); this->PrintError("after UseProgram(0)"); this->CleanupRender(); this->PrintError("after CleanupRender"); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->SavedFrameBuffer)); this->SavedFrameBuffer=0; // Undo the viewport change we made to reduce resolution int size[2]; int lowerLeft[2]; ren->GetTiledSizeAndOrigin(size,size+1,lowerLeft,lowerLeft+1); glViewport(lowerLeft[0],lowerLeft[1], size[0], size[1]); glEnable( GL_SCISSOR_TEST ); glScissor(lowerLeft[0],lowerLeft[1], size[0], size[1]); // Render the texture to the screen - this copies the offscreen buffer // onto the screen as a texture mapped polygon this->RenderTextureToScreen(ren); this->PrintError("after RenderTextureToScreen"); glEnable(GL_DEPTH_TEST); glPopAttrib(); // restore the blending mode and function glFinish(); this->PrintError("PostRender2"); } //----------------------------------------------------------------------------- // The main render method called from the superclass //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer *ren, vtkVolume *vol) { // We've already checked that we have input vtkImageData *input = this->GetTransformedInput(); // Get the bounds of this data double bounds[6]; this->GetBounds(bounds); // Get the scalar range. First we have to get the scalars. double range[2]; vtkDataArray *scalars=this->GetScalars(input,this->ScalarMode, this->ArrayAccessMode, this->ArrayId,this->ArrayName, this->CellFlag); // How many components are there? int numberOfScalarComponents=scalars->GetNumberOfComponents(); // If it is just one, then get the range from the scalars if(numberOfScalarComponents==1) { // Warning: here, we ignore the blank cells. scalars->GetRange(range); } // If it is 3, then use the 4th component's range since that is // the component that will be passed through the scalar opacity // transfer function to look up opacity else { // Note that we've already checked data type and we know this is // unsigned char scalars->GetRange(range,3); } // The rendering work has been broken into 3 stages to support AMR // volume rendering in blocks. Here we are simply rendering the // whole volume as one block. Note that if the volume is too big // to fix into texture memory, it will be streamed through in the // RenderBlock method. this->PreRender(ren,vol,bounds,range,numberOfScalarComponents,1); if(!this->OpacityTables) this->PreRender(ren,vol,bounds,range,numberOfScalarComponents,1); if(this->LoadExtensionsSucceeded) { this->RenderBlock(ren,vol,0); this->PostRender(ren,numberOfScalarComponents); } // Let's just make sure no OpenGL errors occurred during this render this->PrintError("End GPU Render"); // If this isn't a canonical view render, then update the progress to // 1 because we are done. if (!this->GeneratingCanonicalView ) { double progress=1.0; this->InvokeEvent(vtkCommand::VolumeMapperRenderProgressEvent,&progress); ren->GetRenderWindow()->MakeCurrent(); } } //----------------------------------------------------------------------------- // Render a the whole volume. // \pre this->ProgramShader!=0 and is linked. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::RenderWholeVolume(vtkRenderer *ren, vtkVolume *vol) { double volBounds[6]; this->GetTransformedInput()->GetBounds(volBounds); this->RenderSubVolume(ren,volBounds,vol); } //----------------------------------------------------------------------------- // Sort regions from front to back. //----------------------------------------------------------------------------- class vtkRegionDistance2 { public: size_t Id; // 0<=Id<27 // square distance between camera center to region center: >=0 double Distance2; }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- extern "C" int vtkRegionComparisonFunction(const void *x, const void *y) { double dx=static_cast(x)->Distance2; double dy=static_cast(y)->Distance2; int result; if(dxdy) { result=1; } else { result=0; } } return result; } //----------------------------------------------------------------------------- // Render a subvolume. // \pre this->ProgramShader!=0 and is linked. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::RenderRegions(vtkRenderer *ren, vtkVolume *vol) { double bounds[27][6]; double distance2[27]; double camPos[4]; ren->GetActiveCamera()->GetPosition(camPos); double volBounds[6]; this->GetInput()->GetBounds(volBounds); // Pass camera through inverse volume matrix // so that we are in the same coordinate system vol->GetMatrix( this->InvVolumeMatrix ); camPos[3] = 1.0; this->InvVolumeMatrix->Invert(); this->InvVolumeMatrix->MultiplyPoint( camPos, camPos ); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } // These are the region limits for x (first four), y (next four) and // z (last four). The first region limit is the lower bound for // that axis, the next two are the region planes along that axis, and // the final one in the upper bound for that axis. double limit[12]; size_t i; for ( i = 0; i < 3; i++ ) { limit[i*4 ] = volBounds[i*2]; limit[i*4+1] = this->ClippedCroppingRegionPlanes[i*2]; limit[i*4+2] = this->ClippedCroppingRegionPlanes[i*2+1]; limit[i*4+3] = volBounds[i*2+1]; } // For each of the 27 possible regions, find out if it is enabled, // and if so, compute the bounds and the distance from the camera // to the center of the region. size_t numRegions = 0; size_t region; for ( region = 0; region < 27; region++ ) { int regionFlag = 1<CroppingRegionFlags & regionFlag ) { // what is the coordinate in the 3x3x3 grid size_t loc[3]; loc[0] = region%3; loc[1] = (region/3)%3; loc[2] = (region/9)%3; // make sure the cropping region is not empty NEW // otherwise, we skip the region. if((limit[loc[0]]!=limit[loc[0]+1]) && (limit[loc[1]+4]!=limit[loc[1]+5]) && (limit[loc[2]+8]!=limit[loc[2]+9])) { // compute the bounds and center double center[3]; for ( i = 0; i < 3; i++ ) { bounds[numRegions][i*2 ] = limit[4*i+loc[i]]; bounds[numRegions][i*2+1] = limit[4*i+loc[i]+1]; center[i]=(bounds[numRegions][i*2]+bounds[numRegions][i*2+1])*0.5; } // compute the distance squared to the center distance2[numRegions] = (camPos[0]-center[0])*(camPos[0]-center[0]) + (camPos[1]-center[1])*(camPos[1]-center[1]) + (camPos[2]-center[2])*(camPos[2]-center[2]); // we've added one region numRegions++; } } } vtkRegionDistance2 regions[27]; i=0; while(iNumberOfCroppingRegions>=0); } //----------------------------------------------------------------------------- // slabsDataSet are position of the slabs in dataset coordinates. // slabsPoints are position of the slabs in points coordinates. // For instance, slabsDataSet[0] is the position of the plane bounding the slab // on the left of x axis of the dataset. slabsPoints[0]=0.3 means that // this plane lies between point 0 and point 1 along the x-axis. // There is no clamping/clipping according to the dataset bounds so, // slabsPoints can be negative or excess the number of points along the // corresponding axis. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::SlabsFromDatasetToIndex( double slabsDataSet[6], double slabsPoints[6]) { double *spacing=this->GetInput()->GetSpacing(); double origin[3]; // take spacing sign into account double *bds = this->GetInput()->GetBounds(); origin[0] = bds[0]; origin[1] = bds[2]; origin[2] = bds[4]; int i=0; while(i<6) { slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; ++i; } } //----------------------------------------------------------------------------- // slabsDataSet are position of the slabs in dataset coordinates. // slabsPoints are position of the slabs in points coordinates. // For instance, slabsDataSet[0] is the position of the plane bounding the slab // on the left of x axis of the dataset. slabsPoints[0]=0.3 means that // this plane lies between point 0 and point 1 along the x-axis. // There is no clamping/clipping according to the dataset bounds so, // slabsPoints can be negative or excess the number of points along the // corresponding axis. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::SlabsFromIndexToDataset( double slabsPoints[6], double slabsDataSet[6]) { double *spacing=this->GetInput()->GetSpacing(); double origin[3]; // take spacing sign into account double *bds = this->GetInput()->GetBounds(); origin[0] = bds[0]; origin[1] = bds[2]; origin[2] = bds[4]; int i=0; while(i<6) { slabsDataSet[i]=slabsPoints[i]*spacing[i/2]+origin[i/2]; ++i; } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkStreamBlock { public: double Bounds[6]; double Extent[6]; }; //----------------------------------------------------------------------------- // Render a subvolume. bounds are in world coordinates. // \pre this->ProgramShader!=0 and is linked. //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::RenderSubVolume(vtkRenderer *ren, double bounds[6], vtkVolume *volume) { // Time to load scalar field size_t i; int wholeTextureExtent[6]; this->GetTransformedInput()->GetExtent(wholeTextureExtent); if(this->CellFlag) { i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } } // 1. Found out the extent of the subvolume double realExtent[6]; int subvolumeTextureExtent[6]; this->SlabsFromDatasetToIndex(bounds,realExtent); if(this->CellFlag) // 3D texture are celldata { // texture extents are expressed in cells in this case i=0; while(i<6) { subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i]-0.5); ++i; subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i]-0.5)+1; ++i; } } else { // texture extents are expressed in points in this case i=0; while(i<6) { subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i]); ++i; subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i])+1; // used to not have +1 ++i; } } i=0; while(i<6) { assert("check: wholeTextureExtent" && wholeTextureExtent[i]==0); if(subvolumeTextureExtent[i]wholeTextureExtent[i]) { subvolumeTextureExtent[i]=wholeTextureExtent[i]; } ++i; } assert("check: subvolume_inside_wholevolume" && subvolumeTextureExtent[0]>=wholeTextureExtent[0] && subvolumeTextureExtent[1]<=wholeTextureExtent[1] && subvolumeTextureExtent[2]>=wholeTextureExtent[2] && subvolumeTextureExtent[3]<=wholeTextureExtent[3] && subvolumeTextureExtent[4]>=wholeTextureExtent[4] && subvolumeTextureExtent[5]<=wholeTextureExtent[5]); // 2. Is this subvolume already on the GPU? // ie are the extent of the subvolume inside the loaded extent? // Find the texture (and mask). vtkstd::map::iterator it= this->ScalarsTextures->Map.find(this->GetTransformedInput()); vtkKWScalarField *texture; if(it==this->ScalarsTextures->Map.end()) { texture=0; } else { texture=(*it).second; } vtkKWMask *mask=0; if(this->MaskInput!=0) { vtkstd::map::iterator it2= this->MaskTextures->Map.find(this->MaskInput); if(it2==this->MaskTextures->Map.end()) { mask=0; } else { mask=(*it2).second; } } int loaded = texture!=0 && texture->IsLoaded() && this->GetTransformedInput()->GetMTime()<=texture->GetBuildTime() && (this->GetMaskInput() ? this->GetMaskInput()->GetMTime() <= texture->GetBuildTime() : true) && texture->GetLoadedCellFlag()==this->CellFlag; vtkIdType *loadedExtent; if(loaded) { loadedExtent=texture->GetLoadedExtent(); i=0; while(loaded && i<6) { loaded=loaded && loadedExtent[i]<=subvolumeTextureExtent[i]; ++i; loaded=loaded && loadedExtent[i]>=subvolumeTextureExtent[i]; ++i; } } if(loaded) { this->CurrentScalar=texture; vtkgl::ActiveTexture(vtkgl::TEXTURE0); this->CurrentScalar->Bind(); vtkgl::ActiveTexture(vtkgl::TEXTURE7); this->CurrentMask=mask; if(this->CurrentMask!=0) { this->CurrentMask->Bind(); } } if(!loaded) { // 3. Not loaded: try to load the whole dataset if(!this->LoadScalarField(this->GetTransformedInput(),this->MaskInput,wholeTextureExtent,volume)) { // 4. loading the whole dataset failed: try to load the subvolume if(!this->LoadScalarField(this->GetTransformedInput(),this->MaskInput, subvolumeTextureExtent, volume)) { // 5. loading the subvolume failed: stream the subvolume // 5.1 do zslabs first, if too large then cut with x or y with the // largest dimension. order of zlabs depends on sign of spacing[2] int streamTextureExtent[6]; i=0; while(i<6) { streamTextureExtent[i]=subvolumeTextureExtent[i]; ++i; } unsigned int internalFormat; unsigned int format; unsigned int type; int componentSize; this->GetTextureFormat(this->GetInput(),&internalFormat,&format,&type, &componentSize); // Enough memory? int originalTextureSize[3]; int textureSize[3]; i=0; while(i<3) { textureSize[i]=subvolumeTextureExtent[2*i+1]-subvolumeTextureExtent[2*i]+1; originalTextureSize[i]=textureSize[i]; ++i; } // Make sure loading did not fail because of theorical limits GLint width; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&width); int clippedXY=0; int clippedZ=0; if(textureSize[0]>width) { textureSize[0]=width; clippedXY=1; } if(textureSize[1]>width) { textureSize[1]=width; clippedXY=1; } if(textureSize[2]>width) { textureSize[2]=width; clippedZ=1; } int minSize; if(this->CellFlag) { minSize=1; } else { minSize=2; } if(clippedXY) { // We cannot expect to first divide as z-slabs because it is already // clipped in another dimension. From now, just divide in the largest // dimension. bool foundSize=false; while(!foundSize && textureSize[0]>=minSize && textureSize[1]>=minSize) { foundSize=this->TestLoadingScalar(internalFormat,format,type, textureSize,componentSize); if(!foundSize) { int maxDim=0; if(textureSize[1]>textureSize[0]) { maxDim=1; } if(textureSize[2]>textureSize[maxDim]) { maxDim=2; } textureSize[maxDim]>>=1; // /=2 } } } else { // we are in cropping mode, it will be slow anyway. the case we want // to optimize is stream the all scalar field. With that in mine, // it is better to first try to send z-slabs. If even a minimal // z-slab is too big, we have to divide by x or y dimensions. In // this case, it will be slow and we can choose to keep blocks as // square as possible by dividing by the largest dimension at each // iteration. if(!clippedZ) { // we start by subdividing only if we did not already clipped // the z dimension according to the theorical limits. textureSize[2]>>=1; // /=2 } bool foundSize=false; while(!foundSize && textureSize[2]>=minSize) { foundSize=this->TestLoadingScalar(internalFormat,format,type, textureSize,componentSize); if(!foundSize) { textureSize[2]>>=1; // /=2 } } if(!foundSize) { textureSize[2]=minSize; if(textureSize[0]>textureSize[1]) { textureSize[0]>>=1; // /=2 } else { textureSize[1]>>=1; // /=2 } while(!foundSize && textureSize[0]>=minSize && textureSize[1]>=minSize) { foundSize=this->TestLoadingScalar(internalFormat,format,type, textureSize,componentSize); if(!foundSize) { if(textureSize[0]>textureSize[1]) { textureSize[0]>>=1; // /=2 } else { textureSize[1]>>=1; // /=2 } } } } if(!foundSize) { vtkErrorMacro( <<"No memory left on the GPU even for a minimal block."); return 1; // abort } } // except for the last bound. // front to back ordering // Pass camera through inverse volume matrix // so that we are in the same coordinate system double camPos[4]; vtkCamera *cam = ren->GetActiveCamera(); cam->GetPosition(camPos); volume->GetMatrix( this->InvVolumeMatrix ); camPos[3] = 1.0; this->InvVolumeMatrix->Invert(); this->InvVolumeMatrix->MultiplyPoint( camPos, camPos ); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } // 5.2 iterate of each stream of the subvolume and render it: // point scalar: on the first block, the first point is not shared // blockExtent is always expressed in point, not in texture // extent. size_t remainder[3]; i=0; while(i<3) { remainder[i]=static_cast( (originalTextureSize[i]-textureSize[i])%(textureSize[i]-1)); if(remainder[i]>0) { remainder[i]=1; } ++i; } size_t counts[3]; counts[0]=static_cast((originalTextureSize[0]-textureSize[0]) /(textureSize[0]-1)); counts[0]+=remainder[0]+1; counts[1]=static_cast((originalTextureSize[1]-textureSize[1]) /(textureSize[1]-1)); counts[1]+=remainder[1]+1; counts[2]=static_cast((originalTextureSize[2]-textureSize[2]) /(textureSize[2]-1)); counts[2]+=remainder[2]+1; size_t count=counts[0]*counts[1]*counts[2]; double blockExtent[6]; vtkStreamBlock *blocks=new vtkStreamBlock[count]; vtkRegionDistance2 *sortedBlocks=new vtkRegionDistance2[count]; // iterate over z,y,x size_t blockId=0; size_t zIndex=0; blockExtent[4]=realExtent[4]; blockExtent[5]=vtkMath::Floor(blockExtent[4])+textureSize[2]; if(!this->CellFlag) { blockExtent[5]--; } if(blockExtent[5]>realExtent[5]) { blockExtent[5]=realExtent[5]; } while(zIndexCellFlag) { blockExtent[3]--; } if(blockExtent[3]>realExtent[3]) { blockExtent[3]=realExtent[3]; } size_t yIndex=0; while(yIndexCellFlag) { blockExtent[1]--; } if(blockExtent[1]>realExtent[1]) { blockExtent[1]=realExtent[1]; } size_t xIndex=0; while(xIndexSlabsFromIndexToDataset(blockExtent,blockBounds); // compute the bounds and center double center[3]; i=0; while(i<3) { center[i]=(blockBounds[i*2]+blockBounds[i*2+1])*0.5; ++i; } // compute the distance squared to the center double distance2=(camPos[0]-center[0])*(camPos[0]-center[0])+ (camPos[1]-center[1])*(camPos[1]-center[1]) + (camPos[2]-center[2])*(camPos[2]-center[2]); i=0; while(i<6) { blocks[blockId].Bounds[i]=blockBounds[i]; blocks[blockId].Extent[i]=blockExtent[i]; ++i; } sortedBlocks[blockId].Id=blockId; sortedBlocks[blockId].Distance2=distance2; ++blockId; blockExtent[0]=blockExtent[1]; blockExtent[1]=blockExtent[0]+textureSize[0]; if(!this->CellFlag) { blockExtent[1]--; } if(blockExtent[1]>realExtent[1]) { blockExtent[1]=realExtent[1]; } ++xIndex; } // while x blockExtent[2]=blockExtent[3]; blockExtent[3]=blockExtent[2]+textureSize[1]; if(!this->CellFlag) { blockExtent[3]--; } if(blockExtent[3]>realExtent[3]) { blockExtent[3]=realExtent[3]; } ++yIndex; } // while y blockExtent[4]=blockExtent[5]; blockExtent[5]=blockExtent[4]+textureSize[2]; if(!this->CellFlag) { blockExtent[5]--; } if(blockExtent[5]>realExtent[5]) { blockExtent[5]=realExtent[5]; } ++zIndex; } // while z assert("check: valid_number_of_blocks" && blockId==count); qsort(sortedBlocks,static_cast(count), sizeof(vtkRegionDistance2), vtkRegionComparisonFunction); // loop over all blocks we need to render i=0; int abort=0; while(!abort && i < count) // 1) //count) { size_t k=sortedBlocks[i].Id; int blockTextureExtent[6]; int j; if(this->CellFlag) // 3D texture are celldata { // texture extents are expressed in cells in this case j=0; while(j<6) { blockTextureExtent[j]=vtkMath::Floor(blocks[k].Extent[j]); ++j; } } else { // texture extents are expressed in points in this case j=0; while(j<6) { blockTextureExtent[j]=vtkMath::Floor(blocks[k].Extent[j]); ++j; blockTextureExtent[j]=vtkMath::Floor(blocks[k].Extent[j]); if(blockTextureExtent[j]LoadScalarField(this->GetInput(),this->MaskInput, blockTextureExtent, volume)) { cout<<"Loading the streamed block FAILED!!!!!"<CurrentScalar->GetLoadedExtent(); float lowBounds[3]; float highBounds[3]; if(!this->CurrentScalar->GetLoadedCellFlag()) // points { j=0; while(j<3) { double delta= static_cast(loadedExtent[j*2+1]-loadedExtent[j*2]); lowBounds[j]=static_cast((blocks[k].Extent[j*2]-static_cast(loadedExtent[j*2]))/delta); highBounds[j]=static_cast((blocks[k].Extent[j*2+1]-static_cast(loadedExtent[j*2]))/delta); ++j; } } else // cells { j=0; while(j<3) { double delta= static_cast(loadedExtent[j*2+1]-loadedExtent[j*2]); lowBounds[j]=static_cast((blocks[k].Extent[j*2]-0.5-static_cast(loadedExtent[j*2]))/delta); highBounds[j]=static_cast((blocks[k].Extent[j*2+1]-0.5-static_cast(loadedExtent[j*2]))/delta); ++j; } } // bounds have to be normalized. There are used in the shader // as bounds to a value used to sample a texture. assert("check: positive_low_bounds0" && lowBounds[0]>=0.0); assert("check: positive_low_bounds1" && lowBounds[1]>=0.0); assert("check: positive_low_bounds2" && lowBounds[2]>=0.0); assert("check: increasing_bounds0" && lowBounds[0]<=highBounds[0]); assert("check: increasing_bounds1" && lowBounds[1]<=highBounds[1]); assert("check: increasing_bounds2" && lowBounds[2]<=highBounds[2]); assert("check: high_bounds0_less_than1" && highBounds[0]<=1.0); assert("check: high_bounds1_less_than1" && highBounds[1]<=1.0); assert("check: high_bounds2_less_than1" && highBounds[2]<=1.0); GLint lb; lb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "lowBounds"); this->PrintError("get uniform low bounds"); if(lb!=-1) { vtkgl::Uniform3f(lb, lowBounds[0],lowBounds[1],lowBounds[2]); this->PrintError("set uniform low bounds"); } else { vtkErrorMacro(<<" lowBounds is not a uniform variable."); } GLint hb; hb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "highBounds"); this->PrintError("get uniform high bounds"); if(hb!=-1) { vtkgl::Uniform3f(hb, highBounds[0],highBounds[1],highBounds[2]); this->PrintError("set uniform high bounds"); } else { vtkErrorMacro(<<" highBounds is not a uniform variable."); } this->PrintError("uniform low/high bounds block"); // other sub-volume rendering code this->LoadProjectionParameters(ren,volume); this->ClipBoundingBox(ren,blocks[k].Bounds,volume); abort=this->RenderClippedBoundingBox(1,i,count,ren->GetRenderWindow()); if (!abort) { this->CopyFBOToTexture(); } this->PrintError("render clipped block 1"); ++i; } delete[] blocks; delete[] sortedBlocks; return abort; } } } loadedExtent=this->CurrentScalar->GetLoadedExtent(); // low bounds and high bounds are in texture coordinates. float lowBounds[3]; float highBounds[3]; if(!this->CurrentScalar->GetLoadedCellFlag()) // points { i=0; while(i<3) { double delta= static_cast(loadedExtent[i*2+1]-loadedExtent[i*2]+1); lowBounds[i]=static_cast((realExtent[i*2]+0.5-static_cast(loadedExtent[i*2]))/delta); highBounds[i]=static_cast((realExtent[i*2+1]+0.5-static_cast(loadedExtent[i*2]))/delta); ++i; } } else // cells { i=0; while(i<3) { double delta= static_cast(loadedExtent[i*2+1]-loadedExtent[i*2]+1); // this->LoadedExtent[i*2]==0, texcoord starts at 0, if realExtent==0 // otherwise, texcoord start at 1/2N // this->LoadedExtent[i*2]==wholeTextureExtent[i*2+1], texcoord stops at 1, if realExtent==wholeTextureExtent[i*2+1]+1 // otherwise it stop at 1-1/2N // N is the number of texels in the loadedtexture not the number of // texels in the whole texture. lowBounds[i]=static_cast((realExtent[i*2]-static_cast(loadedExtent[i*2]))/delta); highBounds[i]=static_cast((realExtent[i*2+1]-static_cast(loadedExtent[i*2]))/delta); ++i; } } assert("check: positive_low_bounds0" && lowBounds[0]>=0.0); assert("check: positive_low_bounds1" && lowBounds[1]>=0.0); assert("check: positive_low_bounds2" && lowBounds[2]>=0.0); assert("check: increasing_bounds0" && lowBounds[0]<=highBounds[0]); assert("check: increasing_bounds1" && lowBounds[1]<=highBounds[1]); assert("check: increasing_bounds2" && lowBounds[2]<=highBounds[2]); assert("check: high_bounds0_less_than1" && highBounds[0]<=1.0); assert("check: high_bounds1_less_than1" && highBounds[1]<=1.0); assert("check: high_bounds2_less_than1" && highBounds[2]<=1.0); GLint lb; lb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "lowBounds"); this->PrintError("get uniform low bounds"); if(lb!=-1) { vtkgl::Uniform3f(lb, lowBounds[0],lowBounds[1],lowBounds[2]); this->PrintError("set uniform low bounds"); } else { vtkErrorMacro(<<" lowBounds is not a uniform variable."); } GLint hb; hb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "highBounds"); this->PrintError("get uniform high bounds"); if(hb!=-1) { vtkgl::Uniform3f(hb, highBounds[0],highBounds[1],highBounds[2]); this->PrintError("set uniform high bounds"); } else { vtkErrorMacro(<<" highBounds is not a uniform variable."); } this->PrintError("uniform low/high bounds"); // other sub-volume rendering code this->LoadProjectionParameters(ren,volume); this->ClipBoundingBox(ren,bounds,volume); int abort=this->RenderClippedBoundingBox(1,0,1,ren->GetRenderWindow()); if (!abort) { this->CopyFBOToTexture(); } this->PrintError("render clipped 1"); return abort; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::LoadProjectionParameters( vtkRenderer *ren, vtkVolume *vol) { vtkMatrix4x4 *worldToDataset=vol->GetMatrix(); vtkMatrix4x4 *datasetToWorld=this->TempMatrix[0]; vtkMatrix4x4::Invert(worldToDataset,datasetToWorld); double *bounds=this->CurrentScalar->GetLoadedBounds(); double dx=bounds[1]-bounds[0]; double dy=bounds[3]-bounds[2]; double dz=bounds[5]-bounds[4]; // worldToTexture matrix is needed // Compute change-of-coordinate matrix from world space to texture space. vtkMatrix4x4 *worldToTexture=this->TempMatrix[2]; vtkMatrix4x4 *datasetToTexture=this->TempMatrix[1]; // Set the matrix datasetToTexture->Zero(); datasetToTexture->SetElement(0,0,dx); datasetToTexture->SetElement(1,1,dy); datasetToTexture->SetElement(2,2,dz); datasetToTexture->SetElement(3,3,1.0); datasetToTexture->SetElement(0,3,bounds[0]); datasetToTexture->SetElement(1,3,bounds[2]); datasetToTexture->SetElement(2,3,bounds[4]); // worldToTexture=worldToDataSet*dataSetToTexture vtkMatrix4x4::Multiply4x4(worldToDataset,datasetToTexture,worldToTexture); // NEW int parallelProjection=ren->GetActiveCamera()->GetParallelProjection(); // cout << "actualSampleDistance=" << this->ActualSampleDistance << endl; if(parallelProjection) { // Unit vector of the direction of projection in world space. double dirWorld[4]; double dir[4]; ren->GetActiveCamera()->GetDirectionOfProjection(dirWorld); dirWorld[3]=0.0; // direction in dataset space. datasetToWorld->MultiplyPoint(dirWorld,dir); // incremental vector: // direction in texture space times sample distance in world space. dir[0]=dir[0]*this->ActualSampleDistance/dx; dir[1]=dir[1]*this->ActualSampleDistance/dy; dir[2]=dir[2]*this->ActualSampleDistance/dz; GLint rayDir; rayDir=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"parallelRayDirection"); if(rayDir!=-1) { vtkgl::Uniform3f(rayDir,static_cast(dir[0]), static_cast(dir[1]), static_cast(dir[2])); } else { vtkErrorMacro(<<"parallelRayDirection is not a uniform variable."); } //cout<<"rayDir="<GetActiveCamera()->GetPosition(cameraPosWorld); cameraPosWorld[3]=1.0; // we use homogeneous coordinates. datasetToWorld->MultiplyPoint(cameraPosWorld,cameraPosDataset); // From homogeneous to cartesian coordinates. if(cameraPosDataset[3]!=1.0) { double ratio=1/cameraPosDataset[3]; cameraPosDataset[0]*=ratio; cameraPosDataset[1]*=ratio; cameraPosDataset[2]*=ratio; } cameraPosTexture[0] = (cameraPosDataset[0]-bounds[0])/dx; cameraPosTexture[1] = (cameraPosDataset[1]-bounds[2])/dy; cameraPosTexture[2] = (cameraPosDataset[2]-bounds[4])/dz; // Only make sense for the vectorial part of the homogeneous matrix. // coefMatrix=transposeWorldToTexture*worldToTexture // we re-cycle the datasetToWorld pointer with a different name vtkMatrix4x4 *transposeWorldToTexture=this->TempMatrix[1]; // transposeWorldToTexture={^t}worldToTexture vtkMatrix4x4::Transpose(worldToTexture,transposeWorldToTexture); vtkMatrix4x4 *coefMatrix=this->TempMatrix[1]; vtkMatrix4x4::Multiply4x4(transposeWorldToTexture,worldToTexture, coefMatrix); GLint uCameraPosition; uCameraPosition=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"cameraPosition"); if(uCameraPosition!=-1) { vtkgl::Uniform3f(uCameraPosition, static_cast(cameraPosTexture[0]), static_cast(cameraPosTexture[1]), static_cast(cameraPosTexture[2])); } else { vtkErrorMacro(<<"cameraPosition is not a uniform variable."); } GLint uSampleDistance; uSampleDistance=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"sampleDistance"); if(uSampleDistance!=-1) { vtkgl::Uniform1f(uSampleDistance,this->ActualSampleDistance); } else { vtkErrorMacro(<<"sampleDistance is not a uniform variable."); } GLint uMatrix1; uMatrix1=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"matrix1"); if(uMatrix1!=-1) { vtkgl::Uniform3f(uMatrix1, static_cast(coefMatrix->GetElement(0,0)), static_cast(coefMatrix->GetElement(1,1)), static_cast(coefMatrix->GetElement(2,2))); } else { vtkErrorMacro(<<"matrix1 is not a uniform variable."); } GLint uMatrix2; uMatrix2=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"matrix2"); if(uMatrix2!=-1) { vtkgl::Uniform3f(uMatrix2, static_cast(2*coefMatrix->GetElement(0,1)), static_cast(2*coefMatrix->GetElement(1,2)), static_cast(2*coefMatrix->GetElement(0,2))); } else { vtkErrorMacro(<<"matrix2 is not a uniform variable."); } } this->PrintError("after uniforms for projection"); // Change-of-coordinate matrix from Eye space to texture space. vtkMatrix4x4 *eyeToTexture=this->TempMatrix[1]; vtkMatrix4x4 *eyeToWorld=ren->GetActiveCamera()->GetViewTransformMatrix(); vtkMatrix4x4::Multiply4x4(eyeToWorld,worldToTexture,eyeToTexture); GLfloat matrix[16];// used sometimes as 3x3, sometimes as 4x4. double *raw=eyeToTexture->Element[0]; int index; int column; int row; int shadeMethod=this->LastShade; if(shadeMethod==vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes) { index=0; column=0; while(column<3) { row=0; while(row<3) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } GLint uEyeToTexture3; uEyeToTexture3=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"eyeToTexture3"); this->PrintError("after getUniform eyeToTexture3"); if(uEyeToTexture3!=-1) { vtkgl::UniformMatrix3fv(uEyeToTexture3,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"eyeToTexture3 is not a uniform variable."); } this->PrintError("after Uniform eyeToTexture3"); index=0; column=0; while(column<4) { row=0; while(row<4) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } GLint uEyeToTexture4; uEyeToTexture4=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"eyeToTexture4"); if(uEyeToTexture4!=-1) { vtkgl::UniformMatrix4fv(uEyeToTexture4,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"eyeToTexture4 is not a uniform variable."); } } eyeToTexture->Invert(); index=0; column=0; while(column<4) { row=0; while(row<4) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } this->PrintError("before GetUniformLocation TextureToEye"); GLint uTextureToEye; uTextureToEye=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"textureToEye"); this->PrintError("after GetUniformLocation TextureToEye"); if(uTextureToEye!=-1) { vtkgl::UniformMatrix4fv(uTextureToEye,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"textureToEye is not a uniform variable."); } this->PrintError("after UniformMatrxix TextureToEye"); if(shadeMethod==vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes) { eyeToTexture->Transpose(); index=0; column=0; while(column<3) { row=0; while(row<3) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } GLint uTranposeTextureToEye; uTranposeTextureToEye=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"transposeTextureToEye"); if(uTranposeTextureToEye!=-1) { vtkgl::UniformMatrix3fv(uTranposeTextureToEye,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"transposeTextureToEye is not a uniform variable."); } float cellScale[3]; // 1/(2*Step) float cellStep[3]; // Step vtkIdType *loadedExtent=this->CurrentScalar->GetLoadedExtent(); cellScale[0]=static_cast(static_cast( loadedExtent[1]-loadedExtent[0])*0.5); cellScale[1]=static_cast(static_cast( loadedExtent[3]-loadedExtent[2])*0.5); cellScale[2]=static_cast(static_cast( loadedExtent[5]-loadedExtent[4])*0.5); cellStep[0]=static_cast(1.0/static_cast( loadedExtent[1]-loadedExtent[0])); cellStep[1]=static_cast(1.0/static_cast( loadedExtent[3]-loadedExtent[2])); cellStep[2]=static_cast(1.0/static_cast( loadedExtent[5]-loadedExtent[4])); GLint uCellScale; uCellScale=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"cellScale"); if(uCellScale!=-1) { vtkgl::Uniform3f(uCellScale,cellScale[0],cellScale[1],cellScale[2]); } else { vtkErrorMacro(<<"error: cellScale is not a uniform variable."); } GLint uCellStep; uCellStep=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"cellStep"); if(uCellStep!=-1) { vtkgl::Uniform3f(uCellStep,cellStep[0],cellStep[1],cellStep[2]); } else { vtkErrorMacro(<<"error: cellStep is not a uniform variable."); } } } //----------------------------------------------------------------------------- // Concatenate the header string, projection type code and method to the // final fragment code in this->FragmentCode. // \pre valid_raycastMethod: raycastMethod>= // vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && // raycastMethod<=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIPFourDependent //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::BuildProgram(int parallelProjection, int raycastMethod, int shadeMethod, int componentMethod) { assert("pre: valid_raycastMethod" && raycastMethod>= vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && raycastMethod<=vtkMitkOpenGLGPUVolumeRayCastMapperMethodCompositeMask); GLuint fs; // cout<<"projection="<ProgramShader, vtkgl::INFO_LOG_LENGTH,¶ms); if(params>0) { char *buffer=new char[params]; vtkgl::GetProgramInfoLog(this->ProgramShader,params,0,buffer); cout<<"validation log: "<GetEnabledString(glIsEnabled(GL_LIGHTING))<GetEnabledString(glIsEnabled(GL_LIGHTING))<(value); cout<<"active texture is "<<(activeTexture-vtkgl::TEXTURE0)<(value); cout<<"light\t| status\t| ambient\t| diffuse\t| specular\t| position\t| spot direction\t| spot exponent\t| spot cutoff\t| k0\t| k1\t| k2"<=0 // \post valid_result: result>=x //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::PowerOfTwoGreaterOrEqual(int x) { assert("pre: positive_x" && x>=0); int result=1; while(result=x); return result; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::UpdateNoiseTexture() { if(this->NoiseTextureId==0) { GLuint noiseTextureObject; glGenTextures(1,&noiseTextureObject); this->NoiseTextureId=static_cast(noiseTextureObject); vtkgl::ActiveTexture(vtkgl::TEXTURE6); glBindTexture(GL_TEXTURE_2D,noiseTextureObject); GLsizei size=128; // 1024; // Power of two value GLint maxSize; const float factor=0.1f; // const float factor=1.0f; const float amplitude=0.5f*factor; // something positive. // amplitude=0.5. noise between -0.5 +0.5. add some +0.5 shift. glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxSize); if(size>maxSize) { size=maxSize; } if(this->NoiseTexture!=0 && this->NoiseTextureSize!=size) { delete[] this->NoiseTexture; this->NoiseTexture=0; } if(this->NoiseTexture==0) { this->NoiseTexture=new float[size*size]; this->NoiseTextureSize=size; vtkPerlinNoise *noiseGenerator=vtkPerlinNoise::New(); noiseGenerator->SetFrequency(size,1.0,1.0); noiseGenerator->SetPhase(0.0,0.0,0.0); noiseGenerator->SetAmplitude(amplitude); int j=0; while(jNoiseTexture[j*size+i]=0.0; //amplitude+static_cast(noiseGenerator->EvaluateFunction(i,j,0.0)); ++i; } ++j; } noiseGenerator->Delete(); } glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,size,size,0,GL_RED,GL_FLOAT, this->NoiseTexture); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,borderColor); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); vtkgl::ActiveTexture(vtkgl::TEXTURE0); } } // ---------------------------------------------------------------------------- // Description: // Return how much the dataset has to be reduced in each dimension to // fit on the GPU. If the value is 1.0, there is no need to reduce the // dataset. // \pre the calling thread has a current OpenGL context. // \pre mapper_supported: IsRenderSupported(renderer->GetRenderWindow(),0) // The computation is based on hardware limits (3D texture indexable size) // and MaxMemoryInBytes. // \post valid_i_ratio: ratio[0]>0 && ratio[0]<=1.0 // \post valid_j_ratio: ratio[1]>0 && ratio[1]<=1.0 // \post valid_k_ratio: ratio[2]>0 && ratio[2]<=1.0 void vtkMitkOpenGLGPUVolumeRayCastMapper::GetReductionRatio(double ratio[3]) { // Compute texture size int i; int wholeTextureExtent[6]; this->GetInput()->GetExtent(wholeTextureExtent); if(this->CellFlag) // if we deal with cell data { i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } } // Indexable hardware limits GLint maxSize; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&maxSize); vtkIdType rTextureSize[3]; double dMaxSize=static_cast(maxSize); i=0; while(i<3) { double textureSize=wholeTextureExtent[2*i+1]-wholeTextureExtent[2*i]+1; if(textureSize>maxSize) { ratio[i]=dMaxSize/textureSize; } else { ratio[i]=1.0; // no reduction } rTextureSize[i]=static_cast(floor(textureSize*ratio[i])); ++i; } // Data memory limits. vtkDataArray *scalars=this->GetScalars(this->GetInput(),this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, this->CellFlag); int scalarType=scalars->GetDataType(); vtkIdType size=rTextureSize[0]*rTextureSize[1]*rTextureSize[2] *vtkAbstractArray::GetDataTypeSize(scalarType) *scalars->GetNumberOfComponents(); if(size>static_cast(this->MaxMemoryInBytes) *static_cast(this->MaxMemoryFraction)) { double r=static_cast(this->MaxMemoryInBytes) *static_cast(this->MaxMemoryFraction)/static_cast(size); double r3=pow(r,1.0/3.0); // try the keep reduction ratio uniform to avoid artifacts. bool reduced[3]; i=0; int count=0; while(i<3) { vtkIdType newSize=static_cast( floor(static_cast(rTextureSize[i])*r3)); reduced[i]=newSize>=1; if(reduced[i]) { ++count; } ++i; } if(count<3) // some axis cannot be reduced { double r2=sqrt(r); count=0; i=0; while(i<3) { if(reduced[i]) { vtkIdType newSize=static_cast( floor(static_cast(rTextureSize[i])*r2)); reduced[i]=newSize>=1; if(reduced[i]) { ++count; } } ++i; } if(count<2) // we can only reduce one axis { i=0; while(i<3) { if(reduced[i]) { ratio[i]*=r; } ++i; } } else // we can reduce two axes { i=0; while(i<3) { if(reduced[i]) { ratio[i]*=r2; } ++i; } } } else // we can reduce all three axes { i=0; while(i<3) { ratio[i]*=r3; ++i; } } } assert("post: valid_i_ratio" && ratio[0]>0 && ratio[0]<=1.0); assert("post: valid_j_ratio" && ratio[1]>0 && ratio[1]<=1.0); assert("post: valid_k_ratio" && ratio[2]>0 && ratio[2]<=1.0); } //----------------------------------------------------------------------------- // Standard print method //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } #endif diff --git a/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.h b/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.h index 262ed748e3..3853505924 100644 --- a/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.h +++ b/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.h @@ -1,526 +1,526 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkMitkOpenGLGPUVolumeRayCastMapper.h,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. =========================================================================*/ // .NAME vtkMitkOpenGLGPUVolumeRayCastMapper - OpenGL subclass that draws the // image to the screen // .SECTION Description // This is the concrete implementation of a ray cast image display helper - // a helper class responsible for drawing the image to the screen. // .SECTION see also // vtkGPUVolumeRayCastMapper #ifndef __vtkMitkOpenGLGPUVolumeRayCastMapper_h #define __vtkMitkOpenGLGPUVolumeRayCastMapper_h #include "vtkMitkGPUVolumeRayCastMapper.h" #include "mitkCommon.h" #include "MitkExtExports.h" // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) class vtkVolume; class vtkRenderer; class vtkOpenGLExtensionManager; class vtkMatrix4x4; class vtkUnsupportedRequiredExtensionsStringStream; // Pimpl class vtkMapDataArrayTextureId; // Pimpl class vtkMapMaskTextureId; // Pimpl class vtkPolyData; class vtkClipConvexPolyData; class vtkClipPolyData; class vtkTessellatedBoxSource; class vtkOpacityTable; // internal class. class vtkRGBTable; // internal class. class vtkKWScalarField; // internal class. class vtkKWMask; // internal class. class vtkOpacityTables; // Pimpl class vtkDensifyPolyData; class vtkStdString; class MitkExt_EXPORT vtkMitkOpenGLGPUVolumeRayCastMapper : public vtkMitkGPUVolumeRayCastMapper { public: static vtkMitkOpenGLGPUVolumeRayCastMapper *New(); - vtkTypeRevisionMacro(vtkMitkOpenGLGPUVolumeRayCastMapper,vtkMitkGPUVolumeRayCastMapper); + vtkTypeMacro(vtkMitkOpenGLGPUVolumeRayCastMapper,vtkMitkGPUVolumeRayCastMapper); virtual void PrintSelf(ostream& os, vtkIndent indent); // Description: // Based on hardware and properties, we may or may not be able to // render using 3D texture mapping. This indicates if 3D texture // mapping is supported by the hardware, and if the other extensions // necessary to support the specific properties are available. virtual int IsRenderSupported(vtkRenderWindow *window, vtkVolumeProperty *property); // Description: // Return a string matching the OpenGL errorCode. // \post result_exists: result!=0 static const char *OpenGLErrorMessage(unsigned int errorCode); // Description: // Display headerMessage on the standard output and the last OpenGL error // message if any. // \pre headerMessage_exists: headerMessage!=0 static void PrintError(const char *headerMessage); protected: vtkMitkOpenGLGPUVolumeRayCastMapper(); ~vtkMitkOpenGLGPUVolumeRayCastMapper(); // The render method called by the superclass virtual void GPURender(vtkRenderer *ren, vtkVolume *vol); // Methods called by the AMR Volume Mapper. virtual void PreRender(vtkRenderer *ren, vtkVolume *vol, double datasetBounds[6], double scalarRange[2], int numberOfScalarComponents, unsigned int numberOfLevels); // \pre input is up-to-date virtual void RenderBlock(vtkRenderer *ren, vtkVolume *vol, unsigned int level); virtual void PostRender(vtkRenderer *ren, int numberOfScalarComponents); // Description: // Return if the required OpenGL extension `extensionName' is supported. // If not, its name is added to the string of unsupported but required // extensions. // \pre extensions_exist: extensions!=0 // \pre extensionName_exists: extensionName!=0 int TestRequiredExtension(vtkOpenGLExtensionManager *extensions, const char *extensionName); // Description: // Attempt to load required and optional OpenGL extensions for the current // context window. Variable LoadExtensionsSucceeded is set if all required // extensions has been loaded. In addition, variable // Supports_GL_ARB_texture_float is set if this extension has been loaded. // \pre: window_exists: window!=0 void LoadExtensions(vtkRenderWindow *window); // Description: // Create GLSL OpenGL objects such fragment program Ids. void CreateGLSLObjects(); // Description: // Allows late binding textures to framebuffers, because ATI openGL requires // the texture to initialized before void BindFramebuffer(); // Description: // Create OpenGL objects such as textures, buffers and fragment program Ids. // It only registers Ids, there is no actual initialization of textures or // fragment program. // \pre extensions_loaded: this->LoadExtensionsSucceeded // \post done: this->OpenGLObjectsCreated==1 void CreateOpenGLObjects(); // Description: // Delete OpenGL objects. // \post done: this->OpenGLObjectsCreated==0 // \deprecatedSince{2013_12} Use ReleaseGraphicsResources(mitk::BaseRenderer* renderer) instead // DEPRECATED(void ReleaseGraphicsResources(vtkWindow *window)); // Description: // Delete OpenGL objects. // \post done: this->OpenGLObjectsCreated==0 // void ReleaseGraphicsResources(mitk::BaseRenderer* renderer); // Description: // Allocate memory on the GPU for the framebuffers according to the size of // the window or reallocate if the size has changed. Return true if // allocation succeeded. // \pre ren_exists: ren!=0 // \pre opengl_objects_created: this->OpenGLObjectsCreated // \post right_size: LastSize[]=window size. int AllocateFrameBuffers(vtkRenderer *ren); // Description // Load the scalar field (one or four component scalar field), cell or point // based for a given subextent of the whole extent (can be the whole extent) // as a 3D texture on the GPU. // Extents are expressed in point if the cell flag is false or in cells of // the cell flag is true. // It returns true if it succeeded, false if there is not enough memory on // the GPU. // If succeeded, it updates the LoadedExtent, LoadedBounds, LoadedCellFlag // and LoadedTime. It also succeed if the scalar field is already loaded // (ie since last load, input has not changed and cell flag has not changed // and requested texture extents are enclosed in the loaded extent). // \pre input_exists: input!=0 // \pre valid_point_extent: (this->CellFlag || // (textureExtent[0]CellFlag || // (textureExtent[0]<=textureExtent[1] && // textureExtent[2]<=textureExtent[3] && // textureExtent[4]<=textureExtent[5]))) int LoadScalarField(vtkImageData *input, vtkImageData *maskInput, int textureExtent[6], vtkVolume *volume); // Description: // Allocate memory and load color table on the GPU or // reload it if the transfer function changed. // \pre vol_exists: vol!=0 // \pre valid_numberOfScalarComponents: numberOfScalarComponents==1 || numberOfScalarComponents==4 int UpdateColorTransferFunction(vtkVolume *vol, int numberOfScalarComponents); // Description: // Allocate memory and load opacity table on the GPU or // reload it if the transfer functions changed. // \pre vol_exists: vol!=0 // \pre valid_numberOfScalarComponents: numberOfScalarComponents==1 || numberOfScalarComponents==4 int UpdateOpacityTransferFunction(vtkVolume *vol, int numberOfScalarComponents, unsigned int level); // Description: // Prepare rendering in the offscreen framebuffer. // \pre ren_exists: ren!=0 // \pre vol_exists: vol!=0 void SetupRender(vtkRenderer *ren, vtkVolume *vol); // Description: // Clip the bounding box with all clipping planes // and the near and far plane void ClipBoundingBox(vtkRenderer *ren, double worldBounds[6], vtkVolume *vol); // Description: // Render the bounding box. The flag indicates whether // or not tcoords are rendered too. Return abort status (true==abort). // \pre valid_currentBlock: currentBlock>=0 && currentBlock=0 // \post valid_result: result>=x int PowerOfTwoGreaterOrEqual(int x); // Description: // Display the status of the current framebuffer on the standard output. void CheckFrameBufferStatus(); // Description: // Create a string from a buffer id. The result has to be free by the caller. vtkStdString BufferToString(int buffer); // Description: // Display the buffers assigned for drawing and reading operations. void DisplayReadAndDrawBuffers(); // Description: // Display all the attachments of the current framebuffer object. void DisplayFrameBufferAttachments(); // Description: // Display a given attachment for the current framebuffer object. void DisplayFrameBufferAttachment(unsigned int uattachment); // Description: // Concatenate the header string, projection type code and method to the // final fragment code in this->FragmentCode. // \pre valid_raycastMethod: raycastMethod>= vtkMitkOpenGLGPUVolumeRayCastMapperMethodMaximumIntensityProjection && raycastMethod<=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIPFourDependent void BuildProgram(int parallelProjection, int raycastMethod, int shadeMethod, int componentMethod); // Description: // Return the current OpenGL state about lighting. void GetLightingStatus(); // Description: // Check the compilation status of some fragment shader source. void CheckCompilation(unsigned int fragmentShader); // Description: // Check the linkage status of the fragment program. int CheckLinkage(unsigned int programShader); // Description: // Print all active uniform variables void PrintUniformVariables(unsigned int programShader); // Description: // Is the program shader valid in the current OpenGL state? // Debugging purpose only. void ValidateProgram(); // Description: // Update the reduction factor of the render viewport (this->ReductionFactor) // according to the time spent in seconds to render the previous frame // (this->TimeToDraw) and a time in seconds allocated to render the next // frame (allocatedTime). // \pre valid_current_reduction_range: this->ReductionFactor>0.0 && this->ReductionFactor<=1.0 // \pre positive_TimeToDraw: this->TimeToDraw>=0.0 // \pre positive_time: allocatedTime>0 // \post valid_new_reduction_range: this->ReductionFactor>0.0 && this->ReductionFactor<=1.0 void ComputeReductionFactor(double allocatedTime); // Description: // Render a subvolume. // \pre this->ProgramShader!=0 and is linked. void RenderWholeVolume(vtkRenderer *ren, vtkVolume *vol); // Description: // Render a subvolume. // \pre this->ProgramShader!=0 and is linked. void RenderRegions(vtkRenderer *ren, vtkVolume *vol); // Return abort status (true==abort) int RenderSubVolume(vtkRenderer *ren, double bounds[6], vtkVolume *vol); void LoadProjectionParameters(vtkRenderer *ren, vtkVolume *vol); // Description: // Compute and return the number of cropping regions void ComputeNumberOfCroppingRegions(); void GetTextureFormat(vtkImageData *input, unsigned int *internalFormat, unsigned int *format, unsigned int *type, int *componentSize); bool TestLoadingScalar(unsigned int internalFormat, unsigned int format, unsigned int type, int textureSize[3], int componentSize); void SlabsFromDatasetToIndex(double slabsDataSet[6], double slabsPoints[6]); void SlabsFromIndexToDataset(double slabsPoints[6], double slabsDataSet[6]); const char *GetEnabledString(unsigned char value); void GetOpenGLState(); void DebugDisplayBox(vtkPolyData *box); void UpdateNoiseTexture(); // Description: // Compute how each axis of a cell is projected on the viewport in pixel. // This requires to have information about the camera and about the volume. // It set the value of IgnoreSampleDistancePerPixel to true in case of // degenerated case (axes aligned with the view). double ComputeMinimalSampleDistancePerPixel(vtkRenderer *renderer, vtkVolume *volume); // Description: // Return how much the dataset has to be reduced in each dimension to // fit on the GPU. If the value is 1.0, there is no need to reduce the // dataset. // \pre the calling thread has a current OpenGL context. // \pre mapper_supported: IsRenderSupported(renderer->GetRenderWindow(),0) // The computation is based on hardware limits (3D texture indexable size) // and MaxMemoryInBytes. // \post valid_i_ratio: ratio[0]>0 && ratio[0]<=1.0 // \post valid_j_ratio: ratio[1]>0 && ratio[1]<=1.0 // \post valid_k_ratio: ratio[2]>0 && ratio[2]<=1.0 virtual void GetReductionRatio(double ratio[3]); bool m_BindMax; int NumberOfCroppingRegions; // World coordinates of each corner of the dataset. double BoundingBox[8][3]; // Used during the clipping process. vtkPolyData *PolyDataBoundingBox; vtkPlaneCollection *Planes; vtkPlane *NearPlane; vtkClipConvexPolyData *Clip; vtkMatrix4x4 *InvVolumeMatrix; vtkDensifyPolyData *Densify; int OpenGLObjectsCreated; int NumberOfFrameBuffers; unsigned int FrameBufferObject; unsigned int DepthRenderBufferObject; // 3D scalar texture +1D color+1D opacity+2D grabbed depth buffer // +1 2D colorbuffer. unsigned int TextureObjects[5]; unsigned int FragmentMainShader; unsigned int FragmentProjectionShader; unsigned int FragmentTraceShader; unsigned int FragmentCroppingShader; unsigned int FragmentComponentShader; unsigned int FragmentShadeShader; unsigned int ProgramShader; // used in MIP Mode (2 needed for ping-pong technique) unsigned int MaxValueFrameBuffer; unsigned int MaxValueFrameBuffer2; int ReducedSize[2]; vtkPolyData *ClippedBoundingBox; int LastSize[2]; double ReductionFactor; // Supported extensions // List of unsupported required extensions. Pimpl. vtkUnsupportedRequiredExtensionsStringStream *UnsupportedRequiredExtensions; int LoadExtensionsSucceeded; int Supports_GL_ARB_texture_float; int SupportsPixelBufferObjects; vtkTimeStamp DataBufferTime; // Matrices used in internal computation. As a member variable, // only one memory allocation is performed. vtkMatrix4x4 *TempMatrix[3]; double TableRange[2]; // Final string to send to the GPU as the fragment program source code. // char *FragmentCode; // int FragmentCodeCapacity; int ErrorLine; int ErrorColumn; char *ErrorString; // Store the last projection an raycast method in order to not rebuild // the fragment code at every call. int LastParallelProjection; int LastRayCastMethod; int LastCroppingMode; int LastComponent; int LastShade; vtkImageData *SmallInput; vtkTimeStamp SmallInputBuildTime; // Description: // Build the fragment shader program that scale and bias a texture // for window/level purpose. void BuildScaleBiasProgram(); unsigned int ScaleBiasProgramShader; // GLuint int UFrameBufferTexture; // GLint int UScale; // GLint int UBias; // GLint #if 0 vtkIdType LoadedExtent[6]; double LoadedBounds[6]; vtkTimeStamp LoadedScalarTime; int LoadedCellFlag; // point data or cell data (or field data, not handled) ? #endif unsigned int SavedFrameBuffer; // some offscreen mode use a framebuffer too. vtkTessellatedBoxSource *BoxSource; float *NoiseTexture; int NoiseTextureSize; // size of one dimension. unsigned int NoiseTextureId; // GLuint bool IgnoreSampleDistancePerPixel; vtkMapDataArrayTextureId *ScalarsTextures; // need a list for AMR mode. vtkMapMaskTextureId *MaskTextures; // need a list for AMR mode. vtkRGBTable *RGBTable; vtkRGBTable *Mask1RGBTable; vtkRGBTable *Mask2RGBTable; vtkOpacityTables *OpacityTables; vtkKWScalarField *CurrentScalar; vtkKWMask *CurrentMask; float ActualSampleDistance; double LastProgressEventTime; // initial value is 0.0. Expressed in seconds. bool PreserveOrientation; private: vtkMitkOpenGLGPUVolumeRayCastMapper(const vtkMitkOpenGLGPUVolumeRayCastMapper&); // Not implemented. void operator=(const vtkMitkOpenGLGPUVolumeRayCastMapper&); // Not implemented. }; #endif #endif diff --git a/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp b/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp index b73dc50dd0..498f08493a 100644 --- a/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp +++ b/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp @@ -1,2458 +1,2457 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifdef _OPENMP #include #endif #include "vtkWindows.h" #include "vtkMitkOpenGLVolumeTextureMapper3D.h" #include "mitkCommon.h" #define GPU_INFO MITK_INFO("mapper.vr") #define GPU_WARN MITK_WARN("mapper.vr") #include "vtkImageData.h" #include "vtkMatrix4x4.h" #include "vtkDataArray.h" #include "vtkObjectFactory.h" #include "vtkPlane.h" #include "vtkPlaneCollection.h" #include "vtkPointData.h" #include "vtkRenderWindow.h" #include "vtkRenderer.h" #include "vtkTimerLog.h" #include "vtkVolumeProperty.h" #include "vtkTransform.h" #include "vtkLightCollection.h" #include "vtkLight.h" #include "vtkCamera.h" #include "vtkMath.h" #include "vtkOpenGLExtensionManager.h" #include "vtkgl.h" #include "vtkOpenGLRenderWindow.h" #define myGL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define myGL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 #define myGL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 const char *vtkMitkVolumeTextureMapper3D_FourDependentShadeFP = "!!ARBfp1.0\n" //# We need some temporary variables "TEMP index, normal, finalColor;\n" "TEMP temp,temp1, temp2, temp3,temp4; \n" "TEMP sampleColor;\n" "TEMP ndotl, ndoth, ndotv; \n" "TEMP lightInfo, lightResult;\n" //# We are going to use the first //# texture coordinate "ATTRIB tex0 = fragment.texcoord[0];\n" //# This is the lighting information "PARAM lightDirection = program.local[0];\n" "PARAM halfwayVector = program.local[1];\n" "PARAM coefficient = program.local[2];\n" "PARAM lightDiffColor = program.local[3]; \n" "PARAM lightSpecColor = program.local[4]; \n" "PARAM viewVector = program.local[5];\n" "PARAM constants = program.local[6];\n" //# This is our output color "OUTPUT out = result.color;\n" //# Look up the gradient direction //# in the third volume "TEX temp2, tex0, texture[0], 3D;\n" //# This normal is stored 0 to 1, change to -1 to 1 //# by multiplying by 2.0 then adding -1.0. "MAD normal, temp2, constants.x, constants.y;\n" "DP3 temp4, normal, normal;\n" "RSQ temp, temp4.x;\n" "MUL normal, normal, temp;\n" //"RCP temp4,temp.x;\n" //"MUL temp2.w,temp2.w,temp4.x;\n" //"MUL_SAT temp2.w,temp2.w,6.0;\n" "TEX sampleColor, tex0, texture[1], 3D;\n" //# Take the dot product of the light //# direction and the normal "DP3 ndotl, normal, lightDirection;\n" //# Take the dot product of the halfway //# vector and the normal "DP3 ndoth, normal, halfwayVector;\n" "DP3 ndotv, normal, viewVector;\n" //# flip if necessary for two sided lighting "MUL temp3, ndotl, constants.y; \n" "CMP ndotl, ndotv, ndotl, temp3;\n" "MUL temp3, ndoth, constants.y; \n" "CMP ndoth, ndotv, ndoth, temp3;\n" //# put the pieces together for a LIT operation "MOV lightInfo.x, ndotl.x; \n" "MOV lightInfo.y, ndoth.x; \n" "MOV lightInfo.w, coefficient.w; \n" //# compute the lighting "LIT lightResult, lightInfo;\n" //# COLOR FIX "MUL lightResult, lightResult, 4.0;\n" //# This is the ambient contribution "MUL finalColor, coefficient.x, sampleColor;\n" //# This is the diffuse contribution "MUL temp3, lightDiffColor, sampleColor;\n" "MUL temp3, temp3, lightResult.y;\n" "ADD finalColor, finalColor, temp3;\n" //# This is th specular contribution "MUL temp3, lightSpecColor, lightResult.z; \n" //# Add specular into result so far, and replace //# with the original alpha. "ADD out, finalColor, temp3;\n" "MOV out.w, temp2.w;\n" "END\n"; const char *vtkMitkVolumeTextureMapper3D_OneComponentShadeFP = "!!ARBfp1.0\n" //# This is the fragment program for one //# component data with shading //# We need some temporary variables "TEMP index, normal, finalColor;\n" "TEMP temp,temp1, temp2, temp3,temp4; \n" "TEMP sampleColor;\n" "TEMP ndotl, ndoth, ndotv; \n" "TEMP lightInfo, lightResult;\n" //# We are going to use the first //# texture coordinate "ATTRIB tex0 = fragment.texcoord[0];\n" //# This is the lighting information "PARAM lightDirection = program.local[0];\n" "PARAM halfwayVector = program.local[1];\n" "PARAM coefficient = program.local[2];\n" "PARAM lightDiffColor = program.local[3]; \n" "PARAM lightSpecColor = program.local[4]; \n" "PARAM viewVector = program.local[5];\n" "PARAM constants = program.local[6];\n" //# This is our output color "OUTPUT out = result.color;\n" //# Look up the gradient direction //# in the third volume "TEX temp2, tex0, texture[0], 3D;\n" // Gradient Compution //# Look up the scalar value / gradient //# magnitude in the first volume //"TEX temp1, tex0, texture[0], 3D;\n" /* "ADD temp3,tex0,{-0.005,0,0};\n" "TEX temp2,temp3, texture[0], 3D;\n" //"ADD temp3,tex0,{ 0.005,0,0};\n" //"TEX temp1,temp3, texture[0], 3D;\n" "SUB normal.x,temp2.y,temp1.y;\n" "ADD temp3,tex0,{0,-0.005,0};\n" "TEX temp2,temp3, texture[0], 3D;\n" //"ADD temp3,tex0,{0, 0.005,0};\n" //"TEX temp1,temp3, texture[0], 3D;\n" "SUB normal.y,temp2.y,temp1.y;\n" "ADD temp3,tex0,{0,0,-0.005};\n" "TEX temp2,temp3, texture[0], 3D;\n" //"ADD temp3,tex0,{0,0, 0.005};\n" //"TEX temp1,temp3, texture[0], 3D;\n" "SUB normal.z,temp2.y,temp1.y;\n" */ //"MOV normal,{1,1,1};\n" "MOV index.x,temp2.a;\n" //# This normal is stored 0 to 1, change to -1 to 1 //# by multiplying by 2.0 then adding -1.0. "MAD normal, temp2, constants.x, constants.y;\n" //# Swizzle this to use (a,r) as texture //# coordinates //"SWZ index, temp1, a, r, 1, 1;\n" //# Use this coordinate to look up a //# final color in the third texture //# (this is a 2D texture) "DP3 temp4, normal, normal;\n" "RSQ temp, temp4.x;\n" "RCP temp4,temp.x;\n" "MUL normal, normal, temp;\n" "MOV index.y, temp4.x;\n" "TEX sampleColor, index, texture[1], 2D;\n" //"MUL sampleColor.w,sampleColor.w,temp4.x;\n" //# Take the dot product of the light //# direction and the normal "DP3 ndotl, normal, lightDirection;\n" //# Take the dot product of the halfway //# vector and the normal "DP3 ndoth, normal, halfwayVector;\n" "DP3 ndotv, normal, viewVector;\n" //# flip if necessary for two sided lighting "MUL temp3, ndotl, constants.y; \n" "CMP ndotl, ndotv, ndotl, temp3;\n" "MUL temp3, ndoth, constants.y; \n" "CMP ndoth, ndotv, ndoth, temp3;\n" //# put the pieces together for a LIT operation "MOV lightInfo.x, ndotl.x; \n" "MOV lightInfo.y, ndoth.x; \n" "MOV lightInfo.w, coefficient.w; \n" //# compute the lighting "LIT lightResult, lightInfo;\n" //# COLOR FIX "MUL lightResult, lightResult, 4.0;\n" //# This is the ambient contribution "MUL finalColor, coefficient.x, sampleColor;\n" //# This is the diffuse contribution "MUL temp3, lightDiffColor, sampleColor;\n" "MUL temp3, temp3, lightResult.y;\n" "ADD finalColor, finalColor, temp3;\n" //# This is th specular contribution "MUL temp3, lightSpecColor, lightResult.z; \n" //# Add specular into result so far, and replace //# with the original alpha. "ADD out, finalColor, temp3;\n" "MOV out.w, sampleColor.w;\n" "END\n"; //#ifndef VTK_IMPLEMENT_MESA_CXX -vtkCxxRevisionMacro(vtkMitkOpenGLVolumeTextureMapper3D, "$Revision: 1.21 $"); vtkStandardNewMacro(vtkMitkOpenGLVolumeTextureMapper3D); //#endif vtkMitkOpenGLVolumeTextureMapper3D::vtkMitkOpenGLVolumeTextureMapper3D() { //GPU_INFO << "vtkMitkOpenGLVolumeTextureMapper3D"; this->Initialized = 0; this->Volume1Index = 0; this->Volume2Index = 0; this->Volume3Index = 0; this->ColorLookupIndex = 0; this->AlphaLookupIndex = 0; this->RenderWindow = NULL; this->SupportsCompressedTexture = false; prgOneComponentShade = 0; prgRGBAShade = 0; } vtkMitkOpenGLVolumeTextureMapper3D::~vtkMitkOpenGLVolumeTextureMapper3D() { //GPU_INFO << "~vtkMitkOpenGLVolumeTextureMapper3D"; if(prgOneComponentShade) vtkgl::DeleteProgramsARB( 1, &prgOneComponentShade ); if(prgRGBAShade) vtkgl::DeleteProgramsARB( 1, &prgRGBAShade ); } // Release the graphics resources used by this texture. void vtkMitkOpenGLVolumeTextureMapper3D::ReleaseGraphicsResources(vtkWindow *renWin) { //GPU_INFO << "ReleaseGraphicsResources"; if (( this->Volume1Index || this->Volume2Index || this->Volume3Index || this->ColorLookupIndex) && renWin) { static_cast(renWin)->MakeCurrent(); #ifdef GL_VERSION_1_1 // free any textures this->DeleteTextureIndex( &this->Volume1Index ); this->DeleteTextureIndex( &this->Volume2Index ); this->DeleteTextureIndex( &this->Volume3Index ); this->DeleteTextureIndex( &this->ColorLookupIndex ); this->DeleteTextureIndex( &this->AlphaLookupIndex ); #endif } this->Volume1Index = 0; this->Volume2Index = 0; this->Volume3Index = 0; this->ColorLookupIndex = 0; this->RenderWindow = NULL; this->SupportsCompressedTexture=false; this->SupportsNonPowerOfTwoTextures=false; this->Modified(); } // Release the graphics resources used by this texture. void vtkMitkOpenGLVolumeTextureMapper3D::ReleaseGraphicsResources(mitk::BaseRenderer* renderer) { //GPU_INFO << "ReleaseGraphicsResources"; vtkWindow * renWin = renderer->GetVtkRenderer()->GetRenderWindow(); if (( this->Volume1Index || this->Volume2Index || this->Volume3Index || this->ColorLookupIndex) && renWin) { static_cast(renWin)->MakeCurrent(); #ifdef GL_VERSION_1_1 // free any textures this->DeleteTextureIndex( &this->Volume1Index ); this->DeleteTextureIndex( &this->Volume2Index ); this->DeleteTextureIndex( &this->Volume3Index ); this->DeleteTextureIndex( &this->ColorLookupIndex ); this->DeleteTextureIndex( &this->AlphaLookupIndex ); #endif } this->Volume1Index = 0; this->Volume2Index = 0; this->Volume3Index = 0; this->ColorLookupIndex = 0; this->RenderWindow = NULL; this->SupportsCompressedTexture=false; this->SupportsNonPowerOfTwoTextures=false; this->Modified(); } void vtkMitkOpenGLVolumeTextureMapper3D::Render(vtkRenderer *ren, vtkVolume *vol) { //GPU_INFO << "Render"; ren->GetRenderWindow()->MakeCurrent(); if ( !this->Initialized ) { //this->Initialize(); this->Initialize(ren); } if ( !this->RenderPossible ) { vtkErrorMacro( "required extensions not supported" ); return; } vtkMatrix4x4 *matrix = vtkMatrix4x4::New(); vtkPlaneCollection *clipPlanes; vtkPlane *plane; int numClipPlanes = 0; double planeEquation[4]; // build transformation vol->GetMatrix(matrix); matrix->Transpose(); glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT | GL_TEXTURE_BIT); int i; // 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(static_cast(GL_CLIP_PLANE0+i)); plane = static_cast(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(static_cast(GL_CLIP_PLANE0+i),planeEquation); } } // insert model transformation glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glMultMatrixd(matrix->Element[0]); glColor4f( 1.0, 1.0, 1.0, 1.0 ); // Turn lighting off - the polygon textures already have illumination glDisable( GL_LIGHTING ); vtkGraphicErrorMacro(ren->GetRenderWindow(),"Before actual render method"); this->RenderFP(ren,vol); // pop transformation matrix glMatrixMode( GL_MODELVIEW ); glPopMatrix(); matrix->Delete(); glPopAttrib(); } void vtkMitkOpenGLVolumeTextureMapper3D::RenderFP(vtkRenderer *ren, vtkVolume *vol) { //GPU_INFO << "RenderFP"; /* glAlphaFunc (GL_GREATER, static_cast(1.0/255.0)); glEnable (GL_ALPHA_TEST); */ glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); int components = this->GetInput()->GetNumberOfScalarComponents(); switch ( components ) { case 1: this->RenderOneIndependentShadeFP(ren,vol); break; case 4: this->RenderRGBAShadeFP(ren,vol); break; } vtkgl::ActiveTexture( vtkgl::TEXTURE2); glDisable( GL_TEXTURE_2D ); glDisable( vtkgl::TEXTURE_3D ); vtkgl::ActiveTexture( vtkgl::TEXTURE1); glDisable( GL_TEXTURE_2D ); glDisable( vtkgl::TEXTURE_3D ); vtkgl::ActiveTexture( vtkgl::TEXTURE0); glDisable( GL_TEXTURE_2D ); glDisable( vtkgl::TEXTURE_3D ); glDisable( GL_BLEND ); } void vtkMitkOpenGLVolumeTextureMapper3D::DeleteTextureIndex( GLuint *index ) { //GPU_INFO << "DeleteTextureIndex"; if (glIsTexture(*index)) { GLuint tempIndex; tempIndex = *index; glDeleteTextures(1, &tempIndex); *index = 0; } } void vtkMitkOpenGLVolumeTextureMapper3D::CreateTextureIndex( GLuint *index ) { //GPU_INFO << "CreateTextureIndex"; GLuint tempIndex=0; glGenTextures(1, &tempIndex); *index = static_cast(tempIndex); } void vtkMitkOpenGLVolumeTextureMapper3D::RenderPolygons( vtkRenderer *ren, vtkVolume *vol, int stages[4] ) { //GPU_INFO << "RenderPolygons"; vtkRenderWindow *renWin = ren->GetRenderWindow(); if ( renWin->CheckAbortStatus() ) { return; } double bounds[27][6]; float distance2[27]; int numIterations; int i, j, k; // No cropping case - render the whole thing if ( !this->Cropping ) { // Use the input data bounds - we'll take care of the volume's // matrix during rendering this->GetInput()->GetBounds(bounds[0]); numIterations = 1; } // Simple cropping case - render the subvolume else if ( this->CroppingRegionFlags == 0x2000 ) { this->GetCroppingRegionPlanes(bounds[0]); numIterations = 1; } // Complex cropping case - render each region in back-to-front order else { // Get the camera position double camPos[4]; ren->GetActiveCamera()->GetPosition(camPos); double volBounds[6]; this->GetInput()->GetBounds(volBounds); // Pass camera through inverse volume matrix // so that we are in the same coordinate system vtkMatrix4x4 *volMatrix = vtkMatrix4x4::New(); vol->GetMatrix( volMatrix ); camPos[3] = 1.0; volMatrix->Invert(); volMatrix->MultiplyPoint( camPos, camPos ); volMatrix->Delete(); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } // These are the region limits for x (first four), y (next four) and // z (last four). The first region limit is the lower bound for // that axis, the next two are the region planes along that axis, and // the final one in the upper bound for that axis. float limit[12]; for ( i = 0; i < 3; i++ ) { limit[i*4 ] = volBounds[i*2]; limit[i*4+1] = this->CroppingRegionPlanes[i*2]; limit[i*4+2] = this->CroppingRegionPlanes[i*2+1]; limit[i*4+3] = volBounds[i*2+1]; } // For each of the 27 possible regions, find out if it is enabled, // and if so, compute the bounds and the distance from the camera // to the center of the region. int numRegions = 0; int region; for ( region = 0; region < 27; region++ ) { int regionFlag = 1<CroppingRegionFlags & regionFlag ) { // what is the coordinate in the 3x3x3 grid int loc[3]; loc[0] = region%3; loc[1] = (region/3)%3; loc[2] = (region/9)%3; // compute the bounds and center float center[3]; for ( i = 0; i < 3; i++ ) { bounds[numRegions][i*2 ] = limit[4*i+loc[i]]; bounds[numRegions][i*2+1] = limit[4*i+loc[i]+1]; center[i] = (bounds[numRegions][i*2 ] + bounds[numRegions][i*2+1])/2.0; } // compute the distance squared to the center distance2[numRegions] = (camPos[0]-center[0])*(camPos[0]-center[0]) + (camPos[1]-center[1])*(camPos[1]-center[1]) + (camPos[2]-center[2])*(camPos[2]-center[2]); // we've added one region numRegions++; } } // Do a quick bubble sort on distance for ( i = 1; i < numRegions; i++ ) { for ( j = i; j > 0 && distance2[j] > distance2[j-1]; j-- ) { float tmpBounds[6]; float tmpDistance2; for ( k = 0; k < 6; k++ ) { tmpBounds[k] = bounds[j][k]; } tmpDistance2 = distance2[j]; for ( k = 0; k < 6; k++ ) { bounds[j][k] = bounds[j-1][k]; } distance2[j] = distance2[j-1]; for ( k = 0; k < 6; k++ ) { bounds[j-1][k] = tmpBounds[k]; } distance2[j-1] = tmpDistance2; } } numIterations = numRegions; } // loop over all regions we need to render for ( int loop = 0; loop < numIterations; loop++ ) { // Compute the set of polygons for this region // according to the bounds this->ComputePolygons( ren, vol, bounds[loop] ); // Loop over the polygons for ( i = 0; i < this->NumberOfPolygons; i++ ) { if ( renWin->CheckAbortStatus() ) { return; } float *ptr = this->PolygonBuffer + 36*i; glBegin( GL_TRIANGLE_FAN ); for ( j = 0; j < 6; j++ ) { if ( ptr[0] < 0.0 ) { break; } for ( k = 0; k < 4; k++ ) { if ( stages[k] ) { vtkgl::MultiTexCoord3fv( vtkgl::TEXTURE0 + k, ptr ); } } glVertex3fv( ptr+3 ); ptr += 6; } glEnd(); } } } // This method moves the scalars from the input volume into volume1 (and // possibly volume2) which are the 3D texture maps used for rendering. // // In the case where our volume is a power of two, the copy is done // directly. If we need to resample, then trilinear interpolation is used. // // A shift/scale is applied to the input scalar value to produce an 8 bit // value for the texture volume. // // When the input data is one component, the scalar value is placed in the // second component of the two component volume1. The first component is // filled in later with the gradient magnitude. // // When the input data is two component non-independent, the first component // of the input data is placed in the first component of volume1, and the // second component of the input data is placed in the third component of // volume1. Volume1 has three components - the second is filled in later with // the gradient magnitude. // // When the input data is four component non-independent, the first three // components of the input data are placed in volume1 (which has three // components), and the fourth component is placed in the second component // of volume2. The first component of volume2 is later filled in with the // gradient magnitude. template class ScalarGradientCompute { T *dataPtr; unsigned char *tmpPtr; unsigned char *tmpPtr2; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; int fullX; int fullY; int fullZ; int fullXY; int currentChunkStart; int currentChunkEnd; int offZ; float offset; float scale; public: ScalarGradientCompute( T *_dataPtr,unsigned char *_tmpPtr,unsigned char *_tmpPtr2,int _sizeX,int _sizeY,int _sizeZ,int _fullX,int _fullY,int _fullZ,float _offset,float _scale) { dataPtr=_dataPtr; tmpPtr=_tmpPtr; tmpPtr2=_tmpPtr2; sizeX=_sizeX; sizeY=_sizeY; sizeZ=_sizeZ; fullX=_fullX; fullY=_fullY; fullZ=_fullZ; offset=_offset; scale=_scale; sizeXY=sizeX*sizeY; sizeXm1=sizeX-1; sizeYm1=sizeY-1; sizeZm1=sizeZ-1; fullXY=fullX*fullY; } inline float sample(int x,int y,int z) { return float(dataPtr[ x + y * sizeX + z * sizeXY ]); } inline void fill(int x,int y,int z) { int doff = x + y * fullX + (z-offZ) * fullXY; tmpPtr[doff*4+0]= 0; tmpPtr[doff*4+1]= 0; tmpPtr[doff*4+2]= 0; tmpPtr[doff*4+3]= 0; /* tmpPtr2[doff*3+0]= 0; tmpPtr2[doff*3+1]= 0; tmpPtr2[doff*3+2]= 0; */ } inline int clamp(int x) { if(x<0) x=0; else if(x>255) x=255; return x; } inline void write(int x,int y,int z,float grayValue,float gx,float gy,float gz) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude int iGrayValue = static_cast( (grayValue + offset) * scale + 0.5f ); gx *= scale; gy *= scale; gz *= scale; float t = sqrtf( gx*gx + gy*gy + gz*gz ); if ( t > 0.01f ) { if( t < 2.0f ) { float fac = 2.0f/t; gx *= fac; gy *= fac; gz *= fac; } else if( t > 255.0f) { float fac = 255.0f/t; gx *= fac; gy *= fac; gz *= fac; } } else { gx=gy=gz=0.0f; } int nx = static_cast(0.5f*gx+127.5f); int ny = static_cast(0.5f*gy+127.5f); int nz = static_cast(0.5f*gz+127.5f); int doff = x + y * fullX + (z-offZ) * fullXY; //tmpPtr[doff*2+0]= 0; tmpPtr[doff*4+0]= clamp(nx); tmpPtr[doff*4+1]= clamp(ny); tmpPtr[doff*4+2]= clamp(nz); tmpPtr[doff*4+3]= clamp(iGrayValue); /* if( z == fullZ/2 ) if( y == fullY/2 ) MITK_INFO << x << " " << y << " " << z << " : " << iGrayValue << " : " << iGradient; */ } inline void compute(int x,int y,int z) { float grayValue = sample(x,y,z); float gx,gy,gz; gx = sample(x+1,y,z) - sample(x-1,y,z); gy = sample(x,y+1,z) - sample(x,y-1,z); gz = sample(x,y,z+1) - sample(x,y,z-1); write( x, y, z, grayValue, gx, gy, gz ); } inline void computeClamp(int x,int y,int z) { float grayValue = sample(x,y,z); float gx,gy,gz; if(x==0) gx = 2.0f * ( sample(x+1,y,z) - grayValue ); else if(x==sizeXm1) gx = 2.0f * ( grayValue - sample(x-1,y,z) ); else gx = sample(x+1,y,z) - sample(x-1,y,z); if(y==0) gy = 2.0f * ( sample(x,y+1,z) - grayValue ); else if(y==sizeYm1) gy = 2.0f * ( grayValue - sample(x,y-1,z) ); else gy = sample(x,y+1,z) - sample(x,y-1,z); if(z==0) gz = 2.0f * ( sample(x,y,z+1) - grayValue ); else if(z==sizeZm1) gz = 2.0f * ( grayValue - sample(x,y,z-1) ); else gz = sample(x,y,z+1) - sample(x,y,z-1); write( x, y, z, grayValue, gx, gy, gz ); } inline void compute1D(int y,int z) { int x; x=0; computeClamp(x,y,z); x++; while(x=sizeZ) fill2D(z); else compute2D(z); } } }; template void vtkVolumeTextureMapper3DComputeScalars( T *dataPtr, vtkMitkVolumeTextureMapper3D *me, float offset, float scale, GLuint volume1, GLuint /*volume2*/) { T *inPtr; // unsigned char *outPtr, *outPtr2; // int i, j, k; // int idx; int inputDimensions[3]; double inputSpacing[3]; vtkImageData *input = me->GetInput(); input->GetDimensions( inputDimensions ); input->GetSpacing( inputSpacing ); int outputDimensions[3]; float outputSpacing[3]; me->GetVolumeDimensions( outputDimensions ); me->GetVolumeSpacing( outputSpacing ); // int components = input->GetNumberOfScalarComponents(); // double wx, wy, wz; // double fx, fy, fz; // int x, y, z; double sampleRate[3]; sampleRate[0] = outputSpacing[0] / static_cast(inputSpacing[0]); sampleRate[1] = outputSpacing[1] / static_cast(inputSpacing[1]); sampleRate[2] = outputSpacing[2] / static_cast(inputSpacing[2]); int fullX = outputDimensions[0]; int fullY = outputDimensions[1]; int fullZ = outputDimensions[2]; int sizeX = inputDimensions[0]; int sizeY = inputDimensions[1]; int sizeZ = inputDimensions[2]; int chunkSize = 64; if(fullZ < chunkSize) chunkSize=fullZ; int numChunks = ( fullZ + (chunkSize-1) ) / chunkSize; inPtr = dataPtr; unsigned char *tmpPtr = new unsigned char[fullX*fullY*chunkSize*4]; unsigned char *tmpPtr2 = 0;//new unsigned char[fullX*fullY*chunkSize*3]; // For each Chunk { ScalarGradientCompute sgc(dataPtr,tmpPtr,tmpPtr2,sizeX,sizeY,sizeZ,fullX,fullY,fullZ,offset,scale); int currentChunk = 0; while(currentChunk < numChunks) { // MITK_INFO << "processing chunk " << currentChunk; int currentChunkStart = currentChunk * chunkSize; int currentChunkEnd = currentChunkStart + chunkSize - 1 ; if( currentChunkEnd > (fullZ-1) ) currentChunkEnd = (fullZ-1); int currentChunkSize = currentChunkEnd - currentChunkStart + 1; sgc.fillSlices( currentChunkStart , currentChunkEnd ); glBindTexture(vtkgl::TEXTURE_3D, volume1); vtkgl::TexSubImage3D(vtkgl::TEXTURE_3D,0,0,0,currentChunkStart,fullX,fullY,currentChunkSize,GL_RGBA,GL_UNSIGNED_BYTE,tmpPtr); /* glBindTexture(vtkgl::TEXTURE_3D, volume2); vtkgl::TexSubImage3D(vtkgl::TEXTURE_3D,0,0,0,currentChunkStart,fullX,fullY,currentChunkSize,GL_RGB,GL_UNSIGNED_BYTE,tmpPtr2); */ currentChunk ++; } } delete tmpPtr; // delete tmpPtr2; } class RGBACompute { unsigned char *dataPtr; unsigned char *tmpPtr; unsigned char *tmpPtr2; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; int fullX; int fullY; int fullZ; int fullXY; int currentChunkStart; int currentChunkEnd; int offZ; public: RGBACompute( unsigned char *_dataPtr,unsigned char *_tmpPtr,unsigned char *_tmpPtr2,int _sizeX,int _sizeY,int _sizeZ,int _fullX,int _fullY,int _fullZ) { dataPtr=_dataPtr; tmpPtr=_tmpPtr; tmpPtr2=_tmpPtr2; sizeX=_sizeX; sizeY=_sizeY; sizeZ=_sizeZ; fullX=_fullX; fullY=_fullY; fullZ=_fullZ; sizeXY=sizeX*sizeY; sizeXm1=sizeX-1; sizeYm1=sizeY-1; sizeZm1=sizeZ-1; fullXY=fullX*fullY; } inline int sample(int x,int y,int z) { return dataPtr[ ( x + y * sizeX + z * sizeXY ) * 4 +3 ]; } inline void fill(int x,int y,int z) { int doff = x + y * fullX + (z-offZ) * fullXY; tmpPtr[doff*4+0]= 0; tmpPtr[doff*4+1]= 0; tmpPtr[doff*4+2]= 0; tmpPtr[doff*4+3]= 0; tmpPtr2[doff*3+0]= 0; tmpPtr2[doff*3+1]= 0; tmpPtr2[doff*3+2]= 0; } inline int clamp(int x) { if(x<0) x=0; else if(x>255) x=255; return x; } inline void write(int x,int y,int z,int iGrayValue,int gx,int gy,int gz) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ int nx = static_cast(0.5f*gx+127.5f); int ny = static_cast(0.5f*gy+127.5f); int nz = static_cast(0.5f*gz+127.5f); int doff = x + y * fullX + (z-offZ) * fullXY; //tmpPtr[doff*2+0]= 0; tmpPtr[doff*4+0]= clamp(nx); tmpPtr[doff*4+1]= clamp(ny); tmpPtr[doff*4+2]= clamp(nz); tmpPtr[doff*4+3]= clamp(iGrayValue); int soff = x + y * sizeX + z * sizeXY; tmpPtr2[doff*3+0]= dataPtr[soff*4+0]; tmpPtr2[doff*3+1]= dataPtr[soff*4+1]; tmpPtr2[doff*3+2]= dataPtr[soff*4+2]; /* if( z == fullZ/2 ) if( y == fullY/2 ) MITK_INFO << x << " " << y << " " << z << " : " << iGrayValue << " : " << iGradient; */ } inline void compute(int x,int y,int z) { int grayValue = sample(x,y,z); int gx,gy,gz; gx = sample(x+1,y,z) - sample(x-1,y,z); gy = sample(x,y+1,z) - sample(x,y-1,z); gz = sample(x,y,z+1) - sample(x,y,z-1); write( x, y, z, grayValue, gx, gy, gz ); } inline void computeClamp(int x,int y,int z) { int grayValue = sample(x,y,z); int gx,gy,gz; if(x==0) gx = 2 * ( sample(x+1,y,z) - grayValue ); else if(x==sizeXm1) gx = 2 * ( grayValue - sample(x-1,y,z) ); else gx = sample(x+1,y,z) - sample(x-1,y,z); if(y==0) gy = 2 * ( sample(x,y+1,z) - grayValue ); else if(y==sizeYm1) gy = 2 * ( grayValue - sample(x,y-1,z) ); else gy = sample(x,y+1,z) - sample(x,y-1,z); if(z==0) gz = 2 * ( sample(x,y,z+1) - grayValue ); else if(z==sizeZm1) gz = 2 * ( grayValue - sample(x,y,z-1) ); else gz = sample(x,y,z+1) - sample(x,y,z-1); write( x, y, z, grayValue, gx, gy, gz ); } inline void compute1D(int y,int z) { int x=0; computeClamp(x,y,z); x++; while(x=sizeZ) fill2D(z); else compute2D(z); } } }; void vtkVolumeTextureMapper3DComputeRGBA( unsigned char *dataPtr, vtkMitkVolumeTextureMapper3D *me, GLuint volume1, GLuint volume2) { unsigned char *inPtr; // unsigned char *outPtr, *outPtr2; // int i, j, k; // int idx; int inputDimensions[3]; double inputSpacing[3]; vtkImageData *input = me->GetInput(); input->GetDimensions( inputDimensions ); input->GetSpacing( inputSpacing ); int outputDimensions[3]; float outputSpacing[3]; me->GetVolumeDimensions( outputDimensions ); me->GetVolumeSpacing( outputSpacing ); int components = input->GetNumberOfScalarComponents(); MITK_INFO << "components are " << components; // double wx, wy, wz; // double fx, fy, fz; // int x, y, z; double sampleRate[3]; sampleRate[0] = outputSpacing[0] / static_cast(inputSpacing[0]); sampleRate[1] = outputSpacing[1] / static_cast(inputSpacing[1]); sampleRate[2] = outputSpacing[2] / static_cast(inputSpacing[2]); int fullX = outputDimensions[0]; int fullY = outputDimensions[1]; int fullZ = outputDimensions[2]; int sizeX = inputDimensions[0]; int sizeY = inputDimensions[1]; int sizeZ = inputDimensions[2]; int chunkSize = 64; if(fullZ < chunkSize) chunkSize=fullZ; int numChunks = ( fullZ + (chunkSize-1) ) / chunkSize; inPtr = dataPtr; unsigned char *tmpPtr = new unsigned char[fullX*fullY*chunkSize*4]; unsigned char *tmpPtr2 = new unsigned char[fullX*fullY*chunkSize*3]; // For each Chunk { RGBACompute sgc(dataPtr,tmpPtr,tmpPtr2,sizeX,sizeY,sizeZ,fullX,fullY,fullZ); int currentChunk = 0; while(currentChunk < numChunks) { // MITK_INFO << "processing chunk " << currentChunk; int currentChunkStart = currentChunk * chunkSize; int currentChunkEnd = currentChunkStart + chunkSize - 1 ; if( currentChunkEnd > (fullZ-1) ) currentChunkEnd = (fullZ-1); int currentChunkSize = currentChunkEnd - currentChunkStart + 1; sgc.fillSlices( currentChunkStart , currentChunkEnd ); glBindTexture(vtkgl::TEXTURE_3D, volume1); vtkgl::TexSubImage3D(vtkgl::TEXTURE_3D,0,0,0,currentChunkStart,fullX,fullY,currentChunkSize,GL_RGBA,GL_UNSIGNED_BYTE,tmpPtr); glBindTexture(vtkgl::TEXTURE_3D, volume2); vtkgl::TexSubImage3D(vtkgl::TEXTURE_3D,0,0,0,currentChunkStart,fullX,fullY,currentChunkSize,GL_RGB,GL_UNSIGNED_BYTE,tmpPtr2); currentChunk ++; } } delete tmpPtr; delete tmpPtr2; } //----------------------------------------------------------------------------- void vtkMitkOpenGLVolumeTextureMapper3D::ComputeVolumeDimensions() { // Get the image data vtkImageData *input = this->GetInput(); // How big does the Volume need to be? int dim[3]; input->GetDimensions(dim); int powerOfTwoDim[3]; if(this->SupportsNonPowerOfTwoTextures) { for ( int i = 0; i < 3; i++ ) powerOfTwoDim[i]=(dim[i]+1)&~1; // MITK_INFO << "using non-power-two even textures (" << (1.0-double(dim[0]*dim[1]*dim[2])/double(powerOfTwoDim[0]*powerOfTwoDim[1]*powerOfTwoDim[2])) * 100.0 << "% memory wasted)"; } else { for ( int i = 0; i < 3; i++ ) { powerOfTwoDim[i] = 4; while ( powerOfTwoDim[i] < dim[i] ) powerOfTwoDim[i] *= 2; } MITK_WARN << "using power-two textures (" << (1.0-double(dim[0]*dim[1]*dim[2])/double(powerOfTwoDim[0]*powerOfTwoDim[1]*powerOfTwoDim[2])) * 100.0 << "% memory wasted)"; } // Save the volume size this->VolumeDimensions[0] = powerOfTwoDim[0]; this->VolumeDimensions[1] = powerOfTwoDim[1]; this->VolumeDimensions[2] = powerOfTwoDim[2]; // What is the spacing? double spacing[3]; input->GetSpacing(spacing); // Compute the new spacing this->VolumeSpacing[0] = ( dim[0] -1.01)*spacing[0] / static_cast(this->VolumeDimensions[0]-1); this->VolumeSpacing[1] = ( dim[1] -1.01)*spacing[1] / static_cast(this->VolumeDimensions[1]-1); this->VolumeSpacing[2] = ((dim[2])-1.01)*spacing[2] / static_cast(this->VolumeDimensions[2]-1); } //----------------------------------------------------------------------------- bool vtkMitkOpenGLVolumeTextureMapper3D::UpdateVolumes(vtkVolume *vtkNotUsed(vol)) { // Get the image data vtkImageData *input = this->GetInput(); input->Update(); bool needUpdate = false; // Has the volume changed in some way? if ( this->SavedTextureInput != input || this->SavedTextureMTime.GetMTime() < input->GetMTime() ) needUpdate = true; // Do we have any volume on the gpu already? if(!this->Volume1Index) needUpdate = true; if(!needUpdate) return true; ComputeVolumeDimensions(); int components = input->GetNumberOfScalarComponents(); // Find the scalar range double scalarRange[2]; input->GetPointData()->GetScalars()->GetRange(scalarRange, components-1); // Is the difference between max and min less than 4096? If so, and if // the data is not of float or double type, use a simple offset mapping. // If the difference between max and min is 4096 or greater, or the data // is of type float or double, we must use an offset / scaling mapping. // In this case, the array size will be 4096 - we need to figure out the // offset and scale factor. float offset; float scale; int arraySizeNeeded; int scalarType = input->GetScalarType(); if ( scalarType == VTK_FLOAT || scalarType == VTK_DOUBLE || scalarRange[1] - scalarRange[0] > 255 ) { arraySizeNeeded = 256; offset = -scalarRange[0]; scale = 255.0 / (scalarRange[1] - scalarRange[0]); } else { arraySizeNeeded = static_cast(scalarRange[1] - scalarRange[0] + 1); offset = -scalarRange[0]; scale = 1.0; } this->ColorTableSize = arraySizeNeeded; this->ColorTableOffset = offset; this->ColorTableScale = scale; // Allocating volume on gpu { // Deleting old textures this->DeleteTextureIndex(&this->Volume1Index); this->DeleteTextureIndex(&this->Volume2Index); this->DeleteTextureIndex(&this->Volume3Index); this->CreateTextureIndex(&this->Volume1Index); //this->CreateTextureIndex(&this->Volume2Index); int dim[3]; this->GetVolumeDimensions(dim); vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); MITK_INFO << "allocating volume on gpu"; GLint gradientScalarTextureFormat = GL_RGBA8; if(this->UseCompressedTexture && SupportsCompressedTexture) gradientScalarTextureFormat = myGL_COMPRESSED_RGBA_S3TC_DXT5_EXT; glBindTexture(vtkgl::TEXTURE_3D, this->Volume1Index); vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,gradientScalarTextureFormat,dim[0],dim[1],dim[2],0,GL_RGBA,GL_UNSIGNED_BYTE,0); this->Setup3DTextureParameters( true ); } // Transfer the input volume to the RGBA volume void *dataPtr = input->GetScalarPointer(); switch ( scalarType ) { vtkTemplateMacro( vtkVolumeTextureMapper3DComputeScalars( static_cast(dataPtr), this, offset, scale, this->Volume1Index, this->Volume2Index)); } this->SavedTextureInput = input; this->SavedTextureMTime.Modified(); return true; } //----------------------------------------------------------------------------- bool vtkMitkOpenGLVolumeTextureMapper3D::UpdateVolumesRGBA(vtkVolume *vtkNotUsed(vol)) { // Get the image data vtkImageData *input = this->GetInput(); input->Update(); bool needUpdate = false; // Has the volume changed in some way? if ( this->SavedTextureInput != input || this->SavedTextureMTime.GetMTime() < input->GetMTime() ) needUpdate = true; // Do we have any volume on the gpu already? if(!this->Volume1Index) needUpdate = true; if(!needUpdate) return true; MITK_INFO << "updating rgba volume"; ComputeVolumeDimensions(); // Allocating volume on gpu { // Deleting old textures this->DeleteTextureIndex(&this->Volume1Index); this->DeleteTextureIndex(&this->Volume2Index); this->DeleteTextureIndex(&this->Volume3Index); this->CreateTextureIndex(&this->Volume1Index); this->CreateTextureIndex(&this->Volume2Index); int dim[3]; this->GetVolumeDimensions(dim); MITK_INFO << "allocating volume on gpu"; GLint gradientScalarTextureFormat = GL_RGBA8; GLint colorTextureFormat = GL_RGB8; if(this->UseCompressedTexture && SupportsCompressedTexture) { gradientScalarTextureFormat = myGL_COMPRESSED_RGBA_S3TC_DXT5_EXT; colorTextureFormat = myGL_COMPRESSED_RGB_S3TC_DXT1_EXT; } vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume1Index); vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,gradientScalarTextureFormat,dim[0],dim[1],dim[2],0,GL_RGBA,GL_UNSIGNED_BYTE,0); this->Setup3DTextureParameters( true ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume2Index); vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,colorTextureFormat,dim[0],dim[1],dim[2],0,GL_RGB,GL_UNSIGNED_BYTE,0); this->Setup3DTextureParameters( true ); } // Transfer the input volume to the RGBA volume unsigned char *dataPtr = (unsigned char*)input->GetScalarPointer(); vtkVolumeTextureMapper3DComputeRGBA( dataPtr, this, this->Volume1Index, this->Volume2Index); this->SavedTextureInput = input; this->SavedTextureMTime.Modified(); return true; } void vtkMitkOpenGLVolumeTextureMapper3D::Setup3DTextureParameters( bool linear ) { //GPU_INFO << "Setup3DTextureParameters"; if( linear ) { glTexParameterf( vtkgl::TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameterf( vtkgl::TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); } else { glTexParameterf( vtkgl::TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameterf( vtkgl::TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); } glTexParameterf( vtkgl::TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameterf( vtkgl::TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } void vtkMitkOpenGLVolumeTextureMapper3D::SetupOneIndependentTextures( vtkRenderer *vtkNotUsed(ren), vtkVolume *vol ) { // Update the volume containing the 2 byte scalar / gradient magnitude this->UpdateVolumes( vol ); // Update the dependent 2D color table mapping scalar value and // gradient magnitude to RGBA if ( this->UpdateColorLookup( vol ) || !this->ColorLookupIndex ) { this->DeleteTextureIndex( &this->ColorLookupIndex ); this->DeleteTextureIndex( &this->AlphaLookupIndex ); this->CreateTextureIndex( &this->ColorLookupIndex ); vtkgl::ActiveTexture( vtkgl::TEXTURE1 ); glBindTexture(GL_TEXTURE_2D, this->ColorLookupIndex); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); //MITK_INFO << "uploading transferfunction"; GLint colorLookupTextureFormat = GL_RGBA8; if(this->UseCompressedTexture && SupportsCompressedTexture) colorLookupTextureFormat = myGL_COMPRESSED_RGBA_S3TC_DXT5_EXT; glTexImage2D( GL_TEXTURE_2D, 0,colorLookupTextureFormat, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, this->ColorLookup ); } } void vtkMitkOpenGLVolumeTextureMapper3D::SetupRGBATextures( vtkRenderer *vtkNotUsed(ren), vtkVolume *vol ) { MITK_INFO << "SetupFourDependentTextures"; this->UpdateVolumesRGBA(vol); /* vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); vtkgl::ActiveTexture( vtkgl::TEXTURE1 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); vtkgl::ActiveTexture( vtkgl::TEXTURE2 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); // Update the volume containing the 3 byte scalars / gradient magnitude if ( this->UpdateVolumes( vol ) || !this->Volume1Index || !this->Volume2Index || !this->Volume3Index ) { int dim[3]; this->GetVolumeDimensions(dim); vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); glBindTexture(vtkgl::TEXTURE_3D,0); this->DeleteTextureIndex(&this->Volume1Index); this->CreateTextureIndex(&this->Volume1Index); glBindTexture(vtkgl::TEXTURE_3D, this->Volume1Index); vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,this->InternalRGB,dim[0],dim[1], dim[2],0,GL_RGB,GL_UNSIGNED_BYTE,this->Volume1); vtkgl::ActiveTexture( vtkgl::TEXTURE1 ); glBindTexture(vtkgl::TEXTURE_3D,0); this->DeleteTextureIndex(&this->Volume2Index); this->CreateTextureIndex(&this->Volume2Index); glBindTexture(vtkgl::TEXTURE_3D, this->Volume2Index); vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,this->InternalLA,dim[0],dim[1], dim[2],0,GL_LUMINANCE_ALPHA,GL_UNSIGNED_BYTE, this->Volume2); vtkgl::ActiveTexture( vtkgl::TEXTURE2 ); glBindTexture(vtkgl::TEXTURE_3D,0); this->DeleteTextureIndex(&this->Volume3Index); this->CreateTextureIndex(&this->Volume3Index); glBindTexture(vtkgl::TEXTURE_3D, this->Volume3Index); vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,this->InternalRGB,dim[0],dim[1], dim[2],0,GL_RGB,GL_UNSIGNED_BYTE,this->Volume3); } vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume1Index); this->Setup3DTextureParameters( true ); vtkgl::ActiveTexture( vtkgl::TEXTURE1 ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume2Index); this->Setup3DTextureParameters( true ); vtkgl::ActiveTexture( vtkgl::TEXTURE2 ); glBindTexture(vtkgl::TEXTURE_3D_EXT, this->Volume3Index); this->Setup3DTextureParameters( true ); vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glEnable( GL_TEXTURE_2D ); glDisable( vtkgl::TEXTURE_3D ); // Update the dependent 2D table mapping scalar value and // gradient magnitude to opacity if ( this->UpdateColorLookup( vol ) || !this->AlphaLookupIndex ) { this->DeleteTextureIndex(&this->ColorLookupIndex); vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glBindTexture(GL_TEXTURE_2D,0); this->DeleteTextureIndex(&this->AlphaLookupIndex); this->CreateTextureIndex(&this->AlphaLookupIndex); glBindTexture(GL_TEXTURE_2D, this->AlphaLookupIndex); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); //MITK_INFO << "uploading transferfunction"; glTexImage2D(GL_TEXTURE_2D,0,this->InternalAlpha, 256, 256, 0, GL_ALPHA, GL_UNSIGNED_BYTE, this->AlphaLookup ); } vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glBindTexture(GL_TEXTURE_2D, this->AlphaLookupIndex); */ } void vtkMitkOpenGLVolumeTextureMapper3D::RenderOneIndependentShadeFP( vtkRenderer *ren, vtkVolume *vol ) { //GPU_INFO << "RenderOneIndependentShadeFP"; this->SetupOneIndependentTextures( ren, vol ); glEnable( vtkgl::FRAGMENT_PROGRAM_ARB ); vtkgl::BindProgramARB( vtkgl::FRAGMENT_PROGRAM_ARB, prgOneComponentShade ); this->SetupProgramLocalsForShadingFP( ren, vol ); // Bind Textures { vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume1Index); vtkgl::ActiveTexture( vtkgl::TEXTURE1 ); glEnable( GL_TEXTURE_2D ); glDisable( vtkgl::TEXTURE_3D ); glBindTexture(GL_TEXTURE_2D, this->ColorLookupIndex); vtkgl::ActiveTexture( vtkgl::TEXTURE2 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume2Index); } int stages[4] = {1,1,1,0}; this->RenderPolygons( ren, vol, stages ); glDisable( vtkgl::FRAGMENT_PROGRAM_ARB ); } void vtkMitkOpenGLVolumeTextureMapper3D::RenderRGBAShadeFP( vtkRenderer *ren, vtkVolume *vol ) { this->SetupRGBATextures(ren, vol); glEnable( vtkgl::FRAGMENT_PROGRAM_ARB ); vtkgl::BindProgramARB( vtkgl::FRAGMENT_PROGRAM_ARB, prgRGBAShade ); this->SetupProgramLocalsForShadingFP( ren, vol ); // Bind Textures { vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume1Index); vtkgl::ActiveTexture( vtkgl::TEXTURE1 ); glDisable( GL_TEXTURE_2D ); glEnable( vtkgl::TEXTURE_3D ); glBindTexture(vtkgl::TEXTURE_3D, this->Volume2Index); } int stages[4] = {1,1,1,0}; this->RenderPolygons( ren, vol, stages ); glDisable( vtkgl::FRAGMENT_PROGRAM_ARB ); } void vtkMitkOpenGLVolumeTextureMapper3D::GetLightInformation( vtkRenderer *ren, vtkVolume *vol, GLfloat lightDirection[2][4], GLfloat lightDiffuseColor[2][4], GLfloat lightSpecularColor[2][4], GLfloat halfwayVector[2][4], GLfloat ambientColor[4] ) { //GPU_INFO << "GetLightInformation"; float ambient = vol->GetProperty()->GetAmbient(); float diffuse = vol->GetProperty()->GetDiffuse(); float specular = vol->GetProperty()->GetSpecular(); vtkTransform *volumeTransform = vtkTransform::New(); volumeTransform->SetMatrix( vol->GetMatrix() ); volumeTransform->Inverse(); vtkLightCollection *lights = ren->GetLights(); lights->InitTraversal(); vtkLight *light[2]; light[0] = lights->GetNextItem(); light[1] = lights->GetNextItem(); int lightIndex = 0; double cameraPosition[3]; double cameraFocalPoint[3]; ren->GetActiveCamera()->GetPosition( cameraPosition ); ren->GetActiveCamera()->GetFocalPoint( cameraFocalPoint ); double viewDirection[3]; volumeTransform->TransformPoint( cameraPosition, cameraPosition ); volumeTransform->TransformPoint( cameraFocalPoint, cameraFocalPoint ); viewDirection[0] = cameraFocalPoint[0] - cameraPosition[0]; viewDirection[1] = cameraFocalPoint[1] - cameraPosition[1]; viewDirection[2] = cameraFocalPoint[2] - cameraPosition[2]; vtkMath::Normalize( viewDirection ); ambientColor[0] = 0.0; ambientColor[1] = 0.0; ambientColor[2] = 0.0; ambientColor[3] = 0.0; for ( lightIndex = 0; lightIndex < 2; lightIndex++ ) { float dir[3] = {0,0,0}; float half[3] = {0,0,0}; if ( light[lightIndex] == NULL || light[lightIndex]->GetSwitch() == 0 ) { lightDiffuseColor[lightIndex][0] = 0.0; lightDiffuseColor[lightIndex][1] = 0.0; lightDiffuseColor[lightIndex][2] = 0.0; lightDiffuseColor[lightIndex][3] = 0.0; lightSpecularColor[lightIndex][0] = 0.0; lightSpecularColor[lightIndex][1] = 0.0; lightSpecularColor[lightIndex][2] = 0.0; lightSpecularColor[lightIndex][3] = 0.0; } else { float lightIntensity = light[lightIndex]->GetIntensity(); double lightColor[3]; light[lightIndex]->GetDiffuseColor( lightColor ); double lightPosition[3]; double lightFocalPoint[3]; light[lightIndex]->GetTransformedPosition( lightPosition ); light[lightIndex]->GetTransformedFocalPoint( lightFocalPoint ); volumeTransform->TransformPoint( lightPosition, lightPosition ); volumeTransform->TransformPoint( lightFocalPoint, lightFocalPoint ); dir[0] = lightPosition[0] - lightFocalPoint[0]; dir[1] = lightPosition[1] - lightFocalPoint[1]; dir[2] = lightPosition[2] - lightFocalPoint[2]; vtkMath::Normalize( dir ); lightDiffuseColor[lightIndex][0] = lightColor[0]*diffuse*lightIntensity; lightDiffuseColor[lightIndex][1] = lightColor[1]*diffuse*lightIntensity; lightDiffuseColor[lightIndex][2] = lightColor[2]*diffuse*lightIntensity; lightDiffuseColor[lightIndex][3] = 1.0; lightSpecularColor[lightIndex][0]= lightColor[0]*specular*lightIntensity; lightSpecularColor[lightIndex][1]= lightColor[1]*specular*lightIntensity; lightSpecularColor[lightIndex][2]= lightColor[2]*specular*lightIntensity; lightSpecularColor[lightIndex][3] = 0.0; half[0] = dir[0] - viewDirection[0]; half[1] = dir[1] - viewDirection[1]; half[2] = dir[2] - viewDirection[2]; vtkMath::Normalize( half ); ambientColor[0] += ambient*lightColor[0]; ambientColor[1] += ambient*lightColor[1]; ambientColor[2] += ambient*lightColor[2]; } lightDirection[lightIndex][0] = (dir[0]+1.0)/2.0; lightDirection[lightIndex][1] = (dir[1]+1.0)/2.0; lightDirection[lightIndex][2] = (dir[2]+1.0)/2.0; lightDirection[lightIndex][3] = 0.0; halfwayVector[lightIndex][0] = (half[0]+1.0)/2.0; halfwayVector[lightIndex][1] = (half[1]+1.0)/2.0; halfwayVector[lightIndex][2] = (half[2]+1.0)/2.0; halfwayVector[lightIndex][3] = 0.0; } volumeTransform->Delete(); } void vtkMitkOpenGLVolumeTextureMapper3D::SetupProgramLocalsForShadingFP( vtkRenderer *ren, vtkVolume *vol ) { //GPU_INFO << "SetupProgramLocalsForShadingFP"; GLfloat lightDirection[2][4]; GLfloat lightDiffuseColor[2][4]; GLfloat lightSpecularColor[2][4]; GLfloat halfwayVector[2][4]; GLfloat ambientColor[4]; float ambient = vol->GetProperty()->GetAmbient(); float diffuse = vol->GetProperty()->GetDiffuse(); float specular = vol->GetProperty()->GetSpecular(); float specularPower = vol->GetProperty()->GetSpecularPower(); vtkTransform *volumeTransform = vtkTransform::New(); volumeTransform->SetMatrix( vol->GetMatrix() ); volumeTransform->Inverse(); vtkLightCollection *lights = ren->GetLights(); lights->InitTraversal(); vtkLight *light[2]; light[0] = lights->GetNextItem(); light[1] = lights->GetNextItem(); int lightIndex = 0; double cameraPosition[3]; double cameraFocalPoint[3]; ren->GetActiveCamera()->GetPosition( cameraPosition ); ren->GetActiveCamera()->GetFocalPoint( cameraFocalPoint ); volumeTransform->TransformPoint( cameraPosition, cameraPosition ); volumeTransform->TransformPoint( cameraFocalPoint, cameraFocalPoint ); double viewDirection[4]; viewDirection[0] = cameraFocalPoint[0] - cameraPosition[0]; viewDirection[1] = cameraFocalPoint[1] - cameraPosition[1]; viewDirection[2] = cameraFocalPoint[2] - cameraPosition[2]; viewDirection[3] = 0.0; vtkMath::Normalize( viewDirection ); ambientColor[0] = 0.0; ambientColor[1] = 0.0; ambientColor[2] = 0.0; ambientColor[3] = 0.0; for ( lightIndex = 0; lightIndex < 2; lightIndex++ ) { float dir[3] = {0,0,0}; float half[3] = {0,0,0}; if ( light[lightIndex] == NULL || light[lightIndex]->GetSwitch() == 0 ) { lightDiffuseColor[lightIndex][0] = 0.0; lightDiffuseColor[lightIndex][1] = 0.0; lightDiffuseColor[lightIndex][2] = 0.0; lightDiffuseColor[lightIndex][3] = 0.0; lightSpecularColor[lightIndex][0] = 0.0; lightSpecularColor[lightIndex][1] = 0.0; lightSpecularColor[lightIndex][2] = 0.0; lightSpecularColor[lightIndex][3] = 0.0; } else { float lightIntensity = light[lightIndex]->GetIntensity(); double lightColor[3]; light[lightIndex]->GetDiffuseColor( lightColor ); double lightPosition[3]; double lightFocalPoint[3]; light[lightIndex]->GetTransformedPosition( lightPosition ); light[lightIndex]->GetTransformedFocalPoint( lightFocalPoint ); volumeTransform->TransformPoint( lightPosition, lightPosition ); volumeTransform->TransformPoint( lightFocalPoint, lightFocalPoint ); dir[0] = lightPosition[0] - lightFocalPoint[0]; dir[1] = lightPosition[1] - lightFocalPoint[1]; dir[2] = lightPosition[2] - lightFocalPoint[2]; vtkMath::Normalize( dir ); lightDiffuseColor[lightIndex][0] = lightColor[0]*diffuse*lightIntensity; lightDiffuseColor[lightIndex][1] = lightColor[1]*diffuse*lightIntensity; lightDiffuseColor[lightIndex][2] = lightColor[2]*diffuse*lightIntensity; lightDiffuseColor[lightIndex][3] = 0.0; lightSpecularColor[lightIndex][0]= lightColor[0]*specular*lightIntensity; lightSpecularColor[lightIndex][1]= lightColor[1]*specular*lightIntensity; lightSpecularColor[lightIndex][2]= lightColor[2]*specular*lightIntensity; lightSpecularColor[lightIndex][3] = 0.0; half[0] = dir[0] - viewDirection[0]; half[1] = dir[1] - viewDirection[1]; half[2] = dir[2] - viewDirection[2]; vtkMath::Normalize( half ); ambientColor[0] += ambient*lightColor[0]; ambientColor[1] += ambient*lightColor[1]; ambientColor[2] += ambient*lightColor[2]; } lightDirection[lightIndex][0] = dir[0]; lightDirection[lightIndex][1] = dir[1]; lightDirection[lightIndex][2] = dir[2]; lightDirection[lightIndex][3] = 0.0; halfwayVector[lightIndex][0] = half[0]; halfwayVector[lightIndex][1] = half[1]; halfwayVector[lightIndex][2] = half[2]; halfwayVector[lightIndex][3] = 0.0; } volumeTransform->Delete(); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 0, lightDirection[0][0], lightDirection[0][1], lightDirection[0][2], lightDirection[0][3] ); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 1, halfwayVector[0][0], halfwayVector[0][1], halfwayVector[0][2], halfwayVector[0][3] ); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 2, ambient, diffuse, specular, specularPower ); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 3, lightDiffuseColor[0][0], lightDiffuseColor[0][1], lightDiffuseColor[0][2], lightDiffuseColor[0][3] ); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 4, lightSpecularColor[0][0], lightSpecularColor[0][1], lightSpecularColor[0][2], lightSpecularColor[0][3] ); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 5, viewDirection[0], viewDirection[1], viewDirection[2], viewDirection[3] ); vtkgl::ProgramLocalParameter4fARB( vtkgl::FRAGMENT_PROGRAM_ARB, 6, 2.0, -1.0, 0.0, 0.0 ); } int vtkMitkOpenGLVolumeTextureMapper3D::IsRenderSupported( vtkRenderer *renderer, vtkVolumeProperty *property ) { //GPU_INFO << "IsRenderSupported"; if ( !this->Initialized ) { //this->Initialize(); this->Initialize(renderer); } if ( !this->RenderPossible ) { return 0; } if ( !this->GetInput() ) { return 0; } if ( this->GetInput()->GetNumberOfScalarComponents() > 1 && property->GetIndependentComponents() ) { return 0; } return 1; } void vtkMitkOpenGLVolumeTextureMapper3D::Initialize(vtkRenderer *renderer) { //GPU_INFO << "Initialize"; this->Initialized = 1; // vtkOpenGLExtensionManager * extensions = vtkOpenGLExtensionManager::New(); //extensions->SetRenderWindow(NULL); // set render window to the current one. vtkOpenGLExtensionManager *extensions=static_cast(renderer->GetRenderWindow())->GetExtensionManager(); int supports_texture3D=extensions->ExtensionSupported( "GL_VERSION_1_2" ); if(supports_texture3D) { extensions->LoadExtension("GL_VERSION_1_2"); } else { supports_texture3D=extensions->ExtensionSupported( "GL_EXT_texture3D" ); if(supports_texture3D) { extensions->LoadCorePromotedExtension("GL_EXT_texture3D"); } } int supports_multitexture=extensions->ExtensionSupported( "GL_VERSION_1_3" ); if(supports_multitexture) { extensions->LoadExtension("GL_VERSION_1_3"); } else { supports_multitexture= extensions->ExtensionSupported("GL_ARB_multitexture"); if(supports_multitexture) { extensions->LoadCorePromotedExtension("GL_ARB_multitexture"); } } this->SupportsCompressedTexture=extensions->ExtensionSupported("GL_VERSION_1_3")==1; if(!this->SupportsCompressedTexture) { this->SupportsCompressedTexture= extensions->ExtensionSupported("GL_ARB_texture_compression")==1; if(this->SupportsCompressedTexture) { extensions->LoadCorePromotedExtension("GL_ARB_texture_compression"); } } //GPU_INFO(this->SupportsCompressedTexture) << "supporting compressed textures"; this->SupportsNonPowerOfTwoTextures= extensions->ExtensionSupported("GL_VERSION_2_0") || extensions->ExtensionSupported("GL_ARB_texture_non_power_of_two"); //GPU_INFO << "np2: " << (this->SupportsNonPowerOfTwoTextures?1:0); int supports_GL_ARB_fragment_program = extensions->ExtensionSupported( "GL_ARB_fragment_program" ); if(supports_GL_ARB_fragment_program) { extensions->LoadExtension( "GL_ARB_fragment_program" ); } int supports_GL_ARB_vertex_program = extensions->ExtensionSupported( "GL_ARB_vertex_program" ); if(supports_GL_ARB_vertex_program) { extensions->LoadExtension( "GL_ARB_vertex_program" ); } RenderPossible = 0; if ( supports_texture3D && supports_multitexture && supports_GL_ARB_fragment_program && supports_GL_ARB_vertex_program && vtkgl::TexImage3D && vtkgl::ActiveTexture && vtkgl::MultiTexCoord3fv && vtkgl::GenProgramsARB && vtkgl::DeleteProgramsARB && vtkgl::BindProgramARB && vtkgl::ProgramStringARB && vtkgl::ProgramLocalParameter4fARB ) { RenderPossible = 1; } else { std::string errString = "no gpu-acceleration possible cause following extensions/methods are missing or unsupported:"; if(!supports_texture3D) errString += " EXT_TEXTURE3D"; if(!supports_multitexture) errString += " EXT_MULTITEXTURE"; if(!supports_GL_ARB_fragment_program) errString += " ARB_FRAGMENT_PROGRAM"; if(!supports_GL_ARB_vertex_program) errString += " ARB_VERTEX_PROGRAM"; if(!vtkgl::TexImage3D) errString += " glTexImage3D"; if(!vtkgl::ActiveTexture) errString += " glActiveTexture"; if(!vtkgl::MultiTexCoord3fv) errString += " glMultiTexCoord3fv"; if(!vtkgl::GenProgramsARB) errString += " glGenProgramsARB"; if(!vtkgl::DeleteProgramsARB) errString += " glDeleteProgramsARB"; if(!vtkgl::BindProgramARB) errString += " glBindProgramARB"; if(!vtkgl::ProgramStringARB) errString += " glProgramStringARB"; if(!vtkgl::ProgramLocalParameter4fARB) errString += " glProgramLocalParameter4fARB"; GPU_WARN << errString; }; if(RenderPossible) { vtkgl::GenProgramsARB( 1, &prgOneComponentShade ); vtkgl::BindProgramARB( vtkgl::FRAGMENT_PROGRAM_ARB, prgOneComponentShade ); vtkgl::ProgramStringARB( vtkgl::FRAGMENT_PROGRAM_ARB, vtkgl::PROGRAM_FORMAT_ASCII_ARB, static_cast(strlen(vtkMitkVolumeTextureMapper3D_OneComponentShadeFP)), vtkMitkVolumeTextureMapper3D_OneComponentShadeFP ); vtkgl::GenProgramsARB( 1, &prgRGBAShade ); vtkgl::BindProgramARB( vtkgl::FRAGMENT_PROGRAM_ARB, prgRGBAShade ); vtkgl::ProgramStringARB( vtkgl::FRAGMENT_PROGRAM_ARB, vtkgl::PROGRAM_FORMAT_ASCII_ARB, static_cast(strlen(vtkMitkVolumeTextureMapper3D_FourDependentShadeFP)), vtkMitkVolumeTextureMapper3D_FourDependentShadeFP ); } } // ---------------------------------------------------------------------------- // Print the vtkMitkOpenGLVolumeTextureMapper3D void vtkMitkOpenGLVolumeTextureMapper3D::PrintSelf(ostream& os, vtkIndent indent) { // vtkOpenGLExtensionManager * extensions = vtkOpenGLExtensionManager::New(); // extensions->SetRenderWindow(NULL); // set render window to current render window os << indent << "Initialized " << this->Initialized << endl; /* if ( this->Initialized ) { os << indent << "Supports GL_VERSION_1_2:" << extensions->ExtensionSupported( "GL_VERSION_1_2" ) << endl; os << indent << "Supports GL_EXT_texture3D:" << extensions->ExtensionSupported( "GL_EXT_texture3D" ) << endl; os << indent << "Supports GL_VERSION_1_3:" << extensions->ExtensionSupported( "GL_VERSION_1_3" ) << endl; os << indent << "Supports GL_ARB_multitexture: " << extensions->ExtensionSupported( "GL_ARB_multitexture" ) << endl; os << indent << "Supports GL_NV_texture_shader2: " << extensions->ExtensionSupported( "GL_NV_texture_shader2" ) << endl; os << indent << "Supports GL_NV_register_combiners2: " << extensions->ExtensionSupported( "GL_NV_register_combiners2" ) << endl; os << indent << "Supports GL_ATI_fragment_shader: " << extensions->ExtensionSupported( "GL_ATI_fragment_shader" ) << endl; os << indent << "Supports GL_ARB_fragment_program: " << extensions->ExtensionSupported( "GL_ARB_fragment_program" ) << endl; os << indent << "Supports GL_ARB_texture_compression: " << extensions->ExtensionSupported( "GL_ARB_texture_compression" ) << endl; os << indent << "Supports GL_VERSION_2_0:" << extensions->ExtensionSupported( "GL_VERSION_2_0" ) << endl; os << indent << "Supports GL_ARB_texture_non_power_of_two:" << extensions->ExtensionSupported( "GL_ARB_texture_non_power_of_two" ) << endl; } extensions->Delete(); */ if(this->RenderWindow!=0) { vtkOpenGLExtensionManager *extensions= static_cast(this->RenderWindow)->GetExtensionManager(); if ( this->Initialized ) { os << indent << "Supports GL_VERSION_1_2:" << extensions->ExtensionSupported( "GL_VERSION_1_2" ) << endl; os << indent << "Supports GL_EXT_texture3D:" << extensions->ExtensionSupported( "GL_EXT_texture3D" ) << endl; os << indent << "Supports GL_VERSION_1_3:" << extensions->ExtensionSupported( "GL_VERSION_1_3" ) << endl; os << indent << "Supports GL_ARB_multitexture: " << extensions->ExtensionSupported( "GL_ARB_multitexture" ) << endl; os << indent << "Supports GL_NV_texture_shader2: " << extensions->ExtensionSupported( "GL_NV_texture_shader2" ) << endl; os << indent << "Supports GL_NV_register_combiners2: " << extensions->ExtensionSupported( "GL_NV_register_combiners2" ) << endl; os << indent << "Supports GL_ATI_fragment_shader: " << extensions->ExtensionSupported( "GL_ATI_fragment_shader" ) << endl; os << indent << "Supports GL_ARB_fragment_program: " << extensions->ExtensionSupported( "GL_ARB_fragment_program" ) << endl; os << indent << "Supports GL_ARB_texture_compression: " << extensions->ExtensionSupported( "GL_ARB_texture_compression" ) << endl; os << indent << "Supports GL_VERSION_2_0:" << extensions->ExtensionSupported( "GL_VERSION_2_0" ) << endl; os << indent << "Supports GL_ARB_texture_non_power_of_two:" << extensions->ExtensionSupported( "GL_ARB_texture_non_power_of_two" ) << endl; } } this->Superclass::PrintSelf(os,indent); } diff --git a/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.h b/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.h index 92beb27568..870cade2ea 100644 --- a/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.h +++ b/Modules/MitkExt/Rendering/vtkMitkOpenGLVolumeTextureMapper3D.h @@ -1,153 +1,153 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // .NAME vtkMitkOpenGLVolumeTextureMapper3D - concrete implementation of 3D volume texture mapping // .SECTION Description // vtkMitkOpenGLVolumeTextureMapper3D renders a volume using 3D texture mapping. // See vtkMitkVolumeTextureMapper3D for full description. // .SECTION see also // vtkMitkVolumeTextureMapper3D vtkVolumeMapper #ifndef __vtkMitkOpenGLVolumeTextureMapper3D_h #define __vtkMitkOpenGLVolumeTextureMapper3D_h #include "vtkMitkVolumeTextureMapper3D.h" #include "mitkBaseRenderer.h" #include "MitkExtExports.h" #ifndef VTK_IMPLEMENT_MESA_CXX # include "vtkOpenGL.h" // GLfloat type is used in some method signatures. #endif class vtkRenderWindow; class vtkVolumeProperty; #include "mitkCommon.h" class MitkExt_EXPORT vtkMitkOpenGLVolumeTextureMapper3D : public vtkMitkVolumeTextureMapper3D { public: - vtkTypeRevisionMacro(vtkMitkOpenGLVolumeTextureMapper3D,vtkMitkVolumeTextureMapper3D); + vtkTypeMacro(vtkMitkOpenGLVolumeTextureMapper3D,vtkMitkVolumeTextureMapper3D); void PrintSelf(ostream& os, vtkIndent indent); static vtkMitkOpenGLVolumeTextureMapper3D *New(); // Description: // Is hardware rendering supported? No if the input data is // more than one independent component, or if the hardware does // not support the required extensions // int IsRenderSupported(vtkVolumeProperty *); int IsRenderSupported(vtkRenderer *ren,vtkVolumeProperty *); //BTX // 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); //ETX // Desciption: // Initialize when we go to render, or go to answer the // IsRenderSupported question. Don't call unless we have // a valid OpenGL context! vtkGetMacro( Initialized, int ); // Description: // Release any graphics resources that are being consumed by this texture. // The parameter window could be used to determine which graphic // resources to release. // deprecatedSince{2013_12} Use ReleaseGraphicsResources(mitk::BaseRenderer* renderer) instead DEPRECATED(void ReleaseGraphicsResources(vtkWindow *)); // Description: // Release any graphics resources that are being consumed by this texture. // The parameter renderer could be used to determine which graphic // resources to release. void ReleaseGraphicsResources(mitk::BaseRenderer * renderer); protected: vtkMitkOpenGLVolumeTextureMapper3D(); ~vtkMitkOpenGLVolumeTextureMapper3D(); bool RenderPossible; //BTX void GetLightInformation(vtkRenderer *ren, vtkVolume *vol, GLfloat lightDirection[2][4], GLfloat lightDiffuseColor[2][4], GLfloat lightSpecularColor[2][4], GLfloat halfwayVector[2][4], GLfloat *ambient ); //ETX int Initialized; GLuint Volume1Index; GLuint Volume2Index; GLuint Volume3Index; GLuint ColorLookupIndex; GLuint AlphaLookupIndex; GLuint prgOneComponentShade; GLuint prgRGBAShade; vtkRenderWindow *RenderWindow; bool SupportsCompressedTexture; //void Initialize(); void Initialize(vtkRenderer *r); virtual void RenderFP(vtkRenderer *ren, vtkVolume *vol); void SetupOneIndependentTextures( vtkRenderer *ren, vtkVolume *vol ); void RenderOneIndependentShadeFP( vtkRenderer *ren, vtkVolume *vol ); void SetupRGBATextures( vtkRenderer *ren, vtkVolume *vol ); void RenderRGBAShadeFP( vtkRenderer *ren, vtkVolume *vol ); void DeleteTextureIndex( GLuint *index ); void CreateTextureIndex( GLuint *index ); void RenderPolygons( vtkRenderer *ren, vtkVolume *vol, int stages[4] ); void SetupProgramLocalsForShadingFP( vtkRenderer *ren, vtkVolume *vol ); void Setup3DTextureParameters( bool linear ); void ComputeVolumeDimensions(); bool UpdateVolumes( vtkVolume * ); bool UpdateVolumesRGBA( vtkVolume * ); private: vtkMitkOpenGLVolumeTextureMapper3D(const vtkMitkOpenGLVolumeTextureMapper3D&); // Not implemented. void operator=(const vtkMitkOpenGLVolumeTextureMapper3D&); // Not implemented. }; #endif diff --git a/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.cpp b/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.cpp index 0e6ab0964a..21d75b1d16 100644 --- a/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.cpp +++ b/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.cpp @@ -1,741 +1,740 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkMitkVolumeTextureMapper3D.h" #include "mitkCommon.h" #define GPU_INFO MITK_INFO("mapper.vr") #define GPU_WARN MITK_WARN("mapper.vr") #include "vtkCamera.h" #include "vtkColorTransferFunction.h" #include "vtkDataArray.h" #include "vtkImageData.h" #include "vtkMath.h" #include "vtkMatrix4x4.h" #include "vtkPiecewiseFunction.h" #include "vtkPointData.h" #include "vtkRenderer.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include "vtkVolumeRenderingFactory.h" -vtkCxxRevisionMacro(vtkMitkVolumeTextureMapper3D, "$Revision: 1.16 $"); //---------------------------------------------------------------------------- // Needed when we don't use the vtkStandardNewMacro. vtkInstantiatorNewMacro(vtkMitkVolumeTextureMapper3D); //---------------------------------------------------------------------------- //----------------------------------------------------------------------------- vtkMitkVolumeTextureMapper3D::vtkMitkVolumeTextureMapper3D() { //GPU_INFO << "vtkMitkVolumeTextureMapper3D"; this->PolygonBuffer = NULL; this->IntersectionBuffer = NULL; this->NumberOfPolygons = 0; this->BufferSize = 0; // The input used when creating the textures this->SavedTextureInput = NULL; // The input used when creating the color tables this->SavedParametersInput = NULL; this->SavedRGBFunction = NULL; this->SavedGrayFunction = NULL; this->SavedScalarOpacityFunction = NULL; this->SavedGradientOpacityFunction = NULL; this->SavedColorChannels = 0; this->SavedSampleDistance = 0; this->SavedScalarOpacityDistance = 0; /* this->Volume1 = NULL; this->Volume2 = NULL; this->Volume3 = NULL; */ /* this->VolumeSize = 0; this->VolumeComponents = 0; */ this->VolumeSpacing[0] = this->VolumeSpacing[1] = this->VolumeSpacing[2] = 0; this->VolumeDimensions[0]=0; this->VolumeDimensions[1]=0; this->VolumeDimensions[2]=0; this->SampleDistance = 1.0; this->ActualSampleDistance = 1.0; this->UseCompressedTexture = false; this->SupportsNonPowerOfTwoTextures = false; //GPU_INFO << "np2: " << (this->SupportsNonPowerOfTwoTextures?1:0); } //----------------------------------------------------------------------------- vtkMitkVolumeTextureMapper3D::~vtkMitkVolumeTextureMapper3D() { //GPU_INFO << "~vtkMitkVolumeTextureMapper3D"; delete [] this->PolygonBuffer; delete [] this->IntersectionBuffer; /* delete [] this->Volume1; delete [] this->Volume2; delete [] this->Volume3; */ } //----------------------------------------------------------------------------- vtkMitkVolumeTextureMapper3D *vtkMitkVolumeTextureMapper3D::New() { //GPU_INFO << "New"; // First try to create the object from the vtkObjectFactory vtkObject* ret = vtkVolumeRenderingFactory::CreateInstance("vtkMitkVolumeTextureMapper3D"); return static_cast(ret); } //----------------------------------------------------------------------------- void vtkMitkVolumeTextureMapper3D::ComputePolygons( vtkRenderer *ren, vtkVolume *vol, double inBounds[6] ) { //GPU_INFO << "ComputePolygons"; // Get the camera position and focal point double focalPoint[4], position[4]; double plane[4]; vtkCamera *camera = ren->GetActiveCamera(); camera->GetPosition( position ); camera->GetFocalPoint( focalPoint ); position[3] = 1.0; focalPoint[3] = 1.0; // Pass the focal point and position through the inverse of the // volume's matrix to map back into the data coordinates. We // are going to compute these polygons in the coordinate system // of the input data - this is easiest since this data must be // axis aligned. Then we'll use OpenGL to transform these polygons // into the world coordinate system through the use of the // volume's matrix. vtkMatrix4x4 *matrix = vtkMatrix4x4::New(); vol->GetMatrix( matrix ); matrix->Invert(); matrix->MultiplyPoint( position, position ); matrix->MultiplyPoint( focalPoint, focalPoint ); matrix->Delete(); if ( position[3] ) { position[0] /= position[3]; position[1] /= position[3]; position[2] /= position[3]; } if ( focalPoint[3] ) { focalPoint[0] /= focalPoint[3]; focalPoint[1] /= focalPoint[3]; focalPoint[2] /= focalPoint[3]; } // Create a plane equation using the direction and position of the camera plane[0] = focalPoint[0] - position[0]; plane[1] = focalPoint[1] - position[1]; plane[2] = focalPoint[2] - position[2]; vtkMath::Normalize( plane ); plane[3] = -(plane[0] * position[0] + plane[1] * position[1] + plane[2] * position[2]); // Find the min and max distances of the boundary points of the volume double minDistance = VTK_DOUBLE_MAX; double maxDistance = VTK_DOUBLE_MIN; // The inBounds parameter is the bounds we are using for clipping the // texture planes against. First we need to clip these against the bounds // of the volume to make sure they don't exceed it. double volBounds[6]; this->GetInput()->GetBounds( volBounds ); double bounds[6]; bounds[0] = (inBounds[0]>volBounds[0])?(inBounds[0]):(volBounds[0]); bounds[1] = (inBounds[1]volBounds[2])?(inBounds[2]):(volBounds[2]); bounds[3] = (inBounds[3]volBounds[4])?(inBounds[4]):(volBounds[4]); bounds[5] = (inBounds[5]maxDistance)?(d):(maxDistance); } } } int dim[6]; this->GetVolumeDimensions(dim); float tCoordOffset[3], tCoordScale[3]; tCoordOffset[0] = 0.5 / dim[0]; tCoordOffset[1] = 0.5 / dim[1]; tCoordOffset[2] = 0.5 / dim[2]; tCoordScale[0] = (dim[0]-1) / static_cast(dim[0]); tCoordScale[1] = (dim[1]-1) / static_cast(dim[1]); tCoordScale[2] = (dim[2]-1) / static_cast(dim[2]); float spacing[3]; this->GetVolumeSpacing( spacing ); double offset = 0.333 * 0.5 * (spacing[0] + spacing[1] + spacing[2]); minDistance += 0.1*offset; maxDistance -= 0.1*offset; minDistance = (minDistance < offset)?(offset):(minDistance); double stepSize = this->ActualSampleDistance; // Determine the number of polygons int numPolys = static_cast( (maxDistance - minDistance)/static_cast(stepSize)); // Check if we have space, free old space only if it is too small if ( this->BufferSize < numPolys ) { delete [] this->PolygonBuffer; delete [] this->IntersectionBuffer; this->BufferSize = numPolys; this->PolygonBuffer = new float [36*this->BufferSize]; this->IntersectionBuffer = new float [12*this->BufferSize]; } this->NumberOfPolygons = numPolys; // Compute the intersection points for each edge of the volume int lines[12][2] = { {0,1}, {1,3}, {2,3}, {0,2}, {4,5}, {5,7}, {6,7}, {4,6}, {0,4}, {1,5}, {3,7}, {2,6} }; float *iptr, *pptr; for ( i = 0; i < 12; i++ ) { double line[3]; line[0] = vertices[lines[i][1]][0] - vertices[lines[i][0]][0]; line[1] = vertices[lines[i][1]][1] - vertices[lines[i][0]][1]; line[2] = vertices[lines[i][1]][2] - vertices[lines[i][0]][2]; double d = maxDistance; iptr = this->IntersectionBuffer + i; double planeDotLineOrigin = vtkMath::Dot( plane, vertices[lines[i][0]] ); double planeDotLine = vtkMath::Dot( plane, line ); double t, increment; if ( planeDotLine != 0.0 ) { t = (d - planeDotLineOrigin - plane[3] ) / planeDotLine; increment = -stepSize / planeDotLine; } else { t = -1.0; increment = 0.0; } for ( j = 0; j < numPolys; j++ ) { *iptr = (t > 0.0 && t < 1.0)?(t):(-1.0); t += increment; iptr += 12; } } // Compute the polygons by determining which edges were intersected int neighborLines[12][6] = { { 1, 2, 3, 4, 8, 9}, { 0, 2, 3, 5, 9, 10}, { 0, 1, 3, 6, 10, 11}, { 0, 1, 2, 7, 8, 11}, { 0, 5, 6, 7, 8, 9}, { 1, 4, 6, 7, 9, 10}, { 2, 4, 5, 7, 10, 11}, { 3, 4, 5, 6, 8, 11}, { 0, 3, 4, 7, 9, 11}, { 0, 1, 4, 5, 8, 10}, { 1, 2, 5, 6, 9, 11}, { 2, 3, 6, 7, 8, 10} }; float tCoord[12][4] = {{0,0,0,0}, {1,0,0,1}, {0,1,0,0}, {0,0,0,1}, {0,0,1,0}, {1,0,1,1}, {0,1,1,0}, {0,0,1,1}, {0,0,0,2}, {1,0,0,2}, {1,1,0,2}, {0,1,0,2}}; double low[3]; double high[3]; low[0] = (bounds[0] - volBounds[0]) / (volBounds[1] - volBounds[0]); high[0] = (bounds[1] - volBounds[0]) / (volBounds[1] - volBounds[0]); low[1] = (bounds[2] - volBounds[2]) / (volBounds[3] - volBounds[2]); high[1] = (bounds[3] - volBounds[2]) / (volBounds[3] - volBounds[2]); low[2] = (bounds[4] - volBounds[4]) / (volBounds[5] - volBounds[4]); high[2] = (bounds[5] - volBounds[4]) / (volBounds[5] - volBounds[4]); for ( i = 0; i < 12; i++ ) { tCoord[i][0] = (tCoord[i][0])?(high[0]):(low[0]); tCoord[i][1] = (tCoord[i][1])?(high[1]):(low[1]); tCoord[i][2] = (tCoord[i][2])?(high[2]):(low[2]); } iptr = this->IntersectionBuffer; pptr = this->PolygonBuffer; for ( i = 0; i < numPolys; i++ ) { // Look for a starting point int start = 0; while ( start < 12 && iptr[start] == -1.0 ) { start++; } if ( start == 12 ) { pptr[0] = -1.0; } else { int current = start; int previous = -1; int errFlag = 0; idx = 0; while ( idx < 6 && !errFlag && ( idx == 0 || current != start) ) { double t = iptr[current]; *(pptr + idx*6) = tCoord[current][0] * tCoordScale[0] + tCoordOffset[0]; *(pptr + idx*6 + 1) = tCoord[current][1] * tCoordScale[1] + tCoordOffset[1]; *(pptr + idx*6 + 2) = tCoord[current][2] * tCoordScale[2] + tCoordOffset[2]; int coord = static_cast(tCoord[current][3]); *(pptr + idx*6 + coord) = (low[coord] + t*(high[coord]-low[coord]))*tCoordScale[coord] + tCoordOffset[coord]; *(pptr + idx*6 + 3) = static_cast( vertices[lines[current][0]][0] + t*(vertices[lines[current][1]][0] - vertices[lines[current][0]][0])); *(pptr + idx*6 + 4) = static_cast( vertices[lines[current][0]][1] + t*(vertices[lines[current][1]][1] - vertices[lines[current][0]][1])); *(pptr + idx*6 + 5) = static_cast( vertices[lines[current][0]][2] + t*(vertices[lines[current][1]][2] - vertices[lines[current][0]][2])); idx++; j = 0; while ( j < 6 && (*(this->IntersectionBuffer + i*12 + neighborLines[current][j]) < 0 || neighborLines[current][j] == previous) ) { j++; } if ( j >= 6 ) { errFlag = 1; } else { previous = current; current = neighborLines[current][j]; } } if ( idx < 6 ) { *(pptr + idx*6) = -1; } } iptr += 12; pptr += 36; } } void vtkMitkVolumeTextureMapper3D::UpdateMTime() { this->SavedTextureMTime.Modified(); } //----------------------------------------------------------------------------- int vtkMitkVolumeTextureMapper3D::UpdateColorLookup( vtkVolume *vol ) { //GPU_INFO << "UpdateColorLookup"; int needToUpdate = 0; // Get the image data vtkImageData *input = this->GetInput(); input->Update(); // Has the volume changed in some way? if ( this->SavedParametersInput != input || this->SavedParametersMTime.GetMTime() < input->GetMTime() ) { needToUpdate = 1; } // What sample distance are we going to use for rendering? If we // have to render quickly according to our allocated render time, // don't necessary obey the sample distance requested by the user. // Instead set the sample distance to the average spacing. this->ActualSampleDistance = this->SampleDistance; if ( vol->GetAllocatedRenderTime() < 1.0 ) { float spacing[3]; this->GetVolumeSpacing(spacing); this->ActualSampleDistance = 0.333 * (static_cast(spacing[0]) + static_cast(spacing[1]) + static_cast(spacing[2])); } // How many components? int components = input->GetNumberOfScalarComponents(); // Has the sample distance changed? if ( this->SavedSampleDistance != this->ActualSampleDistance ) { needToUpdate = 1; } vtkColorTransferFunction *rgbFunc = NULL; vtkPiecewiseFunction *grayFunc = NULL; // How many color channels for this component? int colorChannels = vol->GetProperty()->GetColorChannels(0); if ( components < 3 ) { // Has the number of color channels changed? if ( this->SavedColorChannels != colorChannels ) { needToUpdate = 1; } // Has the color transfer function changed in some way, // and we are using it? if ( colorChannels == 3 ) { rgbFunc = vol->GetProperty()->GetRGBTransferFunction(0); if ( this->SavedRGBFunction != rgbFunc || this->SavedParametersMTime.GetMTime() < rgbFunc->GetMTime() ) { needToUpdate = 1; } } // Has the gray transfer function changed in some way, // and we are using it? if ( colorChannels == 1 ) { grayFunc = vol->GetProperty()->GetGrayTransferFunction(0); if ( this->SavedGrayFunction != grayFunc || this->SavedParametersMTime.GetMTime() < grayFunc->GetMTime() ) { needToUpdate = 1; } } } // Has the scalar opacity transfer function changed in some way? vtkPiecewiseFunction *scalarOpacityFunc = vol->GetProperty()->GetScalarOpacity(0); if ( this->SavedScalarOpacityFunction != scalarOpacityFunc || this->SavedParametersMTime.GetMTime() < scalarOpacityFunc->GetMTime() ) { needToUpdate = 1; } // Has the gradient opacity transfer function changed in some way? vtkPiecewiseFunction *gradientOpacityFunc = vol->GetProperty()->GetGradientOpacity(0); if ( this->SavedGradientOpacityFunction != gradientOpacityFunc || this->SavedParametersMTime.GetMTime() < gradientOpacityFunc->GetMTime() ) { needToUpdate = 1; } double scalarOpacityDistance = vol->GetProperty()->GetScalarOpacityUnitDistance(0); if ( this->SavedScalarOpacityDistance != scalarOpacityDistance ) { needToUpdate = 1; } // If we have not found any need to update, return now if ( !needToUpdate ) { return 0; } this->SavedRGBFunction = rgbFunc; this->SavedGrayFunction = grayFunc; this->SavedScalarOpacityFunction = scalarOpacityFunc; this->SavedGradientOpacityFunction = gradientOpacityFunc; this->SavedColorChannels = colorChannels; this->SavedSampleDistance = this->ActualSampleDistance; this->SavedScalarOpacityDistance = scalarOpacityDistance; this->SavedParametersInput = input; this->SavedParametersMTime.Modified(); // Find the scalar range double scalarRange[2]; input->GetPointData()->GetScalars()->GetRange(scalarRange, components-1); int arraySizeNeeded = this->ColorTableSize; if ( components < 3 ) { // Sample the transfer functions between the min and max. if ( colorChannels == 1 ) { grayFunc->GetTable( scalarRange[0], scalarRange[1], arraySizeNeeded, this->TempArray1 ); } else { rgbFunc->GetTable( scalarRange[0], scalarRange[1], arraySizeNeeded, this->TempArray1 ); } } scalarOpacityFunc->GetTable( scalarRange[0], scalarRange[1], arraySizeNeeded, this->TempArray2 ); float goArray[256]; gradientOpacityFunc->GetTable( 0, (scalarRange[1] - scalarRange[0])*0.25, 256, goArray ); // Correct the opacity array for the spacing between the planes. int i; float *fptr2 = this->TempArray2; double factor = this->ActualSampleDistance / scalarOpacityDistance; for ( i = 0; i < arraySizeNeeded; i++ ) { if ( *fptr2 > 0.0001 ) { *fptr2 = 1.0-pow(static_cast(1.0-(*fptr2)),factor); } fptr2++; } int goLoop; unsigned char *ptr, *rgbptr, *aptr; float *fptr1; switch (components) { case 1: // Move the two temp float arrays into one RGBA unsigned char array ptr = this->ColorLookup; for ( goLoop = 0; goLoop < 256; goLoop++ ) { fptr1 = this->TempArray1; fptr2 = this->TempArray2; if ( colorChannels == 1 ) { for ( i = 0; i < arraySizeNeeded; i++ ) { *(ptr++) = static_cast(*(fptr1)*255.0 + 0.5); *(ptr++) = static_cast(*(fptr1)*255.0 + 0.5); *(ptr++) = static_cast(*(fptr1++)*255.0 + 0.5); *(ptr++) = static_cast(*(fptr2++)*goArray[goLoop]*255.0 + 0.5); } } else { for ( i = 0; i < arraySizeNeeded; i++ ) { *(ptr++) = static_cast(*(fptr1++)*255.0 + 0.5); *(ptr++) = static_cast(*(fptr1++)*255.0 + 0.5); *(ptr++) = static_cast(*(fptr1++)*255.0 + 0.5); *(ptr++) = static_cast(*(fptr2++)*goArray[goLoop]*255.0 + 0.5); } } for ( ; i < 256; i++ ) { *(ptr++) = 0; *(ptr++) = 0; *(ptr++) = 0; *(ptr++) = 0; } } break; case 2: // Move the two temp float arrays into one RGB unsigned char array and // one alpha array. rgbptr = this->ColorLookup; aptr = this->AlphaLookup; if ( colorChannels == 1 ) { for ( i = 0; i < arraySizeNeeded; i++ ) { fptr1 = this->TempArray1; fptr2 = this->TempArray2; for ( goLoop = 0; goLoop < 256; goLoop++ ) { *(rgbptr++) = static_cast(*(fptr1)*255.0 + 0.5); *(rgbptr++) = static_cast(*(fptr1)*255.0 + 0.5); *(rgbptr++) = static_cast(*(fptr1++)*255.0 + 0.5); *(aptr++) = static_cast(*(fptr2++)*goArray[goLoop]*255.0 + 0.5); } } } else { fptr1 = this->TempArray1; fptr2 = this->TempArray2; for ( i = 0; i < arraySizeNeeded; i++ ) { for ( goLoop = 0; goLoop < 256; goLoop++ ) { *(rgbptr++) = static_cast(*(fptr1)*255.0 + 0.5); *(rgbptr++) = static_cast(*(fptr1+1)*255.0 + 0.5); *(rgbptr++) = static_cast(*(fptr1+2)*255.0 + 0.5); *(aptr++) = static_cast(*(fptr2)*goArray[goLoop]*255.0 + 0.5); } fptr1+=3; fptr2++; } } for ( ; i < 256; i++ ) { for ( goLoop = 0; goLoop < 256; goLoop++ ) { *(rgbptr++) = 0; *(rgbptr++) = 0; *(rgbptr++) = 0; *(aptr++) = 0; } } break; case 3: case 4: // Move the two temp float arrays into one alpha array aptr = this->AlphaLookup; for ( goLoop = 0; goLoop < 256; goLoop++ ) { fptr2 = this->TempArray2; for ( i = 0; i < arraySizeNeeded; i++ ) { *(aptr++) = static_cast(*(fptr2++)*goArray[goLoop]*255.0 + 0.5); } for ( ; i < 256; i++ ) { *(aptr++) = 0; } } break; } return 1; } //----------------------------------------------------------------------------- // Print the vtkMitkVolumeTextureMapper3D void vtkMitkVolumeTextureMapper3D::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Sample Distance: " << this->SampleDistance << endl; os << indent << "NumberOfPolygons: " << this->NumberOfPolygons << endl; os << indent << "ActualSampleDistance: " << this->ActualSampleDistance << endl; os << indent << "VolumeDimensions: " << this->VolumeDimensions[0] << " " << this->VolumeDimensions[1] << " " << this->VolumeDimensions[2] << endl; os << indent << "VolumeSpacing: " << this->VolumeSpacing[0] << " " << this->VolumeSpacing[1] << " " << this->VolumeSpacing[2] << endl; os << indent << "UseCompressedTexture: " << this->UseCompressedTexture << endl; } diff --git a/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.h b/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.h index 3b96deb32d..117157e656 100644 --- a/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.h +++ b/Modules/MitkExt/Rendering/vtkMitkVolumeTextureMapper3D.h @@ -1,235 +1,235 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // .NAME vtkMitkVolumeTextureMapper3D - volume render with 3D texture mapping // .SECTION Description // vtkMitkVolumeTextureMapper3D renders a volume using 3D texture mapping. // This class is actually an abstract superclass - with all the actual // work done by vtkMitkOpenGLVolumeTextureMapper3D. // // This mappers currently supports: // // - any data type as input // - one component, or two or four non-independent components // - composite blending // - intermixed opaque geometry // - multiple volumes can be rendered if they can // be sorted into back-to-front order (use the vtkFrustumCoverageCuller) // // This mapper does not support: // - more than one independent component // - maximum intensity projection // // Internally, this mapper will potentially change the resolution of the // input data. The data will be resampled to be a power of two in each // direction, and also no greater than 128*256*256 voxels (any aspect) // for one or two component data, or 128*128*256 voxels (any aspect) // for four component data. The limits are currently hardcoded after // a check using the GL_PROXY_TEXTURE3D because some graphics drivers // were always responding "yes" to the proxy call despite not being // able to allocate that much texture memory. // // Currently, calculations are computed using 8 bits per RGBA channel. // In the future this should be expanded to handle newer boards that // can support 15 bit float compositing. // // This mapper supports two main families of graphics hardware: // nvidia and ATI. There are two different implementations of // 3D texture mapping used - one based on nvidia's GL_NV_texture_shader2 // and GL_NV_register_combiners2 extension, and one based on // ATI's GL_ATI_fragment_shader (supported also by some nvidia boards) // To use this class in an application that will run on various // hardware configurations, you should have a back-up volume rendering // method. You should create a vtkMitkVolumeTextureMapper3D, assign its // input, make sure you have a current OpenGL context (you've rendered // at least once), then call IsRenderSupported with a vtkVolumeProperty // as an argument. This method will return 0 if the input has more than // one independent component, or if the graphics hardware does not // support the set of required extensions for using at least one of // the two implemented methods (nvidia or ati) // // .SECTION Thanks // Thanks to Alexandre Gouaillard at the Megason Lab, Department of Systems // Biology, Harvard Medical School // https://wiki.med.harvard.edu/SysBio/Megason/ // for the idea and initial patch to speed-up rendering with compressed // textures. // // .SECTION see also // vtkVolumeMapper #ifndef __vtkMitkVolumeTextureMapper3D_h #define __vtkMitkVolumeTextureMapper3D_h #include "vtkVolumeMapper.h" #include "MitkExtExports.h" class vtkImageData; class vtkColorTransferFunction; class vtkPiecewiseFunction; class vtkVolumeProperty; #include "mitkCommon.h" class MitkExt_EXPORT vtkMitkVolumeTextureMapper3D : public vtkVolumeMapper { public: - vtkTypeRevisionMacro(vtkMitkVolumeTextureMapper3D,vtkVolumeMapper); + vtkTypeMacro(vtkMitkVolumeTextureMapper3D,vtkVolumeMapper); void PrintSelf(ostream& os, vtkIndent indent); static vtkMitkVolumeTextureMapper3D *New(); // Description: // The distance at which to space sampling planes. This // may not be honored for interactive renders. An interactive // render is defined as one that has less than 1 second of // allocated render time. vtkSetMacro( SampleDistance, float ); vtkGetMacro( SampleDistance, float ); // Description: // These are the dimensions of the 3D texture vtkGetVectorMacro( VolumeDimensions, int, 3 ); // Description: // This is the spacing of the 3D texture vtkGetVectorMacro( VolumeSpacing, float, 3 ); // Description: // Based on hardware and properties, we may or may not be able to // render using 3D texture mapping. This indicates if 3D texture // mapping is supported by the hardware, and if the other extensions // necessary to support the specific properties are available. virtual int IsRenderSupported( vtkRenderer *, vtkVolumeProperty *) =0; // Description: // Allow access to the number of polygons used for the // rendering. vtkGetMacro( NumberOfPolygons, int ); // Description: // Allow access to the actual sample distance used to render // the image. vtkGetMacro( ActualSampleDistance, float ); //BTX // 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 *, vtkVolume *) {}; // Description: // Set/Get if the mapper use compressed textures (if supported by the // hardware). Initial value is false. // There are two reasons to use compressed textures: 1. rendering can be 4 // times faster. 2. It saves some VRAM. // There is one reason to not use compressed textures: quality may be lower // than with uncompressed textures. vtkSetMacro(UseCompressedTexture,bool); vtkGetMacro(UseCompressedTexture,bool); void UpdateMTime(); protected: vtkMitkVolumeTextureMapper3D(); ~vtkMitkVolumeTextureMapper3D(); float *PolygonBuffer; float *IntersectionBuffer; int NumberOfPolygons; int BufferSize; /* unsigned char *Volume1; unsigned char *Volume2; unsigned char *Volume3; */ /* int VolumeSize; int VolumeComponents; */ int VolumeDimensions[3]; float VolumeSpacing[3]; float SampleDistance; float ActualSampleDistance; vtkImageData *SavedTextureInput; vtkImageData *SavedParametersInput; vtkColorTransferFunction *SavedRGBFunction; vtkPiecewiseFunction *SavedGrayFunction; vtkPiecewiseFunction *SavedScalarOpacityFunction; vtkPiecewiseFunction *SavedGradientOpacityFunction; int SavedColorChannels; float SavedSampleDistance; float SavedScalarOpacityDistance; unsigned char ColorLookup[65536*4]; unsigned char AlphaLookup[65536]; float TempArray1[3*4096]; float TempArray2[4096]; int ColorTableSize; float ColorTableScale; float ColorTableOffset; unsigned char DiffuseLookup[65536*4]; unsigned char SpecularLookup[65536*4]; vtkTimeStamp SavedTextureMTime; vtkTimeStamp SavedParametersMTime; bool UseCompressedTexture; bool SupportsNonPowerOfTwoTextures; // Description: // For the given viewing direction, compute the set of polygons. void ComputePolygons( vtkRenderer *ren, vtkVolume *vol, double bounds[6] ); // Description: // Update the internal RGBA representation of the volume. Return 1 if // anything change, 0 if nothing changed. int UpdateColorLookup( vtkVolume * ); // Description: // Impemented in subclass - check is texture size is OK. //BTX virtual int IsTextureSizeSupported(int vtkNotUsed(size)[3], int vtkNotUsed(components)) { return 0; } //ETX private: vtkMitkVolumeTextureMapper3D(const vtkMitkVolumeTextureMapper3D&); // Not implemented. void operator=(const vtkMitkVolumeTextureMapper3D&); // Not implemented. }; #endif diff --git a/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.cpp b/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.cpp index 514d8805f6..8c57d69101 100644 --- a/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.cpp +++ b/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.cpp @@ -1,239 +1,238 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "vtkUnstructuredGridMapper.h" #include "vtkGeometryFilter.h" #include "vtkExecutive.h" #include "vtkGarbageCollector.h" #include "vtkInformation.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkUnstructuredGrid.h" -vtkCxxRevisionMacro(vtkUnstructuredGridMapper, "$Revision$"); vtkStandardNewMacro(vtkUnstructuredGridMapper); //---------------------------------------------------------------------------- vtkUnstructuredGridMapper::vtkUnstructuredGridMapper() { this->GeometryExtractor = 0; this->PolyDataMapper = 0; } //---------------------------------------------------------------------------- vtkUnstructuredGridMapper::~vtkUnstructuredGridMapper() { // delete internally created objects. if ( this->GeometryExtractor ) { this->GeometryExtractor->Delete(); } if ( this->PolyDataMapper ) { this->PolyDataMapper->Delete(); } } void vtkUnstructuredGridMapper::SetBoundingObject(mitk::BoundingObject* bo) { m_BoundingObject = bo; } //---------------------------------------------------------------------------- void vtkUnstructuredGridMapper::SetInput(vtkUnstructuredGrid *input) { if(input) { this->SetInputConnection(0, input->GetProducerPort()); } else { // Setting a NULL input removes the connection. this->SetInputConnection(0, 0); } } //---------------------------------------------------------------------------- vtkUnstructuredGrid *vtkUnstructuredGridMapper::GetInput() { //return this->Superclass::GetInputAsDataSet(); return vtkUnstructuredGrid::SafeDownCast( this->GetExecutive()->GetInputData(0, 0)); } //---------------------------------------------------------------------------- void vtkUnstructuredGridMapper::ReleaseGraphicsResources( vtkWindow *renWin ) { if (this->PolyDataMapper) { this->PolyDataMapper->ReleaseGraphicsResources( renWin ); } } //---------------------------------------------------------------------------- void vtkUnstructuredGridMapper::ReleaseGraphicsResources( mitk::BaseRenderer * renderer ) { if (this->PolyDataMapper) { this->PolyDataMapper->ReleaseGraphicsResources( renderer->GetVtkRenderer()->GetRenderWindow()); } } //---------------------------------------------------------------------------- // Receives from Actor -> maps data to primitives // void vtkUnstructuredGridMapper::Render(vtkRenderer *ren, vtkActor *act) { // make sure that we've been properly initialized // if ( !this->GetInput() ) { vtkErrorMacro(<< "No input!\n"); return; } // Need a lookup table // if ( this->LookupTable == 0 ) { this->CreateDefaultLookupTable(); } this->LookupTable->Build(); // Now can create appropriate mapper // if ( this->PolyDataMapper == 0 ) { vtkGeometryFilter *gf = vtkGeometryFilter::New(); vtkPolyDataMapper *pm = vtkPolyDataMapper::New(); pm->SetInput(gf->GetOutput()); this->GeometryExtractor = gf; this->PolyDataMapper = pm; } // share clipping planes with the PolyDataMapper // if (this->ClippingPlanes != this->PolyDataMapper->GetClippingPlanes()) { this->PolyDataMapper->SetClippingPlanes(this->ClippingPlanes); } if (this->m_BoundingObject) { mitk::BoundingBox::BoundsArrayType bounds = this->m_BoundingObject->GetGeometry()->CalculateBoundingBoxRelativeToTransform(0)->GetBounds(); this->GeometryExtractor->SetExtent(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]); this->GeometryExtractor->ExtentClippingOn(); } else { this->GeometryExtractor->ExtentClippingOff(); } this->GeometryExtractor->SetInput(this->GetInput()); this->PolyDataMapper->SetInput(this->GeometryExtractor->GetOutput()); // update ourselves in case something has changed this->PolyDataMapper->SetLookupTable(this->GetLookupTable()); this->PolyDataMapper->SetScalarVisibility(this->GetScalarVisibility()); this->PolyDataMapper->SetUseLookupTableScalarRange( this->GetUseLookupTableScalarRange()); this->PolyDataMapper->SetScalarRange(this->GetScalarRange()); this->PolyDataMapper->SetImmediateModeRendering( this->GetImmediateModeRendering()); this->PolyDataMapper->SetColorMode(this->GetColorMode()); this->PolyDataMapper->SetInterpolateScalarsBeforeMapping( this->GetInterpolateScalarsBeforeMapping()); this->PolyDataMapper->SetScalarMode(this->GetScalarMode()); if ( this->ScalarMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA || this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA ) { if ( this->ArrayAccessMode == VTK_GET_ARRAY_BY_ID ) { this->PolyDataMapper->ColorByArrayComponent(this->ArrayId,ArrayComponent); } else { this->PolyDataMapper->ColorByArrayComponent(this->ArrayName,ArrayComponent); } } this->PolyDataMapper->Render(ren,act); this->TimeToDraw = this->PolyDataMapper->GetTimeToDraw(); } //---------------------------------------------------------------------------- void vtkUnstructuredGridMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if ( this->PolyDataMapper ) { os << indent << "Poly Mapper: (" << this->PolyDataMapper << ")\n"; } else { os << indent << "Poly Mapper: (none)\n"; } if ( this->GeometryExtractor ) { os << indent << "Geometry Extractor: (" << this->GeometryExtractor << ")\n"; } else { os << indent << "Geometry Extractor: (none)\n"; } } //---------------------------------------------------------------------------- unsigned long vtkUnstructuredGridMapper::GetMTime() { unsigned long mTime=this->vtkMapper::GetMTime(); unsigned long time; if ( this->LookupTable != NULL ) { time = this->LookupTable->GetMTime(); mTime = ( time > mTime ? time : mTime ); } return mTime; } //---------------------------------------------------------------------------- int vtkUnstructuredGridMapper::FillInputPortInformation( int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkUnstructuredGrid"); return 1; } //---------------------------------------------------------------------------- void vtkUnstructuredGridMapper::ReportReferences(vtkGarbageCollector* collector) { this->Superclass::ReportReferences(collector); // These filters share our input and are therefore involved in a // reference loop. vtkGarbageCollectorReport(collector, this->GeometryExtractor, "GeometryExtractor"); vtkGarbageCollectorReport(collector, this->PolyDataMapper, "PolyDataMapper"); } diff --git a/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.h b/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.h index 785f689734..bda7b34d30 100644 --- a/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.h +++ b/Modules/MitkExt/Rendering/vtkUnstructuredGridMapper.h @@ -1,88 +1,88 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __vtkUnstructuredGridMapper_h #define __vtkUnstructuredGridMapper_h #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkBoundingObject.h" #include "mitkBaseRenderer.h" #include "vtkMapper.h" class vtkPolyDataMapper; class vtkGeometryFilter; class vtkUnstructuredGrid; class MitkExt_EXPORT vtkUnstructuredGridMapper : public vtkMapper { public: static vtkUnstructuredGridMapper *New(); - vtkTypeRevisionMacro(vtkUnstructuredGridMapper,vtkMapper); + vtkTypeMacro(vtkUnstructuredGridMapper,vtkMapper); void PrintSelf(ostream& os, vtkIndent indent); void Render(vtkRenderer *ren, vtkActor *act); // Description: // Get the internal poly data mapper used to map data set to graphics system. vtkGetObjectMacro(PolyDataMapper, vtkPolyDataMapper); // Description: // Release any graphics resources that are being consumed by this mapper. // The parameter window could be used to determine which graphic // resources to release. // deprecatedSince{2013_12} Use ReleaseGraphicsResources(mitk::BaseRenderer* renderer) instead DEPRECATED(void ReleaseGraphicsResources(vtkWindow *)); // Description: // Release any graphics resources that are being consumed by this mapper. // The parameter renderer could be used to determine which graphic // resources to release. // deprecatedSince{2013_12} Use ReleaseGraphicsResources(mitk::BaseRenderer* renderer) instead void ReleaseGraphicsResources(mitk::BaseRenderer * renderer); // Description: // Get the mtime also considering the lookup table. unsigned long GetMTime(); // Description: // Set the Input of this mapper. void SetInput(vtkUnstructuredGrid *input); vtkUnstructuredGrid *GetInput(); void SetBoundingObject(mitk::BoundingObject* bo); protected: vtkUnstructuredGridMapper(); ~vtkUnstructuredGridMapper(); vtkGeometryFilter *GeometryExtractor; vtkPolyDataMapper *PolyDataMapper; mitk::BoundingObject::Pointer m_BoundingObject; virtual void ReportReferences(vtkGarbageCollector*); // see algorithm for more info virtual int FillInputPortInformation(int port, vtkInformation* info); private: vtkUnstructuredGridMapper(const vtkUnstructuredGridMapper&); // Not implemented. void operator=(const vtkUnstructuredGridMapper&); // Not implemented. }; #endif // __vtkUnstructuredGridMapper_h