Panda3D

pandaFramework.cxx

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 }
 All Classes Functions Variables Enumerations