Panda3D
lightAttrib.cxx
1 // Filename: lightAttrib.cxx
2 // Created by: drose (26Mar02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "lightAttrib.h"
16 #include "pandaNode.h"
17 #include "nodePath.h"
18 #include "graphicsStateGuardianBase.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
21 #include "datagram.h"
22 #include "datagramIterator.h"
23 #include "config_pgraph.h"
24 #include "attribNodeRegistry.h"
25 #include "indent.h"
26 #include <iterator>
27 
28 CPT(RenderAttrib) LightAttrib::_empty_attrib;
29 int LightAttrib::_attrib_slot;
30 CPT(RenderAttrib) LightAttrib::_all_off_attrib;
31 TypeHandle LightAttrib::_type_handle;
32 
33 // This STL Function object is used in filter_to_max(), below, to sort
34 // a list of Lights in reverse order by priority. In the case of two
35 // lights with equal priority, the class priority is compared.
37 public:
38  bool operator ()(const NodePath &a, const NodePath &b) const {
39  nassertr(!a.is_empty() && !b.is_empty(), a < b);
40  Light *la = a.node()->as_light();
41  Light *lb = b.node()->as_light();
42  nassertr(la != (Light *)NULL && lb != (Light *)NULL, a < b);
43 
44  if (la->get_priority() != lb->get_priority()) {
45  return la->get_priority() > lb->get_priority();
46  }
47  return la->get_class_priority() > lb->get_class_priority();
48  }
49 };
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: LightAttrib::make
53 // Access: Published, Static
54 // Description: Constructs a new LightAttrib object that turns on (or
55 // off, according to op) the indicated light(s).
56 //
57 // This method is now deprecated. Use add_on_light() or
58 // add_off_light() instead.
59 ////////////////////////////////////////////////////////////////////
60 CPT(RenderAttrib) LightAttrib::
61 make(LightAttrib::Operation op, Light *light) {
62  pgraph_cat.warning()
63  << "Using deprecated LightAttrib interface.\n";
64 
65  CPT(RenderAttrib) attrib;
66 
67  switch (op) {
68  case O_set:
69  attrib = make_all_off();
70  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light->as_node()));
71  return attrib;
72 
73  case O_add:
74  attrib = make();
75  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light->as_node()));
76  return attrib;
77 
78  case O_remove:
79  attrib = make();
80  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light->as_node()));
81  return attrib;
82  }
83 
84  nassertr(false, make());
85  return make();
86 }
87 
88 ////////////////////////////////////////////////////////////////////
89 // Function: LightAttrib::make
90 // Access: Published, Static
91 // Description: Constructs a new LightAttrib object that turns on (or
92 // off, according to op) the indicate light(s).
93 //
94 // This method is now deprecated. Use add_on_light() or
95 // add_off_light() instead.
96 ////////////////////////////////////////////////////////////////////
97 CPT(RenderAttrib) LightAttrib::
98 make(LightAttrib::Operation op, Light *light1, Light *light2) {
99  pgraph_cat.warning()
100  << "Using deprecated LightAttrib interface.\n";
101 
102  CPT(RenderAttrib) attrib;
103 
104  switch (op) {
105  case O_set:
106  attrib = make_all_off();
107  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
108  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
109  return attrib;
110 
111  case O_add:
112  attrib = make();
113  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
114  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
115  return attrib;
116 
117  case O_remove:
118  attrib = make();
119  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light1->as_node()));
120  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light2->as_node()));
121  return attrib;
122  }
123 
124  nassertr(false, make());
125  return make();
126 }
127 
128 ////////////////////////////////////////////////////////////////////
129 // Function: LightAttrib::make
130 // Access: Published, Static
131 // Description: Constructs a new LightAttrib object that turns on (or
132 // off, according to op) the indicate light(s).
133 //
134 // This method is now deprecated. Use add_on_light() or
135 // add_off_light() instead.
136 ////////////////////////////////////////////////////////////////////
137 CPT(RenderAttrib) LightAttrib::
138 make(LightAttrib::Operation op, Light *light1, Light *light2,
139  Light *light3) {
140  pgraph_cat.warning()
141  << "Using deprecated LightAttrib interface.\n";
142 
143  CPT(RenderAttrib) attrib;
144 
145  switch (op) {
146  case O_set:
147  attrib = make_all_off();
148  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
149  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
150  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
151  return attrib;
152 
153  case O_add:
154  attrib = make();
155  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
156  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
157  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
158  return attrib;
159 
160  case O_remove:
161  attrib = make();
162  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light1->as_node()));
163  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light2->as_node()));
164  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light3->as_node()));
165  return attrib;
166  }
167 
168  nassertr(false, make());
169  return make();
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: LightAttrib::make
174 // Access: Published, Static
175 // Description: Constructs a new LightAttrib object that turns on (or
176 // off, according to op) the indicate light(s).
177 //
178 // This method is now deprecated. Use add_on_light() or
179 // add_off_light() instead.
180 ////////////////////////////////////////////////////////////////////
181 CPT(RenderAttrib) LightAttrib::
182 make(LightAttrib::Operation op, Light *light1, Light *light2,
183  Light *light3, Light *light4) {
184  pgraph_cat.warning()
185  << "Using deprecated LightAttrib interface.\n";
186 
187  CPT(RenderAttrib) attrib;
188 
189  switch (op) {
190  case O_set:
191  attrib = make_all_off();
192  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
193  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
194  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
195  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light4->as_node()));
196  return attrib;
197 
198  case O_add:
199  attrib = make();
200  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light1->as_node()));
201  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light2->as_node()));
202  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light3->as_node()));
203  attrib = DCAST(LightAttrib, attrib)->add_on_light(NodePath(light4->as_node()));
204  return attrib;
205 
206  case O_remove:
207  attrib = make();
208  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light1->as_node()));
209  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light2->as_node()));
210  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light3->as_node()));
211  attrib = DCAST(LightAttrib, attrib)->add_off_light(NodePath(light4->as_node()));
212  return attrib;
213  }
214 
215  nassertr(false, make());
216  return make();
217 }
218 
219 ////////////////////////////////////////////////////////////////////
220 // Function: LightAttrib::make_default
221 // Access: Published, Static
222 // Description: Returns a RenderAttrib that corresponds to whatever
223 // the standard default properties for render attributes
224 // of this type ought to be.
225 ////////////////////////////////////////////////////////////////////
226 CPT(RenderAttrib) LightAttrib::
227 make_default() {
228  return return_new(new LightAttrib);
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: LightAttrib::get_operation
233 // Access: Published
234 // Description: Returns the basic operation type of the LightAttrib.
235 // If this is O_set, the lights listed here completely
236 // replace any lights that were already on. If this is
237 // O_add, the lights here are added to the set of of
238 // lights that were already on, and if O_remove, the
239 // lights here are removed from the set of lights that
240 // were on.
241 //
242 // This method is now deprecated. LightAttribs nowadays
243 // have a separate list of on_lights and off_lights, so
244 // this method doesn't make sense. Query the lists
245 // independently.
246 ////////////////////////////////////////////////////////////////////
247 LightAttrib::Operation LightAttrib::
248 get_operation() const {
249  pgraph_cat.warning()
250  << "Using deprecated LightAttrib interface.\n";
251 
252  if (has_all_off()) {
253  return O_set;
254 
255  } else if (get_num_off_lights() == 0) {
256  return O_add;
257 
258  } else {
259  return O_remove;
260  }
261 }
262 
263 ////////////////////////////////////////////////////////////////////
264 // Function: LightAttrib::get_num_lights
265 // Access: Published
266 // Description: Returns the number of lights listed in the attribute.
267 //
268 // This method is now deprecated. LightAttribs nowadays
269 // have a separate list of on_lights and off_lights, so
270 // this method doesn't make sense. Query the lists
271 // independently.
272 ////////////////////////////////////////////////////////////////////
273 int LightAttrib::
274 get_num_lights() const {
275  pgraph_cat.warning()
276  << "Using deprecated LightAttrib interface.\n";
277 
278  if (get_num_off_lights() == 0) {
279  return get_num_on_lights();
280  } else {
281  return get_num_off_lights();
282  }
283 }
284 
285 ////////////////////////////////////////////////////////////////////
286 // Function: LightAttrib::get_light
287 // Access: Published
288 // Description: Returns the nth light listed in the attribute.
289 //
290 // This method is now deprecated. LightAttribs nowadays
291 // have a separate list of on_lights and off_lights, so
292 // this method doesn't make sense. Query the lists
293 // independently.
294 ////////////////////////////////////////////////////////////////////
296 get_light(int n) const {
297  pgraph_cat.warning()
298  << "Using deprecated LightAttrib interface.\n";
299 
300  if (get_num_off_lights() == 0) {
301  return get_on_light(n).node()->as_light();
302  } else {
303  return get_off_light(n).node()->as_light();
304  }
305 }
306 
307 ////////////////////////////////////////////////////////////////////
308 // Function: LightAttrib::has_light
309 // Access: Published
310 // Description: Returns true if the indicated light is listed in the
311 // attrib, false otherwise.
312 //
313 // This method is now deprecated. LightAttribs nowadays
314 // have a separate list of on_lights and off_lights, so
315 // this method doesn't make sense. Query the lists
316 // independently.
317 ////////////////////////////////////////////////////////////////////
318 bool LightAttrib::
319 has_light(Light *light) const {
320  pgraph_cat.warning()
321  << "Using deprecated LightAttrib interface.\n";
322 
323  if (get_num_off_lights() == 0) {
324  return has_on_light(NodePath(light->as_node()));
325  } else {
326  return has_off_light(NodePath(light->as_node()));
327  }
328 }
329 
330 ////////////////////////////////////////////////////////////////////
331 // Function: LightAttrib::add_light
332 // Access: Published
333 // Description: Returns a new LightAttrib, just like this one, but
334 // with the indicated light added to the list of lights.
335 //
336 // This method is now deprecated. Use add_on_light() or
337 // add_off_light() instead.
338 ////////////////////////////////////////////////////////////////////
339 CPT(RenderAttrib) LightAttrib::
340 add_light(Light *light) const {
341  pgraph_cat.warning()
342  << "Using deprecated LightAttrib interface.\n";
343 
344  if (get_num_off_lights() == 0) {
345  return add_on_light(NodePath(light->as_node()));
346  } else {
347  return add_off_light(NodePath(light->as_node()));
348  }
349 }
350 
351 ////////////////////////////////////////////////////////////////////
352 // Function: LightAttrib::remove_light
353 // Access: Published
354 // Description: Returns a new LightAttrib, just like this one, but
355 // with the indicated light removed from the list of
356 // lights.
357 //
358 // This method is now deprecated. Use remove_on_light()
359 // or remove_off_light() instead.
360 ////////////////////////////////////////////////////////////////////
361 CPT(RenderAttrib) LightAttrib::
362 remove_light(Light *light) const {
363  pgraph_cat.warning()
364  << "Using deprecated LightAttrib interface.\n";
365 
366  if (get_num_off_lights() == 0) {
367  return remove_on_light(NodePath(light->as_node()));
368  } else {
369  return remove_off_light(NodePath(light->as_node()));
370  }
371 }
372 
373 ////////////////////////////////////////////////////////////////////
374 // Function: LightAttrib::make
375 // Access: Published, Static
376 // Description: Constructs a new LightAttrib object that does
377 // nothing.
378 ////////////////////////////////////////////////////////////////////
379 CPT(RenderAttrib) LightAttrib::
380 make() {
381  // We make it a special case and store a pointer to the empty attrib
382  // forever once we find it the first time, as an optimization.
383  if (_empty_attrib == (RenderAttrib *)NULL) {
384  _empty_attrib = return_new(new LightAttrib);
385  }
386 
387  return _empty_attrib;
388 }
389 
390 ////////////////////////////////////////////////////////////////////
391 // Function: LightAttrib::make_all_off
392 // Access: Published, Static
393 // Description: Constructs a new LightAttrib object that turns off
394 // all lights (and hence disables lighting).
395 ////////////////////////////////////////////////////////////////////
396 CPT(RenderAttrib) LightAttrib::
397 make_all_off() {
398  // We make it a special case and store a pointer to the off attrib
399  // forever once we find it the first time, as an optimization.
400  if (_all_off_attrib == (RenderAttrib *)NULL) {
401  LightAttrib *attrib = new LightAttrib;
402  attrib->_off_all_lights = true;
403  _all_off_attrib = return_new(attrib);
404  }
405 
406  return _all_off_attrib;
407 }
408 
409 ////////////////////////////////////////////////////////////////////
410 // Function: LightAttrib::add_on_light
411 // Access: Published
412 // Description: Returns a new LightAttrib, just like this one, but
413 // with the indicated light added to the list of lights
414 // turned on by this attrib.
415 ////////////////////////////////////////////////////////////////////
416 CPT(RenderAttrib) LightAttrib::
417 add_on_light(const NodePath &light) const {
418  nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
419  LightAttrib *attrib = new LightAttrib(*this);
420  attrib->_on_lights.insert(light);
421  attrib->_off_lights.erase(light);
422 
423  pair<Lights::iterator, bool> insert_result =
424  attrib->_on_lights.insert(Lights::value_type(light));
425  if (insert_result.second) {
426  // Also ensure it is removed from the off_lights list.
427  attrib->_off_lights.erase(light);
428  }
429 
430  return return_new(attrib);
431 }
432 
433 ////////////////////////////////////////////////////////////////////
434 // Function: LightAttrib::remove_on_light
435 // Access: Published
436 // Description: Returns a new LightAttrib, just like this one, but
437 // with the indicated light removed from the list of
438 // lights turned on by this attrib.
439 ////////////////////////////////////////////////////////////////////
440 CPT(RenderAttrib) LightAttrib::
441 remove_on_light(const NodePath &light) const {
442  nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
443  LightAttrib *attrib = new LightAttrib(*this);
444  attrib->_on_lights.erase(light);
445  return return_new(attrib);
446 }
447 
448 ////////////////////////////////////////////////////////////////////
449 // Function: LightAttrib::add_off_light
450 // Access: Published
451 // Description: Returns a new LightAttrib, just like this one, but
452 // with the indicated light added to the list of lights
453 // turned off by this attrib.
454 ////////////////////////////////////////////////////////////////////
455 CPT(RenderAttrib) LightAttrib::
456 add_off_light(const NodePath &light) const {
457  nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
458  LightAttrib *attrib = new LightAttrib(*this);
459  if (!_off_all_lights) {
460  attrib->_off_lights.insert(light);
461  }
462  attrib->_on_lights.erase(light);
463  return return_new(attrib);
464 }
465 
466 ////////////////////////////////////////////////////////////////////
467 // Function: LightAttrib::remove_off_light
468 // Access: Published
469 // Description: Returns a new LightAttrib, just like this one, but
470 // with the indicated light removed from the list of
471 // lights turned off by this attrib.
472 ////////////////////////////////////////////////////////////////////
473 CPT(RenderAttrib) LightAttrib::
474 remove_off_light(const NodePath &light) const {
475  nassertr(!light.is_empty() && light.node()->as_light() != (Light *)NULL, this);
476  LightAttrib *attrib = new LightAttrib(*this);
477  attrib->_off_lights.erase(light);
478  return return_new(attrib);
479 }
480 
481 ////////////////////////////////////////////////////////////////////
482 // Function: LightAttrib::filter_to_max
483 // Access: Public
484 // Description: Returns a new LightAttrib, very much like this one,
485 // but with the number of on_lights reduced to be no
486 // more than max_lights. The number of off_lights in
487 // the new LightAttrib is undefined.
488 //
489 // The number of AmbientLights is not included in the
490 // count. All AmbientLights in the original attrib are
491 // always included in the result, regardless of the
492 // value of max_lights.
493 ////////////////////////////////////////////////////////////////////
494 CPT(LightAttrib) LightAttrib::
495 filter_to_max(int max_lights) const {
496  if (max_lights < 0 || (int)_on_lights.size() <= max_lights) {
497  // Trivial case: this LightAttrib qualifies.
498  return this;
499  }
500 
501  // Since check_filtered() will clear the _filtered list if we are out
502  // of date, we should call it first.
503  check_filtered();
504 
505  Filtered::const_iterator fi;
506  fi = _filtered.find(max_lights);
507  if (fi != _filtered.end()) {
508  // Easy case: we have already computed this for this particular
509  // LightAttrib.
510  return (*fi).second;
511  }
512 
513  // Harder case: we have to compute it now. We must choose the n
514  // lights with the highest priority in our list of lights.
515  Lights priority_lights, ambient_lights;
516 
517  // Separate the list of lights into ambient lights and other lights.
518  Lights::const_iterator li;
519  for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
520  const NodePath &np = (*li);
521  nassertr(!np.is_empty() && np.node()->as_light() != (Light *)NULL, this);
522  if (np.node()->is_ambient_light()) {
523  ambient_lights.push_back(np);
524  } else {
525  priority_lights.push_back(np);
526  }
527  }
528 
529  // This sort function uses the STL function object defined above.
530  sort(priority_lights.begin(), priority_lights.end(),
532 
533  // Now lop off all of the lights after the first max_lights.
534  if ((int)priority_lights.size() > max_lights) {
535  priority_lights.erase(priority_lights.begin() + max_lights,
536  priority_lights.end());
537  }
538 
539  // Put the ambient lights back into the list.
540  for (li = ambient_lights.begin(); li != ambient_lights.end(); ++li) {
541  priority_lights.push_back(*li);
542  }
543 
544  // And re-sort the ov_set into its proper order.
545  priority_lights.sort();
546 
547  // Now create a new attrib reflecting these lights.
548  PT(LightAttrib) attrib = new LightAttrib;
549  attrib->_on_lights.swap(priority_lights);
550 
551  CPT(RenderAttrib) new_attrib = return_new(attrib);
552 
553  // Finally, record this newly-created attrib in the map for next
554  // time.
555  CPT(LightAttrib) light_attrib = (const LightAttrib *)new_attrib.p();
556  ((LightAttrib *)this)->_filtered[max_lights] = light_attrib;
557  return light_attrib;
558 }
559 
560 ////////////////////////////////////////////////////////////////////
561 // Function: LightAttrib::get_most_important_light
562 // Access: Public
563 // Description: Returns the most important light (that is, the light
564 // with the highest priority) in the LightAttrib,
565 // excluding any ambient lights. Returns an empty
566 // NodePath if no non-ambient lights are found.
567 ////////////////////////////////////////////////////////////////////
568 NodePath LightAttrib::
569 get_most_important_light() const {
570  NodePath best;
571 
572  CompareLightPriorities compare;
573 
574  Lights::const_iterator li;
575  for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
576  const NodePath &np = (*li);
577  nassertr(!np.is_empty() && np.node()->as_light() != (Light *)NULL, NodePath());
578  if (!np.node()->is_ambient_light()) {
579  if (best.is_empty() || compare(np, best)) {
580  best = np;
581  }
582  }
583  }
584 
585  return best;
586 }
587 
588 ////////////////////////////////////////////////////////////////////
589 // Function: LightAttrib::output
590 // Access: Public, Virtual
591 // Description:
592 ////////////////////////////////////////////////////////////////////
593 void LightAttrib::
594 output(ostream &out) const {
595  out << get_type() << ":";
596  if (_off_lights.empty()) {
597  if (_on_lights.empty()) {
598  if (_off_all_lights) {
599  out << "all off";
600  } else {
601  out << "identity";
602  }
603  } else {
604  if (_off_all_lights) {
605  out << "set";
606  } else {
607  out << "on";
608  }
609  }
610 
611  } else {
612  out << "off";
613  Lights::const_iterator fi;
614  for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
615  NodePath light = (*fi);
616  if (light.is_empty()) {
617  out << " " << light;
618  } else {
619  out << " " << light.get_name();
620  }
621  }
622 
623  if (!_on_lights.empty()) {
624  out << " on";
625  }
626  }
627 
628  Lights::const_iterator li;
629  for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
630  NodePath light = (*li);
631  if (light.is_empty()) {
632  out << " " << light;
633  } else {
634  out << " " << light.get_name();
635  }
636  }
637 }
638 
639 ////////////////////////////////////////////////////////////////////
640 // Function: LightAttrib::write
641 // Access: Public, Virtual
642 // Description:
643 ////////////////////////////////////////////////////////////////////
644 void LightAttrib::
645 write(ostream &out, int indent_level) const {
646  indent(out, indent_level) << get_type() << ":";
647  if (_off_lights.empty()) {
648  if (_on_lights.empty()) {
649  if (_off_all_lights) {
650  out << "all off\n";
651  } else {
652  out << "identity\n";
653  }
654  } else {
655  if (_off_all_lights) {
656  out << "set\n";
657  } else {
658  out << "on\n";
659  }
660  }
661 
662  } else {
663  out << "off\n";
664  Lights::const_iterator fi;
665  for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
666  NodePath light = (*fi);
667  indent(out, indent_level + 2) << light << "\n";
668  }
669 
670  if (!_on_lights.empty()) {
671  indent(out, indent_level) << "on\n";
672  }
673  }
674 
675  Lights::const_iterator li;
676  for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
677  NodePath light = (*li);
678  indent(out, indent_level + 2) << light << "\n";
679  }
680 }
681 
682 ////////////////////////////////////////////////////////////////////
683 // Function: LightAttrib::compare_to_impl
684 // Access: Protected, Virtual
685 // Description: Intended to be overridden by derived LightAttrib
686 // types to return a unique number indicating whether
687 // this LightAttrib is equivalent to the other one.
688 //
689 // This should return 0 if the two LightAttrib objects
690 // are equivalent, a number less than zero if this one
691 // should be sorted before the other one, and a number
692 // greater than zero otherwise.
693 //
694 // This will only be called with two LightAttrib
695 // objects whose get_type() functions return the same.
696 ////////////////////////////////////////////////////////////////////
697 int LightAttrib::
698 compare_to_impl(const RenderAttrib *other) const {
699  const LightAttrib *ta;
700  DCAST_INTO_R(ta, other, 0);
701 
702  if (_off_all_lights != ta->_off_all_lights) {
703  return (int)_off_all_lights - (int)ta->_off_all_lights;
704  }
705 
706  Lights::const_iterator li = _on_lights.begin();
707  Lights::const_iterator oli = ta->_on_lights.begin();
708 
709  while (li != _on_lights.end() && oli != ta->_on_lights.end()) {
710  NodePath light = (*li);
711  NodePath other_light = (*oli);
712 
713  int compare = light.compare_to(other_light);
714  if (compare != 0) {
715  return compare;
716  }
717 
718  ++li;
719  ++oli;
720  }
721 
722  if (li != _on_lights.end()) {
723  return 1;
724  }
725  if (oli != ta->_on_lights.end()) {
726  return -1;
727  }
728 
729  Lights::const_iterator fi = _off_lights.begin();
730  Lights::const_iterator ofi = ta->_off_lights.begin();
731 
732  while (fi != _off_lights.end() && ofi != ta->_off_lights.end()) {
733  NodePath light = (*fi);
734  NodePath other_light = (*ofi);
735 
736  int compare = light.compare_to(other_light);
737  if (compare != 0) {
738  return compare;
739  }
740 
741  ++fi;
742  ++ofi;
743  }
744 
745  if (fi != _off_lights.end()) {
746  return 1;
747  }
748  if (ofi != ta->_off_lights.end()) {
749  return -1;
750  }
751 
752  return 0;
753 }
754 
755 ////////////////////////////////////////////////////////////////////
756 // Function: LightAttrib::get_hash_impl
757 // Access: Protected, Virtual
758 // Description: Intended to be overridden by derived RenderAttrib
759 // types to return a unique hash for these particular
760 // properties. RenderAttribs that compare the same with
761 // compare_to_impl(), above, should return the same
762 // hash; RenderAttribs that compare differently should
763 // return a different hash.
764 ////////////////////////////////////////////////////////////////////
765 size_t LightAttrib::
766 get_hash_impl() const {
767  size_t hash = 0;
768 
769  Lights::const_iterator li;
770  for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
771  NodePath light = (*li);
772  hash = light.add_hash(hash);
773  }
774 
775  // This bool value goes here, between the two lists, to
776  // differentiate between the two.
777  hash = int_hash::add_hash(hash, (int)_off_all_lights);
778 
779  for (li = _off_lights.begin(); li != _off_lights.end(); ++li) {
780  NodePath light = (*li);
781  hash = light.add_hash(hash);
782  }
783 
784  return hash;
785 }
786 
787 ////////////////////////////////////////////////////////////////////
788 // Function: LightAttrib::compose_impl
789 // Access: Protected, Virtual
790 // Description: Intended to be overridden by derived RenderAttrib
791 // types to specify how two consecutive RenderAttrib
792 // objects of the same type interact.
793 //
794 // This should return the result of applying the other
795 // RenderAttrib to a node in the scene graph below this
796 // RenderAttrib, which was already applied. In most
797 // cases, the result is the same as the other
798 // RenderAttrib (that is, a subsequent RenderAttrib
799 // completely replaces the preceding one). On the other
800 // hand, some kinds of RenderAttrib (for instance,
801 // ColorTransformAttrib) might combine in meaningful
802 // ways.
803 ////////////////////////////////////////////////////////////////////
804 CPT(RenderAttrib) LightAttrib::
805 compose_impl(const RenderAttrib *other) const {
806  const LightAttrib *ta;
807  DCAST_INTO_R(ta, other, 0);
808 
809  if (ta->_off_all_lights) {
810  // If the other type turns off all lights, it doesn't matter what
811  // we are.
812  return ta;
813  }
814 
815  // This is a three-way merge between ai, bi, and ci, except that bi
816  // and ci should have no intersection and therefore needn't be
817  // compared to each other.
818  Lights::const_iterator ai = _on_lights.begin();
819  Lights::const_iterator bi = ta->_on_lights.begin();
820  Lights::const_iterator ci = ta->_off_lights.begin();
821 
822  // Create a new LightAttrib that will hold the result.
823  LightAttrib *new_attrib = new LightAttrib;
824  back_insert_iterator<Lights> result =
825  back_inserter(new_attrib->_on_lights);
826 
827  while (ai != _on_lights.end() &&
828  bi != ta->_on_lights.end() &&
829  ci != ta->_off_lights.end()) {
830  if ((*ai) < (*bi)) {
831  if ((*ai) < (*ci)) {
832  // Here is a light that we have in the original, which is not
833  // present in the secondary.
834  *result = *ai;
835  ++ai;
836  ++result;
837 
838  } else if ((*ci) < (*ai)) {
839  // Here is a light that is turned off in the secondary, but
840  // was not present in the original.
841  ++ci;
842 
843  } else { // (*ci) == (*ai)
844  // Here is a light that is turned off in the secondary, and
845  // was present in the original.
846  ++ai;
847  ++ci;
848  }
849 
850  } else if ((*bi) < (*ai)) {
851  // Here is a new light we have in the secondary, that was not
852  // present in the original.
853  *result = *bi;
854  ++bi;
855  ++result;
856 
857  } else { // (*bi) == (*ai)
858  // Here is a light we have in both.
859  *result = *bi;
860  ++ai;
861  ++bi;
862  ++result;
863  }
864  }
865 
866  while (ai != _on_lights.end() && bi != ta->_on_lights.end()) {
867  if ((*ai) < (*bi)) {
868  // Here is a light that we have in the original, which is not
869  // present in the secondary.
870  *result = *ai;
871  ++ai;
872  ++result;
873 
874  } else if ((*bi) < (*ai)) {
875  // Here is a new light we have in the secondary, that was not
876  // present in the original.
877  *result = *bi;
878  ++bi;
879  ++result;
880 
881  } else {
882  // Here is a light we have in both.
883  *result = *bi;
884  ++ai;
885  ++bi;
886  ++result;
887  }
888  }
889 
890  while (ai != _on_lights.end() && ci != ta->_off_lights.end()) {
891  if ((*ai) < (*ci)) {
892  // Here is a light that we have in the original, which is not
893  // present in the secondary.
894  *result = *ai;
895  ++ai;
896  ++result;
897 
898  } else if ((*ci) < (*ai)) {
899  // Here is a light that is turned off in the secondary, but
900  // was not present in the original.
901  ++ci;
902 
903  } else { // (*ci) == (*ai)
904  // Here is a light that is turned off in the secondary, and
905  // was present in the original.
906  ++ai;
907  ++ci;
908  }
909  }
910 
911  while (ai != _on_lights.end()) {
912  *result = *ai;
913  ++ai;
914  ++result;
915  }
916 
917  while (bi != ta->_on_lights.end()) {
918  *result = *bi;
919  ++bi;
920  ++result;
921  }
922 
923  return return_new(new_attrib);
924 }
925 
926 ////////////////////////////////////////////////////////////////////
927 // Function: LightAttrib::invert_compose_impl
928 // Access: Protected, Virtual
929 // Description: Intended to be overridden by derived RenderAttrib
930 // types to specify how two consecutive RenderAttrib
931 // objects of the same type interact.
932 //
933 // See invert_compose() and compose_impl().
934 ////////////////////////////////////////////////////////////////////
935 CPT(RenderAttrib) LightAttrib::
936 invert_compose_impl(const RenderAttrib *other) const {
937  // I think in this case the other attrib always wins. Maybe this
938  // needs a bit more thought. It's hard to imagine that it's even
939  // important to compute this properly.
940  return other;
941 }
942 
943 ////////////////////////////////////////////////////////////////////
944 // Function: LightAttrib::get_auto_shader_attrib_impl
945 // Access: Protected, Virtual
946 // Description:
947 ////////////////////////////////////////////////////////////////////
948 CPT(RenderAttrib) LightAttrib::
949 get_auto_shader_attrib_impl(const RenderState *state) const {
950  return this;
951 }
952 
953 ////////////////////////////////////////////////////////////////////
954 // Function: LightAttrib::sort_on_lights
955 // Access: Private
956 // Description: This is patterned after
957 // TextureAttrib::sort_on_stages(), but since lights
958 // don't actually require sorting, this only empties the
959 // _filtered map.
960 ////////////////////////////////////////////////////////////////////
961 void LightAttrib::
962 sort_on_lights() {
963  _sort_seq = Light::get_sort_seq();
964  _filtered.clear();
965 }
966 
967 ////////////////////////////////////////////////////////////////////
968 // Function: LightAttrib::register_with_read_factory
969 // Access: Public, Static
970 // Description: Tells the BamReader how to create objects of type
971 // LightAttrib.
972 ////////////////////////////////////////////////////////////////////
973 void LightAttrib::
975  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
976 }
977 
978 ////////////////////////////////////////////////////////////////////
979 // Function: LightAttrib::write_datagram
980 // Access: Public, Virtual
981 // Description: Writes the contents of this object to the datagram
982 // for shipping out to a Bam file.
983 ////////////////////////////////////////////////////////////////////
984 void LightAttrib::
986  RenderAttrib::write_datagram(manager, dg);
987 
988  dg.add_bool(_off_all_lights);
989 
990  // write the number of off_lights
991  dg.add_uint16(get_num_off_lights());
992  // write the off lights pointers if any
993  Lights::const_iterator fi;
994  for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
995  NodePath light = (*fi);
996 
997  // Since we can't write out a NodePath, we write out just the
998  // plain PandaNode. The user can use the AttribNodeRegistry on
999  // re-read if there is any ambiguity that needs to be resolved.
1000  manager->write_pointer(dg, light.node());
1001  }
1002 
1003  // write the number of on lights
1004  dg.add_uint16(get_num_on_lights());
1005  // write the on lights pointers if any
1006  Lights::const_iterator nti;
1007  for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) {
1008  NodePath light = (*nti);
1009  manager->write_pointer(dg, light.node());
1010  }
1011 }
1012 
1013 ////////////////////////////////////////////////////////////////////
1014 // Function: LightAttrib::complete_pointers
1015 // Access: Public, Virtual
1016 // Description: Receives an array of pointers, one for each time
1017 // manager->read_pointer() was called in fillin().
1018 // Returns the number of pointers processed.
1019 ////////////////////////////////////////////////////////////////////
1020 int LightAttrib::
1022  int pi = RenderAttrib::complete_pointers(p_list, manager);
1023 
1024  BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
1025  nassertr(aux != NULL, pi);
1026 
1027  int i;
1028  aux->_off_list.reserve(aux->_num_off_lights);
1029  for (i = 0; i < aux->_num_off_lights; ++i) {
1030  PandaNode *node;
1031  DCAST_INTO_R(node, p_list[pi++], pi);
1032  aux->_off_list.push_back(node);
1033  }
1034 
1035  aux->_on_list.reserve(aux->_num_on_lights);
1036  for (i = 0; i < aux->_num_on_lights; ++i) {
1037  PandaNode *node;
1038  DCAST_INTO_R(node, p_list[pi++], pi);
1039  aux->_on_list.push_back(node);
1040  }
1041 
1042  return pi;
1043 }
1044 
1045 ////////////////////////////////////////////////////////////////////
1046 // Function: LightAttrib::finalize
1047 // Access: Public, Virtual
1048 // Description: Called by the BamReader to perform any final actions
1049 // needed for setting up the object after all objects
1050 // have been read and all pointers have been completed.
1051 ////////////////////////////////////////////////////////////////////
1052 void LightAttrib::
1053 finalize(BamReader *manager) {
1054  // Now it's safe to convert our saved PandaNodes into NodePaths.
1055  BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
1056  nassertv(aux != NULL);
1057  nassertv(aux->_num_off_lights == (int)aux->_off_list.size());
1058  nassertv(aux->_num_on_lights == (int)aux->_on_list.size());
1059 
1060  AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
1061 
1062  _off_lights.reserve(aux->_off_list.size());
1063  NodeList::iterator ni;
1064  for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
1065  PandaNode *node = (*ni);
1066  int n = areg->find_node(node->get_type(), node->get_name());
1067  if (n != -1) {
1068  // If it's in the registry, add that NodePath.
1069  _off_lights.push_back(areg->get_node(n));
1070  } else {
1071  // Otherwise, add any arbitrary NodePath. Complain if it's
1072  // ambiguous.
1073  _off_lights.push_back(NodePath(node));
1074  }
1075  }
1076  _off_lights.sort();
1077 
1078  _on_lights.reserve(aux->_on_list.size());
1079  for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
1080  PandaNode *node = (*ni);
1081  int n = areg->find_node(node->get_type(), node->get_name());
1082  if (n != -1) {
1083  // If it's in the registry, add that NodePath.
1084  _on_lights.push_back(areg->get_node(n));
1085  } else {
1086  // Otherwise, add any arbitrary NodePath. Complain if it's
1087  // ambiguous.
1088  _on_lights.push_back(NodePath(node));
1089  }
1090  }
1091  _on_lights.sort();
1092 }
1093 
1094 ////////////////////////////////////////////////////////////////////
1095 // Function: LightAttrib::make_from_bam
1096 // Access: Protected, Static
1097 // Description: This function is called by the BamReader's factory
1098 // when a new object of type LightAttrib is encountered
1099 // in the Bam file. It should create the LightAttrib
1100 // and extract its information from the file.
1101 ////////////////////////////////////////////////////////////////////
1102 TypedWritable *LightAttrib::
1103 make_from_bam(const FactoryParams &params) {
1104  LightAttrib *attrib = new LightAttrib;
1105  DatagramIterator scan;
1106  BamReader *manager;
1107 
1108  parse_params(params, scan, manager);
1109  attrib->fillin(scan, manager);
1110 
1111  manager->register_finalize(attrib);
1112 
1113  return attrib;
1114 }
1115 
1116 ////////////////////////////////////////////////////////////////////
1117 // Function: LightAttrib::fillin
1118 // Access: Protected
1119 // Description: This internal function is called by make_from_bam to
1120 // read in all of the relevant data from the BamFile for
1121 // the new LightAttrib.
1122 ////////////////////////////////////////////////////////////////////
1123 void LightAttrib::
1124 fillin(DatagramIterator &scan, BamReader *manager) {
1125  RenderAttrib::fillin(scan, manager);
1126 
1127  _off_all_lights = scan.get_bool();
1128 
1129  BamAuxData *aux = new BamAuxData;
1130  manager->set_aux_data(this, "lights", aux);
1131 
1132  aux->_num_off_lights = scan.get_uint16();
1133  manager->read_pointers(scan, aux->_num_off_lights);
1134 
1135  aux->_num_on_lights = scan.get_uint16();
1136  manager->read_pointers(scan, aux->_num_on_lights);
1137 }
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes, or returns NULL if it is not.
Definition: pandaNode.cxx:2528
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
The abstract interface to all kinds of lights.
Definition: light.h:42
bool get_bool()
Extracts a boolean value.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
size_type_0 size() const
Returns the number of elements in the ordered vector.
This global object records NodePaths that are referenced by scene graph attribs, such as ClipPlaneAtt...
bool has_light(Light *light) const
Returns true if the indicated light is listed in the attrib, false otherwise.
int compare_to(const NodePath &other) const
Returns a number less than zero if this NodePath sorts before the other one, greater than zero if it ...
Definition: nodePath.I:2412
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
void swap(ordered_vector< Key, Compare, Vector > &other)
Exchanges the contents of this vector and the other vector, in constant time (e.g., with a pointer swap).
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:122
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:700
string get_name() const
Returns the name of the referenced node.
Definition: nodePath.I:2580
void sort()
Maps to sort_unique().
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:886
static UpdateSeq get_sort_seq()
Returns a global sequence number that is incremented any time any Light in the world changes sort or ...
Definition: light.I:132
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
Operation get_operation() const
Returns the basic operation type of the LightAttrib.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
virtual bool is_ambient_light() const
Returns true if this is an AmbientLight, false if it is not a light, or it is some other kind of ligh...
Definition: pandaNode.cxx:2539
Light * get_light(int n) const
Returns the nth light listed in the attribute.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
AuxData * get_aux_data(TypedWritable *obj, const string &name) const
Returns the pointer previously associated with the bam reader by a previous call to set_aux_data()...
Definition: bamReader.cxx:206
int get_num_lights() const
Returns the number of lights listed in the attribute.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
int get_priority() const
Returns the priority associated with this light.
Definition: light.I:118
A class to retrieve the individual data elements previously stored in a Datagram. ...
size_t add_hash(size_t hash) const
Adds the NodePath into the running hash.
Definition: nodePath.I:330
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
void set_aux_data(TypedWritable *obj, const string &name, AuxData *data)
Associates an arbitrary block of data with the indicated object (or NULL), and the indicated name...
Definition: bamReader.cxx:182
static void register_with_read_factory()
Tells the BamReader how to create objects of type LightAttrib.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:33
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:279
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin()...