Selaa lähdekoodia

pgraph cull binning

David Rose 24 vuotta sitten
vanhempi
sitoutus
f79661eb9a

+ 8 - 0
panda/src/display/displayRegion.h

@@ -23,6 +23,8 @@
 #include "referenceCount.h"
 #include "camera.h"
 #include "nodeChain.h"
+#include "cullResult.h"
+#include "pointerTo.h"
 
 #include "plist.h"
 
@@ -108,7 +110,13 @@ protected:
 
   bool _active;
 
+  // This is used to cache the culling result from last frame's
+  // drawing into this display region.  It should only be accessed or
+  // modified by the GraphicsEngine, during the cull traversal.
+  PT(CullResult) _cull_result;
+
   friend class GraphicsLayer;
+  friend class GraphicsEngine;
 };
 
 INLINE ostream &operator << (ostream &out, const DisplayRegion &dr);

+ 111 - 1
panda/src/display/graphicsEngine.cxx

@@ -19,6 +19,8 @@
 #include "graphicsEngine.h"
 #include "pipeline.h"
 #include "drawCullHandler.h"
+#include "binCullHandler.h"
+#include "cullResult.h"
 #include "qpcullTraverser.h"
 #include "clockObject.h"
 
@@ -77,7 +79,8 @@ remove_window(GraphicsWindow *window) {
 ////////////////////////////////////////////////////////////////////
 void GraphicsEngine::
 render_frame() {
-  cull_and_draw_together();
+  //  cull_and_draw_together();
+  cull_bin_draw();
 
   // **** This doesn't belong here; it really belongs in the Pipeline,
   // but here it is for now.
@@ -180,3 +183,110 @@ cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) {
   
   gsg->pop_display_region(old_dr);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::cull_bin_draw
+//       Access: Private
+//  Description: An implementation of render_frame() that renders the
+//               frame with a BinCullHandler, to cull into bins and
+//               then draw the bins.  This is the normal method.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+cull_bin_draw() {
+  Windows::iterator wi;
+  for (wi = _windows.begin(); wi != _windows.end(); ++wi) {
+    GraphicsWindow *win = (*wi);
+    win->clear();
+
+    int num_display_regions = win->get_num_display_regions();
+    for (int i = 0; i < num_display_regions; i++) {
+      DisplayRegion *dr = win->get_display_region(i);
+      cull_bin_draw(win, dr);
+    }
+    win->flip();
+    win->process_events();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::cull_bin_draw
+//       Access: Private
+//  Description: An implementation of render_frame() that renders the
+//               frame with a BinCullHandler, to cull into bins and
+//               then draw the bins.  This is the normal method.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr) {
+  const NodeChain &camera = dr->get_qpcamera();
+  if (camera.is_empty()) {
+    // No camera, no draw.
+    return;
+  }
+
+  qpCamera *camera_node;
+  DCAST_INTO_V(camera_node, camera.node());
+
+  if (!camera_node->is_active()) {
+    // Camera inactive, no draw.
+    return;
+  }
+
+  Lens *lens = camera_node->get_lens();
+  if (lens == (Lens *)NULL) {
+    // No lens, no draw.
+    return;
+  }
+
+  NodeChain scene = camera_node->get_scene();
+  if (scene.is_empty()) {
+    // No scene, no draw.
+    return;
+  }
+
+  GraphicsStateGuardian *gsg = win->get_gsg();
+  nassertv(gsg != (GraphicsStateGuardian *)NULL);
+
+  if (!gsg->set_lens(lens)) {
+    // The lens is inappropriate somehow.
+    display_cat.error()
+      << gsg->get_type() << " cannot render with " << lens->get_type()
+      << "\n";
+    return;
+  }
+
+  PT(CullResult) cull_result = dr->_cull_result;
+  if (cull_result == (CullResult *)NULL) {
+    cull_result = new CullResult(gsg);
+  }
+
+  BinCullHandler cull_handler(cull_result);
+  qpCullTraverser trav;
+  trav.set_cull_handler(&cull_handler);
+
+  // The world transform is computed from the camera's position; we
+  // then might need to adjust it into the GSG's internal coordinate
+  // system.
+  trav.set_camera_transform(scene.get_rel_transform(camera));
+
+  CPT(TransformState) render_transform = camera.get_rel_transform(scene);
+  CoordinateSystem external_cs = gsg->get_coordinate_system();
+  CoordinateSystem internal_cs = gsg->get_internal_coordinate_system();
+  if (internal_cs != CS_default && internal_cs != external_cs) {
+    CPT(TransformState) cs_transform = 
+      TransformState::make_mat(LMatrix4f::convert_mat(external_cs, internal_cs));
+    render_transform = cs_transform->compose(render_transform);
+  }
+  trav.set_render_transform(render_transform);
+  
+  trav.traverse(scene.node());
+  cull_result->finish_cull();
+
+  // Save the results for next frame.
+  dr->_cull_result = cull_result->make_next();
+
+  // Now draw.
+  DisplayRegionStack old_dr = gsg->push_display_region(dr);
+  gsg->prepare_display_region();
+  cull_result->draw();
+  gsg->pop_display_region(old_dr);
+}

+ 3 - 0
panda/src/display/graphicsEngine.h

@@ -54,6 +54,9 @@ private:
   void cull_and_draw_together();
   void cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr);
 
+  void cull_bin_draw();
+  void cull_bin_draw(GraphicsWindow *win, DisplayRegion *dr);
+
   Pipeline *_pipeline;
 
   typedef pset<PT(GraphicsWindow)> Windows;

+ 13 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -776,6 +776,19 @@ void GraphicsStateGuardian::
 release_geom(GeomContext *) {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::set_state_and_transform
+//       Access: Public, Virtual
+//  Description: Simultaneously resets the render state and the
+//               transform state.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+set_state_and_transform(const RenderState *state,
+                        const TransformState *transform) {
+  set_state(state);
+  set_transform(transform);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::clear_framebuffer
 //       Access: Public, Virtual

+ 3 - 0
panda/src/display/graphicsStateGuardian.h

@@ -103,6 +103,9 @@ public:
   virtual GeomContext *prepare_geom(Geom *geom);
   virtual void release_geom(GeomContext *gc);
 
+  virtual void set_state_and_transform(const RenderState *state,
+                                       const TransformState *transform);
+
   virtual void clear(const RenderBuffer &buffer)=0;
   virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region)=0;
   virtual void clear_framebuffer();

+ 16 - 9
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -47,6 +47,8 @@ class GeomSphere;
 class TextureContext;
 class Texture;
 class PixelBuffer;
+class RenderState;
+class TransformState;
 
 class Material;
 class Fog;
@@ -129,15 +131,9 @@ public:
   virtual bool wants_texcoords(void) const=0;
   virtual bool wants_colors(void) const=0;
 
-
-  // Defined here are some internal interface functions for the
-  // GraphicsStateGuardian.  These are here to support
-  // double-dispatching from Geoms and NodeTransitions, and are
-  // intended to be invoked only directly by the appropriate Geom and
-  // NodeTransition types.  They're public only because it would be too
-  // inconvenient to declare each of those types to be friends of this
-  // class.
-
+  // These are some general interface functions; they're defined here
+  // mainly to make it easy to call these from code in some directory
+  // that display depends on.
   virtual TextureContext *prepare_texture(Texture *tex)=0;
   virtual void apply_texture(TextureContext *tc)=0;
   virtual void release_texture(TextureContext *tc)=0;
@@ -149,6 +145,17 @@ public:
   virtual GeomContext *prepare_geom(Geom *geom)=0;
   virtual void release_geom(GeomContext *gc)=0;
 
+  virtual void set_state_and_transform(const RenderState *state,
+                                       const TransformState *transform)=0;
+
+  // Defined here are some internal interface functions for the
+  // GraphicsStateGuardian.  These are here to support
+  // double-dispatching from Geoms and NodeTransitions, and are
+  // intended to be invoked only directly by the appropriate Geom and
+  // NodeTransition types.  They're public only because it would be too
+  // inconvenient to declare each of those types to be friends of this
+  // class.
+
   virtual void draw_point(GeomPoint *geom, GeomContext *gc)=0;
   virtual void draw_line(GeomLine *geom, GeomContext *gc)=0;
   virtual void draw_linestrip(GeomLinestrip *geom, GeomContext *gc)=0;

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

@@ -7,11 +7,16 @@
   
   #define SOURCES \
     billboardAttrib.h billboardAttrib.I \
+    binCullHandler.h binCullHandler.I \
     qpcamera.h qpcamera.I \
     colorAttrib.h colorAttrib.I \
     config_pgraph.h \
+    cullBin.h cullBin.I \
+    cullBinManager.h cullBinManager.I \
+    cullBinUnsorted.h cullBinUnsorted.I \
     cullFaceAttrib.h cullFaceAttrib.I \
     cullHandler.h \
+    cullResult.h \
     qpcullTraverser.h qpcullTraverser.I \
     cycleData.h cycleData.I \
     cycleDataReader.h cycleDataReader.I \
@@ -32,11 +37,16 @@
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx    
   #define INCLUDED_SOURCES \
     billboardAttrib.cxx \
+    binCullHandler.cxx \
     qpcamera.cxx \
     colorAttrib.cxx \
     config_pgraph.cxx \
+    cullBin.cxx \
+    cullBinManager.cxx \
+    cullBinUnsorted.cxx \
     cullFaceAttrib.cxx \
     cullHandler.cxx \
+    cullResult.cxx \
     qpcullTraverser.cxx \
     cycleData.cxx \
     cycleDataReader.cxx \
@@ -62,11 +72,16 @@
 
   #define INSTALL_HEADERS \
     billboardAttrib.h billboardAttrib.I \
+    binCullHandler.h binCullHandler.I \
     qpcamera.h qpcamera.I \
     colorAttrib.h colorAttrib.I \
     config_pgraph.h \
+    cullBin.h cullBin.I \
+    cullBinManager.h cullBinManager.I \
+    cullBinUnsorted.h cullBinUnsorted.I \
     cullFaceAttrib.h cullFaceAttrib.I \
     cullHandler.h \
+    cullResult.h \
     qpcullTraverser.h qpcullTraverser.I \
     cycleData.h cycleData.I \
     cycleDataReader.h cycleDataReader.I \

+ 29 - 0
panda/src/pgraph/binCullHandler.I

@@ -0,0 +1,29 @@
+// Filename: binCullHandler.I
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: BinCullHandler::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE BinCullHandler::
+BinCullHandler(CullResult *cull_result) :
+  _cull_result(cull_result)
+{
+}

+ 33 - 0
panda/src/pgraph/binCullHandler.cxx

@@ -0,0 +1,33 @@
+// Filename: binCullHandler.cxx
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "binCullHandler.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: BinCullHandler::record_geom
+//       Access: Public, Virtual
+//  Description: This callback function is intended to be overridden
+//               by a derived class.  This is called as each Geom is
+//               discovered by the CullTraverser.
+////////////////////////////////////////////////////////////////////
+void BinCullHandler::
+record_geom(Geom *geom, const TransformState *transform,
+            const RenderState *state) {
+  _cull_result->add_geom(geom, transform, state);
+}

+ 53 - 0
panda/src/pgraph/binCullHandler.h

@@ -0,0 +1,53 @@
+// Filename: binCullHandler.h
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 BINCULLHANDLER_H
+#define BINCULLHANDLER_H
+
+#include "pandabase.h"
+#include "cullHandler.h"
+#include "cullResult.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : BinCullHandler
+// Description : This CullHandler sends all of the geoms it receives
+//               into a CullResult object, for binning (and later
+//               drawing).  This is the kind of CullHandler to use for
+//               most normal rendering needs.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA BinCullHandler : public CullHandler {
+public:
+  INLINE BinCullHandler(CullResult *cull_result);
+
+  //  virtual void begin_decal();
+  virtual void record_geom(Geom *geom, const TransformState *transform,
+                           const RenderState *state);
+  //  virtual void push_decal();
+  //  virtual void pop_decal();
+
+private:
+  PT(CullResult) _cull_result;
+};
+
+#include "binCullHandler.I"
+
+#endif
+
+
+  

+ 5 - 1
panda/src/pgraph/config_pgraph.cxx

@@ -22,6 +22,8 @@
 #include "qpcamera.h"
 #include "colorAttrib.h"
 #include "cullFaceAttrib.h"
+#include "cullBin.h"
+#include "cullBinUnsorted.h"
 #include "qpgeomNode.h"
 #include "qplensNode.h"
 #include "nodeChain.h"
@@ -35,7 +37,7 @@
 
 #include "dconfig.h"
 
-Configure(config_pgraph);
+ConfigureDef(config_pgraph);
 NotifyCategoryDef(pgraph, "");
 
 ConfigureFn(config_pgraph) {
@@ -63,6 +65,8 @@ init_libpgraph() {
   qpCamera::init_type();
   ColorAttrib::init_type();
   CullFaceAttrib::init_type();
+  CullBin::init_type();
+  CullBinUnsorted::init_type();
   qpGeomNode::init_type();
   qpLensNode::init_type();
   NodeChain::init_type();

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

@@ -21,7 +21,9 @@
 
 #include "pandabase.h"
 #include "notifyCategoryProxy.h"
+#include "dconfig.h"
 
+ConfigureDecl(config_pgraph, EXPCL_PANDA, EXPTP_PANDA);
 NotifyCategoryDecl(pgraph, EXPCL_PANDA, EXPTP_PANDA);
 
 extern EXPCL_PANDA void init_libpgraph();

+ 29 - 0
panda/src/pgraph/cullBin.I

@@ -0,0 +1,29 @@
+// Filename: cullBin.I
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: CullBin::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE CullBin::
+CullBin(GraphicsStateGuardianBase *gsg) : 
+  _gsg(gsg)
+{
+}

+ 75 - 0
panda/src/pgraph/cullBin.cxx

@@ -0,0 +1,75 @@
+// Filename: cullBin.cxx
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cullBin.h"
+
+
+TypeHandle CullBin::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBin::make_next
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated CullBin object that
+//               contains a copy of just the subset of the data from
+//               this CullBin object that is worth keeping around
+//               for next frame.
+//
+//               If a particular CullBin object has no data worth
+//               preserving till next frame, it is acceptable to
+//               return NULL (which is the default behavior of this
+//               method).
+////////////////////////////////////////////////////////////////////
+PT(CullBin) CullBin::
+make_next() const {
+  return (CullBin *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBin::add_geom
+//       Access: Public, Virtual
+//  Description: Adds the geom, along with its associated state, to
+//               the bin for rendering.
+////////////////////////////////////////////////////////////////////
+void CullBin::
+add_geom(Geom *geom, const TransformState *transform,
+         const RenderState *state) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBin::finish_cull
+//       Access: Public
+//  Description: Called after all the geoms have been added, this
+//               indicates that the cull process is finished for this
+//               frame and gives the bins a chance to do any
+//               post-processing (like sorting) before moving on to
+//               draw.
+////////////////////////////////////////////////////////////////////
+void CullBin::
+finish_cull() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBin::draw
+//       Access: Public
+//  Description: Draws all the geoms in the bin, in the appropriate
+//               order.
+////////////////////////////////////////////////////////////////////
+void CullBin::
+draw() {
+}
+

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

@@ -0,0 +1,81 @@
+// Filename: cullBin.h
+// Created by:  drose (27Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CULLBIN_H
+#define CULLBIN_H
+
+#include "pandabase.h"
+
+#include "typedReferenceCount.h"
+#include "pointerTo.h"
+
+class Geom;
+class TransformState;
+class RenderState;
+class GraphicsStateGuardianBase;
+
+////////////////////////////////////////////////////////////////////
+//       Class : CullBin
+// Description : A collection of Geoms and their associated state, for
+//               a particular scene.  The cull traversal (and the
+//               BinCullHandler) assigns Geoms to bins as it comes
+//               across them.
+//
+//               This is an abstract base class; derived classes like
+//               CullBinStateSorted and CullBinBackToFront provide the
+//               actual implementation.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA CullBin : public TypedReferenceCount {
+public:
+  INLINE CullBin(GraphicsStateGuardianBase *gsg);
+
+  virtual PT(CullBin) make_next() const;
+
+  virtual void add_geom(Geom *geom, const TransformState *transform,
+                        const RenderState *state)=0;
+  virtual void finish_cull();
+
+  virtual void draw()=0;
+
+protected:
+  GraphicsStateGuardianBase *_gsg;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "CullBin",
+                  TypedReferenceCount::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 "cullBin.I"
+
+#endif
+
+
+  

+ 125 - 0
panda/src/pgraph/cullBinManager.I

@@ -0,0 +1,125 @@
+// Filename: cullBinManager.I
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: CullBinManager::SortBins::Constructor
+//       Access: Public
+//  Description: This is a function object whose sole purpose is to
+//               put the _sorted_bins vector in the proper order for
+//               rendering the bins.
+////////////////////////////////////////////////////////////////////
+INLINE CullBinManager::SortBins::
+SortBins(CullBinManager *manager) :
+  _manager(manager)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::SortBins::operator ()
+//       Access: Public
+//  Description: The function call method of the function object.
+//               Returns true if the two bin indices are already in
+//               sorted order with a < b, or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool CullBinManager::SortBins::
+operator () (int a, int b) const {
+  return _manager->_bin_definitions[a]._sort < _manager->_bin_definitions[b]._sort;
+}
+
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_num_bins
+//       Access: Published
+//  Description: Returns the number of bins in the world.
+////////////////////////////////////////////////////////////////////
+INLINE int CullBinManager::
+get_num_bins() const {
+  // We quietly sort the bins in order if they are not already sorted.
+  // This is a non-const operation, but we pretend it's const because
+  // it's intended to be a transparent update.
+  if (!_bins_are_sorted) {
+    ((CullBinManager *)this)->do_sort_bins();
+  }
+  return _sorted_bins.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_bin
+//       Access: Published
+//  Description: Returns the bin_index of the nth bin in the set,
+//               where n is a number between 0 and get_num_bins().
+//               This returns the list of bin_index numbers, in sorted
+//               order (that is, in the order in which the bins should
+//               be rendered).
+////////////////////////////////////////////////////////////////////
+INLINE int CullBinManager::
+get_bin(int n) const {
+  nassertr(n >= 0 && n < (int)_sorted_bins.size(), -1);
+  return _sorted_bins[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_bin_name
+//       Access: Published
+//  Description: Returns the name of the bin with the indicated
+//               bin_index (where bin_index was retrieved by get_bin()
+
+//               or find_bin()).  The bin's name may not be changed
+//               during the life of the bin.
+////////////////////////////////////////////////////////////////////
+INLINE string CullBinManager::
+get_bin_name(int bin_index) const {
+  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), string());
+  nassertr(_bin_definitions[bin_index]._in_use, string());
+  return _bin_definitions[bin_index]._name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_bin_type
+//       Access: Published
+//  Description: Returns the type of the bin with the indicated
+//               bin_index (where bin_index was retrieved by get_bin()
+//               or find_bin()).  The bin's type may not be changed
+//               during the life of the bin.
+////////////////////////////////////////////////////////////////////
+INLINE CullBinManager::BinType CullBinManager::
+get_bin_type(int bin_index) const {
+  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), BT_invalid);
+  nassertr(_bin_definitions[bin_index]._in_use, BT_invalid);
+  return _bin_definitions[bin_index]._type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_bin_sort
+//       Access: Published
+//  Description: Returns the sort order of the bin with the indicated
+//               bin_index (where bin_index was retrieved by get_bin()
+//               or find_bin()).
+//
+//               The bins are rendered in increasing order by their
+//               sort order; this number may be changed from time to
+//               time to reorder the bins.
+////////////////////////////////////////////////////////////////////
+INLINE int CullBinManager::
+get_bin_sort(int bin_index) const {
+  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), 0);
+  nassertr(_bin_definitions[bin_index]._in_use, 0);
+  return _bin_definitions[bin_index]._sort;
+}

+ 309 - 0
panda/src/pgraph/cullBinManager.cxx

@@ -0,0 +1,309 @@
+// Filename: cullBinManager.cxx
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cullBinManager.h"
+#include "cullBinUnsorted.h"
+#include "renderState.h"
+#include "cullResult.h"
+#include "config_pgraph.h"
+#include "string_utils.h"
+
+
+CullBinManager *CullBinManager::_global_ptr = (CullBinManager *)NULL;
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::Constructor
+//       Access: Protected
+//  Description: The constructor is not intended to be called
+//               directly; there is only one CullBinManager and it
+//               constructs itself.  This could have been a private
+//               constructor, but gcc issues a spurious warning if the
+//               constructor is private and the class has no friends.
+////////////////////////////////////////////////////////////////////
+CullBinManager::
+CullBinManager() {
+  _bins_are_sorted = true;
+  _unused_bin_index = false;
+
+  setup_initial_bins();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::Destructor
+//       Access: Protected
+//  Description: Don't call the destructor.
+////////////////////////////////////////////////////////////////////
+CullBinManager::
+~CullBinManager() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::add_bin
+//       Access: Published
+//  Description: Defines a new bin with the indicated name, and
+//               returns the new bin_index.  If there is already a bin
+//               with the same name returns its bin_index if it had
+//               the same properties; otherwise, reports an error and
+//               returns -1.
+////////////////////////////////////////////////////////////////////
+int CullBinManager::
+add_bin(const string &name, BinType type, int sort) {
+  BinsByName::const_iterator bni = _bins_by_name.find(name);
+  if (bni != _bins_by_name.end()) {
+    // We already have such a bin.  This is not a problem if the bin
+    // has the same properties.
+    int bin_index = (*bni).second;
+    nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), -1);
+    const BinDefinition &def = _bin_definitions[bin_index];
+    nassertr(def._in_use, -1);
+    if (def._type == type && def._sort == sort) {
+      return bin_index;
+    }
+
+    // Nope, the old bin had different properties.  Too bad.
+    pgraph_cat.warning()
+      << "Cannot create a bin named " << name
+      << "; already have a bin by that name.\n";
+    return -1;
+  }
+
+  // No bin by that name already; choose a bin_index to assign to the
+  // newly created bin.
+  int new_bin_index = -1;
+  if (_unused_bin_index) {
+    // If there is some bin index that's not being used, we can claim
+    // it.
+    int i = 0;
+    for (i = 0; i < (int)_bin_definitions.size() && new_bin_index == -1; i++) {
+      if (!_bin_definitions[i]._in_use) {
+        new_bin_index = i;
+      }
+    }
+
+    if (new_bin_index == -1) {
+      // Oops, maybe we've used up all the unused indices already.
+      _unused_bin_index = false;
+    }
+  }
+
+  if (new_bin_index == -1) {
+    // Slot a new index on the end of the vector.
+    new_bin_index = _bin_definitions.size();
+    _bin_definitions.push_back(BinDefinition());
+  }
+
+  BinDefinition &def = _bin_definitions[new_bin_index];
+  def._in_use = true;
+  def._name = name;
+  def._type = type;
+  def._sort = sort;
+
+  _bins_by_name.insert(BinsByName::value_type(name, new_bin_index));
+  _sorted_bins.push_back(new_bin_index);
+  _bins_are_sorted = false;
+
+  return new_bin_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::remove_bin
+//       Access: Published
+//  Description: Permanently removes the indicated bin.  This
+//               operation is not protected from the pipeline and will
+//               disturb whatever is currently rendering in draw.  You
+//               should not call this during the normal course of
+//               rendering a frame; it is intended only as an aid to
+//               development, to allow the developer to interactively
+//               fiddle with the set of bins.
+////////////////////////////////////////////////////////////////////
+void CullBinManager::
+remove_bin(int bin_index) {
+  nassertv(bin_index >= 0 && bin_index < (int)_bin_definitions.size());
+  nassertv(_bin_definitions[bin_index]._in_use);
+
+  _bin_definitions[bin_index]._in_use = false;
+  SortedBins::iterator si = 
+    find(_sorted_bins.begin(), _sorted_bins.end(), bin_index);
+  nassertv(si != _sorted_bins.end());
+  _sorted_bins.erase(si);
+  _bins_by_name.erase(_bin_definitions[bin_index]._name);
+
+  // Now we have to make sure all of the data objects in the world
+  // that had cached this bin index or have a bin object are correctly
+  // updated.
+  
+  // First, tell all the RenderStates in the world to reset their bin
+  // index cache.
+  RenderState::bin_removed(bin_index);
+
+  // Now tell all the CullResults to clear themselves up too.
+  CullResult::bin_removed(bin_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::find_bin
+//       Access: Published
+//  Description: Returns the bin_index associated with the bin of the
+//               given name, or -1 if no bin has that name.
+////////////////////////////////////////////////////////////////////
+int CullBinManager::
+find_bin(const string &name) const {
+  BinsByName::const_iterator bni;
+  bni = _bins_by_name.find(name);
+  if (bni != _bins_by_name.end()) {
+    return (*bni).second;
+  }
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::get_global_ptr
+//       Access: Published, Static
+//  Description: Returns the pointer to the global CullBinManager
+//               object.
+////////////////////////////////////////////////////////////////////
+CullBinManager *CullBinManager::
+get_global_ptr() {
+  if (_global_ptr == (CullBinManager *)NULL) {
+    _global_ptr = new CullBinManager;
+  }
+  return _global_ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::make_new_bin
+//       Access: Public
+//  Description: Intended to be called by CullResult when a new
+//               CullBin pointer corresponding to the indicated
+//               bin_index is required.  It allocates and returns a
+//               brand new CullBin object of the appropriate type.
+////////////////////////////////////////////////////////////////////
+PT(CullBin) CullBinManager::
+make_new_bin(int bin_index, GraphicsStateGuardianBase *gsg) {
+  nassertr(bin_index >= 0 && bin_index < (int)_bin_definitions.size(), NULL);
+  nassertr(_bin_definitions[bin_index]._in_use, NULL);
+
+  return new CullBinUnsorted(gsg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::do_sort_bins
+//       Access: Private
+//  Description: Puts the _sorted_bins vector in proper rendering
+//               order.
+////////////////////////////////////////////////////////////////////
+void CullBinManager::
+do_sort_bins() {
+  sort(_sorted_bins.begin(), _sorted_bins.end(), SortBins(this));
+  _bins_are_sorted = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::setup_initial_bins
+//       Access: Private
+//  Description: Called only at construction time to create the
+//               default bins and the bins specified in the Configrc
+//               file.
+////////////////////////////////////////////////////////////////////
+void CullBinManager::
+setup_initial_bins() {
+  // First, add all of the bins specified in the Configrc file.
+  Config::ConfigTable::Symbol cull_bins;
+  config_pgraph.GetAll("cull-bin", cull_bins);
+
+  Config::ConfigTable::Symbol::iterator bi;
+  for (bi = cull_bins.begin(); bi != cull_bins.end(); ++bi) {
+    ConfigString def = (*bi).Val();
+
+    // This is a string in three tokens, separated by whitespace:
+    //    bin_name sort type
+
+    vector_string words;
+    extract_words(def, words);
+
+    if (words.size() != 3) {
+      pgraph_cat.error()
+        << "Invalid cull-bin definition: " << def << "\n"
+        << "Definition should be three words: bin_name sort type\n";
+    } else {
+      int sort;
+      if (!string_to_int(words[1], sort)) {
+        pgraph_cat.error()
+          << "Invalid cull-bin definition: " << def << "\n"
+          << "Sort token " << words[1] << " is not an integer.\n";
+
+      } else {
+        BinType type = parse_bin_type(words[2]);
+        if (type == BT_invalid) {
+          pgraph_cat.error()
+            << "Invalid cull-bin definition: " << def << "\n"
+            << "Bin type " << words[2] << " is not known.\n";
+        } else {
+          add_bin(words[0], type, sort);
+        }
+      }
+    }
+  }
+
+  // Now add the default bins, unless the names have already been
+  // specified explicitly in the Config file, above.
+  if (find_bin("background") == -1) {
+    add_bin("background", BT_fixed, 10);
+  }
+  if (find_bin("opaque") == -1) {
+    add_bin("opaque", BT_state_sorted, 20);
+  }
+  if (find_bin("transparent") == -1) {
+    add_bin("transparent", BT_back_to_front, 30);
+  }
+  if (find_bin("fixed") == -1) {
+    add_bin("fixed", BT_fixed, 40);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinManager::parse_bin_type
+//       Access: Private, Static
+//  Description: Given the name of a bin type, returns the
+//               corresponding BinType value, or BT_invalid if it is
+//               an unknown type.
+////////////////////////////////////////////////////////////////////
+CullBinManager::BinType CullBinManager::
+parse_bin_type(const string &bin_type) {
+  if (cmp_nocase_uh(bin_type, "unsorted") == 0) {
+    return BT_unsorted;
+
+  } else if (cmp_nocase_uh(bin_type, "state_sorted") == 0) {
+    return BT_state_sorted;
+
+  } else if (cmp_nocase_uh(bin_type, "statesorted") == 0) {
+    return BT_state_sorted;
+
+  } else if (cmp_nocase_uh(bin_type, "fixed") == 0) {
+    return BT_fixed;
+
+  } else if (cmp_nocase_uh(bin_type, "back_to_front") == 0) {
+    return BT_back_to_front;
+
+  } else if (cmp_nocase_uh(bin_type, "backtofront") == 0) {
+    return BT_back_to_front;
+
+  } else {
+    return BT_invalid;
+  }
+}

+ 105 - 0
panda/src/pgraph/cullBinManager.h

@@ -0,0 +1,105 @@
+// Filename: cullBinManager.h
+// Created by:  drose (27Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CULLBINMANAGER_H
+#define CULLBINMANAGER_H
+
+#include "pandabase.h"
+#include "cullBin.h"
+#include "pointerTo.h"
+#include "pvector.h"
+#include "pmap.h"
+
+class CullResult;
+class GraphicsStateGuardianBase;
+
+////////////////////////////////////////////////////////////////////
+//       Class : CullBinManager
+// Description : This is a global object that maintains the collection
+//               of named CullBins in the world.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA CullBinManager {
+protected:
+  CullBinManager();
+  ~CullBinManager();
+
+PUBLISHED:
+  enum BinType {
+    BT_invalid,
+    BT_unsorted,
+    BT_state_sorted,
+    BT_back_to_front,
+    BT_fixed,
+  };
+
+  int add_bin(const string &name, BinType type, int sort);
+  void remove_bin(int bin_index);
+
+  INLINE int get_num_bins() const;
+  INLINE int get_bin(int n) const;
+  int find_bin(const string &name) const;
+
+  INLINE string get_bin_name(int bin_index) const;
+  INLINE BinType get_bin_type(int bin_index) const;
+
+  INLINE int get_bin_sort(int bin_index) const;
+  INLINE void set_bin_sort(int bin_index, int sort);
+
+  static CullBinManager *get_global_ptr();
+
+public:
+  // This interface is only intended to be used by CullResult.
+  PT(CullBin) make_new_bin(int bin_index, GraphicsStateGuardianBase *gsg);
+
+private:
+  void do_sort_bins();
+  void setup_initial_bins();
+  static BinType parse_bin_type(const string &bin_type);
+
+  class EXPCL_PANDA BinDefinition {
+  public:
+    bool _in_use;
+    string _name;
+    BinType _type;
+    int _sort;
+  };
+  typedef pvector<BinDefinition> BinDefinitions;
+  BinDefinitions _bin_definitions;
+
+  class SortBins {
+  public:
+    INLINE SortBins(CullBinManager *manager);
+    INLINE bool operator () (int a, int b) const;
+    CullBinManager *_manager;
+  };
+
+  typedef pmap<string, int> BinsByName;
+  BinsByName _bins_by_name;
+
+  typedef pvector<int> SortedBins;
+  SortedBins _sorted_bins;
+  bool _bins_are_sorted;
+  bool _unused_bin_index;
+
+  static CullBinManager *_global_ptr;
+  friend class SortBins;
+};
+
+#include "cullBinManager.I"
+
+#endif

+ 44 - 0
panda/src/pgraph/cullBinUnsorted.I

@@ -0,0 +1,44 @@
+// Filename: cullBinUnsorted.I
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: CullBinUnsorted::GeomData::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE CullBinUnsorted::GeomData::
+GeomData(Geom *geom, const TransformState *transform,
+         const RenderState *state) :
+  _geom(geom),
+  _transform(transform),
+  _state(state)
+{
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinUnsorted::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE CullBinUnsorted::
+CullBinUnsorted(GraphicsStateGuardianBase *gsg) :
+  CullBin(gsg)
+{
+}

+ 52 - 0
panda/src/pgraph/cullBinUnsorted.cxx

@@ -0,0 +1,52 @@
+// Filename: cullBinUnsorted.cxx
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cullBinUnsorted.h"
+#include "graphicsStateGuardianBase.h"
+
+
+TypeHandle CullBinUnsorted::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinUnsorted::add_geom
+//       Access: Public, Virtual
+//  Description: Adds the geom, along with its associated state, to
+//               the bin for rendering.
+////////////////////////////////////////////////////////////////////
+void CullBinUnsorted::
+add_geom(Geom *geom, const TransformState *transform,
+         const RenderState *state) {
+  _geoms.push_back(GeomData(geom, transform, state));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullBinUnsorted::draw
+//       Access: Public
+//  Description: Draws all the geoms in the bin, in the appropriate
+//               order.
+////////////////////////////////////////////////////////////////////
+void CullBinUnsorted::
+draw() {
+  Geoms::iterator gi;
+  for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
+    GeomData &geom_data = (*gi);
+    _gsg->set_state_and_transform(geom_data._state, geom_data._transform);
+    geom_data._geom->draw(_gsg);
+  }
+}
+

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

@@ -0,0 +1,81 @@
+// Filename: cullBinUnsorted.h
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CULLBINUNSORTED_H
+#define CULLBINUNSORTED_H
+
+#include "pandabase.h"
+
+#include "cullBin.h"
+#include "geom.h"
+#include "transformState.h"
+#include "renderState.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : CullBinUnsorted
+// Description : A specific kind of CullBin that does not reorder the
+//               geometry; it simply passes it through to the GSG in
+//               the same order it was encountered, which will be in
+//               scene-graph order.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA CullBinUnsorted : public CullBin {
+public:
+  INLINE CullBinUnsorted(GraphicsStateGuardianBase *gsg);
+
+  virtual void add_geom(Geom *geom, const TransformState *transform,
+                        const RenderState *state);
+  virtual void draw();
+
+private:
+  class GeomData {
+  public:
+    INLINE GeomData(Geom *geom, const TransformState *transform,
+                    const RenderState *state);
+    PT(Geom) _geom;
+    CPT(TransformState) _transform;
+    CPT(RenderState) _state;
+  };
+
+  typedef pvector<GeomData> Geoms;
+  Geoms _geoms;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    CullBin::init_type();
+    register_type(_type_handle, "CullBinUnsorted",
+                  CullBin::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 "cullBinUnsorted.I"
+
+#endif
+
+
+  

+ 11 - 0
panda/src/pgraph/cullHandler.cxx

@@ -21,6 +21,17 @@
 #include "transformState.h"
 #include "renderState.h"
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullHandler::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+CullHandler::
+~CullHandler()
+{
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullHandler::record_geom
 //       Access: Public, Virtual

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

@@ -34,6 +34,8 @@ class RenderState;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA CullHandler {
 public:
+  virtual ~CullHandler();
+
   //  virtual void begin_decal();
   virtual void record_geom(Geom *geom, const TransformState *transform,
                            const RenderState *state);

+ 69 - 0
panda/src/pgraph/cullResult.I

@@ -0,0 +1,69 @@
+// Filename: cullResult.I
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: CullResult::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE CullResult::
+CullResult(GraphicsStateGuardianBase *gsg) :
+  _gsg(gsg)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE CullResult::
+~CullResult() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::get_bin
+//       Access: Public
+//  Description: Returns the CullBin associated with the indicated
+//               bin_index, or NULL if the bin_index is invalid.  If
+//               there is the first time this bin_index has been
+//               requested for this CullResult, creates a new CullBin
+//               object on the fly.
+////////////////////////////////////////////////////////////////////
+INLINE CullBin *CullResult::
+get_bin(int bin_index) {
+  if (bin_index >= 0 && bin_index < (int)_bins.size() && 
+      _bins[bin_index] != (CullBin *)NULL) {
+    return _bins[bin_index];
+  }
+  return make_new_bin(bin_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::add_geom
+//       Access: Public
+//  Description: Adds the indicated Geom to the appropriate bin.
+////////////////////////////////////////////////////////////////////
+INLINE void CullResult::
+add_geom(Geom *geom, const TransformState *transform,
+         const RenderState *state) {
+  CullBin *bin = get_bin(state->get_bin_index());
+  nassertv(bin != (CullBin *)NULL);
+  bin->add_geom(geom, transform, state);
+}

+ 121 - 0
panda/src/pgraph/cullResult.cxx

@@ -0,0 +1,121 @@
+// Filename: cullResult.cxx
+// Created by:  drose (28Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cullResult.h"
+#include "cullBinManager.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::make_next
+//       Access: Public
+//  Description: Returns a newly-allocated CullResult object that
+//               contains a copy of just the subset of the data from
+//               this CullResult object that is worth keeping around
+//               for next frame.
+////////////////////////////////////////////////////////////////////
+PT(CullResult) CullResult::
+make_next() const {
+  PT(CullResult) new_result = new CullResult(_gsg);
+  new_result->_bins.reserve(_bins.size());
+
+  for (Bins::const_iterator bi = _bins.begin(); bi != _bins.end(); ++bi) {
+    CullBin *old_bin = (*bi);
+    if (old_bin == (CullBin *)NULL) {
+      new_result->_bins.push_back((CullBin *)NULL);
+    } else {
+      new_result->_bins.push_back(old_bin->make_next());
+    }
+  }
+
+  return new_result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::finish_cull
+//       Access: Public
+//  Description: Called after all the geoms have been added, this
+//               indicates that the cull process is finished for this
+//               frame and gives the bins a chance to do any
+//               post-processing (like sorting) before moving on to
+//               draw.
+////////////////////////////////////////////////////////////////////
+void CullResult::
+finish_cull() {
+  for (Bins::iterator bi = _bins.begin(); bi != _bins.end(); ++bi) {
+    CullBin *bin = (*bi);
+    if (bin != (CullBin *)NULL) {
+      bin->finish_cull();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::draw
+//       Access: Public
+//  Description: Asks all the bins to draw themselves in the correct
+//               order.
+////////////////////////////////////////////////////////////////////
+void CullResult::
+draw() {
+  // Ask the bin manager for the correct order to draw all the bins.
+  CullBinManager *bin_manager = CullBinManager::get_global_ptr();
+  int num_bins = bin_manager->get_num_bins();
+  for (int i = 0; i < num_bins; i++) {
+    int bin_index = bin_manager->get_bin(i);
+    nassertv(bin_index >= 0);
+
+    if (bin_index < (int)_bins.size() && _bins[bin_index] != (CullBin *)NULL) {
+      _bins[bin_index]->draw();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::bin_removed
+//       Access: Public, Static
+//  Description: Intended to be called by
+//               CullBinManager::remove_bin(), this informs all the
+//               CullResults in the world to remove the indicated
+//               bin_index from their cache if it has been cached.
+////////////////////////////////////////////////////////////////////
+void CullResult::
+bin_removed(int bin_index) {
+  // Do something here.
+  nassertv(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::make_new_bin
+//       Access: Private
+//  Description: Allocates a new CullBin for the given bin_index and
+//               stores it for next time.
+////////////////////////////////////////////////////////////////////
+CullBin *CullResult::
+make_new_bin(int bin_index) {
+  CullBinManager *bin_manager = CullBinManager::get_global_ptr();
+  PT(CullBin) bin = bin_manager->make_new_bin(bin_index, _gsg);
+  if (bin != (CullBin *)NULL) {
+    // Now store it in the vector.
+    while (bin_index >= (int)_bins.size()) {
+      _bins.push_back((CullBin *)NULL);
+    }
+    nassertr(bin_index >= 0 && bin_index < (int)_bins.size(), NULL);
+    _bins[bin_index] = bin;
+  }
+
+  return bin;
+}

+ 80 - 0
panda/src/pgraph/cullResult.h

@@ -0,0 +1,80 @@
+// Filename: cullResult.h
+// Created by:  drose (27Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CULLRESULT_H
+#define CULLRESULT_H
+
+#include "pandabase.h"
+#include "cullBin.h"
+#include "renderState.h"
+
+#include "referenceCount.h"
+#include "pointerTo.h"
+#include "pvector.h"
+#include "pset.h"
+
+class GraphicsStateGuardianBase;
+class TransformState;
+class RenderState;
+
+////////////////////////////////////////////////////////////////////
+//       Class : CullResult
+// Description : This stores the result of a BinCullHandler traversal:
+//               an ordered collection of CullBins, each of which
+//               holds a number of Geoms and RenderStates to be
+//               rendered in some defined order.
+//
+//               This is also used to keep the results of last frame's
+//               cull traversal around to make next frame's traversal
+//               of the same scene a little easier.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA CullResult : public ReferenceCount {
+public:
+  INLINE CullResult(GraphicsStateGuardianBase *gsg);
+  INLINE ~CullResult();
+
+  PT(CullResult) make_next() const;
+
+  INLINE CullBin *get_bin(int bin_index);
+
+  INLINE void add_geom(Geom *geom, const TransformState *transform,
+                       const RenderState *state);
+  void finish_cull();
+  void draw();
+
+public:
+  static void bin_removed(int bin_index);
+
+private:
+  CullBin *make_new_bin(int bin_index);
+
+  GraphicsStateGuardianBase *_gsg;
+
+  typedef pvector< PT(CullBin) > Bins;
+  Bins _bins;
+
+  typedef pset<CullResult *> CullResults;
+  static CullResults _cull_results;
+};
+
+#include "cullResult.I"
+
+#endif
+
+
+  

+ 5 - 5
panda/src/pgraph/pgraph_composite1.cxx

@@ -1,12 +1,12 @@
 #include "billboardAttrib.cxx"
+#include "binCullHandler.cxx"
 #include "qpcamera.cxx"
 #include "colorAttrib.cxx"
 #include "config_pgraph.cxx"
+#include "cullBin.cxx"
+#include "cullBinManager.cxx"
+#include "cullBinUnsorted.cxx"
 #include "cullFaceAttrib.cxx"
 #include "cullHandler.cxx"
+#include "cullResult.cxx"
 #include "qpcullTraverser.cxx"
-#include "cycleData.cxx"
-#include "cycleDataReader.cxx"
-#include "cycleDataWriter.cxx"
-#include "qpgeomNode.cxx"
-#include "qplensNode.cxx"

+ 5 - 0
panda/src/pgraph/pgraph_composite2.cxx

@@ -1,3 +1,8 @@
+#include "cycleData.cxx"
+#include "cycleDataReader.cxx"
+#include "cycleDataWriter.cxx"
+#include "qpgeomNode.cxx"
+#include "qplensNode.cxx"
 #include "nodeChain.cxx"
 #include "nodeChainComponent.cxx"
 #include "pandaNode.cxx"

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

@@ -167,3 +167,22 @@ get_billboard() const {
   }
   return _billboard;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::get_bin_index
+//       Access: Public
+//  Description: Returns the bin index indicated by the CullBinAttrib
+//               transition, if any, associated by this state (or the
+//               default bin index if there is no CullBinAttrib).  As
+//               in get_billboard(), above, this function is provided
+//               as an optimization.
+////////////////////////////////////////////////////////////////////
+INLINE int RenderState::
+get_bin_index() const {
+  if ((_flags & F_checked_bin_index) == 0) {
+    // We pretend this function is const, even though it transparently
+    // modifies the internal bin_index cache.
+    ((RenderState *)this)->determine_bin_index();
+  }
+  return _bin_index;
+}

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

@@ -18,6 +18,8 @@
 
 #include "renderState.h"
 #include "billboardAttrib.h"
+#include "cullBinManager.h"
+#include "config_pgraph.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "datagramIterator.h"
@@ -666,6 +668,20 @@ issue_delta_set(const RenderState *other,
   return other;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::bin_removed
+//       Access: Public, Static
+//  Description: Intended to be called by
+//               CullBinManager::remove_bin(), this informs all the
+//               RenderStates in the world to remove the indicated
+//               bin_index from their cache if it has been cached.
+////////////////////////////////////////////////////////////////////
+void RenderState::
+bin_removed(int bin_index) {
+  // Do something here.
+  nassertv(false);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::return_new
 //       Access: Private, Static
@@ -841,6 +857,33 @@ determine_billboard() {
   _flags |= F_checked_billboard;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::determine_bin_index
+//       Access: Private
+//  Description: This is the private implementation of
+//               get_bin_index().
+////////////////////////////////////////////////////////////////////
+void RenderState::
+determine_bin_index() {
+  string bin_name = "opaque";
+
+  /*
+  const RenderAttrib *attrib = get_attrib(CullBinAttrib::get_class_type());
+  if (attrib != (const RenderAttrib *)NULL) {
+    const CullBinAttrib *bin_attrib = DCAST(CullBinAttrib, attrib);
+  }
+  */
+
+  CullBinManager *bin_manager = CullBinManager::get_global_ptr();
+  _bin_index = bin_manager->find_bin(bin_name);
+  if (_bin_index == -1) {
+    pgraph_cat.warning()
+      << "No bin named " << bin_name << "; creating default bin.\n";
+    _bin_index = bin_manager->add_bin(bin_name, CullBinManager::BT_unsorted, 0);
+  }
+  _flags |= F_checked_bin_index;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::register_with_read_factory
 //       Access: Public, Static

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

@@ -88,17 +88,21 @@ PUBLISHED:
 
 public:
   INLINE const BillboardAttrib *get_billboard() const;
+  INLINE int get_bin_index() const;
 
   CPT(RenderState) issue_delta_modify(const RenderState *other, 
                                       GraphicsStateGuardianBase *gsg) const;
   CPT(RenderState) issue_delta_set(const RenderState *other, 
                                    GraphicsStateGuardianBase *gsg) const;
 
+  static void bin_removed(int bin_index);
+
 private:
   static CPT(RenderState) return_new(RenderState *state);
   CPT(RenderState) do_compose(const RenderState *other) const;
   CPT(RenderState) do_invert_compose(const RenderState *other) const;
   void determine_billboard();
+  void determine_bin_index();
 
 private:
   typedef pset<const RenderState *, IndirectLess<RenderState> > States;
@@ -154,8 +158,13 @@ private:
   // We cache the pointer to the BillboardAttrib stored in the state,
   // if there is one.
   const BillboardAttrib *_billboard;
+  
+  // We also cache the index to the associated GeomBin.
+  int _bin_index;
+
   enum Flags {
     F_checked_billboard    = 0x0001,
+    F_checked_bin_index    = 0x0002,
   };
   short _flags;
 

+ 1 - 1
panda/src/testbed/pview.cxx

@@ -183,7 +183,7 @@ make_default_geometry(PandaNode *parent) {
   if (tex != (Texture *)NULL) {
     tex->set_minfilter(Texture::FT_linear);
     tex->set_magfilter(Texture::FT_linear);
-    state->add_attrib(TextureAttrib::make(tex));
+    state = state->add_attrib(TextureAttrib::make(tex));
   }
   
   qpGeomNode *geomnode = new qpGeomNode("tri");