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