Panda3D
|
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 }