Răsfoiți Sursa

integrate more new-scene-graph stuff

David Rose 24 ani în urmă
părinte
comite
6a8b0b3913
48 a modificat fișierele cu 1463 adăugiri și 140 ștergeri
  1. 22 6
      panda/src/display/Sources.pp
  2. 4 1
      panda/src/display/displayRegion.I
  3. 16 1
      panda/src/display/displayRegion.cxx
  4. 4 0
      panda/src/display/displayRegion.h
  5. 2 0
      panda/src/display/display_composite1.cxx
  6. 29 0
      panda/src/display/drawCullHandler.I
  7. 36 0
      panda/src/display/drawCullHandler.cxx
  8. 56 0
      panda/src/display/drawCullHandler.h
  9. 5 1
      panda/src/display/graphicsChannel.I
  10. 15 0
      panda/src/display/graphicsChannel.cxx
  11. 3 0
      panda/src/display/graphicsChannel.h
  12. 18 0
      panda/src/display/graphicsEngine.I
  13. 156 0
      panda/src/display/graphicsEngine.cxx
  14. 66 0
      panda/src/display/graphicsEngine.h
  15. 7 4
      panda/src/display/graphicsLayer.I
  16. 20 0
      panda/src/display/graphicsLayer.cxx
  17. 4 0
      panda/src/display/graphicsLayer.h
  18. 103 1
      panda/src/display/graphicsStateGuardian.I
  19. 102 2
      panda/src/display/graphicsStateGuardian.cxx
  20. 35 3
      panda/src/display/graphicsStateGuardian.h
  21. 55 0
      panda/src/display/graphicsWindow.I
  22. 62 0
      panda/src/display/graphicsWindow.cxx
  23. 19 5
      panda/src/display/graphicsWindow.h
  24. 61 0
      panda/src/display/lensStack.I
  25. 50 0
      panda/src/display/lensStack.h
  26. 72 70
      panda/src/glgsg/glGraphicsStateGuardian.cxx
  27. 3 12
      panda/src/glgsg/glGraphicsStateGuardian.h
  28. 6 0
      panda/src/gsgbase/graphicsStateGuardianBase.h
  29. 1 1
      panda/src/pgraph/Sources.pp
  30. 15 0
      panda/src/pgraph/colorAttrib.cxx
  31. 1 0
      panda/src/pgraph/colorAttrib.h
  32. 2 2
      panda/src/pgraph/cullHandler.cxx
  33. 5 2
      panda/src/pgraph/cullHandler.h
  34. 2 2
      panda/src/pgraph/pandaNode.I
  35. 9 1
      panda/src/pgraph/pandaNode.h
  36. 1 13
      panda/src/pgraph/pipeline.cxx
  37. 1 4
      panda/src/pgraph/pipeline.h
  38. 1 1
      panda/src/pgraph/qpcullTraverser.cxx
  39. 21 0
      panda/src/pgraph/renderAttrib.I
  40. 29 2
      panda/src/pgraph/renderAttrib.cxx
  41. 5 0
      panda/src/pgraph/renderAttrib.h
  42. 273 5
      panda/src/pgraph/renderState.cxx
  43. 12 1
      panda/src/pgraph/renderState.h
  44. 15 0
      panda/src/pgraph/textureAttrib.cxx
  45. 1 0
      panda/src/pgraph/textureAttrib.h
  46. 24 0
      panda/src/sgraph/camera.I
  47. 5 0
      panda/src/sgraph/camera.h
  48. 9 0
      panda/src/testbed/Sources.pp

+ 22 - 6
panda/src/display/Sources.pp

@@ -4,28 +4,38 @@
 #begin lib_target
   #define TARGET display
   #define LOCAL_LIBS \
-    putil gsgbase gobj linmath graph mathutil sgraph \
+    pgraph putil gsgbase gobj linmath graph mathutil sgraph \
     pstatclient
 
   #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx 
  
   #define SOURCES  \
      config_display.h displayRegion.I displayRegion.h  \
+     displayRegionStack.I \
+     displayRegionStack.h \
+     drawCullHandler.h drawCullHandler.I \
+     frameBufferStack.I frameBufferStack.h \
      geomContext.I geomContext.h geomNodeContext.I geomNodeContext.h \
-     graphicsChannel.I graphicsChannel.h graphicsLayer.I  \
+     graphicsChannel.I graphicsChannel.h \
+     graphicsEngine.I graphicsEngine.h \
+     graphicsLayer.I  \
      graphicsLayer.h graphicsPipe.I graphicsPipe.N graphicsPipe.h  \
      graphicsStateGuardian.I graphicsStateGuardian.N  \
      graphicsStateGuardian.h graphicsWindow.I graphicsWindow.N  \
      graphicsWindow.h graphicsWindowInputDevice.I  \
      graphicsWindowInputDevice.h hardwareChannel.I  \
      hardwareChannel.h interactiveGraphicsPipe.I  \
-     interactiveGraphicsPipe.h noninteractiveGraphicsPipe.I  \
+     interactiveGraphicsPipe.h \
+     lensStack.I lensStack.h \
+     noninteractiveGraphicsPipe.I  \
      noninteractiveGraphicsPipe.h pipeSpec.I pipeSpec.h  \
      savedFrameBuffer.I savedFrameBuffer.h
      
  #define INCLUDED_SOURCES  \
      config_display.cxx displayRegion.cxx \
+     drawCullHandler.cxx \
      geomContext.cxx geomNodeContext.cxx graphicsChannel.cxx  \
+     graphicsEngine.cxx \
      graphicsLayer.cxx graphicsPipe.cxx graphicsStateGuardian.cxx  \
      graphicsWindow.cxx graphicsWindowInputDevice.cxx  \
      hardwareChannel.cxx interactiveGraphicsPipe.cxx  \
@@ -35,14 +45,20 @@
   #define INSTALL_HEADERS \
     config_display.h \
     displayRegion.I displayRegion.h displayRegionStack.I \
-    displayRegionStack.h frameBufferStack.I frameBufferStack.h \
+    displayRegionStack.h \
+    drawCullHandler.h drawCullHandler.I \
+    frameBufferStack.I frameBufferStack.h \
     geomContext.I geomContext.h geomNodeContext.I geomNodeContext.h \
-    graphicsChannel.I graphicsChannel.h graphicsLayer.I graphicsLayer.h \
+    graphicsChannel.I graphicsChannel.h \
+    graphicsEngine.I graphicsEngine.h \
+    graphicsLayer.I graphicsLayer.h \
     graphicsPipe.I graphicsPipe.h graphicsStateGuardian.I \
     graphicsStateGuardian.h graphicsWindow.I graphicsWindow.h \
     graphicsWindowInputDevice.I graphicsWindowInputDevice.h \
     hardwareChannel.I hardwareChannel.h interactiveGraphicsPipe.I \
-    interactiveGraphicsPipe.h noninteractiveGraphicsPipe.I \
+    interactiveGraphicsPipe.h \
+    lensStack.I lensStack.h \
+    noninteractiveGraphicsPipe.I \
     noninteractiveGraphicsPipe.h pipeSpec.I pipeSpec.h renderBuffer.h \
     savedFrameBuffer.I savedFrameBuffer.h
 

+ 4 - 1
panda/src/display/displayRegion.I

@@ -140,7 +140,10 @@ get_cull_frustum() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void DisplayRegion::
 set_active(bool active) {
-  _active = active;
+  if (active != _active) {
+    _active = active;
+    win_display_regions_changed();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 16 - 1
panda/src/display/displayRegion.cxx

@@ -21,9 +21,9 @@
 #include "graphicsChannel.h"
 #include "graphicsWindow.h"
 #include "config_display.h"
-
 #include "displayRegion.h"
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DisplayRegion::Constructor
 //       Access: Public
@@ -193,3 +193,18 @@ output(ostream &out) const {
       << ")=pixels(" << _pl << " " << _pr << " " << _pb << " " << _pt
       << ")";
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: DisplayRegion::win_display_regions_changed
+//       Access: Public
+//  Description: Intended to be called when the active state on a
+//               nested channel or layer or display region changes,
+//               forcing the window to recompute its list of active
+//               display regions.
+////////////////////////////////////////////////////////////////////
+void DisplayRegion::
+win_display_regions_changed() {
+  if (_layer != (GraphicsLayer *)NULL) {
+    _layer->win_display_regions_changed();
+  }
+}

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

@@ -35,6 +35,7 @@ class GraphicsLayer;
 class GraphicsChannel;
 class GraphicsWindow;
 class GraphicsPipe;
+class CullHandler;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : DisplayRegion
@@ -80,6 +81,9 @@ PUBLISHED:
 
   void output(ostream &out) const;
 
+public:
+  void win_display_regions_changed();
+
 protected:
 
   float _l;

+ 2 - 0
panda/src/display/display_composite1.cxx

@@ -1,8 +1,10 @@
 
 #include "displayRegion.cxx"
+#include "drawCullHandler.cxx"
 #include "geomContext.cxx"
 #include "geomNodeContext.cxx"
 #include "graphicsChannel.cxx"
+#include "graphicsEngine.cxx"
 #include "graphicsLayer.cxx"
 #include "graphicsPipe.cxx"
 #include "graphicsStateGuardian.cxx"

+ 29 - 0
panda/src/display/drawCullHandler.I

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

+ 36 - 0
panda/src/display/drawCullHandler.cxx

@@ -0,0 +1,36 @@
+// Filename: drawCullHandler.cxx
+// Created by:  drose (25Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "drawCullHandler.h"
+#include "geom.h"
+#include "renderState.h"
+#include "graphicsStateGuardian.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: DrawCullHandler::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 DrawCullHandler::
+record_geom(Geom *geom, const RenderState *state) {
+  _gsg->set_state(state);
+  geom->draw(_gsg);
+}

+ 56 - 0
panda/src/display/drawCullHandler.h

@@ -0,0 +1,56 @@
+// Filename: drawCullHandler.h
+// Created by:  drose (25Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 DRAWCULLHANDLER_H
+#define DRAWCULLHANDLER_H
+
+#include "pandabase.h"
+#include "cullHandler.h"
+
+class GraphicsStateGuardian;
+
+////////////////////////////////////////////////////////////////////
+//       Class : DrawCullHandler
+// Description : This special kind of CullHandler immediately draws
+//               its contents as soon as it receives them.  This draws
+//               geometry immediately as it is encountered in the
+//               scene graph by cull, mixing the draw and cull
+//               traversals into one traversal, and prohibiting state
+//               sorting.  However, it has somewhat lower overhead
+//               than separating out draw and cull, if state sorting
+//               and multiprocessing are not required.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA DrawCullHandler : public CullHandler {
+public:
+  INLINE DrawCullHandler(GraphicsStateGuardian *gsg);
+
+  //  virtual void begin_decal();
+  virtual void record_geom(Geom *geom, const RenderState *state);
+  //  virtual void push_decal();
+  //  virtual void pop_decal();
+
+private:
+  GraphicsStateGuardian *_gsg;
+};
+
+#include "drawCullHandler.I"
+
+#endif
+
+
+  

+ 5 - 1
panda/src/display/graphicsChannel.I

@@ -16,6 +16,7 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsChannel::set_active
 //       Access: Public
@@ -24,7 +25,10 @@
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsChannel::
 set_active(bool active) {
-  _is_active = active;
+  if (active != _is_active) {
+    _is_active = active;
+    win_display_regions_changed();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 15 - 0
panda/src/display/graphicsChannel.cxx

@@ -226,3 +226,18 @@ window_resized(int x, int y) {
     (*li)->channel_resized(x, y);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsChannel::win_display_regions_changed
+//       Access: Public
+//  Description: Intended to be called when the active state on a
+//               nested channel or layer or display region changes,
+//               forcing the window to recompute its list of active
+//               display regions.
+////////////////////////////////////////////////////////////////////
+void GraphicsChannel::
+win_display_regions_changed() {
+  if (_window != (GraphicsWindow *)NULL) {
+    _window->win_display_regions_changed();
+  }
+}

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

@@ -36,6 +36,7 @@
 class GraphicsChannel;
 class GraphicsPipe;
 class GraphicsWindow;
+class CullHandler;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsChannel
@@ -67,6 +68,8 @@ PUBLISHED:
 public:
   virtual void window_resized(int x, int y);
 
+  void win_display_regions_changed();
+
 PUBLISHED:
   INLINE void set_active(bool active);
   INLINE bool is_active() const;

+ 18 - 0
panda/src/display/graphicsEngine.I

@@ -0,0 +1,18 @@
+// Filename: graphicsEngine.I
+// Created by:  drose (24Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 156 - 0
panda/src/display/graphicsEngine.cxx

@@ -0,0 +1,156 @@
+// Filename: graphicsEngine.cxx
+// Created by:  drose (24Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "graphicsEngine.h"
+#include "pipeline.h"
+#include "drawCullHandler.h"
+#include "qpcullTraverser.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::Constructor
+//       Access: Published
+//  Description: Creates a new GraphicsEngine object.  The Pipeline is
+//               normally left to default to NULL, which indicates the
+//               global render pipeline, but it may be any Pipeline
+//               you choose.
+////////////////////////////////////////////////////////////////////
+GraphicsEngine::
+GraphicsEngine(Pipeline *pipeline) :
+  _pipeline(pipeline)
+{
+  if (_pipeline == (Pipeline *)NULL) {
+    _pipeline = Pipeline::get_render_pipeline();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::add_window
+//       Access: Published
+//  Description: Adds a new window to the set of windows that will be
+//               processed when render_frame() is called.  This also
+//               increments the reference count to the window.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+add_window(GraphicsWindow *window) {
+  _windows.insert(window);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::remove_window
+//       Access: Published
+//  Description: Removes the indicated window from the set of windows
+//               that will be processed when render_frame() is called.
+//               This also decrements the reference count to the
+//               window, allowing the window to be destructed if there
+//               are no other references to it.
+//
+//               The return value is true if the window was removed,
+//               false if it was not found.
+////////////////////////////////////////////////////////////////////
+bool GraphicsEngine::
+remove_window(GraphicsWindow *window) {
+  size_t count = _windows.erase(window);
+  return (count != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::render_frame
+//       Access: Published
+//  Description: Renders the next frame in all the registered windows,
+//               and flips all of the frame buffers.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+render_frame() {
+  cull_and_draw_together();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::cull_and_draw_together
+//       Access: Private
+//  Description: An implementation of render_frame() that renders the
+//               frame with a DrawCullHandler, to cull and draw all
+//               windows in the same pass.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+cull_and_draw_together() {
+  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_and_draw_together(win, dr);
+    }
+    win->flip();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::cull_and_draw_together
+//       Access: Private
+//  Description: An implementation of render_frame() that renders the
+//               frame with a DrawCullHandler, to cull and draw all
+//               windows in the same pass.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr) {
+  Camera *camera = dr->get_camera();
+  if (camera == (Camera *)NULL || !camera->is_active()) {
+    // No camera, no draw.
+    return;
+  }
+
+  Lens *lens = camera->get_lens();
+  if (lens == (Lens *)NULL) {
+    // No lens, no draw.
+    return;
+  }
+
+  PandaNode *scene = camera->get_qpscene();
+  if (scene == (PandaNode *)NULL) {
+    // 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;
+  }
+
+  DrawCullHandler cull_handler(gsg);
+  qpCullTraverser trav;
+  trav.set_cull_handler(&cull_handler);
+  
+  // Here we should figure out the world transform: the camera's
+  // inverse transform.
+  
+  DisplayRegionStack old_dr = gsg->push_display_region(dr);
+  gsg->prepare_display_region();
+  
+  trav.traverse(scene);
+  
+  gsg->pop_display_region(old_dr);
+}

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

@@ -0,0 +1,66 @@
+// Filename: graphicsEngine.h
+// Created by:  drose (24Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 GRAPHICSENGINE_H
+#define GRAPHICSENGINE_H
+
+#include "pandabase.h"
+#include "graphicsWindow.h"
+#include "pointerTo.h"
+#include "pset.h"
+
+class Pipeline;
+class DisplayRegion;
+
+////////////////////////////////////////////////////////////////////
+//       Class : GraphicsEngine
+// Description : This class is the main interface to controlling the
+//               render process.  There is typically only one
+//               GraphicsEngine in an application, and it synchronizes
+//               rendering to all all of the active windows; although
+//               it is possible to have multiple GraphicsEngine
+//               objects if multiple synchronicity groups are
+//               required.
+//
+//               The GraphicsEngine is responsible for managing the
+//               cull and draw processes.  The application simply
+//               calls engine->render_frame() and considers it done.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA GraphicsEngine : public Namable {
+PUBLISHED:
+  GraphicsEngine(Pipeline *pipeline = NULL);
+
+  void add_window(GraphicsWindow *window);
+  bool remove_window(GraphicsWindow *window);
+
+  void render_frame();
+
+private:
+  void cull_and_draw_together();
+  void cull_and_draw_together(GraphicsWindow *win, DisplayRegion *dr);
+
+  Pipeline *_pipeline;
+
+  typedef pset<PT(GraphicsWindow)> Windows;
+  Windows _windows;
+};
+
+#include "graphicsEngine.I"
+
+#endif
+

+ 7 - 4
panda/src/display/graphicsLayer.I

@@ -18,7 +18,7 @@
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsLayer::get_channel
-//       Access: Public
+//       Access: Published
 //  Description: Returns the GraphicsChannel that this layer is
 //               associated with.  It is possible that the
 //               GraphicsChannel might have been deleted while an
@@ -33,18 +33,21 @@ get_channel() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsLayer::set_active
-//       Access: Public
+//       Access: Published
 //  Description: Sets the active flag on the layer.  If the layer
 //               is marked as inactive, nothing will be rendered.
 ////////////////////////////////////////////////////////////////////
 INLINE void GraphicsLayer::
 set_active(bool active) {
-  _is_active = active;
+  if (active != _is_active) {
+    _is_active = active;
+    win_display_regions_changed();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsLayer::is_active
-//       Access: Public
+//       Access: Published
 //  Description: Returns the active flag on the layer.
 ////////////////////////////////////////////////////////////////////
 INLINE bool GraphicsLayer::

+ 20 - 0
panda/src/display/graphicsLayer.cxx

@@ -93,6 +93,7 @@ GraphicsLayer::
        ++dri) {
     (*dri)->_layer = NULL;
   }
+  win_display_regions_changed();
 
   // We don't need to remove ourself from the channel's list of
   // layers.  We must have already been removed, or we wouldn't be
@@ -113,6 +114,7 @@ make_display_region() {
     dr->compute_pixels(win->get_width(), win->get_height());
   }
   _display_regions.push_back(dr);
+  win_display_regions_changed();
   return dr;
 }
 
@@ -131,6 +133,7 @@ make_display_region(float l, float r, float b, float t) {
     dr->compute_pixels(win->get_width(), win->get_height());
   }
   _display_regions.push_back(dr);
+  win_display_regions_changed();
   return dr;
 }
 
@@ -169,6 +172,7 @@ remove_dr(int index) {
   nassertv(index >= 0 && index < (int)_display_regions.size());
   _display_regions[index]->_layer = NULL;
   _display_regions.erase(_display_regions.begin() + index);
+  win_display_regions_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -190,6 +194,7 @@ remove_dr(DisplayRegion *display_region) {
   if (dri != _display_regions.end()) {
     display_region->_layer = NULL;
     _display_regions.erase(dri);
+    win_display_regions_changed();
     return true;
   }
   return false;
@@ -238,3 +243,18 @@ channel_resized(int x, int y) {
     (*dri)->compute_pixels(x, y);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsLayer::win_display_regions_changed
+//       Access: Public
+//  Description: Intended to be called when the active state on a
+//               nested channel or layer or display region changes,
+//               forcing the window to recompute its list of active
+//               display regions.
+////////////////////////////////////////////////////////////////////
+void GraphicsLayer::
+win_display_regions_changed() {
+  if (_channel != (GraphicsChannel *)NULL) {
+    _channel->win_display_regions_changed();
+  }
+}

+ 4 - 0
panda/src/display/graphicsLayer.h

@@ -37,6 +37,7 @@
 class GraphicsChannel;
 class GraphicsWindow;
 class GraphicsPipe;
+class CullHandler;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsLayer
@@ -74,6 +75,8 @@ PUBLISHED:
 public:
   void channel_resized(int x, int y);
 
+  void win_display_regions_changed();
+
 PUBLISHED:
   INLINE void set_active(bool active);
   INLINE bool is_active() const;
@@ -109,6 +112,7 @@ private:
   static TypeHandle _type_handle;
 
   friend class GraphicsChannel;
+  friend class GraphicsWindow;
 };
 
 #include "graphicsLayer.I"

+ 103 - 1
panda/src/display/graphicsStateGuardian.I

@@ -16,7 +16,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <notify.h>
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::StateInfo::Constructor
@@ -114,6 +113,37 @@ set_state(const AllTransitionsWrapper &new_state) {
   set_state(new_state.get_transitions());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::modify_state
+//       Access: Public
+//  Description: Applies the attributes indicated in the state set to
+//               the current state, and issues the changes to the
+//               graphics hardware.
+//
+//               Any transitions not mentioned are left unchanged.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsStateGuardian::
+modify_state(const RenderState *state) {
+  _qpstate = _qpstate->issue_delta_modify(state, this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::set_state
+//       Access: Public
+//  Description: Applies the attributes indicated in the state set to
+//               the current state, and issues the changes to the
+//               graphics hardware.
+//
+//               The state is taken to be a complete description of
+//               what the graphics state should be; any transitions
+//               not mentioned are implicitly reset to their initial
+//               values.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsStateGuardian::
+set_state(const RenderState *state) {
+  _qpstate = _qpstate->issue_delta_set(state, this);
+}
+
 /*
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_state
@@ -168,6 +198,19 @@ get_current_display_region(void) const {
   return _current_display_region;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_current_lens
+//       Access: Public
+//  Description: Returns the current lens being rendered with, as set
+//               by the last call to push_lens() (or restored by
+//               pop_lens()).  This lens will be made active (if it is
+//               not already) by a call to prepare_lens().
+////////////////////////////////////////////////////////////////////
+INLINE const Lens *GraphicsStateGuardian::
+get_current_lens() const {
+  return _current_lens;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::push_display_region
 //       Access: Public
@@ -245,6 +288,65 @@ pop_frame_buffer(FrameBufferStack &node) {
   node._stack_level = -1;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::push_lens
+//       Access: Public
+//  Description: Saves the current lens information and sets up a new
+//               lens for rendering.  The return value from this
+//               function must eventually be passed to a matching
+//               pop_lens() call.
+//
+//               The new lens will not actually be made active for
+//               rendering until the next call to prepare_lens().
+//               This is a state-changing optimization.
+////////////////////////////////////////////////////////////////////
+INLINE LensStack GraphicsStateGuardian::
+push_lens(const Lens *lens) {
+  LensStack old;
+  old._lens = _current_lens;
+  old._stack_level = _lens_stack_level;
+  _lens_stack_level++;
+  _current_lens = lens;
+  return old;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::pop_lens
+//       Access: Public
+//  Description: Restores the lens previously in effect, before the
+//               matching call to push_lens().
+//
+//               The newly-restored lens will not actually be made
+//               active for rendering until the next call to
+//               prepare_lens().  This is a state-changing
+//               optimization.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsStateGuardian::
+pop_lens(LensStack &node) {
+  nassertv(_lens_stack_level > 0);
+  _lens_stack_level--;
+  nassertv(node._stack_level == _lens_stack_level);
+  _current_lens = node._lens;
+  node._stack_level = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::set_lens
+//       Access: Public
+//  Description: Sets a new lens for rendering without bothering to
+//               push or pop.  This replaces the lens most recently
+//               pushed, if any.  There is no need to call
+//               prepare_lens() following this call.
+//
+//               The return value is true if the lens is acceptable,
+//               false if it is not.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+set_lens(const Lens *lens) {
+  _current_lens = lens;
+  return prepare_lens();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::set_coordinate_system
 //       Access: Public

+ 102 - 2
panda/src/display/graphicsStateGuardian.cxx

@@ -21,6 +21,7 @@
 #include "config_display.h"
 #include "textureContext.h"
 #include "renderBuffer.h"
+#include "colorAttrib.h"
 
 #include "clockObject.h"
 #include "geomNode.h"
@@ -93,6 +94,7 @@ GraphicsStateGuardian(GraphicsWindow *win) {
   _win = win;
   _coordinate_system = default_coordinate_system;
   _current_display_region = (DisplayRegion*)0L;
+  _current_lens = (Lens *)NULL;
   reset();
 }
 
@@ -115,8 +117,10 @@ void GraphicsStateGuardian::
 reset() {
   _display_region_stack_level = 0;
   _frame_buffer_stack_level = 0;
+  _lens_stack_level = 0;
 
   _state.clear();
+  _qpstate = RenderState::make_empty();
 
   _buffer_mask = 0;
   _color_clear_value.set(gsg_clear_r, gsg_clear_g, gsg_clear_b, 0.0);
@@ -125,6 +129,17 @@ reset() {
   _accum_clear_value.set(0.0, 0.0, 0.0, 0.0);
   _clear_buffer_type = RenderBuffer::T_back | RenderBuffer::T_depth;
   _normals_enabled = false;
+
+  //Color and alpha transform variables
+  _color_transform_enabled = false;
+  _alpha_transform_enabled = false;
+  _current_color_mat = LMatrix4f::ident_mat();
+  _current_alpha_offset = 0;
+  _current_alpha_scale = 1;
+
+  _has_scene_graph_color = false;
+  _issued_color_stale = false;
+  _vertex_colors_enabled = true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -761,6 +776,47 @@ void GraphicsStateGuardian::
 release_geom(GeomContext *) {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::clear_framebuffer
+//       Access: Public, Virtual
+//  Description: Erases the contents of the framebuffer, according to
+//               _clear_buffer_type, which is set by
+//               enable_frame_clear().
+//
+//               This is used to prepare the framebuffer for drawing
+//               a new frame.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+clear_framebuffer() {
+  if (_clear_buffer_type != 0) {
+    PT(DisplayRegion) win_dr =
+      _win->make_scratch_display_region(_win->get_width(), _win->get_height());
+    nassertv(win_dr != (DisplayRegion*)NULL);
+    DisplayRegionStack old_dr = push_display_region(win_dr);
+    prepare_display_region();
+    clear(get_render_buffer(_clear_buffer_type));
+    pop_display_region(old_dr);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::prepare_lens
+//       Access: Public, Virtual
+//  Description: Makes the current lens (whichever lens was most
+//               recently specified with push_lens()) active, so that
+//               it will transform future rendered geometry.  Normally
+//               this is only called from the draw process, and
+//               usually it is called immediately after a call to
+//               push_lens().
+//
+//               The return value is true if the lens is acceptable,
+//               false if it is not.
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+prepare_lens() {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::wants_normals
 //       Access: Public, Virtual
@@ -784,11 +840,12 @@ wants_texcoords() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::wants_colors
 //       Access: Public, Virtual
-//  Description:
+//  Description: Returns true if the GSG should issue geometry color
+//               commands, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool GraphicsStateGuardian::
 wants_colors() const {
-  return false;
+  return _vertex_colors_enabled;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -822,6 +879,49 @@ void GraphicsStateGuardian::
 end_decal(GeomNode *) {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::issue_color
+//       Access: Public, Virtual
+//  Description: This method is defined in the base class because it
+//               is likely that this functionality will be used for
+//               all (or at least most) kinds of
+//               GraphicsStateGuardians--it's not specific to any one
+//               rendering backend.
+//
+//               The ColorAttribute just changes the interpretation of
+//               the color on the vertices, and fiddles with
+//               _vertex_colors_enabled, etc.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+issue_color(const ColorAttrib *attrib) {
+  switch (attrib->get_color_type()) {
+  case ColorAttrib::T_flat:
+    // Color attribute flat: it specifies a scene graph color that
+    // overrides the vertex color.
+    _scene_graph_color = attrib->get_color();
+    _has_scene_graph_color = true;
+    _vertex_colors_enabled = false;
+    _issued_color_stale = true;
+    break;
+
+  case ColorAttrib::T_off:
+    // Color attribute off: it specifies that no scene graph color is
+    // in effect, and vertex color is not important either.
+    _has_scene_graph_color = false;
+    _issued_color_stale = false;
+    _vertex_colors_enabled = false;
+    break;
+
+  case ColorAttrib::T_vertex:
+    // Color attribute vertex: it specifies that vertex color should
+    // be revealed.
+    _has_scene_graph_color = false;
+    _issued_color_stale = false;
+    _vertex_colors_enabled = true;
+    break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::mark_prepared_texture
 //       Access: Protected

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

@@ -24,6 +24,7 @@
 #include "savedFrameBuffer.h"
 #include "frameBufferStack.h"
 #include "displayRegionStack.h"
+#include "lensStack.h"
 
 #include "graphicsStateGuardianBase.h"
 #include "nodeTransition.h"
@@ -34,7 +35,9 @@
 #include "renderTraverser.h"
 #include "pStatCollector.h"
 #include "allTransitionsWrapper.h"
+#include "renderState.h"
 
+#include "notify.h"
 #include "pvector.h"
 
 class AllTransitionsWrapper;
@@ -101,8 +104,10 @@ public:
 
   virtual void clear(const RenderBuffer &buffer)=0;
   virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region)=0;
+  virtual void clear_framebuffer();
 
   virtual void prepare_display_region()=0;
+  virtual bool prepare_lens();
 
   virtual void render_frame()=0;
   virtual void render_scene(Node *root, LensNode *projnode)=0;
@@ -119,27 +124,32 @@ public:
   // These functions will be queried by the GeomIssuer to determine if
   // it should issue normals, texcoords, and/or colors, based on the
   // GSG's current state.
-  virtual bool wants_normals(void) const;
-  virtual bool wants_texcoords(void) const;
-  virtual bool wants_colors(void) const;
+  virtual bool wants_normals() const;
+  virtual bool wants_texcoords() const;
+  virtual bool wants_colors() const;
 
   virtual void begin_decal(GeomNode *base_geom, AllTransitionsWrapper &attrib);
   virtual void end_decal(GeomNode *base_geom);
 
   virtual void reset();
 
+  // *** QP
   void modify_state(const NodeTransitions &new_state);
   //  void modify_state(const NodeTransitionCache &new_state);
   void set_state(const NodeTransitionCache &new_state);
   INLINE void set_state(const AllTransitionsWrapper &new_state);
   //  INLINE const NodeTransitionCache *get_state() const;
 
+  INLINE void modify_state(const RenderState *state);
+  INLINE void set_state(const RenderState *state);
+
   RenderBuffer get_render_buffer(int buffer_type);
 
   INLINE LensNode *get_current_camera(void) const ;
   INLINE const Node* get_current_root_node(void) const;
 
   INLINE const DisplayRegion *get_current_display_region(void) const;
+  INLINE const Lens *get_current_lens() const;
 
   INLINE DisplayRegionStack push_display_region(const DisplayRegion *dr);
   INLINE void pop_display_region(DisplayRegionStack &node);
@@ -147,6 +157,10 @@ public:
                                             const DisplayRegion *dr);
   INLINE void pop_frame_buffer(FrameBufferStack &node);
 
+  INLINE LensStack push_lens(const Lens *lens);
+  INLINE void pop_lens(LensStack &stack);
+  INLINE bool set_lens(const Lens *lens);
+
   INLINE void set_coordinate_system(CoordinateSystem cs);
   INLINE CoordinateSystem get_coordinate_system() const;
 
@@ -159,6 +173,8 @@ public:
 
   INLINE void clear_cached_state(void) { _state.clear(); };  
 
+  virtual void issue_color(const ColorAttrib *attrib);
+
 protected:
   virtual PT(SavedFrameBuffer) save_frame_buffer(const RenderBuffer &buffer,
                                                  CPT(DisplayRegion) dr)=0;
@@ -207,6 +223,8 @@ protected:
   typedef pvector<StateInfo> State;
   State _state;
 
+  CPT(RenderState) _qpstate;
+
   int _buffer_mask;
   Colorf _color_clear_value;
   float _depth_clear_value;
@@ -216,6 +234,7 @@ protected:
 
   int _display_region_stack_level;
   int _frame_buffer_stack_level;
+  int _lens_stack_level;
 
   GraphicsWindow *_win;
   PT(RenderTraverser) _render_traverser;
@@ -225,11 +244,24 @@ protected:
   LensNode *_current_camera;
   CPT(DisplayRegion) _current_display_region;
 
+  CPT(Lens) _current_lens;
+
   // This is used by wants_normals()
   bool _normals_enabled;
 
   CoordinateSystem _coordinate_system;
 
+  Colorf _scene_graph_color;
+  bool _has_scene_graph_color;
+  bool _issued_color_stale;
+  bool _vertex_colors_enabled;
+
+  bool _color_transform_enabled;
+  bool _alpha_transform_enabled;
+  LMatrix4f _current_color_mat;
+  float _current_alpha_offset;
+  float _current_alpha_scale;
+
 public:
   // Statistics
   static PStatCollector _total_texusage_pcollector;

+ 55 - 0
panda/src/display/graphicsWindow.I

@@ -418,6 +418,19 @@ render_and_update() {
   update();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::win_display_regions_changed
+//       Access: Public
+//  Description: Intended to be called when the active state on a
+//               nested channel or layer or display region changes,
+//               forcing the window to recompute its list of active
+//               display regions.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindow::
+win_display_regions_changed() {
+  _display_regions_stale = true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::set_sync
 //       Access: Public
@@ -441,3 +454,45 @@ get_sync() const {
   return _is_synced;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::get_num_display_regions
+//       Access: Published
+//  Description: Returns the number of active DisplayRegions that have
+//               been created within the various layers and channels
+//               of the window.
+////////////////////////////////////////////////////////////////////
+INLINE int GraphicsWindow::
+get_num_display_regions() const {
+  determine_display_regions();
+  return _display_regions.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::get_display_region
+//       Access: Published
+//  Description: Returns the nth active DisplayRegion of those that
+//               have been created within the various layers and
+//               channels of the window.
+////////////////////////////////////////////////////////////////////
+INLINE DisplayRegion *GraphicsWindow::
+get_display_region(int n) const {
+  determine_display_regions();
+  nassertr(n >= 0 && n < (int)_display_regions.size(), NULL);
+  return _display_regions[n];
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::determine_display_regions
+//       Access: Private
+//  Description: Recomputes the list of active DisplayRegions within
+//               the window, if they have changed recently.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindow::
+determine_display_regions() const {
+  // This function isn't strictly speaking const, but we pretend it is
+  // because it only updates a transparent cache value.
+  if (_display_regions_stale) {
+    ((GraphicsWindow *)this)->do_determine_display_regions();
+  }
+}

+ 62 - 0
panda/src/display/graphicsWindow.cxx

@@ -142,6 +142,7 @@ GraphicsWindow(GraphicsPipe *pipe) : Configurable() {
   _idle_callback = NULL;
   _frame_number = 0;
   _is_synced = false;
+  _display_regions_stale = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -350,6 +351,40 @@ declare_channel(int index, GraphicsChannel *chan) {
   _channels[index] = chan;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::do_determine_display_regions
+//       Access: Private
+//  Description: Recomputes the list of active DisplayRegions within
+//               the window.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindow::
+do_determine_display_regions() {
+  _display_regions.clear();
+  Channels::const_iterator ci;
+  for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
+    GraphicsChannel *chan = (*ci);
+    if (chan->is_active()) {
+      GraphicsChannel::GraphicsLayers::const_iterator li;
+      for (li = chan->_layers.begin(); li != chan->_layers.end(); ++li) {
+        GraphicsLayer *layer = (*li);
+        if (layer->is_active()) {
+          GraphicsLayer::DisplayRegions::const_iterator dri;
+          for (dri = layer->_display_regions.begin(); 
+               dri != layer->_display_regions.end(); 
+               ++dri) {
+            DisplayRegion *dr = (*dri);
+            if (dr->is_active()) {
+              _display_regions.push_back(dr);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  _display_regions_stale = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::register_draw_function
 //       Access: Public, Virtual
@@ -413,6 +448,33 @@ void GraphicsWindow::
 update() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::clear
+//       Access: Public
+//  Description: Invokes the GSG to clear the entire contents of the
+//               window prior to drawing into it.  This is normally
+//               called only by the draw process at the beginning of
+//               the frame.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindow::
+clear() {
+  _gsg->clear_framebuffer();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindow::flip
+//       Access: Public, Virtual
+//  Description: Flips the back buffer and front buffer, or does
+//               whatever other processing is appropriate, after the
+//               frame has been completely drawn.  Normally this is
+//               only called by the draw process between frames, in
+//               sync with all the other windows.
+////////////////////////////////////////////////////////////////////
+void GraphicsWindow::
+flip() {
+  end_frame();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindow::begin_frame
 //       Access: Public, Virtual

+ 19 - 5
panda/src/display/graphicsWindow.h

@@ -63,6 +63,7 @@ enum WindowModeType
 
 class GraphicsPipe;
 class GraphicsWindow;
+class CullHandler;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GraphicsWindow
@@ -109,14 +110,10 @@ public:
 public:
 
   GraphicsWindow(GraphicsPipe*);
-#ifdef WIN32_VC
   GraphicsWindow(GraphicsPipe*, const Properties&);
-#else
-  GraphicsWindow(GraphicsPipe*, const GraphicsWindow::Properties&);
-#endif
   virtual ~GraphicsWindow();
 
-  INLINE const GraphicsWindow::Properties& get_properties() const;
+  INLINE const Properties& get_properties() const;
 
 PUBLISHED:
   INLINE int get_width() const;
@@ -191,17 +188,24 @@ PUBLISHED:
   virtual void register_draw_function(GraphicsWindow::vfn);
   virtual void register_idle_function(GraphicsWindow::vfn);
 
+  // Old-style scene graph rendering (will be phased out eventually).
   virtual void main_loop();
   virtual bool supports_update() const;
   virtual void update();
   INLINE void render_and_update();
 
 public:
+  // New-style scene graph rendering (not yet complete).
+  void clear();
+  virtual void flip();
+
   virtual void begin_frame();
   virtual void end_frame();
   virtual void deactivate_window(void);
   virtual void reactivate_window(void);
 
+  INLINE void win_display_regions_changed();
+
   // Statistics
   static PStatCollector _app_pcollector;
   static PStatCollector _show_code_pcollector;
@@ -241,13 +245,23 @@ PUBLISHED:
   int get_max_channel_index() const;
   bool is_channel_defined(int index) const;
 
+  INLINE int get_num_display_regions() const;
+  INLINE DisplayRegion *get_display_region(int n) const;
+
 protected:
   void declare_channel(int index, GraphicsChannel *chan);
 
 private:
+  INLINE void determine_display_regions() const;
+  void do_determine_display_regions();
+
   typedef pvector< PT(GraphicsChannel) > Channels;
   Channels _channels;
 
+  typedef pvector<DisplayRegion *> DisplayRegions;
+  DisplayRegions _display_regions;
+  bool _display_regions_stale;
+
 public:
 
   // factory stuff

+ 61 - 0
panda/src/display/lensStack.I

@@ -0,0 +1,61 @@
+// Filename: lensStack.I
+// Created by:  drose (25Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: LensStack::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE LensStack::
+LensStack() {
+  _stack_level = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensStack::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE LensStack::
+~LensStack() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensStack::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE LensStack::
+LensStack(const LensStack &copy) :
+  _lens(copy._lens),
+  _stack_level(copy._stack_level)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensStack::Copy Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void LensStack::
+operator =(const LensStack &copy) {
+  _lens = copy._lens;
+  _stack_level = copy._stack_level;
+}

+ 50 - 0
panda/src/display/lensStack.h

@@ -0,0 +1,50 @@
+// Filename: lensStack.h
+// Created by:  drose (25Feb02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 LENSSTACK_H
+#define LENSSTACK_H
+
+#include <pandabase.h>
+
+#include "lens.h"
+
+class GraphicsStateGuardian;
+
+////////////////////////////////////////////////////////////////////
+//       Class : LensStack
+// Description : An instance of this kind of object is returned by
+//               GraphicsStateGuardian::push_lens().  It holds the
+//               information needed to restore the previous display
+//               region in the subsequent matching call to pop_lens().
+////////////////////////////////////////////////////////////////////
+class LensStack {
+public:
+  INLINE LensStack();
+  INLINE ~LensStack();
+  INLINE LensStack(const LensStack &copy);
+  INLINE void operator =(const LensStack &copy);
+
+private:
+  CPT(Lens) _lens;
+  int _stack_level;
+  friend class GraphicsStateGuardian;
+};
+
+#include "lensStack.I"
+
+#endif

+ 72 - 70
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -65,6 +65,7 @@
 #include "stencilTransition.h"
 #include "pointShapeTransition.h"
 #include "polygonOffsetTransition.h"
+#include "textureAttrib.h"
 #include "clockObject.h"
 #include "string_utils.h"
 #include "dcast.h"
@@ -300,17 +301,6 @@ reset() {
   _current_projection_mat = LMatrix4f::ident_mat();
   _projection_mat_stack_count = 0;
 
-  //Color and alpha transform variables
-  _color_transform_enabled = false;
-  _alpha_transform_enabled = false;
-  _current_color_mat = LMatrix4f::ident_mat();
-  _current_alpha_offset = 0;
-  _current_alpha_scale = 1;
-
-  _has_scene_graph_color = false;
-  _issued_color_stale = false;
-  _vertex_colors_enabled = true;
-
   // Make sure the GL state matches all of our initial attribute
   // states.
   PT(DepthTestTransition) dta = new DepthTestTransition;
@@ -462,6 +452,51 @@ prepare_display_region() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::prepare_lens
+//       Access: Public, Virtual
+//  Description: Makes the current lens (whichever lens was most
+//               recently specified with push_lens()) active, so that
+//               it will transform future rendered geometry.  Normally
+//               this is only called from the draw process, and
+//               usually it is called immediately after a call to
+//               push_lens().
+//
+//               The return value is true if the lens is acceptable,
+//               false if it is not.
+////////////////////////////////////////////////////////////////////
+bool GLGraphicsStateGuardian::
+prepare_lens() {
+  if (_current_lens == (Lens *)NULL) {
+    return false;
+  }
+
+  if (!_current_lens->is_linear()) {
+    return false;
+  }
+
+  const LMatrix4f &projection_mat = _current_lens->get_projection_mat();
+
+  // The projection matrix must always be right-handed Y-up, even if
+  // our coordinate system of choice is otherwise, because certain GL
+  // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of
+  // a coordinate system.  Sigh.  In order to implement a Z-up (or
+  // other arbitrary) coordinate system, we'll use a Y-up projection
+  // matrix, and store the conversion to our coordinate system of
+  // choice in the modelview matrix.
+  LMatrix4f new_projection_mat =
+    LMatrix4f::convert_mat(CS_yup_right, _current_lens->get_coordinate_system()) *
+    projection_mat;
+
+#ifdef GSG_VERBOSE
+  glgsg_cat.debug()
+    << "glMatrixMode(GL_PROJECTION): " << new_projection_mat << endl;
+#endif
+  glMatrixMode(GL_PROJECTION);
+  glLoadMatrixf(new_projection_mat.get_data());
+
+  return true;
+}
 
 
 ////////////////////////////////////////////////////////////////////
@@ -498,16 +533,8 @@ render_frame() {
   clear_attribute(TextureTransition::get_class_type());
 #endif
 
-  if (_clear_buffer_type != 0) {
-    // First, clear the entire window.
-    PT(DisplayRegion) win_dr =
-      _win->make_scratch_display_region(_win->get_width(), _win->get_height());
-    nassertv(win_dr != (DisplayRegion*)NULL);
-    DisplayRegionStack old_dr = push_display_region(win_dr);
-    prepare_display_region();
-    clear(get_render_buffer(_clear_buffer_type));
-    pop_display_region(old_dr);
-  }
+  // First, clear the entire window.
+  clear_framebuffer();
 
   // Now render each of our layers in order.
   int max_channel_index = _win->get_max_channel_index();
@@ -624,38 +651,16 @@ render_subgraph(RenderTraverser *traverser,
   //  activate();
 
   Lens *lens = projnode->get_lens();
-  if (!lens->is_linear()) {
+  LensNode *old_camera = _current_camera;
+  _current_camera = projnode;
+
+  LensStack lens_stack = push_lens(lens);
+  if (!prepare_lens()) {
     glgsg_cat.error()
       << "Cannot render with a nonlinear lens!\n";
     return;
   }
 
-  LensNode *old_camera = _current_camera;
-  _current_camera = projnode;
-  LMatrix4f old_projection_mat = _current_projection_mat;
-
-  const LMatrix4f &projection_mat = lens->get_projection_mat();
-
-  // The projection matrix must always be right-handed Y-up, even if
-  // our coordinate system of choice is otherwise, because certain GL
-  // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of
-  // a coordinate system.  Sigh.  In order to implement a Z-up (or
-  // other arbitrary) coordinate system, we'll use a Y-up projection
-  // matrix, and store the conversion to our coordinate system of
-  // choice in the modelview matrix.
-  _current_projection_mat =
-    LMatrix4f::convert_mat(CS_yup_right, lens->get_coordinate_system()) *
-    projection_mat;
-  _projection_mat_stack_count++;
-
-  // We load the projection matrix directly.
-#ifdef GSG_VERBOSE
-  glgsg_cat.debug()
-    << "glMatrixMode(GL_PROJECTION): " << _current_projection_mat << endl;
-#endif
-  glMatrixMode(GL_PROJECTION);
-  glLoadMatrixf(_current_projection_mat.get_data());
-
   // We infer the modelview matrix by doing a wrt on the lens
   // node.
   LMatrix4f modelview_mat;
@@ -677,18 +682,8 @@ render_subgraph(RenderTraverser *traverser,
   render_subgraph(traverser, subgraph, sub_trans);
 
   _current_camera = old_camera;
-  _current_projection_mat = old_projection_mat;
-  _projection_mat_stack_count--;
-
 
-  // We must now restore the projection matrix from before.  We could
-  // do a push/pop matrix, but OpenGL doesn't promise more than 2
-  // levels in the projection matrix stack, so we'd better do it in
-  // the CPU.
-  if (_projection_mat_stack_count > 0) {
-    glMatrixMode(GL_PROJECTION);
-    glLoadMatrixf(_current_projection_mat.get_data());
-  }
+  pop_lens(lens_stack);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -3420,6 +3415,24 @@ issue_polygon_offset(const PolygonOffsetTransition *attrib) {
   report_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::issue_texture
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void GLGraphicsStateGuardian::
+issue_texture(const TextureAttrib *attrib) {
+  if (attrib->is_off()) {
+    enable_texturing(false);
+  } else {
+    enable_texturing(true);
+    Texture *tex = attrib->get_texture();
+    nassertv(tex != (Texture *)NULL);
+    tex->apply(this);
+  }
+  report_errors();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::wants_normals
 //       Access: Public, Virtual
@@ -3440,17 +3453,6 @@ wants_texcoords() const {
   return _texturing_enabled;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::wants_colors
-//       Access: Public, Virtual
-//  Description: Returns true if the GSG should issue geometry color
-//               commands, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool GLGraphicsStateGuardian::
-wants_colors() const {
-  return _vertex_colors_enabled;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::begin_decal
 //       Access: Public, Virtual

+ 3 - 12
panda/src/glgsg/glGraphicsStateGuardian.h

@@ -74,6 +74,7 @@ public:
   virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region);
 
   virtual void prepare_display_region();
+  virtual bool prepare_lens();
 
   virtual void render_frame();
   virtual void render_scene(Node *root, LensNode *projnode);
@@ -155,9 +156,10 @@ public:
   virtual void issue_point_shape(const PointShapeTransition *attrib);
   virtual void issue_polygon_offset(const PolygonOffsetTransition *attrib);
 
+  virtual void issue_texture(const TextureAttrib *attrib);
+
   virtual bool wants_normals(void) const;
   virtual bool wants_texcoords(void) const;
-  virtual bool wants_colors(void) const;
 
   virtual void begin_decal(GeomNode *base_geom, AllTransitionsWrapper &attrib);
   virtual void end_decal(GeomNode *base_geom);
@@ -326,8 +328,6 @@ protected:
   bool _dithering_enabled;
   bool _alpha_test_enabled;
   bool _polygon_offset_enabled;
-  bool _color_transform_enabled;
-  bool _alpha_transform_enabled;
   int _decal_level;
 
   class LightInfo {
@@ -353,15 +353,6 @@ protected:
 
   CPT(DisplayRegion) _actual_display_region;
 
-  LMatrix4f _current_color_mat;
-  float _current_alpha_offset;
-  float _current_alpha_scale;
-
-  Colorf _scene_graph_color;
-  bool _has_scene_graph_color;
-  bool _issued_color_stale;
-  bool _vertex_colors_enabled;
-
   int _pass_number;
 
 public:

+ 6 - 0
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -75,6 +75,9 @@ class LinesmoothTransition;
 class PointShapeTransition;
 class PolygonOffsetTransition;
 
+class TextureAttrib;
+class ColorAttrib;
+
 class Node;
 class GeomNode;
 class PointLight;
@@ -188,6 +191,9 @@ public:
   virtual void issue_point_shape(const PointShapeTransition *) { }
   virtual void issue_polygon_offset(const PolygonOffsetTransition *) { }
 
+  virtual void issue_texture(const TextureAttrib *) { }
+  virtual void issue_color(const ColorAttrib *) { }
+
 PUBLISHED:
   static TypeHandle get_class_type() {
     return _type_handle;

+ 1 - 1
panda/src/pgraph/Sources.pp

@@ -1,6 +1,6 @@
 #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
                    dtoolutil:c dtoolbase:c dtool:m
-#define LOCAL_LIBS gobj putil graph linmath express pandabase
+#define LOCAL_LIBS gsgbase gobj putil graph linmath express pandabase
 
 #begin lib_target
   #define TARGET pgraph

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

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "colorAttrib.h"
+#include "graphicsStateGuardianBase.h"
 #include "dcast.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -63,6 +64,20 @@ make_off() {
   return return_new(attrib);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ColorAttrib::issue
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the indicated GSG
+//               to issue the graphics commands appropriate to the
+//               given attribute.  This is normally called
+//               (indirectly) only from
+//               GraphicsStateGuardian::set_state() or modify_state().
+////////////////////////////////////////////////////////////////////
+void ColorAttrib::
+issue(GraphicsStateGuardianBase *gsg) const {
+  gsg->issue_color(this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ColorAttrib::output
 //       Access: Public, Virtual

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

@@ -48,6 +48,7 @@ PUBLISHED:
   INLINE const Colorf &get_color() const;
 
 public:
+  virtual void issue(GraphicsStateGuardianBase *gsg) const;
   virtual void output(ostream &out) const;
 
 protected:

+ 2 - 2
panda/src/pgraph/cullHandler.cxx

@@ -21,7 +21,7 @@
 #include "renderState.h"
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CullHandler::found_geom
+//     Function: CullHandler::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
@@ -31,6 +31,6 @@
 //               it's not intended to be used except for debugging.
 ////////////////////////////////////////////////////////////////////
 void CullHandler::
-found_geom(Geom *geom, const RenderState *state) {
+record_geom(Geom *geom, const RenderState *state) {
   cerr << *geom << " " << *state << "\n";
 }

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

@@ -29,11 +29,14 @@ class RenderState;
 // Description : This defines the abstract interface for an object
 //               that receives Geoms identified by the CullTraverser.
 //               By itself, it's not a particularly useful class; to
-//               use it, derive from it and redefine found_geom().
+//               use it, derive from it and redefine record_geom().
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA CullHandler {
 public:
-  virtual void found_geom(Geom *geom, const RenderState *state);
+  //  virtual void begin_decal();
+  virtual void record_geom(Geom *geom, const RenderState *state);
+  //  virtual void push_decal();
+  //  virtual void pop_decal();
 };
 
 #endif

+ 2 - 2
panda/src/pgraph/pandaNode.I

@@ -187,14 +187,14 @@ get_child(int n) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PandaNode::get_sort
+//     Function: PandaNode::get_child_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 {
+get_child_sort(int n) const {
   CDReader cdata(_cycler);
   nassertr(n >= 0 && n < (int)cdata->_down.size(), -1);
   return cdata->_down[n].get_sort();

+ 9 - 1
panda/src/pgraph/pandaNode.h

@@ -55,13 +55,21 @@ PUBLISHED:
 
   INLINE int get_num_children() const;
   INLINE PandaNode *get_child(int n) const;
-  INLINE int get_sort(int n) const;
+  INLINE int get_child_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);
 
+  /*
+  bool stash_child(PandaNode *child);
+  bool unstash_child(PandaNode *child);
+  INLINE int get_num_stashed() const;
+  INLINE PandaNode *get_stashed(int n) const;
+  INLINE PandaNode *get_stashed_sort(int n) const;
+  */
+
   void remove_all_children();
 
   INLINE void set_attrib(const RenderAttrib *attrib, int override = 0);

+ 1 - 13
panda/src/pgraph/pipeline.cxx

@@ -42,23 +42,11 @@ Pipeline::
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Pipeline::cycle
-//       Access: Public
+//       Access: Public, Virtual
 //  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() {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 4
panda/src/pgraph/pipeline.h

@@ -42,10 +42,7 @@ public:
 
   INLINE static Pipeline *get_render_pipeline();
 
-  void cycle();
-
-protected:
-  virtual void pre_cycle();
+  virtual void cycle();
 
 private:
   static void make_render_pipeline();

+ 1 - 1
panda/src/pgraph/qpcullTraverser.cxx

@@ -104,7 +104,7 @@ r_traverse(PandaNode *node, const RenderState *state, int flags) {
       Geom *geom = geom_node->get_geom(i);
       CPT(RenderState) geom_state = 
         next_state->compose(geom_node->get_geom_state(i));
-      _cull_handler->found_geom(geom, geom_state);
+      _cull_handler->record_geom(geom, geom_state);
     }
   }
 

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

@@ -32,6 +32,27 @@ compose(const RenderAttrib *other) const {
   return compose_impl(other);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::invert_compose
+//       Access: Public
+//  Description: Returns a new RenderAttrib object that represents the
+//               composition of the inverse 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.
+//
+//               This is similar to compose() except that the source
+//               attrib is inverted first.  This is used to compute
+//               the relative attribute for one node as viewed from
+//               some other node, which is especially useful for
+//               transform-type attributes.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(RenderAttrib) RenderAttrib::
+invert_compose(const RenderAttrib *other) const {
+  return invert_compose_impl(other);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::make_default
 //       Access: Public

+ 29 - 2
panda/src/pgraph/renderAttrib.cxx

@@ -68,8 +68,21 @@ RenderAttrib::
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: RenderAttrib::output
+//     Function: RenderAttrib::issue
 //       Access: Public, Virtual
+//  Description: Calls the appropriate method on the indicated GSG
+//               to issue the graphics commands appropriate to the
+//               given attribute.  This is normally called
+//               (indirectly) only from
+//               GraphicsStateGuardian::set_state() or modify_state().
+////////////////////////////////////////////////////////////////////
+void RenderAttrib::
+issue(GraphicsStateGuardianBase *) const {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::output
+//       Access: Published, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void RenderAttrib::
@@ -79,7 +92,7 @@ output(ostream &out) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::write
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void RenderAttrib::
@@ -167,6 +180,20 @@ compose_impl(const RenderAttrib *other) const {
   return other;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderAttrib::invert_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.
+//
+//               See invert_compose() and compose_impl().
+////////////////////////////////////////////////////////////////////
+CPT(RenderAttrib) RenderAttrib::
+invert_compose_impl(const RenderAttrib *other) const {
+  return other;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderAttrib::make_default_impl
 //       Access: Protected, Virtual

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

@@ -26,6 +26,8 @@
 #include "pointerTo.h"
 #include "pset.h"
 
+class GraphicsStateGuardianBase;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : RenderAttrib
 // Description : This is the base class for a number of render
@@ -54,8 +56,10 @@ public:
   virtual ~RenderAttrib();
 
   INLINE CPT(RenderAttrib) compose(const RenderAttrib *other) const;
+  INLINE CPT(RenderAttrib) invert_compose(const RenderAttrib *other) const;
   INLINE CPT(RenderAttrib) make_default() const;
   INLINE int compare_to(const RenderAttrib &other) const;
+  virtual void issue(GraphicsStateGuardianBase *gsg) const;
 
 PUBLISHED:
   virtual void output(ostream &out) const;
@@ -66,6 +70,7 @@ protected:
 
   virtual int compare_to_impl(const RenderAttrib *other) const;
   virtual CPT(RenderAttrib) compose_impl(const RenderAttrib *other) const;
+  virtual CPT(RenderAttrib) invert_compose_impl(const RenderAttrib *other) const;
   virtual RenderAttrib *make_default_impl() const=0;
 
 private:

+ 273 - 5
panda/src/pgraph/renderState.cxx

@@ -121,6 +121,18 @@ RenderState::
     ++ci;
   }
 
+  // A similar bit of code for the invert cache.
+  ci = _invert_composition_cache.begin();
+  while (ci != _invert_composition_cache.end()) {
+    {
+      PT(RenderState) other = (RenderState *)(*ci).first;
+      Composition comp = (*ci).second;
+      nassertv(other != (const RenderState *)this);
+      other->_invert_composition_cache.erase(this);
+    }
+    ++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.
@@ -270,8 +282,6 @@ compose(const RenderState *other) const {
   // 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";
-
   // We handle empty state (identity) as a trivial special case.
   if (is_empty()) {
     return other;
@@ -330,6 +340,68 @@ compose(const RenderState *other) const {
   ((RenderState *)other)->_composition_cache[this]._result = NULL;
   ((RenderState *)this)->_composition_cache[other]._result = result;
 
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::invert_compose
+//       Access: Published
+//  Description: Returns a new RenderState object that represents the
+//               composition of this state's inverse with the other
+//               state.
+//
+//               This is similar to compose(), but is particularly
+//               useful for computing the relative state of a node as
+//               viewed from some other node.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+invert_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 << "invert composing " << *this << " with " << *other << "\n";
+
+  // We handle empty state (identity) as a trivial special case.
+  if (is_empty()) {
+    return other;
+  }
+  // Unlike compose(), the case of other->is_empty() is not quite as
+  // trivial for invert_compose().
+
+  if (other == this) {
+    // a->invert_compose(a) always produces identity.
+    return make_empty();
+  }
+
+  // Is this composition already cached?
+  CompositionCache::const_iterator ci = _invert_composition_cache.find(other);
+  if (ci != _invert_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_invert_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_invert_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)->_invert_composition_cache[this]._result = NULL;
+  ((RenderState *)this)->_invert_composition_cache[other]._result = result;
+
   cerr << "  returning new result " << (void *)result.p() << "\n";
   return result;
 }
@@ -396,7 +468,7 @@ remove(TypeHandle type) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::output
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void RenderState::
@@ -417,7 +489,7 @@ output(ostream &out) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::write
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void RenderState::
@@ -430,6 +502,149 @@ write(ostream &out, int indent_level) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::issue_delta_modify
+//       Access: Public
+//  Description: This is intended to be called only from
+//               GraphicsStateGuardian::modify_state().  It calls
+//               issue() for each attribute given in the other state
+//               that differs from the current state (which is assumed
+//               to represent the GSG's current state).  Returns the
+//               RenderState representing the newly composed result.
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+issue_delta_modify(const RenderState *other, 
+                   GraphicsStateGuardianBase *gsg) const {
+  if (other == this) {
+    // If the state doesn't change, that's a trivial special case.
+    return other;
+  }
+
+  // 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);
+
+  bool any_changed = false;
+
+  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.  Leave it alone.
+      *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.  Issue the new one, and save it.
+      (*bi)._attrib->issue(gsg);
+      *result = *bi;
+      ++bi;
+      ++result;
+      any_changed = true;
+    } else {
+      // Here is an attribute we have in both.  Issue the new one if
+      // it's different, and save it.
+      if ((*ai)._attrib != (*bi)._attrib) {
+        any_changed = true;
+        (*bi)._attrib->issue(gsg);
+      }
+      *result = *bi;
+      ++ai;
+      ++bi;
+      ++result;
+    }
+  }
+
+  while (ai != _attributes.end()) {
+    *result = *ai;
+    ++ai;
+    ++result;
+  }
+
+  while (bi != other->_attributes.end()) {
+    (*bi)._attrib->issue(gsg);
+    *result = *bi;
+    ++bi;
+    ++result;
+    any_changed = true;
+  }
+
+  if (any_changed) {
+    return return_new(new_state);
+  } else {
+    delete new_state;
+    return other;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::issue_delta_set
+//       Access: Public
+//  Description: This is intended to be called only from
+//               GraphicsStateGuardian::set_state().  It calls issue()
+//               for each attribute given in the other state that
+//               differs from the current state (which is assumed to
+//               represent the GSG's current state).  Returns the
+//               RenderState representing the newly composed result
+//               (which will be the same as other).
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+issue_delta_set(const RenderState *other, 
+                GraphicsStateGuardianBase *gsg) const {
+  if (other->is_empty()) {
+    // If the other state is empty, that's a trivial special case.
+    return this;
+  }
+
+  // We don't need to build a new RenderState, because the return
+  // value will be exactly other.
+
+  Attributes::const_iterator ai = _attributes.begin();
+  Attributes::const_iterator bi = other->_attributes.begin();
+
+  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.  Issue the default state instead.
+      (*ai)._attrib->make_default()->issue(gsg);
+      ++ai;
+
+    } else if ((*bi) < (*ai)) {
+      // Here is a new attribute we have in the secondary, that was
+      // not present in the original.  Issue the new one.
+      (*bi)._attrib->issue(gsg);
+      ++bi;
+
+    } else {
+      // Here is an attribute we have in both.  Issue the new one if
+      // it's different.
+      if ((*ai)._attrib != (*bi)._attrib) {
+        (*bi)._attrib->issue(gsg);
+      }
+      ++ai;
+      ++bi;
+    }
+  }
+
+  while (ai != _attributes.end()) {
+    (*ai)._attrib->make_default()->issue(gsg);
+    ++ai;
+  }
+
+  while (bi != other->_attributes.end()) {
+    (*bi)._attrib->issue(gsg);
+    ++bi;
+  }
+
+  return other;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RenderState::return_new
 //       Access: Private, Static
@@ -513,7 +728,7 @@ do_compose(const RenderState *other) const {
 
       } else if (b._override < a._override) {
         // A overrides.
-        *result = *bi;
+        *result = *ai;
 
       } else {
         // No, they're equivalent, so compose them.
@@ -540,6 +755,59 @@ do_compose(const RenderState *other) const {
   return return_new(new_state);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RenderState::do_invert_compose
+//       Access: Private
+//  Description: The private implemention of invert_compose().
+////////////////////////////////////////////////////////////////////
+CPT(RenderState) RenderState::
+do_invert_compose(const RenderState *other) const {
+  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 = Attribute((*ai)._attrib->invert_compose((*ai)._attrib->make_default()), 0);
+      ++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.  In this case, override
+      // is meaningless.
+      *result = Attribute((*ai)._attrib->invert_compose((*bi)._attrib), (*bi)._override);
+      ++ai;
+      ++bi;
+      ++result;
+    }
+  }
+
+  while (ai != _attributes.end()) {
+    *result = Attribute((*ai)._attrib->invert_compose((*ai)._attrib->make_default()), 0);
+    ++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

+ 12 - 1
panda/src/pgraph/renderState.h

@@ -27,6 +27,8 @@
 #include "indirectLess.h"
 #include "ordered_vector.h"
 
+class GraphicsStateGuardianBase;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : RenderState
 // Description : This represents a unique collection of RenderAttrib
@@ -73,6 +75,7 @@ PUBLISHED:
                                const RenderAttrib *attrib4, int override = 0);
 
   CPT(RenderState) compose(const RenderState *other) const;
+  CPT(RenderState) invert_compose(const RenderState *other) const;
 
   CPT(RenderState) add(const RenderAttrib *attrib, int override = 0) const;
   CPT(RenderState) remove(TypeHandle type) const;
@@ -80,9 +83,16 @@ PUBLISHED:
   void output(ostream &out) const;
   void write(ostream &out, int indent_level) const;
 
+public:
+  CPT(RenderState) issue_delta_modify(const RenderState *other, 
+                                      GraphicsStateGuardianBase *gsg) const;
+  CPT(RenderState) issue_delta_set(const RenderState *other, 
+                                   GraphicsStateGuardianBase *gsg) const;
+
 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;
 
 private:
   typedef pset<const RenderState *, IndirectLess<RenderState> > States;
@@ -106,8 +116,9 @@ private:
     
   typedef pmap<const RenderState *, Composition> CompositionCache;
   CompositionCache _composition_cache;
+  CompositionCache _invert_composition_cache;
 
-  // This pointer is used to cache the result of compose(this).  This
+  // Thise 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

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

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "textureAttrib.h"
+#include "graphicsStateGuardianBase.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "datagram.h"
@@ -49,6 +50,20 @@ make_off() {
   return return_new(attrib);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::issue
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the indicated GSG
+//               to issue the graphics commands appropriate to the
+//               given attribute.  This is normally called
+//               (indirectly) only from
+//               GraphicsStateGuardian::set_state() or modify_state().
+////////////////////////////////////////////////////////////////////
+void TextureAttrib::
+issue(GraphicsStateGuardianBase *gsg) const {
+  gsg->issue_texture(this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureAttrib::output
 //       Access: Public, Virtual

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

@@ -42,6 +42,7 @@ PUBLISHED:
   INLINE Texture *get_texture() const;
 
 public:
+  virtual void issue(GraphicsStateGuardianBase *gsg) const;
   virtual void output(ostream &out) const;
 
 protected:

+ 24 - 0
panda/src/sgraph/camera.I

@@ -62,3 +62,27 @@ INLINE Node *Camera::
 get_scene() const {
   return _scene;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::set_qpscene
+//       Access: Public
+//  Description: Sets the scene that will be rendered by the camera.
+//               This is normally the root node of a scene graph,
+//               typically a node called 'render', although it could
+//               represent the root of any subgraph.
+////////////////////////////////////////////////////////////////////
+INLINE void Camera::
+set_qpscene(PandaNode *scene) {
+  _qpscene = scene;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Camera::get_qpscene
+//       Access: Public
+//  Description: Returns the scene that will be rendered by the
+//               camera.  See set_qpscene().
+////////////////////////////////////////////////////////////////////
+INLINE PandaNode *Camera::
+get_qpscene() const {
+  return _qpscene;
+}

+ 5 - 0
panda/src/sgraph/camera.h

@@ -28,6 +28,7 @@
 #include "pvector.h"
 
 class DisplayRegion;
+class PandaNode;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : Camera
@@ -56,6 +57,9 @@ PUBLISHED:
   INLINE void set_scene(Node *scene);
   INLINE Node *get_scene() const;
 
+  INLINE void set_qpscene(PandaNode *scene);
+  INLINE PandaNode *get_qpscene() const;
+
   int get_num_drs() const;
   DisplayRegion *get_dr(int index) const;
 
@@ -65,6 +69,7 @@ private:
 
   bool _active;
   PT_Node _scene;
+  PandaNode *_qpscene;
 
   typedef pvector<DisplayRegion *> DisplayRegions;
   DisplayRegions _display_regions;

+ 9 - 0
panda/src/testbed/Sources.pp

@@ -26,6 +26,15 @@
 
 #end bin_target
 
+#begin test_bin_target
+  #define TARGET pview
+
+  #define SOURCES \
+    pview.cxx
+
+  #define LOCAL_LIBS pgraph $[LOCAL_LIBS]
+#end test_bin_target
+
 #begin test_bin_target
   #define TARGET open_window