Browse Source

use NodePaths for ProjectionScreen interface

David Rose 22 years ago
parent
commit
a1ba7a54e7

+ 110 - 23
panda/src/distort/nonlinearImager.cxx

@@ -52,6 +52,18 @@ NonlinearImager::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NonlinearImager::add_screen
+//       Access: Published
+//               This version of this method is deprecated and will
+//               soon be removed.  Use the version that takes two
+//               parameters instead.
+////////////////////////////////////////////////////////////////////
+int NonlinearImager::
+add_screen(ProjectionScreen *screen) {
+  return add_screen(NodePath(screen), screen->get_name());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NonlinearImager::add_screen
 //       Access: Published
@@ -61,27 +73,28 @@ NonlinearImager::
 //               It must be based on a linear camera (or whatever kind
 //               of camera is respected by the graphics engine).
 //
-//               width and height indicate the size of the texture
-//               that will be created to render the scene for the
-//               screen.  See set_texture_size().
-//
 //               Each ProjectionScreen object should already have some
 //               screen geometry created.
 //
-//               When render() is called, the graphics state guardian
-//               will be used to render a scene for each
-//               ProjectionScreen object, and then each resulting
-//               image will be applied to a mesh to be rendered to the
-//               screen.
+//               As each frame is rendered, an offscreen image will be
+//               rendered from the source camera associated with each
+//               ProjectionScreen, and the resulting image will be
+//               applied to the screen geometry.
 //
 //               The return value is the index number of the new
 //               screen.
 ////////////////////////////////////////////////////////////////////
 int NonlinearImager::
-add_screen(ProjectionScreen *screen, const string &name) {
+add_screen(const NodePath &screen, const string &name) {
+  nassertr(!screen.is_empty() && 
+           screen.node()->is_of_type(ProjectionScreen::get_class_type()), -1);
+
+  ProjectionScreen *screen_node = DCAST(ProjectionScreen, screen.node());
+
   _screens.push_back(Screen());
   Screen &new_screen = _screens.back();
   new_screen._screen = screen;
+  new_screen._screen_node = screen_node;
   new_screen._name = name;
   new_screen._buffer = (GraphicsOutput *)NULL;
   new_screen._tex_width = 256;
@@ -92,10 +105,17 @@ add_screen(ProjectionScreen *screen, const string &name) {
   size_t vi;
   for (vi = 0; vi < _viewers.size(); ++vi) {
     new_screen._meshes.push_back(Mesh());
-    new_screen._meshes[vi]._last_screen = screen->get_last_screen();
+    new_screen._meshes[vi]._last_screen = screen_node->get_last_screen();
   }
 
   _stale = true;
+
+  if (_dark_room.is_empty()) {
+    _dark_room = screen.get_top();
+  } else {
+    nassertr(_dark_room.is_same_graph(screen), _screens.size() - 1);
+  }
+
   return _screens.size() - 1;
 }
 
@@ -107,7 +127,7 @@ add_screen(ProjectionScreen *screen, const string &name) {
 //               if it does not appear.
 ////////////////////////////////////////////////////////////////////
 int NonlinearImager::
-find_screen(ProjectionScreen *screen) const {
+find_screen(const NodePath &screen) const {
   for (size_t i = 0; i < _screens.size(); i++) {
     if (_screens[i]._screen == screen) {
       return i;
@@ -162,7 +182,7 @@ get_num_screens() const {
 //  Description: Returns the nth screen that has been added to the
 //               imager.
 ////////////////////////////////////////////////////////////////////
-ProjectionScreen *NonlinearImager::
+NodePath NonlinearImager::
 get_screen(int index) const {
   nassertr(index >= 0 && index < (int)_screens.size(), (ProjectionScreen *)NULL);
   return _screens[index]._screen;
@@ -294,7 +314,15 @@ get_screen_active(int index) const {
 ////////////////////////////////////////////////////////////////////
 int NonlinearImager::
 add_viewer(DisplayRegion *dr) {
-  GraphicsEngine *engine = dr->get_window()->get_gsg()->get_engine();
+  GraphicsOutput *window = dr->get_window();
+  nassertr(window != (GraphicsOutput *)NULL, -1);
+
+  GraphicsStateGuardian *gsg = window->get_gsg();
+  nassertr(gsg != (GraphicsStateGuardian *)NULL, -1);
+
+  GraphicsEngine *engine = gsg->get_engine();
+  nassertr(engine != (GraphicsEngine *)NULL, -1);
+
   nassertr(_viewers.empty() || (engine == _engine), -1);
   if (_engine == (GraphicsEngine *)NULL) {
     _engine = engine;
@@ -323,9 +351,9 @@ add_viewer(DisplayRegion *dr) {
 
   // The internal camera is an identity-matrix camera that simply
   // views the meshes that represent the user's specified camera.
-  viewer._internal_camera = new Camera("NonlinearImager");
+  viewer._internal_camera = new Camera("internal_camera");
   viewer._internal_camera->set_lens(new MatrixLens);
-  viewer._internal_scene = NodePath("screens");
+  viewer._internal_scene = NodePath("internal_screens");
   viewer._internal_camera->set_scene(viewer._internal_scene);
 
   NodePath camera_np = viewer._internal_scene.attach_new_node(viewer._internal_camera);
@@ -345,6 +373,13 @@ add_viewer(DisplayRegion *dr) {
   }
 
   _stale = true;
+
+  if (_dark_room.is_empty()) {
+    _dark_room = viewer._viewer.get_top();
+  } else {
+    nassertr(_dark_room.is_same_graph(viewer._viewer), vi);
+  }
+
   return vi;
 }
 
@@ -429,6 +464,12 @@ set_viewer_camera(int index, const NodePath &viewer_camera) {
   viewer._viewer = viewer_camera;
   viewer._viewer_node = DCAST(LensNode, viewer_camera.node());
   _stale = true;
+
+  if (_dark_room.is_empty()) {
+    _dark_room = viewer._viewer.get_top();
+  } else {
+    nassertv(_dark_room.is_same_graph(viewer._viewer));
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -444,14 +485,21 @@ get_viewer_camera(int index) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: NonlinearImager::get_internal_scene
+//     Function: NonlinearImager::get_viewer_scene
 //       Access: Published
 //  Description: Returns a pointer to the root node of the internal
 //               scene graph for the nth viewer, which is used to
 //               render all of the screen meshes for this viewer.
+//
+//               This is the scene graph in which the screen meshes
+//               within the dark room have been flattened into the
+//               appropriate transformation according to the viewer's
+//               lens properties (and position relative to the
+//               screens).  It is this scene graph that is finally
+//               rendered to the window.
 ////////////////////////////////////////////////////////////////////
 NodePath NonlinearImager::
-get_internal_scene(int index) const {
+get_viewer_scene(int index) const {
   nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
   return _viewers[index]._internal_scene;
 }
@@ -479,6 +527,38 @@ get_viewer(int index) const {
   return _viewers[index]._dr;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NonlinearImager::get_dark_room
+//       Access: Published
+//  Description: Returns the NodePath to the root of the dark room
+//               scene.  This is the scene in which all of the
+//               ProjectionScreens and the viewer cameras reside.
+//               It's a standalone scene with a few projection screens
+//               arranged artfully around one or more viewers; it's so
+//               named because it's a little virtual theater.
+//
+//               Normally this scene is not rendered directly; it only
+//               exists as an abstract concept, and to define the
+//               relation between the ProjectionScreens and the
+//               viewers.  But it may be rendered to help visualize
+//               the NonlinearImager's behavior.
+////////////////////////////////////////////////////////////////////
+NodePath NonlinearImager::
+get_dark_room() const {
+  return _dark_room;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NonlinearImager::get_graphics_engine
+//       Access: Published
+//  Description: Returns the GraphicsEngine that all of the viewers
+//               added to the NonlinearImager have in common.
+////////////////////////////////////////////////////////////////////
+GraphicsEngine *NonlinearImager::
+get_graphics_engine() const {
+  return _engine;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NonlinearImager::recompute
 //       Access: Published
@@ -555,10 +635,10 @@ recompute_if_stale() {
           for (si = _screens.begin(); si != _screens.end(); ++si) {
             Screen &screen = (*si);
             if (screen._active && 
-                screen._meshes[vi]._last_screen != screen._screen->get_last_screen()) {
+                screen._meshes[vi]._last_screen != screen._screen_node->get_last_screen()) {
               recompute_screen(screen, vi);
             } else {
-              screen._screen->recompute_if_stale();
+              screen._screen_node->recompute_if_stale(screen._screen);
             }
           }
         }
@@ -581,10 +661,11 @@ recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
     return;
   }
 
-  screen._screen->recompute_if_stale();
+  screen._screen_node->recompute_if_stale(screen._screen);
 
   Viewer &viewer = _viewers[vi];
-  PT(PandaNode) mesh = screen._screen->make_flat_mesh(viewer._viewer);
+  PT(PandaNode) mesh = 
+    screen._screen_node->make_flat_mesh(screen._screen, viewer._viewer);
   if (mesh != (PandaNode *)NULL) {
     screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
   }
@@ -606,7 +687,13 @@ recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
 
   if (screen._buffer != (GraphicsOutput *)NULL) {
     screen._meshes[vi]._mesh.set_texture(screen._buffer->get_texture());
+
+    // We don't really need to set the texture on the external screen,
+    // since that's normally not rendered, but we do anyway just for
+    // debugging purposes (in case the user does try to render it, to
+    // see what's going on).
+    screen._screen.set_texture(screen._buffer->get_texture());
   }
 
-  screen._meshes[vi]._last_screen = screen._screen->get_last_screen();
+  screen._meshes[vi]._last_screen = screen._screen_node->get_last_screen();
 }

+ 11 - 6
panda/src/distort/nonlinearImager.h

@@ -96,13 +96,14 @@ PUBLISHED:
   NonlinearImager();
   ~NonlinearImager();
 
-  int add_screen(ProjectionScreen *screen, const string &name = string());
-  int find_screen(ProjectionScreen *screen) const;
+  int add_screen(ProjectionScreen *screen);
+  int add_screen(const NodePath &screen, const string &name);
+  int find_screen(const NodePath &screen) const;
   void remove_screen(int index);
   void remove_all_screens();
 
   int get_num_screens() const;
-  ProjectionScreen *get_screen(int index) const;
+  NodePath get_screen(int index) const;
   GraphicsOutput *get_buffer(int index) const;
   void set_texture_size(int index, int width, int height);
   void set_source_camera(int index, const NodePath &source_camera);
@@ -117,12 +118,14 @@ PUBLISHED:
 
   void set_viewer_camera(int index, const NodePath &viewer_camera);
   NodePath get_viewer_camera(int index) const;
-
-  NodePath get_internal_scene(int index) const;
+  NodePath get_viewer_scene(int index) const;
 
   int get_num_viewers() const;
   DisplayRegion *get_viewer(int index) const;
 
+  NodePath get_dark_room() const;
+  GraphicsEngine *get_graphics_engine() const;
+
   void recompute();
 
 public:
@@ -150,7 +153,8 @@ private:
 
   class Screen {
   public:
-    PT(ProjectionScreen) _screen;
+    NodePath _screen;
+    PT(ProjectionScreen) _screen_node;
     string _name;
     PT(GraphicsOutput) _buffer;
     NodePath _source_camera;
@@ -169,6 +173,7 @@ private:
   Screens _screens;
 
   GraphicsEngine *_engine;
+  NodePath _dark_room;
 
   bool _stale;
 };

+ 9 - 8
panda/src/distort/projectionScreen.cxx

@@ -116,8 +116,8 @@ has_cull_callback() const {
 //               visible, or false if it should be culled.
 ////////////////////////////////////////////////////////////////////
 bool ProjectionScreen::
-cull_callback(CullTraverser *, CullTraverserData &) {
-  recompute_if_stale();
+cull_callback(CullTraverser *, CullTraverserData &data) {
+  recompute_if_stale(data._node_path.get_node_path());
   return true;
 }
 
@@ -313,7 +313,8 @@ regenerate_screen(const NodePath &projector, const string &screen_name,
 //               does not get dereferenced and deleted.
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) ProjectionScreen::
-make_flat_mesh(const NodePath &camera) {
+make_flat_mesh(const NodePath &this_np, const NodePath &camera) {
+  nassertr(!this_np.is_empty() && this_np.node() == this, NULL);
   nassertr(!camera.is_empty() && 
            camera.node()->is_of_type(LensNode::get_class_type()),
            NULL);
@@ -321,10 +322,9 @@ make_flat_mesh(const NodePath &camera) {
   nassertr(camera_node->get_lens() != (Lens *)NULL, NULL);
 
   // First, ensure the UV's are up-to-date.
-  recompute_if_stale();
+  recompute_if_stale(this_np);
 
   PT(PandaNode) top = new PandaNode(get_name());
-  NodePath this_np(this);
 
   LMatrix4f rel_mat;
   bool computed_rel_mat = false;
@@ -348,7 +348,7 @@ make_flat_mesh(const NodePath &camera) {
 ////////////////////////////////////////////////////////////////////
 void ProjectionScreen::
 recompute() {
-  NodePath this_np(this);
+  NodePath this_np(NodePath::any_path(this));
   do_recompute(this_np);
 }
 
@@ -361,7 +361,9 @@ recompute() {
 //               changed.
 ////////////////////////////////////////////////////////////////////
 void ProjectionScreen::
-recompute_if_stale() {
+recompute_if_stale(const NodePath &this_np) {
+  nassertv(!this_np.is_empty() && this_np.node() == this);
+
   if (_projector_node != (LensNode *)NULL && 
       _projector_node->get_lens() != (Lens *)NULL) {
     UpdateSeq lens_change = _projector_node->get_lens()->get_last_change();
@@ -370,7 +372,6 @@ recompute_if_stale() {
 
     } else {
       // Get the relative transform to ensure it hasn't changed.
-      NodePath this_np(this);
       const LMatrix4f &top_mat = this_np.get_mat(_projector);
       if (!_rel_top_mat.almost_equal(top_mat)) {
         _rel_top_mat = top_mat;

+ 2 - 2
panda/src/distort/projectionScreen.h

@@ -71,7 +71,7 @@ PUBLISHED:
   void regenerate_screen(const NodePath &projector, const string &screen_name,
                          int num_x_verts, int num_y_verts, float distance,
                          float fill_ratio);
-  PT(PandaNode) make_flat_mesh(const NodePath &camera);
+  PT(PandaNode) make_flat_mesh(const NodePath &this_np, const NodePath &camera);
 
   INLINE void set_invert_uvs(bool invert_uvs);
   INLINE bool get_invert_uvs() const;
@@ -88,7 +88,7 @@ PUBLISHED:
 
 public:
   INLINE const UpdateSeq &get_last_screen() const;
-  void recompute_if_stale();
+  void recompute_if_stale(const NodePath &this_np);
 
 private:
   void do_recompute(const NodePath &this_np);