Browse Source

add NodePath::set_color_scale_off() and Camera::set_initial_state() and related methods

David Rose 21 years ago
parent
commit
597d379038

+ 7 - 3
panda/src/display/graphicsEngine.cxx

@@ -978,9 +978,13 @@ setup_scene(const NodePath &camera, GraphicsStateGuardian *gsg) {
   // We will need both the camera transform (the net transform to the
   // camera from the scene) and the world transform (the camera
   // transform inverse, or the net transform to the scene from the
-  // camera).
-  CPT(TransformState) camera_transform = camera.get_transform(scene_root);
-  CPT(TransformState) world_transform = scene_root.get_transform(camera);
+  // camera).  These are actually defined from the parent of the
+  // scene_root, because the scene_root's own transform is immediately
+  // applied to these during rendering.  (Normally, the parent of the
+  // scene_root is the empty NodePath, although it need not be.)
+  NodePath scene_parent = scene_root.get_parent();
+  CPT(TransformState) camera_transform = camera.get_transform(scene_parent);
+  CPT(TransformState) world_transform = scene_parent.get_transform(camera);
 
   // The render transform is the same as the world transform, except
   // it is converted into the GSG's internal coordinate system.  This

+ 3 - 3
panda/src/display/graphicsStateGuardian.cxx

@@ -590,10 +590,10 @@ void GraphicsStateGuardian::
 issue_color_scale(const ColorScaleAttrib *attrib) {
   _current_color_scale = attrib->get_scale();
 
-  if (_current_color_scale == LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
-    _color_transform_enabled &= ~CT_scale;
-  } else {
+  if (attrib->has_scale()) {
     _color_transform_enabled |= CT_scale;
+  } else {
+    _color_transform_enabled &= ~CT_scale;
   }
 
   _scene_graph_color_stale = _has_scene_graph_color;

+ 49 - 2
panda/src/pgraph/camera.I

@@ -118,7 +118,7 @@ get_camera_mask() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Camera::set_cull_center
-//       Access: Public
+//       Access: Published
 //  Description: Specifies the point from which the culling operations
 //               are performed.  Normally, this is the same as the
 //               camera, and that is the default if this is not
@@ -133,7 +133,7 @@ set_cull_center(const NodePath &cull_center) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Camera::get_cull_center
-//       Access: Public
+//       Access: Published
 //  Description: Returns the point from which the culling operations
 //               will be performed, if it was set by
 //               set_cull_center(), or the empty NodePath otherwise.
@@ -142,3 +142,50 @@ INLINE const NodePath &Camera::
 get_cull_center() const {
   return _cull_center;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::set_initial_state
+//       Access: Published
+//  Description: Sets the initial state which is applied to all nodes
+//               in the scene, as if it were set at the top of the
+//               scene graph.
+////////////////////////////////////////////////////////////////////
+INLINE void Camera::
+set_initial_state(const RenderState *state) {
+  _initial_state = state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::get_initial_state
+//       Access: Published
+//  Description: Returns the initial state as set by a previous call
+//               to set_initial_state().
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderState) Camera::
+get_initial_state() const {
+  return _initial_state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::set_tag_state_key
+//       Access: Published
+//  Description: Sets the tag key which, when encountered as a tag on
+//               nodes in the scene graph, causes this Camera to apply
+//               an arbitrary state transition based on the value of
+//               the tag (as specified to set_tag_state()).
+////////////////////////////////////////////////////////////////////
+INLINE void Camera::
+set_tag_state_key(const string &tag_state_key) {
+  _tag_state_key = tag_state_key;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::get_tag_state_key
+//       Access: Published
+//  Description: Returns the tag key as set by a previous call to
+//               set_tag_state_key().
+////////////////////////////////////////////////////////////////////
+INLINE const string &Camera::
+get_tag_state_key() const {
+  return _tag_state_key;
+}

+ 69 - 2
panda/src/pgraph/camera.cxx

@@ -32,7 +32,8 @@ Camera::
 Camera(const string &name) :
   LensNode(name),
   _active(true),
-  _camera_mask(DrawMask::all_on())
+  _camera_mask(DrawMask::all_on()),
+  _initial_state(RenderState::make_empty())
 {
 }
 
@@ -46,7 +47,10 @@ Camera(const Camera &copy) :
   LensNode(copy),
   _active(copy._active),
   _scene(copy._scene),
-  _camera_mask(copy._camera_mask)
+  _camera_mask(copy._camera_mask),
+  _initial_state(copy._initial_state),
+  _tag_state_key(copy._tag_state_key),
+  _tag_states(copy._tag_states)
 {
 }
 
@@ -104,6 +108,69 @@ safe_to_transform() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::set_tag_state
+//       Access: Published
+//  Description: Associates a particular state transition with the
+//               indicated tag value.  When a node is encountered
+//               during traversal with the tag key specified by
+//               set_tag_state_key(), if the value of that tag matches
+//               tag_state, then the indicated state is applied to
+//               this node--but only when it is rendered by this
+//               camera.
+//
+//               This can be used to apply special effects to nodes
+//               when they are rendered by certain cameras.  It is
+//               particularly useful for multipass rendering, in which
+//               specialty cameras might be needed to render the scene
+//               with a particular set of effects.
+////////////////////////////////////////////////////////////////////
+void Camera::
+set_tag_state(const string &tag_state, const RenderState *state) {
+  _tag_states[tag_state] = state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::clear_tag_state
+//       Access: Published
+//  Description: Removes the association established by a previous
+//               call to set_tag_state().
+////////////////////////////////////////////////////////////////////
+void Camera::
+clear_tag_state(const string &tag_state) {
+  _tag_states.erase(tag_state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::has_tag_state
+//       Access: Published
+//  Description: Returns true if set_tag_state() has previously been
+//               called with the indicated tag state, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool Camera::
+has_tag_state(const string &tag_state) const {
+  TagStates::const_iterator tsi;
+  tsi = _tag_states.find(tag_state);
+  return (tsi != _tag_states.end());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::get_tag_state
+//       Access: Published
+//  Description: Returns the state associated with the indicated tag
+//               state by a previous call to set_tag_state(), or the
+//               empty state if nothing has been associated.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) Camera::
+get_tag_state(const string &tag_state) const {
+  TagStates::const_iterator tsi;
+  tsi = _tag_states.find(tag_state);
+  if (tsi != _tag_states.end()) {
+    return (*tsi).second;
+  }
+  return RenderState::make_empty();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Camera::add_display_region
 //       Access: Private

+ 20 - 0
panda/src/pgraph/camera.h

@@ -24,6 +24,9 @@
 #include "lensNode.h"
 #include "nodePath.h"
 #include "drawMask.h"
+#include "renderState.h"
+#include "pointerTo.h"
+#include "pmap.h"
 
 class DisplayRegion;
 
@@ -62,6 +65,17 @@ PUBLISHED:
   INLINE void set_cull_center(const NodePath &cull_center);
   INLINE const NodePath &get_cull_center() const;
 
+  INLINE void set_initial_state(const RenderState *state);
+  INLINE CPT(RenderState) get_initial_state() const;
+
+  INLINE void set_tag_state_key(const string &tag_state_key);
+  INLINE const string &get_tag_state_key() const;
+
+  void set_tag_state(const string &tag_state, const RenderState *state);
+  void clear_tag_state(const string &tag_state);
+  bool has_tag_state(const string &tag_state) const;
+  CPT(RenderState) get_tag_state(const string &tag_state) const;
+
 private:
   void add_display_region(DisplayRegion *display_region);
   void remove_display_region(DisplayRegion *display_region);
@@ -75,6 +89,12 @@ private:
   typedef pvector<DisplayRegion *> DisplayRegions;
   DisplayRegions _display_regions;
 
+  CPT(RenderState) _initial_state;
+  string _tag_state_key;
+
+  typedef pmap<string, CPT(RenderState) > TagStates;
+  TagStates _tag_states;
+
 public:
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

+ 43 - 2
panda/src/pgraph/colorScaleAttrib.I

@@ -19,14 +19,55 @@
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ColorScaleAttrib::Constructor
-//       Access: Private
+//       Access: Protected
 //  Description: Use ColorScaleAttrib::make() to construct a new
 //               ColorScaleAttrib object.
 ////////////////////////////////////////////////////////////////////
 INLINE ColorScaleAttrib::
-ColorScaleAttrib(const LVecBase4f &scale) :
+ColorScaleAttrib(bool off, const LVecBase4f &scale) :
+  _off(off),
   _scale(scale)
 {
+  _has_scale = !_scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::Copy Constructor
+//       Access: Protected
+//  Description: Use ColorScaleAttrib::make() to construct a new
+//               ColorScaleAttrib object.
+////////////////////////////////////////////////////////////////////
+INLINE ColorScaleAttrib::
+ColorScaleAttrib(const ColorScaleAttrib &copy) :
+  _off(copy._off),
+  _has_scale(copy._has_scale),
+  _scale(copy._scale)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::is_off
+//       Access: Published
+//  Description: Returns true if the ColorScaleAttrib will ignore any
+//               color scales inherited from above, false otherwise.
+//               This is not the same thing as !has_scale(); a
+//               ColorScaleAttrib may have the "off" flag set and also
+//               have another scale specified.
+////////////////////////////////////////////////////////////////////
+INLINE bool ColorScaleAttrib::
+is_off() const {
+  return _off;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::has_scale
+//       Access: Published
+//  Description: Returns true if the ColorScaleAttrib has a
+//               non-identity scale, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool ColorScaleAttrib::
+has_scale() const {
+  return _has_scale;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 65 - 11
panda/src/pgraph/colorScaleAttrib.cxx

@@ -34,7 +34,36 @@ TypeHandle ColorScaleAttrib::_type_handle;
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) ColorScaleAttrib::
 make(const LVecBase4f &scale) {
-  ColorScaleAttrib *attrib = new ColorScaleAttrib(scale);
+  ColorScaleAttrib *attrib = new ColorScaleAttrib(false, scale);
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::make_off
+//       Access: Published, Static
+//  Description: Constructs a new ColorScaleAttrib object that ignores
+//               any ColorScaleAttrib inherited from above.  You may
+//               also specify an additional color scale to apply to
+//               geometry below (using set_scale()).
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorScaleAttrib::
+make_off() {
+  ColorScaleAttrib *attrib = 
+    new ColorScaleAttrib(true, LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorScaleAttrib::set_scale
+//       Access: Published
+//  Description: Returns a new ColorScaleAttrib, just like this one, but
+//               with the scale changed to the indicated value.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorScaleAttrib::
+set_scale(const LVecBase4f &scale) const {
+  ColorScaleAttrib *attrib = new ColorScaleAttrib(*this);
+  attrib->_scale = scale;
+  attrib->_has_scale = !scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
   return return_new(attrib);
 }
 
@@ -59,7 +88,13 @@ issue(GraphicsStateGuardianBase *gsg) const {
 ////////////////////////////////////////////////////////////////////
 void ColorScaleAttrib::
 output(ostream &out) const {
-  out << get_type() << ":(" << get_scale() << ")";
+  out << get_type() << ":";
+  if (is_off()) {
+    out << "off";
+  }
+  if (has_scale()) {
+    out << "(" << get_scale() << ")";
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -81,6 +116,11 @@ int ColorScaleAttrib::
 compare_to_impl(const RenderAttrib *other) const {
   const ColorScaleAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
+
+  if (is_off() != ta->is_off()) {
+    return (int)is_off() - (int)ta->is_off();
+  }
+
   return _scale.compare_to(ta->_scale);
 }
 
@@ -105,12 +145,17 @@ CPT(RenderAttrib) ColorScaleAttrib::
 compose_impl(const RenderAttrib *other) const {
   const ColorScaleAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
+
+  if (ta->is_off()) {
+    return ta;
+  }
+
   LVecBase4f new_scale(ta->_scale[0] * _scale[0],
                        ta->_scale[1] * _scale[1],
                        ta->_scale[2] * _scale[2],
                        ta->_scale[3] * _scale[3]);
-
-  ColorScaleAttrib *attrib = new ColorScaleAttrib(new_scale);
+  
+  ColorScaleAttrib *attrib = new ColorScaleAttrib(is_off(), new_scale);
   return return_new(attrib);
 }
 
@@ -125,14 +170,17 @@ compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 CPT(RenderAttrib) ColorScaleAttrib::
 invert_compose_impl(const RenderAttrib *other) const {
+  if (is_off()) {
+    return other;
+  }
   const ColorScaleAttrib *ta;
   DCAST_INTO_R(ta, other, 0);
-  LVecBase4f new_scale(ta->_scale[0] / _scale[0],
-                       ta->_scale[1] / _scale[1],
-                       ta->_scale[2] / _scale[2],
-                       ta->_scale[3] / _scale[3]);
+  LVecBase4f new_scale(_scale[0] == 0.0f ? 1.0f : ta->_scale[0] / _scale[0],
+                       _scale[1] == 0.0f ? 1.0f : ta->_scale[1] / _scale[1],
+                       _scale[2] == 0.0f ? 1.0f : ta->_scale[2] / _scale[2],
+                       _scale[3] == 0.0f ? 1.0f : ta->_scale[3] / _scale[3]);
 
-  ColorScaleAttrib *attrib = new ColorScaleAttrib(new_scale);
+  ColorScaleAttrib *attrib = new ColorScaleAttrib(false, new_scale);
   return return_new(attrib);
 }
 
@@ -149,7 +197,7 @@ invert_compose_impl(const RenderAttrib *other) const {
 ////////////////////////////////////////////////////////////////////
 RenderAttrib *ColorScaleAttrib::
 make_default_impl() const {
-  return new ColorScaleAttrib(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+  return new ColorScaleAttrib(false, LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -173,6 +221,10 @@ void ColorScaleAttrib::
 write_datagram(BamWriter *manager, Datagram &dg) {
   RenderAttrib::write_datagram(manager, dg);
 
+  // We cheat, and modify the bam stream without upping the bam
+  // version.  We can do this since we know that no existing bam files
+  // have a ColorScaleAttrib in them.
+  dg.add_bool(_off);
   _scale.write_datagram(dg);
 }
 
@@ -186,7 +238,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
 ////////////////////////////////////////////////////////////////////
 TypedWritable *ColorScaleAttrib::
 make_from_bam(const FactoryParams &params) {
-  ColorScaleAttrib *attrib = new ColorScaleAttrib(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
+  ColorScaleAttrib *attrib = new ColorScaleAttrib(false, LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
   DatagramIterator scan;
   BamReader *manager;
 
@@ -207,5 +259,7 @@ void ColorScaleAttrib::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderAttrib::fillin(scan, manager);
 
+  _off = scan.get_bool();
   _scale.read_datagram(scan);
+  _has_scale = !_scale.almost_equal(LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f));
 }

+ 9 - 2
panda/src/pgraph/colorScaleAttrib.h

@@ -32,13 +32,18 @@ class FactoryParams;
 //               vertices.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA ColorScaleAttrib : public RenderAttrib {
-private:
-  INLINE ColorScaleAttrib(const LVecBase4f &scale);
+protected:
+  INLINE ColorScaleAttrib(bool off, const LVecBase4f &scale);
+  INLINE ColorScaleAttrib(const ColorScaleAttrib &copy);
 
 PUBLISHED:
   static CPT(RenderAttrib) make(const LVecBase4f &scale);
+  static CPT(RenderAttrib) make_off();
 
+  INLINE bool is_off() const;
+  INLINE bool has_scale() const;
   INLINE const LVecBase4f &get_scale() const;
+  CPT(RenderAttrib) set_scale(const LVecBase4f &scale) const;
 
 public:
   virtual void issue(GraphicsStateGuardianBase *gsg) const;
@@ -51,6 +56,8 @@ protected:
   virtual RenderAttrib *make_default_impl() const;
 
 private:
+  bool _off;
+  bool _has_scale;
   LVecBase4f _scale;
 
 public:

+ 26 - 0
panda/src/pgraph/cullTraverser.I

@@ -27,6 +27,10 @@
 INLINE void CullTraverser::
 set_scene(SceneSetup *scene_setup) {
   _scene_setup = scene_setup;
+  const Camera *camera = scene_setup->get_camera_node();
+  _tag_state_key = camera->get_tag_state_key();
+  _has_tag_state_key = !_tag_state_key.empty();
+  _initial_state = camera->get_initial_state();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -39,6 +43,28 @@ get_scene() const {
   return _scene_setup;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::has_tag_state_key
+//       Access: Public
+//  Description: Returns true if a nonempty tag state key has been
+//               specified for the scene's camera, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool CullTraverser::
+has_tag_state_key() const {
+  return _has_tag_state_key;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::get_tag_state_key
+//       Access: Public
+//  Description: Returns the tag state key that has been specified for
+//               the scene's camera, if any.
+////////////////////////////////////////////////////////////////////
+INLINE const string &CullTraverser::
+get_tag_state_key() const {
+  return _tag_state_key;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::get_camera_transform
 //       Access: Public

+ 7 - 1
panda/src/pgraph/cullTraverser.cxx

@@ -49,6 +49,7 @@ TypeHandle CullTraverser::_type_handle;
 CullTraverser::
 CullTraverser() {
   _camera_mask = DrawMask::all_on();
+  _has_tag_state_key = false;
   _initial_state = RenderState::make_empty();
   _depth_offset_decals = false;
   _cull_handler = (CullHandler *)NULL;
@@ -64,6 +65,8 @@ CullTraverser::
 CullTraverser(const CullTraverser &copy) :
   _scene_setup(copy._scene_setup),
   _camera_mask(copy._camera_mask),
+  _has_tag_state_key(copy._has_tag_state_key),
+  _tag_state_key(copy._tag_state_key),
   _initial_state(copy._initial_state),
   _depth_offset_decals(copy._depth_offset_decals),
   _view_frustum(copy._view_frustum),
@@ -148,8 +151,11 @@ traverse(CullTraverserData &data) {
   // being "fancy", and skip this processing for non-fancy nodes.
   
   if (data.is_in_view(_camera_mask)) {
+    if (pgraph_cat.is_spam()) {
+      pgraph_cat.spam() << "\n" << data._node_path << "\n";
+    }
+
     PandaNode *node = data.node();
-    pgraph_cat.spam() << "\n" << data._node_path << "\n";
 
     const RenderEffects *node_effects = node->get_effects();
     if (node_effects->has_show_bounds()) {

+ 5 - 0
panda/src/pgraph/cullTraverser.h

@@ -27,6 +27,7 @@
 #include "transformState.h"
 #include "geometricBoundingVolume.h"
 #include "pointerTo.h"
+#include "camera.h"
 #include "drawMask.h"
 #include "typedObject.h"
 #include "pStatCollector.h"
@@ -53,6 +54,8 @@ public:
 
   INLINE void set_scene(SceneSetup *scene_setup);
   INLINE SceneSetup *get_scene() const;
+  INLINE bool has_tag_state_key() const;
+  INLINE const string &get_tag_state_key() const;
 
   INLINE void set_camera_mask(const DrawMask &camera_mask);
   INLINE const DrawMask &get_camera_mask() const;
@@ -99,6 +102,8 @@ private:
 
   PT(SceneSetup) _scene_setup;
   DrawMask _camera_mask;
+  bool _has_tag_state_key;
+  string _tag_state_key;
   CPT(RenderState) _initial_state;
   bool _depth_offset_decals;
   PT(GeometricBoundingVolume) _view_frustum;

+ 0 - 13
panda/src/pgraph/cullTraverserData.I

@@ -136,16 +136,3 @@ is_in_view(const DrawMask &camera_mask) {
   return is_in_view_impl();
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullTraverserData::apply_transform_and_state
-//       Access: Public
-//  Description: Applies the transform and state from the current
-//               node onto the current data.  This also evaluates
-//               billboards, etc.
-////////////////////////////////////////////////////////////////////
-INLINE void CullTraverserData::
-apply_transform_and_state(CullTraverser *trav) {
-  apply_transform_and_state(trav, node()->get_transform(),
-                            node()->get_state(), node()->get_effects());
-}
-

+ 27 - 0
panda/src/pgraph/cullTraverserData.cxx

@@ -27,6 +27,33 @@
 #include "compassEffect.h"
 #include "polylightEffect.h"
 #include "renderState.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverserData::apply_transform_and_state
+//       Access: Public
+//  Description: Applies the transform and state from the current
+//               node onto the current data.  This also evaluates
+//               billboards, etc.
+////////////////////////////////////////////////////////////////////
+void CullTraverserData::
+apply_transform_and_state(CullTraverser *trav) {
+  PandaNode *node = _node_path.node();
+  CPT(RenderState) node_state = node->get_state();
+
+  if (trav->has_tag_state_key() && node->has_tag(trav->get_tag_state_key())) {
+    // Here's a node that has been tagged with the special key for our
+    // current camera.  This indicates some special state transition
+    // for this node, which is unique to this camera.
+    const Camera *camera = trav->get_scene()->get_camera_node();
+    string tag_state = node->get_tag(trav->get_tag_state_key());
+    node_state = node_state->compose(camera->get_tag_state(tag_state));
+  }
+
+  apply_transform_and_state(trav, node->get_transform(),
+                            node_state, node->get_effects());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverserData::apply_specific_transform
 //       Access: Public

+ 1 - 1
panda/src/pgraph/cullTraverserData.h

@@ -62,7 +62,7 @@ public:
   INLINE PandaNode *node() const;
 
   INLINE bool is_in_view(const DrawMask &camera_mask);
-  INLINE void apply_transform_and_state(CullTraverser *trav);
+  void apply_transform_and_state(CullTraverser *trav);
   void apply_transform_and_state(CullTraverser *trav, 
                                  CPT(TransformState) node_transform, 
                                  CPT(RenderState) node_state,

+ 3 - 1
panda/src/pgraph/nodePath.I

@@ -357,11 +357,13 @@ has_parent() const {
 //       Access: Published
 //  Description: Returns the NodePath to the parent of the referenced
 //               node: that is, this NodePath, shortened by one node.
+//               The parent of a singleton NodePath is defined to be
+//               the empty NodePath.
 ////////////////////////////////////////////////////////////////////
 INLINE NodePath NodePath::
 get_parent() const {
   if (!has_parent()) {
-    return NodePath::fail();
+    return NodePath();
   }
   NodePath parent;
   parent._head = _head->get_next();

+ 67 - 12
panda/src/pgraph/nodePath.cxx

@@ -1956,28 +1956,73 @@ clear_color_scale() {
 void NodePath::
 set_color_scale(const LVecBase4f &scale, int priority) {
   nassertv_always(!is_empty());
-  node()->set_attrib(ColorScaleAttrib::make(scale), priority);
+
+  const RenderAttrib *attrib =
+    node()->get_attrib(ColorScaleAttrib::get_class_type());
+  if (attrib != (const RenderAttrib *)NULL) {
+    priority = max(priority,
+                   node()->get_state()->get_override(ColorScaleAttrib::get_class_type()));
+    const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
+
+    // Modify the existing ColorScaleAttrib to add the indicated
+    // colorScale.
+    node()->set_attrib(csa->set_scale(scale), priority);
+
+  } else {
+    // Create a new ColorScaleAttrib for this node.
+    node()->set_attrib(ColorScaleAttrib::make(scale), priority);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_color_scale_off
+//       Access: Published
+//  Description: Disables any color scale attribute inherited from
+//               above.  This is not the same thing as
+//               clear_color_scale(), which undoes any previous
+//               set_color_scale() operation on this node; rather,
+//               this actively disables any set_color_scale() that
+//               might be inherited from a parent node.  This also
+//               disables set_alpha_scale() at the same time.
+//
+//               It is legal to specify a new color scale on the same
+//               node with a subsequent call to set_color_scale() or
+//               set_alpha_scale(); this new scale will apply to lower
+//               geometry.
+////////////////////////////////////////////////////////////////////
+void NodePath::
+set_color_scale_off(int priority) {
+  nassertv_always(!is_empty());
+  node()->set_attrib(ColorScaleAttrib::make_off(), priority);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePath::set_alpha_scale
 //       Access: Published
 //  Description: Sets the alpha scale component of the transform
-//               without affecting the color scale.  Note that any
-//               priority specified will also apply to the color
+//               without (much) affecting the color scale.  Note that
+//               any priority specified will also apply to the color
 //               scale.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
 set_alpha_scale(float scale, int priority) {
   nassertv_always(!is_empty());
+
   const RenderAttrib *attrib =
     node()->get_attrib(ColorScaleAttrib::get_class_type());
   if (attrib != (const RenderAttrib *)NULL) {
+    priority = max(priority,
+                   node()->get_state()->get_override(ColorScaleAttrib::get_class_type()));
     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
+
+    // Modify the existing ColorScaleAttrib to add the indicated
+    // colorScale.
     const LVecBase4f &sc = csa->get_scale();
-    set_color_scale(sc[0], sc[1], sc[2], scale, priority);
+    node()->set_attrib(csa->set_scale(LVecBase4f(sc[0], sc[1], sc[2], scale)), priority);
+
   } else {
-    set_color_scale(1.0f, 1.0f, 1.0f, scale, priority);
+    // Create a new ColorScaleAttrib for this node.
+    node()->set_attrib(ColorScaleAttrib::make(LVecBase4f(1.0f, 1.0f, 1.0f, scale)), priority);
   }
 }
 
@@ -1985,21 +2030,29 @@ set_alpha_scale(float scale, int priority) {
 //     Function: NodePath::set_all_color_scale
 //       Access: Published
 //  Description: Scales all the color components of the object by the
-//               same amount, darkening the object, without affecting
-//               alpha.  Note that any priority specified will also
-//               apply to the alpha scale.
+//               same amount, darkening the object, without (much)
+//               affecting alpha.  Note that any priority specified
+//               will also apply to the alpha scale.
 ////////////////////////////////////////////////////////////////////
 void NodePath::
 set_all_color_scale(float scale, int priority) {
   nassertv_always(!is_empty());
+
   const RenderAttrib *attrib =
     node()->get_attrib(ColorScaleAttrib::get_class_type());
   if (attrib != (const RenderAttrib *)NULL) {
+    priority = max(priority,
+                   node()->get_state()->get_override(ColorScaleAttrib::get_class_type()));
     const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
+
+    // Modify the existing ColorScaleAttrib to add the indicated
+    // colorScale.
     const LVecBase4f &sc = csa->get_scale();
-    set_color_scale(scale, scale, scale, sc[3], priority);
+    node()->set_attrib(csa->set_scale(LVecBase4f(scale, scale, scale, sc[3])), priority);
+
   } else {
-    set_color_scale(scale, scale, scale, 1.0f, priority);
+    // Create a new ColorScaleAttrib for this node.
+    node()->set_attrib(ColorScaleAttrib::make(LVecBase4f(scale, scale, scale, 1.0f)), priority);
   }
 }
 
@@ -2007,8 +2060,10 @@ set_all_color_scale(float scale, int priority) {
 //     Function: NodePath::get_color_scale
 //       Access: Published
 //  Description: Returns the complete color scale vector that has been
-//               applied to the bottom node, or all 1's (identity) if
-//               no scale has been applied.
+//               applied to this node via a previous call to
+//               set_color_scale() and/or set_alpha_scale(), or all
+//               1's (identity) if no scale has been applied to this
+//               particular node.
 ////////////////////////////////////////////////////////////////////
 const LVecBase4f &NodePath::
 get_color_scale() const {

+ 2 - 0
panda/src/pgraph/nodePath.h

@@ -474,6 +474,8 @@ PUBLISHED:
                        int priority = 0);
   INLINE void set_color_scale(float sx, float sy, float sz, float sa,
                               int priority = 0);
+  void set_color_scale_off(int priority = 0);
+
   void set_alpha_scale(float scale, int priority = 0);
   void set_all_color_scale(float scale, int priority = 0);
   INLINE void set_sr(float sr);