David Rose 24 anni fa
parent
commit
a41e2cac34
37 ha cambiato i file con 3786 aggiunte e 0 eliminazioni
  1. 54 0
      panda/src/pgraph/Sources.pp
  2. 66 0
      panda/src/pgraph/colorAttrib.I
  3. 127 0
      panda/src/pgraph/colorAttrib.cxx
  4. 81 0
      panda/src/pgraph/colorAttrib.h
  5. 61 0
      panda/src/pgraph/config_pgraph.cxx
  6. 29 0
      panda/src/pgraph/config_pgraph.h
  7. 27 0
      panda/src/pgraph/cycleData.I
  8. 29 0
      panda/src/pgraph/cycleData.cxx
  9. 44 0
      panda/src/pgraph/cycleData.h
  10. 68 0
      panda/src/pgraph/cycleDataReader.I
  11. 19 0
      panda/src/pgraph/cycleDataReader.cxx
  12. 59 0
      panda/src/pgraph/cycleDataReader.h
  13. 80 0
      panda/src/pgraph/cycleDataWriter.I
  14. 19 0
      panda/src/pgraph/cycleDataWriter.cxx
  15. 59 0
      panda/src/pgraph/cycleDataWriter.h
  16. 325 0
      panda/src/pgraph/pandaNode.I
  17. 295 0
      panda/src/pgraph/pandaNode.cxx
  18. 175 0
      panda/src/pgraph/pandaNode.h
  19. 31 0
      panda/src/pgraph/pipeline.I
  20. 74 0
      panda/src/pgraph/pipeline.cxx
  21. 58 0
      panda/src/pgraph/pipeline.h
  22. 30 0
      panda/src/pgraph/pipelineCycler.I
  23. 19 0
      panda/src/pgraph/pipelineCycler.cxx
  24. 61 0
      panda/src/pgraph/pipelineCycler.h
  25. 109 0
      panda/src/pgraph/pipelineCyclerBase.I
  26. 48 0
      panda/src/pgraph/pipelineCyclerBase.cxx
  27. 55 0
      panda/src/pgraph/pipelineCyclerBase.h
  28. 73 0
      panda/src/pgraph/renderAttrib.I
  29. 240 0
      panda/src/pgraph/renderAttrib.cxx
  30. 110 0
      panda/src/pgraph/renderAttrib.h
  31. 150 0
      panda/src/pgraph/renderState.I
  32. 631 0
      panda/src/pgraph/renderState.cxx
  33. 172 0
      panda/src/pgraph/renderState.h
  34. 82 0
      panda/src/pgraph/test_pgraph.cxx
  35. 52 0
      panda/src/pgraph/textureAttrib.I
  36. 99 0
      panda/src/pgraph/textureAttrib.cxx
  37. 75 0
      panda/src/pgraph/textureAttrib.h

+ 54 - 0
panda/src/pgraph/Sources.pp

@@ -0,0 +1,54 @@
+#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
+                   dtoolutil:c dtoolbase:c dtool:m
+#define LOCAL_LIBS gobj putil graph linmath express pandabase
+
+#begin lib_target
+  #define TARGET pgraph
+  
+  #define SOURCES \
+    colorAttrib.h colorAttrib.I \
+    config_pgraph.h \
+    cycleData.h cycleData.I \
+    cycleDataReader.h cycleDataReader.I \
+    cycleDataWriter.h cycleDataWriter.I \
+    pandaNode.h pandaNode.I \
+    pipeline.h pipeline.I \
+    pipelineCycler.h pipelineCycler.I \
+    pipelineCyclerBase.h pipelineCyclerBase.I \
+    renderAttrib.h renderAttrib.I \
+    renderState.h renderState.I \
+    textureAttrib.h textureAttrib.I
+    
+// #define INCLUDED_SOURCES
+  #define SOURCES $[SOURCES] \
+    colorAttrib.cxx \
+    config_pgraph.cxx \
+    cycleData.cxx \
+    cycleDataReader.cxx \
+    cycleDataWriter.cxx \
+    pandaNode.cxx \
+    pipeline.cxx \
+    pipelineCycler.cxx \
+    pipelineCyclerBase.cxx \
+    renderAttrib.cxx \
+    renderState.cxx \
+    textureAttrib.cxx
+
+  #define INSTALL_HEADERS \
+    pandaNode.h pandaNode.I
+
+  #define IGATESCAN all
+
+#end lib_target
+
+
+#begin test_bin_target
+  #define TARGET test_pgraph
+
+  #define SOURCES \
+    test_pgraph.cxx
+
+  #define LOCAL_LIBS $[LOCAL_LIBS] pgraph
+  #define OTHER_LIBS $[OTHER_LIBS] pystub
+
+#end test_bin_target

+ 66 - 0
panda/src/pgraph/colorAttrib.I

@@ -0,0 +1,66 @@
+// Filename: colorAttrib.I
+// Created by:  drose (22Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::Constructor
+//       Access: Private
+//  Description: Use ColorAttrib::make() to construct a new
+//               ColorAttrib object.
+////////////////////////////////////////////////////////////////////
+INLINE ColorAttrib::
+ColorAttrib(ColorAttrib::Type type, const Colorf &color) :
+  _type(type),
+  _color(color)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::get_color_type
+//       Access: Published
+//  Description: Returns the type of color specified by this
+//               ColorAttrib.  The options are:
+//
+//                 T_vertex - use the vertex color specified in the
+//                 geometry itself.
+//
+//                 T_flat - use the color specified in this
+//                 ColorAttrib for all geometry.  You can get this
+//                 color via get_color().
+//
+//                 T_off - do not issue any color commands at all.
+//                 This is generally used only in contexts where the
+//                 color is meaningless, e.g. when drawing directly to
+//                 the depth buffer.
+////////////////////////////////////////////////////////////////////
+INLINE ColorAttrib::Type ColorAttrib::
+get_color_type() const {
+  return _type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::get_color
+//       Access: Published
+//  Description: If the type is T_flat, this returns the color that
+//               will be applied to geometry.  If the type is anything
+//               else, this is meaningless.
+////////////////////////////////////////////////////////////////////
+INLINE const Colorf &ColorAttrib::
+get_color() const {
+  return _color;
+}

+ 127 - 0
panda/src/pgraph/colorAttrib.cxx

@@ -0,0 +1,127 @@
+// Filename: colorAttrib.cxx
+// Created by:  drose (22Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "colorAttrib.h"
+#include "dcast.h"
+
+TypeHandle ColorAttrib::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::make_vertex
+//       Access: Published, Static
+//  Description: Constructs a new ColorAttrib object that indicates
+//               geometry should be rendered according to its own
+//               vertex color.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorAttrib::
+make_vertex() {
+  ColorAttrib *attrib = new ColorAttrib(T_vertex, Colorf(0.0f, 0.0f, 0.0f, 1.0f));
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::make_flat
+//       Access: Published, Static
+//  Description: Constructs a new ColorAttrib object that indicates
+//               geometry should be rendered in the indicated color.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorAttrib::
+make_flat(const Colorf &color) {
+  ColorAttrib *attrib = new ColorAttrib(T_flat, color);
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::make_off
+//       Access: Published, Static
+//  Description: Constructs a new ColorAttrib object that indicates
+//               geometry should be rendered without any color
+//               commands at all.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) ColorAttrib::
+make_off() {
+  ColorAttrib *attrib = new ColorAttrib(T_off, Colorf(0.0f, 0.0f, 0.0f, 1.0f));
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void ColorAttrib::
+output(ostream &out) const {
+  out << get_type() << ":";
+  switch (get_color_type()) {
+  case T_vertex:
+    out << "vertex";
+    break;
+
+  case T_flat:
+    out << "(" << get_color() << ")";
+    break;
+
+  case T_off:
+    out << "off";
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ColorAttrib
+//               types to return a unique number indicating whether
+//               this ColorAttrib is equivalent to the other one.
+//
+//               This should return 0 if the two ColorAttrib objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two ColorAttrib
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int ColorAttrib::
+compare_to_impl(const RenderAttrib *other) const {
+  const ColorAttrib *ta;
+  DCAST_INTO_R(ta, other, 0);
+  if (_type != ta->_type) {
+    return (int)_type - (int)ta->_type;
+  }
+  if (_type == T_flat) {
+    return _color.compare_to(ta->_color);
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::make_default_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived ColorAttrib
+//               types to specify what the default property for a
+//               ColorAttrib of this type should be.
+//
+//               This should return a newly-allocated ColorAttrib of
+//               the same type that corresponds to whatever the
+//               standard default for this kind of ColorAttrib is.
+////////////////////////////////////////////////////////////////////
+RenderAttrib *ColorAttrib::
+make_default_impl() const {
+  return new ColorAttrib(T_vertex, Colorf(0.0f, 0.0f, 0.0f, 1.0f));
+}

+ 81 - 0
panda/src/pgraph/colorAttrib.h

@@ -0,0 +1,81 @@
+// Filename: colorAttrib.h
+// Created by:  drose (22Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef COLORATTRIB_H
+#define COLORATTRIB_H
+
+#include "pandabase.h"
+
+#include "renderAttrib.h"
+#include "luse.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ColorAttrib
+// Description : Indicates what color should be applied to renderable
+//               geometry.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA ColorAttrib : public RenderAttrib {
+PUBLISHED:
+  enum Type {
+    T_vertex, T_flat, T_off
+  };
+
+private:
+  INLINE ColorAttrib(Type type, const Colorf &color);
+
+PUBLISHED:
+  static CPT(RenderAttrib) make_vertex();
+  static CPT(RenderAttrib) make_flat(const Colorf &color);
+  static CPT(RenderAttrib) make_off();
+
+  INLINE Type get_color_type() const;
+  INLINE const Colorf &get_color() const;
+
+public:
+  virtual void output(ostream &out) const;
+
+protected:
+  virtual int compare_to_impl(const RenderAttrib *other) const;
+  virtual RenderAttrib *make_default_impl() const;
+
+private:
+  Type _type;
+  Colorf _color;
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "ColorAttrib",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "colorAttrib.I"
+
+#endif
+

+ 61 - 0
panda/src/pgraph/config_pgraph.cxx

@@ -0,0 +1,61 @@
+// Filename: config_pgraph.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_pgraph.h"
+
+#include "colorAttrib.h"
+#include "pandaNode.h"
+#include "renderAttrib.h"
+#include "renderState.h"
+#include "textureAttrib.h"
+
+#include "dconfig.h"
+
+Configure(config_pgraph);
+NotifyCategoryDef(pgraph, "");
+
+ConfigureFn(config_pgraph) {
+  init_libpgraph();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libpgraph
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libpgraph() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  ColorAttrib::init_type();
+  PandaNode::init_type();
+  RenderAttrib::init_type();
+  RenderState::init_type();
+  TextureAttrib::init_type();
+
+  PandaNode::register_with_read_factory();
+  RenderState::register_with_read_factory();
+}

+ 29 - 0
panda/src/pgraph/config_pgraph.h

@@ -0,0 +1,29 @@
+// Filename: config_pgraph.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_PGRAPH_H
+#define CONFIG_PGRAPH_H
+
+#include "pandabase.h"
+#include "notifyCategoryProxy.h"
+
+NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA);
+
+extern EXPCL_PANDA void init_libpgraph();
+
+#endif

+ 27 - 0
panda/src/pgraph/cycleData.I

@@ -0,0 +1,27 @@
+// Filename: cycleData.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleData::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE CycleData::
+CycleData() {
+}

+ 29 - 0
panda/src/pgraph/cycleData.cxx

@@ -0,0 +1,29 @@
+// Filename: cycleData.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "cycleData.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleData::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData::
+~CycleData() {
+}

+ 44 - 0
panda/src/pgraph/cycleData.h

@@ -0,0 +1,44 @@
+// Filename: cycleData.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CYCLEDATA_H
+#define CYCLEDATA_H
+
+#include "pandabase.h"
+
+#include "referenceCount.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : CycleData
+// Description : A single page of data maintained by a PipelineCycler.
+//               Normally you should inherit from this class to define
+//               the data structures that are important to protect
+//               between stages of a pipeline.  See PipelineCycler.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA CycleData : public ReferenceCount {
+public:
+  INLINE CycleData();
+  virtual ~CycleData();
+
+  virtual CycleData *make_copy() const=0;
+};
+
+#include "cycleData.I"
+
+#endif
+

+ 68 - 0
panda/src/pgraph/cycleDataReader.I

@@ -0,0 +1,68 @@
+// Filename: cycleDataReader.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataReader::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataReader<CycleDataType>::
+CycleDataReader(const PipelineCycler<CycleDataType> &cycler) :
+  _cycler(cycler)
+{
+  _pointer = (const CycleDataType *)_cycler.read();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataReader::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataReader<CycleDataType>::
+CycleDataReader(const CycleDataReader<CycleDataType> &copy) :
+  _cycler(copy._cycler),
+  _pointer(copy._pointer)
+{
+  _cycler.increment_read(_pointer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataReader::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataReader<CycleDataType>::
+~CycleDataReader() {
+  _cycler.release_read(_pointer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataReader::operator ->
+//       Access: Public
+//  Description: This provides an indirect member access to the actual
+//               CycleData data.
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE const CycleDataType *CycleDataReader<CycleDataType>::
+operator -> () const {
+  return _pointer;
+}

+ 19 - 0
panda/src/pgraph/cycleDataReader.cxx

@@ -0,0 +1,19 @@
+// Filename: cycleDataReader.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "cycleDataReader.h"

+ 59 - 0
panda/src/pgraph/cycleDataReader.h

@@ -0,0 +1,59 @@
+// Filename: cycleDataReader.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CYCLEDATAREADER_H
+#define CYCLEDATAREADER_H
+
+#include "pandabase.h"
+
+#include "cycleData.h"
+#include "pipelineCycler.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : CycleDataReader
+// Description : This template class calls PipelineCycler::read() in
+//               the constructor and PipelineCycler::release_read() in
+//               the destructor.  In the interim, it provides a
+//               transparent read-only access to the CycleData.
+//
+//               It exists as a syntactic convenience to access the
+//               data in the CycleData.  It also allows the whole
+//               system to compile down to nothing if
+//               SUPPORT_PIPELINING is not defined.
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+class CycleDataReader {
+public:
+  INLINE CycleDataReader(const PipelineCycler<CycleDataType> &cycler);
+  INLINE CycleDataReader(const CycleDataReader<CycleDataType> &copy);
+
+  INLINE ~CycleDataReader();
+
+  INLINE const CycleDataType *operator -> () const;
+
+private:
+  const PipelineCycler<CycleDataType> &_cycler;
+  const CycleDataType *_pointer;
+};
+
+// This abbreviation macro is used for ease of typing.
+#define CDR(type) CycleDataReader< type >
+
+#include "cycleDataReader.I"
+
+#endif

+ 80 - 0
panda/src/pgraph/cycleDataWriter.I

@@ -0,0 +1,80 @@
+// Filename: cycleDataWriter.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataWriter::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataWriter<CycleDataType>::
+CycleDataWriter(PipelineCycler<CycleDataType> &cycler) :
+  _cycler(cycler)
+{
+  _pointer = (CycleDataType *)_cycler.write();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataWriter::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataWriter<CycleDataType>::
+CycleDataWriter(const CycleDataWriter<CycleDataType> &copy) :
+  _cycler(copy._cycler),
+  _pointer(copy._pointer)
+{
+  _cycler.increment_write(_pointer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataWriter::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataWriter<CycleDataType>::
+~CycleDataWriter() {
+  _cycler.release_write(_pointer);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataWriter::operator ->
+//       Access: Public
+//  Description: This provides an indirect member access to the actual
+//               CycleData data.
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE CycleDataType *CycleDataWriter<CycleDataType>::
+operator -> () {
+  return _pointer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CycleDataWriter::operator ->
+//       Access: Public
+//  Description: This provides an indirect member access to the actual
+//               CycleData data.
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE const CycleDataType *CycleDataWriter<CycleDataType>::
+operator -> () const {
+  return _pointer;
+}

+ 19 - 0
panda/src/pgraph/cycleDataWriter.cxx

@@ -0,0 +1,19 @@
+// Filename: cycleDataWriter.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "cycleDataWriter.h"

+ 59 - 0
panda/src/pgraph/cycleDataWriter.h

@@ -0,0 +1,59 @@
+// Filename: cycleDataWriter.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CYCLEDATAWRITER_H
+#define CYCLEDATAWRITER_H
+
+#include "pandabase.h"
+
+#include "cycleData.h"
+#include "pipelineCycler.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : CycleDataWriter
+// Description : This template class calls PipelineCycler::write() in
+//               the constructor and PipelineCycler::release_write() in
+//               the destructor.  In the interim, it provides a
+//               transparent read-write access to the CycleData.
+//
+//               It exists as a syntactic convenience to access the
+//               data in the CycleData.  It also allows the whole
+//               system to compile down to nothing if
+//               SUPPORT_PIPELINING is not defined.
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+class CycleDataWriter {
+public:
+  INLINE CycleDataWriter(PipelineCycler<CycleDataType> &cycler);
+  INLINE CycleDataWriter(const CycleDataWriter<CycleDataType> &copy);
+
+  INLINE ~CycleDataWriter();
+
+  INLINE CycleDataType *operator -> ();
+  INLINE const CycleDataType *operator -> () const;
+
+private:
+  PipelineCycler<CycleDataType> &_cycler;
+  CycleDataType *_pointer;
+};
+
+#define CDW(type) CycleDataWriter< type >
+
+#include "cycleDataWriter.I"
+
+#endif

+ 325 - 0
panda/src/pgraph/pandaNode.I

@@ -0,0 +1,325 @@
+// Filename: pandaNode.I
+// Created by:  drose (20Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::DownConnection::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::DownConnection::
+DownConnection(PandaNode *child, int sort) :
+  _child(child),
+  _sort(sort)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::DownConnection::operator <
+//       Access: Public
+//  Description: Provides a partial ordering on the children of a node
+//               so that they are ranked first in sort order, and then
+//               (by virtue of the ordered_vector) in the order they
+//               were added.
+////////////////////////////////////////////////////////////////////
+INLINE bool PandaNode::DownConnection::
+operator < (const DownConnection &other) const {
+  return _sort < other._sort;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::DownConnection::get_child
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode *PandaNode::DownConnection::
+get_child() const {
+  return _child;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::DownConnection::get_sort
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::DownConnection::
+get_sort() const {
+  return _sort;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::CData::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::CData::
+CData() {
+  _state_changes = RenderState::make_empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Children::
+Children(const PipelineCycler<PandaNode::CData> &cycler) :
+  _cdata(cycler)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Children::
+Children(const PandaNode::Children &copy) :
+  _cdata(copy._cdata)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::get_num_children
+//       Access: Public
+//  Description: Returns the number of children of the node.
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::Children::
+get_num_children() const {
+  return _cdata->_down.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Children::get_child
+//       Access: Public
+//  Description: Returns the nth child of the node.
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode *PandaNode::Children::
+get_child(int n) const {
+  nassertr(n >= 0 && n < (int)_cdata->_down.size(), NULL);
+  return _cdata->_down[n].get_child();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::
+PandaNode(const string &name) :
+  Namable(name)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_num_parents
+//       Access: Published
+//  Description: Returns the number of parent nodes this node has.  If
+//               this number is greater than 1, the node has been
+//               multiply instanced.  The order of the parent nodes is
+//               not meaningful and is not related to the order in
+//               which the node was instanced to them.
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::
+get_num_parents() const {
+  CDR(CData) cdata(_cycler);
+  return cdata->_up.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_parent
+//       Access: Published
+//  Description: Returns the nth parent node of this node.  See
+//               get_num_parents().
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode *PandaNode::
+get_parent(int n) const {
+  CDR(CData) cdata(_cycler);
+  nassertr(n >= 0 && n < (int)cdata->_up.size(), NULL);
+  return cdata->_up[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::find_parent
+//       Access: Published
+//  Description: Returns the index of the indicated parent node, if it
+//               is a parent, or -1 if it is not.
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::
+find_parent(PandaNode *node) const {
+  CDR(CData) cdata(_cycler);
+  Up::const_iterator ui = cdata->_up.find(node);
+  if (ui == cdata->_up.end()) {
+    return -1;
+  }
+  return ui - cdata->_up.begin();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_num_children
+//       Access: Published
+//  Description: Returns the number of child nodes this node has.  The
+//               order of the child nodes *is* meaningful and is based
+//               on the sort number that was passed to add_child(),
+//               and also on the order in which the nodes were added.
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::
+get_num_children() const {
+  CDR(CData) cdata(_cycler);
+  return cdata->_down.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_child
+//       Access: Published
+//  Description: Returns the nth child node of this node.  See
+//               get_num_children().
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode *PandaNode::
+get_child(int n) const {
+  CDR(CData) cdata(_cycler);
+  nassertr(n >= 0 && n < (int)cdata->_down.size(), NULL);
+  return cdata->_down[n].get_child();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_sort
+//       Access: Published
+//  Description: Returns the sort index of the nth child node of this
+//               node (that is, the number that was passed to
+//               add_child()).  See get_num_children().
+////////////////////////////////////////////////////////////////////
+INLINE int PandaNode::
+get_sort(int n) const {
+  CDR(CData) cdata(_cycler);
+  nassertr(n >= 0 && n < (int)cdata->_down.size(), -1);
+  return cdata->_down[n].get_sort();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::set_attrib
+//       Access: Published
+//  Description: Adds the indicated render attribute to the scene
+//               graph on this node.  This attribute will now apply to
+//               this node and everything below.  If there was already
+//               an attribute of the same type, it is replaced.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+set_attrib(const RenderAttrib *attrib, int override) {
+  CDW(CData) cdata(_cycler);
+  cdata->_state_changes = cdata->_state_changes->add(attrib, override);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_attrib
+//       Access: Published
+//  Description: Returns the render attribute of the indicated type,
+//               if it is defined on the node, or NULL if it is not.
+//               This checks only what is set on this particular node
+//               level, and has nothing to do with what render
+//               attributes may be inherited from parent nodes.
+////////////////////////////////////////////////////////////////////
+INLINE const RenderAttrib *PandaNode::
+get_attrib(TypeHandle type) const {
+  CDR(CData) cdata(_cycler);
+  int index = cdata->_state_changes->find_attrib(type);
+  if (index >= 0) {
+    return cdata->_state_changes->get_attrib(index);
+  }
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::clear_attrib
+//       Access: Published
+//  Description: Removes the render attribute of the given type from
+//               this node.  This node, and the subgraph below, will
+//               now inherit the indicated render attribute from the
+//               nodes above this one.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+clear_attrib(TypeHandle type) {
+  CDW(CData) cdata(_cycler);
+  cdata->_state_changes = cdata->_state_changes->remove(type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::set_state
+//       Access: Published
+//  Description: Sets the complete RenderState that will be applied to
+//               all nodes at this level and below.  (The actual state
+//               that will be applied to lower nodes is based on the
+//               composition of RenderStates from above this node as
+//               well).  This completely replaces whatever has been
+//               set on this node via repeated calls to set_attrib().
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+set_state(const RenderState *state) {
+  CDW(CData) cdata(_cycler);
+  cdata->_state_changes = state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_state
+//       Access: Published
+//  Description: Returns the complete RenderState that will be applied
+//               to all nodes at this level and below, as set on this
+//               node.  This returns only the RenderState set on this
+//               particular node, and has nothing to do with state
+//               that might be inherited from above.
+////////////////////////////////////////////////////////////////////
+INLINE const RenderState *PandaNode::
+get_state() const {
+  CDR(CData) cdata(_cycler);
+  return cdata->_state_changes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::clear_state
+//       Access: Published
+//  Description: Resets this node to leave the render state alone.
+//               Nodes at this level and below will once again inherit
+//               their render state unchanged from the nodes above
+//               this level.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+clear_state() {
+  CDW(CData) cdata(_cycler);
+  cdata->_state_changes = RenderState::make_empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_children
+//       Access: Public
+//  Description: Returns an object that can be used to walk through
+//               the list of children of the node.  When you intend to
+//               visit multiple children, using this is slightly
+//               faster than calling get_child() directly on the
+//               PandaNode, since this object keeps the PipelineCycler
+//               open the whole time.
+//
+//               However, this object does not protect you from
+//               self-modifying loops (e.g. adding or removing
+//               children during traversal).
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode::Children PandaNode::
+get_children() const {
+  return Children(_cycler);
+}
+

+ 295 - 0
panda/src/pgraph/pandaNode.cxx

@@ -0,0 +1,295 @@
+// Filename: pandaNode.cxx
+// Created by:  drose (20Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandaNode.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "indent.h"
+
+
+TypeHandle PandaNode::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::CData::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+PandaNode::CData::
+CData(const PandaNode::CData &copy) :
+  _down(copy._down),
+  _up(copy._up),
+  _node_bounds(copy._node_bounds),
+  _subgraph_bounds(copy._subgraph_bounds),
+  _state_changes(copy._state_changes)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::CData::make_copy
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData *PandaNode::CData::
+make_copy() const {
+  return new CData(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Copy Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+PandaNode::
+PandaNode(const PandaNode &copy) :
+  TypedWritable(copy),
+  Namable(copy),
+  ReferenceCount(copy)
+{
+  // Copying a node does not copy its children.
+
+  // Copy the other node's bounding volume.
+  CDR(CData) copy_cdata(copy._cycler);
+  CDW(CData) cdata(_cycler);
+  cdata->_node_bounds = copy_cdata->_node_bounds;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Copy Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+operator = (const PandaNode &copy) {
+  TypedWritable::operator = (copy);
+  Namable::operator = (copy);
+  ReferenceCount::operator = (copy);
+
+  // Copy the other node's bounding volume.
+  CDR(CData) copy_cdata(copy._cycler);
+  CDW(CData) cdata(_cycler);
+  cdata->_node_bounds = copy_cdata->_node_bounds;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+PandaNode::
+~PandaNode() {
+  // We shouldn't have any parents left by the time we destruct, or
+  // there's a refcount fault somewhere.
+  CDR(CData) cdata(_cycler);
+  nassertv(cdata->_up.empty());
+
+  remove_all_children();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::find_child
+//       Access: Published
+//  Description: Returns the index of the indicated child node, if it
+//               is a child, or -1 if it is not.
+////////////////////////////////////////////////////////////////////
+int PandaNode::
+find_child(PandaNode *node) const {
+  CDR(CData) cdata(_cycler);
+
+  // We have to search for the child by brute force, since we don't
+  // know what sort index it was added as.
+  Down::const_iterator ci;
+  for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
+    if ((*ci).get_child() == node) {
+      return ci - cdata->_down.begin();
+    }
+  }
+
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::add_child
+//       Access: Published
+//  Description: Adds a new child to the node.  The child is added in
+//               the relative position indicated by sort; if all
+//               children have the same sort index, the child is added
+//               at the end.
+//
+//               If the same child is added to a node more than once,
+//               the previous instance is first removed.
+//
+//               The return value is the index of the new child.
+////////////////////////////////////////////////////////////////////
+int PandaNode::
+add_child(PandaNode *child, int sort) {
+  remove_child(child);
+  CDW(CData) cdata(_cycler);
+  CDW(CData) cdata_child(child->_cycler);
+
+  Down::iterator ci = cdata->_down.insert(DownConnection(child, sort));
+  cdata_child->_up.insert(this);
+
+  return ci - cdata->_down.begin();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::remove_child
+//       Access: Published
+//  Description: Removes the nth child from the node.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+remove_child(int n) {
+  CDW(CData) cdata(_cycler);
+  nassertv(n >= 0 && n < (int)cdata->_down.size());
+
+  PandaNode *child = cdata->_down[n].get_child();
+  CDW(CData) cdata_child(child->_cycler);
+
+  cdata->_down.erase(cdata->_down.begin() + n);
+  int num_erased = cdata_child->_up.erase(this);
+  nassertv(num_erased == 1);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::remove_child
+//       Access: Published
+//  Description: Removes the indicated child from the node.  Returns
+//               true if the child was removed, false if it was not
+//               already a child of the node.
+////////////////////////////////////////////////////////////////////
+bool PandaNode::
+remove_child(PandaNode *child) {
+  CDW(CData) cdata_child(child->_cycler);
+
+  // First, look for and remove this node from the child's parent
+  // list.
+  int num_erased = cdata_child->_up.erase(this);
+  if (num_erased == 0) {
+    // No such node; it wasn't our child to begin with.
+    return false;
+  }
+
+  CDW(CData) cdata(_cycler);
+
+  // Now, look for and remove the child node from our down list.
+  Down::iterator ci;
+  for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
+    if ((*ci).get_child() == child) {
+      cdata->_down.erase(ci);
+      return true;
+    }
+  }
+
+  // We shouldn't get here unless there was a parent-child mismatch.
+  nassertr(false, false);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::remove_all_children
+//       Access: Published
+//  Description: Removes all the children from the node at once.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+remove_all_children() {
+  CDW(CData) cdata(_cycler);
+  Down::iterator ci;
+  for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) {
+    PandaNode *child = (*ci).get_child();
+    CDW(CData) child_cdata(child->_cycler);
+    child_cdata->_up.erase(this);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::output
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+output(ostream &out) const {
+  out << get_type() << " " << get_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::write
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << *this;
+  CDR(CData) cdata(_cycler);
+  if (!cdata->_state_changes->is_empty()) {
+    out << " (" << *cdata->_state_changes << ")";
+  }
+  out << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               PandaNode.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+write_datagram(BamWriter *manager, Datagram &dg) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type PandaNode is encountered
+//               in the Bam file.  It should create the PandaNode
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *PandaNode::
+make_from_bam(const FactoryParams &params) {
+  PandaNode *node = new PandaNode("");
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  node->fillin(scan, manager);
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new PandaNode.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+fillin(DatagramIterator &scan, BamReader *manager) {
+}

+ 175 - 0
panda/src/pgraph/pandaNode.h

@@ -0,0 +1,175 @@
+// Filename: pandaNode.h
+// Created by:  drose (20Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PANDANODE_H
+#define PANDANODE_H
+
+#include "pandabase.h"
+
+#include "cycleData.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "pipelineCycler.h"
+#include "renderState.h"
+
+#include "typedWritable.h"
+#include "boundedObject.h"
+#include "namable.h"
+#include "referenceCount.h"
+#include "luse.h"
+#include "ordered_vector.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : PandaNode
+// Description : A basic node of the scene graph or data graph.  This
+//               is the base class of all specialized nodes, and also
+//               serves as a generic node with no special properties.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PandaNode : public TypedWritable, 
+                              public Namable, virtual public ReferenceCount {
+PUBLISHED:
+  INLINE PandaNode(const string &name);
+  PandaNode(const PandaNode &copy);
+  void operator = (const PandaNode &copy);
+  virtual ~PandaNode();
+
+  INLINE int get_num_parents() const;
+  INLINE PandaNode *get_parent(int n) const;
+  INLINE int find_parent(PandaNode *node) const;
+
+  INLINE int get_num_children() const;
+  INLINE PandaNode *get_child(int n) const;
+  INLINE int get_sort(int n) const;
+  int find_child(PandaNode *node) const;
+
+  int add_child(PandaNode *child, int sort = 0);
+  void remove_child(int n);
+  bool remove_child(PandaNode *child);
+
+  void remove_all_children();
+
+  INLINE void set_attrib(const RenderAttrib *attrib, int override = 0);
+  INLINE const RenderAttrib *get_attrib(TypeHandle type) const;
+  INLINE void clear_attrib(TypeHandle type);
+
+  INLINE void set_state(const RenderState *state);
+  INLINE const RenderState *get_state() const;
+  INLINE void clear_state();
+
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level) const;
+
+private:
+  class DownConnection {
+  public:
+    INLINE DownConnection(PandaNode *child, int sort);
+    INLINE bool operator < (const DownConnection &other) const;
+    INLINE PandaNode *get_child() const;
+    INLINE int get_sort() const;
+
+  private:
+    // Child pointers are reference counted.  That way, holding a
+    // pointer to the root of a subgraph keeps the entire subgraph
+    // around.
+    PT(PandaNode) _child;
+    int _sort;
+  };
+  typedef ov_multiset<DownConnection> Down;
+  // Parent pointers are not reference counted.  That way, parents and
+  // children do not circularly reference each other.  In fact, parent
+  // pointers are just simple pointers, with no additional data.  We
+  // don't really need to keep the parent pointers around, but it's
+  // nice to be able to walk up the graph.
+  typedef ov_set<PandaNode *> Up;
+
+  // This is the data that must be cycled between pipeline stages.
+  class CData : public CycleData {
+  public:
+    INLINE CData();
+    CData(const CData &copy);
+    virtual CycleData *make_copy() const;
+
+    Down _down;
+    Up _up;
+
+    BoundedObject _node_bounds;
+    BoundedObject _subgraph_bounds;
+    CPT(RenderState) _state_changes;
+  };
+
+  PipelineCycler<CData> _cycler;
+
+public:
+  // Use this interface when you want to walk through the list of
+  // children.  This saves a tiny bit of overhead between each step,
+  // by keeping the PipelineCycler open for reading the whole time.
+  // However, it does not protect you from self-modifying loops.
+  class Children {
+  public:
+    INLINE Children(const PipelineCycler<CData> &cycler);
+    INLINE Children(const Children &copy);
+
+    INLINE int get_num_children() const;
+    INLINE PandaNode *get_child(int n) const;
+
+  private:
+    CDR(CData) _cdata;
+  };
+
+  INLINE Children get_children() const;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritable::init_type();
+    ReferenceCount::init_type();
+    register_type(_type_handle, "PandaNode",
+                  TypedWritable::get_class_type(),
+                  ReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class PandaNode::Children;
+};
+
+INLINE ostream &operator << (ostream &out, const PandaNode &node) {
+  node.output(out);
+  return out;
+}
+
+#include "pandaNode.I"
+
+#endif
+

+ 31 - 0
panda/src/pgraph/pipeline.I

@@ -0,0 +1,31 @@
+// Filename: pipeline.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::get_render_pipeline
+//       Access: Public, Static
+//  Description: Returns a pointer to the global render pipeline.
+////////////////////////////////////////////////////////////////////
+INLINE Pipeline *Pipeline::
+get_render_pipeline() {
+  if (_render_pipeline == (Pipeline *)NULL) {
+    make_render_pipeline();
+  }
+  return _render_pipeline;
+}

+ 74 - 0
panda/src/pgraph/pipeline.cxx

@@ -0,0 +1,74 @@
+// Filename: pipeline.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pipeline.h"
+
+Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL;
+
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+Pipeline::
+Pipeline(const string &name) :
+  Namable(name)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+Pipeline::
+~Pipeline() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::cycle
+//       Access: Public
+//  Description: Flows all the pipeline data down to the next stage.
+////////////////////////////////////////////////////////////////////
+void Pipeline::
+cycle() {
+  pre_cycle();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::pre_cycle
+//       Access: Protected, Virtual
+//  Description: A callback function intended to be overridden by a
+//               derived class to perform whatever operations should
+//               be done before cycling the pipeline.
+////////////////////////////////////////////////////////////////////
+void Pipeline::
+pre_cycle() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::make_render_pipeline
+//       Access: Private, Static
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void Pipeline::
+make_render_pipeline() {
+  nassertv(_render_pipeline == (Pipeline *)NULL);
+  _render_pipeline = new Pipeline("render");
+}
+

+ 58 - 0
panda/src/pgraph/pipeline.h

@@ -0,0 +1,58 @@
+// Filename: pipeline.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PIPELINE_H
+#define PIPELINE_H
+
+#include "pandabase.h"
+#include "namable.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Pipeline
+// Description : This class manages a staged pipeline of data, for
+//               instance the render pipeline, so that each stage of
+//               the pipeline can simultaneously access different
+//               copies of the same data.  It actually maintains a
+//               collection of PipelineCycler objects, and manages the
+//               turning of all of them at once.
+//
+//               There is one default Pipeline object, the render
+//               pipeline.  Other specialty pipelines may be created
+//               as needed.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA Pipeline : public Namable {
+public:
+  Pipeline(const string &name);
+  virtual ~Pipeline();
+
+  INLINE static Pipeline *get_render_pipeline();
+
+  void cycle();
+
+protected:
+  virtual void pre_cycle();
+
+private:
+  static void make_render_pipeline();
+  static Pipeline *_render_pipeline;
+};
+
+#include "pipeline.I"
+
+#endif
+

+ 30 - 0
panda/src/pgraph/pipelineCycler.I

@@ -0,0 +1,30 @@
+// Filename: pipelineCycler.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCycler::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+INLINE PipelineCycler<CycleDataType>::
+PipelineCycler(Pipeline *pipeline) :
+  PipelineCyclerBase(new CycleDataType, pipeline)
+{
+}

+ 19 - 0
panda/src/pgraph/pipelineCycler.cxx

@@ -0,0 +1,19 @@
+// Filename: pipelineCycler.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pipelineCycler.h"

+ 61 - 0
panda/src/pgraph/pipelineCycler.h

@@ -0,0 +1,61 @@
+// Filename: pipelineCycler.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PIPELINECYCLER_H
+#define PIPELINECYCLER_H
+
+#include "pandabase.h"
+
+#include "pipelineCyclerBase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : PipelineCycler
+// Description : This class maintains different copies of a page of
+//               data between stages of the graphics pipeline (or any
+//               other pipelining context).
+//
+//               The class object maintains up to n copies of a
+//               CycleData structure, one for each stage of the
+//               pipeline.  The head of the pipeline is responsible
+//               for making changes to its copy, which are then cycled
+//               through the pipeline at each frame.
+//
+//               To access the data, you must first ask for a readable
+//               pointer.  In order to make changes to the data, you
+//               must ask for a writable pointer.  Both kinds of
+//               pointers should be released when you are done, as a
+//               sanity check.  The CycleDataReader and
+//               CycleDataWriter classes transparently handle this.
+//
+//               If pipelining support is not enabled at compile time
+//               (that is, SUPPORT_PIPELINING is not defined), this
+//               object compiles to a minimum object that presents the
+//               same interface but with minimal runtime overhead.
+//               (Actually, this isn't true yet, but it will be one
+//               day.)
+////////////////////////////////////////////////////////////////////
+template<class CycleDataType>
+class PipelineCycler : public PipelineCyclerBase {
+public:
+  INLINE PipelineCycler(Pipeline *pipeline = NULL);
+};
+
+#include "pipelineCycler.I"
+
+#endif
+

+ 109 - 0
panda/src/pgraph/pipelineCyclerBase.I

@@ -0,0 +1,109 @@
+// Filename: pipelineCyclerBase.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::read
+//       Access: Public
+//  Description: Returns a const CycleData pointer, filled with the
+//               data for the current stage of the pipeline as seen by
+//               this thread.  This pointer should eventually be
+//               released by calling release_read().
+////////////////////////////////////////////////////////////////////
+INLINE const CycleData *PipelineCyclerBase::
+read() const {
+  // This function isn't truly const, but it doesn't change the data
+  // in any meaningful way, so we pretend it is.
+  ((PipelineCyclerBase *)this)->_read_count++;
+  return _data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::increment_read
+//       Access: Public
+//  Description: Increments the count on a pointer previously
+//               retrieved by read(); now the pointer will need to be
+//               released twice.
+////////////////////////////////////////////////////////////////////
+INLINE void PipelineCyclerBase::
+increment_read(const CycleData *pointer) const {
+  // This function isn't truly const, but it doesn't change the data
+  // in any meaningful way, so we pretend it is.
+  nassertv(pointer == _data);
+  nassertv(_read_count > 0);
+  ((PipelineCyclerBase *)this)->_read_count++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::release_read
+//       Access: Public
+//  Description: Releases a pointer previously obtained via a call to
+//               read().
+////////////////////////////////////////////////////////////////////
+INLINE void PipelineCyclerBase::
+release_read(const CycleData *pointer) const {
+  // This function isn't truly const, but it doesn't change the data
+  // in any meaningful way, so we pretend it is.
+  nassertv(pointer == _data);
+  nassertv(_read_count > 0);
+  ((PipelineCyclerBase *)this)->_read_count--;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::write
+//       Access: Public
+//  Description: Returns a non-const CycleData pointer, filled with a
+//               unique copy of the data for the current stage of the
+//               pipeline as seen by this thread.  This pointer may
+//               now be used to write to the data, and that copy of
+//               the data will be propagate to all later stages of the
+//               pipeline.  This pointer should eventually be released
+//               by calling release_write().
+////////////////////////////////////////////////////////////////////
+INLINE CycleData *PipelineCyclerBase::
+write() {
+  _write_count++;
+  return _data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::increment_write
+//       Access: Public
+//  Description: Increments the count on a pointer previously
+//               retrieved by write(); now the pointer will need to be
+//               released twice.
+////////////////////////////////////////////////////////////////////
+INLINE void PipelineCyclerBase::
+increment_write(CycleData *pointer) {
+  nassertv(pointer == _data);
+  nassertv(_write_count > 0);
+  _write_count++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::release_write
+//       Access: Public
+//  Description: Releases a pointer previously obtained via a call to
+//               write().
+////////////////////////////////////////////////////////////////////
+INLINE void PipelineCyclerBase::
+release_write(CycleData *pointer) {
+  nassertv(pointer == _data);
+  nassertv(_write_count > 0);
+  _write_count--;
+}

+ 48 - 0
panda/src/pgraph/pipelineCyclerBase.cxx

@@ -0,0 +1,48 @@
+// Filename: pipelineCyclerBase.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pipelineCyclerBase.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PipelineCyclerBase::
+PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline) :
+  _data(initial_data),
+  _pipeline(pipeline),
+  _read_count(0),
+  _write_count(0)
+{
+  if (_pipeline == (Pipeline *)NULL) {
+    _pipeline = Pipeline::get_render_pipeline();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerBase::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PipelineCyclerBase::
+~PipelineCyclerBase() {
+  nassertv(_read_count == 0 && _write_count == 0);
+}
+

+ 55 - 0
panda/src/pgraph/pipelineCyclerBase.h

@@ -0,0 +1,55 @@
+// Filename: pipelineCyclerBase.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PIPELINECYCLERBASE_H
+#define PIPELINECYCLERBASE_H
+
+#include "pandabase.h"
+
+#include "cycleData.h"
+#include "pipeline.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : PipelineCyclerBase
+// Description : This is the non-template part of the implementation
+//               of PipelineCycler.  See PipelineCycler.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PipelineCyclerBase {
+public:
+  PipelineCyclerBase(CycleData *initial_data, Pipeline *pipeline = NULL);
+  ~PipelineCyclerBase();
+
+  INLINE const CycleData *read() const;
+  INLINE void increment_read(const CycleData *pointer) const;
+  INLINE void release_read(const CycleData *pointer) const;
+
+  INLINE CycleData *write();
+  INLINE void increment_write(CycleData *pointer);
+  INLINE void release_write(CycleData *pointer);
+
+private:
+  PT(CycleData) _data;
+  Pipeline *_pipeline;
+  short _read_count, _write_count;
+};
+
+#include "pipelineCyclerBase.I"
+
+#endif
+

+ 73 - 0
panda/src/pgraph/renderAttrib.I

@@ -0,0 +1,73 @@
+// Filename: renderAttrib.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::compose
+//       Access: Public
+//  Description: Returns a new RenderAttrib object that represents the
+//               composition of this attrib with the other attrib.  In
+//               most cases, this is the same as the other attrib; a
+//               compose b produces b.  Some kinds of attributes, like
+//               a TextureTransform, for instance, might produce a new
+//               result: a compose b produces c.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderAttrib) RenderAttrib::
+compose(const RenderAttrib *other) const {
+  return compose_impl(other);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::make_default
+//       Access: Public
+//  Description: Returns a different (or possibly the same)
+//               RenderAttrib pointer of the same type as this one
+//               that corresponds to whatever the standard default
+//               properties for render attributes of this type ought
+//               to be.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderAttrib) RenderAttrib::
+make_default() const {
+  return return_new(make_default_impl());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::compare_to
+//       Access: Public
+//  Description: Provides an arbitrary ordering among all unique
+//               RenderAttribs, so we can store the essentially
+//               different ones in a big set and throw away the rest.
+//
+//               This method is not needed outside of the RenderAttrib
+//               class because all equivalent RenderAttrib objects are
+//               guaranteed to share the same pointer; thus, a pointer
+//               comparison is always sufficient.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderAttrib::
+compare_to(const RenderAttrib &other) const {
+  // First, we compare the types; if they are of different types then
+  // they sort differently.
+  TypeHandle type = get_type();
+  TypeHandle other_type = other.get_type();
+  if (type != other_type) {
+    return type.get_index() - other_type.get_index();
+  }
+
+  // We only call compare_to_impl() if they have the same type.
+  return compare_to_impl(&other);
+}

+ 240 - 0
panda/src/pgraph/renderAttrib.cxx

@@ -0,0 +1,240 @@
+// Filename: renderAttrib.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "renderAttrib.h"
+#include "bamReader.h"
+#include "indent.h"
+
+RenderAttrib::Attribs RenderAttrib::_attribs;
+TypeHandle RenderAttrib::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::Constructor
+//       Access: Protected
+//  Description:
+////////////////////////////////////////////////////////////////////
+RenderAttrib::
+RenderAttrib() {
+  _saved_entry = _attribs.end();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::Copy Constructor
+//       Access: Private
+//  Description: RenderAttribs are not meant to be copied.
+////////////////////////////////////////////////////////////////////
+RenderAttrib::
+RenderAttrib(const RenderAttrib &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::Copy Assignment Operator
+//       Access: Private
+//  Description: RenderAttribs are not meant to be copied.
+////////////////////////////////////////////////////////////////////
+void RenderAttrib::
+operator = (const RenderAttrib &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::Destructor
+//       Access: Public, Virtual
+//  Description: The destructor is responsible for removing the
+//               RenderAttrib from the global set if it is there.
+////////////////////////////////////////////////////////////////////
+RenderAttrib::
+~RenderAttrib() {
+  if (_saved_entry != _attribs.end()) {
+    _attribs.erase(_saved_entry);
+    _saved_entry = _attribs.end();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void RenderAttrib::
+output(ostream &out) const {
+  out << get_type();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void RenderAttrib::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << *this << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::return_new
+//       Access: Protected, Static
+//  Description: This function is used by derived RenderAttrib types
+//               to share a common RenderAttrib pointer for all
+//               equivalent RenderAttrib objects.
+//
+//               The make() function of the derived type should create
+//               a new RenderAttrib and pass it through return_new(),
+//               which will either save the pointer and return it
+//               unchanged (if this is the first similar such object)
+//               or delete it and return an equivalent pointer (if
+//               there was already a similar object saved).
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) RenderAttrib::
+return_new(RenderAttrib *attrib) {
+  nassertr(attrib != (RenderAttrib *)NULL, attrib);
+
+  // This should be a newly allocated pointer, not one that was used
+  // for anything else.
+  nassertr(attrib->_saved_entry == _attribs.end(), attrib);
+
+  // Save the attrib in a local PointerTo so that it will be freed at
+  // the end of this function if no one else uses it.
+  CPT(RenderAttrib) pt_attrib = attrib;
+
+  pair<Attribs::iterator, bool> result = _attribs.insert(attrib);
+  if (result.second) {
+    // The attribute was inserted; save the iterator and return the
+    // input attribute.
+    attrib->_saved_entry = result.first;
+    return pt_attrib;
+  }
+
+  // The attribute was not inserted; there must be an equivalent one
+  // already in the set.  Return that one.
+  return *(result.first);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived RenderAttrib
+//               types to return a unique number indicating whether
+//               this RenderAttrib is equivalent to the other one.
+//
+//               This should return 0 if the two RenderAttrib objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two RenderAttrib
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int RenderAttrib::
+compare_to_impl(const RenderAttrib *other) const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::compose_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived RenderAttrib
+//               types to specify how two consecutive RenderAttrib
+//               objects of the same type interact.
+//
+//               This should return the result of applying the other
+//               RenderAttrib to a node in the scene graph below this
+//               RenderAttrib, which was already applied.  In most
+//               cases, the result is the same as the other
+//               RenderAttrib (that is, a subsequent RenderAttrib
+//               completely replaces the preceding one).  On the other
+//               hand, some kinds of RenderAttrib (for instance,
+//               TextureTransform) might combine in meaningful ways.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) RenderAttrib::
+compose_impl(const RenderAttrib *other) const {
+  return other;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::make_default_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived RenderAttrib
+//               types to specify what the default property for a
+//               RenderAttrib of this type should be.
+//
+//               This should return a newly-allocated RenderAttrib of
+//               the same type that corresponds to whatever the
+//               standard default for this kind of RenderAttrib is.
+////////////////////////////////////////////////////////////////////
+RenderAttrib *RenderAttrib::
+make_default_impl() const {
+  return (RenderAttrib *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void RenderAttrib::
+write_datagram(BamWriter *, Datagram &) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::finalize
+//       Access: Public, Virtual
+//  Description: Method to ensure that any necessary clean up tasks
+//               that have to be performed by this object are performed
+////////////////////////////////////////////////////////////////////
+void RenderAttrib::
+finalize() {
+  // Unref the pointer that we explicitly reffed in make_from_bam().
+  unref();
+
+  // We should never get back to zero after unreffing our own count,
+  // because we expect to have been stored in a pointer somewhere.  If
+  // we do get to zero, it's a memory leak; the way to avoid this is
+  // to call unref_delete() above instead of unref(), but this is
+  // dangerous to do from within a virtual function.
+  nassertv(get_ref_count() != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::new_from_bam
+//       Access: Protected, Static
+//  Description: Uniquifies the pointer for a RenderAttrib object just
+//               created from a bam file, and preserves its reference
+//               count correctly.
+////////////////////////////////////////////////////////////////////
+TypedWritable *RenderAttrib::
+new_from_bam(RenderAttrib *attrib, BamReader *manager) {
+  // First, uniquify the pointer.
+  CPT(RenderAttrib) pointer = return_new(attrib);
+
+  // But now we have a problem, since we have to hold the reference
+  // count and there's no way to return a TypedWritable while still
+  // holding the reference count!  We work around this by explicitly
+  // upping the count, and also setting a finalize() callback to down
+  // it later.
+  if (pointer == attrib) {
+    pointer->ref();
+    manager->register_finalize(attrib);
+  }
+  
+  // We have to cast the pointer back to non-const, because the bam
+  // reader expects that.
+  return (RenderAttrib *)pointer.p();
+}

+ 110 - 0
panda/src/pgraph/renderAttrib.h

@@ -0,0 +1,110 @@
+// Filename: renderAttrib.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef RENDERATTRIB_H
+#define RENDERATTRIB_H
+
+#include "pandabase.h"
+
+#include "typedWritableReferenceCount.h"
+#include "indirectCompareTo.h"
+#include "pointerTo.h"
+#include "pset.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : RenderAttrib
+// Description : This is the base class for a number of render
+//               attributes (other than transform) that may be set on
+//               scene graph nodes to control the appearance of
+//               geometry.  This includes TextureAttrib, ColorAttrib,
+//               etc.
+//
+//               You should not attempt to create or modify a
+//               RenderAttrib directly; instead, use the make() method
+//               of the appropriate kind of attrib you want.  This
+//               will allocate and return a new RenderAttrib of the
+//               appropriate type, and it may share pointers if
+//               possible.  Do not modify the new RenderAttrib if you
+//               wish to change its properties; instead, create a new
+//               one.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA RenderAttrib : public TypedWritableReferenceCount {
+protected:
+  RenderAttrib();
+private:
+  RenderAttrib(const RenderAttrib &copy);
+  void operator = (const RenderAttrib &copy);
+
+public:
+  virtual ~RenderAttrib();
+
+  INLINE CPT(RenderAttrib) compose(const RenderAttrib *other) const;
+  INLINE CPT(RenderAttrib) make_default() const;
+  INLINE int compare_to(const RenderAttrib &other) const;
+
+PUBLISHED:
+  virtual void output(ostream &out) const;
+  virtual void write(ostream &out, int indent_level) const;
+
+protected:
+  static CPT(RenderAttrib) return_new(RenderAttrib *attrib);
+
+  virtual int compare_to_impl(const RenderAttrib *other) const;
+  virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const;
+  virtual RenderAttrib *make_default_impl() const=0;
+
+private:
+  typedef pset<const RenderAttrib *, IndirectCompareTo<RenderAttrib> > Attribs;
+  static Attribs _attribs;
+
+  Attribs::iterator _saved_entry;
+
+public:
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual void finalize();
+
+protected:
+  static TypedWritable *new_from_bam(RenderAttrib *attrib, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "RenderAttrib",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const RenderAttrib &attrib) {
+  attrib.output(out);
+  return out;
+}
+
+#include "renderAttrib.I"
+
+#endif
+

+ 150 - 0
panda/src/pgraph/renderState.I

@@ -0,0 +1,150 @@
+// Filename: renderState.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Attribute::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE RenderState::Attribute::
+Attribute(const RenderAttrib *attrib, int override) :
+  _type(attrib->get_type()),
+  _attrib(attrib),
+  _override(override)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Attribute::Constructor
+//       Access: Public
+//  Description: This constructor makes an invalid Attribute with no
+//               RenderAttrib pointer; its purpose is just to make an
+//               object we can use to look up a particular type in the
+//               Attribute set.
+////////////////////////////////////////////////////////////////////
+INLINE RenderState::Attribute::
+Attribute(TypeHandle type) :
+  _type(type),
+  _attrib(NULL),
+  _override(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Attribute::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE RenderState::Attribute::
+Attribute(const Attribute &copy) :
+  _type(copy._type),
+  _attrib(copy._attrib),
+  _override(copy._override)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Attribute::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void RenderState::Attribute::
+operator = (const Attribute &copy) {
+  _type = copy._type;
+  _attrib = copy._attrib;
+  _override = copy._override;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Attribute::operator <
+//       Access: Public
+//  Description: This is used by the Attributes set to uniquify
+//               RenderAttributes by type.  Only one RenderAttrib of a
+//               given type is allowed in the set.  This ordering must
+//               also match the ordering reported by compare_to().
+////////////////////////////////////////////////////////////////////
+INLINE bool RenderState::Attribute::
+operator < (const Attribute &other) const {
+  return _type < other._type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Attribute::compare_to
+//       Access: Public
+//  Description: Provides an indication of whether a particular
+//               attribute is equivalent to another one, for purposes
+//               of generating unique RenderStates.  This should
+//               compare all properties of the Attribute, but it is
+//               important that the type is compared first, to be
+//               consistent with the ordering defined by operator <.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::Attribute::
+compare_to(const Attribute &other) const {
+  if (_type != other._type) {
+    return _type.get_index() - other._type.get_index();
+  }
+  if (_attrib != other._attrib) {
+    return _attrib - other._attrib;
+  }
+  return _override - other._override;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::is_empty
+//       Access: Published
+//  Description: Returns true if the state is empty, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool RenderState::
+is_empty() const {
+  return _attributes.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_num_attribs
+//       Access: Published
+//  Description: Returns the number of separate attributes indicated
+//               in the state.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+get_num_attribs() const {
+  return _attributes.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_attrib
+//       Access: Published
+//  Description: Returns the nth attribute in the state.
+////////////////////////////////////////////////////////////////////
+INLINE const RenderAttrib *RenderState::
+get_attrib(int n) const {
+  nassertr(n >= 0 && n < (int)_attributes.size(), NULL);
+  return _attributes[n]._attrib;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_override
+//       Access: Published
+//  Description: Returns the override associated with the nth
+//               attribute in the state.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+get_override(int n) const {
+  nassertr(n >= 0 && n < (int)_attributes.size(), 0);
+  return _attributes[n]._override;
+}

+ 631 - 0
panda/src/pgraph/renderState.cxx

@@ -0,0 +1,631 @@
+// Filename: renderState.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "renderState.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagramIterator.h"
+#include "indent.h"
+#include "compareTo.h"
+
+RenderState::States RenderState::_states;
+CPT(RenderState) RenderState::_empty_state;
+TypeHandle RenderState::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Constructor
+//       Access: Protected
+//  Description: Actually, this could be a private constructor, since
+//               no one inherits from RenderState, but gcc gives us a
+//               spurious warning if all constructors are private.
+////////////////////////////////////////////////////////////////////
+RenderState::
+RenderState() {
+  _saved_entry = _states.end();
+  _self_compose = (RenderState *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Copy Constructor
+//       Access: Private
+//  Description: RenderStates are not meant to be copied.
+////////////////////////////////////////////////////////////////////
+RenderState::
+RenderState(const RenderState &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Copy Assignment Operator
+//       Access: Private
+//  Description: RenderStates are not meant to be copied.
+////////////////////////////////////////////////////////////////////
+void RenderState::
+operator = (const RenderState &) {
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::Destructor
+//       Access: Public, Virtual
+//  Description: The destructor is responsible for removing the
+//               RenderState from the global set if it is there.
+////////////////////////////////////////////////////////////////////
+RenderState::
+~RenderState() {
+  // Remove the deleted RenderState object from the global pool.
+  if (_saved_entry != _states.end()) {
+    _states.erase(_saved_entry);
+    _saved_entry = _states.end();
+    
+    cerr << "Removing " << (void *)this << ", " << _states.size()
+         << " remaining.\n";
+  }
+
+  // Now make sure we clean up all other floating pointers to the
+  // RenderState.  These may be scattered around in the various
+  // CompositionCaches from other RenderState objects.
+
+  // Fortunately, since we added CompositionCache records in pairs, we
+  // know exactly the set of RenderState objects that have us in their
+  // cache: it's the same set of RenderState objects that we have in
+  // our own cache.
+
+  // We do need to put some thought into this loop, because as we
+  // clear out cache entries we'll cause other RenderState objects to
+  // destruct, which could cause things to get pulled out of our own
+  // _composition_cache map.  We don't want to get bitten by this
+  // cascading effect.
+  CompositionCache::iterator ci;
+  ci = _composition_cache.begin();
+  while (ci != _composition_cache.end()) {
+    {
+      PT(RenderState) other = (RenderState *)(*ci).first;
+      Composition comp = (*ci).second;
+
+      // We should never have a reflexive entry in this map.  If we
+      // do, something got screwed up elsewhere.
+      nassertv(other != this);
+      
+      // Now we're holding a reference count to the other state, as well
+      // as to the computed result (if any), so neither object will be
+      // tempted to destruct.  Go ahead and remove ourselves from the
+      // other cache.
+      other->_composition_cache.erase(this);
+
+      // It's all right if the other state destructs now, since it
+      // won't try to remove itself from our own composition cache any
+      // more.  Someone might conceivably delete the *next* entry,
+      // though, so we should be sure to let all that deleting finish
+      // up before we attempt to increment ci, by closing the scope
+      // here.
+    }
+    // Now it's safe to increment ci, because the current cache entry
+    // has not gone away, and if the next one has, by now it's safely
+    // gone.
+    ++ci;
+  }
+
+  // Also, if we called compose(this) at some point and the return
+  // value was something other than this, we need to decrement the
+  // associated reference count.
+  if (_self_compose != (RenderState *)NULL && _self_compose != this) {
+    unref_delete((RenderState *)_self_compose);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::operator <
+//       Access: Public
+//  Description: Provides an arbitrary ordering among all unique
+//               RenderStates, so we can store the essentially
+//               different ones in a big set and throw away the rest.
+//
+//               This method is not needed outside of the RenderState
+//               class because all equivalent RenderState objects are
+//               guaranteed to share the same pointer; thus, a pointer
+//               comparison is always sufficient.
+////////////////////////////////////////////////////////////////////
+bool RenderState::
+operator < (const RenderState &other) const {
+  // We must compare all the properties of the attributes, not just
+  // the type; thus, we compare them one at a time using compare_to().
+  return lexicographical_compare(_attributes.begin(), _attributes.end(),
+                                 other._attributes.begin(), other._attributes.end(),
+                                 CompareTo<Attribute>());
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::find_attrib
+//       Access: Published
+//  Description: Searches for an attribute with the indicated type in
+//               the state, and returns its index if it is found, or
+//               -1 if it is not.
+////////////////////////////////////////////////////////////////////
+int RenderState::
+find_attrib(TypeHandle type) const {
+  Attributes::const_iterator ai = _attributes.find(Attribute(type));
+  if (ai == _attributes.end()) {
+    return -1;
+  }
+  return ai - _attributes.begin();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make_empty
+//       Access: Published, Static
+//  Description: Returns a RenderState with no attributes set.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+make_empty() {
+  // The empty state is asked for so often, we make it a special case
+  // and store a pointer forever once we find it the first time.
+  if (_empty_state == (RenderState *)NULL) {
+    RenderState *state = new RenderState;
+    _empty_state = return_new(state);
+  }
+
+  return _empty_state;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make
+//       Access: Published, Static
+//  Description: Returns a RenderState with one attribute set.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+make(const RenderAttrib *attrib, int override) {
+  RenderState *state = new RenderState;
+  state->_attributes.reserve(1);
+  state->_attributes.insert(Attribute(attrib, override));
+  return return_new(state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make
+//       Access: Published, Static
+//  Description: Returns a RenderState with two attributes set.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+make(const RenderAttrib *attrib1,
+     const RenderAttrib *attrib2, int override) {
+  RenderState *state = new RenderState;
+  state->_attributes.reserve(2);
+  state->_attributes.push_back(Attribute(attrib1, override));
+  state->_attributes.push_back(Attribute(attrib2, override));
+  state->_attributes.sort();
+  return return_new(state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make
+//       Access: Published, Static
+//  Description: Returns a RenderState with three attributes set.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+make(const RenderAttrib *attrib1,
+     const RenderAttrib *attrib2,
+     const RenderAttrib *attrib3, int override) {
+  RenderState *state = new RenderState;
+  state->_attributes.reserve(2);
+  state->_attributes.push_back(Attribute(attrib1, override));
+  state->_attributes.push_back(Attribute(attrib2, override));
+  state->_attributes.push_back(Attribute(attrib3, override));
+  state->_attributes.sort();
+  return return_new(state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make
+//       Access: Published, Static
+//  Description: Returns a RenderState with four attributes set.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+make(const RenderAttrib *attrib1,
+     const RenderAttrib *attrib2,
+     const RenderAttrib *attrib3,
+     const RenderAttrib *attrib4, int override) {
+  RenderState *state = new RenderState;
+  state->_attributes.reserve(2);
+  state->_attributes.push_back(Attribute(attrib1, override));
+  state->_attributes.push_back(Attribute(attrib2, override));
+  state->_attributes.push_back(Attribute(attrib3, override));
+  state->_attributes.push_back(Attribute(attrib4, override));
+  state->_attributes.sort();
+  return return_new(state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::compose
+//       Access: Published
+//  Description: Returns a new RenderState object that represents the
+//               composition of this state with the other state.
+//
+//               The result of this operation is cached, and will be
+//               retained as long as both this RenderState object and
+//               the other RenderState object continue to exist.
+//               Should one of them destruct, the cached entry will be
+//               removed, and its pointer will be allowed to destruct
+//               as well.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+compose(const RenderState *other) const {
+  // This method isn't strictly const, because it updates the cache,
+  // but we pretend that it is because it's only a cache which is
+  // transparent to the rest of the interface.
+
+  cerr << "composing " << *this << " with " << *other << "\n";
+
+  if (other == this) {
+    // compose(this) has to be handled as a special case, because the
+    // caching problem is so different.
+    if (_self_compose != (RenderState *)NULL) {
+      return _self_compose;
+    }
+    CPT(RenderState) result = do_compose(this);
+    ((RenderState *)this)->_self_compose = result;
+
+    if (result != this) {
+      // If the result of compose(this) is something other than this,
+      // explicitly increment the reference count.  We have to be sure
+      // to decrement it again later, in our destructor.
+      _self_compose->ref();
+
+      // (If the result was just this again, we still store the
+      // result, but we don't increment the reference count, since
+      // that would be a self-referential leak.  What a mess this is.)
+    }
+    return _self_compose;
+  }
+
+  // Is this composition already cached?
+  CompositionCache::const_iterator ci = _composition_cache.find(other);
+  if (ci != _composition_cache.end()) {
+    const Composition &comp = (*ci).second;
+    if (comp._result == (const RenderState *)NULL) {
+      // Well, it wasn't cached already, but we already had an entry
+      // (probably created for the reverse direction), so use the same
+      // entry to store the new result.
+      ((Composition &)comp)._result = do_compose(other);
+    }
+    // Here's the cache!
+    cerr << "  returning cached result " << (void *)comp._result.p() << "\n";
+    return comp._result;
+  }
+
+  // We need to make a new cache entry, both in this object and in the
+  // other object.  We make both records so the other RenderState
+  // object will know to delete the entry from this object when it
+  // destructs, and vice-versa.
+
+  // The cache entry in this object is the only one that indicates the
+  // result; the other will be NULL for now.
+  CPT(RenderState) result = do_compose(other);
+  // We store them in this order, on the off-chance that other is the
+  // same as this, a degenerate case which is still worth supporting.
+  ((RenderState *)other)->_composition_cache[this]._result = NULL;
+  ((RenderState *)this)->_composition_cache[other]._result = result;
+
+  cerr << "  returning new result " << (void *)result.p() << "\n";
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::add
+//       Access: Published
+//  Description: Returns a new RenderState object that represents the
+//               same as the source state, with the new RenderAttrib
+//               added.  If there is already a RenderAttrib with the
+//               same type, it is replaced.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+add(const RenderAttrib *attrib, int override) const {
+  RenderState *new_state = new RenderState;
+  back_insert_iterator<Attributes> result = 
+    back_inserter(new_state->_attributes);
+
+  Attribute new_attribute(attrib, override);
+  Attributes::const_iterator ai = _attributes.begin();
+
+  while (ai != _attributes.end() && (*ai) < new_attribute) {
+    *result = *ai;
+    ++ai;
+    ++result;
+  }
+  *result = new_attribute;
+  ++result;
+
+  while (ai != _attributes.end()) {
+    *result = *ai;
+    ++ai;
+    ++result;
+  }
+
+  return return_new(new_state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::remove
+//       Access: Published
+//  Description: Returns a new RenderState object that represents the
+//               same as the source state, with the indicated
+//               RenderAttrib removed
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+remove(TypeHandle type) const {
+  RenderState *new_state = new RenderState;
+  back_insert_iterator<Attributes> result = 
+    back_inserter(new_state->_attributes);
+
+  Attributes::const_iterator ai = _attributes.begin();
+
+  while (ai != _attributes.end()) {
+    if ((*ai)._type != type) {
+      *result = *ai;
+      ++result;
+    }
+    ++ai;
+  }
+
+  return return_new(new_state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void RenderState::
+output(ostream &out) const {
+  if (_attributes.empty()) {
+    out << "empty";
+
+  } else {
+    Attributes::const_iterator ai = _attributes.begin();
+    out << (*ai)._type;
+    ++ai;
+    while (ai != _attributes.end()) {
+      out << " " << (*ai)._type;
+      ++ai;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::write
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void RenderState::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level) << _attributes.size() << " attribs:\n";
+  Attributes::const_iterator ai;
+  for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) {
+    const Attribute &attribute = (*ai);
+    attribute._attrib->write(out, indent_level + 2);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::return_new
+//       Access: Private, Static
+//  Description: This function is used to share a common RenderState
+//               pointer for all equivalent RenderState objects.
+//
+//               See the similar logic in RenderAttrib.  The idea is
+//               to create a new RenderState object and pass it
+//               through this function, which will share the pointer
+//               with a previously-created RenderState object if it is
+//               equivalent.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+return_new(RenderState *state) {
+  cerr << "RenderState::return_new(" << *state << ")\n";
+  nassertr(state != (RenderState *)NULL, state);
+
+  // This should be a newly allocated pointer, not one that was used
+  // for anything else.
+  nassertr(state->_saved_entry == _states.end(), state);
+
+  // Save the state in a local PointerTo so that it will be freed at
+  // the end of this function if no one else uses it.
+  CPT(RenderState) pt_state = state;
+
+  pair<States::iterator, bool> result = _states.insert(state);
+  if (result.second) {
+    // The state was inserted; save the iterator and return the
+    // input state.
+    state->_saved_entry = result.first;
+    cerr << "  produces new pointer " << (void *)pt_state.p() << "\n";
+    return pt_state;
+  }
+
+  // The state was not inserted; there must be an equivalent one
+  // already in the set.  Return that one.
+  cerr << "  returns old pointer " << (void *)(*(result.first)) << "\n";
+  return *(result.first);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::do_compose
+//       Access: Private
+//  Description: The private implemention of compose(); this actually
+//               composes two RenderStates, without bothering with the
+//               cache.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+do_compose(const RenderState *other) const {
+  // First, build a new Attributes member that represents the union of
+  // this one and that one.
+  Attributes::const_iterator ai = _attributes.begin();
+  Attributes::const_iterator bi = other->_attributes.begin();
+
+  // Create a new RenderState that will hold the result.
+  RenderState *new_state = new RenderState;
+  back_insert_iterator<Attributes> result = 
+    back_inserter(new_state->_attributes);
+
+  while (ai != _attributes.end() && bi != other->_attributes.end()) {
+    if ((*ai) < (*bi)) {
+      // Here is an attribute 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 attribute we have in the secondary, that was
+      // not present in the original.
+      *result = *bi;
+      ++bi;
+      ++result;
+    } else {
+      // Here is an attribute we have in both.  Does one override the
+      // other?
+      const Attribute &a = (*ai);
+      const Attribute &b = (*bi);
+      if (a._override < b._override) {
+        // B overrides.
+        *result = *bi;
+
+      } else if (b._override < a._override) {
+        // A overrides.
+        *result = *bi;
+
+      } else {
+        // No, they're equivalent, so compose them.
+        *result = Attribute(a._attrib->compose(b._attrib), b._override);
+      }
+      ++ai;
+      ++bi;
+      ++result;
+    }
+  }
+
+  while (ai != _attributes.end()) {
+    *result = *ai;
+    ++ai;
+    ++result;
+  }
+
+  while (bi != other->_attributes.end()) {
+    *result = *bi;
+    ++bi;
+    ++result;
+  }
+
+  return return_new(new_state);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               RenderState.
+////////////////////////////////////////////////////////////////////
+void RenderState::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void RenderState::
+write_datagram(BamWriter *manager, Datagram &dg) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::finalize
+//       Access: Public, Virtual
+//  Description: Method to ensure that any necessary clean up tasks
+//               that have to be performed by this object are performed
+////////////////////////////////////////////////////////////////////
+void RenderState::
+finalize() {
+  // Unref the pointer that we explicitly reffed in make_from_bam().
+  unref();
+
+  // We should never get back to zero after unreffing our own count,
+  // because we expect to have been stored in a pointer somewhere.  If
+  // we do get to zero, it's a memory leak; the way to avoid this is
+  // to call unref_delete() above instead of unref(), but this is
+  // dangerous to do from within a virtual function.
+  nassertv(get_ref_count() != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type RenderState is encountered
+//               in the Bam file.  It should create the RenderState
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *RenderState::
+make_from_bam(const FactoryParams &params) {
+  RenderState *state = new RenderState;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  state->fillin(scan, manager);
+
+  return new_from_bam(state, manager);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::new_from_bam
+//       Access: Protected, Static
+//  Description: Uniquifies the pointer for a RenderState object just
+//               created from a bam file, and preserves its reference
+//               count correctly.
+////////////////////////////////////////////////////////////////////
+TypedWritable *RenderState::
+new_from_bam(RenderState *state, BamReader *manager) {
+  // First, uniquify the pointer.
+  CPT(RenderState) pointer = return_new(state);
+
+  // But now we have a problem, since we have to hold the reference
+  // count and there's no way to return a TypedWritable while still
+  // holding the reference count!  We work around this by explicitly
+  // upping the count, and also setting a finalize() callback to down
+  // it later.
+  if (pointer == state) {
+    pointer->ref();
+    manager->register_finalize(state);
+  }
+  
+  // We have to cast the pointer back to non-const, because the bam
+  // reader expects that.
+  return (RenderState *)pointer.p();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new RenderState.
+////////////////////////////////////////////////////////////////////
+void RenderState::
+fillin(DatagramIterator &scan, BamReader *manager) {
+}

+ 172 - 0
panda/src/pgraph/renderState.h

@@ -0,0 +1,172 @@
+// Filename: renderState.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef RENDERSTATE_H
+#define RENDERSTATE_H
+
+#include "pandabase.h"
+
+#include "renderAttrib.h"
+#include "typedWritableReferenceCount.h"
+#include "pointerTo.h"
+#include "indirectLess.h"
+#include "ordered_vector.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : RenderState
+// Description : This represents a unique collection of RenderAttrib
+//               objects that correspond to a particular renderable
+//               state.
+//
+//               You should not attempt to create or modify a
+//               RenderState object directly.  Instead, call one of
+//               the make() functions to create one for you.  And
+//               instead of modifying a RenderState object, create a
+//               new one.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA RenderState : public TypedWritableReferenceCount {
+protected:
+  RenderState();
+
+private:
+  RenderState(const RenderState &copy);
+  void operator = (const RenderState &copy);
+
+public:
+  virtual ~RenderState();
+
+  bool operator < (const RenderState &other) const;
+
+PUBLISHED:
+  INLINE bool is_empty() const;
+  INLINE int get_num_attribs() const;
+  INLINE const RenderAttrib *get_attrib(int n) const;
+  INLINE int get_override(int n) const;
+
+  int find_attrib(TypeHandle type) const;
+
+  static CPT(RenderState) make_empty();
+  static CPT(RenderState) make(const RenderAttrib *attrib, int override = 0);
+  static CPT(RenderState) make(const RenderAttrib *attrib1,
+                               const RenderAttrib *attrib2, int override = 0);
+  static CPT(RenderState) make(const RenderAttrib *attrib1,
+                               const RenderAttrib *attrib2,
+                               const RenderAttrib *attrib3, int override = 0);
+  static CPT(RenderState) make(const RenderAttrib *attrib1,
+                               const RenderAttrib *attrib2,
+                               const RenderAttrib *attrib3,
+                               const RenderAttrib *attrib4, int override = 0);
+
+  CPT(RenderState) compose(const RenderState *other) const;
+
+  CPT(RenderState) add(const RenderAttrib *attrib, int override = 0) const;
+  CPT(RenderState) remove(TypeHandle type) const;
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level) const;
+
+private:
+  static CPT(RenderState) return_new(RenderState *state);
+  CPT(RenderState) do_compose(const RenderState *other) const;
+
+private:
+  typedef pset<const RenderState *, IndirectLess<RenderState> > States;
+  static States _states;
+  static CPT(RenderState) _empty_state;
+
+  // This iterator records the entry corresponding to this RenderState
+  // object in the above global set.  We keep the iterator around so
+  // we can remove it when the RenderState destructs.
+  States::iterator _saved_entry;
+
+  // This data structure manages the job of caching the composition of
+  // two RenderStates.  It's complicated because we have to be sure to
+  // remove the entry if *either* of the input RenderStates destructs.
+  // To implement this, we always record Composition entries in pairs,
+  // one in each of the two involved RenderState objects.
+  class Composition {
+  public:
+    CPT(RenderState) _result;
+  };
+    
+  typedef pmap<const RenderState *, Composition> CompositionCache;
+  CompositionCache _composition_cache;
+
+  // This pointer is used to cache the result of compose(this).  This
+  // has to be a special case, because we have to handle the reference
+  // counts carefully so that we don't leak.  Most of the time, the
+  // result of compose(this) is this, which should not be reference
+  // counted, but other times the result is something else (which
+  // should be).
+  const RenderState *_self_compose;
+
+  // This is the actual set of data within the RenderState: a set of
+  // RenderAttribs.
+  class Attribute {
+  public:
+    INLINE Attribute(const RenderAttrib *attrib, int override);
+    INLINE Attribute(TypeHandle type);
+    INLINE Attribute(const Attribute &copy);
+    INLINE void operator = (const Attribute &copy);
+    INLINE bool operator < (const Attribute &other) const;
+    INLINE int compare_to(const Attribute &other) const;
+
+    TypeHandle _type;
+    CPT(RenderAttrib) _attrib;
+    int _override;
+  };
+  typedef ov_set<Attribute> Attributes;
+  Attributes _attributes;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual void finalize();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  static TypedWritable *new_from_bam(RenderState *state, BamReader *manager);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "RenderState",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const RenderState &state) {
+  state.output(out);
+  return out;
+}
+
+#include "renderState.I"
+
+#endif
+

+ 82 - 0
panda/src/pgraph/test_pgraph.cxx

@@ -0,0 +1,82 @@
+// Filename: test_pgraph.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandaNode.h"
+#include "textureAttrib.h"
+#include "colorAttrib.h"
+#include "texture.h"
+
+void
+list_hierarchy(PandaNode *node, int indent_level) {
+  node->write(cerr, indent_level);
+  PandaNode::Children cr = node->get_children();
+  int num_children = cr.get_num_children();
+  for (int i = 0; i < num_children; i++) {
+    list_hierarchy(cr.get_child(i), indent_level + 2);
+  }
+}
+
+int 
+main(int argc, char *argv[]) {
+  PT(Texture) tex = new Texture;
+  tex->set_name("tex");
+
+  PT(PandaNode) root = new PandaNode("root");
+  root->set_attrib(TextureAttrib::make_off());
+  root->set_attrib(ColorAttrib::make_flat(Colorf(1, 0, 0, 1)));
+
+  PandaNode *a = new PandaNode("a");
+  root->add_child(a);
+  a->set_attrib(TextureAttrib::make(tex));
+
+  PandaNode *b = new PandaNode("b");
+  root->add_child(b);
+  b->set_attrib(ColorAttrib::make_vertex());
+
+  PandaNode *a1 = new PandaNode("a1");
+  a->add_child(a1);
+
+  cerr << "\n";
+  list_hierarchy(root, 0);
+
+  cerr << "\nroot's attribs:\n";
+  root->get_state()->write(cerr, 0);
+
+  cerr << "\na's attribs:\n";
+  a->get_state()->write(cerr, 0);
+
+  cerr << "\nroot compose a:\n";
+  CPT(RenderState) result1 = root->get_state()->compose(a->get_state());
+  result1->write(cerr, 0);
+
+  //  a->clear_state();
+
+  cerr << "\nroot compose root:\n";
+  CPT(RenderState) result2 = root->get_state()->compose(root->get_state());
+  result2->write(cerr, 0);
+
+  cerr << "\nroot compose a:\n";
+  CPT(RenderState) result3 = root->get_state()->compose(a->get_state());
+  result3->write(cerr, 0);
+
+  cerr << "\na compose root:\n";
+  CPT(RenderState) result4 = a->get_state()->compose(root->get_state());
+  result4->write(cerr, 0);
+
+  return 0;
+}

+ 52 - 0
panda/src/pgraph/textureAttrib.I

@@ -0,0 +1,52 @@
+// Filename: textureAttrib.I
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::Constructor
+//       Access: Private
+//  Description: Use TextureAttrib::make() to construct a new
+//               TextureAttrib object.
+////////////////////////////////////////////////////////////////////
+INLINE TextureAttrib::
+TextureAttrib() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::is_off
+//       Access: Published
+//  Description: Returns true if the TextureAttrib is an 'off'
+//               TextureAttrib, indicating that it should disable
+//               texturing.
+////////////////////////////////////////////////////////////////////
+INLINE bool TextureAttrib::
+is_off() const {
+  return _texture == (Texture *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::get_texture
+//       Access: Published
+//  Description: If the TextureAttrib is not an 'off' TextureAttrib,
+//               returns the texture that is associated.  Otherwise,
+//               return NULL.
+////////////////////////////////////////////////////////////////////
+INLINE Texture *TextureAttrib::
+get_texture() const {
+  return _texture;
+}

+ 99 - 0
panda/src/pgraph/textureAttrib.cxx

@@ -0,0 +1,99 @@
+// Filename: textureAttrib.cxx
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "textureAttrib.h"
+
+TypeHandle TextureAttrib::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::make
+//       Access: Published, Static
+//  Description: Constructs a new TextureAttrib object suitable for
+//               rendering the indicated texture onto geometry.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) TextureAttrib::
+make(Texture *texture) {
+  TextureAttrib *attrib = new TextureAttrib;
+  attrib->_texture = texture;
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::make_off
+//       Access: Published, Static
+//  Description: Constructs a new TextureAttrib object suitable for
+//               rendering untextured geometry.
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) TextureAttrib::
+make_off() {
+  TextureAttrib *attrib = new TextureAttrib;
+  return return_new(attrib);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void TextureAttrib::
+output(ostream &out) const {
+  out << get_type() << ":";
+  if (is_off()) {
+    out << "(off)";
+  } else {
+    out << _texture->get_name();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived TextureAttrib
+//               types to return a unique number indicating whether
+//               this TextureAttrib is equivalent to the other one.
+//
+//               This should return 0 if the two TextureAttrib objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two TextureAttrib
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int TextureAttrib::
+compare_to_impl(const RenderAttrib *other) const {
+  const TextureAttrib *ta;
+  DCAST_INTO_R(ta, other, 0);
+  return (int)(_texture - ta->_texture);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::make_default_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived TextureAttrib
+//               types to specify what the default property for a
+//               TextureAttrib of this type should be.
+//
+//               This should return a newly-allocated TextureAttrib of
+//               the same type that corresponds to whatever the
+//               standard default for this kind of TextureAttrib is.
+////////////////////////////////////////////////////////////////////
+RenderAttrib *TextureAttrib::
+make_default_impl() const {
+  return new TextureAttrib;
+}

+ 75 - 0
panda/src/pgraph/textureAttrib.h

@@ -0,0 +1,75 @@
+// Filename: textureAttrib.h
+// Created by:  drose (21Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef TEXTUREATTRIB_H
+#define TEXTUREATTRIB_H
+
+#include "pandabase.h"
+
+#include "renderAttrib.h"
+#include "texture.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : TextureAttrib
+// Description : Indicates which texture should be applied as the
+//               primary texture.  Also see TextureAttrib2 for the
+//               secondary texture.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA TextureAttrib : public RenderAttrib {
+private:
+  INLINE TextureAttrib();
+
+PUBLISHED:
+  static CPT(RenderAttrib) make(Texture *tex);
+  static CPT(RenderAttrib) make_off();
+
+  INLINE bool is_off() const;
+  INLINE Texture *get_texture() const;
+
+public:
+  virtual void output(ostream &out) const;
+
+protected:
+  virtual int compare_to_impl(const RenderAttrib *other) const;
+  virtual RenderAttrib *make_default_impl() const;
+
+private:
+  PT(Texture) _texture;
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "TextureAttrib",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "textureAttrib.I"
+
+#endif
+