Panda3D
|
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 }