From a60eb87e196f699650aa1c4693cce575d6c00611 Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 29 Jul 2004 23:35:06 +0000 Subject: [PATCH] add NodePath::set_light() interfaces --- panda/src/display/graphicsStateGuardian.cxx | 9 +- panda/src/pgraph/lightAttrib.I | 125 +-- panda/src/pgraph/lightAttrib.cxx | 822 ++++++++++++++------ panda/src/pgraph/lightAttrib.h | 49 +- panda/src/pgraph/nodePath.cxx | 291 +++++++ panda/src/pgraph/nodePath.h | 19 + panda/src/pgraph/renderState.cxx | 36 +- panda/src/pgraph/renderState.h | 1 + 8 files changed, 1031 insertions(+), 321 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index c7ab568b19..f48137b6d5 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -676,12 +676,9 @@ issue_light(const LightAttrib *attrib) { bool any_bound = false; int num_enabled = 0; - int num_lights = attrib->get_num_lights(); - if (attrib->get_operation() == LightAttrib::O_remove) { - num_lights = 0; - } - for (int li = 0; li < num_lights; li++) { - Light *light = attrib->get_light(li); + int num_on_lights = attrib->get_num_on_lights(); + for (int li = 0; li < num_on_lights; li++) { + Light *light = attrib->get_on_light(li); nassertv(light != (Light *)NULL); num_enabled++; diff --git a/panda/src/pgraph/lightAttrib.I b/panda/src/pgraph/lightAttrib.I index 4bed42f95d..53f99fc50c 100644 --- a/panda/src/pgraph/lightAttrib.I +++ b/panda/src/pgraph/lightAttrib.I @@ -25,75 +25,101 @@ //////////////////////////////////////////////////////////////////// INLINE LightAttrib:: LightAttrib() { - _operation = O_set; + _off_all_lights = false; } //////////////////////////////////////////////////////////////////// -// Function: LightAttrib::get_operation -// Access: Published -// Description: Returns the basic operation type of the LightAttrib. -// If this is O_set, the lights listed here completely -// replace any lights that were already on. If this is -// O_add, the lights here are added to the set of of -// lights that were already on, and if O_remove, the -// lights here are removed from the set of lights that -// were on. +// Function: LightAttrib::Copy Constructor +// Access: Private +// Description: Use LightAttrib::make() to construct a new +// LightAttrib object. The copy constructor is only +// defined to facilitate methods like add_on_light(). //////////////////////////////////////////////////////////////////// -INLINE LightAttrib::Operation LightAttrib:: -get_operation() const { - return _operation; +INLINE LightAttrib:: +LightAttrib(const LightAttrib ©) : + _on_lights(copy._on_lights), + _off_lights(copy._off_lights), + _off_all_lights(copy._off_all_lights) +{ } //////////////////////////////////////////////////////////////////// -// Function: LightAttrib::get_num_lights +// Function: LightAttrib::get_num_on_lights // Access: Published -// Description: Returns the number of lights listed in the attribute. +// Description: Returns the number of lights that are turned on by +// the attribute. //////////////////////////////////////////////////////////////////// INLINE int LightAttrib:: -get_num_lights() const { - return _lights.size(); +get_num_on_lights() const { + return _on_lights.size(); } //////////////////////////////////////////////////////////////////// -// Function: LightAttrib::get_light +// Function: LightAttrib::get_on_light // Access: Published -// Description: Returns the nth lights listed in the attribute. +// Description: Returns the nth light turned on by the attribute, +// sorted in render order. //////////////////////////////////////////////////////////////////// INLINE Light *LightAttrib:: -get_light(int n) const { - nassertr(n >= 0 && n < (int)_lights.size(), (Light *)NULL); - return _lights[n]; +get_on_light(int n) const { + nassertr(n >= 0 && n < (int)_on_lights.size(), (Light *)NULL); + return _on_lights[n]; } //////////////////////////////////////////////////////////////////// -// Function: LightAttrib::add_light +// Function: LightAttrib::has_on_light // Access: Published -// Description: Returns a new LightAttrib, just like this one, but -// with the indicated light added to the list of lights. +// Description: Returns true if the indicated light is turned on by +// the attrib, false otherwise. //////////////////////////////////////////////////////////////////// -INLINE CPT(RenderAttrib) LightAttrib:: -add_light(Light *light) const { - if (_operation == O_remove) { - return compose(make(O_remove, light)); - } else { - return compose(make(O_add, light)); - } +INLINE bool LightAttrib:: +has_on_light(Light *light) const { + return _on_lights.find(light) != _on_lights.end(); } //////////////////////////////////////////////////////////////////// -// Function: LightAttrib::remove_light +// Function: LightAttrib::get_num_off_lights // Access: Published -// Description: Returns a new LightAttrib, just like this one, but -// with the indicated light removed from the list of -// lights. +// Description: Returns the number of lights that are turned off by +// the attribute. //////////////////////////////////////////////////////////////////// -INLINE CPT(RenderAttrib) LightAttrib:: -remove_light(Light *light) const { - if (_operation == O_remove) { - return compose(make(O_add, light)); - } else { - return compose(make(O_remove, light)); - } +INLINE int LightAttrib:: +get_num_off_lights() const { + return _off_lights.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_off_light +// Access: Published +// Description: Returns the nth light turned off by the attribute, +// sorted in arbitrary (pointer) order. +//////////////////////////////////////////////////////////////////// +INLINE Light *LightAttrib:: +get_off_light(int n) const { + nassertr(n >= 0 && n < (int)_off_lights.size(), (Light *)NULL); + return _off_lights[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::has_off_light +// Access: Published +// Description: Returns true if the indicated light is turned off by +// the attrib, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool LightAttrib:: +has_off_light(Light *light) const { + return _off_all_lights || _off_lights.find(light) != _off_lights.end(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::has_all_off +// Access: Published +// Description: Returns true if this attrib turns off all lights +// (although it may also turn some on). +//////////////////////////////////////////////////////////////////// +INLINE bool LightAttrib:: +has_all_off() const { + return _off_all_lights; } //////////////////////////////////////////////////////////////////// @@ -104,16 +130,5 @@ remove_light(Light *light) const { //////////////////////////////////////////////////////////////////// INLINE bool LightAttrib:: is_identity() const { - return _operation != O_set && _lights.empty(); -} - -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::is_all_off -// Access: Published -// Description: Returns true if this attrib turns off all lights and -// turns none on. -//////////////////////////////////////////////////////////////////// -INLINE bool LightAttrib:: -is_all_off() const { - return _operation == O_set && _lights.empty(); + return _on_lights.empty() && _off_lights.empty() && !_off_all_lights; } diff --git a/panda/src/pgraph/lightAttrib.cxx b/panda/src/pgraph/lightAttrib.cxx index 77f89877c2..195a70330d 100644 --- a/panda/src/pgraph/lightAttrib.cxx +++ b/panda/src/pgraph/lightAttrib.cxx @@ -24,8 +24,307 @@ #include "datagram.h" #include "datagramIterator.h" +CPT(RenderAttrib) LightAttrib::_empty_attrib; +CPT(RenderAttrib) LightAttrib::_all_off_attrib; TypeHandle LightAttrib::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicated light(s). +// +// This method is now deprecated. Use add_on_light() or +// add_off_light() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light) { + CPT(RenderAttrib) attrib; + + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light); + return attrib; + } + + nassertr(false, make()); + return make(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +// +// This method is now deprecated. Use add_on_light() or +// add_off_light() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light1, Light *light2) { + CPT(RenderAttrib) attrib; + + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light2); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light2); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light2); + return attrib; + } + + nassertr(false, make()); + return make(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +// +// This method is now deprecated. Use add_on_light() or +// add_off_light() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light1, Light *light2, + Light *light3) { + CPT(RenderAttrib) attrib; + + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light2); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light3); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light2); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light3); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light2); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light3); + return attrib; + } + + nassertr(false, make()); + return make(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that turns on (or +// off, according to op) the indicate light(s). +// +// This method is now deprecated. Use add_on_light() or +// add_off_light() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make(LightAttrib::Operation op, Light *light1, Light *light2, + Light *light3, Light *light4) { + CPT(RenderAttrib) attrib; + + switch (op) { + case O_set: + attrib = make_all_off(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light2); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light3); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light4); + return attrib; + + case O_add: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light2); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light3); + attrib = DCAST(LightAttrib, attrib)->add_on_light(light4); + return attrib; + + case O_remove: + attrib = make(); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light1); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light2); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light3); + attrib = DCAST(LightAttrib, attrib)->add_off_light(light4); + return attrib; + } + + nassertr(false, make()); + return make(); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_operation +// Access: Published +// Description: Returns the basic operation type of the LightAttrib. +// If this is O_set, the lights listed here completely +// replace any lights that were already on. If this is +// O_add, the lights here are added to the set of of +// lights that were already on, and if O_remove, the +// lights here are removed from the set of lights that +// were on. +// +// This method is now deprecated. LightAttribs nowadays +// have a separate list of on_lights and off_lights, so +// this method doesn't make sense. Query the lists +// independently. +//////////////////////////////////////////////////////////////////// +LightAttrib::Operation LightAttrib:: +get_operation() const { + if (has_all_off()) { + return O_set; + + } else if (get_num_on_lights() != 0) { + return O_add; + + } else { + return O_remove; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_num_lights +// Access: Published +// Description: Returns the number of lights listed in the attribute. +// +// This method is now deprecated. LightAttribs nowadays +// have a separate list of on_lights and off_lights, so +// this method doesn't make sense. Query the lists +// independently. +//////////////////////////////////////////////////////////////////// +int LightAttrib:: +get_num_lights() const { + if (get_num_on_lights() != 0) { + return get_num_on_lights(); + } else { + return get_num_off_lights(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::get_light +// Access: Published +// Description: Returns the nth lights listed in the attribute. +// +// This method is now deprecated. LightAttribs nowadays +// have a separate list of on_lights and off_lights, so +// this method doesn't make sense. Query the lists +// independently. +//////////////////////////////////////////////////////////////////// +Light *LightAttrib:: +get_light(int n) const { + if (get_num_on_lights() != 0) { + return get_on_light(n); + } else { + return get_off_light(n); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::has_light +// Access: Published +// Description: Returns true if the indicated light is listed in the +// attrib, false otherwise. +// +// This method is now deprecated. LightAttribs nowadays +// have a separate list of on_lights and off_lights, so +// this method doesn't make sense. Query the lists +// independently. +//////////////////////////////////////////////////////////////////// +bool LightAttrib:: +has_light(Light *light) const { + if (get_num_on_lights() != 0) { + return has_on_light(light); + } else { + return has_off_light(light); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::add_light +// Access: Published +// Description: Returns a new LightAttrib, just like this one, but +// with the indicated light added to the list of lights. +// +// This method is now deprecated. Use add_on_light() or +// add_off_light() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +add_light(Light *light) const { + if (get_num_on_lights() != 0) { + return add_on_light(light); + } else { + return add_off_light(light); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::remove_light +// Access: Published +// Description: Returns a new LightAttrib, just like this one, but +// with the indicated light removed from the list of +// lights. +// +// This method is now deprecated. Use remove_on_light() +// or remove_off_light() instead. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +remove_light(Light *light) const { + if (get_num_on_lights() != 0) { + return remove_on_light(light); + } else { + return remove_off_light(light); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::make +// Access: Published, Static +// Description: Constructs a new LightAttrib object that does +// nothing. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +make() { + // We make it a special case and store a pointer to the empty attrib + // forever once we find it the first time, as an optimization. + if (_empty_attrib == (RenderAttrib *)NULL) { + _empty_attrib = return_new(new LightAttrib); + } + + return _empty_attrib; +} + //////////////////////////////////////////////////////////////////// // Function: LightAttrib::make_all_off // Access: Published, Static @@ -34,90 +333,83 @@ TypeHandle LightAttrib::_type_handle; //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) LightAttrib:: make_all_off() { - LightAttrib *attrib = new LightAttrib; - attrib->_operation = O_set; - return return_new(attrib); + // We make it a special case and store a pointer to the off attrib + // forever once we find it the first time, as an optimization. + if (_all_off_attrib == (RenderAttrib *)NULL) { + LightAttrib *attrib = new LightAttrib; + attrib->_off_all_lights = true; + _all_off_attrib = return_new(attrib); + } + + return _all_off_attrib; } //////////////////////////////////////////////////////////////////// -// Function: LightAttrib::make -// Access: Published, Static -// Description: Constructs a new LightAttrib object that turns on (or -// off, according to op) the indicate light(s). -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) LightAttrib:: -make(LightAttrib::Operation op, Light *light) { - LightAttrib *attrib = new LightAttrib; - attrib->_operation = op; - attrib->_lights.push_back(light); - return return_new(attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::make -// Access: Published, Static -// Description: Constructs a new LightAttrib object that turns on (or -// off, according to op) the indicate light(s). -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) LightAttrib:: -make(LightAttrib::Operation op, Light *light1, Light *light2) { - LightAttrib *attrib = new LightAttrib; - attrib->_operation = op; - attrib->_lights.push_back(light1); - attrib->_lights.push_back(light2); - - attrib->_lights.sort(); - return return_new(attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::make -// Access: Published, Static -// Description: Constructs a new LightAttrib object that turns on (or -// off, according to op) the indicate light(s). -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) LightAttrib:: -make(LightAttrib::Operation op, Light *light1, Light *light2, - Light *light3) { - LightAttrib *attrib = new LightAttrib; - attrib->_operation = op; - attrib->_lights.push_back(light1); - attrib->_lights.push_back(light2); - attrib->_lights.push_back(light3); - - attrib->_lights.sort(); - return return_new(attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::make -// Access: Published, Static -// Description: Constructs a new LightAttrib object that turns on (or -// off, according to op) the indicate light(s). -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) LightAttrib:: -make(LightAttrib::Operation op, Light *light1, Light *light2, - Light *light3, Light *light4) { - LightAttrib *attrib = new LightAttrib; - attrib->_operation = op; - attrib->_lights.push_back(light1); - attrib->_lights.push_back(light2); - attrib->_lights.push_back(light3); - attrib->_lights.push_back(light4); - - attrib->_lights.sort(); - return return_new(attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::has_light +// Function: LightAttrib::add_on_light // Access: Published -// Description: Returns true if the indicated light is listed in the -// attrib, false otherwise. +// Description: Returns a new LightAttrib, just like this one, but +// with the indicated light added to the list of lights +// turned on by this attrib. //////////////////////////////////////////////////////////////////// -bool LightAttrib:: -has_light(Light *light) const { - return _lights.find(light) != _lights.end(); +CPT(RenderAttrib) LightAttrib:: +add_on_light(Light *light) const { + LightAttrib *attrib = new LightAttrib(*this); + attrib->_on_lights.insert(light); + attrib->_off_lights.erase(light); + + pair insert_result = + attrib->_on_lights.insert(Lights::value_type(light)); + if (insert_result.second) { + // Also ensure it is removed from the off_lights list. + attrib->_off_lights.erase(light); + } + + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::remove_on_light +// Access: Published +// Description: Returns a new LightAttrib, just like this one, but +// with the indicated light removed from the list of +// lights turned on by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +remove_on_light(Light *light) const { + LightAttrib *attrib = new LightAttrib(*this); + attrib->_on_lights.erase(light); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::add_off_light +// Access: Published +// Description: Returns a new LightAttrib, just like this one, but +// with the indicated light added to the list of lights +// turned off by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +add_off_light(Light *light) const { + LightAttrib *attrib = new LightAttrib(*this); + if (!_off_all_lights) { + attrib->_off_lights.insert(light); + } + attrib->_on_lights.erase(light); + return return_new(attrib); +} + +//////////////////////////////////////////////////////////////////// +// Function: LightAttrib::remove_off_light +// Access: Published +// Description: Returns a new LightAttrib, just like this one, but +// with the indicated light removed from the list of +// lights turned off by this attrib. +//////////////////////////////////////////////////////////////////// +CPT(RenderAttrib) LightAttrib:: +remove_off_light(Light *light) const { + LightAttrib *attrib = new LightAttrib(*this); + attrib->_off_lights.erase(light); + return return_new(attrib); } //////////////////////////////////////////////////////////////////// @@ -142,26 +434,38 @@ issue(GraphicsStateGuardianBase *gsg) const { void LightAttrib:: output(ostream &out) const { out << get_type() << ":"; - if (_operation == O_set && _lights.empty()) { - out << "all off"; - } else { - switch (_operation) { - case O_set: - out << "set"; - break; - case O_add: - out << "add"; - break; - case O_remove: - out << "remove"; - break; + if (_off_lights.empty()) { + if (_on_lights.empty()) { + if (_off_all_lights) { + out << "all off"; + } else { + out << "identity"; + } + } else { + if (_off_all_lights) { + out << "set"; + } else { + out << "on"; + } } - Lights::const_iterator li; - for (li = _lights.begin(); li != _lights.end(); ++li) { - Light *light = (*li); - out << " " << light->get_type(); + } else { + out << "off"; + Lights::const_iterator fi; + for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) { + Light *light = (*fi); + out << " " << *light; } + + if (!_on_lights.empty()) { + out << " on"; + } + } + + Lights::const_iterator li; + for (li = _on_lights.begin(); li != _on_lights.end(); ++li) { + Light *light = (*li); + out << " " << *light; } } @@ -185,14 +489,14 @@ compare_to_impl(const RenderAttrib *other) const { const LightAttrib *ta; DCAST_INTO_R(ta, other, 0); - if (_operation != ta->_operation) { - return (int)_operation - (int)ta->_operation; + if (_off_all_lights != ta->_off_all_lights) { + return (int)_off_all_lights - (int)ta->_off_all_lights; } - Lights::const_iterator li = _lights.begin(); - Lights::const_iterator oli = ta->_lights.begin(); + Lights::const_iterator li = _on_lights.begin(); + Lights::const_iterator oli = ta->_on_lights.begin(); - while (li != _lights.end() && oli != ta->_lights.end()) { + while (li != _on_lights.end() && oli != ta->_on_lights.end()) { Light *light = (*li); Light *other_light = (*oli); @@ -204,10 +508,32 @@ compare_to_impl(const RenderAttrib *other) const { ++oli; } - if (li != _lights.end()) { + if (li != _on_lights.end()) { return 1; } - if (oli != ta->_lights.end()) { + if (oli != ta->_on_lights.end()) { + return -1; + } + + Lights::const_iterator fi = _off_lights.begin(); + Lights::const_iterator ofi = ta->_off_lights.begin(); + + while (fi != _off_lights.end() && ofi != ta->_off_lights.end()) { + Light *light = (*fi); + Light *other_light = (*ofi); + + if (light != other_light) { + return light < other_light ? -1 : 1; + } + + ++fi; + ++ofi; + } + + if (fi != _off_lights.end()) { + return 1; + } + if (ofi != ta->_off_lights.end()) { return -1; } @@ -236,29 +562,121 @@ compose_impl(const RenderAttrib *other) const { const LightAttrib *ta; DCAST_INTO_R(ta, other, 0); - if (ta->_operation == O_set) { - // If the other type is O_set, it doesn't matter what we are. + if (ta->_off_all_lights) { + // If the other type turns off all lights, it doesn't matter what + // we are. return ta; } - if (_operation == ta->_operation) { - // If the operation types match, the composition is simply the - // union. - return do_add(ta, _operation); + // This is a three-way merge between ai, bi, and ci, except that bi + // and ci should have no intersection and therefore needn't be + // compared to each other. + Lights::const_iterator ai = _on_lights.begin(); + Lights::const_iterator bi = ta->_on_lights.begin(); + Lights::const_iterator ci = ta->_off_lights.begin(); - } else if (ta->_operation == O_remove) { - // If the other operation type is remove, and our type is add or - // set, then remove. - return do_remove(ta, _operation); + // Create a new LightAttrib that will hold the result. + LightAttrib *new_attrib = new LightAttrib; + back_insert_iterator result = + back_inserter(new_attrib->_on_lights); - } else if (_operation == O_remove) { - // If our type is remove, then the other one wins. - return ta; + while (ai != _on_lights.end() && + bi != ta->_on_lights.end() && + ci != ta->_off_lights.end()) { + if ((*ai) < (*bi)) { + if ((*ai) < (*ci)) { + // Here is a light that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; - } else { - // Otherwise, the result is the union. - return do_add(ta, _operation); + } else if ((*ci) < (*ai)) { + // Here is a light that is turned off in the secondary, but + // was not present in the original. + ++ci; + + } else { // (*ci) == (*ai) + // Here is a light that is turned off in the secondary, and + // was present in the original. + ++ai; + ++ci; + } + + } else if ((*bi) < (*ai)) { + // Here is a new light we have in the secondary, that was not + // present in the original. + *result = *bi; + ++bi; + ++result; + + } else { // (*bi) == (*ai) + // Here is a light we have in both. + *result = *ai; + ++ai; + ++bi; + ++result; + } } + + while (ai != _on_lights.end() && bi != ta->_on_lights.end()) { + if ((*ai) < (*bi)) { + // Here is a light that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; + + } else if ((*bi) < (*ai)) { + // Here is a new light we have in the secondary, that was not + // present in the original. + *result = *bi; + ++bi; + ++result; + + } else { + // Here is a light we have in both. + *result = *ai; + ++ai; + ++bi; + ++result; + } + } + + while (ai != _on_lights.end() && ci != ta->_off_lights.end()) { + if ((*ai) < (*ci)) { + // Here is a light that we have in the original, which is not + // present in the secondary. + *result = *ai; + ++ai; + ++result; + + } else if ((*ci) < (*ai)) { + // Here is a light that is turned off in the secondary, but + // was not present in the original. + ++ci; + + } else { // (*ci) == (*ai) + // Here is a light that is turned off in the secondary, and + // was present in the original. + ++ai; + ++ci; + } + } + + while (ai != _on_lights.end()) { + *result = *ai; + ++ai; + ++result; + } + + while (bi != ta->_on_lights.end()) { + *result = *bi; + ++bi; + ++result; + } + + return return_new(new_attrib); } //////////////////////////////////////////////////////////////////// @@ -294,106 +712,6 @@ make_default_impl() const { return new LightAttrib; } -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::do_add -// Access: Private -// Description: Returns a new LightAttrib that represents all the -// lights of this attrib, with those of the other one -// added in. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) LightAttrib:: -do_add(const LightAttrib *other, LightAttrib::Operation op) const { - Lights::const_iterator ai = _lights.begin(); - Lights::const_iterator bi = other->_lights.begin(); - - // Create a new LightAttrib that will hold the result. - LightAttrib *new_attrib = new LightAttrib; - new_attrib->_operation = op; - back_insert_iterator result = - back_inserter(new_attrib->_lights); - - while (ai != _lights.end() && bi != other->_lights.end()) { - if ((*ai) < (*bi)) { - // Here is a light that we have in the original, which is not - // present in the secondary. - *result = *ai; - ++ai; - ++result; - } else if ((*bi) < (*ai)) { - // Here is a new light we have in the secondary, that was not - // present in the original. - *result = *bi; - ++bi; - ++result; - } else { - // Here is a light we have in both. - *result = *ai; - ++ai; - ++bi; - ++result; - } - } - - while (ai != _lights.end()) { - *result = *ai; - ++ai; - ++result; - } - - while (bi != other->_lights.end()) { - *result = *bi; - ++bi; - ++result; - } - - return return_new(new_attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: LightAttrib::do_remove -// Access: Private -// Description: Returns a new LightAttrib that represents all the -// lights of this attrib, with those of the other one -// removed. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) LightAttrib:: -do_remove(const LightAttrib *other, LightAttrib::Operation op) const { - Lights::const_iterator ai = _lights.begin(); - Lights::const_iterator bi = other->_lights.begin(); - - // Create a new LightAttrib that will hold the result. - LightAttrib *new_attrib = new LightAttrib; - new_attrib->_operation = op; - back_insert_iterator result = - back_inserter(new_attrib->_lights); - - while (ai != _lights.end() && bi != other->_lights.end()) { - if ((*ai) < (*bi)) { - // Here is a light that we have in the original, which is - // not present in the secondary. Keep it. - *result = *ai; - ++ai; - ++result; - } else if ((*bi) < (*ai)) { - // Here is a new light we have in the secondary, that was - // not present in the original. Ignore it. - ++bi; - } else { - // Here is a light we have in both. Drop it. - ++ai; - ++bi; - } - } - - while (ai != _lights.end()) { - *result = *ai; - ++ai; - ++result; - } - - return return_new(new_attrib); -} - //////////////////////////////////////////////////////////////////// // Function: LightAttrib::register_with_read_factory // Access: Public, Static @@ -415,14 +733,23 @@ void LightAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); - dg.add_int8((int)_operation); - PN_uint16 num_lights = _lights.size(); - nassertv(num_lights == _lights.size()); - dg.add_uint16(num_lights); + dg.add_bool(_off_all_lights); - Lights::const_iterator li; - for (li = _lights.begin(); li != _lights.end(); ++li) { - Light *light = (*li); + // write the number of off_lights + dg.add_uint16(get_num_off_lights()); + // write the off lights pointers if any + Lights::const_iterator fi; + for (fi = _off_lights.begin(); fi != _off_lights.end(); ++fi) { + Light *light = (*fi); + manager->write_pointer(dg, light->as_node()); + } + + // write the number of on lights + dg.add_uint16(get_num_on_lights()); + // write the on lights pointers if any + Lights::const_iterator nti; + for (nti = _on_lights.begin(); nti != _on_lights.end(); ++nti) { + Light *light = (*nti); manager->write_pointer(dg, light->as_node()); } } @@ -438,11 +765,20 @@ int LightAttrib:: complete_pointers(TypedWritable **p_list, BamReader *manager) { int pi = RenderAttrib::complete_pointers(p_list, manager); - Lights::iterator li; - for (li = _lights.begin(); li != _lights.end(); ++li) { + Lights::iterator ci = _off_lights.begin(); + while (ci != _off_lights.end()) { PandaNode *node; DCAST_INTO_R(node, p_list[pi++], pi); - (*li) = node->as_light(); + (*ci) = node->as_light(); + ++ci; + } + + ci = _on_lights.begin(); + while (ci != _on_lights.end()) { + PandaNode *node; + DCAST_INTO_R(node, p_list[pi++], pi); + (*ci) = node->as_light(); + ++ci; } return pi; @@ -479,11 +815,31 @@ void LightAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); - _operation = (Operation)scan.get_int8(); - int num_lights = scan.get_uint16(); + // We cheat a little bit here. In the middle of bam version 4.10, + // we completely redefined the bam storage definition for + // LightAttribs, without bothering to up the bam version or even to + // attempt to read the old definition. We get away with this, + // knowing that the egg loader doesn't create LightAttribs, and + // hence no old bam files have the old definition for LightAttrib + // within them. - for (int i = 0; i < num_lights; i++) { + _off_all_lights = scan.get_bool(); + + int num_off_lights = scan.get_uint16(); + + // Push back a NULL pointer for each off Light for now, until + // we get the actual list of pointers later in complete_pointers(). + _off_lights.reserve(num_off_lights); + int i; + for (i = 0; i < num_off_lights; i++) { manager->read_pointer(scan); - _lights.push_back(NULL); + _off_lights.push_back(NULL); + } + + int num_on_lights = scan.get_uint16(); + _on_lights.reserve(num_on_lights); + for (i = 0; i < num_on_lights; i++) { + manager->read_pointer(scan); + _on_lights.push_back(NULL); } } diff --git a/panda/src/pgraph/lightAttrib.h b/panda/src/pgraph/lightAttrib.h index ef6b5af863..f25c78c275 100644 --- a/panda/src/pgraph/lightAttrib.h +++ b/panda/src/pgraph/lightAttrib.h @@ -35,15 +35,18 @@ class EXPCL_PANDA LightAttrib : public RenderAttrib { private: INLINE LightAttrib(); + INLINE LightAttrib(const LightAttrib ©); PUBLISHED: + + // This is the old, deprecated interface to LightAttrib. Do not use + // any of these methods for new code; these methods will be removed + // soon. enum Operation { O_set, O_add, O_remove }; - - static CPT(RenderAttrib) make_all_off(); static CPT(RenderAttrib) make(Operation op, Light *light); static CPT(RenderAttrib) make(Operation op, @@ -55,17 +58,36 @@ PUBLISHED: Light *light1, Light *light2, Light *light3, Light *light4); - INLINE Operation get_operation() const; + Operation get_operation() const; - INLINE int get_num_lights() const; - INLINE Light *get_light(int n) const; + int get_num_lights() const; + Light *get_light(int n) const; bool has_light(Light *light) const; - INLINE CPT(RenderAttrib) add_light(Light *light) const; - INLINE CPT(RenderAttrib) remove_light(Light *light) const; + CPT(RenderAttrib) add_light(Light *light) const; + CPT(RenderAttrib) remove_light(Light *light) const; + + + // The following is the new, more general interface to the + // LightAttrib. + static CPT(RenderAttrib) make(); + static CPT(RenderAttrib) make_all_off(); + + INLINE int get_num_on_lights() const; + INLINE Light *get_on_light(int n) const; + INLINE bool has_on_light(Light *light) const; + + INLINE int get_num_off_lights() const; + INLINE Light *get_off_light(int n) const; + INLINE bool has_off_light(Light *light) const; + INLINE bool has_all_off() const; INLINE bool is_identity() const; - INLINE bool is_all_off() const; + + CPT(RenderAttrib) add_on_light(Light *light) const; + CPT(RenderAttrib) remove_on_light(Light *light) const; + CPT(RenderAttrib) add_off_light(Light *light) const; + CPT(RenderAttrib) remove_off_light(Light *light) const; public: virtual void issue(GraphicsStateGuardianBase *gsg) const; @@ -78,13 +100,12 @@ protected: virtual RenderAttrib *make_default_impl() const; private: - CPT(RenderAttrib) do_add(const LightAttrib *other, Operation op) const; - CPT(RenderAttrib) do_remove(const LightAttrib *other, Operation op) const; - -private: - Operation _operation; typedef ov_set< PT(Light) > Lights; - Lights _lights; + Lights _on_lights, _off_lights; + bool _off_all_lights; + + static CPT(RenderAttrib) _empty_attrib; + static CPT(RenderAttrib) _all_off_attrib; public: static void register_with_read_factory(); diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 0a64475bda..6bd627d89f 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -26,6 +26,8 @@ #include "cullBinAttrib.h" #include "textureAttrib.h" #include "materialAttrib.h" +#include "lightAttrib.h" +#include "polylightEffect.h" #include "fogAttrib.h" #include "renderModeAttrib.h" #include "cullFaceAttrib.h" @@ -2014,6 +2016,295 @@ get_color_scale() const { return ident_scale; } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_light +// Access: Published +// Description: Adds the indicated light to the list of lights that +// illuminate geometry at this node and below. The +// light itself should be parented into the scene graph +// elsewhere, to represent the light's position in +// space; but until set_light() is called it will +// illuminate no geometry. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_light(Light *light, int priority) { + nassertv_always(!is_empty()); + + const RenderAttrib *attrib = + node()->get_attrib(LightAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + priority = max(priority, + node()->get_state()->get_override(LightAttrib::get_class_type())); + const LightAttrib *la = DCAST(LightAttrib, attrib); + + // Modify the existing LightAttrib to add the indicated + // light. + node()->set_attrib(la->add_on_light(light), priority); + + } else { + // Create a new LightAttrib for this node. + CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); + node()->set_attrib(la->add_on_light(light), priority); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_light_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using no lights at all. This is different +// from not specifying a light; rather, this +// specifically contradicts set_light() at a higher +// node level (or, with a priority, overrides a +// set_light() at a lower level). +// +// If no lights are in effect on a particular piece of +// geometry, that geometry is rendered with lighting +// disabled. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_light_off(int priority) { + nassertv_always(!is_empty()); + node()->set_attrib(LightAttrib::make_all_off(), priority); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_light_off +// Access: Published +// Description: Sets the geometry at this level and below to render +// using without the indicated light. This is different +// from not specifying the light; rather, this +// specifically contradicts set_light() at a higher node +// level (or, with a priority, overrides a set_light() +// at a lower level). +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_light_off(Light *light, int priority) { + nassertv_always(!is_empty()); + + const RenderAttrib *attrib = + node()->get_attrib(LightAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + priority = max(priority, + node()->get_state()->get_override(LightAttrib::get_class_type())); + const LightAttrib *la = DCAST(LightAttrib, attrib); + + // Modify the existing LightAttrib to add the indicated light + // to the "off" list. This also, incidentally, removes it from + // the "on" list if it is there. + node()->set_attrib(la->add_off_light(light), priority); + + } else { + // Create a new LightAttrib for this node that turns off the + // indicated light. + CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make()); + node()->set_attrib(la->add_off_light(light), priority); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_light +// Access: Published +// Description: Completely removes any lighting operations that may +// have been set via set_light() or set_light_off() +// from this particular node. +//////////////////////////////////////////////////////////////////// +void NodePath:: +clear_light() { + nassertv_always(!is_empty()); + node()->clear_attrib(LightAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_light +// Access: Published +// Description: Removes any reference to the indicated light +// from the NodePath. +//////////////////////////////////////////////////////////////////// +void NodePath:: +clear_light(Light *light) { + nassertv_always(!is_empty()); + + const RenderAttrib *attrib = + node()->get_attrib(LightAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + CPT(LightAttrib) la = DCAST(LightAttrib, attrib); + la = DCAST(LightAttrib, la->remove_on_light(light)); + la = DCAST(LightAttrib, la->remove_off_light(light)); + + if (la->is_identity()) { + node()->clear_attrib(LightAttrib::get_class_type()); + + } else { + int priority = node()->get_state()->get_override(LightAttrib::get_class_type()); + node()->set_attrib(la, priority); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_light +// Access: Published +// Description: Returns true if the indicated light has been +// specifically enabled on this particular node. This +// means that someone called set_light() on this node +// with the indicated light. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_light(Light *light) const { + nassertr_always(!is_empty(), false); + + const RenderAttrib *attrib = + node()->get_attrib(LightAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const LightAttrib *la = DCAST(LightAttrib, attrib); + return la->has_on_light(light); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_light_off +// Access: Published +// Description: Returns true if all lights have been specifically +// disabled on this particular node. This means that +// someone called set_light_off() on this node with no +// parameters. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_light_off() const { + nassertr_always(!is_empty(), false); + const RenderAttrib *attrib = + node()->get_attrib(LightAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const LightAttrib *la = DCAST(LightAttrib, attrib); + return la->has_all_off(); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_light_off +// Access: Published +// Description: Returns true if the indicated light has been +// specifically disabled on this particular node. This +// means that someone called set_light_off() on this +// node with the indicated light. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_light_off(Light *light) const { + nassertr_always(!is_empty(), false); + + const RenderAttrib *attrib = + node()->get_attrib(LightAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const LightAttrib *la = DCAST(LightAttrib, attrib); + return la->has_off_light(light); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_light +// Access: Published +// Description: Adds a PolylightEffect to the geometry at this node +// and below. This makes the geometry at this point in +// the scene graph grow brighter or dimmer according to +// its proximity to the indicated PolylightNode; this is +// an effect similar to lighting, but is not related to +// traditional hardware T&L. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_light(PolylightNode *) { + // Not yet implemented. + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_light +// Access: Published +// Description: Removes the indicated PolylightEffect from the +// geometry. This undoes a previous set_light() call. +//////////////////////////////////////////////////////////////////// +void NodePath:: +clear_light(PolylightNode *) { + // Not yet implemented. + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_light +// Access: Published +// Description: Returns true if the indicated PolylightNode was added +// to this node, false otherwise. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_light(PolylightNode *) { + // Not yet implemented. + nassertr(false, false); + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::set_light +// Access: Published +// Description: Adds a Light or Polylight to the geometry at this +// node and below. +//////////////////////////////////////////////////////////////////// +void NodePath:: +set_light(const NodePath &light) { + if (!light.is_empty()) { + PandaNode *node = light.node(); + Light *light_obj = node->as_light(); + if (light_obj != (Light *)NULL) { + set_light(light_obj); + return; + } + } + nassert_raise("Not a light object."); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::clear_light +// Access: Published +// Description: Removes the indicated PolylightEffect from the +// geometry. This undoes a previous set_light() call. +//////////////////////////////////////////////////////////////////// +void NodePath:: +clear_light(const NodePath &light) { + if (!light.is_empty()) { + PandaNode *node = light.node(); + Light *light_obj = node->as_light(); + if (light_obj != (Light *)NULL) { + clear_light(light_obj); + return; + } + } + nassert_raise("Not a light object."); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::has_light +// Access: Published +// Description: Returns true if the indicated PolylightNode was added +// to this node, false otherwise. +//////////////////////////////////////////////////////////////////// +bool NodePath:: +has_light(const NodePath &light) { + if (!light.is_empty()) { + PandaNode *node = light.node(); + Light *light_obj = node->as_light(); + if (light_obj != (Light *)NULL) { + return has_light(light_obj); + } + } + nassert_raise("Not a light object."); + return false; +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::set_bin // Access: Published diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index b1dde11ff1..e87fc9d577 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -35,6 +35,8 @@ class NodePathCollection; class TextureCollection; class FindApproxPath; class FindApproxLevelEntry; +class Light; +class PolylightNode; class Texture; class Material; class Fog; @@ -481,6 +483,23 @@ PUBLISHED: INLINE float get_sb() const; INLINE float get_sa() const; + void set_light(Light *light, int priority = 0); + void set_light_off(int priority = 0); + void set_light_off(Light *light, int priority = 0); + void clear_light(); + void clear_light(Light *light); + bool has_light(Light *light) const; + bool has_light_off() const; + bool has_light_off(Light *light) const; + + void set_light(PolylightNode *light); + void clear_light(PolylightNode *light); + bool has_light(PolylightNode *light); + + void set_light(const NodePath &light); + void clear_light(const NodePath &light); + bool has_light(const NodePath &light); + void set_bin(const string &bin_name, int draw_order, int priority = 0); void clear_bin(); bool has_bin() const; diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 519513cca2..ec799000c5 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -568,6 +568,23 @@ get_attrib(TypeHandle type) const { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::get_override +// Access: Published, Virtual +// Description: Looks for a RenderAttrib of the indicated type in the +// state, and returns its override value if it is found, +// or 0 if it is not. +//////////////////////////////////////////////////////////////////// +int RenderState:: +get_override(TypeHandle type) const { + Attributes::const_iterator ai; + ai = _attributes.find(Attribute(type)); + if (ai != _attributes.end()) { + return (*ai)._override; + } + return 0; +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::output // Access: Published, Virtual @@ -842,11 +859,7 @@ issue_delta_modify(const RenderState *other, if ((*ai)._attrib != (*bi)._attrib) { any_changed = true; (*bi)._attrib->issue(gsg); - - } else if ((*bi)._attrib->always_reissue()) { - (*bi)._attrib->issue(gsg); } - *result = *bi; ++ai; ++bi; @@ -914,7 +927,7 @@ issue_delta_set(const RenderState *other, } else { // Here is an attribute we have in both. Issue the new one if // it's different. - if ((*ai)._attrib != (*bi)._attrib || (*bi)._attrib->always_reissue()) { + if ((*ai)._attrib != (*bi)._attrib) { (*bi)._attrib->issue(gsg); } ++ai; @@ -1020,20 +1033,17 @@ do_compose(const RenderState *other) const { ++bi; ++result; } else { - // Here is an attribute we have in both. Does one override the - // other? + // Here is an attribute we have in both. Does A override B? const Attribute &a = (*ai); const Attribute &b = (*bi); - if (a._override < b._override) { - // B overrides. - *result = *bi; - - } else if (b._override < a._override) { + if (b._override < a._override) { // A overrides. *result = *ai; } else { - // No, they're equivalent, so compose them. + // Either they have the same override value, or B is higher. + // In either case, the result is the composition of the two, + // with B's override value. *result = Attribute(a._attrib->compose(b._attrib), b._override); } ++ai; diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 9c23a16656..17d6859401 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -89,6 +89,7 @@ PUBLISHED: CPT(RenderState) adjust_all_priorities(int adjustment) const; const RenderAttrib *get_attrib(TypeHandle type) const; + int get_override(TypeHandle type) const; void output(ostream &out) const; void write(ostream &out, int indent_level) const;