Commit ef2cf1ae authored by Utkarsh Ayachit's avatar Utkarsh Ayachit

Refactoring surface-selection mechanism.

* Surface selection now works in local-rendering mode (as well as remote
  rendering mode). It expects the vtkPVGeometryFilter to generate process ids
  (vtkProcessId) array in parallel. When present, it is used to determine the
  process id.
* Selection rendering passes now render the "original ids" rather than the
  point/cell ids. Thus representations no longer need to "convert" selection.
  They just need to ensure that they render the correct ids in the selection
  rendering passes.

This makes it possible to determine the "selection" directly on the client.
Thus, we no longer need to gather the selection from the server side.
parent bfca6104
......@@ -43,6 +43,7 @@
#include "vtkShadowMapBakerPass.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkUnstructuredGrid.h"
#include "vtkHardwareSelectionPolyDataPainter.h"
#include <vtksys/SystemTools.hxx>
......@@ -98,7 +99,18 @@ vtkGeometryRepresentation::vtkGeometryRepresentation()
this->CacheKeeper = vtkPVCacheKeeper::New();
this->MultiBlockMaker = vtkGeometryRepresentationMultiBlockMaker::New();
this->Decimator = vtkQuadricClustering::New();
this->Mapper = vtkCompositePolyDataMapper2::New();
// setup the selection mapper so that we don't need to make any selection
// conversions after rendering.
vtkCompositePolyDataMapper2* mapper = vtkCompositePolyDataMapper2::New();
vtkHardwareSelectionPolyDataPainter* selPainter =
vtkHardwareSelectionPolyDataPainter::SafeDownCast(
mapper->GetSelectionPainter()->GetDelegatePainter());
selPainter->SetPointIdArrayName("vtkOriginalPointIds");
selPainter->SetCellIdArrayName("vtkOriginalCellIds");
selPainter->SetProcessIdArrayName("vtkProcessId");
this->Mapper = mapper;
this->LODMapper = vtkCompositePolyDataMapper2::New();
this->Actor = vtkPVLODActor::New();
this->Property = vtkProperty::New();
......@@ -425,6 +437,10 @@ bool vtkGeometryRepresentation::AddToView(vtkView* view)
if (rview)
{
rview->GetRenderer()->AddActor(this->Actor);
// Indicate that this is prop that we are rendering when hardware selection
// is enabled.
rview->RegisterPropForHardwareSelection(this, this->GetRenderedProp());
return true;
}
return false;
......@@ -437,6 +453,7 @@ bool vtkGeometryRepresentation::RemoveFromView(vtkView* view)
if (rview)
{
rview->GetRenderer()->RemoveActor(this->Actor);
rview->UnRegisterPropForHardwareSelection(this, this->GetRenderedProp());
return true;
}
return false;
......@@ -553,52 +570,6 @@ void vtkGeometryRepresentation::UpdateColoringParameters()
}
//----------------------------------------------------------------------------
vtkSelection* vtkGeometryRepresentation::ConvertSelection(
vtkView* _view, vtkSelection* selection)
{
vtkPVRenderView* view = vtkPVRenderView::SafeDownCast(_view);
// if this->GeometryFilter has 0 inputs, it means we don't have any valid
// input data on this process, so we can't convert the selection.
if (!view ||
this->GeometryFilter->GetNumberOfInputConnections(0) == 0)
{
return this->Superclass::ConvertSelection(_view, selection);
}
vtkSelection* newInput = vtkSelection::New();
// locate any selection nodes which belong to this representation.
for (unsigned int cc=0; cc < selection->GetNumberOfNodes(); cc++)
{
vtkSelectionNode* node = selection->GetNode(cc);
vtkProp* prop = NULL;
if (node->GetProperties()->Has(vtkSelectionNode::PROP()))
{
prop = vtkProp::SafeDownCast(node->GetProperties()->Get(vtkSelectionNode::PROP()));
}
if (prop == this->GetRenderedProp())
{
newInput->AddNode(node);
node->GetProperties()->Set(vtkSelectionNode::SOURCE(),
this->GeometryFilter);
}
}
if (newInput->GetNumberOfNodes() == 0)
{
newInput->Delete();
return selection;
}
vtkSelection* output = vtkSelection::New();
vtkSelectionConverter* convertor = vtkSelectionConverter::New();
convertor->Convert(newInput, output, 0);
convertor->Delete();
newInput->Delete();
return output;
}
void vtkGeometryRepresentation::SetAllowSpecularHighlightingWithScalarColoring(int allow)
{
this->AllowSpecularHighlightingWithScalarColoring = allow > 0 ? true : false;
......
......@@ -168,15 +168,6 @@ public:
virtual void SetMapScalars(int val);
virtual void SetStatic(int val);
// Description:
// Convert the selection to a type appropriate for sharing with other
// representations through vtkAnnotationLink, possibly using the view.
// For the superclass, we just return the same selection.
// Subclasses may do something more fancy, like convert the selection
// from a frustrum to a list of pedigree ids. If the selection cannot
// be applied to this representation, return NULL.
virtual vtkSelection* ConvertSelection(vtkView* view, vtkSelection* selection);
virtual void SetAllowSpecularHighlightingWithScalarColoring(int allow);
//BTX
......
......@@ -349,6 +349,28 @@ void vtkPVDataDeliveryManager::UnRegisterRepresentation(
this->Internals->RepresentationToIdMap.erase(iter);
}
//----------------------------------------------------------------------------
unsigned int vtkPVDataDeliveryManager::GetRepresentationId(
vtkPVDataRepresentation* repr)
{
vtkInternals::RepresentationToIdMapType::iterator iter =
this->Internals->RepresentationToIdMap.find(repr);
if (iter == this->Internals->RepresentationToIdMap.end())
{
vtkErrorMacro("Invalid argument.");
return 0;
}
return iter->second;
}
//----------------------------------------------------------------------------
vtkPVDataRepresentation* vtkPVDataDeliveryManager::GetRepresentation(
unsigned int index)
{
vtkInternals::vtkItem* item = this->Internals->GetItem(index, false);
return item? item->Representation : NULL;
}
//----------------------------------------------------------------------------
void vtkPVDataDeliveryManager::SetDeliverToAllProcesses(
vtkPVDataRepresentation* repr, bool mode, bool low_res)
......
......@@ -52,6 +52,8 @@ public:
// to communicate information about representations using their unique ids.
void RegisterRepresentation(unsigned int id, vtkPVDataRepresentation*);
void UnRegisterRepresentation(vtkPVDataRepresentation*);
unsigned int GetRepresentationId(vtkPVDataRepresentation*);
vtkPVDataRepresentation* GetRepresentation(unsigned int);
// Description:
// Representations (indirectly via vtkPVRenderView::SetPiece()) call this
......
......@@ -75,12 +75,32 @@
class vtkPVRenderView::vtkInternals
{
std::map<int, vtkWeakPointer<vtkPVDataRepresentation> > PropMap;
public:
unsigned int UniqueId;
vtkNew<vtkPVDataDeliveryManager> DeliveryManager;
vtkInternals() : UniqueId(1)
{
}
void RegisterSelectionProp(
int id, vtkProp*, vtkPVDataRepresentation* rep)
{
this->PropMap[id] = rep;
}
void UnRegisterSelectionProp(vtkProp* prop, vtkPVDataRepresentation* rep)
{
(void)prop;
(void)rep;
}
vtkPVDataRepresentation* GetRepresentationForPropId(int id)
{
std::map<int, vtkWeakPointer<vtkPVDataRepresentation> >::iterator iter =
this->PropMap.find(id);
return (iter != this->PropMap.end()? iter->second : NULL);
}
};
......@@ -364,6 +384,21 @@ void vtkPVRenderView::RemoveRepresentationInternal(vtkDataRepresentation* rep)
this->Superclass::RemoveRepresentationInternal(rep);
}
//----------------------------------------------------------------------------
void vtkPVRenderView::RegisterPropForHardwareSelection(
vtkPVDataRepresentation* repr, vtkProp* prop)
{
int id = this->Selector->AssignUniqueId(prop);
this->Internals->RegisterSelectionProp(id, prop, repr);
}
//----------------------------------------------------------------------------
void vtkPVRenderView::UnRegisterPropForHardwareSelection(
vtkPVDataRepresentation* repr, vtkProp* prop)
{
this->Internals->UnRegisterSelectionProp(prop, repr);
}
//----------------------------------------------------------------------------
vtkRenderer* vtkPVRenderView::GetRenderer()
{
......@@ -477,12 +512,6 @@ void vtkPVRenderView::Select(int fieldAssociation, int region[4])
return;
}
if (!this->GetRemoteRenderingAvailable())
{
vtkErrorMacro("Cannot make selections since remote rendering is not available.");
return;
}
this->MakingSelection = true;
// Make sure that the representations are up-to-date. This is required since
......@@ -495,33 +524,26 @@ void vtkPVRenderView::Select(int fieldAssociation, int region[4])
this->Selector->SetRenderer(this->GetRenderer());
this->Selector->SetFieldAssociation(fieldAssociation);
// for now, we always do the process pass. In future, we can be smart about
// disabling process pass when not needed.
this->Selector->SetProcessID(
vtkMultiProcessController::GetGlobalController()?
vtkMultiProcessController::GetGlobalController()->GetLocalProcessId() : 0);
vtkSelection* sel = this->Selector->Select(region);
vtkSmartPointer<vtkSelection> sel;
if (this->SynchronizedWindows->GetEnabled() ||
this->SynchronizedWindows->GetLocalProcessIsDriver())
{
sel.TakeReference(this->Selector->Select(region));
if (this->SynchronizedWindows->GetLocalProcessIsDriver())
{
// valid selection is only generated on the driver process. Other's are
// merely rendering the passes so that the result is composited correctly.
this->FinishSelection(sel);
}
}
// look at ::Render(..,..). We need to disable these once we are done with
// rendering.
this->SynchronizedWindows->SetEnabled(false);
this->SynchronizedRenderers->SetEnabled(false);
if (sel)
{
// A valid sel is only generated on the "driver" node. The driver node may not have
// the actual data (except in built-in mode). So representations on this
// process may not be able to handle ConvertSelection() if call it right here.
// Hence we broadcast the selection to all data-server nodes.
this->FinishSelection(sel);
sel->Delete();
}
else
{
vtkErrorMacro("Failed to capture selection.");
}
this->MakingSelection = false;
}
......@@ -529,54 +551,26 @@ void vtkPVRenderView::Select(int fieldAssociation, int region[4])
void vtkPVRenderView::FinishSelection(vtkSelection* sel)
{
assert(sel != NULL);
this->SynchronizedWindows->BroadcastToDataServer(sel);
// now, sel has PROP_ID() set and not PROP() pointers. We setup the PROP()
// pointers, since representations have know knowledge for that the PROP_ID()s
// are.
// first, convert local-prop ids to ids that the data-server can understand if
// the selection was done without compositing, i.e. rendering happened on the
// client side.
for (unsigned int cc=0; cc < sel->GetNumberOfNodes(); cc++)
{
vtkSelectionNode* node = sel->GetNode(cc);
if (node->GetProperties()->Has(vtkSelectionNode::PROP_ID()))
{
int propid = node->GetProperties()->Get(vtkSelectionNode::PROP_ID());
vtkProp* prop = this->Selector->GetPropFromID(propid);
node->GetProperties()->Set(vtkSelectionNode::PROP(), prop);
vtkPVDataRepresentation* repr =
this->Internals->GetRepresentationForPropId(propid);
if (repr)
{
node->GetProperties()->Set(vtkSelectionNode::SOURCE(), repr);
}
}
}
// Now all processes have the full selection. We can tell the representations
// to convert the selections.
vtkSelection* converted = vtkSelection::New();
// Now, vtkPVRenderView is in no position to tell how many representations got
// selected, and what nodes in the vtkSelection correspond to which
// representations. So it simply passes the full vtkSelection to all
// representations and asks them to "convert" it. A representation will return
// the original selection if it was not selected at all or returns the
// converted selection for the part that it can handle, ignoring the rest.
for (int i = 0; i < this->GetNumberOfRepresentations(); ++i)
{
vtkDataRepresentation* repr = this->GetRepresentation(i);
vtkSelection* convertedSelection = repr->ConvertSelection(this, sel);
if (convertedSelection == NULL|| convertedSelection == sel)
{
continue;
}
for (unsigned int cc=0; cc < convertedSelection->GetNumberOfNodes(); cc++)
{
vtkSelectionNode* node = convertedSelection->GetNode(cc);
// update the SOURCE() for the node to be the selected representation.
node->GetProperties()->Set(vtkSelectionNode::SOURCE_ID(), i);
converted->AddNode(convertedSelection->GetNode(cc));
}
convertedSelection->Delete();
}
this->SetLastSelection(converted);
converted->FastDelete();
this->SetLastSelection(sel);
}
//----------------------------------------------------------------------------
......@@ -1242,12 +1236,6 @@ bool vtkPVRenderView::ShouldUseDistributedRendering(double geometry_size)
return false;
}
if (this->MakingSelection)
{
// force remote rendering when doing a surface selection.
return true;
}
if (vtkProcessModule::GetProcessType() == vtkProcessModule::PROCESS_BATCH)
{
// currently, we only support parallel rendering in batch mode.
......@@ -1321,30 +1309,6 @@ bool vtkPVRenderView::GetLightSwitch()
return this->Light->GetSwitch() != 0;
}
//----------------------------------------------------------------------------
void vtkPVRenderView::AddPropToNonCompositedRenderer(vtkProp* prop)
{
this->GetNonCompositedRenderer()->AddActor(prop);
}
//----------------------------------------------------------------------------
void vtkPVRenderView::RemovePropFromNonCompositedRenderer(vtkProp* prop)
{
this->GetNonCompositedRenderer()->RemoveActor(prop);
}
//----------------------------------------------------------------------------
void vtkPVRenderView::AddPropToRenderer(vtkProp* prop)
{
this->GetRenderer()->AddActor(prop);
}
//----------------------------------------------------------------------------
void vtkPVRenderView::RemovePropFromRenderer(vtkProp* prop)
{
this->GetRenderer()->RemoveActor(prop);
}
//----------------------------------------------------------------------------
void vtkPVRenderView::UpdateCenterAxes()
{
......
......@@ -108,28 +108,6 @@ public:
// Returns the render window.
vtkRenderWindow* GetRenderWindow();
// Description:
// It's possible to directly add vtkProps to a view. This API provides access
// to add props to the 3D/composited renderer. Note that if you add props in
// this way, they will not be included in the computations for geometry-size
// which is used to make decisions whether to use LOD or remote rendering etc.
// Nor can such props participate in data-redistribution when volume rendering
// or translucent rendering. As a rule of thumb only add props not directly
// connected to input data using this API such as scalar bars, cube axes etc.
void AddPropToRenderer(vtkProp*);
void RemovePropFromRenderer(vtkProp*);
// Description:
// It's possible to directly add vtkProps to a view. This API provides access
// to add props to the non-composited renderer. Note that if you add props in
// this way, they will not be included in the computations for geometry-size
// which is used to make decisions whether to use LOD or remote rendering etc.
// Nor can such props participate in data-redistribution when volume rendering
// or translucent rendering. As a rule of thumb only add props not directly
// connected to input data using this API such as scalar bars, cube axes etc.
void AddPropToNonCompositedRenderer(vtkProp*);
void RemovePropFromNonCompositedRenderer(vtkProp*);
// Description:
// Returns the interactor. .
vtkGetObjectMacro(Interactor, vtkPVGenericRenderWindowInteractor);
......@@ -332,6 +310,15 @@ public:
static void SetStreamable(
vtkInformation* info, vtkPVDataRepresentation* repr, bool streamable);
// Description:
// Representations that support hardware (render-buffer based) selection,
// should register the prop that they use for selection rendering. They can do
// that in the vtkPVDataRepresentation::AddToView() implementation.
void RegisterPropForHardwareSelection(
vtkPVDataRepresentation* repr, vtkProp* prop);
void UnRegisterPropForHardwareSelection(
vtkPVDataRepresentation* repr, vtkProp* prop);
// Description:
// Turn on/off the default light in the 3D renderer.
void SetLightSwitch(bool enable);
......
......@@ -715,37 +715,37 @@ namespace
//-----------------------------------------------------------------------------
static void vtkShrinkSelection(vtkSelection* sel)
{
std::map<int, int> pixelCounts;
std::map<void*, int> pixelCounts;
unsigned int numNodes = sel->GetNumberOfNodes();
int choosen = -1;
void* choosen = NULL;
int maxPixels = -1;
for (unsigned int cc=0; cc < numNodes; cc++)
{
vtkSelectionNode* node = sel->GetNode(cc);
vtkInformation* properties = node->GetProperties();
if (properties->Has(vtkSelectionNode::PIXEL_COUNT()) &&
properties->Has(vtkSelectionNode::SOURCE_ID()))
properties->Has(vtkSelectionNode::SOURCE()))
{
int numPixels = properties->Get(vtkSelectionNode::PIXEL_COUNT());
int source_id = properties->Get(vtkSelectionNode::SOURCE_ID());
pixelCounts[source_id] += numPixels;
if (pixelCounts[source_id] > maxPixels)
void* source = properties->Get(vtkSelectionNode::SOURCE());
pixelCounts[source] += numPixels;
if (pixelCounts[source] > maxPixels)
{
maxPixels = numPixels;
choosen = source_id;
choosen = source;
}
}
}
std::vector<vtkSmartPointer<vtkSelectionNode> > choosenNodes;
if (choosen != -1)
if (choosen != NULL)
{
for (unsigned int cc=0; cc < numNodes; cc++)
{
vtkSelectionNode* node = sel->GetNode(cc);
vtkInformation* properties = node->GetProperties();
if (properties->Has(vtkSelectionNode::SOURCE_ID()) &&
properties->Get(vtkSelectionNode::SOURCE_ID()) == choosen)
if (properties->Has(vtkSelectionNode::SOURCE()) &&
properties->Get(vtkSelectionNode::SOURCE()) == choosen)
{
choosenNodes.push_back(node);
}
......@@ -766,13 +766,9 @@ bool vtkSMRenderViewProxy::FetchLastSelection(
{
if (selectionSources && selectedRepresentations)
{
vtkSmartPointer<vtkPVLastSelectionInformation> info =
vtkSmartPointer<vtkPVLastSelectionInformation>::New();
this->GetSession()->GatherInformation(
vtkPVSession::DATA_SERVER, info, this->GetGlobalID());
vtkSelection* selection = info->GetSelection();
vtkPVRenderView* rv = vtkPVRenderView::SafeDownCast(
this->GetClientSideObject());
vtkSelection* selection = rv->GetLastSelection();
if (!multiple_selections)
{
// only pass through selection over a single representation.
......
......@@ -597,22 +597,22 @@ bool vtkSMSelectionHelper::MergeSelection(
namespace
{
// Splits \c selection into a collection of selections based on the
// SOURCE_ID().
// SOURCE().
void vtkSplitSelection(vtkSelection* selection,
std::map<int, vtkSmartPointer<vtkSelection> >& map_of_selections)
std::map<vtkPVDataRepresentation*, vtkSmartPointer<vtkSelection> >& map_of_selections)
{
for (unsigned int cc=0; cc < selection->GetNumberOfNodes(); cc++)
{
vtkSelectionNode* node = selection->GetNode(cc);
if (node && node->GetProperties()->Has(vtkSelectionNode::SOURCE_ID()))
if (node && node->GetProperties()->Has(vtkSelectionNode::SOURCE()))
{
int source_id =
node->GetProperties()->Get(vtkSelectionNode::SOURCE_ID());
vtkSelection* sel = map_of_selections[source_id];
vtkPVDataRepresentation* repr = vtkPVDataRepresentation::SafeDownCast(
node->GetProperties()->Get(vtkSelectionNode::SOURCE()));
vtkSelection* sel = map_of_selections[repr];
if (!sel)
{
sel = vtkSelection::New();
map_of_selections[source_id] = sel;
map_of_selections[repr] = sel;
sel->FastDelete();
}
sel->AddNode(node);
......@@ -620,7 +620,8 @@ namespace
}
}
vtkSMProxy* vtkLocateRepresentation(vtkSMProxy* viewProxy, int id)
vtkSMProxy* vtkLocateRepresentation(vtkSMProxy* viewProxy,
vtkPVDataRepresentation* repr)
{
vtkView* view = vtkView::SafeDownCast(viewProxy->GetClientSideObject());
if (!view)
......@@ -629,7 +630,6 @@ namespace
return NULL;
}
vtkDataRepresentation* repr = view->GetRepresentation(id);
// now locate the proxy for this repr.
vtkSMPropertyHelper helper(viewProxy, "Representations");
for (unsigned int cc=0; cc < helper.GetNumberOfElements(); cc++)
......@@ -661,13 +661,13 @@ void vtkSMSelectionHelper::NewSelectionSourcesFromSelection(
// representation that was selected. We now need to create selection source
// proxies for each representation that was selected separately.
// This relies on SOURCE_ID() defined on the selection nodes to locate the
// This relies on SOURCE() defined on the selection nodes to locate the
// representation proxy for the representation that was selected.
std::map<int, vtkSmartPointer<vtkSelection> > selections;
std::map<vtkPVDataRepresentation*, vtkSmartPointer<vtkSelection> > selections;
vtkSplitSelection(selection, selections);
std::map<int, vtkSmartPointer<vtkSelection> >::iterator iter;
std::map<vtkPVDataRepresentation*, vtkSmartPointer<vtkSelection> >::iterator iter;
for (iter = selections.begin(); iter != selections.end(); ++iter)
{
vtkSMProxy* reprProxy = vtkLocateRepresentation(view, iter->first);
......
......@@ -14,19 +14,40 @@
=========================================================================*/
#include "vtkPVHardwareSelector.h"
#include "vtkCamera.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
#include <map>
class vtkPVHardwareSelector::vtkInternals
{
public:
typedef std::map<void*, int> PropMapType;
PropMapType PropMap;
};
vtkStandardNewMacro(vtkPVHardwareSelector);
//----------------------------------------------------------------------------
vtkPVHardwareSelector::vtkPVHardwareSelector()
{
this->SetUseProcessIdFromData(true);
this->ProcessID = 0;
this->UniqueId = 0;
this->Internals = new vtkInternals();
}
//----------------------------------------------------------------------------
vtkPVHardwareSelector::~vtkPVHardwareSelector()
{
delete this->Internals;
this->Internals = 0;
}
//----------------------------------------------------------------------------
bool vtkPVHardwareSelector::PassRequired(int pass)
{
return (pass == PROCESS_PASS? true : this->Superclass::PassRequired(pass));
}
//----------------------------------------------------------------------------
......@@ -58,6 +79,23 @@ bool vtkPVHardwareSelector::NeedToRenderForSelection()
return this->CaptureTime < this->GetMTime();
}
//----------------------------------------------------------------------------
int vtkPVHardwareSelector::AssignUniqueId(vtkProp* prop)
{
int id = this->UniqueId;
this->UniqueId++;
this->Internals->PropMap[prop] = id;
return id;
}
//----------------------------------------------------------------------------
int vtkPVHardwareSelector::GetPropID(int vtkNotUsed(idx), vtkProp* prop)
{
vtkInternals::PropMapType::iterator iter = this->Internals->PropMap.find(prop);
return (iter != this->Internals->PropMap.end() ?
iter->second : -1);
}
//----------------------------------------------------------------------------
void vtkPVHardwareSelector::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -47,15 +47,34 @@ public:
// Called to invalidate the cache.
void InvalidateCachedSelection()
{ this->Modified(); }
int AssignUniqueId(vtkProp*);
//BTX
protected:
vtkPVHardwareSelector();
~vtkPVHardwareSelector();
// Description:
// Return a unique ID for the prop.
virtual int GetPropID(int idx, vtkProp* prop);
// Description:
// Returns is the pass indicated is needed.
// Overridden to report that we always need the process-id pass. In future, we
// can be smart about it by only requiring it for sessions with more than 1
// data-server.
virtual bool PassRequired(int pass);
vtkTimeStamp CaptureTime;
int UniqueId;
private:
vtkPVHardwareSelector(const vtkPVHardwareSelector&); // Not implemented
void operator=(const vtkPVHardwareSelector&); // Not implemented
class vtkInternals;
vtkInternals* Internals;
//ETX
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment