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 LPoint3 &look_at, const LVector3 &up) : 00047 _name(name), _look_at(look_at), _up(up) { } 00048 00049 const char *_name; 00050 LPoint3 _look_at; 00051 LVector3 _up; 00052 }; 00053 00054 static CubeFaceDef cube_faces[6] = { 00055 CubeFaceDef("positive_x", LPoint3(1, 0, 0), LVector3(0, -1, 0)), 00056 CubeFaceDef("negative_x", LPoint3(-1, 0, 0), LVector3(0, -1, 0)), 00057 CubeFaceDef("positive_y", LPoint3(0, 1, 0), LVector3(0, 0, 1)), 00058 CubeFaceDef("negative_y", LPoint3(0, -1, 0), LVector3(0, 0, -1)), 00059 CubeFaceDef("positive_z", LPoint3(0, 0, 1), LVector3(0, -1, 0)), 00060 CubeFaceDef("negative_z", LPoint3(0, 0, -1), LVector3(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 bool default_stereo_flags) : 00079 _lock("GraphicsOutput"), 00080 _cull_window_pcollector(_cull_pcollector, name), 00081 _draw_window_pcollector(_draw_pcollector, name) 00082 { 00083 #ifdef DO_MEMORY_USAGE 00084 MemoryUsage::update_type(this, this); 00085 #endif 00086 _engine = engine; 00087 _pipe = pipe; 00088 _gsg = gsg; 00089 _host = host; 00090 _fb_properties = fb_prop; 00091 _name = name; 00092 _creation_flags = flags; 00093 _x_size = _y_size = 0; 00094 _has_size = win_prop.has_size(); 00095 _is_nonzero_size = false; 00096 if (_has_size) { 00097 _x_size = win_prop.get_x_size(); 00098 _y_size = win_prop.get_y_size(); 00099 _is_nonzero_size = (_x_size > 0 && _y_size > 0); 00100 } 00101 if (_creation_flags & GraphicsPipe::BF_size_track_host) { 00102 // If we're tracking the host size, we assume we'll be nonzero 00103 // eventually. 00104 _is_nonzero_size = true; 00105 } 00106 00107 _is_valid = false; 00108 _flip_ready = false; 00109 _cube_map_index = -1; 00110 _cube_map_dr = NULL; 00111 _sort = 0; 00112 _child_sort = 0; 00113 _got_child_sort = false; 00114 _internal_sort_index = 0; 00115 _inverted = window_inverted; 00116 _swap_eyes = swap_eyes; 00117 _red_blue_stereo = false; 00118 _left_eye_color_mask = 0x0f; 00119 _right_eye_color_mask = 0x0f; 00120 _side_by_side_stereo = false; 00121 _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f); 00122 _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f); 00123 _delete_flag = false; 00124 _texture_card = 0; 00125 _trigger_copy = false; 00126 00127 if (_fb_properties.is_single_buffered()) { 00128 _draw_buffer_type = RenderBuffer::T_front; 00129 } else { 00130 _draw_buffer_type = RenderBuffer::T_back; 00131 } 00132 00133 if (default_stereo_flags) { 00134 // Check the config variables to see if we should make this a 00135 // "stereo" buffer or window. 00136 _red_blue_stereo = red_blue_stereo && !fb_prop.is_stereo(); 00137 if (_red_blue_stereo) { 00138 _left_eye_color_mask = parse_color_mask(red_blue_stereo_colors.get_word(0)); 00139 _right_eye_color_mask = parse_color_mask(red_blue_stereo_colors.get_word(1)); 00140 } 00141 _side_by_side_stereo = side_by_side_stereo && !fb_prop.is_stereo(); 00142 if (_side_by_side_stereo) { 00143 _sbs_left_dimensions.set(sbs_left_dimensions[0], sbs_left_dimensions[1], 00144 sbs_left_dimensions[2], sbs_left_dimensions[3]); 00145 _sbs_right_dimensions.set(sbs_right_dimensions[0], sbs_right_dimensions[1], 00146 sbs_right_dimensions[2], sbs_right_dimensions[3]); 00147 } 00148 } 00149 00150 // We start out with one DisplayRegion that covers the whole window, 00151 // which we may use internally for full-window operations like 00152 // clear() and get_screenshot(). 00153 _overlay_display_region = make_mono_display_region(0.0f, 1.0f, 0.0f, 1.0f); 00154 _overlay_display_region->set_active(false); 00155 00156 // Make sure the "active" flag is set true for pipeline stage 0. 00157 { 00158 CDWriter cdata(_cycler, true); 00159 cdata->_active = true; 00160 } 00161 00162 // By default, each new GraphicsOutput is set up to clear color and 00163 // depth. 00164 set_clear_color_active(true); 00165 set_clear_depth_active(true); 00166 set_clear_stencil_active(true); 00167 00168 switch (background_color.get_num_words()) { 00169 case 1: 00170 set_clear_color(LColor(background_color[0], background_color[0], background_color[0], 0.0f)); 00171 break; 00172 00173 case 2: 00174 set_clear_color(LColor(background_color[0], background_color[0], background_color[0], background_color[1])); 00175 break; 00176 00177 case 3: 00178 set_clear_color(LColor(background_color[0], background_color[1], background_color[2], 0.0f)); 00179 break; 00180 00181 case 4: 00182 set_clear_color(LColor(background_color[0], background_color[1], background_color[2], background_color[3])); 00183 break; 00184 00185 default: 00186 display_cat.warning() 00187 << "Invalid background-color specification: " 00188 << background_color.get_string_value() << "\n"; 00189 } 00190 } 00191 00192 //////////////////////////////////////////////////////////////////// 00193 // Function: GraphicsOutput::Copy Constructor 00194 // Access: Private 00195 // Description: 00196 //////////////////////////////////////////////////////////////////// 00197 GraphicsOutput:: 00198 GraphicsOutput(const GraphicsOutput &) : 00199 _cull_window_pcollector(_cull_pcollector, "Invalid"), 00200 _draw_window_pcollector(_draw_pcollector, "Invalid") 00201 { 00202 nassertv(false); 00203 } 00204 00205 //////////////////////////////////////////////////////////////////// 00206 // Function: GraphicsOutput::Copy Assignment Operator 00207 // Access: Private 00208 // Description: 00209 //////////////////////////////////////////////////////////////////// 00210 void GraphicsOutput:: 00211 operator = (const GraphicsOutput &) { 00212 nassertv(false); 00213 } 00214 00215 //////////////////////////////////////////////////////////////////// 00216 // Function: GraphicsOutput::Destructor 00217 // Access: Published, Virtual 00218 // Description: 00219 //////////////////////////////////////////////////////////////////// 00220 GraphicsOutput:: 00221 ~GraphicsOutput() { 00222 // The window should be closed by the time we destruct. 00223 nassertv(!is_valid()); 00224 00225 // We shouldn't have a GraphicsPipe pointer anymore. 00226 nassertv(_pipe == (GraphicsPipe *)NULL); 00227 00228 // We don't have to destruct our child display regions explicitly, 00229 // since they are all reference-counted and will go away when their 00230 // pointers do. However, we do need to zero out their pointers to 00231 // us. 00232 TotalDisplayRegions::iterator dri; 00233 for (dri = _total_display_regions.begin(); 00234 dri != _total_display_regions.end(); 00235 ++dri) { 00236 (*dri)->_window = NULL; 00237 } 00238 00239 _total_display_regions.clear(); 00240 _overlay_display_region = NULL; 00241 } 00242 00243 //////////////////////////////////////////////////////////////////// 00244 // Function: GraphicsOutput::clear_render_textures 00245 // Access: Published 00246 // Description: If the GraphicsOutput is currently rendering to 00247 // a texture, then all textures are dissociated from 00248 // the GraphicsOuput. 00249 //////////////////////////////////////////////////////////////////// 00250 void GraphicsOutput:: 00251 clear_render_textures() { 00252 CDWriter cdata(_cycler, true); 00253 cdata->_textures.clear(); 00254 ++(cdata->_textures_seq); 00255 throw_event("render-texture-targets-changed"); 00256 } 00257 00258 //////////////////////////////////////////////////////////////////// 00259 // Function: GraphicsOutput::add_render_texture 00260 // Access: Published 00261 // Description: Creates a new Texture object, suitable for rendering 00262 // the contents of this buffer into, and appends it to 00263 // the list of render textures. 00264 // 00265 // If tex is not NULL, it is the texture that will be 00266 // set up for rendering into; otherwise, a new Texture 00267 // object will be created, in which case you may call 00268 // get_texture() to retrieve the new texture pointer. 00269 // 00270 // You can specify a bitplane to attach the texture to. 00271 // the legal choices are: 00272 // 00273 // * RTP_depth 00274 // * RTP_depth_stencil 00275 // * RTP_color 00276 // * RTP_aux_rgba_0 00277 // * RTP_aux_rgba_1 00278 // * RTP_aux_rgba_2 00279 // * RTP_aux_rgba_3 00280 // 00281 // If you do not specify a bitplane to attach the 00282 // texture to, this routine will use a default based 00283 // on the texture's format: 00284 // 00285 // * F_depth_component attaches to RTP_depth 00286 // * F_depth_stencil attaches to RTP_depth_stencil 00287 // * all other formats attach to RTP_color. 00288 // 00289 // The texture's format will be changed to match 00290 // the format of the bitplane to which it is attached. 00291 // For example, if you pass in an F_rgba texture and 00292 // order that it be attached to RTP_depth_stencil, it will turn 00293 // into an F_depth_stencil texture. 00294 // 00295 // Also see make_texture_buffer(), which is a 00296 // higher-level interface for preparing 00297 // render-to-a-texture mode. 00298 //////////////////////////////////////////////////////////////////// 00299 void GraphicsOutput:: 00300 add_render_texture(Texture *tex, RenderTextureMode mode, 00301 RenderTexturePlane plane) { 00302 00303 if (mode == RTM_none) { 00304 return; 00305 } 00306 LightMutexHolder holder(_lock); 00307 00308 // Create texture if necessary. 00309 if (tex == (Texture *)NULL) { 00310 tex = new Texture(get_name()); 00311 tex->set_wrap_u(Texture::WM_clamp); 00312 tex->set_wrap_v(Texture::WM_clamp); 00313 } else { 00314 tex->clear_ram_image(); 00315 } 00316 00317 // Set it to have no compression by default. You can restore 00318 // compression later if you really, really want it; but this freaks 00319 // out some drivers, and presumably it's a mistake if you have 00320 // compression enabled for a rendered texture. 00321 tex->set_compression(Texture::CM_off); 00322 00323 // Choose a default bitplane. 00324 if (plane == RTP_COUNT) { 00325 if (tex->get_format()==Texture::F_depth_stencil) { 00326 plane = RTP_depth_stencil; 00327 } else if (tex->get_format()==Texture::F_depth_component) { 00328 plane = RTP_depth; 00329 } else { 00330 plane = RTP_color; 00331 } 00332 } 00333 00334 // Set the texture's format to match the bitplane. 00335 // (And validate the bitplane, while we're at it). 00336 00337 if (plane == RTP_depth) { 00338 tex->set_format(Texture::F_depth_component); 00339 tex->set_match_framebuffer_format(true); 00340 } else if (plane == RTP_depth_stencil) { 00341 tex->set_format(Texture::F_depth_stencil); 00342 tex->set_match_framebuffer_format(true); 00343 } else if ((plane == RTP_color)|| 00344 (plane == RTP_aux_rgba_0)|| 00345 (plane == RTP_aux_rgba_1)|| 00346 (plane == RTP_aux_rgba_2)|| 00347 (plane == RTP_aux_rgba_3)) { 00348 tex->set_format(Texture::F_rgba); 00349 tex->set_match_framebuffer_format(true); 00350 } else if ((plane == RTP_aux_hrgba_0)|| 00351 (plane == RTP_aux_hrgba_1)|| 00352 (plane == RTP_aux_hrgba_2)|| 00353 (plane == RTP_aux_hrgba_3)) { 00354 tex->set_format(Texture::F_rgba16); 00355 tex->set_match_framebuffer_format(true); 00356 } else if ((plane == RTP_aux_float_0)|| 00357 (plane == RTP_aux_float_1)|| 00358 (plane == RTP_aux_float_2)|| 00359 (plane == RTP_aux_float_3)) { 00360 tex->set_format(Texture::F_rgba32); 00361 tex->set_match_framebuffer_format(true); 00362 } else { 00363 display_cat.error() << 00364 "add_render_texture: invalid bitplane specified.\n"; 00365 return; 00366 } 00367 00368 // Go ahead and tell the texture our anticipated size, even if it 00369 // might be inaccurate (particularly if this is a GraphicsWindow, 00370 // which has system-imposed restrictions on size). 00371 tex->set_size_padded(get_x_size(), get_y_size()); 00372 00373 if (mode == RTM_bind_or_copy) { 00374 if (!support_render_texture || !get_supports_render_texture()) { 00375 // Binding is not supported or it is disabled, so just fall back 00376 // to copy instead. 00377 mode = RTM_copy_texture; 00378 } 00379 } 00380 00381 if (mode == RTM_bind_or_copy) { 00382 // If we're still planning on binding, indicate it in texture 00383 // properly. 00384 tex->set_render_to_texture(true); 00385 } 00386 00387 CDWriter cdata(_cycler, true); 00388 RenderTexture result; 00389 result._texture = tex; 00390 result._plane = plane; 00391 result._rtm_mode = mode; 00392 cdata->_textures.push_back(result); 00393 ++(cdata->_textures_seq); 00394 00395 throw_event("render-texture-targets-changed"); 00396 } 00397 00398 //////////////////////////////////////////////////////////////////// 00399 // Function: GraphicsOutput::setup_render_texture 00400 // Access: Published 00401 // Description: This is a deprecated interface that made sense back 00402 // when GraphicsOutputs could only render into one 00403 // texture at a time. From now on, use 00404 // clear_render_textures and add_render_texture 00405 // instead. 00406 //////////////////////////////////////////////////////////////////// 00407 void GraphicsOutput:: 00408 setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) { 00409 display_cat.warning() << 00410 "Using deprecated setup_render_texture interface.\n"; 00411 clear_render_textures(); 00412 if (to_ram) { 00413 add_render_texture(tex, RTM_copy_ram); 00414 } else if (allow_bind) { 00415 add_render_texture(tex, RTM_bind_or_copy); 00416 } else { 00417 add_render_texture(tex, RTM_copy_texture); 00418 } 00419 } 00420 00421 //////////////////////////////////////////////////////////////////// 00422 // Function: GraphicsOutput::set_active 00423 // Access: Published 00424 // Description: Sets the active flag associated with the 00425 // GraphicsOutput. If the GraphicsOutput is marked 00426 // inactive, nothing is rendered. 00427 //////////////////////////////////////////////////////////////////// 00428 void GraphicsOutput:: 00429 set_active(bool active) { 00430 CDLockedReader cdata(_cycler); 00431 if (cdata->_active != active) { 00432 CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true); 00433 cdataw->_active = active; 00434 } 00435 } 00436 00437 //////////////////////////////////////////////////////////////////// 00438 // Function: GraphicsOutput::is_active 00439 // Access: Published, Virtual 00440 // Description: Returns true if the window is ready to be rendered 00441 // into, false otherwise. 00442 //////////////////////////////////////////////////////////////////// 00443 bool GraphicsOutput:: 00444 is_active() const { 00445 if (!is_valid()) { 00446 return false; 00447 } 00448 00449 CDReader cdata(_cycler); 00450 if (cdata->_one_shot_frame != -1) { 00451 // If one_shot is in effect, then we are active only for the one 00452 // indicated frame. 00453 if (cdata->_one_shot_frame != ClockObject::get_global_clock()->get_frame_count()) { 00454 return false; 00455 } 00456 } 00457 return cdata->_active; 00458 } 00459 00460 //////////////////////////////////////////////////////////////////// 00461 // Function: GraphicsOutput::set_one_shot 00462 // Access: Published 00463 // Description: Changes the current setting of the one-shot flag. 00464 // When this is true, the GraphicsOutput will render the 00465 // current frame and then automatically set itself 00466 // inactive. This is particularly useful for buffers 00467 // that are created for the purposes of 00468 // render-to-texture, for static textures that don't 00469 // need to be continually re-rendered once they have 00470 // been rendered the first time. 00471 // 00472 // Setting the buffer inactive is not the same thing as 00473 // destroying it. You are still responsible for passing 00474 // this buffer to GraphicsEngine::remove_window() when 00475 // you no longer need the texture, in order to clean up 00476 // fully. (However, you should not call remove_window() 00477 // on this buffer while the texture is still needed, 00478 // because depending on the render-to-texture mechanism 00479 // in use, this may invalidate the texture contents.) 00480 //////////////////////////////////////////////////////////////////// 00481 void GraphicsOutput:: 00482 set_one_shot(bool one_shot) { 00483 CDWriter cdata(_cycler, true); 00484 if (one_shot) { 00485 cdata->_one_shot_frame = ClockObject::get_global_clock()->get_frame_count(); 00486 } else { 00487 cdata->_one_shot_frame = -1; 00488 } 00489 } 00490 00491 //////////////////////////////////////////////////////////////////// 00492 // Function: GraphicsOutput::get_one_shot 00493 // Access: Published 00494 // Description: Returns the current setting of the one-shot flag. 00495 // When this is true, the GraphicsOutput will 00496 // automatically set itself inactive after the next 00497 // frame. 00498 //////////////////////////////////////////////////////////////////// 00499 bool GraphicsOutput:: 00500 get_one_shot() const { 00501 CDReader cdata(_cycler); 00502 return (cdata->_one_shot_frame == ClockObject::get_global_clock()->get_frame_count()); 00503 } 00504 00505 //////////////////////////////////////////////////////////////////// 00506 // Function: GraphicsOutput::set_inverted 00507 // Access: Published 00508 // Description: Changes the current setting of the inverted flag. 00509 // When this is true, the scene is rendered into the 00510 // window upside-down and backwards, that is, inverted 00511 // as if viewed through a mirror placed on the floor. 00512 // 00513 // This is primarily intended to support DirectX (and a 00514 // few buggy OpenGL graphics drivers) that perform a 00515 // framebuffer-to-texture copy upside-down from the 00516 // usual OpenGL (and Panda) convention. Panda will 00517 // automatically set this flag for offscreen buffers on 00518 // hardware that is known to do this, to compensate when 00519 // rendering offscreen into a texture. 00520 //////////////////////////////////////////////////////////////////// 00521 void GraphicsOutput:: 00522 set_inverted(bool inverted) { 00523 if (_inverted != inverted) { 00524 _inverted = inverted; 00525 00526 if (_y_size != 0) { 00527 // All of our DisplayRegions need to recompute their pixel 00528 // positions now. 00529 TotalDisplayRegions::iterator dri; 00530 for (dri = _total_display_regions.begin(); 00531 dri != _total_display_regions.end(); 00532 ++dri) { 00533 (*dri)->compute_pixels(_x_size, _y_size); 00534 } 00535 } 00536 } 00537 } 00538 00539 //////////////////////////////////////////////////////////////////// 00540 // Function: GraphicsOutput::set_side_by_side_stereo 00541 // Access: Published 00542 // Description: Enables side-by-side stereo mode on this particular 00543 // window. When side-by-side stereo mode is in effect, 00544 // DisplayRegions that have the "left" channel set will 00545 // render on the part of the window specified by 00546 // sbs_left_dimensions (typically the left half: (0, 00547 // 0.5, 0, 1)), while DisplayRegions that have the 00548 // "right" channel set will render on the part of the 00549 // window specified by sbs_right_dimensions (typically 00550 // the right half: (0.5, 1, 0, 1)). 00551 // 00552 // This is commonly used in a dual-monitor mode, where a 00553 // window is opened that spans two monitors, and each 00554 // monitor represents a different eye. 00555 //////////////////////////////////////////////////////////////////// 00556 void GraphicsOutput:: 00557 set_side_by_side_stereo(bool side_by_side_stereo) { 00558 LVecBase4 left, right; 00559 left.set(sbs_left_dimensions[0], sbs_left_dimensions[1], 00560 sbs_left_dimensions[2], sbs_left_dimensions[3]); 00561 right.set(sbs_right_dimensions[0], sbs_right_dimensions[1], 00562 sbs_right_dimensions[2], sbs_right_dimensions[3]); 00563 set_side_by_side_stereo(side_by_side_stereo, left, right); 00564 } 00565 00566 //////////////////////////////////////////////////////////////////// 00567 // Function: GraphicsOutput::set_side_by_side_stereo 00568 // Access: Published 00569 // Description: Enables side-by-side stereo mode on this particular 00570 // window. When side-by-side stereo mode is in effect, 00571 // DisplayRegions that have the "left" channel set will 00572 // render on the part of the window specified by 00573 // sbs_left_dimensions (typically the left half: (0, 00574 // 0.5, 0, 1)), while DisplayRegions that have the 00575 // "right" channel set will render on the part of the 00576 // window specified by sbs_right_dimensions (typically 00577 // the right half: (0.5, 1, 0, 1)). 00578 // 00579 // This is commonly used in a dual-monitor mode, where a 00580 // window is opened that spans two monitors, and each 00581 // monitor represents a different eye. 00582 //////////////////////////////////////////////////////////////////// 00583 void GraphicsOutput:: 00584 set_side_by_side_stereo(bool side_by_side_stereo, 00585 const LVecBase4 &sbs_left_dimensions, 00586 const LVecBase4 &sbs_right_dimensions) { 00587 _side_by_side_stereo = side_by_side_stereo; 00588 if (_side_by_side_stereo) { 00589 _sbs_left_dimensions = sbs_left_dimensions; 00590 _sbs_right_dimensions = sbs_right_dimensions; 00591 } else { 00592 _sbs_left_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f); 00593 _sbs_right_dimensions.set(0.0f, 1.0f, 0.0f, 1.0f); 00594 } 00595 } 00596 00597 //////////////////////////////////////////////////////////////////// 00598 // Function: GraphicsOutput::get_delete_flag 00599 // Access: Published 00600 // Description: Returns the current setting of the delete flag. When 00601 // this is true, the GraphicsOutput will automatically 00602 // be removed before the beginning of the next frame by 00603 // the GraphicsEngine. 00604 //////////////////////////////////////////////////////////////////// 00605 bool GraphicsOutput:: 00606 get_delete_flag() const { 00607 // We only delete the window or buffer automatically when it is 00608 // no longer associated with a texture. 00609 for (int i = 0; i < (int)_hold_textures.size(); i++) { 00610 if (_hold_textures[i].is_valid_pointer()) { 00611 return false; 00612 } 00613 } 00614 00615 return _delete_flag; 00616 } 00617 00618 //////////////////////////////////////////////////////////////////// 00619 // Function: GraphicsOutput::set_sort 00620 // Access: Published, Virtual 00621 // Description: Adjusts the sorting order of this particular 00622 // GraphicsOutput, relative to other GraphicsOutputs. 00623 //////////////////////////////////////////////////////////////////// 00624 void GraphicsOutput:: 00625 set_sort(int sort) { 00626 if (_sort != sort) { 00627 if (_gsg != (GraphicsStateGuardian *)NULL && 00628 _gsg->get_engine() != (GraphicsEngine *)NULL) { 00629 _gsg->get_engine()->set_window_sort(this, sort); 00630 } 00631 } 00632 } 00633 00634 //////////////////////////////////////////////////////////////////// 00635 // Function: GraphicsOutput::make_display_region 00636 // Access: Published 00637 // Description: Creates a new DisplayRegion that covers the indicated 00638 // sub-rectangle within the window. The range on all 00639 // parameters is 0..1. 00640 // 00641 // If is_stereo() is true for this window, and 00642 // default-stereo-camera is configured true, this 00643 // actually makes a StereoDisplayRegion. Call 00644 // make_mono_display_region() or 00645 // make_stereo_display_region() if you want to insist on 00646 // one or the other. 00647 //////////////////////////////////////////////////////////////////// 00648 DisplayRegion *GraphicsOutput:: 00649 make_display_region(const LVecBase4 &dimensions) { 00650 if (is_stereo() && default_stereo_camera) { 00651 return make_stereo_display_region(dimensions); 00652 } else { 00653 return make_mono_display_region(dimensions); 00654 } 00655 } 00656 00657 //////////////////////////////////////////////////////////////////// 00658 // Function: GraphicsOutput::make_mono_display_region 00659 // Access: Published 00660 // Description: Creates a new DisplayRegion that covers the indicated 00661 // sub-rectangle within the window. The range on all 00662 // parameters is 0..1. 00663 // 00664 // This generally returns a mono DisplayRegion, even if 00665 // is_stereo() is true. However, if side-by-side stereo 00666 // is enabled, this will return a StereoDisplayRegion 00667 // whose two eyes are both set to SC_mono. (This is 00668 // necessary because in side-by-side stereo mode, it is 00669 // necessary to draw even mono DisplayRegions twice). 00670 //////////////////////////////////////////////////////////////////// 00671 DisplayRegion *GraphicsOutput:: 00672 make_mono_display_region(const LVecBase4 &dimensions) { 00673 if (_side_by_side_stereo) { 00674 StereoDisplayRegion *dr = make_stereo_display_region(dimensions); 00675 dr->get_left_eye()->set_stereo_channel(Lens::SC_mono); 00676 dr->get_right_eye()->set_stereo_channel(Lens::SC_mono); 00677 return dr; 00678 } 00679 00680 return new DisplayRegion(this, dimensions); 00681 } 00682 00683 //////////////////////////////////////////////////////////////////// 00684 // Function: GraphicsOutput::make_stereo_display_region 00685 // Access: Published 00686 // Description: Creates a new DisplayRegion that covers the indicated 00687 // sub-rectangle within the window. The range on all 00688 // parameters is 0..1. 00689 // 00690 // This always returns a stereo DisplayRegion, even if 00691 // is_stereo() is false. 00692 //////////////////////////////////////////////////////////////////// 00693 StereoDisplayRegion *GraphicsOutput:: 00694 make_stereo_display_region(const LVecBase4 &dimensions) { 00695 PT(DisplayRegion) left, right; 00696 00697 if (_side_by_side_stereo) { 00698 // On a side-by-side stereo window, each eye gets the 00699 // corresponding dimensions of its own sub-region. 00700 PN_stdfloat left_l = _sbs_left_dimensions[0]; 00701 PN_stdfloat left_b = _sbs_left_dimensions[2]; 00702 PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0]; 00703 PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2]; 00704 LVecBase4 left_dimensions(dimensions[0] * left_w + left_l, 00705 dimensions[1] * left_w + left_l, 00706 dimensions[2] * left_h + left_b, 00707 dimensions[3] * left_h + left_b); 00708 left = new DisplayRegion(this, left_dimensions); 00709 00710 PN_stdfloat right_l = _sbs_right_dimensions[0]; 00711 PN_stdfloat right_b = _sbs_right_dimensions[2]; 00712 PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0]; 00713 PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2]; 00714 LVecBase4 right_dimensions(dimensions[0] * right_w + right_l, 00715 dimensions[1] * right_w + right_l, 00716 dimensions[2] * right_h + right_b, 00717 dimensions[3] * right_h + right_b); 00718 right = new DisplayRegion(this, right_dimensions); 00719 00720 if (_swap_eyes) { 00721 DisplayRegion *t = left; 00722 left = right; 00723 right = t; 00724 } 00725 00726 } else { 00727 // Not a side-by-side stereo window; thus, both the left and right 00728 // eyes are the same region: the region specified. 00729 left = new DisplayRegion(this, dimensions); 00730 right = new DisplayRegion(this, dimensions); 00731 00732 // In this case, we assume that the two eyes will share the same 00733 // depth buffer, which means the right eye should clear the depth 00734 // buffer by default. 00735 if (get_clear_depth_active()) { 00736 right->set_clear_depth_active(true); 00737 } 00738 if (get_clear_stencil_active()) { 00739 right->set_clear_stencil_active(true); 00740 } 00741 } 00742 00743 PT(StereoDisplayRegion) stereo = new StereoDisplayRegion(this, dimensions, 00744 left, right); 00745 00746 return stereo; 00747 } 00748 00749 //////////////////////////////////////////////////////////////////// 00750 // Function: GraphicsOutput::remove_display_region 00751 // Access: Published 00752 // Description: Removes the indicated DisplayRegion from the window, 00753 // and destructs it if there are no other references. 00754 // 00755 // Returns true if the DisplayRegion is found and 00756 // removed, false if it was not a part of the window. 00757 //////////////////////////////////////////////////////////////////// 00758 bool GraphicsOutput:: 00759 remove_display_region(DisplayRegion *display_region) { 00760 LightMutexHolder holder(_lock); 00761 00762 nassertr(display_region != _overlay_display_region, false); 00763 00764 if (display_region->is_stereo()) { 00765 StereoDisplayRegion *sdr; 00766 DCAST_INTO_R(sdr, display_region, false); 00767 do_remove_display_region(sdr->get_left_eye()); 00768 do_remove_display_region(sdr->get_right_eye()); 00769 } 00770 00771 return do_remove_display_region(display_region); 00772 } 00773 00774 //////////////////////////////////////////////////////////////////// 00775 // Function: GraphicsOutput::remove_all_display_regions 00776 // Access: Published 00777 // Description: Removes all display regions from the window, except 00778 // the default one that is created with the window. 00779 //////////////////////////////////////////////////////////////////// 00780 void GraphicsOutput:: 00781 remove_all_display_regions() { 00782 LightMutexHolder holder(_lock); 00783 00784 CDWriter cdata(_cycler, true); 00785 cdata->_active_display_regions_stale = true; 00786 00787 TotalDisplayRegions::iterator dri; 00788 for (dri = _total_display_regions.begin(); 00789 dri != _total_display_regions.end(); 00790 ++dri) { 00791 DisplayRegion *display_region = (*dri); 00792 if (display_region != _overlay_display_region) { 00793 // Let's aggressively clean up the display region too. 00794 display_region->cleanup(); 00795 display_region->_window = NULL; 00796 } 00797 } 00798 _total_display_regions.clear(); 00799 _total_display_regions.push_back(_overlay_display_region); 00800 } 00801 00802 //////////////////////////////////////////////////////////////////// 00803 // Function: GraphicsOutput::set_overlay_display_region 00804 // Access: Published 00805 // Description: Replaces the special "overlay" DisplayRegion that is 00806 // created for each window or buffer. See 00807 // get_overlay_display_region(). This must be a new 00808 // DisplayRegion that has already been created for this 00809 // window, for instance via a call to 00810 // make_mono_display_region(). You are responsible for 00811 // ensuring that the new DisplayRegion covers the entire 00812 // window. The previous overlay display region is not 00813 // automatically removed; you must explicitly call 00814 // remove_display_region() on it after replacing it with 00815 // this method, if you wish it to be removed. 00816 // 00817 // Normally, there is no reason to change the overlay 00818 // DisplayRegion, so this method should be used only 00819 // in very unusual circumstances. 00820 //////////////////////////////////////////////////////////////////// 00821 void GraphicsOutput:: 00822 set_overlay_display_region(DisplayRegion *display_region) { 00823 nassertv(display_region->get_window() == this); 00824 _overlay_display_region = display_region; 00825 } 00826 00827 //////////////////////////////////////////////////////////////////// 00828 // Function: GraphicsOutput::get_num_display_regions 00829 // Access: Published 00830 // Description: Returns the number of DisplayRegions that have 00831 // been created within the window, active or otherwise. 00832 //////////////////////////////////////////////////////////////////// 00833 int GraphicsOutput:: 00834 get_num_display_regions() const { 00835 determine_display_regions(); 00836 int result; 00837 { 00838 LightMutexHolder holder(_lock); 00839 result = _total_display_regions.size(); 00840 } 00841 return result; 00842 } 00843 00844 //////////////////////////////////////////////////////////////////// 00845 // Function: GraphicsOutput::get_display_region 00846 // Access: Published 00847 // Description: Returns the nth DisplayRegion of those that have been 00848 // created within the window. This may return NULL if n 00849 // is out of bounds; particularly likely if the number 00850 // of display regions has changed since the last call to 00851 // get_num_display_regions(). 00852 //////////////////////////////////////////////////////////////////// 00853 PT(DisplayRegion) GraphicsOutput:: 00854 get_display_region(int n) const { 00855 determine_display_regions(); 00856 PT(DisplayRegion) result; 00857 { 00858 LightMutexHolder holder(_lock); 00859 if (n >= 0 && n < (int)_total_display_regions.size()) { 00860 result = _total_display_regions[n]; 00861 } else { 00862 result = NULL; 00863 } 00864 } 00865 return result; 00866 } 00867 00868 //////////////////////////////////////////////////////////////////// 00869 // Function: GraphicsOutput::get_num_active_display_regions 00870 // Access: Published 00871 // Description: Returns the number of active DisplayRegions that have 00872 // been created within the window. 00873 //////////////////////////////////////////////////////////////////// 00874 int GraphicsOutput:: 00875 get_num_active_display_regions() const { 00876 determine_display_regions(); 00877 CDReader cdata(_cycler); 00878 return cdata->_active_display_regions.size(); 00879 } 00880 00881 //////////////////////////////////////////////////////////////////// 00882 // Function: GraphicsOutput::get_active_display_region 00883 // Access: Published 00884 // Description: Returns the nth active DisplayRegion of those that 00885 // have been created within the window. This may return 00886 // NULL if n is out of bounds; particularly likely if 00887 // the number of display regions has changed since the 00888 // last call to get_num_active_display_regions(). 00889 //////////////////////////////////////////////////////////////////// 00890 PT(DisplayRegion) GraphicsOutput:: 00891 get_active_display_region(int n) const { 00892 determine_display_regions(); 00893 00894 CDReader cdata(_cycler); 00895 if (n >= 0 && n < (int)cdata->_active_display_regions.size()) { 00896 return cdata->_active_display_regions[n]; 00897 } 00898 return NULL; 00899 } 00900 00901 //////////////////////////////////////////////////////////////////// 00902 // Function: GraphicsOutput::make_texture_buffer 00903 // Access: Published 00904 // Description: Creates and returns an offscreen buffer for rendering 00905 // into, the result of which will be a texture suitable 00906 // for applying to geometry within the scene rendered 00907 // into this window. 00908 // 00909 // If tex is not NULL, it is the texture that will be 00910 // set up for rendering into; otherwise, a new Texture 00911 // object will be created. In either case, the target 00912 // texture can be retrieved from the return value with 00913 // buffer->get_texture() (assuming the return value is 00914 // not NULL). 00915 // 00916 // If to_ram is true, the buffer will be set up to 00917 // download its contents to the system RAM memory 00918 // associated with the Texture object, instead of 00919 // keeping it strictly within texture memory; this is 00920 // much slower, but it allows using the texture with any 00921 // GSG. 00922 // 00923 // This will attempt to be smart about maximizing render 00924 // performance while minimizing framebuffer waste. It 00925 // might return a GraphicsBuffer set to render directly 00926 // into a texture, if possible; or it might return a 00927 // ParasiteBuffer that renders into this window. The 00928 // return value is NULL if the buffer could not be 00929 // created for some reason. 00930 // 00931 // When you are done using the buffer, you should remove 00932 // it with a call to GraphicsEngine::remove_window(). 00933 //////////////////////////////////////////////////////////////////// 00934 GraphicsOutput *GraphicsOutput:: 00935 make_texture_buffer(const string &name, int x_size, int y_size, 00936 Texture *tex, bool to_ram, FrameBufferProperties *fbp) { 00937 00938 FrameBufferProperties props; 00939 props.set_rgb_color(1); 00940 props.set_depth_bits(1); 00941 00942 if (fbp == NULL) { 00943 fbp = &props; 00944 } 00945 00946 int flags = GraphicsPipe::BF_refuse_window; 00947 if (textures_power_2 != ATS_none) { 00948 flags |= GraphicsPipe::BF_size_power_2; 00949 } 00950 if (tex != (Texture *)NULL && 00951 tex->get_texture_type() == Texture::TT_cube_map) { 00952 flags |= GraphicsPipe::BF_size_square; 00953 } 00954 00955 GraphicsOutput *buffer = get_gsg()->get_engine()-> 00956 make_output(get_gsg()->get_pipe(), 00957 name, get_child_sort(), 00958 *fbp, WindowProperties::size(x_size, y_size), 00959 flags, get_gsg(), get_host()); 00960 00961 if (buffer != (GraphicsOutput *)NULL) { 00962 if (buffer->get_gsg() == (GraphicsStateGuardian *)NULL || 00963 buffer->get_gsg()->get_prepared_objects() != get_gsg()->get_prepared_objects()) { 00964 // If the newly-created buffer doesn't share texture objects 00965 // with the current GSG, then we will have to force the texture 00966 // copy to go through RAM. 00967 to_ram = true; 00968 } 00969 00970 buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_bind_or_copy); 00971 return buffer; 00972 } 00973 00974 return NULL; 00975 } 00976 00977 //////////////////////////////////////////////////////////////////// 00978 // Function: GraphicsOutput::make_cube_map 00979 // Access: Published 00980 // Description: This is similar to make_texture_buffer() in that it 00981 // allocates a separate buffer suitable for rendering to 00982 // a texture that can be assigned to geometry in this 00983 // window, but in this case, the buffer is set up to 00984 // render the six faces of a cube map. 00985 // 00986 // The buffer is automatically set up with six display 00987 // regions and six cameras, each of which are assigned 00988 // the indicated draw_mask and parented to the given 00989 // camera_rig node (which you should then put in your 00990 // scene to render the cube map from the appropriate 00991 // point of view). 00992 // 00993 // You may take the texture associated with the buffer 00994 // and apply it to geometry, particularly with 00995 // TexGenAttrib::M_world_cube_map also in effect, to 00996 // apply a reflection of everything seen by the camera 00997 // rig. 00998 //////////////////////////////////////////////////////////////////// 00999 GraphicsOutput *GraphicsOutput:: 01000 make_cube_map(const string &name, int size, NodePath &camera_rig, 01001 DrawMask camera_mask, bool to_ram, FrameBufferProperties *fbp) { 01002 if (!to_ram) { 01003 // Check the limits imposed by the GSG. (However, if we're 01004 // rendering the texture to RAM only, these limits may be 01005 // irrelevant.) 01006 GraphicsStateGuardian *gsg = get_gsg(); 01007 int max_dimension = gsg->get_max_cube_map_dimension(); 01008 if (max_dimension == 0 || !gsg->get_supports_cube_map()) { 01009 // The GSG doesn't support cube mapping; too bad for you. 01010 display_cat.warning() 01011 << "Cannot make dynamic cube map; GSG does not support cube maps.\n"; 01012 return NULL; 01013 } 01014 if (max_dimension > 0) { 01015 size = min(max_dimension, size); 01016 } 01017 } 01018 01019 // Usually, we want the whole camera_rig to keep itself unrotated 01020 // with respect to the world coordinate space, so the user can apply 01021 // TexGenAttrib::M_world_cube_map to the objects on which the cube 01022 // map texture is applied. If for some reason the user doesn't want 01023 // this behavior, he can take this effect off again. 01024 camera_rig.node()->set_effect(CompassEffect::make(NodePath())); 01025 01026 PT(Texture) tex = new Texture(name); 01027 tex->setup_cube_map(); 01028 tex->set_wrap_u(Texture::WM_clamp); 01029 tex->set_wrap_v(Texture::WM_clamp); 01030 GraphicsOutput *buffer; 01031 01032 buffer = make_texture_buffer(name, size, size, tex, to_ram, fbp); 01033 01034 // We don't need to clear the overall buffer; instead, we'll clear 01035 // each display region. 01036 buffer->set_clear_color_active(false); 01037 buffer->set_clear_depth_active(false); 01038 buffer->set_clear_stencil_active(false); 01039 01040 PT(Lens) lens = new PerspectiveLens; 01041 lens->set_fov(90.0f); 01042 01043 for (int i = 0; i < 6; i++) { 01044 PT(Camera) camera = new Camera(cube_faces[i]._name); 01045 camera->set_lens(lens); 01046 camera->set_camera_mask(camera_mask); 01047 NodePath camera_np = camera_rig.attach_new_node(camera); 01048 camera_np.look_at(cube_faces[i]._look_at, cube_faces[i]._up); 01049 01050 DisplayRegion *dr; 01051 dr = buffer->make_display_region(); 01052 01053 dr->set_cube_map_index(i); 01054 dr->copy_clear_settings(*this); 01055 dr->set_camera(camera_np); 01056 } 01057 01058 return buffer; 01059 } 01060 01061 //////////////////////////////////////////////////////////////////// 01062 // Function: GraphicsOutput::get_texture_card 01063 // Access: Published 01064 // Description: Returns a PandaNode containing a square polygon. 01065 // The dimensions are (-1,0,-1) to (1,0,1). The texture 01066 // coordinates are such that the texture of this 01067 // GraphicsOutput is aligned properly to the polygon. 01068 // The GraphicsOutput promises to surgically update 01069 // the Geom inside the PandaNode if necessary to maintain 01070 // this invariant. 01071 // 01072 // Each invocation of this function returns a freshly- 01073 // allocated PandaNode. You can therefore safely modify 01074 // the RenderAttribs of the PandaNode. The 01075 // PandaNode is initially textured with the texture 01076 // of this GraphicOutput. 01077 //////////////////////////////////////////////////////////////////// 01078 NodePath GraphicsOutput:: 01079 get_texture_card() { 01080 if (_texture_card == 0) { 01081 PT(GeomVertexData) vdata = create_texture_card_vdata(_x_size, _y_size); 01082 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static); 01083 strip->set_shade_model(Geom::SM_uniform); 01084 strip->add_next_vertices(4); 01085 strip->close_primitive(); 01086 _texture_card = new Geom(vdata); 01087 _texture_card->add_primitive(strip); 01088 } 01089 01090 PT(GeomNode) gnode = new GeomNode("texture card"); 01091 gnode->add_geom(_texture_card); 01092 NodePath path(gnode); 01093 01094 // The texture card, by default, is textured with the first 01095 // render-to-texture output texture. Depth and stencil 01096 // textures are ignored. The user can freely alter the 01097 // card's texture attrib. 01098 CDReader cdata(_cycler); 01099 RenderTextures::const_iterator ri; 01100 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) { 01101 Texture *texture = (*ri)._texture; 01102 if ((texture->get_format() != Texture::F_depth_stencil)) { 01103 path.set_texture(texture, 0); 01104 break; 01105 } 01106 } 01107 01108 return path; 01109 } 01110 01111 //////////////////////////////////////////////////////////////////// 01112 // Function: GraphicsOutput::share_depth_buffer 01113 // Access: Published, Virtual 01114 // Description: Will attempt to use the depth buffer of the input 01115 // graphics_output. The buffer sizes must be exactly 01116 // the same. 01117 //////////////////////////////////////////////////////////////////// 01118 bool GraphicsOutput:: 01119 share_depth_buffer(GraphicsOutput *graphics_output) { 01120 return false; 01121 } 01122 01123 //////////////////////////////////////////////////////////////////// 01124 // Function: GraphicsOutput::unshare_depth_buffer 01125 // Access: Published, Virtual 01126 // Description: Discontinue sharing the depth buffer. 01127 //////////////////////////////////////////////////////////////////// 01128 void GraphicsOutput:: 01129 unshare_depth_buffer() { 01130 } 01131 01132 //////////////////////////////////////////////////////////////////// 01133 // Function: GraphicsOutput::get_supports_render_texture 01134 // Access: Published, Virtual 01135 // Description: Returns true if this particular GraphicsOutput can 01136 // render directly into a texture, or false if it must 01137 // always copy-to-texture at the end of each frame to 01138 // achieve this effect. 01139 //////////////////////////////////////////////////////////////////// 01140 bool GraphicsOutput:: 01141 get_supports_render_texture() const { 01142 return false; 01143 } 01144 01145 //////////////////////////////////////////////////////////////////// 01146 // Function: GraphicsOutput::flip_ready 01147 // Access: Public, Virtual 01148 // Description: Returns true if a frame has been rendered and needs 01149 // to be flipped, false otherwise. 01150 //////////////////////////////////////////////////////////////////// 01151 bool GraphicsOutput:: 01152 flip_ready() const { 01153 return _flip_ready; 01154 } 01155 01156 //////////////////////////////////////////////////////////////////// 01157 // Function: GraphicsOutput::get_host 01158 // Access: Public, Virtual 01159 // Description: This is normally called only from within 01160 // make_texture_buffer(). When called on a 01161 // ParasiteBuffer, it returns the host of that buffer; 01162 // but when called on some other buffer, it returns the 01163 // buffer itself. 01164 //////////////////////////////////////////////////////////////////// 01165 GraphicsOutput *GraphicsOutput:: 01166 get_host() { 01167 return this; 01168 } 01169 01170 //////////////////////////////////////////////////////////////////// 01171 // Function: GraphicsOutput::request_open 01172 // Access: Public, Virtual 01173 // Description: This is called by the GraphicsEngine to request that 01174 // the window (or whatever) open itself or, in general, 01175 // make itself valid, at the next call to 01176 // process_events(). 01177 //////////////////////////////////////////////////////////////////// 01178 void GraphicsOutput:: 01179 request_open() { 01180 } 01181 01182 //////////////////////////////////////////////////////////////////// 01183 // Function: GraphicsOutput::request_close 01184 // Access: Public, Virtual 01185 // Description: This is called by the GraphicsEngine to request that 01186 // the window (or whatever) close itself or, in general, 01187 // make itself invalid, at the next call to 01188 // process_events(). By that time we promise the gsg 01189 // pointer will be cleared. 01190 //////////////////////////////////////////////////////////////////// 01191 void GraphicsOutput:: 01192 request_close() { 01193 } 01194 01195 //////////////////////////////////////////////////////////////////// 01196 // Function: GraphicsOutput::set_close_now 01197 // Access: Public, Virtual 01198 // Description: This is called by the GraphicsEngine to insist that 01199 // the output be closed immediately. This is only 01200 // called from the window thread. 01201 //////////////////////////////////////////////////////////////////// 01202 void GraphicsOutput:: 01203 set_close_now() { 01204 } 01205 01206 //////////////////////////////////////////////////////////////////// 01207 // Function: GraphicsOutput::reset_window 01208 // Access: Protected, Virtual 01209 // Description: Resets the window framebuffer from its derived 01210 // children. Does nothing here. 01211 //////////////////////////////////////////////////////////////////// 01212 void GraphicsOutput:: 01213 reset_window(bool swapchain) { 01214 display_cat.info() 01215 << "Resetting " << get_type() << "\n"; 01216 } 01217 01218 //////////////////////////////////////////////////////////////////// 01219 // Function: GraphicsOutput::clear_pipe 01220 // Access: Protected, Virtual 01221 // Description: Sets the window's _pipe pointer to NULL; this is 01222 // generally called only as a precursor to deleting the 01223 // window. 01224 //////////////////////////////////////////////////////////////////// 01225 void GraphicsOutput:: 01226 clear_pipe() { 01227 _pipe = (GraphicsPipe *)NULL; 01228 } 01229 01230 //////////////////////////////////////////////////////////////////// 01231 // Function: GraphicsOutput::set_size_and_recalc 01232 // Access: Public 01233 // Description: Changes the x_size and y_size, then recalculates 01234 // structures that depend on size. The recalculation 01235 // currently includes: 01236 // - compute_pixels on all the graphics regions. 01237 // - updating the texture card, if one is present. 01238 //////////////////////////////////////////////////////////////////// 01239 void GraphicsOutput:: 01240 set_size_and_recalc(int x, int y) { 01241 _x_size = x; 01242 _y_size = y; 01243 _has_size = true; 01244 01245 _is_nonzero_size = (_x_size > 0 && _y_size > 0); 01246 01247 int fb_x_size = get_fb_x_size(); 01248 int fb_y_size = get_fb_y_size(); 01249 01250 TotalDisplayRegions::iterator dri; 01251 for (dri = _total_display_regions.begin(); 01252 dri != _total_display_regions.end(); 01253 ++dri) { 01254 (*dri)->compute_pixels_all_stages(fb_x_size, fb_y_size); 01255 } 01256 01257 if (_texture_card != 0) { 01258 _texture_card->set_vertex_data(create_texture_card_vdata(x, y)); 01259 } 01260 } 01261 01262 //////////////////////////////////////////////////////////////////// 01263 // Function: GraphicsOutput::clear 01264 // Access: Public 01265 // Description: Clears the entire framebuffer before rendering, 01266 // according to the settings of get_color_clear_active() 01267 // and get_depth_clear_active() (inherited from 01268 // DrawableRegion). 01269 // 01270 // This function is called only within the draw thread. 01271 //////////////////////////////////////////////////////////////////// 01272 void GraphicsOutput:: 01273 clear(Thread *current_thread) { 01274 if (is_any_clear_active()) { 01275 if (display_cat.is_spam()) { 01276 display_cat.spam() 01277 << "clear(): " << get_type() << " " 01278 << get_name() << " " << (void *)this << "\n"; 01279 } 01280 01281 nassertv(_gsg != (GraphicsStateGuardian *)NULL); 01282 01283 DisplayRegionPipelineReader dr_reader(_overlay_display_region, current_thread); 01284 _gsg->prepare_display_region(&dr_reader); 01285 _gsg->clear(this); 01286 } 01287 } 01288 01289 //////////////////////////////////////////////////////////////////// 01290 // Function: GraphicsOutput::begin_frame 01291 // Access: Public, Virtual 01292 // Description: This function will be called within the draw thread 01293 // before beginning rendering for a given frame. It 01294 // should do whatever setup is required, and return true 01295 // if the frame should be rendered, or false if it 01296 // should be skipped. 01297 //////////////////////////////////////////////////////////////////// 01298 bool GraphicsOutput:: 01299 begin_frame(FrameMode mode, Thread *current_thread) { 01300 return false; 01301 } 01302 01303 //////////////////////////////////////////////////////////////////// 01304 // Function: GraphicsOutput::end_frame 01305 // Access: Public, Virtual 01306 // Description: This function will be called within the draw thread 01307 // after rendering is completed for a given frame. It 01308 // should do whatever finalization is required. 01309 //////////////////////////////////////////////////////////////////// 01310 void GraphicsOutput:: 01311 end_frame(FrameMode mode, Thread *current_thread) { 01312 } 01313 01314 //////////////////////////////////////////////////////////////////// 01315 // Function: GraphicsOutput::change_scenes 01316 // Access: Public 01317 // Description: Called by the GraphicsEngine when the window is about 01318 // to change to another DisplayRegion. This exists 01319 // mainly to provide a callback for switching the cube 01320 // map face, if we are rendering to the different faces 01321 // of a cube map. 01322 //////////////////////////////////////////////////////////////////// 01323 void GraphicsOutput:: 01324 change_scenes(DisplayRegionPipelineReader *new_dr) { 01325 int new_cube_map_index = new_dr->get_cube_map_index(); 01326 if (new_cube_map_index != -1 && 01327 new_cube_map_index != _cube_map_index) { 01328 int old_cube_map_index = _cube_map_index; 01329 DisplayRegion *old_cube_map_dr = _cube_map_dr; 01330 _cube_map_index = new_cube_map_index; 01331 _cube_map_dr = new_dr->get_object(); 01332 01333 CDReader cdata(_cycler); 01334 RenderTextures::const_iterator ri; 01335 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) { 01336 RenderTextureMode rtm_mode = (*ri)._rtm_mode; 01337 Texture *texture = (*ri)._texture; 01338 if (rtm_mode != RTM_none) { 01339 if (rtm_mode == RTM_bind_or_copy) { 01340 // In render-to-texture mode, switch the rendering backend to 01341 // the new cube map face, so that the subsequent frame will be 01342 // rendered to the new face. 01343 01344 select_cube_map(new_cube_map_index); 01345 01346 } else if (old_cube_map_index != -1) { 01347 // In copy-to-texture mode, copy the just-rendered framebuffer 01348 // to the old cube map face. 01349 nassertv(old_cube_map_dr != (DisplayRegion *)NULL); 01350 if (display_cat.is_debug()) { 01351 display_cat.debug() 01352 << "Copying texture for " << get_name() << " at scene change.\n"; 01353 display_cat.debug() 01354 << "cube_map_index = " << old_cube_map_index << "\n"; 01355 } 01356 RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type(), 01357 get_fb_properties()); 01358 if (rtm_mode == RTM_copy_ram) { 01359 _gsg->framebuffer_copy_to_ram(texture, old_cube_map_index, 01360 old_cube_map_dr, buffer); 01361 } else { 01362 _gsg->framebuffer_copy_to_texture(texture, old_cube_map_index, 01363 old_cube_map_dr, buffer); 01364 } 01365 } 01366 } 01367 } 01368 } 01369 } 01370 01371 //////////////////////////////////////////////////////////////////// 01372 // Function: GraphicsOutput::select_cube_map 01373 // Access: Public, Virtual 01374 // Description: Called internally when the window is in 01375 // render-to-a-texture mode and we are in the process of 01376 // rendering the six faces of a cube map. This should 01377 // do whatever needs to be done to switch the buffer to 01378 // the indicated face. 01379 //////////////////////////////////////////////////////////////////// 01380 void GraphicsOutput:: 01381 select_cube_map(int) { 01382 } 01383 01384 //////////////////////////////////////////////////////////////////// 01385 // Function: GraphicsOutput::begin_flip 01386 // Access: Public, Virtual 01387 // Description: This function will be called within the draw thread 01388 // after end_frame() has been called on all windows, to 01389 // initiate the exchange of the front and back buffers. 01390 // 01391 // This should instruct the window to prepare for the 01392 // flip at the next video sync, but it should not wait. 01393 // 01394 // We have the two separate functions, begin_flip() and 01395 // end_flip(), to make it easier to flip all of the 01396 // windows at the same time. 01397 //////////////////////////////////////////////////////////////////// 01398 void GraphicsOutput:: 01399 begin_flip() { 01400 } 01401 01402 //////////////////////////////////////////////////////////////////// 01403 // Function: GraphicsOutput::ready_flip 01404 // Access: Public, Virtual 01405 // Description: This function will be called within the draw thread 01406 // after end_frame() has been called on all windows, to 01407 // initiate the exchange of the front and back buffers. 01408 // 01409 // This should instruct the window to prepare for the 01410 // flip when it is command but not actually flip 01411 // 01412 //////////////////////////////////////////////////////////////////// 01413 void GraphicsOutput:: 01414 ready_flip() { 01415 } 01416 01417 //////////////////////////////////////////////////////////////////// 01418 // Function: GraphicsOutput::end_flip 01419 // Access: Public, Virtual 01420 // Description: This function will be called within the draw thread 01421 // after begin_flip() has been called on all windows, to 01422 // finish the exchange of the front and back buffers. 01423 // 01424 // This should cause the window to wait for the flip, if 01425 // necessary. 01426 //////////////////////////////////////////////////////////////////// 01427 void GraphicsOutput:: 01428 end_flip() { 01429 _flip_ready = false; 01430 } 01431 01432 //////////////////////////////////////////////////////////////////// 01433 // Function: GraphicsOutput::process_events 01434 // Access: Public, Virtual 01435 // Description: Do whatever processing in the window thread is 01436 // appropriate for this output object each frame. 01437 // 01438 // This function is called only within the window 01439 // thread. 01440 //////////////////////////////////////////////////////////////////// 01441 void GraphicsOutput:: 01442 process_events() { 01443 } 01444 01445 //////////////////////////////////////////////////////////////////// 01446 // Function: GraphicsOutput::pixel_factor_changed 01447 // Access: Published, Virtual 01448 // Description: Called internally when the pixel factor changes. 01449 //////////////////////////////////////////////////////////////////// 01450 void GraphicsOutput:: 01451 pixel_factor_changed() { 01452 if (_has_size) { 01453 set_size_and_recalc(_x_size, _y_size); 01454 } 01455 } 01456 01457 //////////////////////////////////////////////////////////////////// 01458 // Function: GraphicsOutput::prepare_for_deletion 01459 // Access: Protected 01460 // Description: Set the delete flag, and do the usual cleanup 01461 // activities associated with that. 01462 //////////////////////////////////////////////////////////////////// 01463 void GraphicsOutput:: 01464 prepare_for_deletion() { 01465 CDWriter cdata(_cycler, true); 01466 cdata->_active = false; 01467 01468 // If we were rendering directly to texture, we can't delete the 01469 // buffer until all the textures are gone too. 01470 RenderTextures::iterator ri; 01471 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) { 01472 if ((*ri)._rtm_mode == RTM_bind_or_copy) { 01473 _hold_textures.push_back((*ri)._texture); 01474 } 01475 } 01476 cdata->_textures.clear(); 01477 01478 _delete_flag = true; 01479 01480 // We have to be sure to remove all of the display regions 01481 // immediately, so that circular reference counts can be cleared 01482 // up (each display region keeps a pointer to a CullResult, 01483 // which can hold all sorts of pointers). 01484 remove_all_display_regions(); 01485 } 01486 01487 //////////////////////////////////////////////////////////////////// 01488 // Function: GraphicsOutput::promote_to_copy_texture 01489 // Access: Protected 01490 // Description: If any textures are marked RTM_bind_or_copy, change 01491 // them to RTM_copy_texture. 01492 //////////////////////////////////////////////////////////////////// 01493 void GraphicsOutput:: 01494 promote_to_copy_texture() { 01495 CDLockedReader cdata(_cycler); 01496 RenderTextures::const_iterator ri; 01497 01498 bool any_bind = false; 01499 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) { 01500 if ((*ri)._rtm_mode == RTM_bind_or_copy) { 01501 any_bind = true; 01502 break; 01503 } 01504 } 01505 if (any_bind) { 01506 CDWriter cdataw(((GraphicsOutput *)this)->_cycler, cdata, true); 01507 RenderTextures::iterator ri; 01508 for (ri = cdataw->_textures.begin(); ri != cdataw->_textures.end(); ++ri) { 01509 if ((*ri)._rtm_mode == RTM_bind_or_copy) { 01510 (*ri)._rtm_mode = RTM_copy_texture; 01511 } 01512 } 01513 } 01514 } 01515 01516 //////////////////////////////////////////////////////////////////// 01517 // Function: GraphicsOutput::copy_to_textures 01518 // Access: Protected 01519 // Description: For all textures marked RTM_copy_texture, 01520 // RTM_copy_ram, RTM_triggered_copy_texture, or 01521 // RTM_triggered_copy_ram, do the necessary copies. 01522 // 01523 // Returns true if all copies are successful, false 01524 // otherwise. 01525 //////////////////////////////////////////////////////////////////// 01526 bool GraphicsOutput:: 01527 copy_to_textures() { 01528 bool okflag = true; 01529 01530 CDReader cdata(_cycler); 01531 RenderTextures::const_iterator ri; 01532 for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) { 01533 RenderTextureMode rtm_mode = (*ri)._rtm_mode; 01534 if ((rtm_mode == RTM_none) || (rtm_mode == RTM_bind_or_copy)) { 01535 continue; 01536 } 01537 01538 Texture *texture = (*ri)._texture; 01539 PStatTimer timer(_copy_texture_pcollector); 01540 01541 if ((rtm_mode == RTM_copy_texture)|| 01542 (rtm_mode == RTM_copy_ram)|| 01543 ((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))|| 01544 ((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) { 01545 if (display_cat.is_debug()) { 01546 display_cat.debug() 01547 << "Copying texture for " << get_name() << " at frame end.\n"; 01548 display_cat.debug() 01549 << "cube_map_index = " << _cube_map_index << "\n"; 01550 } 01551 RenderTexturePlane plane = (*ri)._plane; 01552 RenderBuffer buffer(_gsg, DrawableRegion::get_renderbuffer_type(plane)); 01553 if (plane == RTP_color) { 01554 buffer = _gsg->get_render_buffer(get_draw_buffer_type(), 01555 get_fb_properties()); 01556 } 01557 01558 bool copied = false; 01559 if (_cube_map_dr != (DisplayRegion *)NULL) { 01560 if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) { 01561 copied = 01562 _gsg->framebuffer_copy_to_ram(texture, _cube_map_index, 01563 _cube_map_dr, buffer); 01564 } else { 01565 copied = 01566 _gsg->framebuffer_copy_to_texture(texture, _cube_map_index, 01567 _cube_map_dr, buffer); 01568 } 01569 } else { 01570 if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) { 01571 copied = 01572 _gsg->framebuffer_copy_to_ram(texture, _cube_map_index, 01573 _overlay_display_region, buffer); 01574 } else { 01575 copied = 01576 _gsg->framebuffer_copy_to_texture(texture, _cube_map_index, 01577 _overlay_display_region, buffer); 01578 } 01579 } 01580 if (!copied) { 01581 okflag = false; 01582 } 01583 } 01584 } 01585 _trigger_copy = false; 01586 01587 return okflag; 01588 } 01589 01590 //////////////////////////////////////////////////////////////////// 01591 // Function: GraphicsOuput::create_texture_card_vdata 01592 // Access: Private 01593 // Description: Generates a GeomVertexData for a texture card. 01594 //////////////////////////////////////////////////////////////////// 01595 PT(GeomVertexData) GraphicsOutput:: 01596 create_texture_card_vdata(int x, int y) { 01597 PN_stdfloat xhi = 1.0; 01598 PN_stdfloat yhi = 1.0; 01599 01600 if (Texture::get_textures_power_2() != ATS_none) { 01601 int xru = Texture::up_to_power_2(x); 01602 int yru = Texture::up_to_power_2(y); 01603 xhi = (x * 1.0f) / xru; 01604 yhi = (y * 1.0f) / yru; 01605 } 01606 01607 CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3n3t2(); 01608 01609 PT(GeomVertexData) vdata = new GeomVertexData 01610 ("card", format, Geom::UH_static); 01611 01612 GeomVertexWriter vertex(vdata, InternalName::get_vertex()); 01613 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord()); 01614 GeomVertexWriter normal(vdata, InternalName::get_normal()); 01615 01616 vertex.add_data3(LVertex::rfu(-1.0f, 0.0f, 1.0f)); 01617 vertex.add_data3(LVertex::rfu(-1.0f, 0.0f, -1.0f)); 01618 vertex.add_data3(LVertex::rfu( 1.0f, 0.0f, 1.0f)); 01619 vertex.add_data3(LVertex::rfu( 1.0f, 0.0f, -1.0f)); 01620 01621 texcoord.add_data2( 0.0f, yhi); 01622 texcoord.add_data2( 0.0f, 0.0f); 01623 texcoord.add_data2( xhi, yhi); 01624 texcoord.add_data2( xhi, 0.0f); 01625 01626 normal.add_data3(LVector3::back()); 01627 normal.add_data3(LVector3::back()); 01628 normal.add_data3(LVector3::back()); 01629 normal.add_data3(LVector3::back()); 01630 01631 return vdata; 01632 } 01633 01634 //////////////////////////////////////////////////////////////////// 01635 // Function: GraphicsOutput::add_display_region 01636 // Access: Private 01637 // Description: Called by the DisplayRegion constructor to 01638 // add the new DisplayRegion to the list. 01639 //////////////////////////////////////////////////////////////////// 01640 DisplayRegion *GraphicsOutput:: 01641 add_display_region(DisplayRegion *display_region) { 01642 LightMutexHolder holder(_lock); 01643 CDWriter cdata(_cycler, true); 01644 cdata->_active_display_regions_stale = true; 01645 01646 _total_display_regions.push_back(display_region); 01647 01648 return display_region; 01649 } 01650 01651 //////////////////////////////////////////////////////////////////// 01652 // Function: GraphicsOutput::do_remove_display_region 01653 // Access: Private 01654 // Description: Internal implementation of remove_display_region. 01655 // Assumes the lock is already held. 01656 //////////////////////////////////////////////////////////////////// 01657 bool GraphicsOutput:: 01658 do_remove_display_region(DisplayRegion *display_region) { 01659 nassertr(display_region != _overlay_display_region, false); 01660 01661 PT(DisplayRegion) drp = display_region; 01662 TotalDisplayRegions::iterator dri = 01663 find(_total_display_regions.begin(), _total_display_regions.end(), drp); 01664 if (dri != _total_display_regions.end()) { 01665 // Let's aggressively clean up the display region too. 01666 CDWriter cdata(_cycler, true); 01667 display_region->cleanup(); 01668 display_region->_window = NULL; 01669 _total_display_regions.erase(dri); 01670 01671 cdata->_active_display_regions_stale = true; 01672 01673 return true; 01674 } 01675 01676 return false; 01677 } 01678 01679 //////////////////////////////////////////////////////////////////// 01680 // Function: GraphicsOutput::do_determine_display_regions 01681 // Access: Private 01682 // Description: Re-sorts the list of active DisplayRegions within 01683 // the window. 01684 //////////////////////////////////////////////////////////////////// 01685 void GraphicsOutput:: 01686 do_determine_display_regions(GraphicsOutput::CData *cdata) { 01687 cdata->_active_display_regions_stale = false; 01688 01689 cdata->_active_display_regions.clear(); 01690 cdata->_active_display_regions.reserve(_total_display_regions.size()); 01691 01692 int index = 0; 01693 TotalDisplayRegions::const_iterator dri; 01694 for (dri = _total_display_regions.begin(); 01695 dri != _total_display_regions.end(); 01696 ++dri) { 01697 DisplayRegion *display_region = (*dri); 01698 if (display_region->is_active()) { 01699 cdata->_active_display_regions.push_back(display_region); 01700 display_region->set_active_index(index); 01701 ++index; 01702 } else { 01703 display_region->set_active_index(-1); 01704 } 01705 } 01706 01707 stable_sort(cdata->_active_display_regions.begin(), cdata->_active_display_regions.end(), IndirectLess<DisplayRegion>()); 01708 } 01709 01710 //////////////////////////////////////////////////////////////////// 01711 // Function: GraphicsOutput::parse_color_mask 01712 // Access: Private, Static 01713 // Description: Parses one of the keywords in the 01714 // red-blue-stereo-colors Config.prc variable, and 01715 // returns the corresponding bitmask. 01716 // 01717 // These bitmask values are taken from ColorWriteAttrib. 01718 //////////////////////////////////////////////////////////////////// 01719 unsigned int GraphicsOutput:: 01720 parse_color_mask(const string &word) { 01721 unsigned int result = 0; 01722 vector_string components; 01723 tokenize(word, components, "|"); 01724 01725 vector_string::const_iterator ci; 01726 for (ci = components.begin(); ci != components.end(); ++ci) { 01727 string w = downcase(*ci); 01728 if (w == "red" || w == "r") { 01729 result |= 0x001; 01730 01731 } else if (w == "green" || w == "g") { 01732 result |= 0x002; 01733 01734 } else if (w == "blue" || w == "b") { 01735 result |= 0x004; 01736 01737 } else if (w == "yellow" || w == "y") { 01738 result |= 0x003; 01739 01740 } else if (w == "magenta" || w == "m") { 01741 result |= 0x005; 01742 01743 } else if (w == "cyan" || w == "c") { 01744 result |= 0x006; 01745 01746 } else if (w == "alpha" || w == "a") { 01747 result |= 0x008; 01748 01749 } else if (w == "off") { 01750 01751 } else { 01752 display_cat.warning() 01753 << "Invalid color in red-blue-stereo-colors: " << (*ci) << "\n"; 01754 } 01755 } 01756 01757 return result; 01758 } 01759 01760 //////////////////////////////////////////////////////////////////// 01761 // Function: GraphicsOutput::CData::Constructor 01762 // Access: Public 01763 // Description: 01764 //////////////////////////////////////////////////////////////////// 01765 GraphicsOutput::CData:: 01766 CData() { 01767 // The default is *not* active, so the entire pipeline stage is 01768 // initially populated with inactive outputs. Pipeline stage 0 is 01769 // set to active in the constructor. 01770 _active = false; 01771 _one_shot_frame = -1; 01772 _active_display_regions_stale = false; 01773 } 01774 01775 //////////////////////////////////////////////////////////////////// 01776 // Function: GraphicsOutput::CData::Constructor 01777 // Access: Public 01778 // Description: 01779 //////////////////////////////////////////////////////////////////// 01780 GraphicsOutput::CData:: 01781 CData(const GraphicsOutput::CData ©) : 01782 _textures(copy._textures), 01783 _active(copy._active), 01784 _one_shot_frame(copy._one_shot_frame), 01785 _active_display_regions(copy._active_display_regions), 01786 _active_display_regions_stale(copy._active_display_regions_stale) 01787 { 01788 } 01789 01790 //////////////////////////////////////////////////////////////////// 01791 // Function: GraphicsOutput::CData::make_copy 01792 // Access: Public, Virtual 01793 // Description: 01794 //////////////////////////////////////////////////////////////////// 01795 CycleData *GraphicsOutput::CData:: 01796 make_copy() const { 01797 return new CData(*this); 01798 } 01799 01800 //////////////////////////////////////////////////////////////////// 01801 // Function: GraphicsOutput::FrameMode output operator 01802 // Description: 01803 //////////////////////////////////////////////////////////////////// 01804 ostream & 01805 operator << (ostream &out, GraphicsOutput::FrameMode fm) { 01806 switch (fm) { 01807 case GraphicsOutput::FM_render: 01808 return out << "render"; 01809 case GraphicsOutput::FM_parasite: 01810 return out << "parasite"; 01811 case GraphicsOutput::FM_refresh: 01812 return out << "refresh"; 01813 } 01814 01815 return out << "(**invalid GraphicsOutput::FrameMode(" << (int)fm << ")**)"; 01816 }