Panda3D
graphicsOutput.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 graphicsOutput.cxx
10  * @author drose
11  * @date 2004-02-06
12  */
13 
14 #include "graphicsOutput.h"
15 #include "graphicsPipe.h"
16 #include "graphicsEngine.h"
17 #include "graphicsWindow.h"
18 #include "config_display.h"
19 #include "lightMutexHolder.h"
20 #include "renderBuffer.h"
21 #include "indirectLess.h"
22 #include "pStatTimer.h"
23 #include "configVariableBool.h"
24 #include "camera.h"
25 #include "displayRegion.h"
26 #include "lens.h"
27 #include "perspectiveLens.h"
28 #include "pointerTo.h"
29 #include "compassEffect.h"
30 #include "geom.h"
31 #include "geomNode.h"
32 #include "geomTristrips.h"
33 #include "geomVertexWriter.h"
34 #include "throw_event.h"
35 #include "config_gobj.h"
36 
37 using std::string;
38 
39 TypeHandle GraphicsOutput::_type_handle;
40 
41 PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current");
42 PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture");
43 PStatCollector GraphicsOutput::_cull_pcollector("Cull");
44 PStatCollector GraphicsOutput::_draw_pcollector("Draw");
45 
46 struct CubeFaceDef {
47  CubeFaceDef(const char *name, const LPoint3 &look_at, const LVector3 &up) :
48  _name(name), _look_at(look_at), _up(up) { }
49 
50  const char *_name;
51  LPoint3 _look_at;
52  LVector3 _up;
53 };
54 
55 static CubeFaceDef cube_faces[6] = {
56  CubeFaceDef("positive_x", LPoint3(1, 0, 0), LVector3(0, -1, 0)),
57  CubeFaceDef("negative_x", LPoint3(-1, 0, 0), LVector3(0, -1, 0)),
58  CubeFaceDef("positive_y", LPoint3(0, 1, 0), LVector3(0, 0, 1)),
59  CubeFaceDef("negative_y", LPoint3(0, -1, 0), LVector3(0, 0, -1)),
60  CubeFaceDef("positive_z", LPoint3(0, 0, 1), LVector3(0, -1, 0)),
61  CubeFaceDef("negative_z", LPoint3(0, 0, -1), LVector3(0, -1, 0))
62 };
63 
64 /**
65  * Normally, the GraphicsOutput constructor is not called directly; these are
66  * created instead via the GraphicsEngine::make_window() function.
67  */
68 GraphicsOutput::
69 GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
70  const string &name,
71  const FrameBufferProperties &fb_prop,
72  const WindowProperties &win_prop,
73  int flags,
75  GraphicsOutput *host,
76  bool default_stereo_flags) :
77  _lock("GraphicsOutput"),
78  _cull_window_pcollector(_cull_pcollector, name),
79  _draw_window_pcollector(_draw_pcollector, name),
80  _clear_window_pcollector(_draw_window_pcollector, "Clear"),
81  _size(0, 0)
82 {
83 #ifdef DO_MEMORY_USAGE
84  MemoryUsage::update_type(this, this);
85 #endif
86  _engine = engine;
87  _pipe = pipe;
88  _gsg = gsg;
89  _host = host;
90  _fb_properties = fb_prop;
91  _name = name;
92  _creation_flags = flags;
93  _has_size = win_prop.has_size();
94  _is_nonzero_size = false;
95  if (_has_size) {
96  _size = win_prop.get_size();
97  _is_nonzero_size = (_size[0] > 0 && _size[1] > 0);
98  }
99  if (_creation_flags & GraphicsPipe::BF_size_track_host) {
100  // If we're tracking the host size, we assume we'll be nonzero eventually.
101  _is_nonzero_size = true;
102  }
103 
104  _is_valid = false;
105  _flip_ready = false;
106  _target_tex_page = -1;
107  _prev_page_dr = nullptr;
108  _sort = 0;
109  _child_sort = 0;
110  _got_child_sort = false;
111  _internal_sort_index = 0;
112  _inverted = window_inverted;
113  _swap_eyes = swap_eyes;
114  _red_blue_stereo = false;
115  _left_eye_color_mask = 0x0f;
116  _right_eye_color_mask = 0x0f;
117  _side_by_side_stereo = false;
118  _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
119  _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
120  _delete_flag = false;
121 
122  if (_fb_properties.is_single_buffered()) {
123  _draw_buffer_type = RenderBuffer::T_front;
124  } else {
125  _draw_buffer_type = RenderBuffer::T_back;
126  }
127 
128  if (default_stereo_flags) {
129  // Check the config variables to see if we should make this a "stereo"
130  // buffer or window.
131  _red_blue_stereo = red_blue_stereo && !fb_prop.is_stereo();
132  if (_red_blue_stereo) {
133  _left_eye_color_mask = parse_color_mask(red_blue_stereo_colors.get_word(0));
134  _right_eye_color_mask = parse_color_mask(red_blue_stereo_colors.get_word(1));
135  }
136  _side_by_side_stereo = side_by_side_stereo && !fb_prop.is_stereo();
137  if (_side_by_side_stereo) {
138  _sbs_left_dimensions.set(sbs_left_dimensions[0], sbs_left_dimensions[1],
139  sbs_left_dimensions[2], sbs_left_dimensions[3]);
140  _sbs_right_dimensions.set(sbs_right_dimensions[0], sbs_right_dimensions[1],
141  sbs_right_dimensions[2], sbs_right_dimensions[3]);
142  }
143  }
144 
145  // We start out with one DisplayRegion that covers the whole window, which
146  // we may use internally for full-window operations like clear() and
147  // get_screenshot().
148  _overlay_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
149  _overlay_display_region->set_active(false);
150  _overlay_display_region->set_scissor_enabled(false);
151 
152  // Make sure the "active" flag is set true for pipeline stage 0.
153  {
154  CDWriter cdata(_cycler, true);
155  cdata->_active = true;
156  }
157 
158  // By default, each new GraphicsOutput is set up to clear color and depth.
159  set_clear_color_active(true);
160  set_clear_depth_active(true);
161  set_clear_stencil_active(true);
162  set_clear_color(background_color.get_value());
163 }
164 
165 /**
166  *
167  */
168 GraphicsOutput::
169 ~GraphicsOutput() {
170  // The window should be closed by the time we destruct.
171  nassertv(!is_valid());
172 
173  // We shouldn't have a GraphicsPipe pointer anymore.
174  nassertv(_pipe == nullptr);
175 
176  // We don't have to destruct our child display regions explicitly, since
177  // they are all reference-counted and will go away when their pointers do.
178  // However, we do need to zero out their pointers to us.
179  TotalDisplayRegions::iterator dri;
180  for (dri = _total_display_regions.begin();
181  dri != _total_display_regions.end();
182  ++dri) {
183  (*dri)->_window = nullptr;
184  }
185 
186  _total_display_regions.clear();
187  _overlay_display_region = nullptr;
188 }
189 
190 /**
191  * If the GraphicsOutput is currently rendering to a texture, then all
192  * textures are dissociated from the GraphicsOuput.
193  */
194 void GraphicsOutput::
196  CDWriter cdata(_cycler, true);
197  cdata->_textures.clear();
198  ++(cdata->_textures_seq);
199  throw_event("render-texture-targets-changed");
200 }
201 
202 /**
203  * Creates a new Texture object, suitable for rendering the contents of this
204  * buffer into, and appends it to the list of render textures.
205  *
206  * If tex is not NULL, it is the texture that will be set up for rendering
207  * into; otherwise, a new Texture object will be created, in which case you
208  * may call get_texture() to retrieve the new texture pointer.
209  *
210  * You can specify a bitplane to attach the texture to. the legal choices
211  * are:
212  *
213  * - RTP_depth
214  * - RTP_depth_stencil
215  * - RTP_color
216  * - RTP_aux_rgba_0
217  * - RTP_aux_rgba_1
218  * - RTP_aux_rgba_2
219  * - RTP_aux_rgba_3
220  *
221  * If you do not specify a bitplane to attach the texture to, this routine
222  * will use a default based on the texture's format:
223  *
224  * - F_depth_component attaches to RTP_depth
225  * - F_depth_stencil attaches to RTP_depth_stencil
226  * - all other formats attach to RTP_color.
227  *
228  * The texture's format will be changed to match the format of the bitplane to
229  * which it is attached. For example, if you pass in an F_rgba texture and
230  * order that it be attached to RTP_depth_stencil, it will turn into an
231  * F_depth_stencil texture.
232  *
233  * Also see make_texture_buffer(), which is a higher-level interface for
234  * preparing render-to-a-texture mode.
235  */
236 void GraphicsOutput::
237 add_render_texture(Texture *tex, RenderTextureMode mode,
238  RenderTexturePlane plane) {
239 
240  if (mode == RTM_none) {
241  return;
242  }
243  LightMutexHolder holder(_lock);
244 
245  // Create texture if necessary.
246  if (tex == nullptr) {
247  tex = new Texture(get_name());
248  tex->set_wrap_u(SamplerState::WM_clamp);
249  tex->set_wrap_v(SamplerState::WM_clamp);
250  } else {
251  tex->clear_ram_image();
252  }
253 
254  // Set it to have no compression by default. You can restore compression
255  // later if you really, really want it; but this freaks out some drivers,
256  // and presumably it's a mistake if you have compression enabled for a
257  // rendered texture.
258  tex->set_compression(Texture::CM_off);
259 
260  // Choose a default bitplane.
261  if (plane == RTP_COUNT) {
262  switch (tex->get_format()) {
263  case Texture::F_depth_stencil:
264  plane = RTP_depth_stencil;
265  break;
266 
267  case Texture::F_depth_component:
268  case Texture::F_depth_component16:
269  case Texture::F_depth_component24:
270  case Texture::F_depth_component32:
271  plane = RTP_depth;
272  break;
273 
274  default:
275  plane = RTP_color;
276  break;
277  }
278  }
279 
280  // Set the texture's format to match the bitplane. (And validate the
281  // bitplane, while we're at it).
282 
283  if (plane == RTP_depth) {
284  _fb_properties.setup_depth_texture(tex);
285  tex->set_match_framebuffer_format(true);
286 
287  } else if (plane == RTP_depth_stencil) {
288  tex->set_format(Texture::F_depth_stencil);
289  if (_fb_properties.get_float_depth()) {
290  tex->set_component_type(Texture::T_float);
291  } else {
292  tex->set_component_type(Texture::T_unsigned_int_24_8);
293  }
294  tex->set_match_framebuffer_format(true);
295 
296  } else if (plane == RTP_color ||
297  plane == RTP_aux_rgba_0 ||
298  plane == RTP_aux_rgba_1 ||
299  plane == RTP_aux_rgba_2 ||
300  plane == RTP_aux_rgba_3) {
301  _fb_properties.setup_color_texture(tex);
302  tex->set_match_framebuffer_format(true);
303 
304  } else if (plane == RTP_aux_hrgba_0 ||
305  plane == RTP_aux_hrgba_1 ||
306  plane == RTP_aux_hrgba_2 ||
307  plane == RTP_aux_hrgba_3) {
308  tex->set_format(Texture::F_rgba16);
309  tex->set_match_framebuffer_format(true);
310 
311  } else if (plane == RTP_aux_float_0 ||
312  plane == RTP_aux_float_1 ||
313  plane == RTP_aux_float_2 ||
314  plane == RTP_aux_float_3) {
315  tex->set_format(Texture::F_rgba32);
316  tex->set_component_type(Texture::T_float);
317  tex->set_match_framebuffer_format(true);
318 
319  } else {
320  display_cat.error() <<
321  "add_render_texture: invalid bitplane specified.\n";
322  return;
323  }
324 
325  // Go ahead and tell the texture our anticipated size, even if it might be
326  // inaccurate (particularly if this is a GraphicsWindow, which has system-
327  // imposed restrictions on size).
328  tex->set_size_padded(get_x_size(), get_y_size(), tex->get_z_size());
329 
330  if (_fb_properties.is_stereo() && plane == RTP_color) {
331  if (tex->get_num_views() < 2) {
332  tex->set_num_views(2);
333  }
334  }
335 
336  if (!support_render_texture || !get_supports_render_texture()) {
337  // Binding is not supported or it is disabled, so just fall back to copy
338  // instead.
339  if (mode == RTM_bind_or_copy) {
340  mode = RTM_copy_texture;
341  } else if (mode == RTM_bind_layered) {
342  // We can't fallback to copy, because that doesn't work for layered
343  // textures. The best thing we can do is raise an error message.
344  display_cat.error() <<
345  "add_render_texture: RTM_bind_layered was requested but "
346  "render-to-texture is not supported or has been disabled!\n";
347  }
348  }
349 
350  if (mode == RTM_bind_layered && _gsg != nullptr && !_gsg->get_supports_geometry_shaders()) {
351  // Layered FBOs require a geometry shader to write to any but the first
352  // layer.
353  display_cat.warning() <<
354  "add_render_texture: RTM_bind_layered was requested but "
355  "geometry shaders are not supported!\n";
356  }
357 
358  if (mode == RTM_bind_or_copy || mode == RTM_bind_layered) {
359  // If we're still planning on binding, indicate it in texture properly.
360  tex->set_render_to_texture(true);
361  }
362 
363  CDWriter cdata(_cycler, true);
364  RenderTexture result;
365  result._texture = tex;
366  result._plane = plane;
367  result._rtm_mode = mode;
368  cdata->_textures.push_back(result);
369  ++(cdata->_textures_seq);
370 
371  throw_event("render-texture-targets-changed");
372 }
373 
374 /**
375  * This is a deprecated interface that made sense back when GraphicsOutputs
376  * could only render into one texture at a time. From now on, use
377  * clear_render_textures and add_render_texture instead.
378  */
379 void GraphicsOutput::
380 setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
381  display_cat.warning() <<
382  "Using deprecated setup_render_texture interface.\n";
384  if (to_ram) {
385  add_render_texture(tex, RTM_copy_ram);
386  } else if (allow_bind) {
387  add_render_texture(tex, RTM_bind_or_copy);
388  } else {
389  add_render_texture(tex, RTM_copy_texture);
390  }
391 }
392 
393 /**
394  * Sets the active flag associated with the GraphicsOutput. If the
395  * GraphicsOutput is marked inactive, nothing is rendered.
396  */
397 void GraphicsOutput::
398 set_active(bool active) {
399  CDLockedReader cdata(_cycler);
400  if (cdata->_active != active) {
401  CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true);
402  cdataw->_active = active;
403  }
404 }
405 
406 /**
407  * Returns true if the window is ready to be rendered into, false otherwise.
408  */
409 bool GraphicsOutput::
410 is_active() const {
411  if (!is_valid()) {
412  return false;
413  }
414 
415  CDLockedReader cdata(_cycler);
416  if (!cdata->_active) {
417  return false;
418  }
419 
420  if (cdata->_one_shot_frame != -1) {
421  // If one_shot is in effect, then we are active only for the one indicated
422  // frame.
423  if (cdata->_one_shot_frame != ClockObject::get_global_clock()->get_frame_count()) {
424  return false;
425  } else {
426  return true;
427  }
428  }
429 
430  // If the window has a clear value set, it is active.
431  if (is_any_clear_active()) {
432  return true;
433  }
434 
435  // If we triggered a copy operation, it is also active.
436  if (_trigger_copy) {
437  return true;
438  }
439 
440  // The window is active if at least one display region is active.
441  if (cdata->_active_display_regions_stale) {
442  CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, false);
443  ((GraphicsOutput *)this)->do_determine_display_regions(cdataw);
444  return !cdataw->_active_display_regions.empty();
445  } else {
446  return !cdata->_active_display_regions.empty();
447  }
448 }
449 
450 /**
451  * Changes the current setting of the one-shot flag. When this is true, the
452  * GraphicsOutput will render the current frame and then automatically set
453  * itself inactive. This is particularly useful for buffers that are created
454  * for the purposes of render-to-texture, for static textures that don't need
455  * to be continually re-rendered once they have been rendered the first time.
456  *
457  * Setting the buffer inactive is not the same thing as destroying it. You
458  * are still responsible for passing this buffer to
459  * GraphicsEngine::remove_window() when you no longer need the texture, in
460  * order to clean up fully. (However, you should not call remove_window() on
461  * this buffer while the texture is still needed, because depending on the
462  * render-to-texture mechanism in use, this may invalidate the texture
463  * contents.)
464  */
465 void GraphicsOutput::
466 set_one_shot(bool one_shot) {
467  CDWriter cdata(_cycler, true);
468  if (one_shot) {
469  cdata->_one_shot_frame = ClockObject::get_global_clock()->get_frame_count();
470  } else {
471  cdata->_one_shot_frame = -1;
472  }
473 }
474 
475 /**
476  * Returns the current setting of the one-shot flag. When this is true, the
477  * GraphicsOutput will automatically set itself inactive after the next frame.
478  */
479 bool GraphicsOutput::
480 get_one_shot() const {
481  CDReader cdata(_cycler);
482  return (cdata->_one_shot_frame == ClockObject::get_global_clock()->get_frame_count());
483 }
484 
485 /**
486  * Changes the current setting of the inverted flag. When this is true, the
487  * scene is rendered into the window upside-down and backwards, that is,
488  * inverted as if viewed through a mirror placed on the floor.
489  *
490  * This is primarily intended to support DirectX (and a few buggy OpenGL
491  * graphics drivers) that perform a framebuffer-to-texture copy upside-down
492  * from the usual OpenGL (and Panda) convention. Panda will automatically set
493  * this flag for offscreen buffers on hardware that is known to do this, to
494  * compensate when rendering offscreen into a texture.
495  */
496 void GraphicsOutput::
497 set_inverted(bool inverted) {
498  if (_inverted != inverted) {
499  _inverted = inverted;
500 
501  if (get_y_size() != 0) {
502  // All of our DisplayRegions need to recompute their pixel positions
503  // now.
504  TotalDisplayRegions::iterator dri;
505  for (dri = _total_display_regions.begin();
506  dri != _total_display_regions.end();
507  ++dri) {
508  (*dri)->compute_pixels(get_x_size(), get_y_size());
509  }
510  }
511  }
512 }
513 
514 /**
515  * Enables side-by-side stereo mode on this particular window. When side-by-
516  * side stereo mode is in effect, DisplayRegions that have the "left" channel
517  * set will render on the part of the window specified by sbs_left_dimensions
518  * (typically the left half: (0, 0.5, 0, 1)), while DisplayRegions that have
519  * the "right" channel set will render on the part of the window specified by
520  * sbs_right_dimensions (typically the right half: (0.5, 1, 0, 1)).
521  *
522  * This is commonly used in a dual-monitor mode, where a window is opened that
523  * spans two monitors, and each monitor represents a different eye.
524  */
525 void GraphicsOutput::
526 set_side_by_side_stereo(bool side_by_side_stereo) {
527  LVecBase4 left, right;
528  left.set(sbs_left_dimensions[0], sbs_left_dimensions[1],
529  sbs_left_dimensions[2], sbs_left_dimensions[3]);
530  right.set(sbs_right_dimensions[0], sbs_right_dimensions[1],
531  sbs_right_dimensions[2], sbs_right_dimensions[3]);
532  set_side_by_side_stereo(side_by_side_stereo, left, right);
533 }
534 
535 /**
536  * Enables side-by-side stereo mode on this particular window. When side-by-
537  * side stereo mode is in effect, DisplayRegions that have the "left" channel
538  * set will render on the part of the window specified by sbs_left_dimensions
539  * (typically the left half: (0, 0.5, 0, 1)), while DisplayRegions that have
540  * the "right" channel set will render on the part of the window specified by
541  * sbs_right_dimensions (typically the right half: (0.5, 1, 0, 1)).
542  *
543  * This is commonly used in a dual-monitor mode, where a window is opened that
544  * spans two monitors, and each monitor represents a different eye.
545  */
546 void GraphicsOutput::
547 set_side_by_side_stereo(bool side_by_side_stereo,
548  const LVecBase4 &sbs_left_dimensions,
549  const LVecBase4 &sbs_right_dimensions) {
550  _side_by_side_stereo = side_by_side_stereo;
551  if (_side_by_side_stereo) {
552  _sbs_left_dimensions = sbs_left_dimensions;
553  _sbs_right_dimensions = sbs_right_dimensions;
554  } else {
555  _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
556  _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f);
557  }
558 }
559 
560 /**
561  * Returns the current setting of the delete flag. When this is true, the
562  * GraphicsOutput will automatically be removed before the beginning of the
563  * next frame by the GraphicsEngine.
564  */
565 bool GraphicsOutput::
567  // We only delete the window or buffer automatically when it is no longer
568  // associated with a texture.
569  for (int i = 0; i < (int)_hold_textures.size(); i++) {
570  if (_hold_textures[i].is_valid_pointer()) {
571  return false;
572  }
573  }
574 
575  return _delete_flag;
576 }
577 
578 /**
579  * Adjusts the sorting order of this particular GraphicsOutput, relative to
580  * other GraphicsOutputs.
581  */
582 void GraphicsOutput::
583 set_sort(int sort) {
584  if (_sort != sort) {
585  if (_gsg != nullptr &&
586  _gsg->get_engine() != nullptr) {
587  _gsg->get_engine()->set_window_sort(this, sort);
588  }
589  }
590 }
591 
592 /**
593  * Creates a new DisplayRegion that covers the indicated sub-rectangle within
594  * the window. The range on all parameters is 0..1.
595  *
596  * If is_stereo() is true for this window, and default-stereo-camera is
597  * configured true, this actually makes a StereoDisplayRegion. Call
598  * make_mono_display_region() or make_stereo_display_region() if you want to
599  * insist on one or the other.
600  */
602 make_display_region(const LVecBase4 &dimensions) {
603  if (is_stereo() && default_stereo_camera) {
604  return make_stereo_display_region(dimensions);
605  } else {
606  return make_mono_display_region(dimensions);
607  }
608 }
609 
610 /**
611  * Creates a new DisplayRegion that covers the indicated sub-rectangle within
612  * the window. The range on all parameters is 0..1.
613  *
614  * This generally returns a mono DisplayRegion, even if is_stereo() is true.
615  * However, if side-by-side stereo is enabled, this will return a
616  * StereoDisplayRegion whose two eyes are both set to SC_mono. (This is
617  * necessary because in side-by-side stereo mode, it is necessary to draw even
618  * mono DisplayRegions twice).
619  */
621 make_mono_display_region(const LVecBase4 &dimensions) {
622  if (_side_by_side_stereo) {
624  dr->get_left_eye()->set_stereo_channel(Lens::SC_mono);
625  dr->get_right_eye()->set_stereo_channel(Lens::SC_mono);
626  return dr;
627  }
628 
629  return new DisplayRegion(this, dimensions);
630 }
631 
632 /**
633  * Creates a new DisplayRegion that covers the indicated sub-rectangle within
634  * the window. The range on all parameters is 0..1.
635  *
636  * This always returns a stereo DisplayRegion, even if is_stereo() is false.
637  */
639 make_stereo_display_region(const LVecBase4 &dimensions) {
640  PT(DisplayRegion) left, right;
641 
642  if (_side_by_side_stereo) {
643  // On a side-by-side stereo window, each eye gets the corresponding
644  // dimensions of its own sub-region.
645  PN_stdfloat left_l = _sbs_left_dimensions[0];
646  PN_stdfloat left_b = _sbs_left_dimensions[2];
647  PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0];
648  PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2];
649  LVecBase4 left_dimensions(dimensions[0] * left_w + left_l,
650  dimensions[1] * left_w + left_l,
651  dimensions[2] * left_h + left_b,
652  dimensions[3] * left_h + left_b);
653  left = new DisplayRegion(this, left_dimensions);
654 
655  PN_stdfloat right_l = _sbs_right_dimensions[0];
656  PN_stdfloat right_b = _sbs_right_dimensions[2];
657  PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0];
658  PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2];
659  LVecBase4 right_dimensions(dimensions[0] * right_w + right_l,
660  dimensions[1] * right_w + right_l,
661  dimensions[2] * right_h + right_b,
662  dimensions[3] * right_h + right_b);
663  right = new DisplayRegion(this, right_dimensions);
664 
665  if (_swap_eyes) {
666  DisplayRegion *t = left;
667  left = right;
668  right = t;
669  }
670 
671  } else {
672  // Not a side-by-side stereo window; thus, both the left and right eyes
673  // are the same region: the region specified.
674  left = new DisplayRegion(this, dimensions);
675  right = new DisplayRegion(this, dimensions);
676 
677  // In this case, we assume that the two eyes will share the same depth
678  // buffer, which means the right eye should clear the depth buffer by
679  // default.
680  if (get_clear_depth_active()) {
681  right->set_clear_depth_active(true);
682  }
683  if (get_clear_stencil_active()) {
684  right->set_clear_stencil_active(true);
685  }
686  }
687 
688  PT(StereoDisplayRegion) stereo = new StereoDisplayRegion(this, dimensions,
689  left, right);
690 
691  return stereo;
692 }
693 
694 /**
695  * Removes the indicated DisplayRegion from the window, and destructs it if
696  * there are no other references.
697  *
698  * Returns true if the DisplayRegion is found and removed, false if it was not
699  * a part of the window.
700  */
701 bool GraphicsOutput::
703  LightMutexHolder holder(_lock);
704 
705  nassertr(display_region != _overlay_display_region, false);
706 
707  if (display_region->is_stereo()) {
708  StereoDisplayRegion *sdr;
709  DCAST_INTO_R(sdr, display_region, false);
710  do_remove_display_region(sdr->get_left_eye());
711  do_remove_display_region(sdr->get_right_eye());
712  }
713 
714  return do_remove_display_region(display_region);
715 }
716 
717 /**
718  * Removes all display regions from the window, except the default one that is
719  * created with the window.
720  */
721 void GraphicsOutput::
723  LightMutexHolder holder(_lock);
724 
725  TotalDisplayRegions::iterator dri;
726  for (dri = _total_display_regions.begin();
727  dri != _total_display_regions.end();
728  ++dri) {
729  DisplayRegion *display_region = (*dri);
730  if (display_region != _overlay_display_region) {
731  // Let's aggressively clean up the display region too.
732  display_region->cleanup();
733  display_region->_window = nullptr;
734  }
735  }
736  _total_display_regions.clear();
737  _total_display_regions.push_back(_overlay_display_region);
738 
739  OPEN_ITERATE_ALL_STAGES(_cycler) {
740  CDStageWriter cdata(_cycler, pipeline_stage);
741  cdata->_active_display_regions_stale = true;
742  }
743  CLOSE_ITERATE_ALL_STAGES(_cycler);
744 }
745 
746 /**
747  * Replaces the special "overlay" DisplayRegion that is created for each
748  * window or buffer. See get_overlay_display_region(). This must be a new
749  * DisplayRegion that has already been created for this window, for instance
750  * via a call to make_mono_display_region(). You are responsible for ensuring
751  * that the new DisplayRegion covers the entire window. The previous overlay
752  * display region is not automatically removed; you must explicitly call
753  * remove_display_region() on it after replacing it with this method, if you
754  * wish it to be removed.
755  *
756  * Normally, there is no reason to change the overlay DisplayRegion, so this
757  * method should be used only in very unusual circumstances.
758  */
759 void GraphicsOutput::
761  nassertv(display_region->get_window() == this);
762  _overlay_display_region = display_region;
763 }
764 
765 /**
766  * Returns the number of DisplayRegions that have been created within the
767  * window, active or otherwise.
768  */
769 int GraphicsOutput::
770 get_num_display_regions() const {
771  LightMutexHolder holder(_lock);
772  return _total_display_regions.size();
773 }
774 
775 /**
776  * Returns the nth DisplayRegion of those that have been created within the
777  * window. This may return NULL if n is out of bounds; particularly likely if
778  * the number of display regions has changed since the last call to
779  * get_num_display_regions().
780  */
781 PT(DisplayRegion) GraphicsOutput::
782 get_display_region(int n) const {
783  determine_display_regions();
784  PT(DisplayRegion) result;
785  {
786  LightMutexHolder holder(_lock);
787  if (n >= 0 && n < (int)_total_display_regions.size()) {
788  result = _total_display_regions[n];
789  } else {
790  result = nullptr;
791  }
792  }
793  return result;
794 }
795 
796 /**
797  * Returns the number of active DisplayRegions that have been created within
798  * the window.
799  */
800 int GraphicsOutput::
801 get_num_active_display_regions() const {
802  determine_display_regions();
803  CDReader cdata(_cycler);
804  return cdata->_active_display_regions.size();
805 }
806 
807 /**
808  * Returns the nth active DisplayRegion of those that have been created within
809  * the window. This may return NULL if n is out of bounds; particularly
810  * likely if the number of display regions has changed since the last call to
811  * get_num_active_display_regions().
812  */
813 PT(DisplayRegion) GraphicsOutput::
814 get_active_display_region(int n) const {
815  determine_display_regions();
816 
817  CDReader cdata(_cycler);
818  if (n >= 0 && n < (int)cdata->_active_display_regions.size()) {
819  return cdata->_active_display_regions[n];
820  }
821  return nullptr;
822 }
823 
824 /**
825  * Creates and returns an offscreen buffer for rendering into, the result of
826  * which will be a texture suitable for applying to geometry within the scene
827  * rendered into this window.
828  *
829  * If tex is not NULL, it is the texture that will be set up for rendering
830  * into; otherwise, a new Texture object will be created. In either case, the
831  * target texture can be retrieved from the return value with
832  * buffer->get_texture() (assuming the return value is not NULL).
833  *
834  * If to_ram is true, the buffer will be set up to download its contents to
835  * the system RAM memory associated with the Texture object, instead of
836  * keeping it strictly within texture memory; this is much slower, but it
837  * allows using the texture with any GSG.
838  *
839  * This will attempt to be smart about maximizing render performance while
840  * minimizing framebuffer waste. It might return a GraphicsBuffer set to
841  * render directly into a texture, if possible; or it might return a
842  * ParasiteBuffer that renders into this window. The return value is NULL if
843  * the buffer could not be created for some reason.
844  *
845  * When you are done using the buffer, you should remove it with a call to
846  * GraphicsEngine::remove_window().
847  */
848 GraphicsOutput *GraphicsOutput::
849 make_texture_buffer(const string &name, int x_size, int y_size,
850  Texture *tex, bool to_ram, FrameBufferProperties *fbp) {
851 
852  FrameBufferProperties props;
853  props.set_rgb_color(1);
854  props.set_color_bits(1);
855  props.set_alpha_bits(1);
856  props.set_depth_bits(1);
857 
858  if (fbp == nullptr) {
859  fbp = &props;
860  }
861 
862  int flags = GraphicsPipe::BF_refuse_window;
863  if (textures_power_2 != ATS_none) {
864  flags |= GraphicsPipe::BF_size_power_2;
865  }
866  if (tex != nullptr &&
867  tex->get_texture_type() == Texture::TT_cube_map) {
868  flags |= GraphicsPipe::BF_size_square;
869  }
870 
871  GraphicsOutput *buffer = get_gsg()->get_engine()->
872  make_output(get_gsg()->get_pipe(),
873  name, get_child_sort(),
874  *fbp, WindowProperties::size(x_size, y_size),
875  flags, get_gsg(), get_host());
876 
877  if (buffer != nullptr) {
878  if (buffer->get_gsg() == nullptr ||
879  buffer->get_gsg()->get_prepared_objects() != get_gsg()->get_prepared_objects()) {
880  // If the newly-created buffer doesn't share texture objects with the
881  // current GSG, then we will have to force the texture copy to go
882  // through RAM.
883  to_ram = true;
884  }
885 
886  buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_bind_or_copy);
887  return buffer;
888  }
889 
890  return nullptr;
891 }
892 
893 /**
894  * This is similar to make_texture_buffer() in that it allocates a separate
895  * buffer suitable for rendering to a texture that can be assigned to geometry
896  * in this window, but in this case, the buffer is set up to render the six
897  * faces of a cube map.
898  *
899  * The buffer is automatically set up with six display regions and six
900  * cameras, each of which are assigned the indicated draw_mask and parented to
901  * the given camera_rig node (which you should then put in your scene to
902  * render the cube map from the appropriate point of view).
903  *
904  * You may take the texture associated with the buffer and apply it to
905  * geometry, particularly with TexGenAttrib::M_world_cube_map also in effect,
906  * to apply a reflection of everything seen by the camera rig.
907  */
909 make_cube_map(const string &name, int size, NodePath &camera_rig,
910  DrawMask camera_mask, bool to_ram, FrameBufferProperties *fbp) {
911  if (!to_ram) {
912  // Check the limits imposed by the GSG. (However, if we're rendering the
913  // texture to RAM only, these limits may be irrelevant.)
915  int max_dimension = gsg->get_max_cube_map_dimension();
916  if (max_dimension == 0 || !gsg->get_supports_cube_map()) {
917  // The GSG doesn't support cube mapping; too bad for you.
918  display_cat.warning()
919  << "Cannot make dynamic cube map; GSG does not support cube maps.\n";
920  return nullptr;
921  }
922  if (max_dimension > 0) {
923  size = std::min(max_dimension, size);
924  }
925  }
926 
927  // Usually, we want the whole camera_rig to keep itself unrotated with
928  // respect to the world coordinate space, so the user can apply
929  // TexGenAttrib::M_world_cube_map to the objects on which the cube map
930  // texture is applied. If for some reason the user doesn't want this
931  // behavior, he can take this effect off again.
932  camera_rig.node()->set_effect(CompassEffect::make(NodePath()));
933 
934  PT(Texture) tex = new Texture(name);
935  tex->setup_cube_map();
936  tex->set_wrap_u(SamplerState::WM_clamp);
937  tex->set_wrap_v(SamplerState::WM_clamp);
938  GraphicsOutput *buffer;
939 
940  buffer = make_texture_buffer(name, size, size, tex, to_ram, fbp);
941 
942  // We don't need to clear the overall buffer; instead, we'll clear each
943  // display region.
944  buffer->set_clear_color_active(false);
945  buffer->set_clear_depth_active(false);
946  buffer->set_clear_stencil_active(false);
947 
948  PT(Lens) lens = new PerspectiveLens(90, 90);
949 
950  for (int i = 0; i < 6; i++) {
951  PT(Camera) camera = new Camera(cube_faces[i]._name);
952  camera->set_lens(lens);
953  camera->set_camera_mask(camera_mask);
954  NodePath camera_np = camera_rig.attach_new_node(camera);
955  camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up);
956 
957  DisplayRegion *dr;
958  dr = buffer->make_display_region();
959 
960  dr->set_target_tex_page(i);
961  dr->copy_clear_settings(*this);
962  dr->set_camera(camera_np);
963  }
964 
965  return buffer;
966 }
967 
968 /**
969  * Returns a PandaNode containing a square polygon. The dimensions are
970  * (-1,0,-1) to (1,0,1). The texture coordinates are such that the texture of
971  * this GraphicsOutput is aligned properly to the polygon. The GraphicsOutput
972  * promises to surgically update the Geom inside the PandaNode if necessary to
973  * maintain this invariant.
974  *
975  * Each invocation of this function returns a freshly- allocated PandaNode.
976  * You can therefore safely modify the RenderAttribs of the PandaNode. The
977  * PandaNode is initially textured with the texture of this GraphicOutput.
978  */
981  if (_texture_card == nullptr) {
982  PT(GeomVertexData) vdata = create_texture_card_vdata(get_x_size(), get_y_size());
983  PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
984  strip->set_shade_model(Geom::SM_uniform);
985  strip->add_next_vertices(4);
986  strip->close_primitive();
987  PT(Geom) geom = new Geom(vdata);
988  geom->add_primitive(strip);
989  _texture_card = new GeomNode("texture card");
990  _texture_card->add_geom(geom);
991  }
992 
993  NodePath path("texture card");
994  path.node()->add_child(_texture_card);
995 
996  // The texture card, by default, is textured with the first render-to-
997  // texture output texture. Depth and stencil textures are ignored. The
998  // user can freely alter the card's texture attrib.
999  CDReader cdata(_cycler);
1000  RenderTextures::const_iterator ri;
1001  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1002  Texture *texture = (*ri)._texture;
1003  if ((texture->get_format() != Texture::F_depth_stencil)) {
1004  path.set_texture(texture, 0);
1005  break;
1006  }
1007  }
1008 
1009  return path;
1010 }
1011 
1012 /**
1013  * Will attempt to use the depth buffer of the input graphics_output. The
1014  * buffer sizes must be exactly the same.
1015  */
1016 bool GraphicsOutput::
1018  return false;
1019 }
1020 
1021 /**
1022  * Discontinue sharing the depth buffer.
1023  */
1024 void GraphicsOutput::
1026 }
1027 
1028 /**
1029  * Returns true if this particular GraphicsOutput can render directly into a
1030  * texture, or false if it must always copy-to-texture at the end of each
1031  * frame to achieve this effect.
1032  */
1033 bool GraphicsOutput::
1034 get_supports_render_texture() const {
1035  return false;
1036 }
1037 
1038 /**
1039  * Returns true if a frame has been rendered and needs to be flipped, false
1040  * otherwise.
1041  */
1042 bool GraphicsOutput::
1043 flip_ready() const {
1044  return _flip_ready;
1045 }
1046 
1047 /**
1048  * This is normally called only from within make_texture_buffer(). When
1049  * called on a ParasiteBuffer, it returns the host of that buffer; but when
1050  * called on some other buffer, it returns the buffer itself.
1051  */
1054  return this;
1055 }
1056 
1057 /**
1058  * This is called by the GraphicsEngine to request that the window (or
1059  * whatever) open itself or, in general, make itself valid, at the next call
1060  * to process_events().
1061  */
1062 void GraphicsOutput::
1064 }
1065 
1066 /**
1067  * This is called by the GraphicsEngine to request that the window (or
1068  * whatever) close itself or, in general, make itself invalid, at the next
1069  * call to process_events(). By that time we promise the gsg pointer will be
1070  * cleared.
1071  */
1072 void GraphicsOutput::
1074 }
1075 
1076 /**
1077  * This is called by the GraphicsEngine to insist that the output be closed
1078  * immediately. This is only called from the window thread.
1079  */
1080 void GraphicsOutput::
1082 }
1083 
1084 /**
1085  * Resets the window framebuffer from its derived children. Does nothing
1086  * here.
1087  */
1088 void GraphicsOutput::
1089 reset_window(bool swapchain) {
1090  display_cat.info()
1091  << "Resetting " << get_type() << "\n";
1092 }
1093 
1094 /**
1095  * Sets the window's _pipe pointer to NULL; this is generally called only as a
1096  * precursor to deleting the window.
1097  */
1098 void GraphicsOutput::
1100  _pipe = nullptr;
1101 }
1102 
1103 /**
1104  * Changes the x_size and y_size, then recalculates structures that depend on
1105  * size. The recalculation currently includes: - compute_pixels on all the
1106  * graphics regions. - updating the texture card, if one is present.
1107  */
1108 void GraphicsOutput::
1109 set_size_and_recalc(int x, int y) {
1110  _size.set(x, y);
1111  _has_size = true;
1112 
1113  _is_nonzero_size = (x > 0 && y > 0);
1114 
1115  int fb_x_size = get_fb_x_size();
1116  int fb_y_size = get_fb_y_size();
1117 
1118  TotalDisplayRegions::iterator dri;
1119  for (dri = _total_display_regions.begin();
1120  dri != _total_display_regions.end();
1121  ++dri) {
1122  (*dri)->compute_pixels_all_stages(fb_x_size, fb_y_size);
1123  }
1124 
1125  if (_texture_card != nullptr && _texture_card->get_num_geoms() > 0) {
1126  _texture_card->modify_geom(0)->set_vertex_data(create_texture_card_vdata(x, y));
1127  }
1128 }
1129 
1130 /**
1131  * Clears the entire framebuffer before rendering, according to the settings
1132  * of get_color_clear_active() and get_depth_clear_active() (inherited from
1133  * DrawableRegion).
1134  *
1135  * This function is called only within the draw thread.
1136  */
1137 void GraphicsOutput::
1138 clear(Thread *current_thread) {
1139  if (is_any_clear_active()) {
1140  if (display_cat.is_spam()) {
1141  display_cat.spam()
1142  << "clear(): " << get_type() << " "
1143  << get_name() << " " << (void *)this << "\n";
1144  }
1145 
1146  nassertv(_gsg != nullptr);
1147 
1148  DisplayRegionPipelineReader dr_reader(_overlay_display_region, current_thread);
1149  _gsg->prepare_display_region(&dr_reader);
1150  _gsg->clear(this);
1151  }
1152 }
1153 
1154 /**
1155  * This function will be called within the draw thread before beginning
1156  * rendering for a given frame. It should do whatever setup is required, and
1157  * return true if the frame should be rendered, or false if it should be
1158  * skipped.
1159  */
1160 bool GraphicsOutput::
1161 begin_frame(FrameMode mode, Thread *current_thread) {
1162  return false;
1163 }
1164 
1165 /**
1166  * This function will be called within the draw thread after rendering is
1167  * completed for a given frame. It should do whatever finalization is
1168  * required.
1169  */
1170 void GraphicsOutput::
1171 end_frame(FrameMode mode, Thread *current_thread) {
1172 }
1173 
1174 /**
1175  * Called by the GraphicsEngine when the window is about to change to another
1176  * DisplayRegion. This exists mainly to provide a callback for switching the
1177  * cube map face, if we are rendering to the different faces of a cube map.
1178  */
1179 void GraphicsOutput::
1181  int new_target_tex_page = new_dr->get_target_tex_page();
1182 
1183  if (new_target_tex_page != -1 && new_target_tex_page != _target_tex_page) {
1184 
1185  if (new_target_tex_page == -1) {
1186  new_target_tex_page = 0;
1187  }
1188  int old_target_tex_page = _target_tex_page;
1189  DisplayRegion *old_page_dr = _prev_page_dr;
1190  _target_tex_page = new_target_tex_page;
1191  _prev_page_dr = new_dr->get_object();
1192 
1193  CDReader cdata(_cycler);
1194  RenderTextures::const_iterator ri;
1195  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1196  RenderTextureMode rtm_mode = (*ri)._rtm_mode;
1197  RenderTexturePlane plane = (*ri)._plane;
1198  Texture *texture = (*ri)._texture;
1199  if (rtm_mode != RTM_none) {
1200  if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
1201  // In render-to-texture mode, switch the rendering backend to the
1202  // new page, so that the subsequent frame will be rendered to the
1203  // correct page.
1204  select_target_tex_page(_target_tex_page);
1205 
1206  } else if (old_target_tex_page != -1) {
1207  // In copy-to-texture mode, copy the just-rendered framebuffer to
1208  // the old texture page.
1209 
1210  nassertv(old_page_dr != nullptr);
1211  if (display_cat.is_debug()) {
1212  display_cat.debug()
1213  << "Copying texture for " << get_name() << " at scene change.\n";
1214  display_cat.debug()
1215  << "target_tex_page = " << old_target_tex_page << "\n";
1216  }
1217  RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
1218  get_fb_properties());
1219 
1220  if (plane == RTP_color && _fb_properties.is_stereo()) {
1221  // We've got two texture views to copy.
1222  RenderBuffer left(_gsg, buffer._buffer_type & ~RenderBuffer::T_right);
1223  RenderBuffer right(_gsg, buffer._buffer_type & ~RenderBuffer::T_left);
1224 
1225  if (rtm_mode == RTM_copy_ram) {
1226  _gsg->framebuffer_copy_to_ram(texture, 0, old_target_tex_page,
1227  old_page_dr, left);
1228  _gsg->framebuffer_copy_to_ram(texture, 1, old_target_tex_page,
1229  old_page_dr, right);
1230  } else {
1231  _gsg->framebuffer_copy_to_texture(texture, 0, old_target_tex_page,
1232  old_page_dr, left);
1233  _gsg->framebuffer_copy_to_texture(texture, 1, old_target_tex_page,
1234  old_page_dr, right);
1235  }
1236  } else {
1237  if (rtm_mode == RTM_copy_ram) {
1238  _gsg->framebuffer_copy_to_ram(texture, 0, old_target_tex_page,
1239  old_page_dr, buffer);
1240  } else {
1241  _gsg->framebuffer_copy_to_texture(texture, 0, old_target_tex_page,
1242  old_page_dr, buffer);
1243  }
1244  }
1245  }
1246  }
1247  }
1248  }
1249 }
1250 
1251 /**
1252  * Called internally when the window is in render-to-a-texture mode and we are
1253  * in the process of rendering the six faces of a cube map, or any other
1254  * multi-page texture. This should do whatever needs to be done to switch the
1255  * buffer to the indicated page.
1256  */
1257 void GraphicsOutput::
1259 }
1260 
1261 /**
1262  * This function will be called within the draw thread after end_frame() has
1263  * been called on all windows, to initiate the exchange of the front and back
1264  * buffers.
1265  *
1266  * This should instruct the window to prepare for the flip at the next video
1267  * sync, but it should not wait.
1268  *
1269  * We have the two separate functions, begin_flip() and end_flip(), to make it
1270  * easier to flip all of the windows at the same time.
1271  */
1272 void GraphicsOutput::
1274 }
1275 
1276 /**
1277  * This function will be called within the draw thread after end_frame() has
1278  * been called on all windows, to initiate the exchange of the front and back
1279  * buffers.
1280  *
1281  * This should instruct the window to prepare for the flip when it is command
1282  * but not actually flip
1283  *
1284  */
1285 void GraphicsOutput::
1287 }
1288 
1289 /**
1290  * This function will be called within the draw thread after begin_flip() has
1291  * been called on all windows, to finish the exchange of the front and back
1292  * buffers.
1293  *
1294  * This should cause the window to wait for the flip, if necessary.
1295  */
1296 void GraphicsOutput::
1298  _flip_ready = false;
1299 }
1300 
1301 /**
1302  * Do whatever processing in the window thread is appropriate for this output
1303  * object each frame.
1304  *
1305  * This function is called only within the window thread.
1306  */
1307 void GraphicsOutput::
1309 }
1310 
1311 /**
1312  * Called internally when the pixel factor changes.
1313  */
1314 void GraphicsOutput::
1315 pixel_factor_changed() {
1316  if (_has_size) {
1318  }
1319 }
1320 
1321 /**
1322  * Set the delete flag, and do the usual cleanup activities associated with
1323  * that.
1324  */
1325 void GraphicsOutput::
1326 prepare_for_deletion() {
1327  CDWriter cdata(_cycler, true);
1328  cdata->_active = false;
1329 
1330  // If we were rendering directly to texture, we can't delete the buffer
1331  // until all the textures are gone too.
1332  RenderTextures::iterator ri;
1333  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1334  if ((*ri)._rtm_mode == RTM_bind_or_copy || (*ri)._rtm_mode == RTM_bind_layered) {
1335  _hold_textures.push_back((*ri)._texture);
1336  }
1337  }
1338  cdata->_textures.clear();
1339 
1340  _delete_flag = true;
1341 
1342  // We have to be sure to remove all of the display regions immediately, so
1343  // that circular reference counts can be cleared up (each display region
1344  // keeps a pointer to a CullResult, which can hold all sorts of pointers).
1346 }
1347 
1348 /**
1349  * If any textures are marked RTM_bind_or_copy, change them to
1350  * RTM_copy_texture. This does not change textures that are set to
1351  * RTM_bind_layered, as layered framebuffers aren't supported with
1352  * RTM_copy_texture.
1353  */
1354 void GraphicsOutput::
1355 promote_to_copy_texture() {
1356  CDLockedReader cdata(_cycler);
1357  RenderTextures::const_iterator ri;
1358 
1359  bool any_bind = false;
1360  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1361  if ((*ri)._rtm_mode == RTM_bind_or_copy) {
1362  any_bind = true;
1363  break;
1364  }
1365  }
1366  if (any_bind) {
1367  CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true);
1368  RenderTextures::iterator ri;
1369  for (ri = cdataw->_textures.begin(); ri != cdataw->_textures.end(); ++ri) {
1370  if ((*ri)._rtm_mode == RTM_bind_or_copy) {
1371  (*ri)._rtm_mode = RTM_copy_texture;
1372  }
1373  }
1374  }
1375 }
1376 
1377 /**
1378  * For all textures marked RTM_copy_texture, RTM_copy_ram,
1379  * RTM_triggered_copy_texture, or RTM_triggered_copy_ram, do the necessary
1380  * copies.
1381  *
1382  * Returns true if all copies are successful, false otherwise.
1383  */
1384 bool GraphicsOutput::
1385 copy_to_textures() {
1386  bool okflag = true;
1387 
1388  CDReader cdata(_cycler);
1389  RenderTextures::const_iterator ri;
1390  for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
1391  RenderTextureMode rtm_mode = (*ri)._rtm_mode;
1392  if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) {
1393  continue;
1394  }
1395 
1396  Texture *texture = (*ri)._texture;
1397  PStatTimer timer(_copy_texture_pcollector);
1398 
1399  if ((rtm_mode == RTM_copy_texture)||
1400  (rtm_mode == RTM_copy_ram)||
1401  ((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
1402  ((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
1403  if (display_cat.is_debug()) {
1404  display_cat.debug()
1405  << "Copying texture for " << get_name() << " at frame end.\n";
1406  display_cat.debug()
1407  << "target_tex_page = " << _target_tex_page << "\n";
1408  }
1409  RenderTexturePlane plane = (*ri)._plane;
1411  if (plane == RTP_color) {
1412  buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
1413  get_fb_properties());
1414  }
1415 
1416  bool copied = false;
1417  DisplayRegion *dr = _overlay_display_region;
1418  if (_prev_page_dr != nullptr) {
1419  dr = _prev_page_dr;
1420  }
1421 
1422  if (plane == RTP_color && _fb_properties.is_stereo()) {
1423  // We've got two texture views to copy.
1424  RenderBuffer left(_gsg, buffer._buffer_type & ~RenderBuffer::T_right);
1425  RenderBuffer right(_gsg, buffer._buffer_type & ~RenderBuffer::T_left);
1426 
1427  if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
1428  copied = _gsg->framebuffer_copy_to_ram(texture, 0, _target_tex_page,
1429  dr, left);
1430  copied = _gsg->framebuffer_copy_to_ram(texture, 1, _target_tex_page,
1431  dr, right) && copied;
1432  } else {
1433  copied = _gsg->framebuffer_copy_to_texture(texture, 0, _target_tex_page,
1434  dr, left);
1435  copied = _gsg->framebuffer_copy_to_texture(texture, 1, _target_tex_page,
1436  dr, right) && copied;
1437  }
1438  } else {
1439  if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
1440  copied = _gsg->framebuffer_copy_to_ram(texture, 0, _target_tex_page,
1441  dr, buffer);
1442  } else {
1443  copied = _gsg->framebuffer_copy_to_texture(texture, 0, _target_tex_page,
1444  dr, buffer);
1445  }
1446  }
1447  if (!copied) {
1448  okflag = false;
1449  }
1450  }
1451  }
1452  if (_trigger_copy != nullptr) {
1453  _trigger_copy->set_result(nullptr);
1454  _trigger_copy = nullptr;
1455  }
1456 
1457  return okflag;
1458 }
1459 
1460 /**
1461  * Generates a GeomVertexData for a texture card.
1462  */
1463 PT(GeomVertexData) GraphicsOutput::
1464 create_texture_card_vdata(int x, int y) {
1465  PN_stdfloat xhi = 1.0;
1466  PN_stdfloat yhi = 1.0;
1467 
1468  if (Texture::get_textures_power_2() != ATS_none) {
1469  int xru = Texture::up_to_power_2(x);
1470  int yru = Texture::up_to_power_2(y);
1471  xhi = (x * 1.0f) / xru;
1472  yhi = (y * 1.0f) / yru;
1473  }
1474 
1476 
1477  PT(GeomVertexData) vdata = new GeomVertexData
1478  ("card", format, Geom::UH_static);
1479 
1480  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
1481  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
1482  GeomVertexWriter normal(vdata, InternalName::get_normal());
1483 
1484  vertex.add_data3(LVertex::rfu(-1.0f, 0.0f, 1.0f));
1485  vertex.add_data3(LVertex::rfu(-1.0f, 0.0f, -1.0f));
1486  vertex.add_data3(LVertex::rfu( 1.0f, 0.0f, 1.0f));
1487  vertex.add_data3(LVertex::rfu( 1.0f, 0.0f, -1.0f));
1488 
1489  texcoord.add_data2( 0.0f, yhi);
1490  texcoord.add_data2( 0.0f, 0.0f);
1491  texcoord.add_data2( xhi, yhi);
1492  texcoord.add_data2( xhi, 0.0f);
1493 
1494  normal.add_data3(LVector3::back());
1495  normal.add_data3(LVector3::back());
1496  normal.add_data3(LVector3::back());
1497  normal.add_data3(LVector3::back());
1498 
1499  return vdata;
1500 }
1501 
1502 /**
1503  * Called by the DisplayRegion constructor to add the new DisplayRegion to the
1504  * list.
1505  */
1506 DisplayRegion *GraphicsOutput::
1507 add_display_region(DisplayRegion *display_region) {
1508  LightMutexHolder holder(_lock);
1509  CDWriter cdata(_cycler, true);
1510  cdata->_active_display_regions_stale = true;
1511 
1512  _total_display_regions.push_back(display_region);
1513 
1514  return display_region;
1515 }
1516 
1517 /**
1518  * Internal implementation of remove_display_region. Assumes the lock is
1519  * already held.
1520  */
1521 bool GraphicsOutput::
1522 do_remove_display_region(DisplayRegion *display_region) {
1523  nassertr(display_region != _overlay_display_region, false);
1524 
1525  PT(DisplayRegion) drp = display_region;
1526  TotalDisplayRegions::iterator dri =
1527  find(_total_display_regions.begin(), _total_display_regions.end(), drp);
1528  if (dri != _total_display_regions.end()) {
1529  // Let's aggressively clean up the display region too.
1530  display_region->cleanup();
1531  display_region->_window = nullptr;
1532  _total_display_regions.erase(dri);
1533 
1534  OPEN_ITERATE_ALL_STAGES(_cycler) {
1535  CDStageWriter cdata(_cycler, pipeline_stage);
1536  cdata->_active_display_regions_stale = true;
1537  }
1538  CLOSE_ITERATE_ALL_STAGES(_cycler);
1539  return true;
1540  }
1541 
1542  return false;
1543 }
1544 
1545 /**
1546  * Re-sorts the list of active DisplayRegions within the window.
1547  */
1548 void GraphicsOutput::
1549 do_determine_display_regions(GraphicsOutput::CData *cdata) {
1550  cdata->_active_display_regions_stale = false;
1551 
1552  cdata->_active_display_regions.clear();
1553  cdata->_active_display_regions.reserve(_total_display_regions.size());
1554 
1555  int index = 0;
1556  TotalDisplayRegions::const_iterator dri;
1557  for (dri = _total_display_regions.begin();
1558  dri != _total_display_regions.end();
1559  ++dri) {
1560  DisplayRegion *display_region = (*dri);
1561  if (display_region->is_active()) {
1562  cdata->_active_display_regions.push_back(display_region);
1563  display_region->set_active_index(index);
1564  ++index;
1565  } else {
1566  display_region->set_active_index(-1);
1567  }
1568  }
1569 
1570  std::stable_sort(cdata->_active_display_regions.begin(),
1571  cdata->_active_display_regions.end(),
1573 }
1574 
1575 /**
1576  * Parses one of the keywords in the red-blue-stereo-colors Config.prc
1577  * variable, and returns the corresponding bitmask.
1578  *
1579  * These bitmask values are taken from ColorWriteAttrib.
1580  */
1581 unsigned int GraphicsOutput::
1582 parse_color_mask(const string &word) {
1583  unsigned int result = 0;
1584  vector_string components;
1585  tokenize(word, components, "|");
1586 
1587  vector_string::const_iterator ci;
1588  for (ci = components.begin(); ci != components.end(); ++ci) {
1589  string w = downcase(*ci);
1590  if (w == "red" || w == "r") {
1591  result |= 0x001;
1592 
1593  } else if (w == "green" || w == "g") {
1594  result |= 0x002;
1595 
1596  } else if (w == "blue" || w == "b") {
1597  result |= 0x004;
1598 
1599  } else if (w == "yellow" || w == "y") {
1600  result |= 0x003;
1601 
1602  } else if (w == "magenta" || w == "m") {
1603  result |= 0x005;
1604 
1605  } else if (w == "cyan" || w == "c") {
1606  result |= 0x006;
1607 
1608  } else if (w == "alpha" || w == "a") {
1609  result |= 0x008;
1610 
1611  } else if (w == "off") {
1612 
1613  } else {
1614  display_cat.warning()
1615  << "Invalid color in red-blue-stereo-colors: " << (*ci) << "\n";
1616  }
1617  }
1618 
1619  return result;
1620 }
1621 
1622 /**
1623  *
1624  */
1625 GraphicsOutput::CData::
1626 CData() {
1627  // The default is *not* active, so the entire pipeline stage is initially
1628  // populated with inactive outputs. Pipeline stage 0 is set to active in
1629  // the constructor.
1630  _active = false;
1631  _one_shot_frame = -1;
1632  _active_display_regions_stale = false;
1633 }
1634 
1635 /**
1636  *
1637  */
1638 GraphicsOutput::CData::
1639 CData(const GraphicsOutput::CData &copy) :
1640  _textures(copy._textures),
1641  _active(copy._active),
1642  _one_shot_frame(copy._one_shot_frame),
1643  _active_display_regions(copy._active_display_regions),
1644  _active_display_regions_stale(copy._active_display_regions_stale)
1645 {
1646 }
1647 
1648 /**
1649  *
1650  */
1651 CycleData *GraphicsOutput::CData::
1652 make_copy() const {
1653  return new CData(*this);
1654 }
1655 
1656 /**
1657  *
1658  */
1659 std::ostream &
1660 operator << (std::ostream &out, GraphicsOutput::FrameMode fm) {
1661  switch (fm) {
1662  case GraphicsOutput::FM_render:
1663  return out << "render";
1664  case GraphicsOutput::FM_parasite:
1665  return out << "parasite";
1666  case GraphicsOutput::FM_refresh:
1667  return out << "refresh";
1668  }
1669 
1670  return out << "(**invalid GraphicsOutput::FrameMode(" << (int)fm << ")**)";
1671 }
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void request_close()
This is called by the GraphicsEngine to request that the window (or whatever) close itself or,...
static int get_renderbuffer_type(int plane)
Returns the RenderBuffer::Type that corresponds to a RenderTexturePlane.
void set_size_and_recalc(int x, int y)
Changes the x_size and y_size, then recalculates structures that depend on size.
void cleanup()
Cleans up some pointers associated with the DisplayRegion to help reduce the chance of memory leaks d...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_num_views
Sets the number of "views" within a texture.
Definition: texture.h:346
StereoDisplayRegion * make_stereo_display_region()
Creates a new DisplayRegion that covers the entire window.
virtual GraphicsOutput * get_host()
This is normally called only from within make_texture_buffer().
GraphicsOutput * make_cube_map(const std::string &name, int size, NodePath &camera_rig, DrawMask camera_mask=PandaNode::get_all_camera_mask(), bool to_ram=false, FrameBufferProperties *fbp=nullptr)
This is similar to make_texture_buffer() in that it allocates a separate buffer suitable for renderin...
void set_side_by_side_stereo(bool side_by_side_stereo)
Enables side-by-side stereo mode on this particular window.
std::string get_word(size_t n) const
Returns the variable's nth value.
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
const LColor & get_value() const
Returns the variable's value.
get_z_size
Returns the depth of the texture image in texels.
Definition: texture.h:342
virtual void end_flip()
This function will be called within the draw thread after begin_flip() has been called on all windows...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_match_framebuffer_format
Sets the special flag that, if true, indicates to the GSG that the Texture's format should be chosen ...
Definition: texture.h:581
void change_scenes(DisplayRegionPipelineReader *new_dr)
Called by the GraphicsEngine when the window is about to change to another DisplayRegion.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_wrap_v
This setting determines what happens when the texture is sampled with a V value outside the range 0....
Definition: texture.h:374
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
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
int get_y_size() const
Returns the visible height of the window or buffer, if it is known.
get_texture_type
Returns the overall interpretation of the texture.
Definition: texture.h:357
void add_data2(PN_stdfloat x, PN_stdfloat y)
Sets the write row to a particular 2-component value, and advances the write row.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_clear_color_active(bool clear_color_active)
Toggles the flag that indicates whether the color buffer should be cleared every frame.
void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram)
This is a deprecated interface that made sense back when GraphicsOutputs could only render into one t...
get_child_sort
Returns the sort value of future offscreen buffers created by make_texture_sort().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
Defines a series of triangle strips.
Definition: geomTristrips.h:23
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
is_stereo
Returns true if this is a StereoDisplayRegion, false otherwise.
Definition: displayRegion.h:90
int get_fb_y_size() const
Returns the internal height of the window or buffer.
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.
void setup_cube_map()
Sets the texture as an empty cube map texture with no dimensions.
Definition: texture.I:155
static const GeomVertexFormat * get_v3n3t2()
Returns a standard vertex format with a 2-component texture coordinate pair, a 3-component normal,...
get_max_cube_map_dimension
Returns the largest possible texture size in any one dimension for a cube map texture,...
PT(DisplayRegion) GraphicsOutput
Returns the nth DisplayRegion of those that have been created within the window.
DisplayRegion * make_display_region()
Creates a new DisplayRegion that covers the entire window.
static WindowProperties size(const LVecBase2i &size)
Returns a WindowProperties structure with only the size specified.
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
virtual void select_target_tex_page(int page)
Called internally when the window is in render-to-a-texture mode and we are in the process of renderi...
bool is_valid() const
Returns true if the output is fully created and ready for rendering, false otherwise.
void set_texture(Texture *tex, int priority=0)
Adds the indicated texture to the list of textures that will be rendered on the default texture stage...
Definition: nodePath.cxx:2871
An STL function object class, this is intended to be used on any ordered collection of pointers to cl...
Definition: indirectLess.h:25
set_render_to_texture
Sets a flag on the texture that indicates whether the texture is intended to be used as a direct-rend...
Definition: texture.h:409
void set_size_padded(int x=1, int y=1, int z=1)
Changes the size of the texture, padding if necessary, and setting the pad region as well.
Definition: texture.cxx:1907
A lightweight class that represents a single element that may be timed and/or counted via stats.
static AutoTextureScale get_textures_power_2()
This flag returns ATS_none, ATS_up, or ATS_down and controls the scaling of textures in general.
Definition: texture.I:1863
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition: texture.h:362
virtual void set_close_now()
This is called by the GraphicsEngine to insist that the output be closed immediately.
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...
virtual void clear_pipe()
Sets the window's _pipe pointer to NULL; this is generally called only as a precursor to deleting the...
void set_clear_stencil_active(bool clear_stencil_active)
Toggles the flag that indicates whether the stencil buffer should be cleared every frame.
virtual void request_open()
This is called by the GraphicsEngine to request that the window (or whatever) open itself or,...
DisplayRegion * make_mono_display_region()
Creates a new DisplayRegion that covers the entire window.
set_sort
Adjusts the sorting order of this particular GraphicsOutput, relative to other GraphicsOutputs.
virtual void clear(Thread *current_thread)
Clears the entire framebuffer before rendering, according to the settings of get_color_clear_active()...
set_one_shot
Changes the current setting of the one-shot flag.
bool get_delete_flag() const
Returns the current setting of the delete flag.
get_frame_count
Returns the number of times tick() has been called since the ClockObject was created,...
Definition: clockObject.h:94
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool setup_depth_texture(Texture *tex) const
Sets the texture up for render-to-texture matching these framebuffer properties.
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
set_format
Changes the format value for the texture components.
Definition: texture.h:362
Similar to MutexHolder, but for a light mutex.
get_pipe
Returns the GraphicsPipe that this window is associated with.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A perspective-type lens: a normal camera.
NodePath get_texture_card()
Returns a PandaNode containing a square polygon.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
void copy_clear_settings(const DrawableRegion &copy)
Copies only the clear settings from the other drawable region.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
bool get_clear_depth_active() const
Returns the current setting of the flag that indicates whether the depth buffer should be cleared eve...
void set_clear_depth_active(bool clear_depth_active)
Toggles the flag that indicates whether the depth buffer should be cleared every frame.
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.
int get_target_tex_page() const
Returns the target page number associated with this particular DisplayRegion, or -1 if it is not asso...
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: pandaNode.cxx:1005
bool get_clear_stencil_active() const
Returns the current setting of the flag that indicates whether the color buffer should be cleared eve...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void remove_all_display_regions()
Removes all display regions from the window, except the default one that is created with the window.
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
set_color_bits
Sets the number of requested color bits as a single number that represents the sum of the individual ...
get_right_eye
Returns a pointer to the right DisplayRegion managed by this stereo object.
get_supports_cube_map
Returns true if this GSG can render cube map textures.
set_wrap_u
This setting determines what happens when the texture is sampled with a U value outside the range 0....
Definition: texture.h:370
This is a base class for the various different classes that represent the result of a frame of render...
This is a special DisplayRegion wrapper that actually includes a pair of DisplayRegions internally: t...
int get_x_size() const
Returns the visible width of the window or buffer, if it is known.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_draw_buffer_type() const
Returns the RenderBuffer into which the GSG should issue draw commands.
virtual void process_events()
Do whatever processing in the window thread is appropriate for this output object each frame.
void clear_ram_image()
Discards the current system-RAM image.
Definition: texture.I:1439
get_num_views
Returns the number of "views" in the texture.
Definition: texture.h:346
set_target_tex_page
This is a special parameter that is only used when rendering the faces of a cube map or multipage and...
virtual void reset_window(bool swapchain)
Resets the window framebuffer from its derived children.
get_size
Returns size in pixels of the useful part of the window, not including decorations.
void clear_render_textures()
If the GraphicsOutput is currently rendering to a texture, then all textures are dissociated from the...
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
Definition: memoryUsage.I:55
bool is_stereo() const
Returns Returns true if this window can render stereo DisplayRegions, either through red-blue stereo ...
set_camera
Sets the camera that is associated with this DisplayRegion.
Definition: displayRegion.h:94
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class defines the physical layout of the vertex data stored within a Geom.
void tokenize(const string &str, vector_string &words, const string &delimiters, bool discard_repeated_delimiters)
Chops the source string up into pieces delimited by any of the characters specified in delimiters.
virtual void ready_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_fb_x_size() const
Returns the internal width of the window or buffer.
virtual bool is_any_clear_active() const
Returns true if any of the clear types (so far there are just color or depth) have been set active,...
set_component_type
Changes the data value for the texture components.
Definition: texture.h:366
set_compression
Requests that this particular Texture be compressed when it is loaded into texture memory.
Definition: texture.h:405
static int up_to_power_2(int value)
Returns the smallest power of 2 greater than or equal to value.
Definition: texture.cxx:1983
get_name
Returns the name that was passed to the GraphicsOutput constructor.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
get_window
Returns the GraphicsOutput that this DisplayRegion is ultimately associated with, or NULL if no windo...
Definition: displayRegion.h:88
bool setup_color_texture(Texture *tex) const
Sets the texture up for render-to-texture matching these framebuffer properties.
A thread; that is, a lightweight process.
Definition: thread.h:46
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
get_supports_render_texture
Returns true if this particular GraphicsOutput can render directly into a texture,...
Encapsulates all the communication with a particular instance of a given rendering backend.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_left_eye
Returns a pointer to the left DisplayRegion managed by this stereo object.
set_active
Sets the active flag associated with the GraphicsOutput.
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:57
virtual bool flip_ready() const
Returns true if a frame has been rendered and needs to be flipped, false otherwise.
void set_overlay_display_region(DisplayRegion *display_region)
Replaces the special "overlay" DisplayRegion that is created for each window or buffer.
This class is the main interface to controlling the render process.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void add_render_texture(Texture *tex, RenderTextureMode mode, RenderTexturePlane bitplane=RTP_COUNT)
Creates a new Texture object, suitable for rendering the contents of this buffer into,...
set_inverted
Changes the current setting of the inverted flag.
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.
virtual void unshare_depth_buffer()
Discontinue sharing the depth buffer.
A RenderBuffer is an arbitrary subset of the various layers (depth buffer, color buffer,...
Definition: renderBuffer.h:27
get_gsg
Returns the GSG that is associated with this window.
has_size
Returns true if the window size has been specified, false otherwise.
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:161
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool remove_display_region(DisplayRegion *display_region)
Removes the indicated DisplayRegion from the window, and destructs it if there are no other reference...
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:34
virtual bool share_depth_buffer(GraphicsOutput *graphics_output)
Will attempt to use the depth buffer of the input graphics_output.
is_active
Returns the active flag associated with the DisplayRegion.
Definition: displayRegion.h:98
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
void look_at(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the transform on this NodePath so that it rotates to face the indicated point in space.
Definition: nodePath.I:789