1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLODActor.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkLODActor.h"
16 
17 #include "vtkMapperCollection.h"
18 #include "vtkMaskPoints.h"
19 #include "vtkMatrix4x4.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkOutlineFilter.h"
22 #include "vtkPolyDataMapper.h"
23 #include "vtkProperty.h"
24 #include "vtkRenderWindow.h"
25 #include "vtkRenderer.h"
26 #include "vtkTexture.h"
27 #include "vtkTimerLog.h"
28 
29 #include <cmath>
30 
31 vtkStandardNewMacro(vtkLODActor);
32 vtkCxxSetObjectMacro(vtkLODActor, LowResFilter, vtkPolyDataAlgorithm);
33 vtkCxxSetObjectMacro(vtkLODActor, MediumResFilter, vtkPolyDataAlgorithm);
34 
35 //----------------------------------------------------------------------------
vtkLODActor()36 vtkLODActor::vtkLODActor()
37 {
38   // get a hardware dependent actor and mappers
39   this->Device = vtkActor::New();
40   vtkMatrix4x4 *m = vtkMatrix4x4::New();
41   this->Device->SetUserMatrix(m);
42   m->Delete();
43 
44   this->LODMappers = vtkMapperCollection::New();
45   this->MediumResFilter = nullptr;
46   this->LowResFilter = nullptr;
47   this->NumberOfCloudPoints = 150;
48   this->LowMapper = nullptr;
49   this->MediumMapper = nullptr;
50 }
51 
52 //----------------------------------------------------------------------------
~vtkLODActor()53 vtkLODActor::~vtkLODActor()
54 {
55   this->Device->Delete();
56   this->Device = nullptr;
57   this->DeleteOwnLODs();
58   this->LODMappers->Delete();
59 }
60 
61 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)62 void vtkLODActor::PrintSelf(ostream& os, vtkIndent indent)
63 {
64   this->Superclass::PrintSelf(os, indent);
65 
66   os << indent << "Cloud Points: " << this->NumberOfCloudPoints << endl;
67 
68   // how should we print out the LODMappers?
69   os << indent << "Number Of LOD Mappers: "
70      << this->LODMappers->GetNumberOfItems() << endl;
71   os << indent << "Medium Resolution Filter: " << this->MediumResFilter << "\n";
72   if (this->MediumResFilter)
73   {
74     this->MediumResFilter->PrintSelf(os,indent.GetNextIndent());
75   }
76   os << indent << "Low Resolution Filter: " << this->LowResFilter << "\n";
77   if (this->LowResFilter)
78   {
79     this->LowResFilter->PrintSelf(os,indent.GetNextIndent());
80   }
81 }
82 
83 //----------------------------------------------------------------------------
Render(vtkRenderer * ren,vtkMapper * vtkNotUsed (m))84 void vtkLODActor::Render(vtkRenderer *ren, vtkMapper *vtkNotUsed(m))
85 {
86   float myTime, bestTime, tempTime;
87   vtkMatrix4x4 *matrix;
88   vtkMapper *mapper, *bestMapper;
89 
90   if (!this->Mapper)
91   {
92     vtkErrorMacro("No mapper for actor.");
93     return;
94   }
95 
96   // first time through create lods if non have been added
97   if (this->LODMappers->GetNumberOfItems() == 0)
98   {
99     this->CreateOwnLODs();
100   }
101 
102   // If the actor has changed or the primary mapper has changed ...
103   // Is this the correct test?
104   if (this->MediumMapper)
105   {
106     if (this->GetMTime() > this->BuildTime ||
107         this->Mapper->GetMTime() > this->BuildTime)
108     {
109       this->UpdateOwnLODs();
110     }
111   }
112 
113   // figure out how much time we have to render
114   myTime = this->AllocatedRenderTime;
115 
116   // Figure out which resolution to use
117   // none is a valid resolution. Do we want to have a lowest:
118   // bbox, single point, ...
119   // There is no order to the list, so it is assumed that mappers that take
120   // longer to render are better quality.
121   // Timings might become out of date, but we rely on
122 
123   bestMapper = this->Mapper;
124   bestTime = bestMapper->GetTimeToDraw();
125   if (bestTime > myTime)
126   {
127     vtkCollectionSimpleIterator mit;
128     this->LODMappers->InitTraversal(mit);
129     while ((mapper = this->LODMappers->GetNextMapper(mit)) != nullptr &&
130            bestTime != 0.0)
131     {
132       tempTime = mapper->GetTimeToDraw();
133 
134       // If the LOD has never been rendered, select it!
135       if (tempTime == 0.0)
136       {
137         bestMapper = mapper;
138         bestTime = 0.0;
139       }
140       else
141       {
142         if (bestTime > myTime && tempTime < bestTime)
143         {
144           bestMapper = mapper;
145           bestTime = tempTime;
146         }
147         if (tempTime > bestTime && tempTime < myTime)
148         {
149           bestMapper = mapper;
150           bestTime = tempTime;
151         }
152       }
153     }
154   }
155 
156   // render the property
157   if (!this->Property)
158   {
159     // force creation of a property
160     this->GetProperty();
161   }
162   this->Property->Render(this, ren);
163   if (this->BackfaceProperty)
164   {
165     this->BackfaceProperty->BackfaceRender(this, ren);
166     this->Device->SetBackfaceProperty(this->BackfaceProperty);
167   }
168   this->Device->SetProperty(this->Property);
169 
170   // render the texture
171   if (this->Texture)
172   {
173     this->Texture->Render(ren);
174   }
175 
176   // make sure the device has the same matrix
177   matrix = this->Device->GetUserMatrix();
178   this->GetMatrix(matrix);
179 
180   // Store information on time it takes to render.
181   // We might want to estimate time from the number of polygons in mapper.
182 
183   // The internal actor needs to share property keys. This allows depth peeling
184   // etc to work.
185   this->Device->SetPropertyKeys(this->GetPropertyKeys());
186 
187   this->Device->Render(ren, bestMapper);
188   this->EstimatedRenderTime = bestMapper->GetTimeToDraw();
189 }
190 
RenderOpaqueGeometry(vtkViewport * vp)191 int vtkLODActor::RenderOpaqueGeometry(vtkViewport *vp)
192 {
193   int renderedSomething = 0;
194   vtkRenderer* ren = static_cast<vtkRenderer*>(vp);
195 
196   if (!this->Mapper)
197   {
198     return 0;
199   }
200 
201   // make sure we have a property
202   if (!this->Property)
203   {
204     // force creation of a property
205     this->GetProperty();
206   }
207 
208   // is this actor opaque ?
209   // Do this check only when not in selection mode
210   if (this->GetIsOpaque() ||
211     (ren->GetSelector() && this->Property->GetOpacity() > 0.0))
212   {
213     this->Property->Render(this, ren);
214 
215     // render the backface property
216     if (this->BackfaceProperty)
217     {
218       this->BackfaceProperty->BackfaceRender(this, ren);
219     }
220 
221     // render the texture
222     if (this->Texture)
223     {
224       this->Texture->Render(ren);
225     }
226     this->Render(ren, this->Mapper);
227 
228     renderedSomething = 1;
229   }
230 
231   return renderedSomething;
232 }
233 
ReleaseGraphicsResources(vtkWindow * renWin)234 void vtkLODActor::ReleaseGraphicsResources(vtkWindow *renWin)
235 {
236   vtkMapper *mapper;
237   vtkActor::ReleaseGraphicsResources(renWin);
238 
239   // broadcast the message down to the individual LOD mappers
240   vtkCollectionSimpleIterator mit;
241   for (this->LODMappers->InitTraversal(mit);
242     (mapper = this->LODMappers->GetNextMapper(mit));)
243   {
244     mapper->ReleaseGraphicsResources(renWin);
245   }
246 }
247 
248 //----------------------------------------------------------------------------
249 // does not matter if mapper is in mapper collection.
AddLODMapper(vtkMapper * mapper)250 void vtkLODActor::AddLODMapper(vtkMapper *mapper)
251 {
252   if (this->MediumMapper)
253   {
254     this->DeleteOwnLODs();
255   }
256 
257   if (!this->Mapper)
258   {
259     this->SetMapper(mapper);
260   }
261 
262   this->LODMappers->AddItem(mapper);
263 }
264 
265 //----------------------------------------------------------------------------
266 // Can only be used if no LOD mappers have been added.
267 // Maybe we should remove this exculsive feature.
CreateOwnLODs()268 void vtkLODActor::CreateOwnLODs()
269 {
270   if (this->MediumMapper)
271   {
272     return;
273   }
274 
275   if (!this->Mapper)
276   {
277     vtkErrorMacro("Cannot create LODs with out a mapper.");
278     return;
279   }
280 
281   // There are ways of getting around this limitation...
282   if (this->LODMappers->GetNumberOfItems() > 0)
283   {
284     vtkErrorMacro(<<
285           "Cannot generate LOD mappers when some have been added already");
286     return;
287   }
288 
289   // create filters and mappers
290   if (!this->MediumResFilter)
291   {
292     vtkMaskPoints *mediumResFilter = vtkMaskPoints::New();
293     mediumResFilter->RandomModeOn();
294     mediumResFilter->GenerateVerticesOn();
295     this->SetMediumResFilter(mediumResFilter);
296     mediumResFilter->Delete();
297   }
298 
299   this->MediumMapper = vtkPolyDataMapper::New();
300 
301   if (!this->LowResFilter)
302   {
303     vtkOutlineFilter *lowResFilter = vtkOutlineFilter::New();
304     this->SetLowResFilter(lowResFilter);
305     lowResFilter->Delete();
306   }
307 
308   this->LowMapper = vtkPolyDataMapper::New();
309   this->LODMappers->AddItem(this->MediumMapper);
310   this->LODMappers->AddItem(this->LowMapper);
311 
312   this->UpdateOwnLODs();
313 }
314 
315 //----------------------------------------------------------------------------
UpdateOwnLODs()316 void vtkLODActor::UpdateOwnLODs()
317 {
318   if (!this->Mapper)
319   {
320     vtkErrorMacro("Cannot create LODs with out a mapper.");
321     return;
322   }
323 
324   if (!this->MediumMapper)
325   {
326     this->CreateOwnLODs();
327     if (!this->MediumMapper)
328     { // could not create the LODs
329       return;
330     }
331   }
332 
333   // connect the filters to the mapper, and set parameters
334   this->MediumResFilter->SetInputConnection(
335     this->Mapper->GetInputConnection(0, 0));
336   this->LowResFilter->SetInputConnection(
337     this->Mapper->GetInputConnection(0, 0));
338 
339   // If the medium res filter is a vtkMaskPoints, then set the ivar in here.
340   // In reality, we should deprecate the vtkLODActor::SetNumberOfCloudPoints
341   // method, since now you can get the filters that make up the low and
342   // medium res and set them yourself.
343   if (vtkMaskPoints *f = vtkMaskPoints::SafeDownCast(this->MediumResFilter))
344   {
345     f->SetMaximumNumberOfPoints(this->NumberOfCloudPoints);
346   }
347 
348   // copy all parameters including LUTs, scalar range, etc.
349   this->MediumMapper->ShallowCopy(this->Mapper);
350   this->MediumMapper->SetInputConnection(
351     this->MediumResFilter->GetOutputPort());
352   this->LowMapper->ShallowCopy(this->Mapper);
353   this->LowMapper->ScalarVisibilityOff();
354   this->LowMapper->SetInputConnection(
355     this->LowResFilter->GetOutputPort());
356 
357   this->BuildTime.Modified();
358 }
359 
360 //----------------------------------------------------------------------------
361 // Deletes Mappers and filters created by this object.
362 // (number two and three)
DeleteOwnLODs()363 void vtkLODActor::DeleteOwnLODs()
364 {
365   // remove the mappers from the LOD collection
366   if (this->LowMapper)
367   {
368     this->LODMappers->RemoveItem(this->LowMapper);
369     this->LowMapper->Delete();
370     this->LowMapper = nullptr;
371   }
372 
373   if (this->MediumMapper)
374   {
375     this->LODMappers->RemoveItem(this->MediumMapper);
376     this->MediumMapper->Delete();
377     this->MediumMapper = nullptr;
378   }
379 
380   // delete the filters used to create the LODs ...
381   // The nullptr check should not be necessary, but for sanity ...
382   this->SetLowResFilter(nullptr);
383   this->SetMediumResFilter(nullptr);
384 }
385 
386 //----------------------------------------------------------------------------
Modified()387 void vtkLODActor::Modified()
388 {
389   if (this->Device) // Will be nullptr only during destruction of this class.
390   {
391     this->Device->Modified();
392   }
393   this->vtkActor::Modified();
394 }
395 
ShallowCopy(vtkProp * prop)396 void vtkLODActor::ShallowCopy(vtkProp *prop)
397 {
398   vtkLODActor *a = vtkLODActor::SafeDownCast(prop);
399   if (a)
400   {
401     this->SetNumberOfCloudPoints(a->GetNumberOfCloudPoints());
402     vtkMapperCollection *c = a->GetLODMappers();
403     vtkMapper *map;
404     vtkCollectionSimpleIterator mit;
405     for (c->InitTraversal(mit); (map = c->GetNextMapper(mit));)
406     {
407       this->AddLODMapper(map);
408     }
409   }
410 
411   // Now do superclass
412   this->vtkActor::ShallowCopy(prop);
413 }
414