Panda3D

pview.cxx

00001 // Filename: pview.cxx
00002 // Created by:  drose (25Feb02)
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 "pandaSystem.h"
00017 #include "textNode.h"
00018 #include "configVariableBool.h"
00019 #include "texturePool.h"
00020 #include "multitexReducer.h"
00021 #include "sceneGraphReducer.h"
00022 #include "partGroup.h"
00023 #include "cardMaker.h"
00024 #include "bamCache.h"
00025 #include "virtualFileSystem.h"
00026 #include "panda_getopt.h"
00027 #include "preprocess_argv.h"
00028 
00029 // By including checkPandaVersion.h, we guarantee that runtime
00030 // attempts to run pview will fail if it inadvertently links with the
00031 // wrong version of libdtool.so/.dll.
00032 
00033 #include "checkPandaVersion.h"
00034 
00035 PandaFramework framework;
00036 
00037 ConfigVariableBool pview_test_hack
00038 ("pview-test-hack", false,
00039  "Enable the '0' key in pview to run whatever hacky test happens to be in "
00040  "there right now.");
00041 
00042 bool
00043 output_screenshot(Filename &fn)
00044 {
00045   Thread *current_thread = Thread::get_current_thread();
00046 
00047   // Only one frame crashes.
00048   framework.do_frame(current_thread);
00049   framework.do_frame(current_thread);
00050 
00051   WindowFramework *wf = framework.get_window(0);
00052   bool ok = wf->get_graphics_output()->save_screenshot(fn, "from pview");
00053   if (!ok) {
00054     cerr << "Could not generate screenshot " << fn << "\n";
00055   }
00056   return ok;
00057 }
00058 
00059 void
00060 event_W(const Event *, void *) {
00061   // shift-W: open a new window on the same scene.
00062 
00063   // If we already have a window, use the same GSG.
00064   GraphicsPipe *pipe = (GraphicsPipe *)NULL;
00065   GraphicsStateGuardian *gsg = (GraphicsStateGuardian *)NULL;
00066 
00067   if (framework.get_num_windows() > 0) {
00068     WindowFramework *old_window = framework.get_window(0);
00069     GraphicsOutput *win = old_window->get_graphics_output();
00070     pipe = win->get_pipe();
00071     //    gsg = win->get_gsg();
00072   }
00073 
00074   WindowFramework *window = framework.open_window(pipe, gsg);
00075   if (window != (WindowFramework *)NULL) {
00076     window->enable_keyboard();
00077     window->setup_trackball();
00078     framework.get_models().instance_to(window->get_render());
00079   }
00080 }
00081 
00082 void
00083 event_F(const Event *, void *) {
00084   // shift-F: flatten the model hierarchy.
00085   framework.get_models().flatten_strong();
00086 }
00087 
00088 void
00089 event_Enter(const Event *, void *) {
00090   // alt-enter: toggle between window/fullscreen in the same scene.
00091 
00092   // If we already have a window, use the same GSG.
00093   GraphicsPipe *pipe = (GraphicsPipe *)NULL;
00094   GraphicsStateGuardian *gsg = (GraphicsStateGuardian *)NULL;
00095 
00096   WindowProperties props;
00097 
00098   for (int i = 0; i < framework.get_num_windows(); ++i) {
00099     WindowFramework *old_window = framework.get_window(i);
00100     GraphicsWindow *win = old_window->get_graphics_window();
00101     if (win != (GraphicsWindow *)NULL) {
00102       pipe = win->get_pipe();
00103       gsg = win->get_gsg();
00104       props = win->get_properties();
00105       framework.close_window(old_window);
00106       break;
00107     }
00108   }
00109 
00110   // set the toggle
00111   props.set_fullscreen(!props.get_fullscreen());
00112   int flags = GraphicsPipe::BF_require_window;
00113   
00114   WindowFramework *window = framework.open_window(props, flags, pipe, gsg);
00115   if (window != (WindowFramework *)NULL) {
00116     window->enable_keyboard();
00117     window->setup_trackball();
00118     framework.get_models().instance_to(window->get_render());
00119   }
00120 }
00121 
00122 void
00123 event_2(const Event *event, void *) {
00124   // 2: split the window into two display regions.
00125 
00126   EventParameter param = event->get_parameter(0);
00127   WindowFramework *wf;
00128   DCAST_INTO_V(wf, param.get_ptr());
00129 
00130   WindowFramework *split = wf->split_window();
00131   if (split != (WindowFramework *)NULL) {
00132     split->enable_keyboard();
00133     split->setup_trackball();
00134     framework.get_models().instance_to(split->get_render());
00135   }
00136 }
00137 
00138 void
00139 event_0(const Event *event, void *) {
00140   // 0: run hacky test.
00141   EventParameter param = event->get_parameter(0);
00142   WindowFramework *wf;
00143   DCAST_INTO_V(wf, param.get_ptr());
00144 
00145   // Create a new offscreen buffer.
00146   GraphicsOutput *win = wf->get_graphics_output();
00147   PT(GraphicsOutput) buffer = win->make_texture_buffer("tex", 256, 256);
00148   cerr << buffer->get_type() << "\n";
00149 
00150   // Set the offscreen buffer to render the same scene as the main camera.
00151   DisplayRegion *dr = buffer->make_display_region();
00152   dr->set_camera(NodePath(wf->get_camera(0)));
00153 
00154   // Make the clear color on the buffer be yellow, so it's obviously
00155   // different from the main scene's background color.
00156   buffer->set_clear_color(LColor(1, 1, 0, 0));
00157 
00158   // Apply the offscreen buffer's texture to a card in the main
00159   // window.
00160   CardMaker cm("card");
00161   cm.set_frame(0, 1, 0, 1);
00162   NodePath card_np(cm.generate());
00163   
00164   card_np.reparent_to(wf->get_render_2d());
00165   card_np.set_texture(buffer->get_texture());
00166 }
00167 
00168 void 
00169 usage() {
00170   cerr <<
00171     "\n"
00172     "Usage: pview [opts] model [model ...]\n"
00173     "       pview -h\n\n";
00174 }
00175 
00176 void 
00177 help() {
00178   usage();
00179   cerr <<
00180     "pview opens a quick Panda window for viewing one or more models and/or\n"
00181     "animations.\n\n"
00182 
00183     "Options:\n\n"
00184 
00185     "  -a\n"
00186     "      Convert and play animations, if loading an external file type\n"
00187     "      (like .mb) directly and if the converter supports animations.\n"
00188     "      Also implicitly enables the animation controls.\n\n"
00189     
00190     "  -c\n"
00191     "      Automatically center models within the viewing window on startup.\n"
00192     "      This can also be achieved with the 'c' hotkey at runtime.\n\n"
00193 
00194     "  -l\n"
00195     "      Open the window before loading any models with the text \"Loading\"\n"
00196     "      displayed in the window.  The default is not to open the window\n"
00197     "      until all models are loaded.\n\n"
00198 
00199     "  -i\n"
00200     "      Ignore bundle/group names.  Normally, the <group> name must match\n"
00201     "      the <bundle> name, or the animation will not be used.\n\n"
00202 
00203     "  -s filename\n"
00204     "      After displaying the models, immediately take a screenshot and\n"
00205     "      exit.\n\n"
00206 
00207     "  -D\n"
00208     "      Delete the model files after loading them (presumably this option\n"
00209     "      will only be used when loading a temporary model file).\n\n"
00210 
00211     "  -V\n"
00212     "      Report the current version of Panda, and exit.\n\n"
00213     
00214     "  -h\n"
00215     "      Display this help text.\n\n";
00216 }
00217 
00218 void 
00219 report_version() {
00220   nout << "\n";
00221   PandaSystem *ps = PandaSystem::get_global_ptr();
00222   ps->write(nout);
00223   nout << "\n";
00224 }
00225 
00226 int
00227 main(int argc, char **argv) {
00228   preprocess_argv(argc, argv);
00229   framework.open_framework(argc, argv);
00230   framework.set_window_title("Panda Viewer");
00231 
00232   bool anim_controls = false;
00233   bool auto_center = false;
00234   bool show_loading = false;
00235   bool auto_screenshot = false;
00236   int hierarchy_match_flags = PartGroup::HMF_ok_part_extra |
00237                               PartGroup::HMF_ok_anim_extra;
00238   Filename screenshotfn;
00239   bool delete_models = false;
00240 
00241   extern char *optarg;
00242   extern int optind;
00243   static const char *optflags = "acls:DVhi";
00244   int flag = getopt(argc, argv, optflags);
00245 
00246   while (flag != EOF) {
00247     switch (flag) {
00248     case 'a':
00249       anim_controls = true;
00250       PandaFramework::_loader_options.set_flags(PandaFramework::_loader_options.get_flags() | LoaderOptions::LF_convert_anim);
00251       break;
00252 
00253     case 'c':
00254       auto_center = true;
00255       break;
00256 
00257     case 'l':
00258       show_loading = true;
00259       break;
00260       
00261     case 'i':
00262       hierarchy_match_flags |= PartGroup::HMF_ok_wrong_root_name;
00263       break;
00264 
00265     case 's':
00266       auto_screenshot = true;
00267       screenshotfn = optarg;
00268       break;
00269 
00270     case 'D':
00271       delete_models = true;
00272       break;
00273 
00274     case 'V':
00275       report_version();
00276       return 1;
00277 
00278     case 'h':
00279       help();
00280       return 1;
00281 
00282     case '?':
00283       usage();
00284       return 1;
00285 
00286     default:
00287       cerr << "Unhandled switch: " << flag << endl;
00288       break;
00289     }
00290     flag = getopt(argc, argv, optflags);
00291   }
00292   argc -= (optind - 1);
00293   argv += (optind - 1);
00294 
00295   WindowFramework *window = framework.open_window();
00296   if (window != (WindowFramework *)NULL) {
00297     // We've successfully opened a window.
00298 
00299     NodePath loading_np;
00300 
00301     if (show_loading) {
00302       // Put up a "loading" message for the user's benefit.
00303       NodePath aspect_2d = window->get_aspect_2d();
00304       PT(TextNode) loading = new TextNode("loading");
00305       loading_np = aspect_2d.attach_new_node(loading);
00306       loading_np.set_scale(0.125f);
00307       loading->set_text_color(1.0f, 1.0f, 1.0f, 1.0f);
00308       loading->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f);
00309       loading->set_shadow(0.04, 0.04);
00310       loading->set_align(TextNode::A_center);
00311       loading->set_text("Loading...");
00312 
00313       // Allow a couple of frames to go by so the window will be fully
00314       // created and the text will be visible.
00315       Thread *current_thread = Thread::get_current_thread();
00316       framework.do_frame(current_thread);
00317       framework.do_frame(current_thread);
00318     }
00319 
00320     window->enable_keyboard();
00321     window->setup_trackball();
00322     framework.get_models().instance_to(window->get_render());
00323     if (argc < 2) {
00324       // If we have no arguments, get that trusty old triangle out.
00325       window->load_default_model(framework.get_models());
00326     } else {
00327       window->load_models(framework.get_models(), argc, argv);
00328 
00329       if (delete_models) {
00330         VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00331         for (int i = 1; i < argc && argv[i] != (char *)NULL; i++) {
00332           Filename model = Filename::from_os_specific(argv[i]);
00333           if (vfs->exists(model)) {
00334             nout << "Deleting " << model << "\n";
00335             vfs->delete_file(model);
00336           }
00337         }
00338       }
00339     }
00340     window->loop_animations(hierarchy_match_flags);
00341 
00342     // Make sure the textures are preloaded.
00343     framework.get_models().prepare_scene(window->get_graphics_output()->get_gsg());
00344     
00345     loading_np.remove_node();
00346 
00347     if (auto_center) {
00348       window->center_trackball(framework.get_models());
00349     }
00350 
00351     if (auto_screenshot) {
00352       return(output_screenshot(screenshotfn) ? 0:1);
00353     }
00354 
00355     if (anim_controls) {
00356       window->set_anim_controls(true);
00357     }
00358 
00359     framework.enable_default_keys();
00360     framework.define_key("shift-w", "open a new window", event_W, NULL);
00361     framework.define_key("shift-f", "flatten hierarchy", event_F, NULL);
00362     framework.define_key("alt-enter", "toggle between window/fullscreen", event_Enter, NULL);
00363     framework.define_key("2", "split the window", event_2, NULL);
00364     if (pview_test_hack) {
00365       framework.define_key("0", "run quick hacky test", event_0, NULL);
00366     }
00367     framework.main_loop();
00368     framework.report_frame_rate(nout);
00369   }
00370 
00371   framework.close_framework();
00372   return (0);
00373 }
 All Classes Functions Variables Enumerations