From a1ba7a54e788d4664d0c1a6dc18a0a4bd6d59c32 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 31 Mar 2004 23:33:13 +0000 Subject: [PATCH] use NodePaths for ProjectionScreen interface --- panda/src/distort/nonlinearImager.cxx | 133 ++++++++++++++++++++----- panda/src/distort/nonlinearImager.h | 17 ++-- panda/src/distort/projectionScreen.cxx | 17 ++-- panda/src/distort/projectionScreen.h | 4 +- 4 files changed, 132 insertions(+), 39 deletions(-) diff --git a/panda/src/distort/nonlinearImager.cxx b/panda/src/distort/nonlinearImager.cxx index d23475fce1..26cb9e7c76 100644 --- a/panda/src/distort/nonlinearImager.cxx +++ b/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(); } diff --git a/panda/src/distort/nonlinearImager.h b/panda/src/distort/nonlinearImager.h index b99a7bb54a..7563a651e7 100644 --- a/panda/src/distort/nonlinearImager.h +++ b/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; }; diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index 52a6d3fe0d..52b93a1cb2 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/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; diff --git a/panda/src/distort/projectionScreen.h b/panda/src/distort/projectionScreen.h index f4c70176ab..921eeef96e 100644 --- a/panda/src/distort/projectionScreen.h +++ b/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);