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