Panda3D

nonlinearImager.cxx

00001 // Filename: nonlinearImager.cxx
00002 // Created by:  drose (12Dec01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "nonlinearImager.h"
00016 #include "config_distort.h"
00017 
00018 #include "graphicsStateGuardian.h"
00019 #include "matrixLens.h"
00020 #include "graphicsOutput.h"
00021 #include "graphicsEngine.h"
00022 #include "dcast.h"
00023 #include "cPointerCallbackObject.h"
00024 #include "asyncTaskManager.h"
00025 #include "genericAsyncTask.h"
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: NonlinearImager::Constructor
00029 //       Access: Published
00030 //  Description: 
00031 ////////////////////////////////////////////////////////////////////
00032 NonlinearImager::
00033 NonlinearImager() {
00034   _engine = (GraphicsEngine *)NULL;
00035   _stale = true;
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: NonlinearImager::Destructor
00040 //       Access: Published
00041 //  Description: 
00042 ////////////////////////////////////////////////////////////////////
00043 NonlinearImager::
00044 ~NonlinearImager() {
00045   remove_all_screens();
00046   remove_all_viewers();
00047 
00048   if (_recompute_task != (AsyncTask *)NULL) {
00049     AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
00050     task_mgr->remove(_recompute_task);
00051   }
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: NonlinearImager::add_screen
00056 //       Access: Published
00057 //               This version of this method is deprecated and will
00058 //               soon be removed.  Use the version that takes two
00059 //               parameters instead.
00060 ////////////////////////////////////////////////////////////////////
00061 int NonlinearImager::
00062 add_screen(ProjectionScreen *screen) {
00063   return add_screen(NodePath(screen), screen->get_name());
00064 }
00065 
00066 ////////////////////////////////////////////////////////////////////
00067 //     Function: NonlinearImager::add_screen
00068 //       Access: Published
00069 //  Description: Adds a new ProjectionScreen to the list of screens
00070 //               that will be processed by the NonlinearImager.  Each
00071 //               ProjectionScreen represents a view into the world.
00072 //               It must be based on a linear camera (or whatever kind
00073 //               of camera is respected by the graphics engine).
00074 //
00075 //               Each ProjectionScreen object should already have some
00076 //               screen geometry created.
00077 //
00078 //               As each frame is rendered, an offscreen image will be
00079 //               rendered from the source camera associated with each
00080 //               ProjectionScreen, and the resulting image will be
00081 //               applied to the screen geometry.
00082 //
00083 //               The return value is the index number of the new
00084 //               screen.
00085 ////////////////////////////////////////////////////////////////////
00086 int NonlinearImager::
00087 add_screen(const NodePath &screen, const string &name) {
00088   nassertr(!screen.is_empty() && 
00089            screen.node()->is_of_type(ProjectionScreen::get_class_type()), -1);
00090 
00091   ProjectionScreen *screen_node = DCAST(ProjectionScreen, screen.node());
00092 
00093   _screens.push_back(Screen());
00094   Screen &new_screen = _screens.back();
00095   new_screen._screen = screen;
00096   new_screen._screen_node = screen_node;
00097   new_screen._name = name;
00098   new_screen._buffer = (GraphicsOutput *)NULL;
00099   new_screen._tex_width = 256;
00100   new_screen._tex_height = 256;
00101   new_screen._active = true;
00102 
00103   // Slot a mesh for each viewer.
00104   size_t vi;
00105   for (vi = 0; vi < _viewers.size(); ++vi) {
00106     new_screen._meshes.push_back(Mesh());
00107     new_screen._meshes[vi]._last_screen = screen_node->get_last_screen();
00108   }
00109 
00110   _stale = true;
00111 
00112   if (_dark_room.is_empty()) {
00113     _dark_room = screen.get_top();
00114   } else {
00115     nassertr(_dark_room.is_same_graph(screen), _screens.size() - 1);
00116   }
00117 
00118   return _screens.size() - 1;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: NonlinearImager::find_screen
00123 //       Access: Published
00124 //  Description: Returns the index number of the first appearance of
00125 //               the indicated screen within the imager's list, or -1
00126 //               if it does not appear.
00127 ////////////////////////////////////////////////////////////////////
00128 int NonlinearImager::
00129 find_screen(const NodePath &screen) const {
00130   for (size_t i = 0; i < _screens.size(); i++) {
00131     if (_screens[i]._screen == screen) {
00132       return i;
00133     }
00134   }
00135 
00136   return -1;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: NonlinearImager::remove_screen
00141 //       Access: Published
00142 //  Description: Removes the screen with the indicated index number
00143 //               from the imager.
00144 ////////////////////////////////////////////////////////////////////
00145 void NonlinearImager::
00146 remove_screen(int index) {
00147   nassertv_always(index >= 0 && index < (int)_screens.size());
00148   Screen &screen = _screens[index];
00149   for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
00150     screen._meshes[vi]._mesh.remove_node();
00151   }
00152   _screens.erase(_screens.begin() + index);
00153 }
00154 
00155 ////////////////////////////////////////////////////////////////////
00156 //     Function: NonlinearImager::remove_all_screens
00157 //       Access: Published
00158 //  Description: Removes all screens from the imager.
00159 ////////////////////////////////////////////////////////////////////
00160 void NonlinearImager::
00161 remove_all_screens() {
00162   while (!_screens.empty()) {
00163     remove_screen(_screens.size() - 1);
00164   }
00165 }
00166 
00167 ////////////////////////////////////////////////////////////////////
00168 //     Function: NonlinearImager::get_num_screens
00169 //       Access: Published
00170 //  Description: Returns the number of screens that have been added to
00171 //               the imager.
00172 ////////////////////////////////////////////////////////////////////
00173 int NonlinearImager::
00174 get_num_screens() const {
00175   return _screens.size();
00176 }
00177 
00178 ////////////////////////////////////////////////////////////////////
00179 //     Function: NonlinearImager::get_screen
00180 //       Access: Published
00181 //  Description: Returns the nth screen that has been added to the
00182 //               imager.
00183 ////////////////////////////////////////////////////////////////////
00184 NodePath NonlinearImager::
00185 get_screen(int index) const {
00186   nassertr(index >= 0 && index < (int)_screens.size(), (ProjectionScreen *)NULL);
00187   return _screens[index]._screen;
00188 }
00189 
00190 ////////////////////////////////////////////////////////////////////
00191 //     Function: NonlinearImager::get_buffer
00192 //       Access: Published
00193 //  Description: Returns the offscreen buffer that is automatically
00194 //               created for the nth projection screen.  This may
00195 //               return NULL if the screen is inactive or if it has
00196 //               not been rendered yet.
00197 ////////////////////////////////////////////////////////////////////
00198 GraphicsOutput *NonlinearImager::
00199 get_buffer(int index) const {
00200   nassertr(index >= 0 && index < (int)_screens.size(), (GraphicsOutput *)NULL);
00201   return _screens[index]._buffer;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: NonlinearImager::set_texture_size
00206 //       Access: Published
00207 //  Description: Sets the width and height of the texture used to
00208 //               render the scene for the indicated screen.  This must
00209 //               be less than or equal to the window size, and it
00210 //               should be a power of two.
00211 //
00212 //               In general, the larger the texture, the greater the
00213 //               detail of the rendered scene.
00214 ////////////////////////////////////////////////////////////////////
00215 void NonlinearImager::
00216 set_texture_size(int index, int width, int height) {
00217   nassertv(index >= 0 && index < (int)_screens.size());
00218   
00219   Screen &screen = _screens[index];
00220 
00221   screen._tex_width = width;
00222   screen._tex_height = height;
00223 
00224   if (screen._buffer != (GraphicsOutput *)NULL) {
00225     bool removed = _engine->remove_window(screen._buffer);
00226     screen._buffer = (GraphicsOutput *)NULL;
00227     nassertv(removed);
00228   }
00229 
00230   _stale = true;
00231 }
00232 
00233 ////////////////////////////////////////////////////////////////////
00234 //     Function: NonlinearImager::set_source_camera
00235 //       Access: Published
00236 //  Description: Specifies the camera that will be used to render the
00237 //               image for this particular screen.
00238 //
00239 //               The parameter must be a NodePath whose node is a
00240 //               Camera.  The camera itself indicates the scene that
00241 //               is to be rendered.
00242 ////////////////////////////////////////////////////////////////////
00243 void NonlinearImager::
00244 set_source_camera(int index, const NodePath &source_camera) {
00245   nassertv(index >= 0 && index < (int)_screens.size());
00246   nassertv(!source_camera.is_empty() && 
00247            source_camera.node()->is_of_type(Camera::get_class_type()));
00248   _screens[index]._source_camera = source_camera;
00249 }
00250 
00251 ////////////////////////////////////////////////////////////////////
00252 //     Function: NonlinearImager::set_screen_active
00253 //       Access: Published
00254 //  Description: Sets the active flag on the indicated screen.  If the
00255 //               active flag is true, the screen will be used;
00256 //               otherwise, it will not appear.
00257 ////////////////////////////////////////////////////////////////////
00258 void NonlinearImager::
00259 set_screen_active(int index, bool active) {
00260   nassertv(index >= 0 && index < (int)_screens.size());
00261 
00262   Screen &screen = _screens[index];
00263   screen._active = active;
00264 
00265   if (!active) {
00266     // If we've just made this screen inactive, remove its meshes.
00267     for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
00268       screen._meshes[vi]._mesh.remove_node();
00269     }
00270 
00271     // Also remove its buffer.
00272     if (screen._buffer != (GraphicsOutput *)NULL) {
00273       bool removed = _engine->remove_window(screen._buffer);
00274       screen._buffer = (GraphicsOutput *)NULL;
00275       nassertv(removed);
00276     }
00277 
00278     // Hide the screen in the dark room.  This doesn't really matter,
00279     // since the dark room isn't normally rendered, but hide it anyway
00280     // in case the user stuck a camera in there for fun.
00281     screen._screen.hide();
00282 
00283   } else {
00284     // If we've just made it active, it needs to be recomputed.
00285     _stale = true;
00286 
00287     screen._screen.show();
00288   }
00289 }
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: NonlinearImager::get_screen_active
00293 //       Access: Published
00294 //  Description: Returns the active flag on the indicated screen.
00295 ////////////////////////////////////////////////////////////////////
00296 bool NonlinearImager::
00297 get_screen_active(int index) const {
00298   nassertr(index >= 0 && index < (int)_screens.size(), false);
00299   return _screens[index]._active;
00300 }
00301 
00302 
00303 ////////////////////////////////////////////////////////////////////
00304 //     Function: NonlinearImager::add_viewer
00305 //       Access: Published
00306 //  Description: Adds the indicated DisplayRegion as a viewer into the
00307 //               NonlinearImager room.  The camera associated with the
00308 //               DisplayRegion at the time add_viewer() is called is
00309 //               used as the initial viewer camera; it may have a
00310 //               nonlinear lens, like a fisheye or cylindrical lens.
00311 //
00312 //               This sets up a special scene graph for this
00313 //               DisplayRegion alone and sets up the DisplayRegion
00314 //               with a specialty camera.  If future changes to the
00315 //               camera are desired, you should use the
00316 //               set_viewer_camera() interface.
00317 //
00318 //               All viewers must share the same GraphicsEngine.
00319 //
00320 //               The return value is the index of the new viewer.
00321 ////////////////////////////////////////////////////////////////////
00322 int NonlinearImager::
00323 add_viewer(DisplayRegion *dr) {
00324   GraphicsOutput *window = dr->get_window();
00325   nassertr(window != (GraphicsOutput *)NULL, -1);
00326 
00327   GraphicsStateGuardian *gsg = window->get_gsg();
00328   nassertr(gsg != (GraphicsStateGuardian *)NULL, -1);
00329 
00330   GraphicsEngine *engine = gsg->get_engine();
00331   nassertr(engine != (GraphicsEngine *)NULL, -1);
00332 
00333   nassertr(_viewers.empty() || (engine == _engine), -1);
00334   if (_engine == (GraphicsEngine *)NULL) {
00335     _engine = engine;
00336   }
00337 
00338   if (_recompute_task == (AsyncTask *)NULL) {
00339     _recompute_task = 
00340       new GenericAsyncTask("nli_recompute", recompute_callback, (void *)this);
00341     AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr();
00342     task_mgr->add(_recompute_task);
00343   }
00344 
00345   int previous_vi = find_viewer(dr);
00346   if (previous_vi >= 0) {
00347     return previous_vi;
00348   }
00349 
00350   size_t vi = _viewers.size();
00351   _viewers.push_back(Viewer());
00352   Viewer &viewer = _viewers[vi];
00353 
00354   viewer._dr = dr;
00355 
00356   // Get the current camera off of the DisplayRegion, if any.
00357   viewer._viewer = dr->get_camera();
00358   if (viewer._viewer.is_empty()) {
00359     viewer._viewer_node = (LensNode *)NULL;
00360   } else {
00361     viewer._viewer_node = DCAST(LensNode, viewer._viewer.node());
00362   }
00363 
00364   // The internal camera is an identity-matrix camera that simply
00365   // views the meshes that represent the user's specified camera.
00366   viewer._internal_camera = new Camera("internal_camera");
00367   viewer._internal_camera->set_lens(new MatrixLens);
00368   viewer._internal_scene = NodePath("internal_screens");
00369   viewer._internal_camera->set_scene(viewer._internal_scene);
00370 
00371   NodePath camera_np = viewer._internal_scene.attach_new_node(viewer._internal_camera);
00372   viewer._dr->set_camera(camera_np);
00373 
00374   // Enable face culling on the wireframe mesh.  This will help us to
00375   // cull out invalid polygons that result from vertices crossing a
00376   // singularity (for instance, at the back of a fisheye lens).
00377   viewer._internal_scene.set_two_sided(0);
00378 
00379   // Finally, slot a new mesh for each screen.
00380   Screens::iterator si;
00381   for (si = _screens.begin(); si != _screens.end(); ++si) {
00382     Screen &screen = (*si);
00383     screen._meshes.push_back(Mesh());
00384     nassertr(screen._meshes.size() == _viewers.size(), -1);
00385   }
00386 
00387   _stale = true;
00388 
00389   if (_dark_room.is_empty()) {
00390     _dark_room = viewer._viewer.get_top();
00391   } else {
00392     nassertr(_dark_room.is_same_graph(viewer._viewer), vi);
00393   }
00394 
00395   return vi;
00396 }
00397 
00398 ////////////////////////////////////////////////////////////////////
00399 //     Function: NonlinearImager::find_viewer
00400 //       Access: Published
00401 //  Description: Returns the index number of the indicated
00402 //               DisplayRegion within the list of viewers, or -1 if it
00403 //               is not found.
00404 ////////////////////////////////////////////////////////////////////
00405 int NonlinearImager::
00406 find_viewer(DisplayRegion *dr) const {
00407   for (size_t vi = 0; vi < _viewers.size(); vi++) {
00408     if (_viewers[vi]._dr == dr) {
00409       return vi;
00410     }
00411   }
00412 
00413   return -1;
00414 }
00415 
00416 ////////////////////////////////////////////////////////////////////
00417 //     Function: NonlinearImager::remove_viewer
00418 //       Access: Published
00419 //  Description: Removes the viewer with the indicated index number
00420 //               from the imager.
00421 ////////////////////////////////////////////////////////////////////
00422 void NonlinearImager::
00423 remove_viewer(int index) {
00424   nassertv_always(index >= 0 && index < (int)_viewers.size());
00425   Viewer &viewer = _viewers[index];
00426   viewer._internal_camera->set_scene(NodePath());
00427   viewer._dr->set_camera(viewer._viewer);
00428 
00429   // Also remove the corresponding mesh from each screen.
00430   Screens::iterator si;
00431   for (si = _screens.begin(); si != _screens.end(); ++si) {
00432     Screen &screen = (*si);
00433     nassertv(index < (int)screen._meshes.size());
00434     screen._meshes[index]._mesh.remove_node();
00435     screen._meshes.erase(screen._meshes.begin() + index);
00436   }
00437 
00438   _viewers.erase(_viewers.begin() + index);
00439 }
00440 
00441 ////////////////////////////////////////////////////////////////////
00442 //     Function: NonlinearImager::remove_all_viewers
00443 //       Access: Published
00444 //  Description: Removes all viewers from the imager.
00445 ////////////////////////////////////////////////////////////////////
00446 void NonlinearImager::
00447 remove_all_viewers() {
00448   while (!_viewers.empty()) {
00449     remove_viewer(_viewers.size() - 1);
00450   }
00451 }
00452 
00453 ////////////////////////////////////////////////////////////////////
00454 //     Function: NonlinearImager::set_viewer_camera
00455 //       Access: Published
00456 //  Description: Specifies the LensNode that is to serve as the
00457 //               viewer for this screen.  The relative position of
00458 //               the LensNode to the NonlinearImager, as well as the
00459 //               properties of the lens associated with the LensNode,
00460 //               determines the UV's that will be assigned to the
00461 //               geometry within the NonlinearImager.
00462 //
00463 //               It is not necessary to call this except to change the
00464 //               camera after a viewer has been added, since the
00465 //               default is to use whatever camera is associated with
00466 //               the DisplayRegion at the time the viewer is added.
00467 //
00468 //               The NodePath must refer to a LensNode (or a Camera).
00469 ////////////////////////////////////////////////////////////////////
00470 void NonlinearImager::
00471 set_viewer_camera(int index, const NodePath &viewer_camera) {
00472   nassertv(index >= 0 && index < (int)_viewers.size());
00473   nassertv(!viewer_camera.is_empty() && 
00474            viewer_camera.node()->is_of_type(LensNode::get_class_type()));
00475   Viewer &viewer = _viewers[index];
00476   viewer._viewer = viewer_camera;
00477   viewer._viewer_node = DCAST(LensNode, viewer_camera.node());
00478   _stale = true;
00479 
00480   if (_dark_room.is_empty()) {
00481     _dark_room = viewer._viewer.get_top();
00482   } else {
00483     nassertv(_dark_room.is_same_graph(viewer._viewer));
00484   }
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: NonlinearImager::get_viewer_camera
00489 //       Access: Published
00490 //  Description: Returns the NodePath to the LensNode that is to serve
00491 //               as nth viewer for this screen.
00492 ////////////////////////////////////////////////////////////////////
00493 NodePath NonlinearImager::
00494 get_viewer_camera(int index) const {
00495   nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
00496   return _viewers[index]._viewer;
00497 }
00498 
00499 ////////////////////////////////////////////////////////////////////
00500 //     Function: NonlinearImager::get_viewer_scene
00501 //       Access: Published
00502 //  Description: Returns a pointer to the root node of the internal
00503 //               scene graph for the nth viewer, which is used to
00504 //               render all of the screen meshes for this viewer.
00505 //
00506 //               This is the scene graph in which the screen meshes
00507 //               within the dark room have been flattened into the
00508 //               appropriate transformation according to the viewer's
00509 //               lens properties (and position relative to the
00510 //               screens).  It is this scene graph that is finally
00511 //               rendered to the window.
00512 ////////////////////////////////////////////////////////////////////
00513 NodePath NonlinearImager::
00514 get_viewer_scene(int index) const {
00515   nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
00516   return _viewers[index]._internal_scene;
00517 }
00518 
00519 ////////////////////////////////////////////////////////////////////
00520 //     Function: NonlinearImager::get_num_viewers
00521 //       Access: Published
00522 //  Description: Returns the number of viewers that have been added to
00523 //               the imager.
00524 ////////////////////////////////////////////////////////////////////
00525 int NonlinearImager::
00526 get_num_viewers() const {
00527   return _viewers.size();
00528 }
00529 
00530 ////////////////////////////////////////////////////////////////////
00531 //     Function: NonlinearImager::get_viewer
00532 //       Access: Published
00533 //  Description: Returns the nth viewer's DisplayRegion that has been
00534 //               added to the imager.
00535 ////////////////////////////////////////////////////////////////////
00536 DisplayRegion *NonlinearImager::
00537 get_viewer(int index) const {
00538   nassertr(index >= 0 && index < (int)_viewers.size(), (DisplayRegion *)NULL);
00539   return _viewers[index]._dr;
00540 }
00541 
00542 ////////////////////////////////////////////////////////////////////
00543 //     Function: NonlinearImager::get_dark_room
00544 //       Access: Published
00545 //  Description: Returns the NodePath to the root of the dark room
00546 //               scene.  This is the scene in which all of the
00547 //               ProjectionScreens and the viewer cameras reside.
00548 //               It's a standalone scene with a few projection screens
00549 //               arranged artfully around one or more viewers; it's so
00550 //               named because it's a little virtual theater.
00551 //
00552 //               Normally this scene is not rendered directly; it only
00553 //               exists as an abstract concept, and to define the
00554 //               relation between the ProjectionScreens and the
00555 //               viewers.  But it may be rendered to help visualize
00556 //               the NonlinearImager's behavior.
00557 ////////////////////////////////////////////////////////////////////
00558 NodePath NonlinearImager::
00559 get_dark_room() const {
00560   return _dark_room;
00561 }
00562 
00563 ////////////////////////////////////////////////////////////////////
00564 //     Function: NonlinearImager::get_graphics_engine
00565 //       Access: Published
00566 //  Description: Returns the GraphicsEngine that all of the viewers
00567 //               added to the NonlinearImager have in common.
00568 ////////////////////////////////////////////////////////////////////
00569 GraphicsEngine *NonlinearImager::
00570 get_graphics_engine() const {
00571   return _engine;
00572 }
00573 
00574 ////////////////////////////////////////////////////////////////////
00575 //     Function: NonlinearImager::recompute
00576 //       Access: Published
00577 //  Description: Forces a regeneration of all the mesh objects, etc.
00578 ////////////////////////////////////////////////////////////////////
00579 void NonlinearImager::
00580 recompute() {
00581   size_t vi;
00582   for (vi = 0; vi < _viewers.size(); ++vi) {
00583     Viewer &viewer = _viewers[vi];
00584 
00585     Screens::iterator si;
00586     for (si = _screens.begin(); si != _screens.end(); ++si) {
00587       Screen &screen = (*si);
00588       if (screen._active) {
00589         recompute_screen(screen, vi);
00590       }
00591     }
00592 
00593     if (viewer._viewer_node != (LensNode *)NULL && 
00594         viewer._viewer_node->get_lens() != (Lens *)NULL) {
00595       viewer._viewer_lens_change = 
00596         viewer._viewer_node->get_lens()->get_last_change();
00597     }
00598   }
00599 
00600   _stale = false;
00601 }
00602 
00603 ////////////////////////////////////////////////////////////////////
00604 //     Function: NonlinearImager::recompute_callback
00605 //       Access: Private, Static
00606 //  Description: This function is added as a task, to ensure that all
00607 //               frames are up-to-date.
00608 ////////////////////////////////////////////////////////////////////
00609 AsyncTask::DoneStatus NonlinearImager::
00610 recompute_callback(GenericAsyncTask *, void *data) {
00611   NonlinearImager *self = (NonlinearImager *)data;
00612   self->recompute_if_stale();
00613   return AsyncTask::DS_cont;
00614 }
00615 
00616 ////////////////////////////////////////////////////////////////////
00617 //     Function: NonlinearImager::recompute_if_stale
00618 //       Access: Private
00619 //  Description: Calls recompute() if it needs to be called.
00620 ////////////////////////////////////////////////////////////////////
00621 void NonlinearImager::
00622 recompute_if_stale() {
00623   if (_stale) {
00624     recompute();
00625   } else {
00626     size_t vi;
00627     for (vi = 0; vi < _viewers.size(); ++vi) {
00628       Viewer &viewer = _viewers[vi];
00629       if (viewer._viewer_node != (LensNode *)NULL) {
00630         UpdateSeq lens_change = 
00631           viewer._viewer_node->get_lens()->get_last_change();
00632         if (lens_change != viewer._viewer_lens_change) {
00633           // The viewer has changed, so we need to recompute all screens
00634           // on this viewer.
00635           Screens::iterator si;
00636           for (si = _screens.begin(); si != _screens.end(); ++si) {
00637             Screen &screen = (*si);
00638             if (screen._active) {
00639               recompute_screen(screen, vi);
00640             }
00641           }
00642           
00643         } else {
00644           // We may not need to recompute all screens, but maybe some of
00645           // them.
00646           Screens::iterator si;
00647           for (si = _screens.begin(); si != _screens.end(); ++si) {
00648             Screen &screen = (*si);
00649             if (screen._active && 
00650                 screen._meshes[vi]._last_screen != screen._screen_node->get_last_screen()) {
00651               recompute_screen(screen, vi);
00652             } else {
00653               screen._screen_node->recompute_if_stale(screen._screen);
00654             }
00655           }
00656         }
00657       }
00658     }
00659   }
00660 }
00661 
00662 ////////////////////////////////////////////////////////////////////
00663 //     Function: NonlinearImager::recompute_screen
00664 //       Access: Private
00665 //  Description: Regenerates the mesh objects just for the indicated
00666 //               screen.
00667 ////////////////////////////////////////////////////////////////////
00668 void NonlinearImager::
00669 recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
00670   nassertv(vi < screen._meshes.size());
00671   screen._meshes[vi]._mesh.remove_node();
00672   if (!screen._active) {
00673     return;
00674   }
00675 
00676   screen._screen_node->recompute_if_stale(screen._screen);
00677 
00678   Viewer &viewer = _viewers[vi];
00679   PT(PandaNode) mesh = 
00680     screen._screen_node->make_flat_mesh(screen._screen, viewer._viewer);
00681   if (mesh != (PandaNode *)NULL) {
00682     screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
00683   }
00684 
00685   if (screen._buffer == (GraphicsOutput *)NULL) {
00686     GraphicsOutput *win = viewer._dr->get_window();
00687     GraphicsOutput *buffer = win->make_texture_buffer
00688       (screen._name, screen._tex_width, screen._tex_height, NULL, false);
00689 
00690     if (buffer != (GraphicsOutput *)NULL) {
00691       screen._buffer = buffer;
00692       DisplayRegion *dr = buffer->make_display_region();
00693       dr->set_camera(screen._source_camera);
00694 
00695     } else {
00696       screen._meshes[vi]._mesh.clear_texture();
00697     }
00698   }
00699 
00700   if (screen._buffer != (GraphicsOutput *)NULL) {
00701     screen._meshes[vi]._mesh.set_texture(screen._buffer->get_texture());
00702 
00703     // We don't really need to set the texture on the dark room
00704     // screen, since that's normally not rendered, but we do anyway
00705     // just for debugging purposes (in case the user does try to
00706     // render it, to see what's going on).
00707     screen._screen.set_texture(screen._buffer->get_texture());
00708   }
00709 
00710   screen._meshes[vi]._last_screen = screen._screen_node->get_last_screen();
00711 }
 All Classes Functions Variables Enumerations