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