7 #include "fwRenderVTK/SRender.hpp" 9 #include "fwRenderVTK/IAdaptor.hpp" 10 #include "fwRenderVTK/IVtkRenderWindowInteractorManager.hpp" 11 #include "fwRenderVTK/OffScreenInteractorManager.hpp" 12 #include "fwRenderVTK/registry/adaptors.hpp" 13 #include "fwRenderVTK/vtk/InteractorStyle3DForNegato.hpp" 15 #include <fwCom/Signal.hpp> 16 #include <fwCom/Signal.hxx> 17 #include <fwCom/Slot.hpp> 18 #include <fwCom/Slot.hxx> 19 #include <fwCom/Slots.hpp> 20 #include <fwCom/Slots.hxx> 22 #include <fwData/Color.hpp> 23 #include <fwData/mt/ObjectWriteLock.hpp> 25 #include <fwRuntime/ConfigurationElementContainer.hpp> 26 #include <fwRuntime/utils/GenericExecutableFactoryRegistrar.hpp> 28 #include <fwServices/helper/Config.hpp> 29 #include <fwServices/macros.hpp> 30 #include <fwServices/op/Add.hpp> 32 #include <fwThread/Timer.hpp> 34 #include <fwTools/fwID.hpp> 36 #include <fwVtkIO/vtk.hpp> 38 #include <boost/foreach.hpp> 39 #include <boost/function.hpp> 40 #include <boost/optional.hpp> 42 #include <vtkCellPicker.h> 43 #include <vtkImageFlip.h> 44 #include <vtkInstantiator.h> 45 #include <vtkRenderer.h> 46 #include <vtkRendererCollection.h> 47 #include <vtkRenderWindow.h> 48 #include <vtkSmartPointer.h> 49 #include <vtkTransform.h> 50 #include <vtkWindowToImageFilter.h> 58 const ::fwCom::Signals::SignalKeyType SRender::s_DROPPED_SIG =
"dropped";
59 const ::fwCom::Slots::SlotKeyType SRender::s_RENDER_SLOT =
"render";
60 const ::fwCom::Slots::SlotKeyType SRender::s_REQUEST_RENDER_SLOT =
"requestRender";
61 const ::fwCom::Slots::SlotKeyType SRender::s_TOGGLE_AUTO_RENDER_SLOT =
"toggleAutoRender";
63 static const ::fwServices::IService::KeyType s_OFFSCREEN_INOUT =
"offScreen";
67 SRender::SRender() noexcept :
68 m_pendingRenderRequest(false),
69 m_renderMode(RenderMode::AUTO),
75 newSignal<DroppedSignalType>(s_DROPPED_SIG);
77 newSlot(s_RENDER_SLOT, &SRender::render,
this);
78 newSlot(s_REQUEST_RENDER_SLOT, &SRender::requestRender,
this);
79 newSlot(s_TOGGLE_AUTO_RENDER_SLOT, &SRender::toggleAutoRender,
this);
84 SRender::~SRender() noexcept
90 void SRender::configureRenderer(
const ConfigType& rendererConf )
92 const std::string
id = rendererConf.get<std::string>(
"<xmlattr>.id");
93 const std::string background = rendererConf.get<std::string>(
"<xmlattr>.background",
"");
95 if(m_renderers.count(
id) == 0)
97 m_renderers[id] = vtkRenderer::New();
101 m_renderers[id]->SetUseDepthPeeling( 1 );
102 m_renderers[id]->SetMaximumNumberOfPeels( 8 );
103 m_renderers[id]->SetOcclusionRatio( 0. );
106 const int layer = rendererConf.get<
int>(
"<xmlattr>.layer", m_renderers[id]->GetLayer());
107 m_renderers[id]->SetLayer(layer);
110 if ( !background.empty() )
112 if(background[0] ==
'#')
114 ::fwData::Color::sptr color = ::fwData::Color::New();
115 color->setRGBA(background);
116 m_renderers[id]->SetBackground(color->getRGBA()[0], color->getRGBA()[1], color->getRGBA()[2]);
121 double color = std::stod(background);
122 m_renderers[id]->SetBackground(color, color, color);
129 void SRender::configurePicker(
const ConfigType& pickerConf )
131 const std::string
id = pickerConf.get<std::string>(
"<xmlattr>.id");
132 const std::string vtkclass = pickerConf.get<std::string>(
"<xmlattr>.vtkclass",
"vtkCellPicker");
133 const double tolerance = pickerConf.get<
double>(
"<xmlattr>.tolerance", 0.0);
135 if(m_pickers.count(
id) == 0)
137 m_pickers[id] = vtkAbstractPropPicker::SafeDownCast(vtkInstantiator::CreateInstance(vtkclass.c_str()));
138 OSLM_ASSERT(
"'" << vtkclass.c_str() <<
"' instantiation failled.", m_pickers[id]);
139 m_pickers[id]->InitializePickList();
140 m_pickers[id]->PickFromListOn();
141 vtkPicker* picker = vtkPicker::SafeDownCast(m_pickers[
id]);
144 picker->SetTolerance(tolerance);
151 void SRender::configureVtkObject(
const ConfigType& vtkObjectConf )
153 const std::string
id = vtkObjectConf.get<std::string>(
"<xmlattr>.id");
154 const std::string vtkClass = vtkObjectConf.get<std::string>(
"<xmlattr>.class");
157 SLM_ASSERT(
"Empty 'class'.", !vtkClass.empty() );
159 if( m_vtkObjects.count(
id) == 0 )
161 if ( vtkClass ==
"vtkTransform" )
163 m_vtkObjects[id] = createVtkTransform(vtkObjectConf);
167 m_vtkObjects[id] = vtkInstantiator::CreateInstance(vtkClass.c_str());
174 vtkTransform* SRender::createVtkTransform(
const ConfigType& vtkObjectConf )
176 vtkTransform* newMat = vtkTransform::New();
178 SLM_ASSERT(
"VTK transforms can contain at most one 'vtkTransform' sub-element.",
179 vtkObjectConf.count(
"vtkTransform") <= 1 );
181 const ::boost::optional<const ConfigType&> vtkTransformConf = vtkObjectConf.get_child_optional(
"vtkTransform");
183 if(vtkTransformConf.is_initialized())
185 BOOST_FOREACH(const ::boost::property_tree::ptree::value_type& v, vtkTransformConf.get())
187 SLM_ASSERT(
"Invalid markup '" + v.first +
"', 'concatenate' must be used here.", v.first ==
"concatenate");
189 const std::string& transformId = v.second.data();
191 vtkTransform* mat = vtkTransform::SafeDownCast( getVtkObject(transformId) );
193 SLM_ASSERT(
"No transform named '" + transformId +
"'.", mat !=
nullptr);
195 const std::string inverse = v.second.get<std::string>(
"<xmlattr>.inverse",
"no");
197 SLM_ASSERT(
"Inverse must be 'yes' or 'no'.", inverse ==
"yes" || inverse ==
"no");
201 newMat->Concatenate( mat->GetLinearInverse() );
205 newMat->Concatenate( mat );
215 void SRender::addVtkObject(
const VtkObjectIdType& _id, vtkObject* _vtkObj )
217 SLM_ASSERT(
"vtkObject id is empty", !_id.empty() );
220 if( m_vtkObjects.count(_id) == 0 )
222 m_vtkObjects[_id] = _vtkObj;
228 void SRender::configuring()
230 const ConfigType& srvConf = this->getConfigTree();
232 const size_t nbInouts = srvConf.count(
"inout");
234 SLM_ASSERT(
"This service accepts at most one inout.", nbInouts <= 1);
236 m_flip = (srvConf.get<std::string>(
"flip",
"false") ==
"true");
240 const std::string key = srvConf.get<std::string>(
"inout.<xmlattr>.key",
"");
241 m_offScreen = (key == s_OFFSCREEN_INOUT);
243 SLM_ASSERT(
"'" + key +
"' is not a valid key. Only '" + s_OFFSCREEN_INOUT +
"' is accepted.", m_offScreen);
247 SLM_WARN_IF(
"Flip tag is set to 'true' but no off screen render image is used.", m_flip);
251 m_sceneConf = srvConf.get_child(
"scene");
253 const std::string renderMode = m_sceneConf.get(
"<xmlattr>.renderMode",
"auto");
255 if (renderMode ==
"auto")
257 m_renderMode = RenderMode::AUTO;
259 else if (renderMode ==
"timer")
261 m_renderMode = RenderMode::TIMER;
263 else if (renderMode ==
"sync")
265 m_renderMode = RenderMode::SYNC;
267 else if (renderMode ==
"none")
269 m_renderMode = RenderMode::NONE;
273 SLM_WARN_IF(
"renderMode '" + renderMode +
" is unknown, setting renderMode to 'auto'.",
274 !renderMode.empty());
277 m_width = m_sceneConf.get<
unsigned int>(
"<xmlattr>.width", m_width);
278 m_height = m_sceneConf.get<
unsigned int>(
"<xmlattr>.height", m_height);
280 BOOST_FOREACH(const ::fwServices::IService::ConfigType::value_type& v, m_sceneConf.equal_range(
"adaptor"))
282 const std::string adaptorUid = v.second.get<std::string>(
"<xmlattr>.uid",
"");
284 SLM_FATAL_IF(
"Missing 'uid' attribute in adaptor configuration", adaptorUid ==
"");
287 auto&
registry = ::fwRenderVTK::registry::getAdaptorRegistry();
288 registry[adaptorUid] = this->getID();
292 const unsigned int targetFrameRate = srvConf.get<
unsigned int>(
"fps", 30);
294 if(m_renderMode == RenderMode::TIMER)
296 unsigned int timeStep =
static_cast<unsigned int>( 1000.f / targetFrameRate );
297 m_timer = m_associatedWorker->createTimer();
299 ::fwThread::Timer::TimeDurationType duration = std::chrono::milliseconds(timeStep);
300 m_timer->setFunction( std::bind( &SRender::requestRender,
this) );
301 m_timer->setDuration(duration);
307 void SRender::starting()
314 this->startContext();
317 BOOST_FOREACH(const ::fwServices::IService::ConfigType::value_type& v, m_sceneConf)
319 const std::string& subEltName = v.first;
320 if(subEltName ==
"renderer")
322 this->configureRenderer(v.second);
324 else if(subEltName ==
"picker")
326 this->configurePicker(v.second);
328 else if(subEltName ==
"vtkObject")
330 this->configureVtkObject(v.second);
332 else if(subEltName !=
"adaptor" && subEltName !=
"<xmlattr>")
334 SLM_FATAL(
"Unknown sub-element '" + subEltName +
"'.");
338 m_interactorManager->getInteractor()->GetRenderWindow()->SetNumberOfLayers(static_cast<int>(m_renderers.size()));
339 for( RenderersMapType::iterator iter = m_renderers.begin(); iter != m_renderers.end(); ++iter )
341 vtkRenderer* renderer = (*iter).second;
342 m_interactorManager->getInteractor()->GetRenderWindow()->AddRenderer(renderer);
353 void SRender::stopping()
370 void SRender::updating()
376 void SRender::render()
378 OSLM_ASSERT(
"Scene must be started", this->isStarted());
381 ::fwData::Image::sptr image = this->getInOut< ::fwData::Image >(s_OFFSCREEN_INOUT);
382 SLM_ASSERT(
"Offscreen image not found.", image);
384 vtkSmartPointer<vtkRenderWindow> renderWindow = m_interactorManager->getInteractor()->GetRenderWindow();
386 renderWindow->Render();
388 vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
389 windowToImageFilter->SetInputBufferTypeToRGBA();
390 windowToImageFilter->SetInput( renderWindow );
391 windowToImageFilter->Update();
397 vtkSmartPointer<vtkImageFlip> flipImage = vtkSmartPointer<vtkImageFlip>::New();
398 flipImage->SetFilteredAxes(1);
399 flipImage->SetInputData(windowToImageFilter->GetOutput());
402 ::fwVtkIO::fromVTKImage(flipImage->GetOutput(), image);
406 ::fwVtkIO::fromVTKImage(windowToImageFilter->GetOutput(), image);
418 m_interactorManager->getInteractor()->Render();
420 this->setPendingRenderRequest(
false);
425 bool SRender::isShownOnScreen()
429 return this->getContainer()->isShownOnScreen();
439 void SRender::requestRender()
441 if ( this->isShownOnScreen() && !this->getPendingRenderRequest())
443 this->setPendingRenderRequest(
true);
444 if(m_renderMode == RenderMode::SYNC)
446 OSLM_DEBUG(
"sync SRender: " << this->getID());
447 this->slot(SRender::s_RENDER_SLOT)->run();
451 this->slot(SRender::s_RENDER_SLOT)->asyncRun();
458 void SRender::toggleAutoRender()
460 if(m_renderMode == RenderMode::AUTO)
462 m_renderMode = RenderMode::NONE;
464 else if(m_renderMode == RenderMode::NONE)
466 m_renderMode = RenderMode::AUTO;
469 auto interactor = m_interactorManager->getInteractor()->GetInteractorStyle();
471 interactorStyle->
setAutoRender(m_renderMode == RenderMode::AUTO);
476 void SRender::startContext()
480 m_interactorManager = ::fwRenderVTK::IVtkRenderWindowInteractorManager::createManager();
481 m_interactorManager->installInteractor( this->getContainer() );
485 ::fwRenderVTK::OffScreenInteractorManager::sptr interactorManager =
486 ::fwRenderVTK::OffScreenInteractorManager::New();
487 interactorManager->installInteractor(m_width, m_height);
488 m_interactorManager = interactorManager;
491 auto interactor = vtkSmartPointer<InteractorStyle3DForNegato>::New();
492 SLM_ASSERT(
"Can't instantiate interactor", interactor);
493 interactor->setAutoRender(m_renderMode == RenderMode::AUTO);
494 m_interactorManager->getInteractor()->SetInteractorStyle( interactor );
496 m_interactorManager->setRenderService(this->getSptr());
499 m_interactorManager->getInteractor()->GetRenderWindow()->SetAlphaBitPlanes(1);
500 m_interactorManager->getInteractor()->GetRenderWindow()->SetMultiSamples(0);
507 void SRender::stopContext()
509 for( RenderersMapType::iterator iter = m_renderers.begin(); iter != m_renderers.end(); ++iter )
511 vtkRenderer* renderer = iter->second;
512 renderer->InteractiveOff();
513 m_interactorManager->getInteractor()->GetRenderWindow()->RemoveRenderer(renderer);
519 m_interactorManager->uninstallInteractor();
520 m_interactorManager.reset();
525 vtkRenderer* SRender::getRenderer(RendererIdType rendererId)
527 OSLM_ASSERT(
"Renderer not found : '" << rendererId <<
"'", m_renderers.count(rendererId) == 1);
529 return m_renderers[rendererId];
534 vtkAbstractPropPicker* SRender::getPicker(PickerIdType pickerId)
536 PickersMapType::const_iterator iter = m_pickers.find(pickerId);
537 if ( iter == m_pickers.end())
539 SLM_DEBUG(
"Picker '" + pickerId +
"' not found");
547 vtkObject* SRender::getVtkObject(
const VtkObjectIdType& objectId)
const 549 VtkObjectMapType::const_iterator iter = m_vtkObjects.find(objectId);
550 if ( iter == m_vtkObjects.end())
552 SLM_DEBUG(
"vtkObject '" + objectId +
"' not found");
560 vtkTransform* SRender::getOrAddVtkTransform(
const VtkObjectIdType& _id )
562 vtkTransform* t = vtkTransform::SafeDownCast(getVtkObject(_id));
565 t = vtkTransform::New();
566 this->addVtkObject(_id, t);
573 bool SRender::isOffScreen()
const 580 void SRender::setOffScreenRenderSize(
unsigned int _width,
unsigned int _height)
584 m_width = std::max(_width, 1u);
585 m_height = std::max(_height, 1u);
588 m_interactorManager->getInteractor()->GetRenderWindow()->MakeCurrent();
589 m_interactorManager->getInteractor()->GetRenderWindow()->SetSize(static_cast<int>(m_width),
590 static_cast<int>(m_height));
Contains fwAtomsFilter::registry details.
IInteractorStyle is an interface dedicated to hold some flags for class inherited from vtkInteractorS...
#define OSLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
Class allowing to block a Connection.
Namespace fwServices is dedicated to (mimic) the dynamic affectation of methods to (pure data) object...
A helper to lock object on exclusive mode.
#define SLM_DEBUG(message)
void setAutoRender(bool _autoRender)
Set the autorender flag.
#define SLM_FATAL(message)
#define SLM_ASSERT(message, cond)
work like 'assert' from 'cassert', with in addition a message logged by spylog (with FATAL loglevel) ...
#define SLM_FATAL_IF(message, cond)
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
The namespace fwRenderVTK contains classes for rendering with VTK.
#define SLM_WARN_IF(message, cond)
#define OSLM_DEBUG(message)