Panda3D
 All Classes Functions Variables Enumerations
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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
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
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
NodePath get_off_light(int n) const
Returns the nth light turned off by the attribute, sorted in arbitrary (pointer) order.
Definition: lightAttrib.I:94
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
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
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
This global object records NodePaths that are referenced by scene graph attribs, such as ClipPlaneAtt...
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.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
int get_priority() const
Returns the priority associated with this light.
Definition: light.I:118
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.
void reserve(size_type_0 n)
Informs the vector of a planned change in size; ensures that the capacity of the vector is greater th...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
bool has_on_light(const NodePath &light) const
Returns true if the indicated light is turned on by the attrib, false otherwise.
Definition: lightAttrib.I:72
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:122
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:200
Light * get_light(int n) const
Returns the nth light listed in the attribute.
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:118
bool has_off_light(const NodePath &light) const
Returns true if the indicated light is turned off by the attrib, false otherwise. ...
Definition: lightAttrib.I:106
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
string get_name() const
Returns the name of the referenced node.
Definition: nodePath.I:2580
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager-&gt;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...
int get_num_lights() const
Returns the number of lights listed in the attribute.
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
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:694
bool has_light(Light *light) const
Returns true if the indicated light is listed in the attrib, false otherwise.
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:880
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
int get_num_on_lights() const
Returns the number of lights that are turned on by the attribute.
Definition: lightAttrib.I:49
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
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
Operation get_operation() const
Returns the basic operation type of the LightAttrib.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
bool has_all_off() const
Returns true if this attrib turns off all lights (although it may also turn some on).
Definition: lightAttrib.I:118
size_t add_hash(size_t hash) const
Adds the NodePath into the running hash.
Definition: nodePath.I:330
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
NodePath get_on_light(int n) const
Returns the nth light turned on by the attribute, sorted in render order.
Definition: lightAttrib.I:60
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:176
int get_num_off_lights() const
Returns the number of lights that are turned off by the attribute.
Definition: lightAttrib.I:83
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 &quot;on&quot; 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-&gt;read_pointer() was called in fillin()...