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