Panda3D
|
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 }