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