Panda3D
|
00001 // Filename: pandaFramework.cxx 00002 // Created by: drose (02Apr02) 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 "pandaFramework.h" 00016 #include "clockObject.h" 00017 #include "pStatClient.h" 00018 #include "eventQueue.h" 00019 #include "dataGraphTraverser.h" 00020 #include "depthOffsetAttrib.h" 00021 #include "collisionNode.h" 00022 #include "occluderNode.h" 00023 #include "config_framework.h" 00024 #include "graphicsPipeSelection.h" 00025 #include "nodePathCollection.h" 00026 #include "textNode.h" 00027 #include "mouseAndKeyboard.h" 00028 #include "mouseRecorder.h" 00029 #include "throw_event.h" 00030 #include "executionEnvironment.h" 00031 #include "sceneGraphAnalyzer.h" 00032 #include "transformState.h" 00033 #include "renderState.h" 00034 00035 LoaderOptions PandaFramework::_loader_options; 00036 00037 //////////////////////////////////////////////////////////////////// 00038 // Function: PandaFramework::Constructor 00039 // Access: Public 00040 // Description: 00041 //////////////////////////////////////////////////////////////////// 00042 PandaFramework:: 00043 PandaFramework() : 00044 _event_handler(*EventHandler::get_global_event_handler()), 00045 _task_mgr(*AsyncTaskManager::get_global_ptr()) 00046 { 00047 _is_open = false; 00048 _made_default_pipe = false; 00049 _window_title = string(); 00050 _engine = (GraphicsEngine *)NULL; 00051 _start_time = 0.0; 00052 _frame_count = 0; 00053 _wireframe_enabled = false; 00054 _texture_enabled = true; 00055 _two_sided_enabled = false; 00056 _lighting_enabled = false; 00057 _perpixel_enabled = false; 00058 _background_type = WindowFramework::BT_default; 00059 _default_keys_enabled = false; 00060 _exit_flag = false; 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: PandaFramework::Destructor 00065 // Access: Public, Virtual 00066 // Description: 00067 //////////////////////////////////////////////////////////////////// 00068 PandaFramework:: 00069 ~PandaFramework() { 00070 if (_is_open) { 00071 close_framework(); 00072 } 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: PandaFramework::open_framework 00077 // Access: Public 00078 // Description: Should be called once at the beginning of the 00079 // application to initialize Panda (and the framework) 00080 // for use. The command-line arguments should be passed 00081 // in so Panda can remove any arguments that it 00082 // recognizes as special control parameters. 00083 //////////////////////////////////////////////////////////////////// 00084 void PandaFramework:: 00085 open_framework(int &argc, char **&argv) { 00086 if (_is_open) { 00087 return; 00088 } 00089 00090 _is_open = true; 00091 00092 #ifdef LINK_ALL_STATIC 00093 // If we're statically linking, we need to explicitly link with 00094 // at least one of the available renderers. 00095 #ifdef HAVE_GL 00096 extern EXPCL_PANDAGL void init_libpandagl(); 00097 init_libpandagl(); 00098 #elif HAVE_DX9 00099 extern EXPCL_PANDADX9 void init_libpandadx9(); 00100 init_libpandadx9(); 00101 #elif HAVE_DX8 00102 extern EXPCL_PANDADX8 void init_libpandadx8(); 00103 init_libpandadx8(); 00104 #elif HAVE_TINYDISPLAY 00105 extern EXPCL_TINYDISPLAY void init_libtinydisplay(); 00106 init_libtinydisplay(); 00107 #endif 00108 00109 // Ensure the animation subsystem is available. 00110 extern EXPCL_PANDA_CHAR void init_libchar(); 00111 init_libchar(); 00112 00113 // We also want the egg loader. 00114 #ifdef HAVE_EGG 00115 extern EXPCL_PANDAEGG void init_libpandaegg(); 00116 init_libpandaegg(); 00117 #endif 00118 00119 #endif 00120 00121 // Let's explicitly make a call to the image type library to ensure 00122 // it gets pulled in by the dynamic linker. 00123 extern EXPCL_PANDA_PNMIMAGETYPES void init_libpnmimagetypes(); 00124 init_libpnmimagetypes(); 00125 00126 reset_frame_rate(); 00127 00128 { 00129 PT(GenericAsyncTask) task = new GenericAsyncTask("event", task_event, this); 00130 _task_mgr.add(task); 00131 } 00132 00133 _data_root = NodePath("data"); 00134 { 00135 PT(GenericAsyncTask) task = new GenericAsyncTask("data_loop", task_data_loop, this); 00136 task->set_sort(-50); 00137 _task_mgr.add(task); 00138 } 00139 00140 if (garbage_collect_states) { 00141 PT(GenericAsyncTask) task = new GenericAsyncTask("garbageCollectStates", task_garbage_collect, this); 00142 task->set_sort(46); 00143 _task_mgr.add(task); 00144 } 00145 00146 _highlight_wireframe = NodePath("wireframe"); 00147 _highlight_wireframe.set_render_mode_wireframe(1); 00148 _highlight_wireframe.set_texture_off(1); 00149 _highlight_wireframe.set_color(1.0f, 0.0f, 0.0f, 1.0f, 1); 00150 _highlight_wireframe.set_attrib(DepthOffsetAttrib::make()); 00151 00152 if (!playback_session.empty()) { 00153 // If the config file so indicates, create a recorder and start it 00154 // playing. 00155 _recorder = new RecorderController; 00156 _recorder->begin_playback(Filename::from_os_specific(playback_session)); 00157 00158 PT(GenericAsyncTask) task = new GenericAsyncTask("play_frame", task_play_frame, this); 00159 task->set_sort(55); 00160 _task_mgr.add(task); 00161 00162 } else if (!record_session.empty()) { 00163 // If the config file so indicates, create a recorder and start it 00164 // recording. 00165 _recorder = new RecorderController; 00166 _recorder->begin_record(Filename::from_os_specific(record_session)); 00167 00168 PT(GenericAsyncTask) task = new GenericAsyncTask("record_frame", task_record_frame, this); 00169 task->set_sort(45); 00170 _task_mgr.add(task); 00171 } 00172 00173 _event_handler.add_hook("window-event", event_window_event, this); 00174 } 00175 00176 //////////////////////////////////////////////////////////////////// 00177 // Function: PandaFramework::close_framework 00178 // Access: Public 00179 // Description: Should be called at the end of an application to 00180 // close Panda. This is optional, as the destructor 00181 // will do the same thing. 00182 //////////////////////////////////////////////////////////////////// 00183 void PandaFramework:: 00184 close_framework() { 00185 if (!_is_open) { 00186 return; 00187 } 00188 00189 close_all_windows(); 00190 // Also close down any other windows that might have been opened. 00191 if (_engine != (GraphicsEngine *)NULL) { 00192 _engine->remove_all_windows(); 00193 _engine = NULL; 00194 } 00195 00196 _event_handler.remove_all_hooks(); 00197 00198 _is_open = false; 00199 _made_default_pipe = false; 00200 _default_pipe.clear(); 00201 00202 _start_time = 0.0; 00203 _frame_count = 0; 00204 _wireframe_enabled = false; 00205 _two_sided_enabled = false; 00206 _lighting_enabled = false; 00207 _default_keys_enabled = false; 00208 _exit_flag = false; 00209 00210 _recorder = NULL; 00211 00212 Thread::prepare_for_exit(); 00213 } 00214 00215 //////////////////////////////////////////////////////////////////// 00216 // Function: PandaFramework::get_default_pipe 00217 // Access: Public 00218 // Description: Returns the default pipe. This is the GraphicsPipe 00219 // that all windows in the framework will be created on, 00220 // unless otherwise specified in open_window(). It is 00221 // usually the primary graphics interface on the local 00222 // machine. 00223 // 00224 // If the default pipe has not yet been created, this 00225 // creates it. 00226 // 00227 // The return value is the default pipe, or NULL if no 00228 // default pipe could be created. 00229 //////////////////////////////////////////////////////////////////// 00230 GraphicsPipe *PandaFramework:: 00231 get_default_pipe() { 00232 nassertr(_is_open, NULL); 00233 if (!_made_default_pipe) { 00234 make_default_pipe(); 00235 _made_default_pipe = true; 00236 } 00237 return _default_pipe; 00238 } 00239 00240 //////////////////////////////////////////////////////////////////// 00241 // Function: PandaFramework::get_mouse 00242 // Access: Public 00243 // Description: Returns a NodePath to the MouseAndKeyboard associated 00244 // with the indicated GraphicsWindow object. If there's 00245 // not yet a mouse associated with the window, creates 00246 // one. 00247 // 00248 // This allows multiple WindowFramework objects that 00249 // represent different display regions of the same 00250 // GraphicsWindow to share the same mouse. 00251 //////////////////////////////////////////////////////////////////// 00252 NodePath PandaFramework:: 00253 get_mouse(GraphicsOutput *window) { 00254 Mouses::iterator mi = _mouses.find(window); 00255 if (mi != _mouses.end()) { 00256 return (*mi).second; 00257 } 00258 00259 NodePath mouse; 00260 00261 if (window->is_of_type(GraphicsWindow::get_class_type())) { 00262 NodePath data_root = get_data_root(); 00263 GraphicsWindow *win = DCAST(GraphicsWindow, window); 00264 MouseAndKeyboard *mouse_node = new MouseAndKeyboard(win, 0, "mouse"); 00265 mouse = data_root.attach_new_node(mouse_node); 00266 00267 RecorderController *recorder = get_recorder(); 00268 if (recorder != (RecorderController *)NULL) { 00269 // If we're in recording or playback mode, associate a recorder. 00270 MouseRecorder *mouse_recorder = new MouseRecorder("mouse"); 00271 mouse = mouse.attach_new_node(mouse_recorder); 00272 recorder->add_recorder("mouse", mouse_recorder); 00273 } 00274 } 00275 00276 _mouses[window] = mouse; 00277 00278 return mouse; 00279 } 00280 00281 //////////////////////////////////////////////////////////////////// 00282 // Function: PandaFramework::remove_mouse 00283 // Access: Public 00284 // Description: Removes the mouse that may have been created by an 00285 // earlier call to get_mouse(). 00286 //////////////////////////////////////////////////////////////////// 00287 void PandaFramework:: 00288 remove_mouse(const GraphicsOutput *window) { 00289 Mouses::iterator mi = _mouses.find(window); 00290 if (mi != _mouses.end()) { 00291 (*mi).second.remove_node(); 00292 _mouses.erase(mi); 00293 } 00294 } 00295 00296 //////////////////////////////////////////////////////////////////// 00297 // Function: PandaFramework::define_key 00298 // Access: Public 00299 // Description: Sets up a handler for the indicated key. When the 00300 // key is pressed in a window, the given callback will 00301 // be called. The description is a one-line description 00302 // of the function of the key, for display to the user. 00303 //////////////////////////////////////////////////////////////////// 00304 void PandaFramework:: 00305 define_key(const string &event_name, const string &description, 00306 EventHandler::EventCallbackFunction *function, 00307 void *data) { 00308 if (_event_handler.has_hook(event_name)) { 00309 // If there is already a hook for the indicated keyname, we're 00310 // most likely replacing a previous definition of a key. Search 00311 // for the old definition and remove it. 00312 KeyDefinitions::iterator di; 00313 di = _key_definitions.begin(); 00314 while (di != _key_definitions.end() && (*di)._event_name != event_name) { 00315 ++di; 00316 } 00317 if (di != _key_definitions.end()) { 00318 _key_definitions.erase(di); 00319 } 00320 } 00321 00322 // Now add a new hook for the keyname, and also add the new 00323 // description. 00324 _event_handler.add_hook(event_name, function, data); 00325 00326 if (!description.empty()) { 00327 KeyDefinition keydef; 00328 keydef._event_name = event_name; 00329 keydef._description = description; 00330 _key_definitions.push_back(keydef); 00331 } 00332 } 00333 00334 //////////////////////////////////////////////////////////////////// 00335 // Function: PandaFramework::get_default_window_props 00336 // Access: Public, Virtual 00337 // Description: Fills in the indicated window properties structure 00338 // according to the normal window properties for this 00339 // application. 00340 //////////////////////////////////////////////////////////////////// 00341 void PandaFramework:: 00342 get_default_window_props(WindowProperties &props) { 00343 // This function is largely vestigial and will be removed soon. We 00344 // have moved the default window properties into 00345 // WindowProperties::get_default(). 00346 00347 props.add_properties(WindowProperties::get_default()); 00348 if (!_window_title.empty()) { 00349 props.set_title(_window_title); 00350 } 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: PandaFramework::open_window 00355 // Access: Public 00356 // Description: Opens a window on the default graphics pipe. If the 00357 // default graphics pipe can't open a window for some 00358 // reason, automatically fails over to the next 00359 // available graphics pipe, and updates _default_pipe 00360 // accordingly. Returns NULL only if all graphics pipes 00361 // fail. 00362 //////////////////////////////////////////////////////////////////// 00363 WindowFramework *PandaFramework:: 00364 open_window() { 00365 GraphicsPipe *pipe = get_default_pipe(); 00366 if (pipe == (GraphicsPipe *)NULL) { 00367 // Can't get a pipe. 00368 return NULL; 00369 } 00370 00371 WindowFramework *wf = open_window(pipe, NULL); 00372 if (wf == (WindowFramework *)NULL) { 00373 // Ok, the default graphics pipe failed; try a little harder. 00374 GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr(); 00375 selection->load_aux_modules(); 00376 00377 int num_pipe_types = selection->get_num_pipe_types(); 00378 for (int i = 0; i < num_pipe_types; i++) { 00379 TypeHandle pipe_type = selection->get_pipe_type(i); 00380 if (pipe_type != _default_pipe->get_type()) { 00381 PT(GraphicsPipe) new_pipe = selection->make_pipe(pipe_type); 00382 if (new_pipe != (GraphicsPipe *)NULL) { 00383 wf = open_window(new_pipe, NULL); 00384 if (wf != (WindowFramework *)NULL) { 00385 // Here's the winner! 00386 _default_pipe = new_pipe; 00387 return wf; 00388 } 00389 } 00390 } 00391 } 00392 00393 // Too bad; none of the pipes could open a window. Fall through 00394 // and return NULL. 00395 } 00396 00397 return wf; 00398 } 00399 00400 //////////////////////////////////////////////////////////////////// 00401 // Function: PandaFramework::open_window 00402 // Access: Public 00403 // Description: Opens a new window on the indicated pipe, using the 00404 // default parameters. Returns the new WindowFramework 00405 // if successful, or NULL if not. 00406 //////////////////////////////////////////////////////////////////// 00407 WindowFramework *PandaFramework:: 00408 open_window(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) { 00409 nassertr(_is_open, NULL); 00410 00411 WindowProperties props; 00412 get_default_window_props(props); 00413 00414 int flags = GraphicsPipe::BF_require_window; 00415 if (window_type == "offscreen") { 00416 flags = GraphicsPipe::BF_refuse_window; 00417 } 00418 00419 return open_window(props, flags, pipe, gsg); 00420 } 00421 00422 //////////////////////////////////////////////////////////////////// 00423 // Function: PandaFramework::open_window 00424 // Access: Public 00425 // Description: Opens a new window using the indicated properties. 00426 // (You may initialize the properties to their default 00427 // values by calling get_default_window_props() first.) 00428 // 00429 // Returns the new WindowFramework if successful, or 00430 // NULL if not. 00431 //////////////////////////////////////////////////////////////////// 00432 WindowFramework *PandaFramework:: 00433 open_window(const WindowProperties &props, int flags, 00434 GraphicsPipe *pipe, GraphicsStateGuardian *gsg) { 00435 if (pipe == (GraphicsPipe *)NULL) { 00436 pipe = get_default_pipe(); 00437 if (pipe == (GraphicsPipe *)NULL) { 00438 // Can't get a pipe. 00439 return NULL; 00440 } 00441 } 00442 00443 nassertr(_is_open, NULL); 00444 PT(WindowFramework) wf = make_window_framework(); 00445 wf->set_wireframe(get_wireframe()); 00446 wf->set_texture(get_texture()); 00447 wf->set_two_sided(get_two_sided()); 00448 wf->set_lighting(get_lighting()); 00449 wf->set_perpixel(get_perpixel()); 00450 wf->set_background_type(get_background_type()); 00451 00452 GraphicsOutput *win = wf->open_window(props, flags, get_graphics_engine(), 00453 pipe, gsg); 00454 _engine->open_windows(); 00455 if (win != (GraphicsOutput *)NULL && !win->is_valid()) { 00456 // The window won't open. 00457 _engine->remove_window(win); 00458 wf->close_window(); 00459 win = NULL; 00460 } 00461 00462 if (win == (GraphicsOutput *)NULL) { 00463 // Oops, couldn't make a window or buffer. 00464 framework_cat.error() 00465 << "Unable to create window.\n"; 00466 return NULL; 00467 } 00468 00469 _windows.push_back(wf); 00470 return wf; 00471 } 00472 00473 //////////////////////////////////////////////////////////////////// 00474 // Function: PandaFramework::find_window 00475 // Access: Public 00476 // Description: Returns the index of the first WindowFramework object 00477 // found that references the indicated GraphicsOutput 00478 // pointer, or -1 if none do. 00479 //////////////////////////////////////////////////////////////////// 00480 int PandaFramework:: 00481 find_window(const GraphicsOutput *win) const { 00482 int n; 00483 for (n = 0; n < (int)_windows.size(); n++) { 00484 if (_windows[n]->get_graphics_output() == win) { 00485 return n; 00486 } 00487 } 00488 00489 return -1; 00490 } 00491 00492 //////////////////////////////////////////////////////////////////// 00493 // Function: PandaFramework::find_window 00494 // Access: Public 00495 // Description: Returns the index of the given WindowFramework 00496 // object, or -1 if the object does not represent a 00497 // window opened with this PandaFramework. 00498 //////////////////////////////////////////////////////////////////// 00499 int PandaFramework:: 00500 find_window(const WindowFramework *wf) const { 00501 int n; 00502 for (n = 0; n < (int)_windows.size(); n++) { 00503 if (_windows[n] == wf) { 00504 return n; 00505 } 00506 } 00507 00508 return -1; 00509 } 00510 00511 00512 //////////////////////////////////////////////////////////////////// 00513 // Function: PandaFramework::close_window 00514 // Access: Public 00515 // Description: Closes the nth window and removes it from the list. 00516 //////////////////////////////////////////////////////////////////// 00517 void PandaFramework:: 00518 close_window(int n) { 00519 nassertv(n >= 0 && n < (int)_windows.size()); 00520 WindowFramework *wf = _windows[n]; 00521 00522 GraphicsOutput *win = wf->get_graphics_output(); 00523 if (win != (GraphicsOutput *)NULL) { 00524 _engine->remove_window(win); 00525 } 00526 00527 wf->close_window(); 00528 _windows.erase(_windows.begin() + n); 00529 } 00530 00531 //////////////////////////////////////////////////////////////////// 00532 // Function: PandaFramework::close_all_windows 00533 // Access: Public 00534 // Description: Closes all currently open windows and empties the 00535 // list of windows. 00536 //////////////////////////////////////////////////////////////////// 00537 void PandaFramework:: 00538 close_all_windows() { 00539 Windows::iterator wi; 00540 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00541 WindowFramework *wf = (*wi); 00542 00543 GraphicsOutput *win = wf->get_graphics_output(); 00544 if (win != (GraphicsOutput *)NULL) { 00545 _engine->remove_window(win); 00546 } 00547 00548 wf->close_window(); 00549 } 00550 00551 Mouses::iterator mi; 00552 for (mi = _mouses.begin(); mi != _mouses.end(); ++mi) { 00553 (*mi).second.remove_node(); 00554 } 00555 00556 _windows.clear(); 00557 _mouses.clear(); 00558 } 00559 00560 //////////////////////////////////////////////////////////////////// 00561 // Function: PandaFramework::all_windows_closed 00562 // Access: Public 00563 // Description: Returns true if all of the opened windows have been 00564 // closed by the user, false otherwise. 00565 //////////////////////////////////////////////////////////////////// 00566 bool PandaFramework:: 00567 all_windows_closed() const { 00568 Windows::const_iterator wi; 00569 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00570 WindowFramework *wf = (*wi); 00571 if (wf->get_graphics_output()->is_valid()) { 00572 return false; 00573 } 00574 } 00575 00576 return true; 00577 } 00578 00579 //////////////////////////////////////////////////////////////////// 00580 // Function: PandaFramework::get_models 00581 // Access: Public 00582 // Description: Returns the root of the scene graph normally reserved 00583 // for parenting models and such. This scene graph may 00584 // be instanced to each window's render tree as the 00585 // window is created. 00586 //////////////////////////////////////////////////////////////////// 00587 NodePath &PandaFramework:: 00588 get_models() { 00589 if (_models.is_empty()) { 00590 _models = NodePath("models"); 00591 } 00592 return _models; 00593 } 00594 00595 //////////////////////////////////////////////////////////////////// 00596 // Function: PandaFramework::report_frame_rate 00597 // Access: Public 00598 // Description: Reports the currently measured average frame rate to 00599 // the indicated ostream. 00600 //////////////////////////////////////////////////////////////////// 00601 void PandaFramework:: 00602 report_frame_rate(ostream &out) const { 00603 double now = ClockObject::get_global_clock()->get_frame_time(); 00604 double delta = now - _start_time; 00605 00606 int frame_count = ClockObject::get_global_clock()->get_frame_count(); 00607 int num_frames = frame_count - _frame_count; 00608 if (num_frames > 0) { 00609 out << num_frames << " frames in " << delta << " seconds.\n"; 00610 double fps = ((double)num_frames) / delta; 00611 out << fps << " fps average (" << 1000.0 / fps << "ms)\n"; 00612 } 00613 } 00614 00615 //////////////////////////////////////////////////////////////////// 00616 // Function: PandaFramework::reset_frame_rate 00617 // Access: Public 00618 // Description: Resets the frame rate computation. 00619 //////////////////////////////////////////////////////////////////// 00620 void PandaFramework:: 00621 reset_frame_rate() { 00622 _start_time = ClockObject::get_global_clock()->get_frame_time(); 00623 _frame_count = ClockObject::get_global_clock()->get_frame_count(); 00624 } 00625 00626 //////////////////////////////////////////////////////////////////// 00627 // Function: PandaFramework::set_wireframe 00628 // Access: Public 00629 // Description: Sets the wireframe state on all windows. 00630 //////////////////////////////////////////////////////////////////// 00631 void PandaFramework:: 00632 set_wireframe(bool enable) { 00633 Windows::iterator wi; 00634 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00635 WindowFramework *wf = (*wi); 00636 wf->set_wireframe(enable); 00637 } 00638 00639 _wireframe_enabled = enable; 00640 } 00641 00642 //////////////////////////////////////////////////////////////////// 00643 // Function: PandaFramework::set_texture 00644 // Access: Public 00645 // Description: Sets the texture state on all windows. 00646 //////////////////////////////////////////////////////////////////// 00647 void PandaFramework:: 00648 set_texture(bool enable) { 00649 Windows::iterator wi; 00650 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00651 WindowFramework *wf = (*wi); 00652 wf->set_texture(enable); 00653 } 00654 00655 _texture_enabled = enable; 00656 } 00657 00658 //////////////////////////////////////////////////////////////////// 00659 // Function: PandaFramework::set_two_sided 00660 // Access: Public 00661 // Description: Sets the two_sided state on all windows. 00662 //////////////////////////////////////////////////////////////////// 00663 void PandaFramework:: 00664 set_two_sided(bool enable) { 00665 Windows::iterator wi; 00666 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00667 WindowFramework *wf = (*wi); 00668 wf->set_two_sided(enable); 00669 } 00670 00671 _two_sided_enabled = enable; 00672 } 00673 00674 //////////////////////////////////////////////////////////////////// 00675 // Function: PandaFramework::set_lighting 00676 // Access: Public 00677 // Description: Sets the lighting state on all windows. 00678 //////////////////////////////////////////////////////////////////// 00679 void PandaFramework:: 00680 set_lighting(bool enable) { 00681 Windows::iterator wi; 00682 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00683 WindowFramework *wf = (*wi); 00684 wf->set_lighting(enable); 00685 } 00686 00687 _lighting_enabled = enable; 00688 } 00689 00690 //////////////////////////////////////////////////////////////////// 00691 // Function: PandaFramework::set_perpixel 00692 // Access: Public 00693 // Description: Sets the perpixel state on all windows. 00694 //////////////////////////////////////////////////////////////////// 00695 void PandaFramework:: 00696 set_perpixel(bool enable) { 00697 Windows::iterator wi; 00698 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00699 WindowFramework *wf = (*wi); 00700 wf->set_perpixel(enable); 00701 } 00702 00703 _perpixel_enabled = enable; 00704 } 00705 00706 //////////////////////////////////////////////////////////////////// 00707 // Function: BackgroundFramework::set_background_type 00708 // Access: Public 00709 // Description: Sets the background type of all windows. 00710 //////////////////////////////////////////////////////////////////// 00711 void PandaFramework:: 00712 set_background_type(WindowFramework::BackgroundType type) { 00713 Windows::iterator wi; 00714 for (wi = _windows.begin(); wi != _windows.end(); ++wi) { 00715 WindowFramework *wf = (*wi); 00716 wf->set_background_type(type); 00717 } 00718 00719 _background_type = type; 00720 } 00721 00722 //////////////////////////////////////////////////////////////////// 00723 // Function: PandaFramework::hide_collision_solids 00724 // Access: Public 00725 // Description: Hides any collision solids, or occluders, which are 00726 // visible in the indicated scene graph. Returns the 00727 // number of nodes hidden. 00728 //////////////////////////////////////////////////////////////////// 00729 int PandaFramework:: 00730 hide_collision_solids(NodePath node) { 00731 int num_changed = 0; 00732 00733 if (node.node()->is_of_type(CollisionNode::get_class_type()) || 00734 node.node()->is_of_type(OccluderNode::get_class_type())) { 00735 if (!node.is_hidden()) { 00736 node.hide(); 00737 num_changed++; 00738 } 00739 } 00740 00741 int num_children = node.get_num_children(); 00742 for (int i = 0; i < num_children; i++) { 00743 num_changed += hide_collision_solids(node.get_child(i)); 00744 } 00745 00746 return num_changed; 00747 } 00748 00749 //////////////////////////////////////////////////////////////////// 00750 // Function: PandaFramework::show_collision_solids 00751 // Access: Public 00752 // Description: Shows any collision solids, or occluders, which are 00753 // directly hidden in the indicated scene graph. 00754 // Returns the number of nodes shown. 00755 //////////////////////////////////////////////////////////////////// 00756 int PandaFramework:: 00757 show_collision_solids(NodePath node) { 00758 int num_changed = 0; 00759 00760 if (node.node()->is_of_type(CollisionNode::get_class_type()) || 00761 node.node()->is_of_type(OccluderNode::get_class_type())) { 00762 if (node.get_hidden_ancestor() == node) { 00763 node.show(); 00764 num_changed++; 00765 } 00766 } 00767 00768 int num_children = node.get_num_children(); 00769 for (int i = 0; i < num_children; i++) { 00770 num_changed += show_collision_solids(node.get_child(i)); 00771 } 00772 00773 return num_changed; 00774 } 00775 00776 //////////////////////////////////////////////////////////////////// 00777 // Function: PandaFramework::set_highlight 00778 // Access: Public 00779 // Description: Sets the indicated node (normally a node within the 00780 // get_models() tree) up as the highlighted node. 00781 // Certain operations affect the highlighted node only. 00782 //////////////////////////////////////////////////////////////////// 00783 void PandaFramework:: 00784 set_highlight(const NodePath &node) { 00785 clear_highlight(); 00786 _highlight = node; 00787 if (!_highlight.is_empty()) { 00788 framework_cat.info(false) << _highlight << "\n"; 00789 _highlight.show_bounds(); 00790 00791 // Also create a new instance of the highlighted geometry, as a 00792 // sibling of itself, under the special highlight property. 00793 if (_highlight.has_parent()) { 00794 _highlight_wireframe.reparent_to(_highlight.get_parent()); 00795 _highlight.instance_to(_highlight_wireframe); 00796 } 00797 } 00798 } 00799 00800 //////////////////////////////////////////////////////////////////// 00801 // Function: PandaFramework::clear_highlight 00802 // Access: Public 00803 // Description: Unhighlights the currently highlighted node, if any. 00804 //////////////////////////////////////////////////////////////////// 00805 void PandaFramework:: 00806 clear_highlight() { 00807 if (!_highlight.is_empty()) { 00808 _highlight.hide_bounds(); 00809 _highlight = NodePath(); 00810 00811 // Clean up the special highlight instance. 00812 _highlight_wireframe.detach_node(); 00813 _highlight_wireframe.get_children().detach(); 00814 } 00815 } 00816 00817 //////////////////////////////////////////////////////////////////// 00818 // Function: PandaFramework::enable_default_keys 00819 // Access: Public 00820 // Description: Sets callbacks on the event handler to handle all of 00821 // the normal viewer keys, like t to toggle texture, ESC 00822 // or q to quit, etc. 00823 //////////////////////////////////////////////////////////////////// 00824 void PandaFramework:: 00825 enable_default_keys() { 00826 if (!_default_keys_enabled) { 00827 do_enable_default_keys(); 00828 _default_keys_enabled = true; 00829 } 00830 } 00831 00832 //////////////////////////////////////////////////////////////////// 00833 // Function: PandaFramework::do_frame 00834 // Access: Public, Virtual 00835 // Description: Renders one frame and performs all associated 00836 // processing. Returns true if we should continue 00837 // rendering, false if we should exit. This is normally 00838 // called only from main_loop(). 00839 //////////////////////////////////////////////////////////////////// 00840 bool PandaFramework:: 00841 do_frame(Thread *current_thread) { 00842 nassertr(_is_open, false); 00843 00844 _task_mgr.poll(); 00845 00846 return !_exit_flag; 00847 } 00848 00849 //////////////////////////////////////////////////////////////////// 00850 // Function: PandaFramework::main_loop 00851 // Access: Public 00852 // Description: Called to yield control to the panda framework. This 00853 // function does not return until set_exit_flag() has 00854 // been called. 00855 //////////////////////////////////////////////////////////////////// 00856 void PandaFramework:: 00857 main_loop() { 00858 Thread *current_thread = Thread::get_current_thread(); 00859 while (do_frame(current_thread)) { 00860 } 00861 } 00862 00863 //////////////////////////////////////////////////////////////////// 00864 // Function: PandaFramework::make_window_framework 00865 // Access: Protected, Virtual 00866 // Description: Creates a new WindowFramework object. This is 00867 // provided as a hook so derived PandaFramework classes 00868 // can create custom WindowFramework objects. 00869 //////////////////////////////////////////////////////////////////// 00870 PT(WindowFramework) PandaFramework:: 00871 make_window_framework() { 00872 return new WindowFramework(this); 00873 } 00874 00875 //////////////////////////////////////////////////////////////////// 00876 // Function: PandaFramework::make_default_pipe 00877 // Access: Protected, Virtual 00878 // Description: Creates the default GraphicsPipe that will contain 00879 // all windows that are not opened on a specific pipe. 00880 //////////////////////////////////////////////////////////////////// 00881 void PandaFramework:: 00882 make_default_pipe() { 00883 // This depends on the shared library or libraries (DLL's to you 00884 // Windows folks) that have been loaded in at runtime from the 00885 // load-display and/or aux-display Configrc variables. 00886 GraphicsPipeSelection *selection = GraphicsPipeSelection::get_global_ptr(); 00887 selection->print_pipe_types(); 00888 _default_pipe = selection->make_default_pipe(); 00889 00890 if (_default_pipe == (GraphicsPipe*)NULL) { 00891 nout << "No graphics pipe is available!\n" 00892 << "Your Config.prc file must name at least one valid panda display\n" 00893 << "library via load-display or aux-display.\n"; 00894 } 00895 } 00896 00897 //////////////////////////////////////////////////////////////////// 00898 // Function: PandaFramework::do_enable_default_keys 00899 // Access: Protected, Virtual 00900 // Description: The implementation of enable_default_keys(). 00901 //////////////////////////////////////////////////////////////////// 00902 void PandaFramework:: 00903 do_enable_default_keys() { 00904 define_key("escape", "close window", event_esc, this); 00905 define_key("q", "close window", event_esc, this); 00906 define_key("f", "report frame rate", event_f, this); 00907 define_key("w", "toggle wireframe mode", event_w, this); 00908 define_key("t", "toggle texturing", event_t, this); 00909 define_key("b", "toggle backface (double-sided) rendering", event_b, this); 00910 define_key("i", "invert (reverse) single-sided faces", event_i, this); 00911 define_key("l", "toggle lighting", event_l, this); 00912 define_key("p", "toggle per-pixel lighting", event_p, this); 00913 define_key("c", "recenter view on object", event_c, this); 00914 define_key("a", "toggle animation controls", event_a, this); 00915 define_key("shift-c", "toggle collision surfaces", event_C, this); 00916 define_key("shift-b", "report bounding volume", event_B, this); 00917 define_key("shift-l", "list hierarchy", event_L, this); 00918 define_key("shift-a", "analyze hierarchy", event_A, this); 00919 define_key("h", "highlight node", event_h, this); 00920 define_key("arrow_up", "move highlight to parent", event_arrow_up, this); 00921 define_key("arrow_down", "move highlight to child", event_arrow_down, this); 00922 define_key("arrow_left", "move highlight to sibling", event_arrow_left, this); 00923 define_key("arrow_right", "move highlight to sibling", event_arrow_right, this); 00924 define_key("shift-s", "activate PStats", event_S, this); 00925 define_key("f9", "Take screenshot", event_f9, this); 00926 define_key(",", "change background color", event_comma, this); 00927 define_key("?", "", event_question, this); 00928 define_key("shift-/", "", event_question, this); 00929 } 00930 00931 //////////////////////////////////////////////////////////////////// 00932 // Function: PandaFramework::clear_text 00933 // Access: Protected 00934 // Description: Removes any onscreen text (like help text or 00935 // screenshot filename). Returns true if there was any 00936 // text in the first place, false otherwise. 00937 //////////////////////////////////////////////////////////////////// 00938 bool PandaFramework:: 00939 clear_text() { 00940 bool any_text = false; 00941 if (!_screenshot_text.is_empty()) { 00942 _screenshot_text.remove_node(); 00943 any_text = true; 00944 } 00945 00946 if (!_help_text.is_empty()) { 00947 _help_text.remove_node(); 00948 any_text = true; 00949 } 00950 00951 return any_text; 00952 } 00953 00954 //////////////////////////////////////////////////////////////////// 00955 // Function: PandaFramework::event_esc 00956 // Access: Public, Static 00957 // Description: Default handler for ESC or q key: close the current 00958 // window (and exit the application if that was the last 00959 // window). 00960 //////////////////////////////////////////////////////////////////// 00961 void PandaFramework:: 00962 event_esc(const Event *event, void *data) { 00963 if (event->get_num_parameters() == 1) { 00964 EventParameter param = event->get_parameter(0); 00965 WindowFramework *wf; 00966 DCAST_INTO_V(wf, param.get_ptr()); 00967 00968 PT(GraphicsOutput) win = wf->get_graphics_output(); 00969 00970 PandaFramework *self = (PandaFramework *)data; 00971 self->close_window(wf); 00972 00973 // Also close any other WindowFrameworks on the same window. 00974 int window_index = self->find_window(win); 00975 while (window_index != -1) { 00976 self->close_window(window_index); 00977 window_index = self->find_window(win); 00978 } 00979 00980 // Free up the mouse for that window. 00981 self->remove_mouse(win); 00982 00983 // Make sure the close request propagates through the system. 00984 self->_engine->open_windows(); 00985 00986 // If we closed the last window, shut down. 00987 if (self->all_windows_closed()) { 00988 self->_exit_flag = true; 00989 } 00990 } 00991 } 00992 00993 //////////////////////////////////////////////////////////////////// 00994 // Function: PandaFramework::event_f 00995 // Access: Public, Static 00996 // Description: Default handler for f key: report and reset frame 00997 // rate. 00998 //////////////////////////////////////////////////////////////////// 00999 void PandaFramework:: 01000 event_f(const Event *, void *data) { 01001 PandaFramework *self = (PandaFramework *)data; 01002 self->report_frame_rate(nout); 01003 self->reset_frame_rate(); 01004 } 01005 01006 //////////////////////////////////////////////////////////////////// 01007 // Function: PandaFramework::event_w 01008 // Access: Public, Static 01009 // Description: Default handler for w key: toggle wireframe. 01010 //////////////////////////////////////////////////////////////////// 01011 void PandaFramework:: 01012 event_w(const Event *event, void *) { 01013 if (event->get_num_parameters() == 1) { 01014 EventParameter param = event->get_parameter(0); 01015 WindowFramework *wf; 01016 DCAST_INTO_V(wf, param.get_ptr()); 01017 01018 wf->set_wireframe(!wf->get_wireframe()); 01019 } 01020 } 01021 01022 //////////////////////////////////////////////////////////////////// 01023 // Function: PandaFramework::event_t 01024 // Access: Public, Static 01025 // Description: Default handler for t key: toggle texture. 01026 //////////////////////////////////////////////////////////////////// 01027 void PandaFramework:: 01028 event_t(const Event *event, void *) { 01029 if (event->get_num_parameters() == 1) { 01030 EventParameter param = event->get_parameter(0); 01031 WindowFramework *wf; 01032 DCAST_INTO_V(wf, param.get_ptr()); 01033 01034 wf->set_texture(!wf->get_texture()); 01035 } 01036 } 01037 01038 //////////////////////////////////////////////////////////////////// 01039 // Function: PandaFramework::event_b 01040 // Access: Public, Static 01041 // Description: Default handler for b key: toggle backface (two-sided 01042 // rendering). 01043 //////////////////////////////////////////////////////////////////// 01044 void PandaFramework:: 01045 event_b(const Event *event, void *) { 01046 if (event->get_num_parameters() == 1) { 01047 EventParameter param = event->get_parameter(0); 01048 WindowFramework *wf; 01049 DCAST_INTO_V(wf, param.get_ptr()); 01050 01051 wf->set_two_sided(!wf->get_two_sided()); 01052 } 01053 } 01054 01055 //////////////////////////////////////////////////////////////////// 01056 // Function: PandaFramework::event_i 01057 // Access: Public, Static 01058 // Description: Default handler for i key: invert one-sided faces. 01059 //////////////////////////////////////////////////////////////////// 01060 void PandaFramework:: 01061 event_i(const Event *event, void *) { 01062 if (event->get_num_parameters() == 1) { 01063 EventParameter param = event->get_parameter(0); 01064 WindowFramework *wf; 01065 DCAST_INTO_V(wf, param.get_ptr()); 01066 01067 wf->set_one_sided_reverse(!wf->get_one_sided_reverse()); 01068 } 01069 } 01070 01071 //////////////////////////////////////////////////////////////////// 01072 // Function: PandaFramework::event_l 01073 // Access: Public, Static 01074 // Description: Default handler for l key: toggle lighting. 01075 //////////////////////////////////////////////////////////////////// 01076 void PandaFramework:: 01077 event_l(const Event *event, void *) { 01078 if (event->get_num_parameters() == 1) { 01079 EventParameter param = event->get_parameter(0); 01080 WindowFramework *wf; 01081 DCAST_INTO_V(wf, param.get_ptr()); 01082 01083 wf->set_lighting(!wf->get_lighting()); 01084 } 01085 } 01086 01087 //////////////////////////////////////////////////////////////////// 01088 // Function: PandaFramework::event_p 01089 // Access: Public, Static 01090 // Description: Default handler for p key: toggle per-pixel lighting. 01091 //////////////////////////////////////////////////////////////////// 01092 void PandaFramework:: 01093 event_p(const Event *event, void *) { 01094 if (event->get_num_parameters() == 1) { 01095 EventParameter param = event->get_parameter(0); 01096 WindowFramework *wf; 01097 DCAST_INTO_V(wf, param.get_ptr()); 01098 01099 wf->set_perpixel(!wf->get_perpixel()); 01100 } 01101 } 01102 01103 //////////////////////////////////////////////////////////////////// 01104 // Function: PandaFramework::event_c 01105 // Access: Public, Static 01106 // Description: Default handler for c key: center the trackball over 01107 // the scene, or over the highlighted part of the scene. 01108 //////////////////////////////////////////////////////////////////// 01109 void PandaFramework:: 01110 event_c(const Event *event, void *data) { 01111 if (event->get_num_parameters() == 1) { 01112 EventParameter param = event->get_parameter(0); 01113 WindowFramework *wf; 01114 DCAST_INTO_V(wf, param.get_ptr()); 01115 01116 PandaFramework *self = (PandaFramework *)data; 01117 01118 NodePath node = self->get_highlight(); 01119 if (node.is_empty()) { 01120 node = self->get_models(); 01121 } 01122 wf->center_trackball(node); 01123 } 01124 } 01125 01126 //////////////////////////////////////////////////////////////////// 01127 // Function: PandaFramework::event_a 01128 // Access: Public, Static 01129 // Description: Default handler for a key: toggle the animation 01130 // controls. 01131 //////////////////////////////////////////////////////////////////// 01132 void PandaFramework:: 01133 event_a(const Event *event, void *data) { 01134 if (event->get_num_parameters() == 1) { 01135 EventParameter param = event->get_parameter(0); 01136 WindowFramework *wf; 01137 DCAST_INTO_V(wf, param.get_ptr()); 01138 01139 wf->next_anim_control(); 01140 } 01141 } 01142 01143 //////////////////////////////////////////////////////////////////// 01144 // Function: PandaFramework::event_C 01145 // Access: Public, Static 01146 // Description: Default handler for shift-C key: toggle the showing 01147 // of collision solids. 01148 //////////////////////////////////////////////////////////////////// 01149 void PandaFramework:: 01150 event_C(const Event *, void *data) { 01151 PandaFramework *self = (PandaFramework *)data; 01152 01153 NodePath node = self->get_highlight(); 01154 if (node.is_empty()) { 01155 node = self->get_models(); 01156 } 01157 01158 if (self->hide_collision_solids(node) == 0) { 01159 self->show_collision_solids(node); 01160 } 01161 } 01162 01163 //////////////////////////////////////////////////////////////////// 01164 // Function: PandaFramework::event_B 01165 // Access: Public, Static 01166 // Description: Default handler for shift-B key: describe the 01167 // bounding volume of the currently selected object, or 01168 // the entire scene. 01169 //////////////////////////////////////////////////////////////////// 01170 void PandaFramework:: 01171 event_B(const Event *, void *data) { 01172 PandaFramework *self = (PandaFramework *)data; 01173 01174 NodePath node = self->get_highlight(); 01175 if (node.is_empty()) { 01176 node = self->get_models(); 01177 } 01178 01179 node.get_bounds()->write(nout); 01180 } 01181 01182 //////////////////////////////////////////////////////////////////// 01183 // Function: PandaFramework::event_L 01184 // Access: Public, Static 01185 // Description: Default handler for shift-L key: list the contents of 01186 // the scene graph, or the highlighted node. 01187 //////////////////////////////////////////////////////////////////// 01188 void PandaFramework:: 01189 event_L(const Event *, void *data) { 01190 PandaFramework *self = (PandaFramework *)data; 01191 01192 NodePath node = self->get_highlight(); 01193 if (node.is_empty()) { 01194 node = self->get_models(); 01195 } 01196 01197 node.ls(); 01198 } 01199 01200 //////////////////////////////////////////////////////////////////// 01201 // Function: PandaFramework::event_A 01202 // Access: Public, Static 01203 // Description: Default handler for shift-A key: analyze the contents 01204 // of the scene graph, or the highlighted node. 01205 //////////////////////////////////////////////////////////////////// 01206 void PandaFramework:: 01207 event_A(const Event *, void *data) { 01208 PandaFramework *self = (PandaFramework *)data; 01209 01210 NodePath node = self->get_highlight(); 01211 if (node.is_empty()) { 01212 node = self->get_models(); 01213 } 01214 01215 SceneGraphAnalyzer sga; 01216 sga.add_node(node.node()); 01217 sga.write(nout); 01218 } 01219 01220 //////////////////////////////////////////////////////////////////// 01221 // Function: PandaFramework::event_h 01222 // Access: Public, Static 01223 // Description: Default handler for h key: toggle highlight mode. In 01224 // this mode, you can walk the scene graph with the 01225 // arrow keys to highlight different nodes. 01226 //////////////////////////////////////////////////////////////////// 01227 void PandaFramework:: 01228 event_h(const Event *, void *data) { 01229 PandaFramework *self = (PandaFramework *)data; 01230 01231 if (self->has_highlight()) { 01232 self->clear_highlight(); 01233 } else { 01234 self->set_highlight(self->get_models()); 01235 } 01236 } 01237 01238 //////////////////////////////////////////////////////////////////// 01239 // Function: PandaFramework::event_arrow_up 01240 // Access: Public, Static 01241 // Description: Default handler for up arrow key: in highlight mode, 01242 // move the highlight to the node's parent. 01243 //////////////////////////////////////////////////////////////////// 01244 void PandaFramework:: 01245 event_arrow_up(const Event *, void *data) { 01246 PandaFramework *self = (PandaFramework *)data; 01247 01248 if (self->has_highlight()) { 01249 NodePath node = self->get_highlight(); 01250 if (node.has_parent() && node != self->get_models()) { 01251 self->set_highlight(node.get_parent()); 01252 } 01253 } 01254 } 01255 01256 //////////////////////////////////////////////////////////////////// 01257 // Function: PandaFramework::event_arrow_down 01258 // Access: Public, Static 01259 // Description: Default handler for up arrow key: in highlight mode, 01260 // move the highlight to the node's first child. 01261 //////////////////////////////////////////////////////////////////// 01262 void PandaFramework:: 01263 event_arrow_down(const Event *, void *data) { 01264 PandaFramework *self = (PandaFramework *)data; 01265 01266 if (self->has_highlight()) { 01267 NodePath node = self->get_highlight(); 01268 if (node.get_num_children() > 0) { 01269 self->set_highlight(node.get_child(0)); 01270 } 01271 } 01272 } 01273 01274 //////////////////////////////////////////////////////////////////// 01275 // Function: PandaFramework::event_arrow_left 01276 // Access: Public, Static 01277 // Description: Default handler for up arrow key: in highlight mode, 01278 // move the highlight to the node's nearest sibling on 01279 // the left. 01280 //////////////////////////////////////////////////////////////////// 01281 void PandaFramework:: 01282 event_arrow_left(const Event *, void *data) { 01283 PandaFramework *self = (PandaFramework *)data; 01284 01285 if (self->has_highlight()) { 01286 NodePath node = self->get_highlight(); 01287 NodePath parent = node.get_parent(); 01288 if (node.has_parent() && node != self->get_models()) { 01289 int index = parent.node()->find_child(node.node()); 01290 nassertv(index >= 0); 01291 int sibling = index - 1; 01292 01293 if (sibling >= 0 && 01294 parent.node()->get_child(sibling) == self->_highlight_wireframe.node()) { 01295 // Skip over the special highlight node. 01296 sibling--; 01297 } 01298 01299 if (sibling >= 0) { 01300 self->set_highlight(NodePath(parent, parent.node()->get_child(sibling))); 01301 } 01302 } 01303 } 01304 } 01305 01306 //////////////////////////////////////////////////////////////////// 01307 // Function: PandaFramework::event_arrow_right 01308 // Access: Public, Static 01309 // Description: Default handler for up arrow key: in highlight mode, 01310 // move the highlight to the node's nearest sibling on 01311 // the right. 01312 //////////////////////////////////////////////////////////////////// 01313 void PandaFramework:: 01314 event_arrow_right(const Event *, void *data) { 01315 PandaFramework *self = (PandaFramework *)data; 01316 01317 if (self->has_highlight()) { 01318 NodePath node = self->get_highlight(); 01319 NodePath parent = node.get_parent(); 01320 if (node.has_parent() && node != self->get_models()) { 01321 int index = parent.node()->find_child(node.node()); 01322 nassertv(index >= 0); 01323 int num_children = parent.node()->get_num_children(); 01324 int sibling = index + 1; 01325 01326 if (sibling < num_children && 01327 parent.node()->get_child(sibling) == self->_highlight_wireframe.node()) { 01328 // Skip over the special highlight node. 01329 sibling++; 01330 } 01331 01332 if (sibling < num_children) { 01333 self->set_highlight(NodePath(parent, parent.node()->get_child(sibling))); 01334 } 01335 } 01336 } 01337 } 01338 01339 //////////////////////////////////////////////////////////////////// 01340 // Function: PandaFramework::event_S 01341 // Access: Public, Static 01342 // Description: Default handler for shift-S key: activate stats. 01343 //////////////////////////////////////////////////////////////////// 01344 void PandaFramework:: 01345 event_S(const Event *, void *) { 01346 #ifdef DO_PSTATS 01347 nout << "Connecting to stats host" << endl; 01348 PStatClient::connect(); 01349 #else 01350 nout << "Stats host not supported." << endl; 01351 #endif 01352 } 01353 01354 //////////////////////////////////////////////////////////////////// 01355 // Function: PandaFramework::event_f9 01356 // Access: Public, Static 01357 // Description: Default handler for f9 key: take screenshot. 01358 //////////////////////////////////////////////////////////////////// 01359 void PandaFramework:: 01360 event_f9(const Event *event, void *data) { 01361 PandaFramework *self = (PandaFramework *)data; 01362 01363 if (event->get_num_parameters() == 1) { 01364 EventParameter param = event->get_parameter(0); 01365 WindowFramework *wf; 01366 DCAST_INTO_V(wf, param.get_ptr()); 01367 01368 if (self->clear_text()) { 01369 // Render one more frame to remove the text. 01370 self->_engine->render_frame(); 01371 } 01372 01373 Filename filename = wf->get_graphics_output()->save_screenshot_default(); 01374 string text; 01375 if (filename.empty()) { 01376 text = "Screenshot failed"; 01377 } else { 01378 text = filename; 01379 } 01380 01381 // Adds the full path to the output string 01382 string output_text = (string)ExecutionEnvironment::get_cwd() + "/" + (string)text; 01383 01384 TextNode *text_node = new TextNode("screenshot"); 01385 self->_screenshot_text = NodePath(text_node); 01386 text_node->set_align(TextNode::A_center); 01387 text_node->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f); 01388 text_node->set_shadow(0.04, 0.04); 01389 text_node->set_text(output_text); 01390 self->_screenshot_text.set_scale(0.06); 01391 self->_screenshot_text.set_pos(0.0, 0.0, -0.7); 01392 self->_screenshot_text.reparent_to(wf->get_aspect_2d()); 01393 cout << "Screenshot saved: " + output_text + "\n"; 01394 01395 // Set a do-later to remove the text in 3 seconds. 01396 self->_task_mgr.remove(self->_task_mgr.find_tasks("clear_text")); 01397 PT(GenericAsyncTask) task = new GenericAsyncTask("clear_text", task_clear_text, self); 01398 task->set_delay(3.0); 01399 self->_task_mgr.add(task); 01400 } 01401 } 01402 01403 //////////////////////////////////////////////////////////////////// 01404 // Function: PandaFramework::event_comma 01405 // Access: Public, Static 01406 // Description: Default handler for comma key: rotate background color. 01407 //////////////////////////////////////////////////////////////////// 01408 void PandaFramework:: 01409 event_comma(const Event *event, void *) { 01410 if (event->get_num_parameters() == 1) { 01411 EventParameter param = event->get_parameter(0); 01412 WindowFramework *wf; 01413 DCAST_INTO_V(wf, param.get_ptr()); 01414 01415 switch (wf->get_background_type()) { 01416 case WindowFramework::BT_other: 01417 case WindowFramework::BT_none: 01418 break; 01419 01420 case WindowFramework::BT_white: 01421 wf->set_background_type(WindowFramework::BT_default); 01422 break; 01423 01424 default: 01425 wf->set_background_type((WindowFramework::BackgroundType)(wf->get_background_type() + 1)); 01426 } 01427 } 01428 } 01429 01430 //////////////////////////////////////////////////////////////////// 01431 // Function: PandaFramework::event_question 01432 // Access: Public, Static 01433 // Description: Default handler for ? key: show the available keys. 01434 //////////////////////////////////////////////////////////////////// 01435 void PandaFramework:: 01436 event_question(const Event *event, void *data) { 01437 PandaFramework *self = (PandaFramework *)data; 01438 if (event->get_num_parameters() == 1) { 01439 EventParameter param = event->get_parameter(0); 01440 WindowFramework *wf; 01441 DCAST_INTO_V(wf, param.get_ptr()); 01442 01443 self->_screenshot_text.remove_node(); 01444 01445 if (!self->_help_text.is_empty()) { 01446 self->_help_text.remove_node(); 01447 // This key is a toggle; remove the help text and do nothing else. 01448 01449 } else { 01450 // Build up a string to display. 01451 ostringstream help; 01452 KeyDefinitions::const_iterator ki; 01453 for (ki = self->_key_definitions.begin(); 01454 ki != self->_key_definitions.end(); 01455 ++ki) { 01456 const KeyDefinition &keydef = (*ki); 01457 help << keydef._event_name << "\t" << keydef._description << "\n"; 01458 } 01459 01460 string help_text = help.str(); 01461 01462 TextNode *text_node = new TextNode("help"); 01463 self->_help_text = NodePath(text_node); 01464 text_node->set_align(TextNode::A_left); 01465 text_node->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f); 01466 text_node->set_shadow(0.04, 0.04); 01467 text_node->set_text(help_text); 01468 01469 LVecBase4 frame = text_node->get_frame_actual(); 01470 01471 PN_stdfloat height = frame[3] - frame[2]; 01472 PN_stdfloat scale = min(0.06, 1.8 / height); 01473 self->_help_text.set_scale(scale); 01474 01475 PN_stdfloat pos_scale = scale / -2.0; 01476 self->_help_text.set_pos((frame[0] + frame[1]) * pos_scale, 01477 0.0, 01478 (frame[2] + frame[3]) * pos_scale); 01479 01480 self->_help_text.reparent_to(wf->get_aspect_2d()); 01481 } 01482 } 01483 } 01484 01485 //////////////////////////////////////////////////////////////////// 01486 // Function: PandaFramework::event_window_event 01487 // Access: Public, Static 01488 // Description: Default handler for window events: window resized or 01489 // closed, etc. 01490 //////////////////////////////////////////////////////////////////// 01491 void PandaFramework:: 01492 event_window_event(const Event *event, void *data) { 01493 PandaFramework *self = (PandaFramework *)data; 01494 if (event->get_num_parameters() == 1) { 01495 // The parameter of the window event is the window itself, rather 01496 // than the window framework object (which is the parameter of all 01497 // of the keyboard events). 01498 EventParameter param = event->get_parameter(0); 01499 const GraphicsOutput *win; 01500 DCAST_INTO_V(win, param.get_ptr()); 01501 01502 // Is this a window we've heard about? 01503 int window_index = self->find_window(win); 01504 if (window_index == -1) { 01505 framework_cat.debug() 01506 << "Ignoring message from unknown window.\n"; 01507 01508 } else { 01509 if (!win->is_valid()) { 01510 // The window has been closed. 01511 int window_index = self->find_window(win); 01512 while (window_index != -1) { 01513 self->close_window(window_index); 01514 window_index = self->find_window(win); 01515 } 01516 01517 // Free up the mouse for that window. 01518 self->remove_mouse(win); 01519 01520 // If the last window was closed, exit the application. 01521 if (self->all_windows_closed() && !self->_exit_flag) { 01522 framework_cat.info() 01523 << "Last window was closed by user.\n"; 01524 self->_exit_flag = true; 01525 } 01526 } else { 01527 // Adjust aspect ratio. 01528 for (int n = 0; n < (int)self->_windows.size(); n++) { 01529 if (self->_windows[n]->get_graphics_output() == win) { 01530 self->_windows[n]->adjust_dimensions(); 01531 } 01532 } 01533 } 01534 } 01535 } 01536 } 01537 01538 //////////////////////////////////////////////////////////////////// 01539 // Function: PandaFramework::task_data_loop 01540 // Access: Public, Static 01541 // Description: Called once per frame to process the data graph (which 01542 // handles user input via the mouse and keyboard, etc.) 01543 //////////////////////////////////////////////////////////////////// 01544 AsyncTask::DoneStatus PandaFramework:: 01545 task_data_loop(GenericAsyncTask *task, void *data) { 01546 PandaFramework *self = (PandaFramework *)data; 01547 01548 DataGraphTraverser dg_trav; 01549 dg_trav.traverse(self->_data_root.node()); 01550 01551 return AsyncTask::DS_cont; 01552 } 01553 01554 //////////////////////////////////////////////////////////////////// 01555 // Function: PandaFramework::task_event 01556 // Access: Public, Static 01557 // Description: Called once per frame to process the pending events. 01558 //////////////////////////////////////////////////////////////////// 01559 AsyncTask::DoneStatus PandaFramework:: 01560 task_event(GenericAsyncTask *task, void *data) { 01561 PandaFramework *self = (PandaFramework *)data; 01562 01563 throw_event("NewFrame"); 01564 self->_event_handler.process_events(); 01565 01566 return AsyncTask::DS_cont; 01567 } 01568 01569 //////////////////////////////////////////////////////////////////// 01570 // Function: PandaFramework::task_igloop 01571 // Access: Public, Static 01572 // Description: Called once per frame to render the scene. 01573 //////////////////////////////////////////////////////////////////// 01574 AsyncTask::DoneStatus PandaFramework:: 01575 task_igloop(GenericAsyncTask *task, void *data) { 01576 PandaFramework *self = (PandaFramework *)data; 01577 01578 if (self->_engine != (GraphicsEngine *)NULL) { 01579 self->_engine->render_frame(); 01580 } 01581 01582 return AsyncTask::DS_cont; 01583 } 01584 01585 //////////////////////////////////////////////////////////////////// 01586 // Function: PandaFramework::task_record_frame 01587 // Access: Public, Static 01588 // Description: Called once per frame to ask the recorder to record 01589 // the user input data, if enabled. 01590 //////////////////////////////////////////////////////////////////// 01591 AsyncTask::DoneStatus PandaFramework:: 01592 task_record_frame(GenericAsyncTask *task, void *data) { 01593 PandaFramework *self = (PandaFramework *)data; 01594 01595 if (self->_recorder != (RecorderController *)NULL) { 01596 self->_recorder->record_frame(); 01597 } 01598 01599 return AsyncTask::DS_cont; 01600 } 01601 01602 //////////////////////////////////////////////////////////////////// 01603 // Function: PandaFramework::task_play_frame 01604 // Access: Public, Static 01605 // Description: Called once per frame to ask the recorder to play back 01606 // the user input data, if enabled. 01607 //////////////////////////////////////////////////////////////////// 01608 AsyncTask::DoneStatus PandaFramework:: 01609 task_play_frame(GenericAsyncTask *task, void *data) { 01610 PandaFramework *self = (PandaFramework *)data; 01611 01612 if (self->_recorder != (RecorderController *)NULL) { 01613 self->_recorder->play_frame(); 01614 } 01615 01616 return AsyncTask::DS_cont; 01617 } 01618 01619 //////////////////////////////////////////////////////////////////// 01620 // Function: PandaFramework::task_clear_text 01621 // Access: Public, Static 01622 // Description: Called once to remove the screenshot text from onscreen. 01623 //////////////////////////////////////////////////////////////////// 01624 AsyncTask::DoneStatus PandaFramework:: 01625 task_clear_text(GenericAsyncTask *task, void *data) { 01626 PandaFramework *self = (PandaFramework *)data; 01627 01628 self->clear_text(); 01629 return AsyncTask::DS_cont; 01630 } 01631 01632 //////////////////////////////////////////////////////////////////// 01633 // Function: PandaFramework::task_garbage_collect 01634 // Access: Public, Static 01635 // Description: This task is created automatically if 01636 // garbage_collect_states is true. It calls the needed 01637 // TransformState::garbage_collect() and 01638 // RenderState::garbage_collect() methods each frame. 01639 //////////////////////////////////////////////////////////////////// 01640 AsyncTask::DoneStatus PandaFramework:: 01641 task_garbage_collect(GenericAsyncTask *task, void *data) { 01642 TransformState::garbage_collect(); 01643 RenderState::garbage_collect(); 01644 return AsyncTask::DS_cont; 01645 }