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