Panda3D
 All Classes Functions Variables Enumerations
displayRegion.cxx
1 // Filename: displayRegion.cxx
2 // Created by: cary (10Feb99)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "displayRegion.h"
16 #include "stereoDisplayRegion.h"
17 #include "graphicsEngine.h"
18 #include "graphicsOutput.h"
19 #include "config_display.h"
20 #include "texture.h"
21 #include "camera.h"
22 #include "dcast.h"
23 #include "pnmImage.h"
24 
25 #include <time.h>
26 
27 TypeHandle DisplayRegion::_type_handle;
28 TypeHandle DisplayRegionPipelineReader::_type_handle;
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: DisplayRegion::Constructor
32 // Access: Protected
33 // Description:
34 ////////////////////////////////////////////////////////////////////
35 DisplayRegion::
36 DisplayRegion(GraphicsOutput *window, const LVecBase4 &dimensions) :
37  _window(window),
38  _incomplete_render(true),
39  _texture_reload_priority(0),
40  _cull_region_pcollector("Cull:Invalid"),
41  _draw_region_pcollector("Draw:Invalid")
42 {
43  _screenshot_buffer_type = window->get_draw_buffer_type();
44  _draw_buffer_type = window->get_draw_buffer_type();
45  set_num_regions(1);
46  set_dimensions(0, dimensions);
47  compute_pixels_all_stages();
48 
49  _window->add_display_region(this);
50 }
51 
52 ////////////////////////////////////////////////////////////////////
53 // Function: DisplayRegion::Copy Constructor
54 // Access: Private
55 // Description:
56 ////////////////////////////////////////////////////////////////////
57 DisplayRegion::
58 DisplayRegion(const DisplayRegion &copy) :
59  _window(NULL),
60  _cull_region_pcollector("Cull:Invalid"),
61  _draw_region_pcollector("Draw:Invalid")
62 {
63 }
64 
65 ////////////////////////////////////////////////////////////////////
66 // Function: DisplayRegion::Copy Assignment Operator
67 // Access: Private
68 // Description:
69 ////////////////////////////////////////////////////////////////////
70 void DisplayRegion::
71 operator = (const DisplayRegion&) {
72  nassertv(false);
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: DisplayRegion::Destructor
77 // Access: Public, Virtual
78 // Description:
79 ////////////////////////////////////////////////////////////////////
80 DisplayRegion::
81 ~DisplayRegion() {
82  cleanup();
83 
84  // The window pointer should already have been cleared by the time
85  // the DisplayRegion destructs (since the GraphicsOutput class keeps
86  // a reference count on the DisplayRegion).
87  nassertv(_window == (GraphicsOutput *)NULL);
88 }
89 
90 ////////////////////////////////////////////////////////////////////
91 // Function: DisplayRegion::cleanup
92 // Access: Public
93 // Description: Cleans up some pointers associated with the
94 // DisplayRegion to help reduce the chance of memory
95 // leaks due to circular reference counts.
96 ////////////////////////////////////////////////////////////////////
97 void DisplayRegion::
100 
101  CDCullWriter cdata(_cycler_cull, true);
102  cdata->_cull_result = NULL;
103 }
104 
105 ////////////////////////////////////////////////////////////////////
106 // Function: DisplayRegion::set_lens_index
107 // Access: Published
108 // Description: Sets the lens index, allows for multiple lenses to
109 // be attached to a camera. This is useful for a
110 // variety of setups, such as fish eye rendering.
111 // The default is 0.
112 ////////////////////////////////////////////////////////////////////
113 void DisplayRegion::
114 set_lens_index(int index) {
115  int pipeline_stage = Thread::get_current_pipeline_stage();
116  nassertv(pipeline_stage == 0);
117  CDWriter cdata(_cycler);
118  cdata->_lens_index = index;
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: DisplayRegion::set_dimensions
123 // Access: Published, Virtual
124 // Description: Changes the portion of the framebuffer this
125 // DisplayRegion corresponds to. The parameters range
126 // from 0 to 1, where 0,0 is the lower left corner and
127 // 1,1 is the upper right; (0, 1, 0, 1) represents the
128 // whole screen.
129 ////////////////////////////////////////////////////////////////////
130 void DisplayRegion::
131 set_dimensions(int i, const LVecBase4 &dimensions) {
132  int pipeline_stage = Thread::get_current_pipeline_stage();
133  nassertv(pipeline_stage == 0);
134  CDWriter cdata(_cycler);
135 
136  cdata->_regions[i]._dimensions = dimensions;
137 
138  if (_window != (GraphicsOutput *)NULL && _window->has_size()) {
139  do_compute_pixels(i, _window->get_fb_x_size(), _window->get_fb_y_size(), cdata);
140  }
141 }
142 
143 ////////////////////////////////////////////////////////////////////
144 // Function: DisplayRegion::get_pipe
145 // Access: Published
146 // Description: Returns the GraphicsPipe that this DisplayRegion is
147 // ultimately associated with, or NULL if no pipe is
148 // associated.
149 ////////////////////////////////////////////////////////////////////
151 get_pipe() const {
152  return (_window != (GraphicsOutput *)NULL) ? _window->get_pipe() : NULL;
153 }
154 
155 ////////////////////////////////////////////////////////////////////
156 // Function: DisplayRegion::is_stereo
157 // Access: Published, Virtual
158 // Description: Returns true if this is a StereoDisplayRegion, false
159 // otherwise.
160 ////////////////////////////////////////////////////////////////////
161 bool DisplayRegion::
162 is_stereo() const {
163  return false;
164 }
165 
166 ////////////////////////////////////////////////////////////////////
167 // Function: DisplayRegion::set_camera
168 // Access: Published, Virtual
169 // Description: Sets the camera that is associated with this
170 // DisplayRegion. There is a one-to-many association
171 // between cameras and DisplayRegions; one camera may be
172 // shared by multiple DisplayRegions.
173 //
174 // The camera is actually set via a NodePath, which
175 // clarifies which instance of the camera (if there
176 // happen to be multiple instances) we should use.
177 ////////////////////////////////////////////////////////////////////
178 void DisplayRegion::
179 set_camera(const NodePath &camera) {
180  int pipeline_stage = Thread::get_current_pipeline_stage();
181 
182  // We allow set_camera(NodePath()) to happen in cleanup(), which can
183  // be called from any pipeline stage.
184  nassertv(pipeline_stage == 0 || camera.is_empty());
185  CDStageWriter cdata(_cycler, 0);
186 
187  Camera *camera_node = (Camera *)NULL;
188  if (!camera.is_empty()) {
189  DCAST_INTO_V(camera_node, camera.node());
190  }
191 
192  if (camera_node != cdata->_camera_node) {
193  // Note that these operations on the DisplayRegion are not
194  // pipelined: they operate across all pipeline stages. Since we
195  // have already asserted we are running in pipeline stage 0, no
196  // problem.
197  if (cdata->_camera_node != (Camera *)NULL) {
198  // We need to tell the old camera we're not using him anymore.
199  cdata->_camera_node->remove_display_region(this);
200  }
201  cdata->_camera_node = camera_node;
202  if (cdata->_camera_node != (Camera *)NULL) {
203  // Now tell the new camera we are using him.
204  cdata->_camera_node->add_display_region(this);
205  }
206  }
207 
208  cdata->_camera = camera;
209 }
210 
211 ////////////////////////////////////////////////////////////////////
212 // Function: DisplayRegion::set_active
213 // Access: Published, Virtual
214 // Description: Sets the active flag associated with the
215 // DisplayRegion. If the DisplayRegion is marked
216 // inactive, nothing is rendered.
217 ////////////////////////////////////////////////////////////////////
218 void DisplayRegion::
219 set_active(bool active) {
220  int pipeline_stage = Thread::get_current_pipeline_stage();
221  nassertv(pipeline_stage == 0);
222  CDLockedReader cdata(_cycler);
223 
224  if (active != cdata->_active) {
225  CDWriter cdataw(_cycler, cdata);
226  cdataw->_active = active;
227  win_display_regions_changed();
228  }
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: DisplayRegion::set_sort
233 // Access: Published, Virtual
234 // Description: Sets the sort value associated with the
235 // DisplayRegion. Within a window, DisplayRegions will
236 // be rendered in order from the lowest sort value to
237 // the highest.
238 ////////////////////////////////////////////////////////////////////
239 void DisplayRegion::
240 set_sort(int sort) {
241  nassertv(Thread::get_current_pipeline_stage() == 0);
242  CDLockedReader cdata(_cycler);
243 
244  if (sort != cdata->_sort) {
245  CDWriter cdataw(_cycler, cdata);
246  cdataw->_sort = sort;
247  win_display_regions_changed();
248  }
249 }
250 
251 ////////////////////////////////////////////////////////////////////
252 // Function: DisplayRegion::set_stereo_channel
253 // Access: Published, Virtual
254 // Description: Specifies whether the DisplayRegion represents the
255 // left or right channel of a stereo pair, or whether it
256 // is a normal, monocular image. This automatically
257 // adjusts the lens that is used to render to this
258 // DisplayRegion to its left or right eye, according to
259 // the lens's stereo properties.
260 //
261 // When the DisplayRegion is attached to a stereo window
262 // (one for which is_stereo() returns true), this also
263 // specifies which physical channel the DisplayRegion
264 // renders to.
265 //
266 // Normally you would create at least two DisplayRegions
267 // for a stereo window, one for each of the left and
268 // right channels. The two DisplayRegions may share the
269 // same camera (and thus the same lens); this parameter
270 // is used to control the exact properties of the lens
271 // when it is used to render into this DisplayRegion.
272 //
273 // Also see the StereoDisplayRegion, which automates
274 // managing a pair of left/right DisplayRegions.
275 //
276 // An ordinary DisplayRegion may be set to SC_mono,
277 // SC_left, or SC_right. You may set SC_stereo only on
278 // a StereoDisplayRegion.
279 //
280 // This call also resets tex_view_offset to its default
281 // value, which is 0 for the left eye or 1 for the right
282 // eye of a stereo display region, or 0 for a mono
283 // display region.
284 ////////////////////////////////////////////////////////////////////
285 void DisplayRegion::
286 set_stereo_channel(Lens::StereoChannel stereo_channel) {
287  nassertv(is_stereo() || stereo_channel != Lens::SC_stereo);
288 
289  nassertv(Thread::get_current_pipeline_stage() == 0);
290 
291  CDWriter cdata(_cycler);
292  cdata->_stereo_channel = stereo_channel;
293  cdata->_tex_view_offset = (stereo_channel == Lens::SC_right) ? 1 : 0;
294 }
295 
296 ////////////////////////////////////////////////////////////////////
297 // Function: DisplayRegion::set_tex_view_offset
298 // Access: Published, Virtual
299 // Description: Sets the current texture view offset for this
300 // DisplayRegion. This is normally set to zero. If
301 // nonzero, it is used to select a particular view of
302 // any multiview textures that are rendered within this
303 // DisplayRegion.
304 //
305 // For a StereoDisplayRegion, this is normally 0 for the
306 // left eye, and 1 for the right eye, to support stereo
307 // textures. This is set automatically when you call
308 // set_stereo_channel().
309 ////////////////////////////////////////////////////////////////////
310 void DisplayRegion::
311 set_tex_view_offset(int tex_view_offset) {
312  nassertv(Thread::get_current_pipeline_stage() == 0);
313 
314  CDWriter cdata(_cycler);
315  cdata->_tex_view_offset = tex_view_offset;
316 }
317 
318 ////////////////////////////////////////////////////////////////////
319 // Function: DisplayRegion::set_incomplete_render
320 // Access: Published, Virtual
321 // Description: Sets the incomplete_render flag. When this is
322 // true, the frame will be rendered even if some of the
323 // geometry or textures in the scene are not available
324 // (e.g. they have been temporarily paged out). When
325 // this is false, the frame will be held up while this
326 // data is reloaded.
327 //
328 // This flag may also be set on the
329 // GraphicsStateGuardian. It will be considered true
330 // for a given DisplayRegion only if it is true on both
331 // the GSG and on the DisplayRegion.
332 //
333 // See GraphicsStateGuardian::set_incomplete_render()
334 // for more detail.
335 ////////////////////////////////////////////////////////////////////
336 void DisplayRegion::
337 set_incomplete_render(bool incomplete_render) {
338  _incomplete_render = incomplete_render;
339 }
340 
341 ////////////////////////////////////////////////////////////////////
342 // Function: DisplayRegion::set_texture_reload_priority
343 // Access: Published, Virtual
344 // Description: Specifies an integer priority which is assigned to
345 // any asynchronous texture reload requests spawned
346 // while processing this DisplayRegion. This controls
347 // which textures are loaded first when multiple
348 // textures need to be reloaded at once; it also
349 // controls the relative priority between asynchronous
350 // texture loads and asynchronous model or animation
351 // loads.
352 //
353 // Specifying a larger number here makes the textures
354 // rendered by this DisplayRegion load up first. This
355 // may be particularly useful to do, for instance, for
356 // the DisplayRegion that renders the gui.
357 ////////////////////////////////////////////////////////////////////
358 void DisplayRegion::
359 set_texture_reload_priority(int texture_reload_priority) {
360  _texture_reload_priority = texture_reload_priority;
361 }
362 
363 ////////////////////////////////////////////////////////////////////
364 // Function: DisplayRegion::set_cull_traverser
365 // Access: Published, Virtual
366 // Description: Specifies the CullTraverser that will be used to draw
367 // the contents of this DisplayRegion. Normally the
368 // default CullTraverser is sufficient, but this may be
369 // changed to change the default cull behavior.
370 ////////////////////////////////////////////////////////////////////
371 void DisplayRegion::
373  _trav = trav;
374 }
375 
376 ////////////////////////////////////////////////////////////////////
377 // Function: DisplayRegion::get_cull_traverser
378 // Access: Published
379 // Description: Returns the CullTraverser that will be used to draw
380 // the contents of this DisplayRegion.
381 ////////////////////////////////////////////////////////////////////
384  if (_trav == (CullTraverser *)NULL) {
385  _trav = new CullTraverser;
386  }
387  return _trav;
388 }
389 
390 ////////////////////////////////////////////////////////////////////
391 // Function: DisplayRegion::set_target_tex_page
392 // Access: Published, Virtual
393 // Description: This is a special parameter that is only used when
394 // rendering the faces of a cube map or multipage and/or
395 // multiview texture.
396 //
397 // This sets up the DisplayRegion to render to the ith
398 // page and jth view of its associated texture(s); the
399 // value must be consistent with the range of values
400 // availble to the texture. A normal DisplayRegion that
401 // is not associated with any particular page should be
402 // set to page -1 and view 0.
403 //
404 // This is particularly useful when rendering cube maps
405 // and/or stereo textures.
406 ////////////////////////////////////////////////////////////////////
407 void DisplayRegion::
409  int pipeline_stage = Thread::get_current_pipeline_stage();
410  nassertv(pipeline_stage == 0);
411  CDWriter cdata(_cycler);
412  cdata->_target_tex_page = page;
413 }
414 
415 ////////////////////////////////////////////////////////////////////
416 // Function: DisplayRegion::output
417 // Access: Published, Virtual
418 // Description:
419 ////////////////////////////////////////////////////////////////////
420 void DisplayRegion::
421 output(ostream &out) const {
422  CDReader cdata(_cycler);
423  out << "DisplayRegion(" << cdata->_regions[0]._dimensions
424  << ")=pixels(" << cdata->_regions[0]._pixels << ")";
425 }
426 
427 ////////////////////////////////////////////////////////////////////
428 // Function: DisplayRegion::make_screenshot_filename
429 // Access: Published, Static
430 // Description: Synthesizes a suitable default filename for passing
431 // to save_screenshot().
432 //
433 // The default filename is generated from the supplied
434 // prefix and from the Config variable
435 // screenshot-filename, which contains the following
436 // strings:
437 //
438 // %~p - the supplied prefix
439 // %~f - the frame count
440 // %~e - the value of screenshot-extension
441 // All other % strings in strftime().
442 ////////////////////////////////////////////////////////////////////
444 make_screenshot_filename(const string &prefix) {
445  time_t now = time(NULL);
446  struct tm *ttm = localtime(&now);
447  int frame_count = ClockObject::get_global_clock()->get_frame_count();
448 
449  static const int buffer_size = 1024;
450  char buffer[buffer_size];
451 
452  ostringstream filename_strm;
453 
454  size_t i = 0;
455  while (i < screenshot_filename.length()) {
456  char ch1 = screenshot_filename[i++];
457  if (ch1 == '%' && i < screenshot_filename.length()) {
458  char ch2 = screenshot_filename[i++];
459  if (ch2 == '~' && i < screenshot_filename.length()) {
460  char ch3 = screenshot_filename[i++];
461  switch (ch3) {
462  case 'p':
463  filename_strm << prefix;
464  break;
465 
466  case 'f':
467  filename_strm << frame_count;
468  break;
469 
470  case 'e':
471  filename_strm << screenshot_extension;
472  break;
473  }
474 
475  } else {
476  // Use strftime() to decode the percent code.
477  char format[3] = {'%', ch2, '\0'};
478  if (strftime(buffer, buffer_size, format, ttm)) {
479  for (char *b = buffer; *b != '\0'; b++) {
480  switch (*b) {
481  case ' ':
482  case ':':
483  case '/':
484  filename_strm << '-';
485  break;
486 
487  case '\n':
488  break;
489 
490  default:
491  filename_strm << *b;
492  }
493  }
494  }
495  }
496  } else {
497  filename_strm << ch1;
498  }
499  }
500 
501  return Filename(filename_strm.str());
502 }
503 
504 
505 ////////////////////////////////////////////////////////////////////
506 // Function: DisplayRegion::save_screenshot_default
507 // Access: Published
508 // Description: Saves a screenshot of the region to a default
509 // filename, and returns the filename, or empty string
510 // if the screenshot failed. The filename is generated
511 // by make_screenshot_filename().
512 ////////////////////////////////////////////////////////////////////
514 save_screenshot_default(const string &prefix) {
515  Filename filename = make_screenshot_filename(prefix);
516  if (save_screenshot(filename)) {
517  return filename;
518  }
519  return Filename();
520 }
521 
522 ////////////////////////////////////////////////////////////////////
523 // Function: DisplayRegion::save_screenshot
524 // Access: Published
525 // Description: Saves a screenshot of the region to the indicated
526 // filename. Returns true on success, false on failure.
527 ////////////////////////////////////////////////////////////////////
528 bool DisplayRegion::
529 save_screenshot(const Filename &filename, const string &image_comment) {
530  PNMImage image;
531  if (!get_screenshot(image)) {
532  return false;
533  }
534 
535  image.set_comment(image_comment);
536  if (!image.write(filename)) {
537  return false;
538  }
539  return true;
540 }
541 
542 ////////////////////////////////////////////////////////////////////
543 // Function: DisplayRegion::get_screenshot
544 // Access: Published
545 // Description: Captures the most-recently rendered image from the
546 // framebuffer into the indicated PNMImage. Returns
547 // true on success, false on failure.
548 ////////////////////////////////////////////////////////////////////
549 bool DisplayRegion::
551  PT(Texture) tex = get_screenshot();
552 
553  if (tex == NULL) {
554  return false;
555  }
556 
557  if (!tex->store(image)) {
558  return false;
559  }
560 
561  return true;
562 }
563 
564 ////////////////////////////////////////////////////////////////////
565 // Function: DisplayRegion::get_screenshot
566 // Access: Published
567 // Description: Captures the most-recently rendered image from the
568 // framebuffer and returns it as a Texture, or NULL
569 // on failure.
570 ////////////////////////////////////////////////////////////////////
572 get_screenshot() {
573  Thread *current_thread = Thread::get_current_thread();
574 
575  GraphicsOutput *window = get_window();
576  nassertr(window != (GraphicsOutput *)NULL, NULL);
577 
578  GraphicsStateGuardian *gsg = window->get_gsg();
579  nassertr(gsg != (GraphicsStateGuardian *)NULL, NULL);
580 
581  if (!window->begin_frame(GraphicsOutput::FM_refresh, current_thread)) {
582  return NULL;
583  }
584 
585  PT(Texture) tex = new Texture;
586 
587  RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type(),
588  _window->get_fb_properties());
589  if (!gsg->framebuffer_copy_to_ram(tex, 0, -1, this, buffer)) {
590  return NULL;
591  }
592 
593  window->end_frame(GraphicsOutput::FM_refresh, current_thread);
594 
595  return tex;
596 }
597 
598 ////////////////////////////////////////////////////////////////////
599 // Function: DisplayRegion::make_cull_result_graph
600 // Access: Published
601 // Description: Returns a special scene graph constructed to
602 // represent the results of the last frame's cull
603 // operation.
604 //
605 // This will be a hierarchy of nodes, one node for each
606 // bin, each of which will in term be a parent of a
607 // number of GeomNodes, representing the geometry drawn
608 // in each bin.
609 //
610 // This is useful mainly for high-level debugging and
611 // abstraction tools; it should not be mistaken for the
612 // low-level cull result itself, which is constructed
613 // and maintained internally. No such scene graph is
614 // normally constructed during the rendering of a frame;
615 // this is an artificial construct created for the
616 // purpose of making it easy to analyze the results of
617 // the cull operation.
618 ////////////////////////////////////////////////////////////////////
620 make_cull_result_graph() {
621  CullResult *cull_result = get_cull_result(Thread::get_current_thread());
622  if (cull_result == (CullResult *)NULL) {
623  return NULL;
624  }
625  return cull_result->make_result_graph();
626 }
627 
628 ////////////////////////////////////////////////////////////////////
629 // Function: DisplayRegion::compute_pixels
630 // Access: Public
631 // Description: Computes the pixel locations of the DisplayRegion
632 // within its window. The DisplayRegion will request
633 // the size from the window.
634 ////////////////////////////////////////////////////////////////////
635 void DisplayRegion::
637  if (_window != (GraphicsOutput *)NULL) {
638  CDWriter cdata(_cycler, false);
639  for (size_t i = 0; i < cdata->_regions.size(); ++i) {
640  do_compute_pixels(i, _window->get_fb_x_size(), _window->get_fb_y_size(),
641  cdata);
642  }
643  }
644 }
645 
646 ////////////////////////////////////////////////////////////////////
647 // Function: DisplayRegion::compute_pixels_all_stages
648 // Access: Public
649 // Description: Computes the pixel locations of the DisplayRegion
650 // within its window. The DisplayRegion will request
651 // the size from the window.
652 ////////////////////////////////////////////////////////////////////
653 void DisplayRegion::
655  int pipeline_stage = Thread::get_current_pipeline_stage();
656  nassertv(pipeline_stage == 0);
657 
658  if (_window != (GraphicsOutput *)NULL) {
659  OPEN_ITERATE_ALL_STAGES(_cycler) {
660  CDStageWriter cdata(_cycler, pipeline_stage);
661  for (size_t i = 0; i < cdata->_regions.size(); ++i) {
662  do_compute_pixels(i, _window->get_fb_x_size(), _window->get_fb_y_size(),
663  cdata);
664  }
665  }
666  CLOSE_ITERATE_ALL_STAGES(_cycler);
667  }
668 }
669 
670 ////////////////////////////////////////////////////////////////////
671 // Function: DisplayRegion::compute_pixels
672 // Access: Public
673 // Description: Computes the pixel locations of the DisplayRegion
674 // within its window, given the size of the window in
675 // pixels.
676 ////////////////////////////////////////////////////////////////////
677 void DisplayRegion::
678 compute_pixels(int x_size, int y_size) {
679  CDWriter cdata(_cycler, false);
680  for (size_t i = 0; i < cdata->_regions.size(); ++i) {
681  do_compute_pixels(i, x_size, y_size, cdata);
682  }
683 }
684 
685 ////////////////////////////////////////////////////////////////////
686 // Function: DisplayRegion::compute_pixels_all_stages
687 // Access: Public
688 // Description: Performs a compute_pixels() operation for all stages
689 // of the pipeline. This is appropriate, for instance,
690 // when a window changes sizes, since this is a global
691 // operation; and you want the new window size to be
692 // immediately available even to the downstream stages.
693 ////////////////////////////////////////////////////////////////////
694 void DisplayRegion::
695 compute_pixels_all_stages(int x_size, int y_size) {
696  OPEN_ITERATE_ALL_STAGES(_cycler) {
697  CDStageWriter cdata(_cycler, pipeline_stage);
698  for (size_t i = 0; i < cdata->_regions.size(); ++i) {
699  do_compute_pixels(i, x_size, y_size, cdata);
700  }
701  }
702  CLOSE_ITERATE_ALL_STAGES(_cycler);
703 }
704 
705 ////////////////////////////////////////////////////////////////////
706 // Function: DisplayRegion::supports_pixel_zoom
707 // Access: Public, Virtual
708 // Description: Returns true if a call to set_pixel_zoom() will be
709 // respected, false if it will be ignored. If this
710 // returns false, then get_pixel_factor() will always
711 // return 1.0, regardless of what value you specify for
712 // set_pixel_zoom().
713 //
714 // This may return false if the underlying renderer
715 // doesn't support pixel zooming, or if you have called
716 // this on a DisplayRegion that doesn't have both
717 // set_clear_color() and set_clear_depth() enabled.
718 ////////////////////////////////////////////////////////////////////
719 bool DisplayRegion::
721  if (_window != (GraphicsOutput *)NULL) {
722  if (_window->supports_pixel_zoom()) {
724  }
725  }
726  return false;
727 }
728 
729 ////////////////////////////////////////////////////////////////////
730 // Function: DisplayRegion::win_display_regions_changed
731 // Access: Private
732 // Description: Intended to be called when the active state on a
733 // nested channel or layer or display region changes,
734 // forcing the window to recompute its list of active
735 // display regions. It is assumed the lock is already
736 // held.
737 ////////////////////////////////////////////////////////////////////
738 void DisplayRegion::
739 win_display_regions_changed() {
740  if (_window != (GraphicsOutput *)NULL) {
741  _window->win_display_regions_changed();
742  }
743 }
744 
745 ////////////////////////////////////////////////////////////////////
746 // Function: DisplayRegion::do_compute_pixels
747 // Access: Private
748 // Description: The private implementation of compute_pixels, this
749 // assumes that we already have the lock.
750 ////////////////////////////////////////////////////////////////////
751 void DisplayRegion::
752 do_compute_pixels(int i, int x_size, int y_size, CData *cdata) {
753  if (display_cat.is_debug()) {
754  display_cat.debug()
755  << "DisplayRegion::do_compute_pixels(" << x_size << ", " << y_size << ")\n";
756  }
757 
758  Region &region = cdata->_regions[i];
759 
760  int old_w = region._pixels[1] - region._pixels[0];
761  int old_h = region._pixels[3] - region._pixels[2];
762 
763  region._pixels[0] = int((region._dimensions[0] * x_size) + 0.5);
764  region._pixels[1] = int((region._dimensions[1] * x_size) + 0.5);
765  region._pixels_i[0] = region._pixels[0];
766  region._pixels_i[1] = region._pixels[1];
767 
768  nassertv(_window != (GraphicsOutput *)NULL);
769  if (_window->get_inverted()) {
770  // The window is inverted; compute the DisplayRegion accordingly.
771  region._pixels[2] = int(((1.0f - region._dimensions[3]) * y_size) + 0.5);
772  region._pixels[3] = int(((1.0f - region._dimensions[2]) * y_size) + 0.5);
773  region._pixels_i[2] = int((region._dimensions[3] * y_size) + 0.5);
774  region._pixels_i[3] = int((region._dimensions[2] * y_size) + 0.5);
775 
776  } else {
777  // The window is normal.
778  region._pixels[2] = int((region._dimensions[2] * y_size) + 0.5);
779  region._pixels[3] = int((region._dimensions[3] * y_size) + 0.5);
780  region._pixels_i[2] = int(((1.0f - region._dimensions[2]) * y_size) + 0.5);
781  region._pixels_i[3] = int(((1.0f - region._dimensions[3]) * y_size) + 0.5);
782  }
783 }
784 
785 ////////////////////////////////////////////////////////////////////
786 // Function: DisplayRegion::set_active_index
787 // Access: Private
788 // Description: This is called by GraphicsOutput to indicate that the
789 // index of this DisplayRegion within the window's list
790 // of active DisplayRegions might have changed. The
791 // index number will be -1 if the DisplayRegion is not
792 // active.
793 //
794 // This is primarily intended only for updating the
795 // PStatCollector name appropriately.
796 ////////////////////////////////////////////////////////////////////
797 void DisplayRegion::
798 set_active_index(int index) {
799 #ifdef DO_PSTATS
800  ostringstream strm;
801  strm << "dr_" << index;
802  string name = strm.str();
803 
804  _cull_region_pcollector = PStatCollector(_window->get_cull_window_pcollector(), name);
805  _draw_region_pcollector = PStatCollector(_window->get_draw_window_pcollector(), name);
806 #endif // DO_PSTATS
807 }
808 
809 ////////////////////////////////////////////////////////////////////
810 // Function: DisplayRegion::do_cull
811 // Access: Protected, Virtual
812 // Description: Performs a cull traversal. The default
813 // implementation simply calls GraphicsEngine::do_cull.
814 ////////////////////////////////////////////////////////////////////
815 void DisplayRegion::
816 do_cull(CullHandler *cull_handler, SceneSetup *scene_setup,
817  GraphicsStateGuardian *gsg, Thread *current_thread) {
818 
819  GraphicsEngine::do_cull(cull_handler, scene_setup, gsg, current_thread);
820 }
821 
822 ////////////////////////////////////////////////////////////////////
823 // Function: DisplayRegion::CData::Constructor
824 // Access: Public
825 // Description:
826 ////////////////////////////////////////////////////////////////////
827 DisplayRegion::CData::
828 CData() :
829  _lens_index(0),
830  _camera_node((Camera *)NULL),
831  _active(true),
832  _sort(0),
833  _stereo_channel(Lens::SC_mono),
834  _tex_view_offset(0),
835  _target_tex_page(-1),
836  _scissor_enabled(true)
837 {
838  _regions.push_back(Region());
839 }
840 
841 ////////////////////////////////////////////////////////////////////
842 // Function: DisplayRegion::CData::Copy Constructor
843 // Access: Public
844 // Description:
845 ////////////////////////////////////////////////////////////////////
846 DisplayRegion::CData::
847 CData(const DisplayRegion::CData &copy) :
848  _regions(copy._regions),
849  _lens_index(copy._lens_index),
850  _camera(copy._camera),
851  _camera_node(copy._camera_node),
852  _active(copy._active),
853  _sort(copy._sort),
854  _stereo_channel(copy._stereo_channel),
855  _tex_view_offset(copy._tex_view_offset),
856  _target_tex_page(copy._target_tex_page),
857  _scissor_enabled(copy._scissor_enabled)
858 {
859 }
860 
861 ////////////////////////////////////////////////////////////////////
862 // Function: DisplayRegion::CData::make_copy
863 // Access: Public, Virtual
864 // Description:
865 ////////////////////////////////////////////////////////////////////
866 CycleData *DisplayRegion::CData::
867 make_copy() const {
868  return new CData(*this);
869 }
870 
871 ////////////////////////////////////////////////////////////////////
872 // Function: DisplayRegion::CDataCull::make_copy
873 // Access: Public, Virtual
874 // Description:
875 ////////////////////////////////////////////////////////////////////
876 CycleData *DisplayRegion::CDataCull::
877 make_copy() const {
878  return new CDataCull(*this);
879 }
880 
881 ////////////////////////////////////////////////////////////////////
882 // Function: DisplayRegionPipelineReader::get_pipe
883 // Access: Public
884 // Description: Returns the GraphicsPipe that this DisplayRegion is
885 // ultimately associated with, or NULL if no pipe is
886 // associated.
887 ////////////////////////////////////////////////////////////////////
889 get_pipe() const {
890  return (_object->_window != (GraphicsOutput *)NULL) ? _object->_window->get_pipe() : NULL;
891 }
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
static Filename make_screenshot_filename(const string &prefix="screenshot")
Synthesizes a suitable default filename for passing to save_screenshot().
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
void cleanup()
Cleans up some pointers associated with the DisplayRegion to help reduce the chance of memory leaks d...
Filename save_screenshot_default(const string &prefix="screenshot")
Saves a screenshot of the region to a default filename, and returns the filename, or empty string if ...
bool has_size() const
Returns true if the size of the window/frame buffer is known, false otherwise.
bool write(const Filename &filename, PNMFileType *type=NULL) const
Writes the image to the indicated filename.
Definition: pnmImage.cxx:362
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:68
virtual void set_sort(int sort)
Sets the sort value associated with the DisplayRegion.
bool get_clear_color_active() const
Returns the current setting of the flag that indicates whether the color buffer should be cleared eve...
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:45
virtual bool is_stereo() const
Returns true if this is a StereoDisplayRegion, false otherwise.
static void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, GraphicsStateGuardian *gsg, Thread *current_thread)
Fires off a cull traversal using the indicated camera.
bool get_screenshot(PNMImage &image)
Captures the most-recently rendered image from the framebuffer into the indicated PNMImage...
void set_comment(const string &comment)
Writes a user comment string to the image (header).
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
void set_dimensions(PN_stdfloat l, PN_stdfloat r, PN_stdfloat b, PN_stdfloat t)
Changes the portion of the framebuffer this DisplayRegion corresponds to.
virtual void set_texture_reload_priority(int texture_reload_priority)
Specifies an integer priority which is assigned to any asynchronous texture reload requests spawned w...
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
void compute_pixels_all_stages()
Computes the pixel locations of the DisplayRegion within its window.
virtual void set_target_tex_page(int page)
This is a special parameter that is only used when rendering the faces of a cube map or multipage and...
bool save_screenshot(const Filename &filename, const string &image_comment="")
Saves a screenshot of the region to the indicated filename.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
virtual void set_cull_traverser(CullTraverser *trav)
Specifies the CullTraverser that will be used to draw the contents of this DisplayRegion.
void compute_pixels()
Computes the pixel locations of the DisplayRegion within its window.
virtual bool supports_pixel_zoom() const
Returns true if a call to set_pixel_zoom() will be respected, false if it will be ignored...
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame...
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
GraphicsPipe * get_pipe() const
Returns the GraphicsPipe that this window is associated with.
PStatCollector & get_draw_window_pcollector()
Returns a PStatCollector for timing the draw operation for just this GraphicsOutput.
A lightweight class that represents a single element that may be timed and/or counted via stats...
virtual void set_tex_view_offset(int tex_view_offset)
Sets the current texture view offset for this DisplayRegion.
virtual void set_active(bool active)
Sets the active flag associated with the DisplayRegion.
int get_draw_buffer_type() const
Returns the RenderBuffer into which the GSG should issue draw commands.
virtual void set_incomplete_render(bool incomplete_render)
Sets the incomplete_render flag.
bool get_inverted() const
Returns the current setting of the inverted flag.
This defines the abstract interface for an object that receives Geoms identified by the CullTraverser...
Definition: cullHandler.h:31
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
virtual bool supports_pixel_zoom() const
Returns true if a call to set_pixel_zoom() will be respected, false if it will be ignored...
GraphicsPipe * get_pipe() const
Returns the GraphicsPipe that this DisplayRegion is ultimately associated with, or NULL if no pipe is...
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
int get_frame_count(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of times tick() has been called since the ClockObject was created, or since it was last reset.
Definition: clockObject.I:113
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
virtual void set_stereo_channel(Lens::StereoChannel stereo_channel)
Specifies whether the DisplayRegion represents the left or right channel of a stereo pair...
GraphicsStateGuardian * get_gsg() const
Returns the GSG that is associated with this window.
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
This is a base class for the various different classes that represent the result of a frame of render...
GraphicsPipe * get_pipe() const
Returns the GraphicsPipe that this DisplayRegion is ultimately associated with, or NULL if no pipe is...
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
This stores the result of a BinCullHandler traversal: an ordered collection of CullBins, each of which holds a number of Geoms and RenderStates to be rendered in some defined order.
Definition: cullResult.h:47
virtual void set_camera(const NodePath &camera)
Sets the camera that is associated with this DisplayRegion.
void set_lens_index(int index)
Sets the lens index, allows for multiple lenses to be attached to a camera.
A thread; that is, a lightweight process.
Definition: thread.h:51
int get_fb_x_size() const
Returns the internal width of the window or buffer.
bool get_clear_depth_active() const
Returns the current setting of the flag that indicates whether the depth buffer should be cleared eve...
Encapsulates all the communication with a particular instance of a given rendering backend...
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:236
CullTraverser * get_cull_traverser()
Returns the CullTraverser that will be used to draw the contents of this DisplayRegion.
int get_fb_y_size() const
Returns the internal height of the window or buffer.
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:61
PStatCollector & get_cull_window_pcollector()
Returns a PStatCollector for timing the cull operation for just this GraphicsOutput.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:35
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:37
static int get_current_pipeline_stage()
Returns the integer pipeline stage associated with the current thread.
Definition: thread.I:167
A RenderBuffer is an arbitrary subset of the various layers (depth buffer, color buffer, etc.) of a drawing region.
Definition: renderBuffer.h:30
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48