Panda3D

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"
17 #include "graphicsStateGuardianBase.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
27 CPT(RenderAttrib) LightAttrib::_empty_attrib;
28 int LightAttrib::_attrib_slot;
29 CPT(RenderAttrib) LightAttrib::_all_off_attrib;
30 TypeHandle 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.
35 class CompareLightPriorities {
36 public:
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 */
54 LightAttrib::
55 LightAttrib(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 */
73 LightAttrib::
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 */
94 CPT(RenderAttrib) LightAttrib::
95 make(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 */
128 CPT(RenderAttrib) LightAttrib::
129 make(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 */
165 CPT(RenderAttrib) LightAttrib::
166 make(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 */
206 CPT(RenderAttrib) LightAttrib::
207 make(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 */
248 CPT(RenderAttrib) LightAttrib::
249 make_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 */
264 LightAttrib::Operation LightAttrib::
265 get_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 */
287 int LightAttrib::
288 get_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 */
306 Light *LightAttrib::
307 get_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 */
326 bool LightAttrib::
327 has_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 */
344 CPT(RenderAttrib) LightAttrib::
345 add_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 */
362 CPT(RenderAttrib) LightAttrib::
363 remove_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 */
377 CPT(RenderAttrib) LightAttrib::
378 make() {
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 */
392 CPT(RenderAttrib) LightAttrib::
393 make_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 */
409 CPT(RenderAttrib) LightAttrib::
410 add_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 */
433 CPT(RenderAttrib) LightAttrib::
434 remove_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 */
450 CPT(RenderAttrib) LightAttrib::
451 replace_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 }
473 return return_new(attrib);
474 }
475
476 /**
477 * Returns a new LightAttrib, just like this one, but with the indicated light
478 * added to the list of lights turned off by this attrib.
479 */
480 CPT(RenderAttrib) LightAttrib::
481 add_off_light(const NodePath &light) const {
482 nassertr(!light.is_empty(), this);
483 Light *lobj = light.node()->as_light();
484 nassertr(lobj != nullptr, this);
485
486 LightAttrib *attrib = new LightAttrib(*this);
487 if (!_off_all_lights) {
488 attrib->_off_lights.insert(light);
489 }
490 if (attrib->_on_lights.erase(light)) {
491 lobj->attrib_unref();
492 }
493 return return_new(attrib);
494 }
495
496 /**
497 * Returns a new LightAttrib, just like this one, but with the indicated light
498 * removed from the list of lights turned off by this attrib.
499 */
500 CPT(RenderAttrib) LightAttrib::
501 remove_off_light(const NodePath &light) const {
502 nassertr(!light.is_empty() && light.node()->as_light() != nullptr, this);
503 LightAttrib *attrib = new LightAttrib(*this);
504 attrib->_off_lights.erase(light);
505 return return_new(attrib);
506 }
507
508 /**
509 * Returns a new LightAttrib, just like this one, but with the indicated light
510 * replaced with the given other light.
511 */
512 CPT(RenderAttrib) LightAttrib::
513 replace_off_light(const NodePath &source, const NodePath &dest) const {
514 if (source == dest) {
515 return this;
516 }
517
518 nassertr(!source.is_empty(), this);
519 Light *slobj = source.node()->as_light();
520 nassertr(slobj != nullptr, this);
521
522 nassertr(!dest.is_empty(), this);
523 Light *dlobj = dest.node()->as_light();
524 nassertr(dlobj != nullptr, this);
525
526 LightAttrib *attrib = new LightAttrib(*this);
527
528 auto it = attrib->_off_lights.find(source);
529 if (it != attrib->_off_lights.end()) {
530 dlobj->attrib_ref();
531 slobj->attrib_unref();
532
533 *it = dest;
534 }
535 return return_new(attrib);
536 }
537
538 /**
539 * Returns the most important light (that is, the light with the highest
540 * priority) in the LightAttrib, excluding any ambient lights. Returns an
541 * empty NodePath if no non-ambient lights are found.
542 */
543 NodePath LightAttrib::
544 get_most_important_light() const {
545 check_sorted();
546
547 if (_num_non_ambient_lights > 0) {
548 return _sorted_on_lights[0];
549 } else {
550 return NodePath();
551 }
552 }
553
554 /**
555 * Returns the total contribution of all the ambient lights.
556 */
557 LColor LightAttrib::
558 get_ambient_contribution() const {
559 check_sorted();
560
561 LVecBase4 total(0);
562
563 Lights::const_iterator li;
564 li = _sorted_on_lights.begin() + _num_non_ambient_lights;
565 for (; li != _sorted_on_lights.end(); ++li) {
566 const NodePath &np = (*li);
567 Light *light = np.node()->as_light();
568 nassertd(light != nullptr && light->is_ambient_light()) continue;
569
570 total += light->get_color();
571 }
572
573 return total;
574 }
575
576 /**
577 *
578 */
579 void LightAttrib::
580 output(std::ostream &out) const {
581 out << get_type() << ":";
582 if (_off_lights.empty()) {
583 if (_on_lights.empty()) {
584 if (_off_all_lights) {
585 out << "all off";
586 } else {
587 out << "identity";
588 }
589 } else {
590 if (_off_all_lights) {
591 out << "set";
592 } else {
593 out << "on";
594 }
595 }
596
597 } else {
598 out << "off";
599 Lights::const_iterator fi;
600 for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
601 NodePath light = (*fi);
602 if (light.is_empty()) {
603 out << " " << light;
604 } else {
605 out << " " << light.get_name();
606 }
607 }
608
609 if (!_on_lights.empty()) {
610 out << " on";
611 }
612 }
613
614 Lights::const_iterator li;
615 for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
616 NodePath light = (*li);
617 if (light.is_empty()) {
618 out << " " << light;
619 } else {
620 out << " " << light.get_name();
621 }
622 }
623 }
624
625 /**
626 *
627 */
628 void LightAttrib::
629 write(std::ostream &out, int indent_level) const {
630 indent(out, indent_level) << get_type() << ":";
631 if (_off_lights.empty()) {
632 if (_on_lights.empty()) {
633 if (_off_all_lights) {
634 out << "all off\n";
635 } else {
636 out << "identity\n";
637 }
638 } else {
639 if (_off_all_lights) {
640 out << "set\n";
641 } else {
642 out << "on\n";
643 }
644 }
645
646 } else {
647 out << "off\n";
648 Lights::const_iterator fi;
649 for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
650 NodePath light = (*fi);
651 indent(out, indent_level + 2) << light << "\n";
652 }
653
654 if (!_on_lights.empty()) {
655 indent(out, indent_level) << "on\n";
656 }
657 }
658
659 Lights::const_iterator li;
660 for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
661 NodePath light = (*li);
662 indent(out, indent_level + 2) << light << "\n";
663 }
664 }
665
666 /**
667 * Intended to be overridden by derived LightAttrib types to return a unique
668 * number indicating whether this LightAttrib is equivalent to the other one.
669 *
670 * This should return 0 if the two LightAttrib objects are equivalent, a
671 * number less than zero if this one should be sorted before the other one,
672 * and a number greater than zero otherwise.
673 *
674 * This will only be called with two LightAttrib objects whose get_type()
675 * functions return the same.
676 */
677 int LightAttrib::
678 compare_to_impl(const RenderAttrib *other) const {
679 const LightAttrib *ta = (const LightAttrib *)other;
680
681 if (_off_all_lights != ta->_off_all_lights) {
682 return (int)_off_all_lights - (int)ta->_off_all_lights;
683 }
684
685 Lights::const_iterator li = _on_lights.begin();
686 Lights::const_iterator oli = ta->_on_lights.begin();
687
688 while (li != _on_lights.end() && oli != ta->_on_lights.end()) {
689 NodePath light = (*li);
690 NodePath other_light = (*oli);
691
692 int compare = light.compare_to(other_light);
693 if (compare != 0) {
694 return compare;
695 }
696
697 ++li;
698 ++oli;
699 }
700
701 if (li != _on_lights.end()) {
702 return 1;
703 }
704 if (oli != ta->_on_lights.end()) {
705 return -1;
706 }
707
708 Lights::const_iterator fi = _off_lights.begin();
709 Lights::const_iterator ofi = ta->_off_lights.begin();
710
711 while (fi != _off_lights.end() && ofi != ta->_off_lights.end()) {
712 NodePath light = (*fi);
713 NodePath other_light = (*ofi);
714
715 int compare = light.compare_to(other_light);
716 if (compare != 0) {
717 return compare;
718 }
719
720 ++fi;
721 ++ofi;
722 }
723
724 if (fi != _off_lights.end()) {
725 return 1;
726 }
727 if (ofi != ta->_off_lights.end()) {
728 return -1;
729 }
730
731 return 0;
732 }
733
734 /**
735 * Intended to be overridden by derived RenderAttrib types to return a unique
736 * hash for these particular properties. RenderAttribs that compare the same
737 * with compare_to_impl(), above, should return the same hash; RenderAttribs
738 * that compare differently should return a different hash.
739 */
740 size_t LightAttrib::
741 get_hash_impl() const {
742 size_t hash = 0;
743
744 Lights::const_iterator li;
745 for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
746 NodePath light = (*li);
747 hash = light.add_hash(hash);
748 }
749
750 // This bool value goes here, between the two lists, to differentiate
751 // between the two.
752 hash = int_hash::add_hash(hash, (int)_off_all_lights);
753
754 for (li = _off_lights.begin(); li != _off_lights.end(); ++li) {
755 NodePath light = (*li);
756 hash = light.add_hash(hash);
757 }
758
759 return hash;
760 }
761
762 /**
763 * Intended to be overridden by derived RenderAttrib types to specify how two
764 * consecutive RenderAttrib objects of the same type interact.
765 *
766 * This should return the result of applying the other RenderAttrib to a node
767 * in the scene graph below this RenderAttrib, which was already applied. In
768 * most cases, the result is the same as the other RenderAttrib (that is, a
769 * subsequent RenderAttrib completely replaces the preceding one). On the
770 * other hand, some kinds of RenderAttrib (for instance, ColorTransformAttrib)
771 * might combine in meaningful ways.
772 */
773 CPT(RenderAttrib) LightAttrib::
774 compose_impl(const RenderAttrib *other) const {
775 const LightAttrib *ta = (const LightAttrib *)other;
776
777 if (ta->_off_all_lights) {
778 // If the other type turns off all lights, it doesn't matter what we are.
779 return ta;
780 }
781
782 // This is a three-way merge between ai, bi, and ci, except that bi and ci
783 // should have no intersection and therefore needn't be compared to each
784 // other.
785 Lights::const_iterator ai = _on_lights.begin();
786 Lights::const_iterator bi = ta->_on_lights.begin();
787 Lights::const_iterator ci = ta->_off_lights.begin();
788
789 // Create a new LightAttrib that will hold the result.
790 LightAttrib *new_attrib = new LightAttrib;
791 std::back_insert_iterator<Lights> result =
792 std::back_inserter(new_attrib->_on_lights);
793
794 while (ai != _on_lights.end() &&
795 bi != ta->_on_lights.end() &&
796 ci != ta->_off_lights.end()) {
797 if ((*ai) < (*bi)) {
798 if ((*ai) < (*ci)) {
799 // Here is a light that we have in the original, which is not present
800 // in the secondary.
801 *result = *ai;
802 ++ai;
803 ++result;
804
805 } else if ((*ci) < (*ai)) {
806 // Here is a light that is turned off in the secondary, but was not
807 // present in the original.
808 ++ci;
809
810 } else { // (*ci) == (*ai)
811 // Here is a light that is turned off in the secondary, and was
812 // present in the original.
813 ++ai;
814 ++ci;
815 }
816
817 } else if ((*bi) < (*ai)) {
818 // Here is a new light we have in the secondary, that was not present in
819 // the original.
820 *result = *bi;
821 ++bi;
822 ++result;
823
824 } else { // (*bi) == (*ai)
825 // Here is a light we have in both.
826 *result = *bi;
827 ++ai;
828 ++bi;
829 ++result;
830 }
831 }
832
833 while (ai != _on_lights.end() && bi != ta->_on_lights.end()) {
834 if ((*ai) < (*bi)) {
835 // Here is a light that we have in the original, which is not present in
836 // the secondary.
837 *result = *ai;
838 ++ai;
839 ++result;
840
841 } else if ((*bi) < (*ai)) {
842 // Here is a new light we have in the secondary, that was not present in
843 // the original.
844 *result = *bi;
845 ++bi;
846 ++result;
847
848 } else {
849 // Here is a light we have in both.
850 *result = *bi;
851 ++ai;
852 ++bi;
853 ++result;
854 }
855 }
856
857 while (ai != _on_lights.end() && ci != ta->_off_lights.end()) {
858 if ((*ai) < (*ci)) {
859 // Here is a light that we have in the original, which is not present in
860 // the secondary.
861 *result = *ai;
862 ++ai;
863 ++result;
864
865 } else if ((*ci) < (*ai)) {
866 // Here is a light that is turned off in the secondary, but was not
867 // present in the original.
868 ++ci;
869
870 } else { // (*ci) == (*ai)
871 // Here is a light that is turned off in the secondary, and was present
872 // in the original.
873 ++ai;
874 ++ci;
875 }
876 }
877
878 while (ai != _on_lights.end()) {
879 *result = *ai;
880 ++ai;
881 ++result;
882 }
883
884 while (bi != ta->_on_lights.end()) {
885 *result = *bi;
886 ++bi;
887 ++result;
888 }
889
890 // Increase the attrib_ref of all the lights in this new attribute.
891 Lights::const_iterator it;
892 for (it = new_attrib->_on_lights.begin(); it != new_attrib->_on_lights.end(); ++it) {
893 Light *lobj = (*it).node()->as_light();
894 nassertd(lobj != nullptr) continue;
895 lobj->attrib_ref();
896 }
897
898 // This is needed since _sorted_on_lights is not yet populated.
899 new_attrib->_sort_seq = UpdateSeq::old();
900
901 return return_new(new_attrib);
902 }
903
904 /**
905 * Intended to be overridden by derived RenderAttrib types to specify how two
906 * consecutive RenderAttrib objects of the same type interact.
907 *
908 * See invert_compose() and compose_impl().
909 */
910 CPT(RenderAttrib) LightAttrib::
911 invert_compose_impl(const RenderAttrib *other) const {
912 // I think in this case the other attrib always wins. Maybe this needs a
913 // bit more thought. It's hard to imagine that it's even important to
914 // compute this properly.
915 return other;
916 }
917
918 /**
919 * Makes sure the lights are sorted in order of priority. Also counts the
920 * number of non-ambient lights.
921 */
922 void LightAttrib::
923 sort_on_lights() {
924 _sort_seq = Light::get_sort_seq();
925
926 // Separate the list of lights into ambient lights and other lights.
927 _sorted_on_lights.clear();
928 OrderedLights ambient_lights;
929
930 Lights::const_iterator li;
931 for (li = _on_lights.begin(); li != _on_lights.end(); ++li) {
932 const NodePath &np = (*li);
933 nassertd(!np.is_empty() && np.node()->as_light() != nullptr) continue;
934
935 if (!np.node()->is_ambient_light()) {
936 _sorted_on_lights.push_back(np);
937 } else {
938 ambient_lights.push_back(np);
939 }
940 }
941
942 // Remember how many lights were non-ambient lights, which makes it easier
943 // to traverse through the list of non-ambient lights.
944 _num_non_ambient_lights = _sorted_on_lights.size();
945
946 // This sort function uses the STL function object defined above.
947 sort(_sorted_on_lights.begin(), _sorted_on_lights.end(),
948 CompareLightPriorities());
949
950 // Now insert the ambient lights back at the end. We don't really care
951 // about their relative priorities, because their contribution will simply
952 // be summed up in the end anyway.
953 _sorted_on_lights.insert(_sorted_on_lights.end(),
954 ambient_lights.begin(), ambient_lights.end());
955 }
956
957 /**
958 * Tells the BamReader how to create objects of type LightAttrib.
959 */
960 void LightAttrib::
961 register_with_read_factory() {
962 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
963 }
964
965 /**
966 * Writes the contents of this object to the datagram for shipping out to a
967 * Bam file.
968 */
969 void LightAttrib::
970 write_datagram(BamWriter *manager, Datagram &dg) {
971 RenderAttrib::write_datagram(manager, dg);
972
973 dg.add_bool(_off_all_lights);
974
975 // write the number of off_lights
976 dg.add_uint16(get_num_off_lights());
977
978 // write the off lights pointers if any
979 Lights::const_iterator fi;
980 if (manager->get_file_minor_ver() < 40) {
981 for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
982 manager->write_pointer(dg, fi->node());
983 }
984 } else {
985 for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) {
986 (*fi).write_datagram(manager, dg);
987 }
988 }
989
990 // write the number of on lights
991 dg.add_uint16(get_num_on_lights());
992 // write the on lights pointers if any
993 Lights::const_iterator nti;
994 if (manager->get_file_minor_ver() < 40) {
995 for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) {
996 manager->write_pointer(dg, nti->node());
997 }
998 } else {
999 for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) {
1000 (*nti).write_datagram(manager, dg);
1001 }
1002 }
1003 }
1004
1005 /**
1006 * Receives an array of pointers, one for each time manager->read_pointer()
1007 * was called in fillin(). Returns the number of pointers processed.
1008 */
1009 int LightAttrib::
1010 complete_pointers(TypedWritable **p_list, BamReader *manager) {
1011 int pi = RenderAttrib::complete_pointers(p_list, manager);
1012
1013 if (manager->get_file_minor_ver() >= 40) {
1014 for (size_t i = 0; i < _off_lights.size(); ++i) {
1015 pi += _off_lights[i].complete_pointers(p_list + pi, manager);
1016 }
1017
1018 for (size_t i = 0; i < _on_lights.size(); ++i) {
1019 pi += _on_lights[i].complete_pointers(p_list + pi, manager);
1020 }
1021
1022 } else {
1023 BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
1024 nassertr(aux != nullptr, pi);
1025
1026 int i;
1027 aux->_off_list.reserve(aux->_num_off_lights);
1028 for (i = 0; i < aux->_num_off_lights; ++i) {
1029 PandaNode *node;
1030 DCAST_INTO_R(node, p_list[pi++], pi);
1031 aux->_off_list.push_back(node);
1032 }
1033
1034 aux->_on_list.reserve(aux->_num_on_lights);
1035 for (i = 0; i < aux->_num_on_lights; ++i) {
1036 PandaNode *node;
1037 DCAST_INTO_R(node, p_list[pi++], pi);
1038 aux->_on_list.push_back(node);
1039 }
1040 }
1041
1042 return pi;
1043 }
1044
1045 /**
1046 * Called by the BamReader to perform any final actions needed for setting up
1047 * the object after all objects have been read and all pointers have been
1048 * completed.
1049 */
1050 void LightAttrib::
1051 finalize(BamReader *manager) {
1052 if (manager->get_file_minor_ver() >= 40) {
1053 AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
1054
1055 // Check if any of the nodes we loaded are mentioned in the
1056 // AttribNodeRegistry. If so, replace them.
1057 for (size_t i = 0; i < _off_lights.size(); ++i) {
1058 int n = areg->find_node(_off_lights[i]);
1059 if (n != -1) {
1060 // If it's in the registry, replace it.
1061 _off_lights[i] = areg->get_node(n);
1062 }
1063 }
1064
1065 for (size_t i = 0; i < _on_lights.size(); ++i) {
1066 int n = areg->find_node(_on_lights[i]);
1067 if (n != -1) {
1068 // If it's in the registry, replace it.
1069 _on_lights[i] = areg->get_node(n);
1070 }
1071
1072 Light *lobj = _on_lights[i].node()->as_light();
1073 nassertd(lobj != nullptr) continue;
1074 lobj->attrib_ref();
1075 }
1076
1077 } else {
1078 // Now it's safe to convert our saved PandaNodes into NodePaths.
1079 BamAuxData *aux = (BamAuxData *)manager->get_aux_data(this, "lights");
1080 nassertv(aux != nullptr);
1081 nassertv(aux->_num_off_lights == (int)aux->_off_list.size());
1082 nassertv(aux->_num_on_lights == (int)aux->_on_list.size());
1083
1084 AttribNodeRegistry *areg = AttribNodeRegistry::get_global_ptr();
1085
1086 _off_lights.reserve(aux->_off_list.size());
1087 NodeList::iterator ni;
1088 for (ni = aux->_off_list.begin(); ni != aux->_off_list.end(); ++ni) {
1089 PandaNode *node = (*ni);
1090 int n = areg->find_node(node->get_type(), node->get_name());
1091 if (n != -1) {
1092 // If it's in the registry, add that NodePath.
1093 _off_lights.push_back(areg->get_node(n));
1094 } else {
1095 // Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
1096 _off_lights.push_back(NodePath(node));
1097 }
1098 }
1099
1100 _on_lights.reserve(aux->_on_list.size());
1101 for (ni = aux->_on_list.begin(); ni != aux->_on_list.end(); ++ni) {
1102 PandaNode *node = (*ni);
1103 int n = areg->find_node(node->get_type(), node->get_name());
1104 if (n != -1) {
1105 // If it's in the registry, add that NodePath.
1106 _on_lights.push_back(areg->get_node(n));
1107 node = _on_lights.back().node();
1108 } else {
1109 // Otherwise, add any arbitrary NodePath. Complain if it's ambiguous.
1110 _on_lights.push_back(NodePath(node));
1111 }
1112
1113 Light *lobj = node->as_light();
1114 nassertd(lobj != nullptr) continue;
1115 lobj->attrib_ref();
1116 }
1117 }
1118
1119 // Now that the NodePaths have been filled in, we can sort the list.
1120 _off_lights.sort();
1121 _on_lights.sort();
1122 }
1123
1124 /**
1125 * This function is called by the BamReader's factory when a new object of
1126 * type LightAttrib is encountered in the Bam file. It should create the
1127 * LightAttrib and extract its information from the file.
1128 */
1129 TypedWritable *LightAttrib::
1130 make_from_bam(const FactoryParams &params) {
1131 LightAttrib *attrib = new LightAttrib;
1132 DatagramIterator scan;
1133 BamReader *manager;
1134
1135 parse_params(params, scan, manager);
1136 attrib->fillin(scan, manager);
1137
1138 manager->register_finalize(attrib);
1139
1140 return attrib;
1141 }
1142
1143 /**
1144 * This internal function is called by make_from_bam to read in all of the
1145 * relevant data from the BamFile for the new LightAttrib.
1146 */
1147 void LightAttrib::
1148 fillin(DatagramIterator &scan, BamReader *manager) {
1149 RenderAttrib::fillin(scan, manager);
1150
1151 _off_all_lights = scan.get_bool();
1152
1153 if (manager->get_file_minor_ver() >= 40) {
1154 _off_lights.resize(scan.get_uint16());
1155 for (size_t i = 0; i < _off_lights.size(); ++i) {
1156 _off_lights[i].fillin(scan, manager);
1157 }
1158
1159 _on_lights.resize(scan.get_uint16());
1160 for (size_t i = 0; i < _on_lights.size(); ++i) {
1161 _on_lights[i].fillin(scan, manager);
1162 }
1163 } else {
1164 BamAuxData *aux = new BamAuxData;
1165 manager->set_aux_data(this, "lights", aux);
1166
1167 aux->_num_off_lights = scan.get_uint16();
1168 manager->read_pointers(scan, aux->_num_off_lights);
1169
1170 aux->_num_on_lights = scan.get_uint16();
1171 manager->read_pointers(scan, aux->_num_on_lights);
1172 }
1173
1174 _sorted_on_lights.clear();
1175 _sort_seq = UpdateSeq::old();
1176 }
attribNodeRegistry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
parse_params
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AttribNodeRegistry
This global object records NodePaths that are referenced by scene graph attribs, such as ClipPlaneAtt...
Definition: attribNodeRegistry.h:33
AttribNodeRegistry::find_node
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 ...
Definition: attribNodeRegistry.cxx:136
AttribNodeRegistry::get_node
get_node
Returns the nth NodePath recorded in the registry.
Definition: attribNodeRegistry.h:44
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamReader::register_finalize
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:808
BamReader::read_pointers
void read_pointers(DatagramIterator &scan, int count)
A convenience function to read a contiguous list of pointers.
Definition: bamReader.cxx:653
BamReader::set_aux_data
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.
Definition: bamReader.cxx:167
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
BamReader::get_aux_data
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(),...
Definition: bamReader.cxx:189
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
BamWriter::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being written.
Definition: bamWriter.I:59
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition: datagramIterator.I:145
DatagramIterator::get_bool
bool get_bool()
Extracts a boolean value.
Definition: datagramIterator.I:48
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_bool
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
Factory::register_factory
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
LightAttrib::BamAuxData
Definition: lightAttrib.h:141
LightAttrib
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30
LightAttrib::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: lightAttrib.cxx:970
LightAttrib::get_off_light
get_off_light
Returns the nth light turned off by the attribute, sorted in arbitrary (pointer) order.
Definition: lightAttrib.h:80
LightAttrib::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type LightAttrib.
Definition: lightAttrib.cxx:961
LightAttrib::get_num_lights
int get_num_lights() const
Returns the number of lights listed in the attribute.
Definition: lightAttrib.cxx:288
LightAttrib::has_all_off
bool has_all_off() const
Returns true if this attrib turns off all lights (although it may also turn some on).
Definition: lightAttrib.I:100
LightAttrib::get_num_off_lights
get_num_off_lights
Returns the number of lights that are turned off by the attribute.
Definition: lightAttrib.h:80
LightAttrib::get_num_on_lights
get_num_on_lights
Returns the number of lights that are turned on by the attribute.
Definition: lightAttrib.h:74
LightAttrib::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: lightAttrib.cxx:1010
LightAttrib::has_off_light
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
LightAttrib::has_light
bool has_light(Light *light) const
Returns true if the indicated light is listed in the attrib, false otherwise.
Definition: lightAttrib.cxx:327
LightAttrib::finalize
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: lightAttrib.cxx:1051
LightAttrib::has_on_light
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
LightAttrib::get_operation
Operation get_operation() const
Returns the basic operation type of the LightAttrib.
Definition: lightAttrib.cxx:265
LightAttrib::get_light
Light * get_light(int n) const
Returns the nth light listed in the attribute.
Definition: lightAttrib.cxx:307
LightAttrib::get_on_light
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
Definition: lightAttrib.h:74
Light
The abstract interface to all kinds of lights.
Definition: light.h:38
Light::attrib_ref
virtual void attrib_ref()
This is called when the light is added to a LightAttrib.
Definition: light.cxx:166
Light::is_ambient_light
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
Light::get_sort_seq
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
Light::attrib_unref
virtual void attrib_unref()
This is called when the light is removed from a LightAttrib.
Definition: light.cxx:173
Light::get_priority
get_priority
Returns the priority associated with this light.
Definition: light.h:64
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::add_hash
size_t add_hash(size_t hash) const
Adds the NodePath into the running hash.
Definition: nodePath.I:264
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
NodePath::compare_to
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
NodePath::get_name
get_name
Returns the name of the referenced node.
Definition: nodePath.h:945
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::as_light
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes,...
Definition: pandaNode.cxx:2095
RenderAttrib
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
RenderAttrib::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: renderAttrib.cxx:527
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
TypedWritable::complete_pointers
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().
Definition: typedWritable.cxx:81
UpdateSeq
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
integer_hash::add_hash
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
Definition: stl_compares.I:101
ordered_vector::back
reference back()
Returns a reference to the first element.
Definition: ordered_vector.I:197
ordered_vector::reserve
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...
Definition: ordered_vector.I:572
ordered_vector::begin
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
Definition: ordered_vector.I:41
ordered_vector::push_back
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
Definition: ordered_vector.I:614
ordered_vector::size
size_type_0 size() const
Returns the number of elements in the ordered vector.
Definition: ordered_vector.I:221
ordered_vector::empty
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
Definition: ordered_vector.I:240
ordered_vector::end
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
Definition: ordered_vector.I:50
ov_set::sort
void sort()
Maps to sort_unique().
Definition: ordered_vector.I:731
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
graphicsStateGuardianBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT
CPT(RenderAttrib) LightAttrib
Constructs a new LightAttrib object that turns on (or off, according to op) the indicated light(s).
Definition: lightAttrib.cxx:94
lightAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
nodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandaNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.