Panda3D
windowFramework.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file windowFramework.cxx
10  * @author drose
11  * @date 2002-04-02
12  */
13 
14 #include "windowFramework.h"
15 #include "pandaFramework.h"
16 #include "displayRegion.h"
17 #include "buttonThrower.h"
18 #include "transform2sg.h"
19 #include "dSearchPath.h"
20 #include "filename.h"
21 #include "loader.h"
22 #include "keyboardButton.h"
23 #include "geom.h"
24 #include "geomTriangles.h"
25 #include "geomTristrips.h"
26 #include "geomVertexData.h"
27 #include "geomVertexFormat.h"
28 #include "geomVertexWriter.h"
29 #include "texturePool.h"
30 #include "textureAttrib.h"
31 #include "colorAttrib.h"
32 #include "perspectiveLens.h"
33 #include "orthographicLens.h"
34 #include "auto_bind.h"
35 #include "ambientLight.h"
36 #include "directionalLight.h"
37 #include "lightAttrib.h"
38 #include "boundingSphere.h"
39 #include "deg_2_rad.h"
40 #include "config_framework.h"
41 #include "cullFaceAttrib.h"
42 #include "rescaleNormalAttrib.h"
43 #include "shadeModelAttrib.h"
44 #include "pgTop.h"
45 #include "geomNode.h"
46 #include "texture.h"
47 #include "texturePool.h"
48 #include "loaderFileTypeRegistry.h"
49 #include "pnmImage.h"
50 #include "virtualFileSystem.h"
51 #include "string_utils.h"
52 #include "bamFile.h"
53 #include "staticTextFont.h"
54 #include "mouseButton.h"
55 
56 // This is generated data for the standard texture we apply to the blue
57 // triangle.
58 #include "rock_floor.rgb_src.c"
59 
60 // This is generated data for shuttle_controls.bam, a bamified version of
61 // shuttle_controls.egg (found in the models tree). It's compiled in
62 // shuttle_controls.bam_src.c.
63 #include "shuttle_controls.bam_src.c"
64 
65 using std::istringstream;
66 using std::ostringstream;
67 using std::string;
68 
69 // This number is chosen arbitrarily to override any settings in model files.
70 static const int override_priority = 100;
71 
72 PT(TextFont) WindowFramework::_shuttle_controls_font = nullptr;
73 TypeHandle WindowFramework::_type_handle;
74 
75 /**
76  *
77  */
78 WindowFramework::
79 WindowFramework(PandaFramework *panda_framework) :
80  _panda_framework(panda_framework)
81 {
82  _got_keyboard = false;
83  _got_trackball = false;
84  _got_lights = false;
85  _anim_controls_enabled = false;
86  _anim_index = 0;
87  _wireframe_enabled = false;
88  _wireframe_filled = false;
89  _texture_enabled = true;
90  _two_sided_enabled = false;
91  _one_sided_reverse_enabled = false;
92  _lighting_enabled = false;
93  _perpixel_enabled = false;
94  _background_type = BT_default;
95 }
96 
97 /**
98  *
99  */
100 WindowFramework::
101 WindowFramework(const WindowFramework &copy, DisplayRegion *display_region) :
102  _panda_framework(copy._panda_framework),
103  _window(copy._window),
104  _display_region_3d(display_region)
105 {
106  _got_keyboard = false;
107  _got_trackball = false;
108  _got_lights = false;
109  _anim_controls_enabled = false;
110  _anim_index = 0;
111  _wireframe_enabled = false;
112  _texture_enabled = true;
113  _two_sided_enabled = false;
114  _one_sided_reverse_enabled = false;
115  _lighting_enabled = false;
116  _perpixel_enabled = false;
117  _background_type = BT_default;
118 
119  set_background_type(copy._background_type);
120  // Set up a 3-d camera for the window by default.
121  NodePath camera_np = make_camera();
122  _display_region_3d->set_camera(camera_np);
123 }
124 
125 /**
126  *
127  */
128 WindowFramework::
129 ~WindowFramework() {
130  close_window();
131 }
132 
133 /**
134  * Opens the actual window or buffer. This is normally called only from
135  * PandaFramework::open_window().
136  */
137 GraphicsOutput *WindowFramework::
138 open_window(const WindowProperties &props, int flags, GraphicsEngine *engine,
140  const FrameBufferProperties &fbprops) {
141  nassertr(_window == nullptr, _window);
142 
143  static int next_window_index = 1;
144  ostringstream stream;
145  stream << "window" << next_window_index;
146  next_window_index++;
147  string name = stream.str();
148 
149  _window = nullptr;
150  GraphicsOutput *winout =
151  engine->make_output(pipe, name, 0, fbprops,
152  props, flags, gsg, nullptr);
153  if (winout != nullptr) {
154  _window = winout;
155  // _window->request_properties(props);
156 
157  // Create a display region that covers the entire window.
158  _display_region_3d = _window->make_display_region();
159 
160  // Make sure the DisplayRegion does the clearing, not the window, so we
161  // can have multiple DisplayRegions of different colors.
162  _window->set_clear_color_active(false);
163  _window->set_clear_depth_active(false);
164  _window->set_clear_stencil_active(false);
165 
166  // Set up a 3-d camera for the window by default.
167  NodePath camera_np = make_camera();
168  _display_region_3d->set_camera(camera_np);
169 
170  set_background_type(_background_type);
171 
172  if (show_frame_rate_meter) {
173  _frame_rate_meter = new FrameRateMeter("frame_rate_meter");
174  _frame_rate_meter->setup_window(_window);
175  }
176  if (show_scene_graph_analyzer_meter) {
177  _scene_graph_analyzer_meter = new SceneGraphAnalyzerMeter("scene_graph_analyzer_meter", get_render().node());
178  _scene_graph_analyzer_meter->setup_window(_window);
179  }
180  }
181 
182  return _window;
183 }
184 
185 /**
186  * Closes the window or buffer. This is normally called from
187  * PandaFramework::close_window().
188  */
189 void WindowFramework::
190 close_window() {
191  _window.clear();
192  _camera_group.remove_node();
193  _render.remove_node();
194  _render_2d.remove_node();
195  _mouse.remove_node();
196 
197  _alight.clear();
198  _dlight.clear();
199  _got_keyboard = false;
200  _got_trackball = false;
201  _got_lights = false;
202 
203  _wireframe_enabled = false;
204  _texture_enabled = true;
205  _two_sided_enabled = false;
206  _one_sided_reverse_enabled = false;
207  _lighting_enabled = false;
208  _perpixel_enabled = false;
209 
210  if (_frame_rate_meter != nullptr) {
211  _frame_rate_meter->clear_window();
212  _frame_rate_meter = nullptr;
213  }
214  if (_scene_graph_analyzer_meter != nullptr) {
215  _scene_graph_analyzer_meter->clear_window();
216  _scene_graph_analyzer_meter = nullptr;
217  }
218 }
219 
220 /**
221  * Returns the node above the collection of 3-d cameras in the scene graph.
222  * This node may be moved around to represent the viewpoint.
223  */
226  if (_camera_group.is_empty()) {
227  _camera_group = get_render().attach_new_node("camera_group");
228  }
229  return _camera_group;
230 }
231 
232 /**
233  * Returns the root of the 3-d scene graph.
234  */
237  if (_render.is_empty()) {
238  _render = NodePath("render");
239 
240  _render.node()->set_attrib(RescaleNormalAttrib::make_default());
241  _render.node()->set_attrib(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
242 
243  // This is maybe here temporarily, and maybe not.
244  _render.set_two_sided(0);
245  }
246  return _render;
247 }
248 
249 /**
250  * Returns the root of the 2-d scene graph.
251  */
254  if (_render_2d.is_empty()) {
255  _render_2d = NodePath("render_2d");
256 
257  // Some standard properties for the 2-d display.
258 
259  _render_2d.set_depth_write(0);
260  _render_2d.set_depth_test(0);
261  _render_2d.set_material_off(1);
262  _render_2d.set_two_sided(1);
263 
264  // Now set up a 2-d camera to view render_2d.
265 
266  // Create a display region that matches the size of the 3-d display
267  // region.
268  PN_stdfloat l, r, b, t;
269  _display_region_3d->get_dimensions(l, r, b, t);
270  _display_region_2d = _window->make_mono_display_region(l, r, b, t);
271  _display_region_2d->set_sort(10);
272 
273  // Finally, we need a camera to associate with the display region.
274  PT(Camera) camera = new Camera("camera2d");
275  NodePath camera_np = _render_2d.attach_new_node(camera);
276 
277  PT(Lens) lens = new OrthographicLens;
278 
279  static const PN_stdfloat left = -1.0f;
280  static const PN_stdfloat right = 1.0f;
281  static const PN_stdfloat bottom = -1.0f;
282  static const PN_stdfloat top = 1.0f;
283  lens->set_film_size(right - left, top - bottom);
284  lens->set_film_offset((right + left) * 0.5, (top + bottom) * 0.5);
285  lens->set_near_far(-1000, 1000);
286 
287  camera->set_lens(lens);
288  _display_region_2d->set_camera(camera_np);
289  }
290 
291  return _render_2d;
292 }
293 
294 /**
295  * Returns the node under the 2-d scene graph that is scaled to suit the
296  * window's aspect ratio.
297  */
300  if (_aspect_2d.is_empty()) {
301  PGTop *top = new PGTop("aspect_2d");
302  _aspect_2d = get_render_2d().attach_new_node(top);
303 
304  // Tell the PGTop about our MouseWatcher object, so the PGui system can
305  // operate.
306  PandaNode *mouse_node = get_mouse().node();
307  if (mouse_node->is_of_type(MouseWatcher::get_class_type())) {
308  top->set_mouse_watcher(DCAST(MouseWatcher, mouse_node));
309  }
310 
311  PN_stdfloat this_aspect_ratio = aspect_ratio;
312  if (this_aspect_ratio == 0.0f) {
313  // An aspect ratio of 0.0 means to try to infer it.
314  this_aspect_ratio = 1.0f;
315 
316  if (_window->has_size()) {
317  int x_size = _window->get_sbs_left_x_size();
318  int y_size = _window->get_sbs_left_y_size();
319  if (y_size != 0) {
320  this_aspect_ratio = (PN_stdfloat)x_size / (PN_stdfloat)y_size;
321  }
322  }
323  }
324 
325  _aspect_2d.set_scale(1.0f / this_aspect_ratio, 1.0f, 1.0f);
326  }
327 
328  return _aspect_2d;
329 }
330 
331 /**
332  * Returns a special root that uses units in pixels that are relative to the
333  * window. The upperleft corner of the window is (0, 0), the lowerleft corner
334  * is (xsize, -ysize), in this coordinate system.
335  */
338  if (_pixel_2d.is_empty()) {
339  PGTop *top = new PGTop("pixel_2d");
340  _pixel_2d = get_render_2d().attach_new_node(top);
341  _pixel_2d.set_pos(-1, 0, 1);
342 
343  if (_window->has_size()) {
344  int x_size = _window->get_sbs_left_x_size();
345  int y_size = _window->get_sbs_left_y_size();
346  if (x_size > 0){
347  _pixel_2d.set_sx(2.0f / (float)x_size);
348  }
349  _pixel_2d.set_sy(1.0f);
350  if (y_size > 0){
351  _pixel_2d.set_sz(2.0f / (float)y_size);
352  }
353  }
354  }
355 
356  return _pixel_2d;
357 }
358 
359 /**
360  * Returns the node in the data graph corresponding to the mouse associated
361  * with this window.
362  */
365  if (_mouse.is_empty()) {
366  NodePath mouse = _panda_framework->get_mouse(_window);
367 
368  // Create a MouseWatcher to filter the mouse input. We do this mainly so
369  // we can constrain the mouse input to our particular display region, if
370  // we have one. This means the node we return from get_mouse() is
371  // actually a MouseWatcher, but since it presents the same interface as a
372  // Mouse, no one should mind.
373 
374  // Another advantage to using a MouseWatcher is that the PGTop of aspect2d
375  // likes it better.
376  PT(MouseWatcher) mw = new MouseWatcher("watcher");
377 
378  if (_window->get_side_by_side_stereo()) {
379  // If the window has side-by-side stereo enabled, then we should
380  // constrain the MouseWatcher to the window's DisplayRegion. This will
381  // enable the MouseWatcher to track the left and right halves of the
382  // screen individually.
383  mw->set_display_region(_window->get_overlay_display_region());
384  }
385 
386  _mouse = mouse.attach_new_node(mw);
387  }
388  return _mouse;
389 }
390 
391 /**
392  * Returns the node in the data graph corresponding to the ButtonThrower
393  * object associated with this window.
394  */
397  return _button_thrower;
398 }
399 
400 /**
401  * Creates a ButtonThrower to listen to button presses and throw them as
402  * events.
403  */
406  if (_got_keyboard) {
407  return;
408  }
409 
410  if (_window->is_of_type(GraphicsWindow::get_class_type()) &&
411  DCAST(GraphicsWindow, _window)->get_num_input_devices() > 0) {
412  NodePath mouse = get_mouse();
413 
414  // Create a button thrower to listen for our keyboard events and associate
415  // this WindowFramework pointer with each one.
416  PT(ButtonThrower) bt = new ButtonThrower("kb-events");
417  bt->add_parameter(EventParameter(this));
418  ModifierButtons mods;
419  mods.add_button(KeyboardButton::shift());
420  mods.add_button(KeyboardButton::control());
421  mods.add_button(KeyboardButton::alt());
422  mods.add_button(KeyboardButton::meta());
423  bt->set_modifier_buttons(mods);
424  _button_thrower = mouse.attach_new_node(bt);
425  }
426 
427  _got_keyboard = true;
428 }
429 
430 /**
431  * Sets up the mouse to trackball around the camera.
432  */
435  if (_got_trackball) {
436  return;
437  }
438 
439  if (_window->is_of_type(GraphicsWindow::get_class_type()) &&
440  DCAST(GraphicsWindow, _window)->get_num_input_devices() > 0) {
441  NodePath mouse = get_mouse();
442  NodePath camera = get_camera_group();
443 
444  _trackball = new Trackball("trackball");
445  _trackball->set_pos(LVector3::forward() * 50.0);
446  mouse.attach_new_node(_trackball);
447 
448  PT(Transform2SG) tball2cam = new Transform2SG("tball2cam");
449  tball2cam->set_node(camera.node());
450  _trackball->add_child(tball2cam);
451  }
452 
453  _got_trackball = true;
454 }
455 
456 /**
457  * Centers the trackball on the indicated object, and scales the trackball
458  * motion suitably.
459  */
461 center_trackball(const NodePath &object) {
462  if (_trackball == nullptr) {
463  return;
464  }
465 
466  PT(BoundingVolume) volume = object.get_bounds();
467  // We expect at least a geometric bounding volume around the world.
468  nassertv(volume != nullptr);
469  nassertv(volume->is_of_type(GeometricBoundingVolume::get_class_type()));
470  CPT(GeometricBoundingVolume) gbv = DCAST(GeometricBoundingVolume, volume);
471 
472  if (object.has_parent()) {
473  CPT(TransformState) net_transform = object.get_parent().get_net_transform();
474  PT(GeometricBoundingVolume) new_gbv = DCAST(GeometricBoundingVolume, gbv->make_copy());
475  new_gbv->xform(net_transform->get_mat());
476  gbv = new_gbv;
477  }
478 
479  // Determine the bounding sphere around the object.
480  if (gbv->is_infinite()) {
481  framework_cat.warning()
482  << "Infinite bounding volume for " << object << "\n";
483  return;
484  }
485 
486  if (gbv->is_empty()) {
487  framework_cat.warning()
488  << "Empty bounding volume for " << object << "\n";
489  return;
490  }
491 
492  // The BoundingVolume might be a sphere (it's likely), but since it might
493  // not, we'll take no chances and make our own sphere.
494  PT(BoundingSphere) sphere = new BoundingSphere(gbv->get_approx_center(), 0.0f);
495  if (!sphere->extend_by(gbv)) {
496  framework_cat.warning()
497  << "Cannot determine bounding volume of " << object << "\n";
498  return;
499  }
500 
501  LPoint3 center = sphere->get_center();
502  PN_stdfloat radius = sphere->get_radius();
503 
504  PN_stdfloat distance = 50.0f;
505 
506  // Choose a suitable distance to view the whole volume in our frame. This
507  // is based on the camera lens in use. Determine the lens based on the
508  // first camera; this will be the default camera.
509  Lens *lens = nullptr;
510  if (!_cameras.empty()) {
511  Cameras::const_iterator ci;
512  for (ci = _cameras.begin();
513  ci != _cameras.end() && lens == nullptr;
514  ++ci) {
515  lens = (*ci)->get_lens();
516  }
517  }
518 
519  if (lens != nullptr) {
520  LVecBase2 fov = lens->get_fov();
521  distance = radius / ctan(deg_2_rad(std::min(fov[0], fov[1]) / 2.0f));
522 
523  // Ensure the far plane is far enough back to see the entire object.
524  PN_stdfloat ideal_far_plane = distance + radius * 1.5;
525  lens->set_far(std::max(lens->get_default_far(), ideal_far_plane));
526 
527  // And that the near plane is far enough forward.
528  PN_stdfloat ideal_near_plane = distance - radius;
529  lens->set_near(std::min(lens->get_default_near(), ideal_near_plane));
530  }
531 
532  _trackball->set_origin(center);
533  _trackball->set_pos(LVector3::forward() * distance);
534 
535  // Also set the movement scale on the trackball to be consistent with the
536  // size of the model and the lens field-of-view.
537  _trackball->set_forward_scale(distance * 0.006);
538 }
539 
540 /**
541  * Loads up all the model files listed in the indicated argument list. If
542  * first_arg is supplied, it is the first argument in the list to consider.
543  *
544  * Returns true if all models loaded successfully, or false if at least one of
545  * them had an error.
546  */
548 load_models(const NodePath &parent, int argc, char *argv[], int first_arg) {
549  pvector<Filename> files;
550 
551  for (int i = first_arg; i < argc && argv[i] != nullptr; i++) {
552  files.push_back(Filename::from_os_specific(argv[i]));
553  }
554 
555  return load_models(parent, files);
556 }
557 
558 /**
559  * Loads up all the model files listed in the indicated argument list.
560  *
561  * Returns true if all models loaded successfully, or false if at least one of
562  * them had an error.
563  */
565 load_models(const NodePath &parent, const pvector<Filename> &files) {
566  bool all_ok = true;
567 
569  for (fi = files.begin(); fi != files.end(); ++fi) {
570  const Filename &filename = (*fi);
571  NodePath model = load_model(parent, filename);
572  if (model.is_empty()) {
573  all_ok = false;
574  }
575  }
576 
577  return all_ok;
578 }
579 
580 /**
581  * Loads up the indicated model and returns the new NodePath, or the empty
582  * NodePath if the model could not be loaded.
583  */
585 load_model(const NodePath &parent, Filename filename) {
586  framework_cat.info() << "Loading " << filename << "\n";
587 
588  // If the filename already exists where it is, or if it is fully qualified,
589  // don't search along the model path for it.
591  bool search = !(filename.is_fully_qualified() || vfs->exists(filename));
592 
593  // We allow loading image files here. Check to see if it might be an image
594  // file, based on the filename extension.
595  bool is_image = false;
596  string extension = filename.get_extension();
597 #ifdef HAVE_ZLIB
598  if (extension == "pz" || extension == "gz") {
599  extension = Filename(filename.get_basename_wo_extension()).get_extension();
600  }
601 #endif // HAVE_ZLIB
602  TexturePool *texture_pool = TexturePool::get_global_ptr();
603  LoaderFileType *model_type = nullptr;
604 
605  if (!extension.empty()) {
607  model_type = reg->get_type_from_extension(extension);
608 
609  if (model_type == nullptr) {
610  // The extension isn't a known model file type; is it a known image file
611  // extension?
612  TexturePool *texture_pool = TexturePool::get_global_ptr();
613  if (texture_pool->get_texture_type(extension) != nullptr) {
614  // It is a known image file extension.
615  is_image = true;
616  }
617  }
618  }
619 
620  LoaderOptions options = PandaFramework::_loader_options;
621  if (search) {
622  options.set_flags(options.get_flags() | LoaderOptions::LF_search);
623  } else {
624  options.set_flags(options.get_flags() & ~LoaderOptions::LF_search);
625  }
626 
627  Loader loader;
628  PT(PandaNode) node;
629  if (is_image) {
630  node = load_image_as_model(filename);
631  } else {
632  node = loader.load_sync(filename, options);
633 
634  // It failed to load. Is it because the extension isn't recognised? If
635  // so, then we just got done printing out the known scene types, and we
636  // should also print out the supported texture types.
637  if (node == nullptr && !is_image && model_type == nullptr) {
638  texture_pool->write_texture_types(nout, 2);
639  }
640  }
641 
642  if (node == nullptr) {
643  nout << "Unable to load " << filename << "\n";
644  return NodePath::not_found();
645  }
646 
647  return parent.attach_new_node(node);
648 }
649 
650 /**
651  * Loads our favorite blue triangle. This is intended to provide some default
652  * geometry to have *something* to look at for testing, when no other models
653  * are provided.
654  */
656 load_default_model(const NodePath &parent) {
657  CPT(RenderState) state = RenderState::make_empty();
658 
659  state = state->add_attrib(ColorAttrib::make_flat(LColor(0.5, 0.5, 1.0, 1.0)));
660 
661  // Get the default texture to apply to the triangle; it's compiled into the
662  // code these days.
663  string rock_floor_string((const char *)rock_floor, rock_floor_len);
664  istringstream rock_floor_strm(rock_floor_string);
665  PNMImage rock_floor_pnm;
666  if (rock_floor_pnm.read(rock_floor_strm, "rock-floor.rgb")) {
667  PT(Texture) tex = new Texture;
668  tex->set_name("rock-floor.rgb");
669  tex->load(rock_floor_pnm);
670  tex->set_minfilter(SamplerState::FT_linear);
671  tex->set_magfilter(SamplerState::FT_linear);
672  state = state->add_attrib(TextureAttrib::make(tex));
673  }
674 
675  GeomNode *geomnode = new GeomNode("tri");
676 
677  PT(GeomVertexData) vdata = new GeomVertexData
679  Geom::UH_static);
680  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
681  GeomVertexWriter normal(vdata, InternalName::get_normal());
682  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
683 
684  vertex.add_data3(LVertex::rfu(0.0, 0.0, 0.0));
685  vertex.add_data3(LVertex::rfu(1.0, 0.0, 0.0));
686  vertex.add_data3(LVertex::rfu(0.0, 0.0, 1.0));
687 
688  normal.add_data3(LNormal::back());
689  normal.add_data3(LNormal::back());
690  normal.add_data3(LNormal::back());
691 
692  texcoord.add_data2(0.0, 0.0);
693  texcoord.add_data2(1.0, 0.0);
694  texcoord.add_data2(0.0, 1.0);
695 
696  PT(GeomTriangles) tri = new GeomTriangles(Geom::UH_static);
697  tri->add_consecutive_vertices(0, 3);
698  tri->close_primitive();
699 
700  PT(Geom) geom = new Geom(vdata);
701  geom->add_primitive(tri);
702 
703  geomnode->add_geom(geom, state);
704 
705  return parent.attach_new_node(geomnode);
706 }
707 
708 /**
709  * Looks for characters and their matching animation files in the scene graph;
710  * binds and loops any matching animations found.
711  */
713 loop_animations(int hierarchy_match_flags) {
714  // If we happened to load up both a character file and its matching
715  // animation file, attempt to bind them together now and start the
716  // animations looping.
717  auto_bind(get_render().node(), _anim_controls, hierarchy_match_flags);
718  _anim_controls.loop_all(true);
719 }
720 
721 /**
722  * Walks through all the animations that were bound by loop_animations() and
723  * staggers their play rate slightly so that they will not remain perfectly in
724  * sync.
725  */
728  for (int i = 0; i < _anim_controls.get_num_anims(); ++i) {
729  AnimControl *control = _anim_controls.get_anim(i);
730  double r = (double)rand() / (double)RAND_MAX;
731  r = r * 0.2 + 0.9;
732  control->set_play_rate(r);
733  }
734 }
735 
736 /**
737  * Rotates the animation controls through all of the available animations. If
738  * the animation controls are not already enabled, enables them at sets to the
739  * first animation; if they are already enabled, steps to the next animation;
740  * if that is the last animation, disables the animation controls.
741  */
744  if (_anim_controls_enabled) {
745  destroy_anim_controls();
746 
747  if (_anim_controls.get_num_anims() == 0) {
748  set_anim_controls(false);
749  return;
750  }
751 
752  // Stop the active animation.
753  pause_button();
754  ++_anim_index;
755 
756  if (_anim_index >= _anim_controls.get_num_anims()) {
757  set_anim_controls(false);
758  _anim_controls.loop_all(true);
759  } else {
760  create_anim_controls();
761  play_button();
762  }
763  } else {
764  _anim_index = 0;
765  set_anim_controls(true);
766  if (_anim_controls.get_num_anims() > 0) {
767  play_button();
768  }
769  }
770 }
771 
772 /**
773  * Creates an onscreen animation slider for frame-stepping through the
774  * animations.
775  */
777 set_anim_controls(bool enable) {
778  _anim_controls_enabled = enable;
779  if (_anim_controls_enabled) {
780  create_anim_controls();
781 
782  } else {
783  destroy_anim_controls();
784  }
785 }
786 
787 /**
788  * Reevaluates the dimensions of the window, presumably after the window has
789  * been resized by the user or some other force. Adjusts the render film
790  * size, aspect2d scale (aspect ratio) and the dimensionsas of pixel_2d
791  * according to the new window shape, or new config setting.
792  */
795  PN_stdfloat this_aspect_ratio = aspect_ratio;
796 
797  int x_size = 0, y_size = 0;
798  if (_window->has_size()) {
799  x_size = _window->get_sbs_left_x_size();
800  y_size = _window->get_sbs_left_y_size();
801  }
802 
803  if (this_aspect_ratio == 0.0f) {
804  // An aspect ratio of 0.0 means to try to infer it.
805  this_aspect_ratio = 1.0f;
806  if (y_size != 0) {
807  this_aspect_ratio = (float)x_size / (float)y_size;
808  }
809  }
810 
811  if (!_aspect_2d.is_empty()) {
812  _aspect_2d.set_scale(1.0f / this_aspect_ratio, 1.0f, 1.0f);
813  }
814 
815  if (!_pixel_2d.is_empty()) {
816  // Adjust the pixel 2d scale
817  if (x_size > 0){
818  _pixel_2d.set_sx(2.0f / (float)x_size);
819  }
820  _pixel_2d.set_sy(1.0f);
821  if (y_size > 0){
822  _pixel_2d.set_sz(2.0f / (float)y_size);
823  }
824  }
825 
826  Cameras::iterator ci;
827  for (ci = _cameras.begin(); ci != _cameras.end(); ++ci) {
828  Lens *lens = (*ci)->get_lens();
829  if (lens != nullptr) {
830  if (y_size != 0) {
831  lens->set_film_size(x_size, y_size);
832  } else {
833  lens->set_aspect_ratio(this_aspect_ratio);
834  }
835  }
836  }
837 }
838 
839 /**
840  * Divides the window into two display regions, each of which gets its own
841  * trackball and keyboard events. The new window pointer is returned.
842  *
843  * There is not an interface for recombining divided windows.
844  */
846 split_window(SplitType split_type) {
847  DisplayRegion *new_region = nullptr;
848 
849  if (split_type == ST_default) {
850  // Choose either horizontal or vertical according to the largest
851  // dimension.
852 
853  if (_display_region_3d->get_pixel_width() >
854  _display_region_3d->get_pixel_height()) {
855  split_type = ST_horizontal;
856  } else {
857  split_type = ST_vertical;
858  }
859  }
860 
861  PN_stdfloat left, right, bottom, top;
862  _display_region_3d->get_dimensions(left, right, bottom, top);
863  new_region = _display_region_3d->get_window()->make_display_region();
864 
865  if (split_type == ST_vertical) {
866  _display_region_3d->set_dimensions(left, right, bottom, (top + bottom) / 2.0f);
867  if (_display_region_2d != nullptr) {
868  _display_region_2d->set_dimensions(left, right, bottom, (top + bottom) / 2.0f);
869  }
870 
871  new_region->set_dimensions(left, right, (top + bottom) / 2.0f, top);
872 
873  } else {
874  _display_region_3d->set_dimensions(left, (left + right) / 2.0f, bottom, top);
875  if (_display_region_2d != nullptr) {
876  _display_region_2d->set_dimensions(left, (left + right) / 2.0f, bottom, top);
877  }
878 
879  new_region->set_dimensions((left + right) / 2.0f, right, bottom, top);
880  }
881 
882  PT(WindowFramework) wf = new WindowFramework(*this, new_region);
883  _panda_framework->_windows.push_back(wf);
884 
885  return wf;
886 }
887 
888 /**
889  * Forces wireframe state (true) or restores default rendering (false).
890  */
892 set_wireframe(bool enable, bool filled) {
893  if (enable == _wireframe_enabled && filled == _wireframe_filled) {
894  return;
895  }
896 
897  NodePath render = get_render();
898 
899  if (!_two_sided_enabled) {
900  render.clear_two_sided();
901  }
902 
903  if (enable) {
904  if (filled) {
905  render.set_attrib(RenderModeAttrib::make(
906  RenderModeAttrib::M_filled_wireframe,
907  1.4f, false, LColor(1, 1, 1, .5f)),
908  override_priority);
909  // Darken the scene so that the wireframe is clearly visible, even when
910  // the scene is completely white.
911  render.set_color_scale(LColor(0.7f, 0.7f, 0.7f, 1), override_priority);
912  } else {
913  render.set_render_mode_wireframe(override_priority);
914  render.set_two_sided(true, override_priority);
915  render.clear_color_scale();
916  }
917  } else {
918  render.clear_render_mode();
919  if (_one_sided_reverse_enabled) {
920  CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse();
921  render.node()->set_attrib(attrib);
922  }
923  render.clear_color_scale();
924  }
925 
926  _wireframe_enabled = enable;
927  _wireframe_filled = filled;
928 }
929 
930 /**
931  * Forces textures off (false) or restores default rendering (true).
932  */
934 set_texture(bool enable) {
935  if (enable == _texture_enabled) {
936  return;
937  }
938 
939  NodePath render = get_render();
940 
941  if (!enable) {
942  render.set_texture_off(override_priority);
943  } else {
944  render.clear_texture();
945  }
946 
947  _texture_enabled = enable;
948 }
949 
950 /**
951  * Forces two-sided rendering (true) or restores default rendering (false).
952  */
954 set_two_sided(bool enable) {
955  if (enable == _two_sided_enabled) {
956  return;
957  }
958 
959  NodePath render = get_render();
960 
961  if (enable) {
962  render.set_two_sided(true, override_priority);
963  } else {
964  if (!_wireframe_enabled) {
965  render.clear_two_sided();
966  }
967  }
968 
969  _two_sided_enabled = enable;
970  _one_sided_reverse_enabled = false;
971 }
972 
973 /**
974  * Toggles one-sided reverse mode. In this mode, the front sides of one-sided
975  * polygons are culled instead of the back side.
976  */
978 set_one_sided_reverse(bool enable) {
979  if (enable == _one_sided_reverse_enabled) {
980  return;
981  }
982 
983  NodePath render = get_render();
984 
985  if (!_wireframe_enabled) {
986  if (enable) {
987  CPT(RenderAttrib) attrib = CullFaceAttrib::make_reverse();
988  render.node()->set_attrib(attrib);
989  } else {
990  render.clear_two_sided();
991  }
992  }
993 
994  _two_sided_enabled = false;
995  _one_sided_reverse_enabled = enable;
996 }
997 
998 /**
999  * Turns lighting on (true) or off (false).
1000  */
1001 void WindowFramework::
1002 set_lighting(bool enable) {
1003  if (enable == _lighting_enabled) {
1004  return;
1005  }
1006 
1007  NodePath render = get_render();
1008 
1009  if (enable) {
1010  if (!_got_lights) {
1011  setup_lights();
1012  }
1013  render.set_light(_alight);
1014  render.set_light(_dlight);
1015  } else {
1016  render.clear_light();
1017  }
1018 
1019  _lighting_enabled = enable;
1020 }
1021 
1022 /**
1023  * Turns per-pixel lighting on (true) or off (false).
1024  */
1025 void WindowFramework::
1026 set_perpixel(bool enable) {
1027  if (enable == _perpixel_enabled) {
1028  return;
1029  }
1030 
1031  NodePath render = get_render();
1032 
1033  if (enable) {
1034  render.set_shader_auto();
1035  } else {
1036  render.set_shader_off();
1037  }
1038 
1039  _perpixel_enabled = enable;
1040 }
1041 
1042 /**
1043  * Sets the background of the window to one of the pre-canned background types
1044  * (or to BT_other, which indicates the user intends to set up his own special
1045  * background mode).
1046  */
1047 void WindowFramework::
1048 set_background_type(WindowFramework::BackgroundType type) {
1049  _background_type = type;
1050 
1051  if (_display_region_3d == nullptr) {
1052  return;
1053  }
1054 
1055  switch (_background_type) {
1056  case BT_other:
1057  break;
1058 
1059  case BT_default:
1060  _display_region_3d->set_clear_color_active(true);
1061  _display_region_3d->set_clear_depth_active(true);
1062  _display_region_3d->set_clear_stencil_active(true);
1063  _display_region_3d->set_clear_color(_window->get_clear_color());
1064  _display_region_3d->set_clear_depth(_window->get_clear_depth());
1065  _display_region_3d->set_clear_stencil(_window->get_clear_stencil());
1066  break;
1067 
1068  case BT_black:
1069  _display_region_3d->set_clear_color_active(true);
1070  _display_region_3d->set_clear_depth_active(true);
1071  _display_region_3d->set_clear_stencil_active(true);
1072  _display_region_3d->set_clear_color(LColor(0.0f, 0.0f, 0.0f, 0.0f));
1073  _display_region_3d->set_clear_depth(1.0f);
1074  _display_region_3d->set_clear_stencil(0);
1075  break;
1076 
1077  case BT_gray:
1078  _display_region_3d->set_clear_color_active(true);
1079  _display_region_3d->set_clear_depth_active(true);
1080  _display_region_3d->set_clear_stencil_active(true);
1081  _display_region_3d->set_clear_color(LColor(0.3, 0.3, 0.3, 0.0f));
1082  _display_region_3d->set_clear_depth(1.0f);
1083  _display_region_3d->set_clear_stencil(0);
1084  break;
1085 
1086  case BT_white:
1087  _display_region_3d->set_clear_color_active(true);
1088  _display_region_3d->set_clear_depth_active(true);
1089  _display_region_3d->set_clear_stencil_active(true);
1090  _display_region_3d->set_clear_color(LColor(1.0f, 1.0f, 1.0f, 0.0f));
1091  _display_region_3d->set_clear_depth(1.0f);
1092  _display_region_3d->set_clear_stencil(0);
1093  break;
1094 
1095  case BT_none:
1096  _display_region_3d->set_clear_color_active(false);
1097  _display_region_3d->set_clear_depth_active(false);
1098  _display_region_3d->set_clear_stencil_active(false);
1099  break;
1100  }
1101 }
1102 
1103 /**
1104  * Returns a font that contains the shuttle controls icons.
1105  */
1108  if (_shuttle_controls_font == nullptr) {
1109  PT(TextFont) font;
1110 
1111  string shuttle_controls_string((const char *)shuttle_controls, shuttle_controls_len);
1112  istringstream in(shuttle_controls_string);
1113  BamFile bam_file;
1114  if (bam_file.open_read(in, "shuttle_controls font stream")) {
1115  PT(PandaNode) node = bam_file.read_node();
1116  if (node != nullptr) {
1117  _shuttle_controls_font = new StaticTextFont(node);
1118  }
1119  }
1120  }
1121 
1122  return _shuttle_controls_font;
1123 }
1124 
1125 /**
1126  * Makes a new 3-d camera for the window.
1127  */
1130  // Finally, we need a camera to associate with the display region.
1131  PT(Camera) camera = new Camera("camera");
1132  NodePath camera_np = get_camera_group().attach_new_node(camera);
1133  _cameras.push_back(camera);
1134 
1135  PT(Lens) lens = new PerspectiveLens;
1136 
1137  if (aspect_ratio != 0.0) {
1138  // If we're given an explict aspect ratio, use it
1139  lens->set_aspect_ratio(aspect_ratio);
1140 
1141  } else {
1142  // Otherwise, infer the aspect ratio from the window size. This does
1143  // assume we have square pixels on our output device.
1144  if (_window->has_size()) {
1145  int x_size = _window->get_sbs_left_x_size();
1146  int y_size = _window->get_sbs_left_y_size();
1147  if (y_size != 0) {
1148  lens->set_film_size(x_size, y_size);
1149  }
1150  }
1151  }
1152 
1153  camera->set_lens(lens);
1154 
1155  return camera_np;
1156 }
1157 
1158 /**
1159  * Makes light nodes and attaches them to the camera for viewing the scene.
1160  */
1161 void WindowFramework::
1162 setup_lights() {
1163  if (_got_lights) {
1164  return;
1165  }
1166 
1167  NodePath camera_group = get_camera_group();
1168  NodePath light_group = camera_group.attach_new_node("lights");
1169 
1170  AmbientLight *alight = new AmbientLight("ambient");
1171  alight->set_color(LColor(0.2, 0.2, 0.2, 1.0f));
1172  DirectionalLight *dlight = new DirectionalLight("directional");
1173  dlight->set_color(LColor(0.8f, 0.8f, 0.8f, 1.0f));
1174 
1175  _alight = light_group.attach_new_node(alight);
1176  _dlight = light_group.attach_new_node(dlight);
1177  _dlight.set_hpr(-10, -20, 0);
1178 
1179  _got_lights = true;
1180 }
1181 
1182 /**
1183  * Loads the indicated image file as a texture, and creates a polygon to
1184  * render it. Returns the new model.
1185  */
1186 PT(PandaNode) WindowFramework::
1187 load_image_as_model(const Filename &filename) {
1188  PT(Texture) tex = TexturePool::load_texture(filename);
1189  if (tex == nullptr) {
1190  return nullptr;
1191  }
1192 
1193  // Yes, it is an image file; make a texture out of it.
1194  tex->set_minfilter(SamplerState::FT_linear_mipmap_linear);
1195  tex->set_magfilter(SamplerState::FT_linear);
1196  tex->set_wrap_u(SamplerState::WM_clamp);
1197  tex->set_wrap_v(SamplerState::WM_clamp);
1198  tex->set_wrap_w(SamplerState::WM_clamp);
1199 
1200  // Ok, now make a polygon to show the texture.
1201  bool has_alpha = true;
1202  LVecBase2 tex_scale = tex->get_tex_scale();
1203 
1204  // Get the size from the original image (the texture may have scaled it to
1205  // make a power of 2).
1206  int x_size = tex->get_orig_file_x_size();
1207  int y_size = tex->get_orig_file_y_size();
1208 
1209  // Choose the dimensions of the polygon appropriately.
1210  PN_stdfloat left,right,top,bottom;
1211  static const PN_stdfloat scale = 10.0;
1212  if (x_size > y_size) {
1213  left = -scale;
1214  right = scale;
1215  top = (scale * y_size) / x_size;
1216  bottom = -(scale * y_size) / x_size;
1217  } else if (y_size != 0) {
1218  left = -(scale * x_size) / y_size;
1219  right = (scale * x_size) / y_size;
1220  top = scale;
1221  bottom = -scale;
1222  } else {
1223  framework_cat.warning()
1224  << "Texture size is 0 0: " << *tex << "\n";
1225 
1226  left = -scale;
1227  right = scale;
1228  top = scale;
1229  bottom = -scale;
1230  }
1231 
1232  PT(GeomNode) card_node = new GeomNode("card");
1233  card_node->set_attrib(TextureAttrib::make(tex));
1234  if (has_alpha) {
1235  card_node->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
1236  }
1237 
1238  bool is_3d = false;
1239  if (tex->get_texture_type() == Texture::TT_3d_texture ||
1240  tex->get_texture_type() == Texture::TT_cube_map) {
1241  // For a 3-d texture, generate a cube, instead of a plain card.
1242  is_3d = true;
1243  }
1244 
1245  CPT(GeomVertexFormat) vformat;
1246  if (!is_3d) {
1247  // Vertices and 2-d texture coordinates, all we need.
1248  vformat = GeomVertexFormat::get_v3t2();
1249 
1250  } else {
1251  // Vertices and 3-d texture coordinates.
1252  vformat = GeomVertexFormat::register_format
1254  (InternalName::get_vertex(), 3,
1255  GeomEnums::NT_stdfloat, GeomEnums::C_point,
1256  InternalName::get_texcoord(), 3,
1257  GeomEnums::NT_stdfloat, GeomEnums::C_texcoord));
1258  }
1259 
1260  PT(GeomVertexData) vdata = new GeomVertexData
1261  ("card", vformat, Geom::UH_static);
1262  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
1263  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
1264 
1265  if (!is_3d) {
1266  // A normal 2-d card.
1267  vertex.add_data3(LVertex::rfu(left, 0.02, top));
1268  vertex.add_data3(LVertex::rfu(left, 0.02, bottom));
1269  vertex.add_data3(LVertex::rfu(right, 0.02, top));
1270  vertex.add_data3(LVertex::rfu(right, 0.02, bottom));
1271 
1272  texcoord.add_data2(0.0f, tex_scale[1]);
1273  texcoord.add_data2(0.0f, 0.0f);
1274  texcoord.add_data2(tex_scale[0], tex_scale[1]);
1275  texcoord.add_data2(tex_scale[0], 0.0f);
1276 
1277  } else {
1278  // The eight vertices of a 3-d cube.
1279  vertex.add_data3(-1.0f, -1.0f, 1.0f); // 0
1280  vertex.add_data3(-1.0f, -1.0f, -1.0f); // 1
1281  vertex.add_data3(1.0f, -1.0f, -1.0f); // 2
1282  vertex.add_data3(1.0f, -1.0f, 1.0f); // 3
1283  vertex.add_data3(1.0f, 1.0f, 1.0f); // 4
1284  vertex.add_data3(1.0f, 1.0f, -1.0f); // 5
1285  vertex.add_data3(-1.0f, 1.0f, -1.0f); // 6
1286  vertex.add_data3(-1.0f, 1.0f, 1.0f); // 7
1287 
1288  texcoord.add_data3(-1.0f, -1.0f, 1.0f); // 0
1289  texcoord.add_data3(-1.0f, -1.0f, -1.0f); // 1
1290  texcoord.add_data3(1.0f, -1.0f, -1.0f); // 2
1291  texcoord.add_data3(1.0f, -1.0f, 1.0f); // 3
1292  texcoord.add_data3(1.0f, 1.0f, 1.0f); // 4
1293  texcoord.add_data3(1.0f, 1.0f, -1.0f); // 5
1294  texcoord.add_data3(-1.0f, 1.0f, -1.0f); // 6
1295  texcoord.add_data3(-1.0f, 1.0f, 1.0f); // 7
1296  }
1297 
1298  PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
1299 
1300  if (!is_3d) {
1301  // The two triangles that make up a quad.
1302  strip->add_consecutive_vertices(0, 4);
1303  strip->close_primitive();
1304 
1305  } else {
1306  // The twelve triangles (six quads) that make up a cube.
1307  strip->add_vertex(7);
1308  strip->add_vertex(0);
1309  strip->add_vertex(4);
1310  strip->add_vertex(3);
1311  strip->close_primitive();
1312 
1313  strip->add_vertex(1);
1314  strip->add_vertex(6);
1315  strip->add_vertex(2);
1316  strip->add_vertex(5);
1317  strip->close_primitive();
1318 
1319  strip->add_vertex(5);
1320  strip->add_vertex(4);
1321  strip->add_vertex(2);
1322  strip->add_vertex(3);
1323  strip->add_vertex(1);
1324  strip->add_vertex(0);
1325  strip->add_vertex(6);
1326  strip->add_vertex(7);
1327  strip->add_vertex(5);
1328  strip->add_vertex(4);
1329  strip->close_primitive();
1330  }
1331 
1332  PT(Geom) geom = new Geom(vdata);
1333  geom->add_primitive(strip);
1334 
1335  card_node->add_geom(geom);
1336 
1337  return card_node;
1338 }
1339 
1340 /**
1341  * Creates an onscreen animation slider for frame-stepping through the
1342  * animations.
1343  */
1344 void WindowFramework::
1345 create_anim_controls() {
1346  destroy_anim_controls();
1347 
1348  PT(PGItem) group = new PGItem("anim_controls_group");
1349  PGFrameStyle style;
1350  style.set_type(PGFrameStyle::T_flat);
1351  style.set_color(0.0f, 0.0f, 0.0f, 0.3);
1352  group->set_frame(-1.0f, 1.0f, 0.0f, 0.2);
1353  group->set_frame_style(0, style);
1354  group->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
1355  group->set_active(true);
1356 
1357  _anim_controls_group = get_aspect_2d().attach_new_node(group);
1358  _anim_controls_group.set_pos(0.0f, 0.0f, -0.9f);
1359 
1360  if (_anim_index >= _anim_controls.get_num_anims()) {
1361  PT(TextNode) label = new TextNode("label");
1362  label->set_align(TextNode::A_center);
1363  label->set_text("No animation.");
1364  NodePath tnp = _anim_controls_group.attach_new_node(label);
1365  tnp.set_pos(0.0f, 0.0f, 0.07f);
1366  tnp.set_scale(0.1f);
1367 
1368  return;
1369  }
1370 
1371  AnimControl *control = _anim_controls.get_anim(_anim_index);
1372  nassertv(control != nullptr);
1373 
1374  if (control->get_num_frames() <= 1) {
1375  // Don't show the controls when the animation has only 0 or 1 frames.
1376  ostringstream text;
1377  text << _anim_controls.get_anim_name(_anim_index);
1378  text << " (" << control->get_num_frames() << " frame"
1379  << ((control->get_num_frames() == 1) ? "" : "s") << ")";
1380 
1381  PT(TextNode) label = new TextNode("label");
1382  label->set_align(TextNode::A_center);
1383  label->set_text(text.str());
1384  NodePath tnp = _anim_controls_group.attach_new_node(label);
1385  tnp.set_pos(0.0f, 0.0f, 0.07f);
1386  tnp.set_scale(0.1f);
1387 
1388  return;
1389  }
1390 
1391  PT(TextNode) label = new TextNode("anim_name");
1392  label->set_align(TextNode::A_left);
1393  label->set_text(_anim_controls.get_anim_name(_anim_index));
1394  NodePath tnp = _anim_controls_group.attach_new_node(label);
1395  tnp.set_pos(-0.95f, 0.0f, 0.15f);
1396  tnp.set_scale(0.05f);
1397 
1398  _anim_slider = new PGSliderBar("anim_slider");
1399  _anim_slider->setup_slider(false, 1.9f, 0.1f, 0.005f);
1400  _anim_slider->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
1401  _anim_slider->get_thumb_button()->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
1402 
1403  _anim_slider->set_range(0.0f, (PN_stdfloat)(control->get_num_frames() - 1));
1404  _anim_slider->set_scroll_size(0.0f);
1405  _anim_slider->set_page_size(1.0f);
1406  NodePath snp = _anim_controls_group.attach_new_node(_anim_slider);
1407  snp.set_pos(0.0f, 0.0f, 0.06f);
1408 
1409  _frame_number = new TextNode("frame_number");
1410  _frame_number->set_text_color(0.0f, 0.0f, 0.0f, 1.0f);
1411  _frame_number->set_align(TextNode::A_center);
1412  _frame_number->set_text(format_string(control->get_frame()));
1413  NodePath fnp = NodePath(_anim_slider->get_thumb_button()).attach_new_node(_frame_number);
1414  fnp.set_scale(0.05f);
1415  fnp.set_pos(0.0f, 0.0f, -0.01f);
1416 
1417  _play_rate_slider = new PGSliderBar("play_rate_slider");
1418  _play_rate_slider->setup_slider(false, 0.4, 0.05f, 0.005f);
1419  _play_rate_slider->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
1420  _play_rate_slider->get_thumb_button()->set_suppress_flags(MouseWatcherRegion::SF_mouse_button);
1421  _play_rate_slider->set_value(control->get_play_rate());
1422  NodePath pnp = _anim_controls_group.attach_new_node(_play_rate_slider);
1423  pnp.set_pos(0.75f, 0.0f, 0.15f);
1424 
1425  // Set up the jogshuttle buttons. These use symbols from the
1426  // shuttle_controls_font file.
1427  setup_shuttle_button("9", 0, st_back_button);
1428  setup_shuttle_button(";", 1, st_pause_button);
1429  setup_shuttle_button("4", 2, st_play_button);
1430  setup_shuttle_button(":", 3, st_forward_button);
1431 
1432  _update_anim_controls_task = new GenericAsyncTask("controls", st_update_anim_controls, (void *)this);
1433  _panda_framework->get_task_mgr().add(_update_anim_controls_task);
1434 }
1435 
1436 /**
1437  * Removes the previously-created anim controls, if any.
1438  */
1439 void WindowFramework::
1440 destroy_anim_controls() {
1441  if (!_anim_controls_group.is_empty()) {
1442  _anim_controls_group.remove_node();
1443 
1444  _panda_framework->get_event_handler().remove_hooks_with((void *)this);
1445  if (_update_anim_controls_task != nullptr) {
1446  _panda_framework->get_task_mgr().remove(_update_anim_controls_task);
1447  _update_anim_controls_task.clear();
1448  }
1449  }
1450 }
1451 
1452 /**
1453  * A per-frame callback to update the anim slider for the current frame.
1454  */
1455 void WindowFramework::
1456 update_anim_controls() {
1457  AnimControl *control = _anim_controls.get_anim(_anim_index);
1458  nassertv(control != nullptr);
1459 
1460  if (_anim_slider != nullptr) {
1461  if (_anim_slider->is_button_down()) {
1462  control->pose((int)(_anim_slider->get_value() + 0.5));
1463  } else {
1464  _anim_slider->set_value((PN_stdfloat)control->get_frame());
1465  }
1466  }
1467 
1468  if (_frame_number != nullptr) {
1469  _frame_number->set_text(format_string(control->get_frame()));
1470  }
1471 
1472  control->set_play_rate(_play_rate_slider->get_value());
1473 }
1474 
1475 /**
1476  * Creates a PGButton to implement the indicated shuttle event (play, pause,
1477  * etc.).
1478  */
1479 void WindowFramework::
1480 setup_shuttle_button(const string &label, int index,
1481  EventHandler::EventCallbackFunction *func) {
1482  PT(PGButton) button = new PGButton(label);
1483  button->set_frame(-0.05f, 0.05f, 0.0f, 0.07f);
1484 
1485  PN_stdfloat bevel = 0.005f;
1486 
1487  PGFrameStyle style;
1488  style.set_color(0.8f, 0.8f, 0.8f, 1.0f);
1489  style.set_width(bevel, bevel);
1490 
1491  style.set_type(PGFrameStyle::T_bevel_out);
1492  button->set_frame_style(PGButton::S_ready, style);
1493 
1494  style.set_type(PGFrameStyle::T_bevel_in);
1495  button->set_frame_style(PGButton::S_depressed, style);
1496 
1497  style.set_color(0.9f, 0.9f, 0.9f, 1.0f);
1498  style.set_type(PGFrameStyle::T_bevel_out);
1499  button->set_frame_style(PGButton::S_rollover, style);
1500 
1501  if (get_shuttle_controls_font() != nullptr) {
1502  PT(TextNode) tn = new TextNode("label");
1503  tn->set_align(TextNode::A_center);
1504  tn->set_font(get_shuttle_controls_font());
1505  tn->set_text(label);
1506  tn->set_text_color(0.0f, 0.0f, 0.0f, 1.0f);
1507  LMatrix4 xform = LMatrix4::scale_mat(0.07f);
1508  xform.set_row(3, LVecBase3(0.0f, 0.0f, 0.016f));
1509  tn->set_transform(xform);
1510 
1511  button->get_state_def(PGButton::S_ready).attach_new_node(tn);
1512  button->get_state_def(PGButton::S_depressed).attach_new_node(tn);
1513  button->get_state_def(PGButton::S_rollover).attach_new_node(tn);
1514  }
1515 
1516  NodePath np = _anim_controls_group.attach_new_node(button);
1517  np.set_pos(0.1f * index - 0.15f, 0.0f, 0.12);
1518 
1519  _panda_framework->get_event_handler().add_hook(button->get_click_event(MouseButton::one()), func, (void *)this);
1520 }
1521 
1522 /**
1523  * Handler for a shuttle button.
1524  */
1525 void WindowFramework::
1526 back_button() {
1527  AnimControl *control = _anim_controls.get_anim(_anim_index);
1528  nassertv(control != nullptr);
1529  control->pose(control->get_frame() - 1);
1530 }
1531 
1532 /**
1533  * Handler for a shuttle button.
1534  */
1535 void WindowFramework::
1536 pause_button() {
1537  AnimControl *control = _anim_controls.get_anim(_anim_index);
1538  nassertv(control != nullptr);
1539  control->stop();
1540 }
1541 
1542 /**
1543  * Handler for a shuttle button.
1544  */
1545 void WindowFramework::
1546 play_button() {
1547  AnimControl *control = _anim_controls.get_anim(_anim_index);
1548  nassertv(control != nullptr);
1549  control->loop(false);
1550 }
1551 
1552 /**
1553  * Handler for a shuttle button.
1554  */
1555 void WindowFramework::
1556 forward_button() {
1557  AnimControl *control = _anim_controls.get_anim(_anim_index);
1558  nassertv(control != nullptr);
1559  control->pose(control->get_frame() + 1);
1560 }
1561 
1562 
1563 /**
1564  * The static task function.
1565  */
1566 AsyncTask::DoneStatus WindowFramework::
1567 st_update_anim_controls(GenericAsyncTask *, void *data) {
1568  WindowFramework *self = (WindowFramework *)data;
1569  self->update_anim_controls();
1570  return AsyncTask::DS_cont;
1571 }
1572 
1573 
1574 /**
1575  * The static event handler function.
1576  */
1577 void WindowFramework::
1578 st_back_button(const Event *, void *data) {
1579  WindowFramework *self = (WindowFramework *)data;
1580  self->back_button();
1581 }
1582 
1583 /**
1584  * The static event handler function.
1585  */
1586 void WindowFramework::
1587 st_pause_button(const Event *, void *data) {
1588  WindowFramework *self = (WindowFramework *)data;
1589  self->pause_button();
1590 }
1591 
1592 /**
1593  * The static event handler function.
1594  */
1595 void WindowFramework::
1596 st_play_button(const Event *, void *data) {
1597  WindowFramework *self = (WindowFramework *)data;
1598  self->play_button();
1599 }
1600 
1601 /**
1602  * The static event handler function.
1603  */
1604 void WindowFramework::
1605 st_forward_button(const Event *, void *data) {
1606  WindowFramework *self = (WindowFramework *)data;
1607  self->forward_button();
1608 }
The principle public interface to reading and writing Bam disk files.
Definition: bamFile.h:41
A light shining from infinitely far away in a particular direction, like sunlight.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(PandaNode) WindowFramework
Loads the indicated image file as a texture, and creates a polygon to render it.
void clear_two_sided()
Completely removes any two-sided adjustment that may have been set on this node via set_two_sided().
Definition: nodePath.cxx:4449
The "top" node of the new Panda GUI system.
Definition: pgTop.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This TFormer maintains a list of rectangular regions on the screen that are considered special mouse ...
Definition: mouseWatcher.h:61
void set_depth_test(bool depth_test, int priority=0)
Specifically sets or disables the testing of the depth buffer on this particular node.
Definition: nodePath.cxx:4491
set_color
Sets the basic color of the light.
Definition: light.h:49
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
NodePath get_render_2d()
Returns the root of the 2-d scene graph.
get_play_rate
Returns the rate at which the animation plays.
Definition: animInterface.h:66
void set_width(PN_stdfloat x, PN_stdfloat y)
Sets the width parameter, which has meaning only for certain frame types.
Definition: pgFrameStyle.I:139
void stagger_animations()
Walks through all the animations that were bound by loop_animations() and staggers their play rate sl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool open_read(const Filename &bam_filename, bool report_errors=true)
Attempts to open the indicated filename for reading.
Definition: bamFile.cxx:51
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Indicates a coordinate-system transform on vertices.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a special TextNode that automatically updates itself with output from a SceneGraphAnalyzer in...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool remove(AsyncTask *task)
Removes the indicated task from the active queue.
This class monitors the state of a number of individual buttons and tracks whether each button is kno...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:58
void loop_animations(int hierarchy_match_flags=PartGroup::HMF_ok_part_extra|PartGroup::HMF_ok_anim_extra)
Looks for characters and their matching animation files in the scene graph; binds and loops any match...
get_anim
Returns the nth AnimControl associated with this collection.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
void write_texture_types(std::ostream &out, int indent_level) const
Outputs a list of the available texture types to the indicated output stream.
void set_perpixel(bool enable)
Turns per-pixel lighting on (true) or off (false).
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MakeTextureFunc * get_texture_type(const std::string &extension) const
Returns the factory function to construct a new texture of the type appropriate for the indicated fil...
Definition: texturePool.cxx:84
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
NodePath get_pixel_2d()
Returns a special root that uses units in pixels that are relative to the window.
This is the base class for all the various kinds of gui widget objects.
Definition: pgItem.h:53
void set_depth_write(bool depth_write, int priority=0)
Specifically sets or disables the writing to the depth buffer on this particular node.
Definition: nodePath.cxx:4548
An optional parameter associated with an event.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath get_render()
Returns the root of the 3-d scene graph.
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
A hierarchy of directories and files that appears to be one continuous file system,...
NodePath get_aspect_2d()
Returns the node under the 2-d scene graph that is scaled to suit the window's aspect ratio.
static LoaderFileTypeRegistry * get_global_ptr()
Returns a pointer to the global LoaderFileTypeRegistry object.
This defines a bounding sphere, consisting of a center and a radius.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
void set_scale(PN_stdfloat scale)
Sets the scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.I:675
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
void loop(bool restart)
Starts the entire animation looping.
Definition: animInterface.I:45
void add_data2(PN_stdfloat x, PN_stdfloat y)
Sets the write row to a particular 2-component value, and advances the write row.
This encapsulates the data that is normally associated with a single window, or with a single display...
This is a particular kind of PGItem that is specialized to behave like a normal button object.
Definition: pgButton.h:29
void set_type(Type type)
Sets the basic type of frame.
Definition: pgFrameStyle.I:64
void set_clear_color_active(bool clear_color_active)
Toggles the flag that indicates whether the color buffer should be cleared every frame.
Trackball acts like Performer in trackball mode.
Definition: trackball.h:35
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
Definition: pnmImage.cxx:278
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A convenient class for loading models from disk, in bam or egg format (or any of a number of other fo...
Definition: loader.h:42
void set_anim_controls(bool enable)
Creates an onscreen animation slider for frame-stepping through the animations.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static ButtonHandle one()
Returns the ButtonHandle associated with the first mouse button.
Definition: mouseButton.cxx:43
void set_lighting(bool enable)
Turns lighting on (true) or off (false).
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of triangle strips.
Definition: geomTristrips.h:23
A light source that seems to illuminate all points in space at once.
Definition: ambientLight.h:26
void stop()
Stops a currently playing or looping animation right where it is.
Definition: animInterface.I:91
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void loop_all(bool restart)
Starts all animations looping.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
Definition: filename.I:562
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath load_default_model(const NodePath &parent)
Loads our favorite blue triangle.
DisplayRegion * make_display_region()
Creates a new DisplayRegion that covers the entire window.
set_aspect_ratio
Sets the aspect ratio of the lens.
Definition: lens.h:106
GraphicsOutput * make_output(GraphicsPipe *pipe, const std::string &name, int sort, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, int flags, GraphicsStateGuardian *gsg=nullptr, GraphicsOutput *host=nullptr)
Creates a new window (or buffer) and returns it.
static PN_stdfloat get_default_far()
Returns the default far plane distance that will be assigned to each newly- created lens.
Definition: lens.cxx:157
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
void set_wireframe(bool enable, bool filled=false)
Forces wireframe state (true) or restores default rendering (false).
void set_one_sided_reverse(bool enable)
Toggles one-sided reverse mode.
An encapsulation of a font; i.e.
Definition: textFont.h:32
get_num_anims
Returns the number of AnimControls associated with this collection.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
NodePath get_mouse()
Returns the node in the data graph corresponding to the mouse associated with this window.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void clear_light()
Completely removes any lighting operations that may have been set via set_light() or set_light_off() ...
Definition: nodePath.cxx:2306
get_fov
Returns the horizontal and vertical film size of the virtual film.
Definition: lens.h:101
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A StaticTextFont is loaded up from a model that was previously generated via egg-mkfont,...
NodePath load_model(const NodePath &parent, Filename filename)
Loads up the indicated model and returns the new NodePath, or the empty NodePath if the model could n...
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
set_near
Defines the position of the near plane (or cylinder, sphere, whatever).
Definition: lens.h:113
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_film_size
Sets the horizontal size of the film without changing its shape.
Definition: lens.h:82
NodePath get_mouse(GraphicsOutput *window)
Returns a NodePath to the MouseAndKeyboard associated with the indicated GraphicsWindow object.
bool add_button(ButtonHandle button)
Adds the indicated button to the set of buttons that will be monitored for upness and downness.
bool add_hook(const std::string &event_name, EventFunction *function)
Adds the indicated function to the list of those that will be called when the named event is thrown.
bool remove_hooks_with(void *data)
Removes all CallbackFunction hooks that have the indicated pointer as the associated data pointer.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_two_sided(bool enable)
Forces two-sided rendering (true) or restores default rendering (false).
void add(AsyncTask *task)
Adds the indicated task to the active queue.
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:563
void adjust_dimensions()
Reevaluates the dimensions of the window, presumably after the window has been resized by the user or...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void center_trackball(const NodePath &object)
Centers the trackball on the indicated object, and scales the trackball motion suitably.
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a)
Sets the dominant color of the frame.
Definition: pgFrameStyle.I:80
A perspective-type lens: a normal camera.
void clear_render_mode()
Completely removes any render mode adjustment that may have been set on this node via set_render_mode...
Definition: nodePath.cxx:4357
void next_anim_control()
Rotates the animation controls through all of the available animations.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
Definition: geom.h:54
void add_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row.
Associates a generic C-style function pointer with an AsyncTask object.
void clear_color_scale()
Completely removes any color scale from the referenced node.
Definition: nodePath.cxx:2040
static PN_stdfloat get_default_near()
Returns the default near plane distance that will be assigned to each newly-created lens.
Definition: lens.cxx:148
void enable_keyboard()
Creates a ButtonThrower to listen to button presses and throw them as events.
NodePath make_camera()
Makes a new 3-d camera for the window.
static Texture * load_texture(const Filename &filename, int primary_file_num_channels=0, bool read_mipmaps=false, const LoaderOptions &options=LoaderOptions())
Loads the given filename up into a texture, if it has not already been loaded, and returns the new te...
Definition: texturePool.I:47
AsyncTaskManager & get_task_mgr()
Returns the Task Manager object that manages tasks in the framework.
This class maintains the set of all known LoaderFileTypes in the universe.
void set_background_type(WindowFramework::BackgroundType type)
Sets the background type of all windows.
void clear_texture()
Completely removes any texture adjustment that may have been set via set_texture() or set_texture_off...
Definition: nodePath.cxx:3002
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear()
Sets this NodePath to the empty NodePath.
Definition: nodePath.I:119
This is a base class for the various different classes that represent the result of a frame of render...
static TexturePool * get_global_ptr()
Initializes and/or returns the global pointer to the one TexturePool object in the system.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_frame
Returns the current integer frame number.
Definition: animInterface.h:70
void set_attrib(const RenderAttrib *attrib, int override=0)
Adds the indicated render attribute to the scene graph on this node.
Definition: pandaNode.cxx:944
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
void set_light(const NodePath &light, int priority=0)
Adds the indicated Light or PolylightNode to the list of lights that illuminate geometry at this node...
Definition: nodePath.cxx:2194
static TextFont * get_shuttle_controls_font()
Returns a font that contains the shuttle controls icons.
An orthographic lens.
This class defines the physical layout of the vertex data stored within a Geom.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
input: Transform (matrix)
Definition: transform2sg.h:28
void set_background_type(BackgroundType type)
Sets the background of the window to one of the pre-canned background types (or to BT_other,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_texture_off(int priority=0)
Sets the geometry at this level and below to render using no texture, on any stage.
Definition: nodePath.cxx:2961
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static NodePath not_found()
Creates a NodePath with the ET_not_found error type set.
Definition: nodePath.I:129
LoaderFileType * get_type_from_extension(const std::string &extension)
Determines the type of the file based on the indicated extension (without a leading dot).
EventHandler & get_event_handler()
Returns the EventHandler object that serves events in the framework.
void set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Sets the rotation component of the transform, leaving translation and scale untouched.
Definition: nodePath.I:651
void set_render_mode_wireframe(int priority=0)
Sets up the geometry at this level and below (unless overridden) to render in wireframe mode.
Definition: nodePath.cxx:4275
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
void set_texture(bool enable)
Forces textures off (false) or restores default rendering (true).
NodePath get_button_thrower()
Returns the node in the data graph corresponding to the ButtonThrower object associated with this win...
This is the base class for a family of scene-graph file types that the Loader supports.
get_window
Returns the GraphicsOutput that this DisplayRegion is ultimately associated with, or NULL if no windo...
Definition: displayRegion.h:88
A named event, possibly with parameters.
Definition: event.h:33
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
bool load_models(const NodePath &parent, int argc, char *argv[], int first_arg=1)
Loads up all the model files listed in the indicated argument list.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_material_off(int priority=0)
Sets the geometry at this level and below to render using no material.
Definition: nodePath.cxx:4113
The primary interface to this module.
Definition: textNode.h:48
Encapsulates all the communication with a particular instance of a given rendering backend.
This is a special TextNode that automatically updates itself with the current frame rate.
This describes the structure of a single array within a Geom data.
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
get_num_frames
Returns the number of frames in the animation.
Definition: animInterface.h:68
void pose(double frame)
Sets the animation to the indicated frame and holds it there.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
WindowFramework * split_window(SplitType split_type=ST_default)
Divides the window into two display regions, each of which gets its own trackball and keyboard events...
Controls the timing of a character animation.
Definition: animControl.h:38
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:57
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static const GeomVertexFormat * get_v3n3cpt2()
Returns a standard vertex format with a 2-component texture coordinate pair, a packed color,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_far
Defines the position of the far plane (or cylinder, sphere, whatever).
Definition: lens.h:114
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class serves to provide a high-level framework for basic applications that use Panda in simple w...
static const GeomVertexFormat * get_v3t2()
Returns a standard vertex format with a 2-component texture coordinate pair and a 3-component vertex ...
void auto_bind(PandaNode *root_node, AnimControlCollection &controls, int hierarchy_match_flags)
Walks the scene graph or subgraph beginning at the indicated node, and attempts to bind any AnimBundl...
Definition: auto_bind.cxx:123
This class is the main interface to controlling the render process.
void setup_trackball()
Sets up the mouse to trackball around the camera.
This is the preferred interface for loading textures from image files.
Definition: texturePool.h:37
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
set_dimensions
Changes the portion of the framebuffer this DisplayRegion corresponds to.
Definition: displayRegion.h:83
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Throws Panda Events for button down/up events generated within the data graph.
Definition: buttonThrower.h:35
NodePath get_camera_group()
Returns the node above the collection of 3-d cameras in the scene graph.
void set_two_sided(bool two_sided, int priority=0)
Specifically sets or disables two-sided rendering mode on this particular node.
Definition: nodePath.cxx:4430
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
get_anim_name
Returns the name of the nth AnimControl associated with this collection.
void set_color_scale(const LVecBase4 &scale, int priority=0)
Sets the color scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.cxx:2080
void add_geom(Geom *geom, const RenderState *state=RenderState::make_empty())
Adds a new Geom to the node.
Definition: geomNode.cxx:584
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition: filename.cxx:328
void set_mouse_watcher(MouseWatcher *watcher)
Sets the MouseWatcher pointer that the PGTop object registers its PG items with.
Definition: pgTop.cxx:132
set_play_rate
Changes the rate at which the animation plays.
Definition: animInterface.h:66
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a particular kind of PGItem that draws a little bar with a slider that moves from left to rig...
Definition: pgSliderBar.h:31
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.