Panda3D

graphicsOutput.cxx

00001 // Filename: graphicsOutput.cxx
00002 // Created by:  drose (06Feb04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "graphicsOutput.h"
00016 #include "graphicsPipe.h"
00017 #include "graphicsEngine.h"
00018 #include "graphicsWindow.h"
00019 #include "config_display.h"
00020 #include "lightMutexHolder.h"
00021 #include "renderBuffer.h"
00022 #include "indirectLess.h"
00023 #include "pStatTimer.h"
00024 #include "configVariableBool.h"
00025 #include "camera.h"
00026 #include "displayRegion.h"
00027 #include "lens.h"
00028 #include "perspectiveLens.h"
00029 #include "pointerTo.h"
00030 #include "compassEffect.h"
00031 #include "geom.h"
00032 #include "geomNode.h"
00033 #include "geomTristrips.h"
00034 #include "geomVertexWriter.h"
00035 #include "throw_event.h"
00036 #include "config_gobj.h"
00037 
00038 TypeHandle GraphicsOutput::_type_handle;
00039 
00040 PStatCollector GraphicsOutput::_make_current_pcollector("Draw:Make current");
00041 PStatCollector GraphicsOutput::_copy_texture_pcollector("Draw:Copy texture");
00042 PStatCollector GraphicsOutput::_cull_pcollector("Cull");
00043 PStatCollector GraphicsOutput::_draw_pcollector("Draw");
00044 
00045 struct CubeFaceDef {
00046   CubeFaceDef(const char *name, const LPoint3f &look_at, const LVector3f &up) :
00047     _name(name), _look_at(look_at), _up(up) { }
00048 
00049   const char *_name;
00050   LPoint3f _look_at;
00051   LVector3f _up;
00052 };
00053 
00054 static CubeFaceDef cube_faces[6] = {
00055   CubeFaceDef("positive_x", LPoint3f(1, 0, 0), LVector3f(0, -1, 0)),
00056   CubeFaceDef("negative_x", LPoint3f(-1, 0, 0), LVector3f(0, -1, 0)),
00057   CubeFaceDef("positive_y", LPoint3f(0, 1, 0), LVector3f(0, 0, 1)),
00058   CubeFaceDef("negative_y", LPoint3f(0, -1, 0), LVector3f(0, 0, -1)),
00059   CubeFaceDef("positive_z", LPoint3f(0, 0, 1), LVector3f(0, -1, 0)),
00060   CubeFaceDef("negative_z", LPoint3f(0, 0, -1), LVector3f(0, -1, 0))
00061 };
00062 
00063 ////////////////////////////////////////////////////////////////////
00064 //     Function: GraphicsOutput::Constructor
00065 //       Access: Protected
00066 //  Description: Normally, the GraphicsOutput constructor is not
00067 //               called directly; these are created instead via the
00068 //               GraphicsEngine::make_window() function.
00069 ////////////////////////////////////////////////////////////////////
00070 GraphicsOutput::
00071 GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
00072                const string &name,
00073                const FrameBufferProperties &fb_prop,
00074                const WindowProperties &win_prop,
00075                int flags,
00076                GraphicsStateGuardian *gsg,
00077                GraphicsOutput *host) :
00078   _lock("GraphicsOutput"),
00079   _cull_window_pcollector(_cull_pcollector, name),
00080   _draw_window_pcollector(_draw_pcollector, name)
00081 {
00082 #ifdef DO_MEMORY_USAGE
00083   MemoryUsage::update_type(this, this);
00084 #endif
00085   _engine = engine;
00086   _pipe = pipe;
00087   _gsg = gsg;
00088   _host = host;
00089   _fb_properties = fb_prop;
00090   _name = name;
00091   _creation_flags = flags;
00092   _x_size = _y_size = 0;
00093   _has_size = win_prop.has_size();
00094   if (_has_size) {
00095     _x_size = win_prop.get_x_size();
00096     _y_size = win_prop.get_y_size();
00097   }
00098   _is_valid = false;
00099   _flip_ready = false;
00100   _cube_map_index = -1;
00101   _cube_map_dr = NULL;
00102   _sort = 0;
00103   _child_sort = 0;
00104   _got_child_sort = false;
00105   _internal_sort_index = 0;
00106   _active = true;
00107   _one_shot = false;
00108   _inverted = window_inverted;
00109   _red_blue_stereo = false;
00110   _left_eye_color_mask = 0x0f;
00111   _right_eye_color_mask = 0x0f;
00112   _delete_flag = false;
00113   _texture_card = 0;
00114   _trigger_copy = false;
00115 
00116   if (_fb_properties.is_single_buffered()) {
00117     _draw_buffer_type = RenderBuffer::T_front;
00118   } else {
00119     _draw_buffer_type = RenderBuffer::T_back;
00120   }
00121 
00122   // We start out with one DisplayRegion that covers the whole window,
00123   // which we may use internally for full-window operations like
00124   // clear() and get_screenshot().
00125   _default_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f);
00126   _default_display_region->set_active(false);
00127 
00128   _display_regions_stale = false;
00129 
00130   // By default, each new GraphicsOutput is set up to clear color and
00131   // depth.
00132   set_clear_color_active(true);
00133   set_clear_depth_active(true);
00134   set_clear_stencil_active(true);
00135 
00136   switch (background_color.get_num_words()) {
00137   case 1:
00138     set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], 0.0f));
00139     break;
00140 
00141   case 2:
00142     set_clear_color(Colorf(background_color[0], background_color[0], background_color[0], background_color[1]));
00143     break;
00144 
00145   case 3:
00146     set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], 0.0f));
00147     break;
00148 
00149   case 4:
00150     set_clear_color(Colorf(background_color[0], background_color[1], background_color[2], background_color[3]));
00151     break;
00152 
00153   default:
00154     display_cat.warning()
00155       << "Invalid background-color specification: "
00156       << background_color.get_string_value() << "\n";
00157   }
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: GraphicsOutput::Copy Constructor
00162 //       Access: Private
00163 //  Description:
00164 ////////////////////////////////////////////////////////////////////
00165 GraphicsOutput::
00166 GraphicsOutput(const GraphicsOutput &) :
00167   _cull_window_pcollector(_cull_pcollector, "Invalid"),
00168   _draw_window_pcollector(_draw_pcollector, "Invalid")
00169 {
00170   nassertv(false);
00171 }
00172 
00173 ////////////////////////////////////////////////////////////////////
00174 //     Function: GraphicsOutput::Copy Assignment Operator
00175 //       Access: Private
00176 //  Description:
00177 ////////////////////////////////////////////////////////////////////
00178 void GraphicsOutput::
00179 operator = (const GraphicsOutput &) {
00180   nassertv(false);
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: GraphicsOutput::Destructor
00185 //       Access: Published, Virtual
00186 //  Description:
00187 ////////////////////////////////////////////////////////////////////
00188 GraphicsOutput::
00189 ~GraphicsOutput() {
00190   // The window should be closed by the time we destruct.
00191   nassertv(!is_valid());
00192 
00193   // We shouldn't have a GraphicsPipe pointer anymore.
00194   nassertv(_pipe == (GraphicsPipe *)NULL);
00195 
00196   // We don't have to destruct our child display regions explicitly,
00197   // since they are all reference-counted and will go away when their
00198   // pointers do.  However, we do need to zero out their pointers to
00199   // us.
00200   TotalDisplayRegions::iterator dri;
00201   for (dri = _total_display_regions.begin();
00202        dri != _total_display_regions.end();
00203        ++dri) {
00204     (*dri)->_window = NULL;
00205   }
00206 
00207   _total_display_regions.clear();
00208   _active_display_regions.clear();
00209   _default_display_region = NULL;
00210 }
00211 
00212 ////////////////////////////////////////////////////////////////////
00213 //     Function: GraphicsOutput::clear_render_textures
00214 //       Access: Published
00215 //  Description: If the GraphicsOutput is currently rendering to
00216 //               a texture, then all textures are dissociated from
00217 //               the GraphicsOuput.
00218 ////////////////////////////////////////////////////////////////////
00219 void GraphicsOutput::
00220 clear_render_textures() {
00221   LightMutexHolder holder(_lock);
00222   throw_event("render-texture-targets-changed");
00223   _textures.clear();
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: GraphicsOutput::add_render_texture
00228 //       Access: Published
00229 //  Description: Creates a new Texture object, suitable for rendering
00230 //               the contents of this buffer into, and appends it to
00231 //               the list of render textures.
00232 //
00233 //               If tex is not NULL, it is the texture that will be
00234 //               set up for rendering into; otherwise, a new Texture
00235 //               object will be created, in which case you may call
00236 //               get_texture() to retrieve the new texture pointer.
00237 //
00238 //               You can specify a bitplane to attach the texture to.
00239 //               the legal choices are:
00240 //
00241 //               * RTP_depth
00242 //               * RTP_depth_stencil
00243 //               * RTP_color
00244 //               * RTP_aux_rgba_0
00245 //               * RTP_aux_rgba_1
00246 //               * RTP_aux_rgba_2
00247 //               * RTP_aux_rgba_3
00248 //
00249 //               If you do not specify a bitplane to attach the
00250 //               texture to, this routine will use a default based
00251 //               on the texture's format:
00252 //
00253 //               * F_depth_component attaches to RTP_depth
00254 //               * F_depth_stencil attaches to RTP_depth_stencil
00255 //               * all other formats attach to RTP_color.
00256 //
00257 //               The texture's format will be changed to match
00258 //               the format of the bitplane to which it is attached.
00259 //               For example, if you pass in an F_rgba texture and
00260 //               order that it be attached to RTP_depth_stencil, it will turn
00261 //               into an F_depth_stencil texture.
00262 //
00263 //               Also see make_texture_buffer(), which is a
00264 //               higher-level interface for preparing
00265 //               render-to-a-texture mode.
00266 ////////////////////////////////////////////////////////////////////
00267 void GraphicsOutput::
00268 add_render_texture(Texture *tex, RenderTextureMode mode,
00269                    RenderTexturePlane plane) {
00270 
00271   if (mode == RTM_none) {
00272     return;
00273   }
00274   LightMutexHolder holder(_lock);
00275 
00276   throw_event("render-texture-targets-changed");
00277 
00278   // Create texture if necessary.
00279   if (tex == (Texture *)NULL) {
00280     tex = new Texture(get_name());
00281     tex->set_wrap_u(Texture::WM_clamp);
00282     tex->set_wrap_v(Texture::WM_clamp);
00283   } else {
00284     tex->clear_ram_image();
00285   }
00286 
00287   // Set it to have no compression by default.  You can restore
00288   // compression later if you really, really want it; but this freaks
00289   // out some drivers, and presumably it's a mistake if you have
00290   // compression enabled for a rendered texture.
00291   tex->set_compression(Texture::CM_off);
00292 
00293   // Choose a default bitplane.
00294   if (plane == RTP_COUNT) {
00295     if (tex->get_format()==Texture::F_depth_stencil) {
00296       plane = RTP_depth_stencil;
00297     } else if (tex->get_format()==Texture::F_depth_component) {
00298       plane = RTP_depth;
00299     } else {
00300       plane = RTP_color;
00301     }
00302   }
00303 
00304   // Set the texture's format to match the bitplane.
00305   // (And validate the bitplane, while we're at it).
00306 
00307   if (plane == RTP_depth) {
00308     tex->set_format(Texture::F_depth_component);
00309     tex->set_match_framebuffer_format(true);
00310   } else if (plane == RTP_depth_stencil) {
00311     tex->set_format(Texture::F_depth_stencil);
00312     tex->set_match_framebuffer_format(true);
00313   } else if ((plane == RTP_color)||
00314              (plane == RTP_aux_rgba_0)||
00315              (plane == RTP_aux_rgba_1)||
00316              (plane == RTP_aux_rgba_2)||
00317              (plane == RTP_aux_rgba_3)) {
00318     tex->set_format(Texture::F_rgba);
00319     tex->set_match_framebuffer_format(true);
00320   } else if  ((plane == RTP_aux_hrgba_0)||
00321               (plane == RTP_aux_hrgba_1)||
00322               (plane == RTP_aux_hrgba_2)||
00323               (plane == RTP_aux_hrgba_3)) {
00324     tex->set_format(Texture::F_rgba16);
00325     tex->set_match_framebuffer_format(true);
00326   } else
00327 
00328   {
00329     display_cat.error() <<
00330       "add_render_texture: invalid bitplane specified.\n";
00331     return;
00332   }
00333 
00334   // Go ahead and tell the texture our anticipated size, even if it
00335   // might be inaccurate (particularly if this is a GraphicsWindow,
00336   // which has system-imposed restrictions on size).
00337   tex->set_size_padded(get_x_size(), get_y_size());
00338 
00339   if (mode == RTM_bind_or_copy) {
00340     // Binding is not supported or it is disabled, so just fall back
00341     // to copy instead.
00342     if (!support_render_texture) {
00343       mode = RTM_copy_texture;
00344     } else {
00345       nassertv(_gsg != NULL);
00346       if (!_gsg->get_supports_render_texture()) {
00347         mode = RTM_copy_texture;
00348       }
00349     }
00350   }
00351 
00352   if (mode == RTM_bind_or_copy) {
00353     // If we're still planning on binding, indicate it in texture
00354     // properly.
00355     tex->set_render_to_texture(true);
00356   }
00357 
00358   RenderTexture result;
00359   result._texture = tex;
00360   result._plane = plane;
00361   result._rtm_mode = mode;
00362   _textures.push_back(result);
00363 }
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: GraphicsOutput::setup_render_texture
00367 //       Access: Published
00368 //  Description: This is a deprecated interface that made sense back
00369 //               when GraphicsOutputs could only render into one
00370 //               texture at a time.  From now on, use
00371 //               clear_render_textures and add_render_texture
00372 //               instead.
00373 ////////////////////////////////////////////////////////////////////
00374 void GraphicsOutput::
00375 setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
00376   display_cat.warning() <<
00377     "Using deprecated setup_render_texture interface.\n";
00378   clear_render_textures();
00379   if (to_ram) {
00380     add_render_texture(tex, RTM_copy_ram);
00381   } else if (allow_bind) {
00382     add_render_texture(tex, RTM_bind_or_copy);
00383   } else {
00384     add_render_texture(tex, RTM_copy_texture);
00385   }
00386 }
00387 
00388 ////////////////////////////////////////////////////////////////////
00389 //     Function: GraphicsOutput::set_active
00390 //       Access: Published
00391 //  Description: Sets the active flag associated with the
00392 //               GraphicsOutput.  If the GraphicsOutput is marked
00393 //               inactive, nothing is rendered.
00394 ////////////////////////////////////////////////////////////////////
00395 void GraphicsOutput::
00396 set_active(bool active) {
00397   _active = active;
00398 }
00399 
00400 ////////////////////////////////////////////////////////////////////
00401 //     Function: GraphicsOutput::is_active
00402 //       Access: Published, Virtual
00403 //  Description: Returns true if the window is ready to be rendered
00404 //               into, false otherwise.
00405 ////////////////////////////////////////////////////////////////////
00406 bool GraphicsOutput::
00407 is_active() const {
00408   return _active && is_valid();
00409 }
00410 
00411 ////////////////////////////////////////////////////////////////////
00412 //     Function: GraphicsOutput::set_inverted
00413 //       Access: Published
00414 //  Description: Changes the current setting of the inverted flag.
00415 //               When this is true, the scene is rendered into the
00416 //               window upside-down and backwards, that is, inverted
00417 //               as if viewed through a mirror placed on the floor.
00418 //
00419 //               This is primarily intended to support DirectX (and a
00420 //               few buggy OpenGL graphics drivers) that perform a
00421 //               framebuffer-to-texture copy upside-down from the
00422 //               usual OpenGL (and Panda) convention.  Panda will
00423 //               automatically set this flag for offscreen buffers on
00424 //               hardware that is known to do this, to compensate when
00425 //               rendering offscreen into a texture.
00426 ////////////////////////////////////////////////////////////////////
00427 void GraphicsOutput::
00428 set_inverted(bool inverted) {
00429   if (_inverted != inverted) {
00430     _inverted = inverted;
00431 
00432     if (_y_size != 0) {
00433       // All of our DisplayRegions need to recompute their pixel
00434       // positions now.
00435       TotalDisplayRegions::iterator dri;
00436       for (dri = _total_display_regions.begin();
00437            dri != _total_display_regions.end();
00438            ++dri) {
00439         (*dri)->compute_pixels(_x_size, _y_size);
00440       }
00441     }
00442   }
00443 }
00444 
00445 ////////////////////////////////////////////////////////////////////
00446 //     Function: GraphicsOutput::set_sort
00447 //       Access: Published, Virtual
00448 //  Description: Adjusts the sorting order of this particular
00449 //               GraphicsOutput, relative to other GraphicsOutputs.
00450 ////////////////////////////////////////////////////////////////////
00451 void GraphicsOutput::
00452 set_sort(int sort) {
00453   if (_sort != sort) {
00454     if (_gsg != (GraphicsStateGuardian *)NULL &&
00455         _gsg->get_engine() != (GraphicsEngine *)NULL) {
00456       _gsg->get_engine()->set_window_sort(this, sort);
00457     }
00458   }
00459 }
00460 
00461 ////////////////////////////////////////////////////////////////////
00462 //     Function: GraphicsOutput::make_display_region
00463 //       Access: Published
00464 //  Description: Creates a new DisplayRegion that covers the indicated
00465 //               sub-rectangle within the window.  The range on all
00466 //               parameters is 0..1.
00467 //
00468 //               If is_stereo() is true for this window, and
00469 //               default-stereo-camera is configured true, this
00470 //               actually makes a StereoDisplayRegion.  Call
00471 //               make_mono_display_region() or
00472 //               make_stereo_display_region() if you want to insist on
00473 //               one or the other.
00474 ////////////////////////////////////////////////////////////////////
00475 DisplayRegion *GraphicsOutput::
00476 make_display_region(float l, float r, float b, float t) {
00477   if (is_stereo() && default_stereo_camera) {
00478     return make_stereo_display_region(l, r, b, t);
00479   } else {
00480     return make_mono_display_region(l, r, b, t);
00481   }
00482 }
00483 
00484 ////////////////////////////////////////////////////////////////////
00485 //     Function: GraphicsOutput::make_mono_display_region
00486 //       Access: Published
00487 //  Description: Creates a new DisplayRegion that covers the indicated
00488 //               sub-rectangle within the window.  The range on all
00489 //               parameters is 0..1.
00490 //
00491 //               This always returns a mono DisplayRegion, even if
00492 //               is_stereo() is true.
00493 ////////////////////////////////////////////////////////////////////
00494 DisplayRegion *GraphicsOutput::
00495 make_mono_display_region(float l, float r, float b, float t) {
00496   return add_display_region(new DisplayRegion(this, l, r, b, t));
00497 }
00498 
00499 ////////////////////////////////////////////////////////////////////
00500 //     Function: GraphicsOutput::make_stereo_display_region
00501 //       Access: Published
00502 //  Description: Creates a new DisplayRegion that covers the indicated
00503 //               sub-rectangle within the window.  The range on all
00504 //               parameters is 0..1.
00505 //
00506 //               This always returns a stereo DisplayRegion, even if
00507 //               is_stereo() is false.
00508 ////////////////////////////////////////////////////////////////////
00509 StereoDisplayRegion *GraphicsOutput::
00510 make_stereo_display_region(float l, float r, float b, float t) {
00511   PT(DisplayRegion) left = new DisplayRegion(this, l, r, b, t);
00512   PT(DisplayRegion) right = new DisplayRegion(this, l, r, b, t);
00513 
00514   PT(StereoDisplayRegion) stereo = new StereoDisplayRegion(this, l, r, b, t,
00515                                                            left, right);
00516   add_display_region(stereo);
00517   add_display_region(left);
00518   add_display_region(right);
00519 
00520   return stereo;
00521 }
00522 
00523 ////////////////////////////////////////////////////////////////////
00524 //     Function: GraphicsOutput::remove_display_region
00525 //       Access: Published
00526 //  Description: Removes the indicated DisplayRegion from the window,
00527 //               and destructs it if there are no other references.
00528 //
00529 //               Returns true if the DisplayRegion is found and
00530 //               removed, false if it was not a part of the window.
00531 ////////////////////////////////////////////////////////////////////
00532 bool GraphicsOutput::
00533 remove_display_region(DisplayRegion *display_region) {
00534   LightMutexHolder holder(_lock);
00535 
00536   nassertr(display_region != _default_display_region, false);
00537 
00538   if (display_region->is_stereo()) {
00539     StereoDisplayRegion *sdr;
00540     DCAST_INTO_R(sdr, display_region, false);
00541     do_remove_display_region(sdr->get_left_eye());
00542     do_remove_display_region(sdr->get_right_eye());
00543   }
00544 
00545   return do_remove_display_region(display_region);
00546 }
00547 
00548 ////////////////////////////////////////////////////////////////////
00549 //     Function: GraphicsOutput::remove_all_display_regions
00550 //       Access: Published
00551 //  Description: Removes all display regions from the window, except
00552 //               the default one that is created with the window.
00553 ////////////////////////////////////////////////////////////////////
00554 void GraphicsOutput::
00555 remove_all_display_regions() {
00556   LightMutexHolder holder(_lock);
00557 
00558   TotalDisplayRegions::iterator dri;
00559   for (dri = _total_display_regions.begin();
00560        dri != _total_display_regions.end();
00561        ++dri) {
00562     DisplayRegion *display_region = (*dri);
00563     if (display_region != _default_display_region) {
00564       // Let's aggressively clean up the display region too.
00565       display_region->cleanup();
00566       display_region->_window = NULL;
00567     }
00568   }
00569   _total_display_regions.clear();
00570   _total_display_regions.push_back(_default_display_region);
00571   _display_regions_stale = true;
00572 }
00573 
00574 ////////////////////////////////////////////////////////////////////
00575 //     Function: GraphicsOutput::get_num_display_regions
00576 //       Access: Published
00577 //  Description: Returns the number of DisplayRegions that have
00578 //               been created within the window, active or otherwise.
00579 ////////////////////////////////////////////////////////////////////
00580 int GraphicsOutput::
00581 get_num_display_regions() const {
00582   determine_display_regions();
00583   int result;
00584   {
00585     LightMutexHolder holder(_lock);
00586     result = _total_display_regions.size();
00587   }
00588   return result;
00589 }
00590 
00591 ////////////////////////////////////////////////////////////////////
00592 //     Function: GraphicsOutput::get_display_region
00593 //       Access: Published
00594 //  Description: Returns the nth DisplayRegion of those that have been
00595 //               created within the window.  This may return NULL if n
00596 //               is out of bounds; particularly likely if the number
00597 //               of display regions has changed since the last call to
00598 //               get_num_display_regions().
00599 ////////////////////////////////////////////////////////////////////
00600 PT(DisplayRegion) GraphicsOutput::
00601 get_display_region(int n) const {
00602   determine_display_regions();
00603   PT(DisplayRegion) result;
00604   {
00605     LightMutexHolder holder(_lock);
00606     if (n >= 0 && n < (int)_total_display_regions.size()) {
00607       result = _total_display_regions[n];
00608     } else {
00609       result = NULL;
00610     }
00611   }
00612   return result;
00613 }
00614 
00615 ////////////////////////////////////////////////////////////////////
00616 //     Function: GraphicsOutput::get_num_active_display_regions
00617 //       Access: Published
00618 //  Description: Returns the number of active DisplayRegions that have
00619 //               been created within the window.
00620 ////////////////////////////////////////////////////////////////////
00621 int GraphicsOutput::
00622 get_num_active_display_regions() const {
00623   determine_display_regions();
00624   int result;
00625   {
00626     LightMutexHolder holder(_lock);
00627     result = _active_display_regions.size();
00628   }
00629   return result;
00630 }
00631 
00632 ////////////////////////////////////////////////////////////////////
00633 //     Function: GraphicsOutput::get_active_display_region
00634 //       Access: Published
00635 //  Description: Returns the nth active DisplayRegion of those that
00636 //               have been created within the window.  This may return
00637 //               NULL if n is out of bounds; particularly likely if
00638 //               the number of display regions has changed since the
00639 //               last call to get_num_active_display_regions().
00640 ////////////////////////////////////////////////////////////////////
00641 PT(DisplayRegion) GraphicsOutput::
00642 get_active_display_region(int n) const {
00643   determine_display_regions();
00644   PT(DisplayRegion) result;
00645   {
00646     LightMutexHolder holder(_lock);
00647     if (n >= 0 && n < (int)_active_display_regions.size()) {
00648       result = _active_display_regions[n];
00649     } else {
00650       result = NULL;
00651     }
00652   }
00653   return result;
00654 }
00655 
00656 ////////////////////////////////////////////////////////////////////
00657 //     Function: GraphicsOuput::create_texture_card_vdata
00658 //       Access: Private
00659 //  Description: Generates a GeomVertexData for a texture card.
00660 ////////////////////////////////////////////////////////////////////
00661 PT(GeomVertexData) GraphicsOutput::
00662 create_texture_card_vdata(int x, int y) {
00663   float xhi = 1.0;
00664   float yhi = 1.0;
00665 
00666   if (Texture::get_textures_power_2() != ATS_none) {
00667     int xru = Texture::up_to_power_2(x);
00668     int yru = Texture::up_to_power_2(y);
00669     xhi = (x * 1.0f) / xru;
00670     yhi = (y * 1.0f) / yru;
00671   }
00672 
00673   CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3n3t2();
00674 
00675   PT(GeomVertexData) vdata = new GeomVertexData
00676     ("card", format, Geom::UH_static);
00677 
00678   GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00679   GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
00680   GeomVertexWriter normal(vdata, InternalName::get_normal());
00681 
00682   vertex.add_data3f(Vertexf::rfu(-1.0f, 0.0f,  1.0f));
00683   vertex.add_data3f(Vertexf::rfu(-1.0f, 0.0f, -1.0f));
00684   vertex.add_data3f(Vertexf::rfu( 1.0f, 0.0f,  1.0f));
00685   vertex.add_data3f(Vertexf::rfu( 1.0f, 0.0f, -1.0f));
00686 
00687   texcoord.add_data2f( 0.0f,  yhi);
00688   texcoord.add_data2f( 0.0f, 0.0f);
00689   texcoord.add_data2f(  xhi,  yhi);
00690   texcoord.add_data2f(  xhi, 0.0f);
00691 
00692   normal.add_data3f(LVector3f::back());
00693   normal.add_data3f(LVector3f::back());
00694   normal.add_data3f(LVector3f::back());
00695   normal.add_data3f(LVector3f::back());
00696 
00697   return vdata;
00698 }
00699 
00700 ////////////////////////////////////////////////////////////////////
00701 //     Function: GraphicsOutput::set_size_and_recalc
00702 //       Access: Public
00703 //  Description: Changes the x_size and y_size, then recalculates
00704 //               structures that depend on size.  The recalculation
00705 //               currently includes:
00706 //               - compute_pixels on all the graphics regions.
00707 //               - updating the texture card, if one is present.
00708 ////////////////////////////////////////////////////////////////////
00709 void GraphicsOutput::
00710 set_size_and_recalc(int x, int y) {
00711   _x_size = x;
00712   _y_size = y;
00713   _has_size = true;
00714 
00715   int fb_x_size = get_fb_x_size();
00716   int fb_y_size = get_fb_y_size();
00717 
00718   TotalDisplayRegions::iterator dri;
00719   for (dri = _total_display_regions.begin();
00720        dri != _total_display_regions.end();
00721        ++dri) {
00722     (*dri)->compute_pixels_all_stages(fb_x_size, fb_y_size);
00723   }
00724 
00725   if (_texture_card != 0) {
00726     _texture_card->set_vertex_data(create_texture_card_vdata(x, y));
00727   }
00728 }
00729 
00730 ////////////////////////////////////////////////////////////////////
00731 //     Function: GraphicsOutput::get_texture_card
00732 //       Access: Published
00733 //  Description: Returns a PandaNode containing a square polygon.
00734 //               The dimensions are (-1,0,-1) to (1,0,1). The texture
00735 //               coordinates are such that the texture of this
00736 //               GraphicsOutput is aligned properly to the polygon.
00737 //               The GraphicsOutput promises to surgically update
00738 //               the Geom inside the PandaNode if necessary to maintain
00739 //               this invariant.
00740 //
00741 //               Each invocation of this function returns a freshly-
00742 //               allocated PandaNode.  You can therefore safely modify
00743 //               the RenderAttribs of the PandaNode.  The
00744 //               PandaNode is initially textured with the texture
00745 //               of this GraphicOutput.
00746 ////////////////////////////////////////////////////////////////////
00747 NodePath GraphicsOutput::
00748 get_texture_card() {
00749   if (_texture_card == 0) {
00750     PT(GeomVertexData) vdata = create_texture_card_vdata(_x_size, _y_size);
00751     PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
00752     strip->set_shade_model(Geom::SM_uniform);
00753     strip->add_next_vertices(4);
00754     strip->close_primitive();
00755     _texture_card = new Geom(vdata);
00756     _texture_card->add_primitive(strip);
00757   }
00758 
00759   PT(GeomNode) gnode = new GeomNode("texture card");
00760   gnode->add_geom(_texture_card);
00761   NodePath path(gnode);
00762 
00763   // The texture card, by default, is textured with the first
00764   // render-to-texture output texture.  Depth and stencil
00765   // textures are ignored.  The user can freely alter the
00766   // card's texture attrib.
00767   for (int i=0; i<count_textures(); i++) {
00768     Texture *texture = get_texture(i);
00769     if ((texture->get_format() != Texture::F_depth_stencil)) {
00770       path.set_texture(texture, 0);
00771       break;
00772     }
00773   }
00774 
00775   return path;
00776 }
00777 
00778 ////////////////////////////////////////////////////////////////////
00779 //     Function: GraphicsOutput::make_texture_buffer
00780 //       Access: Published
00781 //  Description: Creates and returns an offscreen buffer for rendering
00782 //               into, the result of which will be a texture suitable
00783 //               for applying to geometry within the scene rendered
00784 //               into this window.
00785 //
00786 //               If tex is not NULL, it is the texture that will be
00787 //               set up for rendering into; otherwise, a new Texture
00788 //               object will be created.  In either case, the target
00789 //               texture can be retrieved from the return value with
00790 //               buffer->get_texture() (assuming the return value is
00791 //               not NULL).
00792 //
00793 //               If to_ram is true, the buffer will be set up to
00794 //               download its contents to the system RAM memory
00795 //               associated with the Texture object, instead of
00796 //               keeping it strictly within texture memory; this is
00797 //               much slower, but it allows using the texture with any
00798 //               GSG.
00799 //
00800 //               This will attempt to be smart about maximizing render
00801 //               performance while minimizing framebuffer waste.  It
00802 //               might return a GraphicsBuffer set to render directly
00803 //               into a texture, if possible; or it might return a
00804 //               ParasiteBuffer that renders into this window.  The
00805 //               return value is NULL if the buffer could not be
00806 //               created for some reason.
00807 //
00808 //               When you are done using the buffer, you should remove
00809 //               it with a call to GraphicsEngine::remove_window() (or
00810 //               set the one_shot flag so it removes itself after one
00811 //               frame).
00812 ////////////////////////////////////////////////////////////////////
00813 GraphicsOutput *GraphicsOutput::
00814 make_texture_buffer(const string &name, int x_size, int y_size,
00815                     Texture *tex, bool to_ram, FrameBufferProperties *fbp) {
00816 
00817   FrameBufferProperties props;
00818   props.set_rgb_color(1);
00819   props.set_depth_bits(1);
00820 
00821   if (fbp == NULL) {
00822     fbp = &props;
00823   }
00824 
00825   int flags = GraphicsPipe::BF_refuse_window;
00826   if (textures_power_2 != ATS_none) {
00827     flags |= GraphicsPipe::BF_size_power_2;
00828   }
00829   if (tex != (Texture *)NULL &&
00830       tex->get_texture_type() == Texture::TT_cube_map) {
00831     flags |= GraphicsPipe::BF_size_square;
00832   }
00833 
00834   GraphicsOutput *buffer = get_gsg()->get_engine()->
00835     make_output(get_gsg()->get_pipe(),
00836                 name, get_child_sort(),
00837                 *fbp, WindowProperties::size(x_size, y_size),
00838                 flags, get_gsg(), get_host());
00839 
00840   if (buffer != (GraphicsOutput *)NULL) {
00841     buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_bind_or_copy);
00842     return buffer;
00843   }
00844 
00845   return NULL;
00846 }
00847 
00848 ////////////////////////////////////////////////////////////////////
00849 //     Function: GraphicsOutput::make_cube_map
00850 //       Access: Published
00851 //  Description: This is similar to make_texture_buffer() in that it
00852 //               allocates a separate buffer suitable for rendering to
00853 //               a texture that can be assigned to geometry in this
00854 //               window, but in this case, the buffer is set up to
00855 //               render the six faces of a cube map.
00856 //
00857 //               The buffer is automatically set up with six display
00858 //               regions and six cameras, each of which are assigned
00859 //               the indicated draw_mask and parented to the given
00860 //               camera_rig node (which you should then put in your
00861 //               scene to render the cube map from the appropriate
00862 //               point of view).
00863 //
00864 //               You may take the texture associated with the buffer
00865 //               and apply it to geometry, particularly with
00866 //               TexGenAttrib::M_world_cube_map also in effect, to
00867 //               apply a reflection of everything seen by the camera
00868 //               rig.
00869 ////////////////////////////////////////////////////////////////////
00870 GraphicsOutput *GraphicsOutput::
00871 make_cube_map(const string &name, int size, NodePath &camera_rig,
00872               DrawMask camera_mask, bool to_ram, FrameBufferProperties *fbp) {
00873   if (!to_ram) {
00874     // Check the limits imposed by the GSG.  (However, if we're
00875     // rendering the texture to RAM only, these limits may be
00876     // irrelevant.)
00877     GraphicsStateGuardian *gsg = get_gsg();
00878     int max_dimension = gsg->get_max_cube_map_dimension();
00879     if (max_dimension == 0 || !gsg->get_supports_cube_map()) {
00880       // The GSG doesn't support cube mapping; too bad for you.
00881       display_cat.warning()
00882         << "Cannot make dynamic cube map; GSG does not support cube maps.\n";
00883       return NULL;
00884     }
00885     if (max_dimension > 0) {
00886       size = min(max_dimension, size);
00887     }
00888   }
00889 
00890   // Usually, we want the whole camera_rig to keep itself unrotated
00891   // with respect to the world coordinate space, so the user can apply
00892   // TexGenAttrib::M_world_cube_map to the objects on which the cube
00893   // map texture is applied.  If for some reason the user doesn't want
00894   // this behavior, he can take this effect off again.
00895   camera_rig.node()->set_effect(CompassEffect::make(NodePath()));
00896 
00897   PT(Texture) tex = new Texture(name);
00898   tex->setup_cube_map();
00899   tex->set_wrap_u(Texture::WM_clamp);
00900   tex->set_wrap_v(Texture::WM_clamp);
00901   GraphicsOutput *buffer;
00902 
00903   buffer = make_texture_buffer(name, size, size, tex, to_ram, fbp);
00904 
00905   // We don't need to clear the overall buffer; instead, we'll clear
00906   // each display region.
00907   buffer->set_clear_color_active(false);
00908   buffer->set_clear_depth_active(false);
00909   buffer->set_clear_stencil_active(false);
00910 
00911   PT(Lens) lens = new PerspectiveLens;
00912   lens->set_fov(90.0f);
00913 
00914   for (int i = 0; i < 6; i++) {
00915     PT(Camera) camera = new Camera(cube_faces[i]._name);
00916     camera->set_lens(lens);
00917     camera->set_camera_mask(camera_mask);
00918     NodePath camera_np = camera_rig.attach_new_node(camera);
00919     camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up);
00920 
00921     DisplayRegion *dr;
00922     dr = buffer->make_display_region();
00923 
00924     dr->set_cube_map_index(i);
00925     dr->copy_clear_settings(*this);
00926     dr->set_camera(camera_np);
00927   }
00928 
00929   return buffer;
00930 }
00931 
00932 ////////////////////////////////////////////////////////////////////
00933 //     Function: GraphicsOutput::get_host
00934 //       Access: Public, Virtual
00935 //  Description: This is normally called only from within
00936 //               make_texture_buffer().  When called on a
00937 //               ParasiteBuffer, it returns the host of that buffer;
00938 //               but when called on some other buffer, it returns the
00939 //               buffer itself.
00940 ////////////////////////////////////////////////////////////////////
00941 GraphicsOutput *GraphicsOutput::
00942 get_host() {
00943   return this;
00944 }
00945 
00946 ////////////////////////////////////////////////////////////////////
00947 //     Function: GraphicsOutput::request_open
00948 //       Access: Public, Virtual
00949 //  Description: This is called by the GraphicsEngine to request that
00950 //               the window (or whatever) open itself or, in general,
00951 //               make itself valid, at the next call to
00952 //               process_events().
00953 ////////////////////////////////////////////////////////////////////
00954 void GraphicsOutput::
00955 request_open() {
00956 }
00957 
00958 ////////////////////////////////////////////////////////////////////
00959 //     Function: GraphicsOutput::request_close
00960 //       Access: Public, Virtual
00961 //  Description: This is called by the GraphicsEngine to request that
00962 //               the window (or whatever) close itself or, in general,
00963 //               make itself invalid, at the next call to
00964 //               process_events().  By that time we promise the gsg
00965 //               pointer will be cleared.
00966 ////////////////////////////////////////////////////////////////////
00967 void GraphicsOutput::
00968 request_close() {
00969 }
00970 
00971 ////////////////////////////////////////////////////////////////////
00972 //     Function: GraphicsOutput::set_close_now
00973 //       Access: Public, Virtual
00974 //  Description: This is called by the GraphicsEngine to insist that
00975 //               the output be closed immediately.  This is only
00976 //               called from the window thread.
00977 ////////////////////////////////////////////////////////////////////
00978 void GraphicsOutput::
00979 set_close_now() {
00980 }
00981 
00982 ////////////////////////////////////////////////////////////////////
00983 //     Function: GraphicsOutput::reset_window
00984 //       Access: Protected, Virtual
00985 //  Description: Resets the window framebuffer from its derived
00986 //               children. Does nothing here.
00987 ////////////////////////////////////////////////////////////////////
00988 void GraphicsOutput::
00989 reset_window(bool swapchain) {
00990   display_cat.info()
00991     << "Resetting " << get_type() << "\n";
00992 }
00993 
00994 ////////////////////////////////////////////////////////////////////
00995 //     Function: GraphicsOutput::clear_pipe
00996 //       Access: Protected, Virtual
00997 //  Description: Sets the window's _pipe pointer to NULL; this is
00998 //               generally called only as a precursor to deleting the
00999 //               window.
01000 ////////////////////////////////////////////////////////////////////
01001 void GraphicsOutput::
01002 clear_pipe() {
01003   _pipe = (GraphicsPipe *)NULL;
01004 }
01005 
01006 ////////////////////////////////////////////////////////////////////
01007 //     Function: GraphicsOutput::begin_frame
01008 //       Access: Public, Virtual
01009 //  Description: This function will be called within the draw thread
01010 //               before beginning rendering for a given frame.  It
01011 //               should do whatever setup is required, and return true
01012 //               if the frame should be rendered, or false if it
01013 //               should be skipped.
01014 ////////////////////////////////////////////////////////////////////
01015 bool GraphicsOutput::
01016 begin_frame(FrameMode mode, Thread *current_thread) {
01017   return false;
01018 }
01019 
01020 ////////////////////////////////////////////////////////////////////
01021 //     Function: GraphicsOutput::end_frame
01022 //       Access: Public, Virtual
01023 //  Description: This function will be called within the draw thread
01024 //               after rendering is completed for a given frame.  It
01025 //               should do whatever finalization is required.
01026 ////////////////////////////////////////////////////////////////////
01027 void GraphicsOutput::
01028 end_frame(FrameMode mode, Thread *current_thread) {
01029 }
01030 
01031 ////////////////////////////////////////////////////////////////////
01032 //     Function: GraphicsOutput::pixel_factor_changed
01033 //       Access: Published, Virtual
01034 //  Description: Called internally when the pixel factor changes.
01035 ////////////////////////////////////////////////////////////////////
01036 void GraphicsOutput::
01037 pixel_factor_changed() {
01038   if (_has_size) {
01039     set_size_and_recalc(_x_size, _y_size);
01040   }
01041 }
01042 
01043 ////////////////////////////////////////////////////////////////////
01044 //     Function: GraphicsOutput::prepare_for_deletion
01045 //       Access: Protected
01046 //  Description: Set the delete flag, and do the usual cleanup
01047 //               activities associated with that.
01048 ////////////////////////////////////////////////////////////////////
01049 void GraphicsOutput::
01050 prepare_for_deletion() {
01051 
01052   _active = false;
01053   _delete_flag = true;
01054 
01055   // We have to be sure to remove all of the display regions
01056   // immediately, so that circular reference counts can be cleared
01057   // up (each display region keeps a pointer to a CullResult,
01058   // which can hold all sorts of pointers).
01059   remove_all_display_regions();
01060 
01061   // If we were rendering directly to texture, we can't delete the
01062   // buffer until the texture is gone too.
01063   for (int i=0; i<count_textures(); i++) {
01064     if (get_rtm_mode(i) == RTM_bind_or_copy) {
01065       _hold_textures.push_back(get_texture(i));
01066     }
01067   }
01068 
01069   // We have to be sure to clear the _textures pointers, though, or
01070   // we'll end up holding a reference to the textures forever.
01071   clear_render_textures();
01072 }
01073 
01074 ////////////////////////////////////////////////////////////////////
01075 //     Function: GraphicsOutput::clear
01076 //       Access: Public
01077 //  Description: Clears the entire framebuffer before rendering,
01078 //               according to the settings of get_color_clear_active()
01079 //               and get_depth_clear_active() (inherited from
01080 //               DrawableRegion).
01081 //
01082 //               This function is called only within the draw thread.
01083 ////////////////////////////////////////////////////////////////////
01084 void GraphicsOutput::
01085 clear(Thread *current_thread) {
01086   if (is_any_clear_active()) {
01087     if (display_cat.is_spam()) {
01088       display_cat.spam()
01089         << "clear(): " << get_type() << " "
01090         << get_name() << " " << (void *)this << "\n";
01091     }
01092 
01093     nassertv(_gsg != (GraphicsStateGuardian *)NULL);
01094 
01095     DisplayRegionPipelineReader dr_reader(_default_display_region, current_thread);
01096     _gsg->prepare_display_region(&dr_reader, Lens::SC_mono);
01097     _gsg->clear(this);
01098   }
01099 }
01100 
01101 ////////////////////////////////////////////////////////////////////
01102 //     Function: GraphicsOutput::copy_to_textures
01103 //       Access: Protected
01104 //  Description: For all textures marked RTM_copy_texture,
01105 //               RTM_copy_ram, RTM_triggered_copy_texture, or
01106 //               RTM_triggered_copy_ram, do the necessary copies.
01107 //
01108 //               Returns true if all copies are successful, false
01109 //               otherwise.
01110 ////////////////////////////////////////////////////////////////////
01111 bool GraphicsOutput::
01112 copy_to_textures() {
01113   bool okflag = true;
01114   for (int i = 0; i < count_textures(); ++i) {
01115     RenderTextureMode rtm_mode = get_rtm_mode(i);
01116     if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) {
01117       continue;
01118     }
01119 
01120     Texture *texture = get_texture(i);
01121     PStatTimer timer(_copy_texture_pcollector);
01122     nassertr(has_texture(), false);
01123 
01124     if ((rtm_mode == RTM_copy_texture)||
01125         (rtm_mode == RTM_copy_ram)||
01126         ((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
01127         ((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
01128       if (display_cat.is_debug()) {
01129         display_cat.debug()
01130           << "Copying texture for " << get_name() << " at frame end.\n";
01131         display_cat.debug()
01132           << "cube_map_index = " << _cube_map_index << "\n";
01133       }
01134       int plane = get_texture_plane(i);
01135       RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(plane));
01136       if (plane == RTP_color) {
01137         buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
01138                                          get_fb_properties());
01139       }
01140 
01141       bool copied = false;
01142       if (_cube_map_dr != (DisplayRegion *)NULL) {
01143         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
01144           copied =
01145             _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
01146                                           _cube_map_dr, buffer);
01147         } else {
01148           copied =
01149             _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
01150                                               _cube_map_dr, buffer);
01151         }
01152       } else {
01153         if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
01154           copied =
01155             _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
01156                                           _default_display_region, buffer);
01157         } else {
01158           copied =
01159             _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
01160                                               _default_display_region, buffer);
01161         }
01162       }
01163       if (!copied) {
01164         okflag = false;
01165       }
01166     }
01167   }
01168   _trigger_copy = false;
01169 
01170   return okflag;
01171 }
01172 
01173 ////////////////////////////////////////////////////////////////////
01174 //     Function: GraphicsOutput::change_scenes
01175 //       Access: Public
01176 //  Description: Called by the GraphicsEngine when the window is about
01177 //               to change to another DisplayRegion.  This exists
01178 //               mainly to provide a callback for switching the cube
01179 //               map face, if we are rendering to the different faces
01180 //               of a cube map.
01181 ////////////////////////////////////////////////////////////////////
01182 void GraphicsOutput::
01183 change_scenes(DisplayRegionPipelineReader *new_dr) {
01184   int new_cube_map_index = new_dr->get_cube_map_index();
01185   if (new_cube_map_index != -1 &&
01186       new_cube_map_index != _cube_map_index) {
01187     int old_cube_map_index = _cube_map_index;
01188     DisplayRegion *old_cube_map_dr = _cube_map_dr;
01189     _cube_map_index = new_cube_map_index;
01190     _cube_map_dr = new_dr->get_object();
01191 
01192     for (int i=0; i<count_textures(); i++) {
01193       Texture *texture = get_texture(i);
01194       RenderTextureMode rtm_mode = get_rtm_mode(i);
01195       if (rtm_mode != RTM_none) {
01196         if (rtm_mode == RTM_bind_or_copy) {
01197           // In render-to-texture mode, switch the rendering backend to
01198           // the new cube map face, so that the subsequent frame will be
01199           // rendered to the new face.
01200 
01201           select_cube_map(new_cube_map_index);
01202 
01203         } else if (old_cube_map_index != -1) {
01204           // In copy-to-texture mode, copy the just-rendered framebuffer
01205           // to the old cube map face.
01206           nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
01207           if (display_cat.is_debug()) {
01208             display_cat.debug()
01209               << "Copying texture for " << get_name() << " at scene change.\n";
01210             display_cat.debug()
01211               << "cube_map_index = " << old_cube_map_index << "\n";
01212           }
01213           RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(),
01214                                                         get_fb_properties());
01215           if (rtm_mode == RTM_copy_ram) {
01216             _gsg->framebuffer_copy_to_ram(texture, old_cube_map_index,
01217                                           old_cube_map_dr, buffer);
01218           } else {
01219             _gsg->framebuffer_copy_to_texture(texture, old_cube_map_index,
01220                                               old_cube_map_dr, buffer);
01221           }
01222         }
01223       }
01224     }
01225   }
01226 }
01227 
01228 ////////////////////////////////////////////////////////////////////
01229 //     Function: GraphicsOutput::select_cube_map
01230 //       Access: Public, Virtual
01231 //  Description: Called internally when the window is in
01232 //               render-to-a-texture mode and we are in the process of
01233 //               rendering the six faces of a cube map.  This should
01234 //               do whatever needs to be done to switch the buffer to
01235 //               the indicated face.
01236 ////////////////////////////////////////////////////////////////////
01237 void GraphicsOutput::
01238 select_cube_map(int) {
01239 }
01240 
01241 ////////////////////////////////////////////////////////////////////
01242 //     Function: GraphicsOutput::begin_flip
01243 //       Access: Public, Virtual
01244 //  Description: This function will be called within the draw thread
01245 //               after end_frame() has been called on all windows, to
01246 //               initiate the exchange of the front and back buffers.
01247 //
01248 //               This should instruct the window to prepare for the
01249 //               flip at the next video sync, but it should not wait.
01250 //
01251 //               We have the two separate functions, begin_flip() and
01252 //               end_flip(), to make it easier to flip all of the
01253 //               windows at the same time.
01254 ////////////////////////////////////////////////////////////////////
01255 void GraphicsOutput::
01256 begin_flip() {
01257 }
01258 
01259 ////////////////////////////////////////////////////////////////////
01260 //     Function: GraphicsOutput::end_flip
01261 //       Access: Public, Virtual
01262 //  Description: This function will be called within the draw thread
01263 //               after begin_flip() has been called on all windows, to
01264 //               finish the exchange of the front and back buffers.
01265 //
01266 //               This should cause the window to wait for the flip, if
01267 //               necessary.
01268 ////////////////////////////////////////////////////////////////////
01269 void GraphicsOutput::
01270 end_flip() {
01271   _flip_ready = false;
01272 }
01273 
01274 ////////////////////////////////////////////////////////////////////
01275 //     Function: GraphicsOutput::process_events
01276 //       Access: Public, Virtual
01277 //  Description: Do whatever processing in the window thread is
01278 //               appropriate for this output object each frame.
01279 //
01280 //               This function is called only within the window
01281 //               thread.
01282 ////////////////////////////////////////////////////////////////////
01283 void GraphicsOutput::
01284 process_events() {
01285 }
01286 
01287 ////////////////////////////////////////////////////////////////////
01288 //     Function: GraphicsOutput::add_display_region
01289 //       Access: Private
01290 //  Description: Called by one of the make_display_region() methods to
01291 //               add the new DisplayRegion to the list.
01292 ////////////////////////////////////////////////////////////////////
01293 DisplayRegion *GraphicsOutput::
01294 add_display_region(DisplayRegion *display_region) {
01295   LightMutexHolder holder(_lock);
01296   _total_display_regions.push_back(display_region);
01297   _display_regions_stale = true;
01298 
01299   return display_region;
01300 }
01301 
01302 ////////////////////////////////////////////////////////////////////
01303 //     Function: GraphicsOutput::do_remove_display_region
01304 //       Access: Private
01305 //  Description: Internal implementation of remove_display_region.
01306 //               Assumes the lock is already held.
01307 ////////////////////////////////////////////////////////////////////
01308 bool GraphicsOutput::
01309 do_remove_display_region(DisplayRegion *display_region) {
01310   nassertr(display_region != _default_display_region, false);
01311 
01312   PT(DisplayRegion) drp = display_region;
01313   TotalDisplayRegions::iterator dri =
01314     find(_total_display_regions.begin(), _total_display_regions.end(), drp);
01315   if (dri != _total_display_regions.end()) {
01316     // Let's aggressively clean up the display region too.
01317     display_region->cleanup();
01318     display_region->_window = NULL;
01319     _total_display_regions.erase(dri);
01320     if (display_region->is_active()) {
01321       _display_regions_stale = true;
01322     }
01323 
01324     return true;
01325   }
01326 
01327   return false;
01328 }
01329 
01330 ////////////////////////////////////////////////////////////////////
01331 //     Function: GraphicsOutput::do_determine_display_regions
01332 //       Access: Private
01333 //  Description: Re-sorts the list of active DisplayRegions within
01334 //               the window.
01335 ////////////////////////////////////////////////////////////////////
01336 void GraphicsOutput::
01337 do_determine_display_regions() {
01338   LightMutexHolder holder(_lock);
01339   _display_regions_stale = false;
01340 
01341   _active_display_regions.clear();
01342   _active_display_regions.reserve(_total_display_regions.size());
01343 
01344   int index = 0;
01345   TotalDisplayRegions::const_iterator dri;
01346   for (dri = _total_display_regions.begin();
01347        dri != _total_display_regions.end();
01348        ++dri) {
01349     DisplayRegion *display_region = (*dri);
01350     if (display_region->is_active()) {
01351       _active_display_regions.push_back(display_region);
01352       display_region->set_active_index(index);
01353       ++index;
01354     } else {
01355       display_region->set_active_index(-1);
01356     }
01357   }
01358 
01359   stable_sort(_active_display_regions.begin(), _active_display_regions.end(), IndirectLess<DisplayRegion>());
01360 }
01361 
01362 ////////////////////////////////////////////////////////////////////
01363 //     Function: GraphicsOutput::FrameMode output operator
01364 //  Description:
01365 ////////////////////////////////////////////////////////////////////
01366 ostream &
01367 operator << (ostream &out, GraphicsOutput::FrameMode fm) {
01368   switch (fm) {
01369   case GraphicsOutput::FM_render:
01370     return out << "render";
01371   case GraphicsOutput::FM_parasite:
01372     return out << "parasite";
01373   case GraphicsOutput::FM_refresh:
01374     return out << "refresh";
01375   }
01376 
01377   return out << "(**invalid GraphicsOutput::FrameMode(" << (int)fm << ")**)";
01378 }
01379 
01380 ////////////////////////////////////////////////////////////////////
01381 //     Function: GraphicsOutput::share_depth_buffer
01382 //       Access: Published, Virtual
01383 //  Description: Will attempt to use the depth buffer of the input
01384 //               graphics_output. The buffer sizes must be exactly
01385 //               the same.
01386 ////////////////////////////////////////////////////////////////////
01387 bool GraphicsOutput::
01388 share_depth_buffer(GraphicsOutput *graphics_output) {
01389   return false;
01390 }
01391 
01392 ////////////////////////////////////////////////////////////////////
01393 //     Function: GraphicsOutput::unshare_depth_buffer
01394 //       Access: Published, Virtual
01395 //  Description: Discontinue sharing the depth buffer.
01396 ////////////////////////////////////////////////////////////////////
01397 void GraphicsOutput::
01398 unshare_depth_buffer() {
01399 
01400 }
 All Classes Functions Variables Enumerations