Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/distort/nonlinearImager.cxx

Go to the documentation of this file.
00001 // Filename: nonlinearImager.cxx
00002 // Created by:  drose (12Dec01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "nonlinearImager.h"
00020 #include "config_distort.h"
00021 
00022 #include "graphicsStateGuardian.h"
00023 #include "matrixLens.h"
00024 #include "graphicsWindow.h"
00025 #include "graphicsEngine.h"
00026 #include "dcast.h"
00027 
00028 ////////////////////////////////////////////////////////////////////
00029 //     Function: NonlinearImager::Constructor
00030 //       Access: Published
00031 //  Description: 
00032 ////////////////////////////////////////////////////////////////////
00033 NonlinearImager::
00034 NonlinearImager() {
00035   _gsg = (GraphicsStateGuardian *)NULL;
00036   _stale = true;
00037 }
00038 
00039 ////////////////////////////////////////////////////////////////////
00040 //     Function: NonlinearImager::Destructor
00041 //       Access: Published
00042 //  Description: 
00043 ////////////////////////////////////////////////////////////////////
00044 NonlinearImager::
00045 ~NonlinearImager() {
00046   remove_all_screens();
00047   remove_all_viewers();
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: NonlinearImager::add_screen
00052 //       Access: Published
00053 //  Description: Adds a new ProjectionScreen to the list of screens
00054 //               that will be processed by the NonlinearImager.  Each
00055 //               ProjectionScreen represents a view into the world.
00056 //               It must be based on a linear camera (or whatever kind
00057 //               of camera is respected by the graphics engine).
00058 //
00059 //               width and height indicate the size of the texture
00060 //               that will be created to render the scene for the
00061 //               screen.  See set_texture_size().
00062 //
00063 //               Each ProjectionScreen object should already have some
00064 //               screen geometry created.
00065 //
00066 //               When render() is called, the graphics state guardian
00067 //               will be used to render a scene for each
00068 //               ProjectionScreen object, and then each resulting
00069 //               image will be applied to a mesh to be rendered to the
00070 //               screen.
00071 //
00072 //               The return value is the index number of the new
00073 //               screen.
00074 ////////////////////////////////////////////////////////////////////
00075 int NonlinearImager::
00076 add_screen(ProjectionScreen *screen) {
00077   _screens.push_back(Screen());
00078   Screen &new_screen = _screens.back();
00079   new_screen._screen = screen;
00080   new_screen._texture = (Texture *)NULL;
00081   new_screen._tex_width = 256;
00082   new_screen._tex_height = 256;
00083   new_screen._active = true;
00084 
00085   // Slot a mesh for each viewer.
00086   size_t vi;
00087   for (vi = 0; vi < _viewers.size(); ++vi) {
00088     new_screen._meshes.push_back(Mesh());
00089     new_screen._meshes[vi]._last_screen = screen->get_last_screen();
00090   }
00091 
00092   _stale = true;
00093   return _screens.size() - 1;
00094 }
00095 
00096 ////////////////////////////////////////////////////////////////////
00097 //     Function: NonlinearImager::find_screen
00098 //       Access: Published
00099 //  Description: Returns the index number of the first appearance of
00100 //               the indicated screen within the imager's list, or -1
00101 //               if it does not appear.
00102 ////////////////////////////////////////////////////////////////////
00103 int NonlinearImager::
00104 find_screen(ProjectionScreen *screen) const {
00105   for (size_t i = 0; i < _screens.size(); i++) {
00106     if (_screens[i]._screen == screen) {
00107       return i;
00108     }
00109   }
00110 
00111   return -1;
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: NonlinearImager::remove_screen
00116 //       Access: Published
00117 //  Description: Removes the screen with the indicated index number
00118 //               from the imager.
00119 ////////////////////////////////////////////////////////////////////
00120 void NonlinearImager::
00121 remove_screen(int index) {
00122   nassertv_always(index >= 0 && index < (int)_screens.size());
00123   Screen &screen = _screens[index];
00124   for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
00125     screen._meshes[vi]._mesh.remove_node();
00126   }
00127   _screens.erase(_screens.begin() + index);
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: NonlinearImager::remove_all_screens
00132 //       Access: Published
00133 //  Description: Removes all screens from the imager.
00134 ////////////////////////////////////////////////////////////////////
00135 void NonlinearImager::
00136 remove_all_screens() {
00137   while (!_screens.empty()) {
00138     remove_screen(_screens.size() - 1);
00139   }
00140 }
00141 
00142 ////////////////////////////////////////////////////////////////////
00143 //     Function: NonlinearImager::get_num_screens
00144 //       Access: Published
00145 //  Description: Returns the number of screens that have been added to
00146 //               the imager.
00147 ////////////////////////////////////////////////////////////////////
00148 int NonlinearImager::
00149 get_num_screens() const {
00150   return _screens.size();
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: NonlinearImager::get_screen
00155 //       Access: Published
00156 //  Description: Returns the nth screen that has been added to the
00157 //               imager.
00158 ////////////////////////////////////////////////////////////////////
00159 ProjectionScreen *NonlinearImager::
00160 get_screen(int index) const {
00161   nassertr(index >= 0 && index < (int)_screens.size(), (ProjectionScreen *)NULL);
00162   return _screens[index]._screen;
00163 }
00164 
00165 ////////////////////////////////////////////////////////////////////
00166 //     Function: NonlinearImager::set_texture_size
00167 //       Access: Published
00168 //  Description: Sets the width and height of the texture used to
00169 //               render the scene for the indicated screen.  This must
00170 //               be less than or equal to the window size, and it
00171 //               should be a power of two.
00172 //
00173 //               In general, the larger the texture, the greater the
00174 //               detail of the rendered scene.
00175 ////////////////////////////////////////////////////////////////////
00176 void NonlinearImager::
00177 set_texture_size(int index, int width, int height) {
00178   nassertv(index >= 0 && index < (int)_screens.size());
00179   _screens[index]._tex_width = width;
00180   _screens[index]._tex_height = height;
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: NonlinearImager::set_source_camera
00185 //       Access: Published
00186 //  Description: Specifies the camera that will be used to render the
00187 //               image for this particular screen.
00188 //
00189 //               The parameter must be a NodePath whose node is a
00190 //               Camera.  The camera itself indicates the scene that
00191 //               is to be rendered.
00192 ////////////////////////////////////////////////////////////////////
00193 void NonlinearImager::
00194 set_source_camera(int index, const NodePath &source_camera) {
00195   nassertv(index >= 0 && index < (int)_screens.size());
00196   nassertv(!source_camera.is_empty() && 
00197            source_camera.node()->is_of_type(Camera::get_class_type()));
00198   _screens[index]._source_camera = source_camera;
00199 }
00200 
00201 ////////////////////////////////////////////////////////////////////
00202 //     Function: NonlinearImager::set_screen_active
00203 //       Access: Published
00204 //  Description: Sets the active flag on the indicated screen.  If the
00205 //               active flag is true, the screen will be used;
00206 //               otherwise, it will not appear.
00207 ////////////////////////////////////////////////////////////////////
00208 void NonlinearImager::
00209 set_screen_active(int index, bool active) {
00210   nassertv(index >= 0 && index < (int)_screens.size());
00211   _screens[index]._active = active;
00212 
00213   if (!active) {
00214     Screen &screen = _screens[index];
00215     // If we've just made this screen inactive, remove its meshes.
00216     for (size_t vi = 0; vi < screen._meshes.size(); vi++) {
00217       screen._meshes[vi]._mesh.remove_node();
00218     }
00219     screen._texture.clear();
00220   } else {
00221     // If we've just made it active, it needs to be recomputed.
00222     _stale = true;
00223   }
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: NonlinearImager::get_screen_active
00228 //       Access: Published
00229 //  Description: Returns the active flag on the indicated screen.
00230 ////////////////////////////////////////////////////////////////////
00231 bool NonlinearImager::
00232 get_screen_active(int index) const {
00233   nassertr(index >= 0 && index < (int)_screens.size(), false);
00234   return _screens[index]._active;
00235 }
00236 
00237 
00238 ////////////////////////////////////////////////////////////////////
00239 //     Function: NonlinearImager::add_viewer
00240 //       Access: Published
00241 //  Description: Adds the indicated DisplayRegion as a viewer into the
00242 //               NonlinearImager room.  The camera associated with the
00243 //               DisplayRegion at the time add_viewer() is called is
00244 //               used as the initial viewer camera; it may have a
00245 //               nonlinear lens, like a fisheye or cylindrical lens.
00246 //
00247 //               This sets up a special scene graph for this
00248 //               DisplayRegion alone and sets up the DisplayRegion
00249 //               with a specialty camera.  If future changes to the
00250 //               camera are desired, you should use the
00251 //               set_viewer_camera() interface.
00252 //
00253 //               All viewers must share the same
00254 //               GraphicsStateGuardian.
00255 //
00256 //               The return value is the index of the new viewer.
00257 ////////////////////////////////////////////////////////////////////
00258 int NonlinearImager::
00259 add_viewer(DisplayRegion *dr) {
00260   GraphicsWindow *win = dr->get_window();
00261   GraphicsStateGuardian *gsg = win->get_gsg();
00262   nassertr(_viewers.empty() || (gsg == _gsg && win == _win), -1);
00263   _gsg = gsg;
00264   _win = win;
00265 
00266   int previous_vi = find_viewer(dr);
00267   if (previous_vi >= 0) {
00268     return previous_vi;
00269   }
00270 
00271   size_t vi = _viewers.size();
00272   _viewers.push_back(Viewer());
00273   Viewer &viewer = _viewers[vi];
00274 
00275   viewer._dr = dr;
00276 
00277   // Get the current camera off of the DisplayRegion, if any.
00278   viewer._viewer = dr->get_camera();
00279   if (viewer._viewer.is_empty()) {
00280     viewer._viewer_node = (LensNode *)NULL;
00281   } else {
00282     viewer._viewer_node = DCAST(LensNode, viewer._viewer.node());
00283   }
00284 
00285   // The internal camera is an identity-matrix camera that simply
00286   // views the meshes that represent the user's specified camera.
00287   viewer._internal_camera = new Camera("NonlinearImager");
00288   viewer._internal_camera->set_lens(new MatrixLens);
00289   viewer._internal_scene = NodePath("screens");
00290   viewer._internal_camera->set_scene(viewer._internal_scene);
00291 
00292   NodePath camera_np = viewer._internal_scene.attach_new_node(viewer._internal_camera);
00293   viewer._dr->set_camera(camera_np);
00294 
00295   // Enable face culling on the wireframe mesh.  This will help us to
00296   // cull out invalid polygons that result from vertices crossing a
00297   // singularity (for instance, at the back of a fisheye lens).
00298   viewer._internal_scene.set_two_sided(0);
00299 
00300   // Finally, slot a new mesh for each screen.
00301   Screens::iterator si;
00302   for (si = _screens.begin(); si != _screens.end(); ++si) {
00303     Screen &screen = (*si);
00304     screen._meshes.push_back(Mesh());
00305     nassertr(screen._meshes.size() == _viewers.size(), -1);
00306   }
00307 
00308   _stale = true;
00309   return vi;
00310 }
00311 
00312 ////////////////////////////////////////////////////////////////////
00313 //     Function: NonlinearImager::find_viewer
00314 //       Access: Published
00315 //  Description: Returns the index number of the indicated
00316 //               DisplayRegion within the list of viewers, or -1 if it
00317 //               is not found.
00318 ////////////////////////////////////////////////////////////////////
00319 int NonlinearImager::
00320 find_viewer(DisplayRegion *dr) const {
00321   for (size_t vi = 0; vi < _viewers.size(); vi++) {
00322     if (_viewers[vi]._dr == dr) {
00323       return vi;
00324     }
00325   }
00326 
00327   return -1;
00328 }
00329 
00330 ////////////////////////////////////////////////////////////////////
00331 //     Function: NonlinearImager::remove_viewer
00332 //       Access: Published
00333 //  Description: Removes the viewer with the indicated index number
00334 //               from the imager.
00335 ////////////////////////////////////////////////////////////////////
00336 void NonlinearImager::
00337 remove_viewer(int index) {
00338   nassertv_always(index >= 0 && index < (int)_viewers.size());
00339   Viewer &viewer = _viewers[index];
00340   viewer._internal_camera->set_scene(NodePath());
00341   viewer._dr->set_camera(viewer._viewer);
00342 
00343   // Also remove the corresponding mesh from each screen.
00344   Screens::iterator si;
00345   for (si = _screens.begin(); si != _screens.end(); ++si) {
00346     Screen &screen = (*si);
00347     nassertv(index < (int)screen._meshes.size());
00348     screen._meshes[index]._mesh.remove_node();
00349     screen._meshes.erase(screen._meshes.begin() + index);
00350   }
00351 
00352   _viewers.erase(_viewers.begin() + index);
00353 }
00354 
00355 ////////////////////////////////////////////////////////////////////
00356 //     Function: NonlinearImager::remove_all_viewers
00357 //       Access: Published
00358 //  Description: Removes all viewers from the imager.
00359 ////////////////////////////////////////////////////////////////////
00360 void NonlinearImager::
00361 remove_all_viewers() {
00362   while (!_viewers.empty()) {
00363     remove_viewer(_viewers.size() - 1);
00364   }
00365 }
00366 
00367 ////////////////////////////////////////////////////////////////////
00368 //     Function: NonlinearImager::set_viewer_camera
00369 //       Access: Published
00370 //  Description: Specifies the LensNode that is to serve as the
00371 //               viewer for this screen.  The relative position of
00372 //               the LensNode to the NonlinearImager, as well as the
00373 //               properties of the lens associated with the LensNode,
00374 //               determines the UV's that will be assigned to the
00375 //               geometry within the NonlinearImager.
00376 //
00377 //               It is not necessary to call this except to change the
00378 //               camera after a viewer has been added, since the
00379 //               default is to use whatever camera is associated with
00380 //               the DisplayRegion at the time the viewer is added.
00381 //
00382 //               The NodePath must refer to a LensNode (or a Camera).
00383 ////////////////////////////////////////////////////////////////////
00384 void NonlinearImager::
00385 set_viewer_camera(int index, const NodePath &viewer_camera) {
00386   nassertv(index >= 0 && index < (int)_viewers.size());
00387   nassertv(!viewer_camera.is_empty() && 
00388            viewer_camera.node()->is_of_type(LensNode::get_class_type()));
00389   Viewer &viewer = _viewers[index];
00390   viewer._viewer = viewer_camera;
00391   viewer._viewer_node = DCAST(LensNode, viewer_camera.node());
00392   _stale = true;
00393 }
00394 
00395 ////////////////////////////////////////////////////////////////////
00396 //     Function: NonlinearImager::get_viewer_camera
00397 //       Access: Published
00398 //  Description: Returns the NodePath to the LensNode that is to serve
00399 //               as nth viewer for this screen.
00400 ////////////////////////////////////////////////////////////////////
00401 NodePath NonlinearImager::
00402 get_viewer_camera(int index) const {
00403   nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
00404   return _viewers[index]._viewer;
00405 }
00406 
00407 ////////////////////////////////////////////////////////////////////
00408 //     Function: NonlinearImager::get_internal_scene
00409 //       Access: Published
00410 //  Description: Returns a pointer to the root node of the internal
00411 //               scene graph for the nth viewer, which is used to
00412 //               render all of the screen meshes for this viewer.
00413 ////////////////////////////////////////////////////////////////////
00414 NodePath NonlinearImager::
00415 get_internal_scene(int index) const {
00416   nassertr(index >= 0 && index < (int)_viewers.size(), NodePath());
00417   return _viewers[index]._internal_scene;
00418 }
00419 
00420 ////////////////////////////////////////////////////////////////////
00421 //     Function: NonlinearImager::get_num_viewers
00422 //       Access: Published
00423 //  Description: Returns the number of viewers that have been added to
00424 //               the imager.
00425 ////////////////////////////////////////////////////////////////////
00426 int NonlinearImager::
00427 get_num_viewers() const {
00428   return _viewers.size();
00429 }
00430 
00431 ////////////////////////////////////////////////////////////////////
00432 //     Function: NonlinearImager::get_viewer
00433 //       Access: Published
00434 //  Description: Returns the nth viewer's DisplayRegion that has been
00435 //               added to the imager.
00436 ////////////////////////////////////////////////////////////////////
00437 DisplayRegion *NonlinearImager::
00438 get_viewer(int index) const {
00439   nassertr(index >= 0 && index < (int)_viewers.size(), (DisplayRegion *)NULL);
00440   return _viewers[index]._dr;
00441 }
00442 
00443 ////////////////////////////////////////////////////////////////////
00444 //     Function: NonlinearImager::recompute
00445 //       Access: Published
00446 //  Description: Forces a regeneration of all the mesh objects, etc.
00447 ////////////////////////////////////////////////////////////////////
00448 void NonlinearImager::
00449 recompute() {
00450   // First, force all the textures to clear.
00451   Screens::iterator si;
00452   for (si = _screens.begin(); si != _screens.end(); ++si) {
00453     Screen &screen = (*si);
00454     screen._texture.clear();
00455   }
00456 
00457   size_t vi;
00458   for (vi = 0; vi < _viewers.size(); ++vi) {
00459     Viewer &viewer = _viewers[vi];
00460 
00461     for (si = _screens.begin(); si != _screens.end(); ++si) {
00462       Screen &screen = (*si);
00463       if (screen._active) {
00464         recompute_screen(screen, vi);
00465       }
00466     }
00467 
00468     if (viewer._viewer_node != (LensNode *)NULL && 
00469         viewer._viewer_node->get_lens() != (Lens *)NULL) {
00470       viewer._viewer_lens_change = 
00471         viewer._viewer_node->get_lens()->get_last_change();
00472     }
00473   }
00474 
00475   _stale = false;
00476 }
00477 
00478 ////////////////////////////////////////////////////////////////////
00479 //     Function: NonlinearImager::render
00480 //       Access: Published
00481 //  Description: Uses the DisplayRegion's GSG to render a scene for
00482 //               each ProjectionScreen, and makes our DisplayRegion
00483 //               ready to render the combined results.  This will
00484 //               destroy the contents of the frame buffer; it should
00485 //               be done before any of the actual frame has started
00486 //               rendering.
00487 ////////////////////////////////////////////////////////////////////
00488 void NonlinearImager::
00489 render(GraphicsEngine *engine) {
00490   recompute_if_stale();
00491 
00492   Screens::iterator si;
00493   for (si = _screens.begin(); si != _screens.end(); ++si) {
00494     if ((*si)._active) {
00495       render_screen(engine, *si);
00496     }
00497   }
00498 }
00499 
00500 ////////////////////////////////////////////////////////////////////
00501 //     Function: NonlinearImager::recompute_if_stale
00502 //       Access: Private
00503 //  Description: Calls recompute() if it needs to be called.
00504 ////////////////////////////////////////////////////////////////////
00505 void NonlinearImager::
00506 recompute_if_stale() {
00507   if (_stale) {
00508     recompute();
00509   } else {
00510     size_t vi;
00511     for (vi = 0; vi < _viewers.size(); ++vi) {
00512       Viewer &viewer = _viewers[vi];
00513       if (viewer._viewer_node != (LensNode *)NULL) {
00514         UpdateSeq lens_change = 
00515           viewer._viewer_node->get_lens()->get_last_change();
00516         if (lens_change != viewer._viewer_lens_change) {
00517           // The viewer has changed, so we need to recompute all screens
00518           // on this viewer.
00519           Screens::iterator si;
00520           for (si = _screens.begin(); si != _screens.end(); ++si) {
00521             Screen &screen = (*si);
00522             if (screen._active) {
00523               recompute_screen(screen, vi);
00524             }
00525           }
00526           
00527         } else {
00528           // We may not need to recompute all screens, but maybe some of
00529           // them.
00530           Screens::iterator si;
00531           for (si = _screens.begin(); si != _screens.end(); ++si) {
00532             Screen &screen = (*si);
00533             if (screen._active && 
00534                 screen._meshes[vi]._last_screen != screen._screen->get_last_screen()) {
00535               recompute_screen(screen, vi);
00536             }
00537           }
00538         }
00539       }
00540     }
00541   }
00542 }
00543 
00544 ////////////////////////////////////////////////////////////////////
00545 //     Function: NonlinearImager::recompute_screen
00546 //       Access: Private
00547 //  Description: Regenerates the mesh objects just for the indicated
00548 //               screen.
00549 ////////////////////////////////////////////////////////////////////
00550 void NonlinearImager::
00551 recompute_screen(NonlinearImager::Screen &screen, size_t vi) {
00552   nassertv(vi < screen._meshes.size());
00553   screen._meshes[vi]._mesh.remove_node();
00554   if (!screen._active) {
00555     return;
00556   }
00557 
00558   Viewer &viewer = _viewers[vi];
00559   PT(PandaNode) mesh = screen._screen->make_flat_mesh(viewer._viewer);
00560   if (mesh != (PandaNode *)NULL) {
00561     screen._meshes[vi]._mesh = viewer._internal_scene.attach_new_node(mesh);
00562   }
00563 
00564   if (screen._texture == (Texture *)NULL ||
00565       screen._texture->_pbuffer == (PixelBuffer *)NULL ||
00566       screen._texture->_pbuffer->get_xsize() != screen._tex_width ||
00567       screen._texture->_pbuffer->get_ysize() != screen._tex_height) {
00568     PT(Texture) texture = new Texture;
00569     texture->set_minfilter(Texture::FT_linear);
00570     texture->set_magfilter(Texture::FT_linear);
00571     texture->set_wrapu(Texture::WM_clamp);
00572     texture->set_wrapv(Texture::WM_clamp);
00573     texture->_pbuffer->set_xsize(screen._tex_width);
00574     texture->_pbuffer->set_ysize(screen._tex_height);
00575 
00576     screen._texture = texture;
00577   }
00578 
00579   screen._meshes[vi]._mesh.set_texture(screen._texture);
00580   screen._meshes[vi]._last_screen = screen._screen->get_last_screen();
00581 }
00582 
00583 ////////////////////////////////////////////////////////////////////
00584 //     Function: NonlinearImager::render_screen
00585 //       Access: Private
00586 //  Description: Renders the scene just for the indicated screen, into
00587 //               the screen's own texture.
00588 ////////////////////////////////////////////////////////////////////
00589 void NonlinearImager::
00590 render_screen(GraphicsEngine *engine, NonlinearImager::Screen &screen) {
00591   if (screen._source_camera.is_empty()) {
00592     distort_cat.error()
00593       << "No source camera specified for screen " << screen._screen->get_name()
00594       << "\n";
00595     return;
00596   }
00597 
00598   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00599 
00600   screen._screen->recompute_if_stale();
00601 
00602   // Make a display region of the proper size and clear it to prepare for
00603   // rendering the scene.
00604   PT(DisplayRegion) scratch_region =
00605     _win->make_scratch_display_region(screen._tex_width, screen._tex_height);
00606   scratch_region->set_camera(screen._source_camera);
00607   engine->render_subframe(_gsg, scratch_region, true);
00608 
00609   // Copy the results of the render from the frame buffer into the
00610   // screen's texture.
00611   screen._texture->copy(_gsg, scratch_region, 
00612                         _gsg->get_render_buffer(RenderBuffer::T_back));
00613 
00614   // It might be nice if we didn't throw away the scratch region every
00615   // time, which prevents us from preserving cull state from one frame
00616   // to the next.
00617 }

Generated on Fri May 2 00:36:39 2003 for Panda by doxygen1.3