1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLODProp3D.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 "vtkLODProp3D.h"
16 
17 #include "vtkActor.h"
18 #include "vtkCommand.h"
19 #include "vtkMapper.h"
20 #include "vtkMatrix4x4.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkPropCollection.h"
23 #include "vtkVolume.h"
24 #include "vtkAbstractVolumeMapper.h"
25 #include "vtkImageSlice.h"
26 #include "vtkImageMapper3D.h"
27 #include "vtkLinearTransform.h"
28 
29 #include <math.h>
30 
31 vtkStandardNewMacro(vtkLODProp3D);
32 
33 #define VTK_INDEX_NOT_IN_USE    -1
34 
35 #define VTK_INVALID_LOD_INDEX   -2
36 
37 #define VTK_LOD_ACTOR_TYPE       1
38 #define VTK_LOD_VOLUME_TYPE      2
39 #define VTK_LOD_IMAGE_TYPE       3
40 
41 class vtkLODProp3DCallback : public vtkCommand
42 {
43 public:
44   // generic new method
New()45   static vtkLODProp3DCallback *New()
46     { return new vtkLODProp3DCallback; }
47 
48   // the execute
Execute(vtkObject * caller,unsigned long event,void * vtkNotUsed (v))49   virtual void Execute(vtkObject *caller,
50                        unsigned long event, void* vtkNotUsed(v))
51     {
52       vtkProp *po = vtkProp::SafeDownCast(caller);
53       if (event == vtkCommand::PickEvent && po)
54         {
55         this->Self->InvokeEvent(vtkCommand::PickEvent,NULL);
56         }
57     }
58 
59   // some ivars that should be set
60   vtkLODProp3D *Self;
61 };
62 
63 
64 // Construct a new vtkLODProp3D. Automatic LOD selection is on, there are
65 // no LODs.
vtkLODProp3D()66 vtkLODProp3D::vtkLODProp3D()
67 {
68   this->NumberOfEntries = 0;
69   this->NumberOfLODs = 0;
70   this->LODs = NULL;
71   this->CurrentIndex = 1000;
72   this->AutomaticLODSelection = 1;
73   this->SelectedLODID = 1000;
74   this->SelectedLODIndex = -1;
75   this->SelectedPickLODID = 1000;
76   this->AutomaticPickLODSelection = 1;
77   this->PickCallback = vtkLODProp3DCallback::New();
78   this->PickCallback->Self = this;
79 }
80 
81 // Destruct the vtkLODProp3D. Delete the vtkProp3Ds that were created
82 // for the LODs. Delete the array of LODs.
~vtkLODProp3D()83 vtkLODProp3D::~vtkLODProp3D()
84 {
85   // Delete the vtkProp3D objects that were created
86   for (int i = 0; i < this->NumberOfEntries; i++)
87     {
88     if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE)
89       {
90       this->LODs[i].Prop3D->RemoveConsumer(this);
91       this->LODs[i].Prop3D->RemoveObserver(this->PickCallback);
92       this->LODs[i].Prop3D->Delete();
93       }
94     }
95 
96   // Delete the array of LODs
97   if (this->NumberOfEntries > 0)
98     {
99     delete [] this->LODs;
100     }
101 
102   this->PickCallback->Delete();
103 }
104 
ConvertIDToIndex(int id)105 int vtkLODProp3D::ConvertIDToIndex(int id)
106 {
107   int index = 0;
108 
109   while (index < this->NumberOfEntries && this->LODs[index].ID != id)
110     {
111     index++;
112     }
113   if (index == this->NumberOfEntries)
114     {
115     vtkErrorMacro(<< "Could not locate ID: " << id);
116     index = VTK_INVALID_LOD_INDEX;
117     }
118 
119   return index;
120 }
121 
122 // Get the next available entry index
GetNextEntryIndex()123 int vtkLODProp3D::GetNextEntryIndex()
124 {
125   // Search for an available index
126   int index = 0;
127   while (index < this->NumberOfEntries &&
128     this->LODs[index].ID != VTK_INDEX_NOT_IN_USE)
129     {
130     index++;
131     }
132 
133   // If an available index was not found, we need more entries
134   if (index >= this->NumberOfEntries)
135     {
136     // If we have no entries, create 10. If we already have some, create
137     // twice as many as we already have.
138     int amount = (this->NumberOfEntries)?(this->NumberOfEntries*2):(10);
139 
140     // Make the new array
141     vtkLODProp3DEntry *newLODs = new vtkLODProp3DEntry[amount];
142 
143     int i;
144     // Copy the old entries into the new array
145     for (i = 0; i < this->NumberOfEntries; i++)
146       {
147       newLODs[i].Prop3D        = this->LODs[i].Prop3D;
148       newLODs[i].Prop3DType    = this->LODs[i].Prop3DType;
149       newLODs[i].ID            = this->LODs[i].ID;
150       newLODs[i].EstimatedTime = this->LODs[i].EstimatedTime;
151       newLODs[i].Level         = this->LODs[i].Level;
152       newLODs[i].State         = this->LODs[i].State;
153       }
154 
155     // This is the index that we will return - one past the old entries
156     index = i;
157 
158     // Initialize the new entries to default values
159     for (; i < amount; i++)
160       {
161       newLODs[i].Prop3D = NULL;
162       newLODs[i].ID     = VTK_INDEX_NOT_IN_USE;
163       }
164 
165     // Delete the old array and set the pointer to the new one
166     delete [] this->LODs;
167     this->LODs = newLODs;
168 
169     // Set the new number of entries that we have
170     this->NumberOfEntries = amount;
171     }
172   return index;
173 }
174 
175 // Get the bounds of this prop. This is just the max bounds of all LODs
GetBounds()176 double *vtkLODProp3D::GetBounds()
177 {
178   double newBounds[6];
179   int first = 1;
180 
181   // Loop through all valid entries
182   for (int i = 0; i < this->NumberOfEntries; i++)
183     {
184     if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE)
185       {
186       vtkProp3D *p = this->LODs[i].Prop3D;
187       if (p->GetMTime() < this->GetMTime())
188         {
189         p->SetUserMatrix(this->GetMatrix());
190         }
191 
192       // Get the bounds of this entry
193       p->GetBounds(newBounds);
194 
195       // If this is the first entry, this is the current bounds
196       if (first)
197         {
198         memcpy(this->Bounds, newBounds, 6*sizeof(double));
199         first = 0;
200         }
201       // If this is not the first entry, compare these bounds with the
202       // current bounds expanding the current ones as necessary
203       else
204         {
205         this->Bounds[0] =
206           (newBounds[0] < this->Bounds[0])?(newBounds[0]):(this->Bounds[0]);
207         this->Bounds[1] =
208           (newBounds[1] > this->Bounds[1])?(newBounds[1]):(this->Bounds[1]);
209         this->Bounds[2] =
210           (newBounds[2] < this->Bounds[2])?(newBounds[2]):(this->Bounds[2]);
211         this->Bounds[3] =
212           (newBounds[3] > this->Bounds[3])?(newBounds[3]):(this->Bounds[3]);
213         this->Bounds[4] =
214           (newBounds[4] < this->Bounds[4])?(newBounds[4]):(this->Bounds[4]);
215         this->Bounds[5] =
216           (newBounds[5] > this->Bounds[5])?(newBounds[5]):(this->Bounds[5]);
217         }
218       }
219     }
220 
221   return this->Bounds;
222 }
223 
224 // Method to remove a LOD based on an ID
RemoveLOD(int id)225 void vtkLODProp3D::RemoveLOD(int id)
226 {
227   int index = this->ConvertIDToIndex(id);
228 
229   if (index == VTK_INVALID_LOD_INDEX)
230     {
231     return;
232     }
233 
234   this->LODs[index].Prop3D->RemoveConsumer(this);
235   this->LODs[index].Prop3D->RemoveObserver(this->PickCallback);
236   this->LODs[index].Prop3D->Delete();
237   this->LODs[index].ID = VTK_INDEX_NOT_IN_USE;
238   this->NumberOfLODs--;
239 }
240 
241 // Convenience method to get the ID of the LOD that was used
242 // during the last render
GetLastRenderedLODID()243 int vtkLODProp3D::GetLastRenderedLODID()
244 {
245   // Check if the selected index is in range
246   if (this->SelectedLODIndex < 0 ||
247        this->SelectedLODIndex >= this->NumberOfEntries)
248     {
249     return -1;
250     }
251 
252   // Check if the selected index is valid
253   if (this->LODs[this->SelectedLODIndex].ID == VTK_INDEX_NOT_IN_USE)
254     {
255     return -1;
256     }
257 
258   return this->LODs[this->SelectedLODIndex].ID;
259 }
260 
261 // Convenience method to get the estimated render time for a given LOD
262 // based on an ID (the number returned when the LOD was added)
GetLODEstimatedRenderTime(int id)263 double vtkLODProp3D::GetLODEstimatedRenderTime(int id)
264 {
265   int index = this->ConvertIDToIndex(id);
266 
267   return (index != VTK_INVALID_LOD_INDEX) ?
268     this->GetLODIndexEstimatedRenderTime(index) : 0.0;
269 }
270 
GetLODIndexEstimatedRenderTime(int index)271 double vtkLODProp3D::GetLODIndexEstimatedRenderTime(int index)
272 {
273   return (index < 0 || index >= this->NumberOfEntries) ?
274     0 : this->LODs[index].EstimatedTime;
275 }
276 
277 // Convenience method to set an actor LOD without a texture, or a
278 // backface property.  Needed from tcl (for example) where null pointers
279 // are not possible
AddLOD(vtkMapper * m,vtkProperty * p,double time)280 int vtkLODProp3D::AddLOD(vtkMapper *m, vtkProperty *p, double time)
281 {
282   return this->AddLOD(m, p, NULL, NULL, time);
283 }
284 
285 // Convenience method to set an actor LOD without a texture.
286 // Needed from tcl (for example) where null pointers are not possible
AddLOD(vtkMapper * m,vtkProperty * p,vtkProperty * back,double time)287 int vtkLODProp3D::AddLOD(vtkMapper *m, vtkProperty *p,
288                          vtkProperty *back, double time)
289 {
290   return this->AddLOD(m, p, back, NULL, time);
291 }
292 
293 // Convenience method to set an actor LOD without a backface property.
294 // Needed from tcl (for example) where null pointers are not possible
AddLOD(vtkMapper * m,vtkProperty * p,vtkTexture * t,double time)295 int vtkLODProp3D::AddLOD(vtkMapper *m, vtkProperty *p,
296                          vtkTexture *t, double time)
297 {
298   return this->AddLOD(m, p, NULL, t, time);
299 }
300 
301 // Convenience method to set an actor LOD without a property.
302 // Needed from tcl (for example) where null pointers are not possible
AddLOD(vtkMapper * m,vtkTexture * t,double time)303 int vtkLODProp3D::AddLOD(vtkMapper *m, vtkTexture *t, double time)
304 {
305   return this->AddLOD(m, NULL, NULL, t, time);
306 }
307 
308 // Convenience method to set an actor LOD without a texture or a property.
309 // Needed from tcl (for example) where null pointers are not possible
AddLOD(vtkMapper * m,double time)310 int vtkLODProp3D::AddLOD(vtkMapper *m, double time)
311 {
312   return this->AddLOD(m, NULL, NULL, NULL, time);
313 }
314 
315 // The real method for adding an actor LOD.
AddLOD(vtkMapper * m,vtkProperty * p,vtkProperty * back,vtkTexture * t,double time)316 int vtkLODProp3D::AddLOD(vtkMapper *m, vtkProperty *p,
317                           vtkProperty *back, vtkTexture *t, double time)
318 {
319   int index = this->GetNextEntryIndex();
320   vtkActor* actor = vtkActor::New();
321   vtkMatrix4x4* matrix = vtkMatrix4x4::New();
322   this->GetMatrix(matrix);
323   actor->SetUserMatrix(matrix);
324   matrix->Delete();
325   actor->SetMapper(m);
326   if (p)
327     {
328     actor->SetProperty(p);
329     }
330 
331   if (back)
332     {
333     actor->SetBackfaceProperty(back);
334     }
335 
336   if (t)
337     {
338     actor->SetTexture(t);
339     }
340 
341   actor->AddConsumer(this);
342 
343   this->LODs[index].Prop3D        = actor;
344   this->LODs[index].Prop3DType    = VTK_LOD_ACTOR_TYPE;
345   this->LODs[index].ID            = this->CurrentIndex++;
346   this->LODs[index].EstimatedTime = time;
347   this->LODs[index].Level         = 0.0;
348   this->LODs[index].State         = 1;
349   this->LODs[index].Prop3D->AddObserver(vtkCommand::PickEvent,
350                                         this->PickCallback);
351   this->NumberOfLODs++;
352 
353   actor->SetEstimatedRenderTime(time);
354 
355   return this->LODs[index].ID;
356 }
357 
358 // Convenience method to set a volume LOD without a property.
359 // Needed from tcl (for example) where null pointers are not possible
AddLOD(vtkAbstractVolumeMapper * m,double time)360 int vtkLODProp3D::AddLOD(vtkAbstractVolumeMapper *m, double time)
361 {
362   return this->AddLOD(m, NULL, time);
363 }
364 
365 // The real method for adding a volume LOD.
AddLOD(vtkAbstractVolumeMapper * m,vtkVolumeProperty * p,double time)366 int vtkLODProp3D::AddLOD(vtkAbstractVolumeMapper *m, vtkVolumeProperty *p,
367                           double time)
368 {
369   int index = this->GetNextEntryIndex();
370   vtkVolume* volume = vtkVolume::New();
371   vtkMatrix4x4* matrix = vtkMatrix4x4::New();
372   this->GetMatrix(matrix);
373   volume->SetUserMatrix(matrix);
374   matrix->Delete();
375   volume->SetMapper(m);
376   if (p)
377     {
378     volume->SetProperty(p);
379     }
380 
381   volume->AddConsumer(this);
382 
383   this->LODs[index].Prop3D        = volume;
384   this->LODs[index].Prop3DType    = VTK_LOD_VOLUME_TYPE;
385   this->LODs[index].ID            = this->CurrentIndex++;
386   this->LODs[index].EstimatedTime = time;
387   this->LODs[index].Level         = 0.0;
388   this->LODs[index].State         = 1;
389   this->LODs[index].Prop3D->AddObserver(vtkCommand::PickEvent,
390                                         this->PickCallback);
391   this->NumberOfLODs++;
392 
393   volume->SetEstimatedRenderTime(time);
394 
395   return this->LODs[index].ID;
396 }
397 
398 // Convenience method to set a volume LOD without a property.
399 // Needed from tcl (for example) where null pointers are not possible
AddLOD(vtkImageMapper3D * m,double time)400 int vtkLODProp3D::AddLOD(vtkImageMapper3D *m, double time)
401 {
402   return this->AddLOD(m, NULL, time);
403 }
404 
405 // The real method for adding a volume LOD.
AddLOD(vtkImageMapper3D * m,vtkImageProperty * p,double time)406 int vtkLODProp3D::AddLOD(vtkImageMapper3D *m, vtkImageProperty *p,
407                           double time)
408 {
409   int index = this->GetNextEntryIndex();
410   vtkImageSlice* image = vtkImageSlice::New();
411   vtkMatrix4x4* matrix = vtkMatrix4x4::New();
412   this->GetMatrix(matrix);
413   image->SetUserMatrix(matrix);
414   matrix->Delete();
415   image->SetMapper(m);
416   if (p)
417     {
418     image->SetProperty(p);
419     }
420 
421   image->AddConsumer(this);
422 
423   this->LODs[index].Prop3D        = image;
424   this->LODs[index].Prop3DType    = VTK_LOD_IMAGE_TYPE;
425   this->LODs[index].ID            = this->CurrentIndex++;
426   this->LODs[index].EstimatedTime = time;
427   this->LODs[index].Level         = 0.0;
428   this->LODs[index].State         = 1;
429   this->LODs[index].Prop3D->AddObserver(vtkCommand::PickEvent,
430                                         this->PickCallback);
431   this->NumberOfLODs++;
432 
433   image->SetEstimatedRenderTime(time);
434 
435   return this->LODs[index].ID;
436 }
437 
438 
439 // Set the mapper for an LOD that is an actor
SetLODMapper(int id,vtkMapper * m)440 void vtkLODProp3D::SetLODMapper(int id, vtkMapper *m)
441 {
442   int index = this->ConvertIDToIndex(id);
443 
444   if (index == VTK_INVALID_LOD_INDEX)
445     {
446     return;
447     }
448 
449   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
450     {
451     vtkErrorMacro(<< "Error: Cannot set an actor mapper on a non-actor!");
452     return;
453     }
454 
455   static_cast<vtkActor *>(this->LODs[index].Prop3D)->SetMapper(m);
456 }
457 
458 // Get the mapper for an LOD that is an actor
GetLODMapper(int id,vtkMapper ** m)459 void vtkLODProp3D::GetLODMapper(int id, vtkMapper **m)
460 {
461   *m = NULL;
462 
463   int index = this->ConvertIDToIndex(id);
464 
465   if (index == VTK_INVALID_LOD_INDEX)
466     {
467     return;
468     }
469 
470   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
471     {
472     vtkErrorMacro(<< "Error: Cannot get an actor mapper on a non-actor!");
473 
474     return;
475     }
476 
477   *m = static_cast<vtkActor *>(this->LODs[index].Prop3D)->GetMapper();
478 }
479 
480 // Set the mapper for an LOD that is a volume
SetLODMapper(int id,vtkAbstractVolumeMapper * m)481 void vtkLODProp3D::SetLODMapper(int id, vtkAbstractVolumeMapper *m)
482 {
483   int index = this->ConvertIDToIndex(id);
484 
485   if (index == VTK_INVALID_LOD_INDEX)
486     {
487     return;
488     }
489 
490   if (this->LODs[index].Prop3DType != VTK_LOD_VOLUME_TYPE)
491     {
492     vtkErrorMacro(<< "Error: Cannot set a volume mapper on a non-volume!");
493     return;
494     }
495 
496   static_cast<vtkVolume *>(this->LODs[index].Prop3D)->SetMapper(m);
497 }
498 
499 // Get the mapper for an LOD that is an actor
GetLODMapper(int id,vtkAbstractVolumeMapper ** m)500 void vtkLODProp3D::GetLODMapper(int id, vtkAbstractVolumeMapper **m)
501 {
502   *m = NULL;
503 
504   int index = this->ConvertIDToIndex(id);
505 
506   if (index == VTK_INVALID_LOD_INDEX)
507     {
508     return;
509     }
510 
511   if (this->LODs[index].Prop3DType != VTK_LOD_VOLUME_TYPE)
512     {
513     vtkErrorMacro(<< "Error: Cannot get a volume mapper on a non-volume!");
514     return;
515     }
516 
517   *m = static_cast<vtkVolume *>(this->LODs[index].Prop3D)->GetMapper();
518 }
519 
520 // Set the mapper for an LOD that is an image
SetLODMapper(int id,vtkImageMapper3D * m)521 void vtkLODProp3D::SetLODMapper(int id, vtkImageMapper3D *m)
522 {
523   int index = this->ConvertIDToIndex(id);
524 
525   if (index == VTK_INVALID_LOD_INDEX)
526     {
527     return;
528     }
529 
530   if (this->LODs[index].Prop3DType != VTK_LOD_IMAGE_TYPE)
531     {
532     vtkErrorMacro(<< "Error: Cannot set an image mapper on a non-image!");
533     return;
534     }
535 
536   static_cast<vtkImageSlice *>(this->LODs[index].Prop3D)->SetMapper(m);
537 }
538 
539 // Get the mapper for an LOD that is an image
GetLODMapper(int id,vtkImageMapper3D ** m)540 void vtkLODProp3D::GetLODMapper(int id, vtkImageMapper3D **m)
541 {
542   *m = NULL;
543 
544   int index = this->ConvertIDToIndex(id);
545 
546   if (index == VTK_INVALID_LOD_INDEX)
547     {
548     return;
549     }
550 
551   if (this->LODs[index].Prop3DType != VTK_LOD_IMAGE_TYPE)
552     {
553     vtkErrorMacro(<< "Error: Cannot get an image mapper on a non-image!");
554     return;
555     }
556 
557   *m = static_cast<vtkImageSlice *>(this->LODs[index].Prop3D)->GetMapper();
558 }
559 
560 // Get the mapper for an LOD that is an AbstractMapper3D
GetLODMapper(int id)561 vtkAbstractMapper3D *vtkLODProp3D::GetLODMapper(int id)
562 {
563   vtkAbstractMapper3D *m = NULL;
564 
565   int index = this->ConvertIDToIndex(id);
566 
567   if (index == VTK_INVALID_LOD_INDEX)
568     {
569     return m;
570     }
571 
572   if (this->LODs[index].Prop3DType == VTK_LOD_ACTOR_TYPE)
573     {
574     m = static_cast<vtkActor *>(this->LODs[index].Prop3D)->GetMapper();
575     }
576   else if (this->LODs[index].Prop3DType == VTK_LOD_VOLUME_TYPE)
577     {
578     m = static_cast<vtkVolume *>(this->LODs[index].Prop3D)->GetMapper();
579     }
580   else if (this->LODs[index].Prop3DType == VTK_LOD_IMAGE_TYPE)
581     {
582     m = static_cast<vtkImageSlice *>(this->LODs[index].Prop3D)->GetMapper();
583     }
584 
585   return m;
586 }
587 
588 // Set the property for an LOD that is an actor
SetLODProperty(int id,vtkProperty * p)589 void vtkLODProp3D::SetLODProperty(int id, vtkProperty *p)
590 {
591   int index = this->ConvertIDToIndex(id);
592 
593   if (index == VTK_INVALID_LOD_INDEX)
594     {
595     return;
596     }
597 
598   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
599     {
600     vtkErrorMacro(<< "Error: Cannot set an actor property on a non-actor!");
601     return;
602     }
603 
604   static_cast<vtkActor *>(this->LODs[index].Prop3D)->SetProperty(p);
605 }
606 
607 // Get the property for an LOD that is an actor
GetLODProperty(int id,vtkProperty ** p)608 void vtkLODProp3D::GetLODProperty(int id, vtkProperty **p)
609 {
610   int index = this->ConvertIDToIndex(id);
611 
612   if (index == VTK_INVALID_LOD_INDEX)
613     {
614     return;
615     }
616 
617   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
618     {
619     vtkErrorMacro(<< "Error: Cannot get an actor property on a non-actor!");
620     return;
621     }
622 
623   *p = static_cast<vtkActor *>(this->LODs[index].Prop3D)->GetProperty();
624 }
625 
626 // Set the property for an LOD that is a volume
SetLODProperty(int id,vtkVolumeProperty * p)627 void vtkLODProp3D::SetLODProperty(int id, vtkVolumeProperty *p)
628 {
629   int index = this->ConvertIDToIndex(id);
630 
631   if (index == VTK_INVALID_LOD_INDEX)
632     {
633     return;
634     }
635 
636   if (this->LODs[index].Prop3DType != VTK_LOD_VOLUME_TYPE)
637     {
638     vtkErrorMacro(<< "Error: Cannot set a volume property on a non-volume!");
639     return;
640     }
641 
642   static_cast<vtkVolume *>(this->LODs[index].Prop3D)->SetProperty(p);
643 }
644 
645 // Get the property for an LOD that is an actor
GetLODProperty(int id,vtkVolumeProperty ** p)646 void vtkLODProp3D::GetLODProperty(int id, vtkVolumeProperty **p)
647 {
648   int index = this->ConvertIDToIndex(id);
649 
650   if (index == VTK_INVALID_LOD_INDEX)
651     {
652     return;
653     }
654 
655   if (this->LODs[index].Prop3DType != VTK_LOD_VOLUME_TYPE)
656     {
657     vtkErrorMacro(<< "Error: Cannot get a volume property on a non-volume!");
658     return;
659     }
660 
661   *p = static_cast<vtkVolume *>(this->LODs[index].Prop3D)->GetProperty();
662 }
663 
664 // Set the property for an LOD that is an image
SetLODProperty(int id,vtkImageProperty * p)665 void vtkLODProp3D::SetLODProperty(int id, vtkImageProperty *p)
666 {
667   int index = this->ConvertIDToIndex(id);
668 
669   if (index == VTK_INVALID_LOD_INDEX)
670     {
671     return;
672     }
673 
674   if (this->LODs[index].Prop3DType != VTK_LOD_IMAGE_TYPE)
675     {
676     vtkErrorMacro(<< "Error: Cannot set an image property on a non-image!");
677     return;
678     }
679 
680   static_cast<vtkImageSlice *>(this->LODs[index].Prop3D)->SetProperty(p);
681 }
682 
683 // Get the property for an LOD that is an image
GetLODProperty(int id,vtkImageProperty ** p)684 void vtkLODProp3D::GetLODProperty(int id, vtkImageProperty **p)
685 {
686   int index = this->ConvertIDToIndex(id);
687 
688   if (index == VTK_INVALID_LOD_INDEX)
689     {
690     return;
691     }
692 
693   if (this->LODs[index].Prop3DType != VTK_LOD_IMAGE_TYPE)
694     {
695     vtkErrorMacro(<< "Error: Cannot get an image property on a non-image!");
696     return;
697     }
698 
699   *p = static_cast<vtkImageSlice *>(this->LODs[index].Prop3D)->GetProperty();
700 }
701 
702 // Set the texture for an LOD that is an actor
SetLODTexture(int id,vtkTexture * t)703 void vtkLODProp3D::SetLODTexture(int id, vtkTexture *t)
704 {
705   int index = this->ConvertIDToIndex(id);
706 
707   if (index == VTK_INVALID_LOD_INDEX)
708     {
709     return;
710     }
711 
712   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
713     {
714     vtkErrorMacro(<< "Error: Cannot set an actor texture on a non-actor!");
715     return;
716     }
717 
718   static_cast<vtkActor *>(this->LODs[index].Prop3D)->SetTexture(t);
719 }
720 
721 // Get the texture for an LOD that is an actor
GetLODTexture(int id,vtkTexture ** t)722 void vtkLODProp3D::GetLODTexture(int id, vtkTexture **t)
723 {
724   int index = this->ConvertIDToIndex(id);
725 
726   if (index == VTK_INVALID_LOD_INDEX)
727     {
728     return;
729     }
730 
731   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
732     {
733     vtkErrorMacro(<< "Error: Cannot get an actor texture on a non-actor!");
734     return;
735     }
736 
737   *t = static_cast<vtkActor *>(this->LODs[index].Prop3D)->GetTexture();
738 }
739 
740 // Set the backface property for an LOD that is an actor
SetLODBackfaceProperty(int id,vtkProperty * t)741 void vtkLODProp3D::SetLODBackfaceProperty(int id, vtkProperty *t)
742 {
743   int index = this->ConvertIDToIndex(id);
744 
745   if (index == VTK_INVALID_LOD_INDEX)
746     {
747     return;
748     }
749 
750   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
751     {
752     vtkErrorMacro(<< "Error: Cannot set an actor backface property on a non-actor!");
753     return;
754     }
755 
756   static_cast<vtkActor *>(this->LODs[index].Prop3D)->SetBackfaceProperty(t);
757 }
758 
759 // Get the backface property for an LOD that is an actor
GetLODBackfaceProperty(int id,vtkProperty ** t)760 void vtkLODProp3D::GetLODBackfaceProperty(int id, vtkProperty **t)
761 {
762   int index = this->ConvertIDToIndex(id);
763 
764   if (index == VTK_INVALID_LOD_INDEX)
765     {
766     return;
767     }
768 
769   if (this->LODs[index].Prop3DType != VTK_LOD_ACTOR_TYPE)
770     {
771     vtkErrorMacro(<< "Error: Cannot get an actor backface property on a non-actor!");
772     return;
773     }
774 
775   *t = static_cast<vtkActor *>(this->LODs[index].Prop3D)->GetBackfaceProperty();
776 }
777 
EnableLOD(int id)778 void vtkLODProp3D::EnableLOD(int id)
779 {
780   int index = this->ConvertIDToIndex(id);
781 
782   if (index == VTK_INVALID_LOD_INDEX || index == VTK_INDEX_NOT_IN_USE)
783     {
784     return;
785     }
786 
787   this->LODs[index].State = 1;
788 }
789 
DisableLOD(int id)790 void vtkLODProp3D::DisableLOD(int id)
791 {
792   int index = this->ConvertIDToIndex(id);
793 
794   if (index == VTK_INVALID_LOD_INDEX || index == VTK_INDEX_NOT_IN_USE)
795     {
796     return;
797     }
798 
799   this->LODs[index].State = 0;
800 }
801 
IsLODEnabled(int id)802 int vtkLODProp3D::IsLODEnabled(int id)
803 {
804   int index = this->ConvertIDToIndex(id);
805 
806   if (index == VTK_INVALID_LOD_INDEX || index == VTK_INDEX_NOT_IN_USE)
807     {
808     return 0;
809     }
810 
811   return this->LODs[index].State;
812 }
813 
SetLODLevel(int id,double level)814 void vtkLODProp3D::SetLODLevel(int id, double level)
815 {
816   int index = this->ConvertIDToIndex(id);
817 
818   if (index == VTK_INVALID_LOD_INDEX || index == VTK_INDEX_NOT_IN_USE)
819     {
820     return;
821     }
822 
823   this->LODs[index].Level = level;
824 }
825 
GetLODLevel(int id)826 double vtkLODProp3D::GetLODLevel(int id)
827 {
828   int index = this->ConvertIDToIndex(id);
829 
830   if (index == VTK_INVALID_LOD_INDEX || index == VTK_INDEX_NOT_IN_USE)
831     {
832     return -1;
833     }
834 
835   return this->LODs[index].Level;
836 }
837 
GetLODIndexLevel(int index)838 double vtkLODProp3D::GetLODIndexLevel(int index)
839 {
840   if (index == VTK_INVALID_LOD_INDEX || index == VTK_INDEX_NOT_IN_USE)
841     {
842     return -1;
843     }
844   return this->LODs[index].Level;
845 }
846 
847 // Release any graphics resources that any of the LODs might be using
848 // for a particular window (such as display lists).
ReleaseGraphicsResources(vtkWindow * w)849 void vtkLODProp3D::ReleaseGraphicsResources(vtkWindow *w)
850 {
851   // Loop through all LODs and pass this message along
852   for (int i = 0; i < this->NumberOfEntries; i++)
853     {
854     if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE)
855       {
856       this->LODs[i].Prop3D->ReleaseGraphicsResources(w);
857       }
858     }
859 }
860 
861 // Standard render method - render any opaque geometry in the selected LOD
RenderOpaqueGeometry(vtkViewport * viewport)862 int vtkLODProp3D::RenderOpaqueGeometry(vtkViewport *viewport)
863 {
864   // Check if the selected index is in range
865   if (this->SelectedLODIndex < 0 ||
866        this->SelectedLODIndex >= this->NumberOfEntries)
867     {
868     vtkErrorMacro(<< "Index out of range!");
869     return 0;
870     }
871 
872   // Check if the selected index is valid
873   if (this->LODs[this->SelectedLODIndex].ID == VTK_INDEX_NOT_IN_USE)
874     {
875     vtkErrorMacro(<< "Index not valid!");
876     return 0;
877     }
878 
879   // Actually do the rendering
880   int retval =
881     this->LODs[this->SelectedLODIndex].Prop3D->RenderOpaqueGeometry(viewport);
882 
883   this->EstimatedRenderTime +=
884     this->LODs[this->SelectedLODIndex].Prop3D->GetEstimatedRenderTime();
885 
886   return retval;
887 }
888 
889 // Standard render method - render any translucent geometry in the selected LOD
RenderTranslucentPolygonalGeometry(vtkViewport * viewport)890 int vtkLODProp3D::RenderTranslucentPolygonalGeometry(vtkViewport *viewport)
891 {
892   // Check if the selected index is in range
893   if (this->SelectedLODIndex < 0 ||
894        this->SelectedLODIndex >= this->NumberOfEntries)
895     {
896     vtkErrorMacro(<< "Index out of range!");
897     return 0;
898     }
899 
900   // Check if the selected index is valid
901   if (this->LODs[this->SelectedLODIndex].ID == VTK_INDEX_NOT_IN_USE)
902     {
903     vtkErrorMacro(<< "Index not valid!");
904     return 0;
905     }
906 
907   // Actually do the rendering
908   int retval = this->LODs[this->SelectedLODIndex].Prop3D->
909     RenderTranslucentPolygonalGeometry(viewport);
910 
911   this->EstimatedRenderTime +=
912     this->LODs[this->SelectedLODIndex].Prop3D->GetEstimatedRenderTime();
913 
914   return retval;
915 }
916 
917 // Description:
918 // Does this prop have some translucent polygonal geometry?
HasTranslucentPolygonalGeometry()919 int vtkLODProp3D::HasTranslucentPolygonalGeometry()
920 {
921   // Check if the selected index is in range
922   if (this->SelectedLODIndex < 0 ||
923        this->SelectedLODIndex >= this->NumberOfEntries)
924     {
925     vtkErrorMacro(<< "Index out of range!");
926     return 0;
927     }
928 
929   // Check if the selected index is valid
930   if (this->LODs[this->SelectedLODIndex].ID == VTK_INDEX_NOT_IN_USE)
931     {
932     vtkErrorMacro(<< "Index not valid!");
933     return 0;
934     }
935 
936   return this->LODs[this->SelectedLODIndex].Prop3D->HasTranslucentPolygonalGeometry();
937 }
938 
939 // Standard render method - render any translucent geometry in the selected LOD
RenderVolumetricGeometry(vtkViewport * viewport)940 int vtkLODProp3D::RenderVolumetricGeometry(vtkViewport *viewport)
941 {
942   // Check if the selected index is in range
943   if (this->SelectedLODIndex < 0 ||
944       this->SelectedLODIndex >= this->NumberOfEntries)
945     {
946     vtkErrorMacro(<< "Index out of range!");
947     return 0;
948     }
949 
950   // Check if the selected index is valid
951   if (this->LODs[this->SelectedLODIndex].ID == VTK_INDEX_NOT_IN_USE)
952     {
953     vtkErrorMacro(<< "Index not valid!");
954     return 0;
955     }
956 
957   // Actually do the rendering
958   int retval = this->LODs[this->SelectedLODIndex].Prop3D->
959     RenderVolumetricGeometry(viewport);
960 
961   this->EstimatedRenderTime +=
962     this->LODs[this->SelectedLODIndex].Prop3D->GetEstimatedRenderTime();
963 
964   return retval;
965 }
966 
967 // Override the method from vtkProp - add to both this prop and the prop of
968 // the selected LOD
AddEstimatedRenderTime(double t,vtkViewport * vp)969 void vtkLODProp3D::AddEstimatedRenderTime(double t, vtkViewport *vp)
970 {
971   // Add to this prop's estimated render time
972   this->EstimatedRenderTime += t;
973 
974   // Check if the selected index is in range
975   if (this->SelectedLODIndex < 0 ||
976        this->SelectedLODIndex >= this->NumberOfEntries)
977     {
978     vtkErrorMacro(<< "Index out of range!");
979     return;
980     }
981 
982   // Check if the selected index is valid
983   if (this->LODs[this->SelectedLODIndex].ID == VTK_INDEX_NOT_IN_USE)
984     {
985     vtkErrorMacro(<< "Index not valid!");
986     return;
987     }
988 
989   // Now that error checking is done, add to the estimated render time
990   // of the selected LOD
991   this->LODs[this->SelectedLODIndex].Prop3D->AddEstimatedRenderTime(t, vp);
992 }
993 
RestoreEstimatedRenderTime()994 void vtkLODProp3D::RestoreEstimatedRenderTime()
995 {
996   // restore the EstimatedTime of the last LOD to be rendered
997   if (this->SelectedLODIndex >= 0 &&
998        this->SelectedLODIndex < this->NumberOfEntries)
999     {
1000     this->LODs[this->SelectedLODIndex].Prop3D->RestoreEstimatedRenderTime();
1001     }
1002 }
1003 
1004 // Set the allocated render time - this is where the decision is made
1005 // as to which LOD to select
SetAllocatedRenderTime(double t,vtkViewport * vp)1006 void vtkLODProp3D::SetAllocatedRenderTime(double t, vtkViewport *vp)
1007 {
1008   int    i;
1009   int    index = -1;
1010   double  bestTime;
1011   double  bestLevel = 0;
1012   double  targetTime;
1013   double  estimatedTime;
1014   double  newTime;
1015 
1016   // update the EstimatedTime of the last LOD to be rendered
1017   if (this->SelectedLODIndex >= 0 &&
1018        this->SelectedLODIndex < this->NumberOfEntries &&
1019        this->LODs[this->SelectedLODIndex].ID != VTK_INDEX_NOT_IN_USE)
1020     {
1021     // For stability, blend in the new time - 25% old + 75% new
1022     newTime =
1023       this->LODs[this->SelectedLODIndex].Prop3D->GetEstimatedRenderTime(vp);
1024     this->LODs[this->SelectedLODIndex].EstimatedTime =
1025       0.25 * this->LODs[this->SelectedLODIndex].EstimatedTime +
1026       0.75 * newTime;
1027     }
1028 
1029   this->SavedEstimatedRenderTime = this->EstimatedRenderTime;
1030 
1031   if (this->AutomaticLODSelection)
1032     {
1033     bestTime = -1.0;
1034 
1035     targetTime = t;
1036 
1037     for (i = 0; i < this->NumberOfEntries; i++)
1038       {
1039       if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE &&
1040            this->LODs[i].State == 1)
1041         {
1042         // Gather some information
1043         estimatedTime = this->GetLODIndexEstimatedRenderTime(i);
1044 
1045         // If we've never rendered this LOD and we have no info on it,
1046         // then try it out
1047         if (estimatedTime == 0.0)
1048           {
1049           index = i;
1050           bestTime = 0.0;
1051           bestLevel = this->GetLODIndexLevel(i);
1052           break;
1053           }
1054 
1055         // If we do have at least a guess as to the render time, and
1056         // this seems like the best we have so far, pick it.
1057         // It is the best we have if
1058         //
1059         // 1) our estimated time is less than what we are looking for,
1060         //    but greater than any we have selected so far.
1061         //
1062         // 2) we have not selected anything else yet
1063         //    (regardless of what the estimated time is)
1064         //
1065         // 3) it is less than the time of the currently selected LOD
1066         //    if that LOD's time is greater than the time we are targeting.
1067         //
1068         if (estimatedTime > 0.0 &&
1069           ((estimatedTime > bestTime && estimatedTime < targetTime) ||
1070           (bestTime == -1.0) ||
1071           (estimatedTime < bestTime && bestTime > targetTime)))
1072           {
1073           index = i;
1074           bestTime = estimatedTime;
1075           bestLevel = this->GetLODIndexLevel(i);
1076           }
1077         }
1078       }
1079 
1080     // If we aren't trying some level for the first time with 0.0 bestTime,
1081     // make sure there isn't a LOD that can be rendered faster and has a
1082     // higher level
1083     double level;
1084     if (bestTime != 0.0)
1085       {
1086       for (i = 0; i < this->NumberOfEntries; i++)
1087         {
1088         if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE &&
1089             this->LODs[i].State == 1)
1090           {
1091           // Gather some information
1092           estimatedTime = this->GetLODIndexEstimatedRenderTime(i);
1093           level = this->GetLODIndexLevel(i);
1094 
1095           // Update the index and the level, but not the time. This is
1096           // so that we find the best level that can be rendered
1097           // faster than the LOD selected above.
1098           if (estimatedTime <= bestTime && level < bestLevel)
1099             {
1100             index = i;
1101             bestLevel = level;
1102             }
1103           }
1104         }
1105       }
1106     }
1107   else
1108     {
1109     index = 0;
1110     while (index < this->NumberOfEntries && this->LODs[index].ID !=
1111            this->SelectedLODID)
1112       {
1113       index++;
1114       }
1115     if (index == this->NumberOfEntries)
1116       {
1117       vtkErrorMacro(<< "Could not render selected LOD ID: " <<
1118                      this->SelectedLODID);
1119       index = 0;
1120       while (index < this->NumberOfEntries && this->LODs[index].ID !=
1121               VTK_INDEX_NOT_IN_USE)
1122         {
1123         index++;
1124         }
1125       }
1126 
1127     }
1128 
1129   this->EstimatedRenderTime = 0.0;
1130   this->AllocatedRenderTime = t;
1131   if (index == -1)
1132     {
1133     return;
1134     }
1135 
1136   this->SelectedLODIndex = index;
1137   this->LODs[this->SelectedLODIndex].Prop3D->SetAllocatedRenderTime(t, vp);
1138 
1139   // Push the matrix down into the selected LOD
1140   vtkProp3D *p = this->LODs[this->SelectedLODIndex].Prop3D;
1141   // Getting our matrix here triggers a ComputeMatrix, if necessary,
1142   // which updates our MatrixMTime
1143   vtkMatrix4x4 *mat = this->GetMatrix();
1144   if (p->GetUserTransformMatrixMTime() < this->MatrixMTime)
1145     {
1146     p->SetUserMatrix(mat) ;
1147     }
1148 }
1149 
PrintSelf(ostream & os,vtkIndent indent)1150 void vtkLODProp3D::PrintSelf(ostream& os, vtkIndent indent)
1151 {
1152   this->Superclass::PrintSelf(os,indent);
1153 
1154   os << indent << "Number Of LODs: " << this->NumberOfLODs << endl;
1155 
1156   os << indent << "Selected LOD ID: " << this->SelectedLODID << endl;
1157 
1158   os << indent << "AutomaticLODSelection: "
1159      << (this->AutomaticLODSelection ? "On\n" : "Off\n");
1160 
1161   os << indent << "AutomaticPickLODSelection: "
1162      << (this->AutomaticPickLODSelection ? "On\n" : "Off\n");
1163 
1164   os << indent << "SelectedPickLODID: " << this->SelectedPickLODID << endl;
1165 
1166   os << indent << "CurrentIndex: " << this->CurrentIndex << endl;
1167 }
1168 
GetActors(vtkPropCollection * ac)1169 void vtkLODProp3D::GetActors(vtkPropCollection *ac)
1170 {
1171 #if 0
1172   // I don't get that 1999 code, why is it limiting the actors to the one
1173   // picked...
1174 
1175   vtkDebugMacro(<< "vtkLODProp3D::GetActors");
1176   int index;
1177   int lodID;
1178 
1179   lodID = this->GetPickLODID();
1180   index = this->ConvertIDToIndex(lodID);
1181 
1182   if (index == VTK_INVALID_LOD_INDEX)
1183     {
1184     return;
1185     }
1186 
1187   if (! this->LODs[index].Prop3D->IsA("vtkVolume"))
1188     {
1189     ac->AddItem(this->LODs[index].Prop3D);
1190     }
1191 #else
1192   for (int i = 0; i < this->NumberOfEntries; i++)
1193     {
1194     if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE &&
1195         vtkActor::SafeDownCast(this->LODs[i].Prop3D))
1196       {
1197       ac->AddItem(this->LODs[i].Prop3D);
1198       }
1199     }
1200 #endif
1201 }
1202 
GetVolumes(vtkPropCollection * ac)1203 void vtkLODProp3D::GetVolumes(vtkPropCollection *ac)
1204 {
1205   for (int i = 0; i < this->NumberOfEntries; i++)
1206     {
1207     if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE &&
1208         vtkVolume::SafeDownCast(this->LODs[i].Prop3D))
1209       {
1210       ac->AddItem(this->LODs[i].Prop3D);
1211       }
1212     }
1213 }
1214 
GetAutomaticPickPropIndex()1215 int vtkLODProp3D::GetAutomaticPickPropIndex()
1216 {
1217   double bestTime = -1.0;
1218   int index = 0;
1219   double targetTime = 0;
1220 
1221   for (int i = 0; i < this->NumberOfEntries; i++)
1222     {
1223     if (this->LODs[i].ID != VTK_INDEX_NOT_IN_USE)
1224       {
1225       // Gather some information
1226       double estimatedTime = this->GetLODIndexEstimatedRenderTime(i);
1227 
1228       // If we've never rendered this LOD and we have no info on it,
1229       // then try it out
1230       if (estimatedTime == 0.0)
1231         {
1232         index = i;
1233         break;
1234         }
1235 
1236       // If we do have at least a guess as to the render time, and
1237       // this seems like the best we have so far, pick it.
1238       // It is the best we have if
1239       //
1240       // 1) our estimated time is less than what we are looking for,
1241       //    but greater than any we have selected so far.
1242       //
1243       // 2) we have not selected anything else yet
1244       //    (regardless of what the estimated time is)
1245       //
1246       // 3) it is less than the time of the currently selected LOD
1247       //    if that LOD's time is greater than the time we are targeting.
1248       //
1249       if (estimatedTime > 0.0 &&
1250         ((estimatedTime > bestTime && estimatedTime < targetTime) ||
1251         (bestTime == -1.0) ||
1252         (estimatedTime < bestTime && bestTime > targetTime)))
1253         {
1254         index = i;
1255         bestTime = estimatedTime;
1256         }
1257       }
1258     }
1259   return index;
1260 }
1261 
GetPickLODID(void)1262 int vtkLODProp3D::GetPickLODID(void)
1263 {
1264   vtkDebugMacro(<< "vtkLODProp3D::GetPickLODID");
1265   int lodID, index;
1266   if (this->AutomaticPickLODSelection)
1267     {
1268     if (this->SelectedLODIndex < 0 ||
1269          this->SelectedLODIndex >= this->NumberOfEntries)
1270       {
1271       index = this->GetAutomaticPickPropIndex();
1272       }
1273     else
1274       {
1275       index = this->SelectedLODIndex;
1276       }
1277     lodID = this->LODs[index].ID;
1278     }
1279   else
1280     {
1281     lodID = this->SelectedPickLODID;
1282     }
1283   return lodID;
1284 }
1285 
SetSelectedPickLODID(int id)1286 void vtkLODProp3D::SetSelectedPickLODID(int id)
1287 {
1288   this->SelectedPickLODID = id;
1289   this->Modified();
1290 }
1291 
ShallowCopy(vtkProp * prop)1292 void vtkLODProp3D::ShallowCopy(vtkProp *prop)
1293 {
1294   vtkLODProp3D *a = vtkLODProp3D::SafeDownCast(prop);
1295 
1296   if (a)
1297     {
1298     this->SetAutomaticLODSelection(a->GetAutomaticLODSelection());
1299     this->SetAutomaticPickLODSelection(a->GetAutomaticPickLODSelection());
1300     this->SetSelectedLODID(a->GetSelectedLODID());
1301     this->NumberOfLODs = a->NumberOfLODs;
1302     // for(int i = 0; i < this->NumberOfLODs; i++) {}
1303     }
1304 
1305   // Now do superclass
1306   this->vtkProp3D::ShallowCopy(prop);
1307 }
1308