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