Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/display/graphicsWindow.cxx

Go to the documentation of this file.
00001 // Filename: graphicsWindow.cxx
00002 // Created by:  mike (09Jan97)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "graphicsWindow.h"
00020 #include "graphicsPipe.h"
00021 #include "config_display.h"
00022 #include "mouseButton.h"
00023 #include "keyboardButton.h"
00024 #include "mutexHolder.h"
00025 #include "hardwareChannel.h"
00026 #include "throw_event.h"
00027 
00028 #include "pmap.h"
00029 
00030 TypeHandle GraphicsWindow::_type_handle;
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: GraphicsWindow::Constructor
00034 //       Access: Protected
00035 //  Description: Normally, the GraphicsWindow constructor is not
00036 //               called directly; these are created instead via the
00037 //               GraphicsEngine::make_window() function.
00038 ////////////////////////////////////////////////////////////////////
00039 GraphicsWindow::
00040 GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) {
00041 #ifdef DO_MEMORY_USAGE
00042   MemoryUsage::update_type(this, this);
00043 #endif
00044   _pipe = pipe;
00045   _gsg = gsg;
00046 
00047   // Some default properties for windows unless specified otherwise.
00048   // Other properties (size, title, etc.) must be explicitly
00049   // specified.
00050   _properties.set_open(false);
00051   _properties.set_undecorated(false);
00052   _properties.set_fullscreen(false);
00053   _properties.set_minimized(false);
00054   _properties.set_cursor_hidden(false);
00055 
00056   _display_regions_stale = false;
00057   _window_event = "window-event";
00058 
00059   // By default, windows are set up to clear color and depth.
00060   set_clear_color_active(true);
00061   set_clear_depth_active(true);
00062 }
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: GraphicsWindow::Copy Constructor
00066 //       Access: Private
00067 //  Description:
00068 ////////////////////////////////////////////////////////////////////
00069 GraphicsWindow::
00070 GraphicsWindow(const GraphicsWindow &) {
00071   nassertv(false);
00072 }
00073 
00074 ////////////////////////////////////////////////////////////////////
00075 //     Function: GraphicsWindow::Copy Assignment Operator
00076 //       Access: Private
00077 //  Description:
00078 ////////////////////////////////////////////////////////////////////
00079 void GraphicsWindow::
00080 operator = (const GraphicsWindow &) {
00081   nassertv(false);
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: GraphicsWindow::Destructor
00086 //       Access: Published, Virtual
00087 //  Description:
00088 ////////////////////////////////////////////////////////////////////
00089 GraphicsWindow::
00090 ~GraphicsWindow() {
00091   // The window should be closed by the time we destruct.
00092   nassertv(!_properties.get_open());
00093 
00094   // And we shouldn't have a GraphicsPipe pointer anymore.
00095   nassertv(_pipe == (GraphicsPipe *)NULL);
00096 
00097   // We don't have to destruct our child channels explicitly, since
00098   // they are all reference-counted and will go away when their
00099   // pointers do.  However, we do need to zero out their pointers to
00100   // us.
00101   Channels::iterator ci;
00102   for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
00103     (*ci)->_window = NULL;
00104   }
00105 }
00106 
00107 ////////////////////////////////////////////////////////////////////
00108 //     Function: GraphicsWindow::get_properties
00109 //       Access: Published
00110 //  Description: Returns the current properties of the window.
00111 ////////////////////////////////////////////////////////////////////
00112 WindowProperties GraphicsWindow::
00113 get_properties() const {
00114   WindowProperties result;
00115   {
00116     MutexHolder holder(_lock);
00117     result = _properties;
00118   }
00119   return result;
00120 }
00121 
00122 ////////////////////////////////////////////////////////////////////
00123 //     Function: GraphicsWindow::get_requested_properties
00124 //       Access: Published
00125 //  Description: Returns the properties of the window that are
00126 //               currently requested.  These properties will be
00127 //               applied to the window (if valid) at the next
00128 //               execution of process_events().
00129 ////////////////////////////////////////////////////////////////////
00130 WindowProperties GraphicsWindow::
00131 get_requested_properties() const {
00132   WindowProperties result;
00133   {
00134     MutexHolder holder(_lock);
00135     result = _requested_properties;
00136   }
00137   return result;
00138 }
00139 
00140 ////////////////////////////////////////////////////////////////////
00141 //     Function: GraphicsWindow::clear_rejected_properties
00142 //       Access: Published
00143 //  Description: Empties the set of failed properties that will be
00144 //               returned by get_rejected_properties().
00145 ////////////////////////////////////////////////////////////////////
00146 void GraphicsWindow::
00147 clear_rejected_properties() {
00148   MutexHolder holder(_lock);
00149   _rejected_properties.clear();
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: GraphicsWindow::get_rejected_properties
00154 //       Access: Published
00155 //  Description: Returns the set of properties that have recently been
00156 //               requested, but could not be applied to the window for
00157 //               some reason.  This set of properties will remain
00158 //               unchanged until they are changed by a new failed
00159 //               request, or clear_rejected_properties() is called.
00160 ////////////////////////////////////////////////////////////////////
00161 WindowProperties GraphicsWindow::
00162 get_rejected_properties() const {
00163   WindowProperties result;
00164   {
00165     MutexHolder holder(_lock);
00166     result = _rejected_properties;
00167   }
00168   return result;
00169 }
00170 
00171 ////////////////////////////////////////////////////////////////////
00172 //     Function: GraphicsWindow::request_properties
00173 //       Access: Published
00174 //  Description: Requests a property change on the window.  For
00175 //               example, use this method to request a window change
00176 //               size or minimize or something.
00177 //
00178 //               The change is not made immediately; rather, the
00179 //               request is saved and will be applied the next time
00180 //               the window task is run (probably at the next frame).
00181 ////////////////////////////////////////////////////////////////////
00182 void GraphicsWindow::
00183 request_properties(const WindowProperties &requested_properties) {
00184   MutexHolder holder(_lock);
00185   _requested_properties.add_properties(requested_properties);
00186 }
00187 
00188 ////////////////////////////////////////////////////////////////////
00189 //     Function: GraphicsWindow::set_window_event
00190 //       Access: Published
00191 //  Description: Changes the name of the event that is generated when
00192 //               this window is modified externally, e.g. to be
00193 //               resized or closed by the user.
00194 //
00195 //               By default, all windows have the same window event
00196 //               unless they are explicitly changed.  When the event
00197 //               is generated, it includes one parameter: the window
00198 //               itself.
00199 ////////////////////////////////////////////////////////////////////
00200 void GraphicsWindow::
00201 set_window_event(const string &window_event) {
00202   MutexHolder holder(_lock);
00203   _window_event = window_event;
00204 }
00205 
00206 ////////////////////////////////////////////////////////////////////
00207 //     Function: GraphicsWindow::get_window_event
00208 //       Access: Published
00209 //  Description: Returns the name of the event that is generated when
00210 //               this window is modified externally, e.g. to be
00211 //               resized or closed by the user.  See set_window_event().
00212 ////////////////////////////////////////////////////////////////////
00213 string GraphicsWindow::
00214 get_window_event() const {
00215   string result;
00216   MutexHolder holder(_lock);
00217   result = _window_event;
00218   return result;
00219 }
00220 
00221 
00222 ////////////////////////////////////////////////////////////////////
00223 //     Function: GraphicsWindow::get_channel
00224 //       Access: Public
00225 //  Description: Returns a GraphicsChannel pointer that can be used to
00226 //               access the indicated channel number.  All windows
00227 //               have at least one channel, channel 0, which
00228 //               corresponds to the entire window.  If the hardware
00229 //               supports it, some kinds of windows may also have a
00230 //               number of hardware channels available at indices
00231 //               1..n, which will correspond to a subregion of the
00232 //               window.
00233 //
00234 //               This function returns a GraphicsChannel pointer if a
00235 //               channel is available, or NULL if it is not.  If
00236 //               called twice with the same index number, it will
00237 //               return the same pointer.
00238 ////////////////////////////////////////////////////////////////////
00239 GraphicsChannel *GraphicsWindow::
00240 get_channel(int index) {
00241   MutexHolder holder(_lock);
00242   nassertr(index >= 0, NULL);
00243 
00244   if (index < (int)_channels.size()) {
00245     if (_channels[index] != (GraphicsChannel *)NULL) {
00246       return _channels[index];
00247     }
00248   }
00249 
00250   // This channel has never been requested before; define it.
00251 
00252   PT(GraphicsChannel) chan;
00253   if (index == 0) {
00254     // Channel 0 is the default channel: the entire screen.
00255     chan = new GraphicsChannel(this);
00256   } else {
00257     // Any other channel is some hardware-specific channel.
00258     GraphicsPipe *pipe = _pipe;
00259     if (pipe != (GraphicsPipe *)NULL) {
00260       chan = _pipe->get_hw_channel(this, index);
00261       if (chan == (GraphicsChannel *)NULL) {
00262         display_cat.error()
00263           << "GraphicsWindow::get_channel() - got a NULL channel" << endl;
00264       } else {
00265         if (chan->get_window() != this) {
00266           chan = NULL;
00267         }
00268       }
00269     }
00270   }
00271 
00272   if (chan != (GraphicsChannel *)NULL) {
00273     declare_channel(index, chan);
00274   }
00275 
00276   return chan;
00277 }
00278 
00279 ////////////////////////////////////////////////////////////////////
00280 //     Function: GraphicsWindow::remove_channel
00281 //       Access: Public
00282 //  Description: Deletes a GraphicsChannel that was previously created
00283 //               via a call to get_channel().  Note that the channel
00284 //               is not actually deleted until all pointers to it are
00285 //               cleared.
00286 ////////////////////////////////////////////////////////////////////
00287 void GraphicsWindow::
00288 remove_channel(int index) {
00289   MutexHolder holder(_lock);
00290   if (index >= 0 && index < (int)_channels.size()) {
00291     _channels[index].clear();
00292   }
00293 }
00294 
00295 ////////////////////////////////////////////////////////////////////
00296 //     Function: GraphicsWindow::get_max_channel_index
00297 //       Access: Public
00298 //  Description: Returns the largest channel index number yet created,
00299 //               plus 1.  All channels associated with this window
00300 //               will have an index number in the range [0,
00301 //               get_max_channel_index()).  This function, in
00302 //               conjunction with is_channel_defined(), below, may be
00303 //               used to determine the complete set of channels
00304 //               associated with the window.
00305 ////////////////////////////////////////////////////////////////////
00306 int GraphicsWindow::
00307 get_max_channel_index() const {
00308   int result;
00309   {
00310     MutexHolder holder(_lock);
00311     result = _channels.size();
00312   }
00313   return result;
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: GraphicsWindow::is_channel_defined
00318 //       Access: Public
00319 //  Description: Returns true if the channel with the given index
00320 //               number has already been defined, false if it hasn't.
00321 //               If this returns true, calling get_channel() on the
00322 //               given index number will return the channel pointer.
00323 //               If it returns false, calling get_channel() will
00324 //               create and return a new channel pointer.
00325 ////////////////////////////////////////////////////////////////////
00326 bool GraphicsWindow::
00327 is_channel_defined(int index) const {
00328   bool result;
00329   {
00330     MutexHolder holder(_lock);
00331     if (index < 0 || index >= (int)_channels.size()) {
00332       result = false;
00333     } else {
00334       result = (_channels[index] != (GraphicsChannel *)NULL);
00335     }
00336   }
00337   return result;
00338 }
00339 
00340 ////////////////////////////////////////////////////////////////////
00341 //     Function: GraphicsWindow::get_num_display_regions
00342 //       Access: Published
00343 //  Description: Returns the number of active DisplayRegions that have
00344 //               been created within the various layers and channels
00345 //               of the window.
00346 ////////////////////////////////////////////////////////////////////
00347 int GraphicsWindow::
00348 get_num_display_regions() const {
00349   determine_display_regions();
00350   int result;
00351   {
00352     MutexHolder holder(_lock);
00353     result = _display_regions.size();
00354   }
00355   return result;
00356 }
00357 
00358 ////////////////////////////////////////////////////////////////////
00359 //     Function: GraphicsWindow::get_display_region
00360 //       Access: Published
00361 //  Description: Returns the nth active DisplayRegion of those that
00362 //               have been created within the various layers and
00363 //               channels of the window.  This may return NULL if n is
00364 //               out of bounds; particularly likely if the number of
00365 //               display regions has changed since the last call to
00366 //               get_num_display_regions().
00367 ////////////////////////////////////////////////////////////////////
00368 DisplayRegion *GraphicsWindow::
00369 get_display_region(int n) const {
00370   determine_display_regions();
00371   DisplayRegion *result;
00372   {
00373     MutexHolder holder(_lock);
00374     if (n >= 0 && n < (int)_display_regions.size()) {
00375       result = _display_regions[n];
00376     } else {
00377       result = NULL;
00378     }
00379   }
00380   return result;
00381 }
00382 
00383 ////////////////////////////////////////////////////////////////////
00384 //     Function: GraphicsWindow::get_num_input_devices
00385 //       Access: Published
00386 //  Description: Returns the number of separate input devices
00387 //               associated with the window.  Typically, a window will
00388 //               have exactly one input device: the keyboard/mouse
00389 //               pair.  However, some windows may have no input
00390 //               devices, and others may add additional devices, for
00391 //               instance for a joystick.
00392 ////////////////////////////////////////////////////////////////////
00393 int GraphicsWindow::
00394 get_num_input_devices() const {
00395   int result;
00396   {
00397     MutexHolder holder(_input_lock);
00398     result = _input_devices.size();
00399   }
00400   return result;
00401 }
00402 
00403 ////////////////////////////////////////////////////////////////////
00404 //     Function: GraphicsWindow::get_input_device_name
00405 //       Access: Published
00406 //  Description: Returns the name of the nth input device.
00407 ////////////////////////////////////////////////////////////////////
00408 string GraphicsWindow::
00409 get_input_device_name(int device) const {
00410   string result;
00411   {
00412     MutexHolder holder(_input_lock);
00413     nassertr(device >= 0 && device < (int)_input_devices.size(), "");
00414     result = _input_devices[device].get_name();
00415   }
00416   return result;
00417 }
00418 
00419 ////////////////////////////////////////////////////////////////////
00420 //     Function: GraphicsWindow::has_pointer
00421 //       Access: Published
00422 //  Description: Returns true if the nth input device has a
00423 //               screen-space pointer (for instance, a mouse), false
00424 //               otherwise.
00425 ////////////////////////////////////////////////////////////////////
00426 bool GraphicsWindow::
00427 has_pointer(int device) const {
00428   bool result;
00429   {
00430     MutexHolder holder(_input_lock);
00431     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
00432     result = _input_devices[device].has_pointer();
00433   }
00434   return result;
00435 }
00436 
00437 ////////////////////////////////////////////////////////////////////
00438 //     Function: GraphicsWindow::has_keyboard
00439 //       Access: Published
00440 //  Description: Returns true if the nth input device has a keyboard,
00441 //               false otherwise.
00442 ////////////////////////////////////////////////////////////////////
00443 bool GraphicsWindow::
00444 has_keyboard(int device) const {
00445   bool result;
00446   {
00447     MutexHolder holder(_input_lock);
00448     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
00449     result = _input_devices[device].has_keyboard();
00450   }
00451   return result;
00452 }
00453 
00454 ////////////////////////////////////////////////////////////////////
00455 //     Function: GraphicsWindow::get_mouse_data
00456 //       Access: Public
00457 //  Description: Returns the MouseData associated with the nth input
00458 //               device.
00459 ////////////////////////////////////////////////////////////////////
00460 MouseData GraphicsWindow::
00461 get_mouse_data(int device) const {
00462   MouseData result;
00463   {
00464     MutexHolder holder(_input_lock);
00465     nassertr(device >= 0 && device < (int)_input_devices.size(), MouseData());
00466     result = _input_devices[device].get_mouse_data();
00467   }
00468   return result;
00469 }
00470 
00471 ////////////////////////////////////////////////////////////////////
00472 //     Function: GraphicsWindow::has_button_event
00473 //       Access: Public
00474 //  Description: Returns true if the indicated device has a pending
00475 //               button event (a mouse button or keyboard button
00476 //               down/up), false otherwise.  If this returns true, the
00477 //               particular event may be extracted via
00478 //               get_button_event().
00479 ////////////////////////////////////////////////////////////////////
00480 bool GraphicsWindow::
00481 has_button_event(int device) const {
00482   bool result;
00483   {
00484     MutexHolder holder(_input_lock);
00485     nassertr(device >= 0 && device < (int)_input_devices.size(), false);
00486     result = _input_devices[device].has_button_event();
00487   }
00488   return result;
00489 }
00490 
00491 ////////////////////////////////////////////////////////////////////
00492 //     Function: GraphicsWindow::get_button_event
00493 //       Access: Public
00494 //  Description: Assuming a previous call to has_button_event()
00495 //               returned true, this returns the pending button event.
00496 ////////////////////////////////////////////////////////////////////
00497 ButtonEvent GraphicsWindow::
00498 get_button_event(int device) {
00499   ButtonEvent result;
00500   {
00501     MutexHolder holder(_input_lock);
00502     nassertr(device >= 0 && device < (int)_input_devices.size(), ButtonEvent());
00503     nassertr(_input_devices[device].has_button_event(), ButtonEvent());
00504     result = _input_devices[device].get_button_event();
00505   }
00506   return result;
00507 }
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: GraphicsWindow::verify_window_sizes
00511 //       Access: Public, Virtual
00512 //  Description: Determines which of the indicated window sizes are
00513 //               supported by available hardware (e.g. in fullscreen
00514 //               mode).
00515 //
00516 //               On entry, dimen is an array containing contiguous x,y
00517 //               pairs specifying possible display sizes; it is
00518 //               numsizes*2 words long.  The function will zero out
00519 //               any invalid x,y size pairs.  The return value is the
00520 //               number of valid sizes that were found.
00521 //
00522 //               Note this doesn't guarantee a resize attempt will
00523 //               work; you still need to check the return value.
00524 //
00525 //               (It might be better to implement some sort of query
00526 //               interface that returns an array of supported sizes,
00527 //               but this way is somewhat simpler and will do the job
00528 //               on most cards, assuming they handle the std sizes the
00529 //               app knows about.)
00530 ////////////////////////////////////////////////////////////////////
00531 int GraphicsWindow::
00532 verify_window_sizes(int numsizes, int *dimen) {
00533   return numsizes;
00534 }
00535 
00536 ////////////////////////////////////////////////////////////////////
00537 //     Function: GraphicsWindow::make_scratch_display_region
00538 //       Access: Public
00539 //  Description: Allocates and returns a temporary DisplayRegion that
00540 //               may be used to render offscreen into.  This
00541 //               DisplayRegion is not associated with any layer.
00542 //
00543 //               To allocate a normal DisplayRegion for rendering, use
00544 //               the interface provided in GraphicsLayer.
00545 ////////////////////////////////////////////////////////////////////
00546 PT(DisplayRegion) GraphicsWindow::
00547 make_scratch_display_region(int x_size, int y_size) const {
00548 #ifndef NDEBUG
00549   {
00550     MutexHolder holder(_lock);
00551     if (x_size > _properties.get_x_size() || 
00552         y_size > _properties.get_y_size()) {
00553       display_cat.error()
00554         << "make_scratch_display_region(): requested region of size " 
00555         << x_size << ", " << y_size << " is larger than window of size "
00556         << _properties.get_x_size() << ", " << _properties.get_y_size()
00557         << ".\n";
00558       x_size = min(x_size, _properties.get_x_size());
00559       y_size = min(y_size, _properties.get_y_size());
00560     }
00561   }
00562 #endif
00563 
00564   PT(DisplayRegion) region = new DisplayRegion(x_size, y_size);
00565   region->copy_clear_settings(*this);
00566   return region;
00567 }
00568  
00569 ////////////////////////////////////////////////////////////////////
00570 //     Function: GraphicsWindow::begin_frame
00571 //       Access: Public, Virtual
00572 //  Description: This function will be called within the draw thread
00573 //               before beginning rendering for a given frame.  It
00574 //               should do whatever setup is required, and return true
00575 //               if the frame should be rendered, or false if it
00576 //               should be skipped.
00577 ////////////////////////////////////////////////////////////////////
00578 bool GraphicsWindow::
00579 begin_frame() {
00580   if (_gsg == (GraphicsStateGuardian *)NULL) {
00581     return false;
00582   }
00583 
00584   // Okay, we already have a GSG, so activate it.
00585   make_current();
00586   return _gsg->begin_frame();
00587 }
00588 
00589 ////////////////////////////////////////////////////////////////////
00590 //     Function: GraphicsWindow::clear
00591 //       Access: Public
00592 //  Description: Clears the entire framebuffer before rendering,
00593 //               according to the settings of get_color_clear_active()
00594 //               and get_depth_clear_active() (inherited from
00595 //               ClearableRegion).
00596 //
00597 //               This function is called only within the draw thread.
00598 ////////////////////////////////////////////////////////////////////
00599 void GraphicsWindow::
00600 clear() {
00601   if (is_any_clear_active()) {
00602     nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00603 
00604     int x_size, y_size;
00605     {
00606       MutexHolder holder(_lock);
00607       x_size = _properties.get_x_size();
00608       y_size = _properties.get_y_size();
00609     }
00610     PT(DisplayRegion) win_dr =
00611       make_scratch_display_region(x_size, y_size);
00612     DisplayRegionStack old_dr = _gsg->push_display_region(win_dr);
00613     _gsg->clear(this);
00614     _gsg->pop_display_region(old_dr);
00615   }
00616 }
00617 
00618 ////////////////////////////////////////////////////////////////////
00619 //     Function: GraphicsWindow::end_frame
00620 //       Access: Public, Virtual
00621 //  Description: This function will be called within the draw thread
00622 //               after rendering is completed for a given frame.  It
00623 //               should do whatever finalization is required.
00624 ////////////////////////////////////////////////////////////////////
00625 void GraphicsWindow::
00626 end_frame() {
00627   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00628   _gsg->end_frame();
00629 }
00630 
00631 ////////////////////////////////////////////////////////////////////
00632 //     Function: GraphicsWindow::make_current
00633 //       Access: Public, Virtual
00634 //  Description: This function will be called within the draw thread
00635 //               during begin_frame() to ensure the graphics context
00636 //               is ready for drawing.
00637 ////////////////////////////////////////////////////////////////////
00638 void GraphicsWindow::
00639 make_current() {
00640 }
00641 
00642 ////////////////////////////////////////////////////////////////////
00643 //     Function: GraphicsWindow::release_gsg
00644 //       Access: Public
00645 //  Description: Releases the current GSG pointer, if it is currently
00646 //               held, and resets the GSG to NULL.  The window will be
00647 //               permanently unable to render; this is normally called
00648 //               only just before destroying the window.  This should
00649 //               only be called from within the draw thread.
00650 ////////////////////////////////////////////////////////////////////
00651 void GraphicsWindow::
00652 release_gsg() {
00653   _gsg.clear();
00654 }
00655 
00656 ////////////////////////////////////////////////////////////////////
00657 //     Function: GraphicsWindow::begin_flip
00658 //       Access: Public, Virtual
00659 //  Description: This function will be called within the draw thread
00660 //               after end_frame() has been called on all windows, to
00661 //               initiate the exchange of the front and back buffers.
00662 //
00663 //               This should instruct the window to prepare for the
00664 //               flip at the next video sync, but it should not wait.
00665 //
00666 //               We have the two separate functions, begin_flip() and
00667 //               end_flip(), to make it easier to flip all of the
00668 //               windows at the same time.
00669 ////////////////////////////////////////////////////////////////////
00670 void GraphicsWindow::
00671 begin_flip() {
00672 }
00673 
00674 ////////////////////////////////////////////////////////////////////
00675 //     Function: GraphicsWindow::end_flip
00676 //       Access: Public, Virtual
00677 //  Description: This function will be called within the draw thread
00678 //               after begin_flip() has been called on all windows, to
00679 //               finish the exchange of the front and back buffers.
00680 //
00681 //               This should cause the window to wait for the flip, if
00682 //               necessary.
00683 ////////////////////////////////////////////////////////////////////
00684 void GraphicsWindow::
00685 end_flip() {
00686 }
00687 
00688 ////////////////////////////////////////////////////////////////////
00689 //     Function: GraphicsWindow::process_events
00690 //       Access: Public, Virtual
00691 //  Description: Do whatever processing is necessary to ensure that
00692 //               the window responds to user events.  Also, honor any
00693 //               requests recently made via request_properties().
00694 //
00695 //               This function is called only within the window
00696 //               thread.
00697 ////////////////////////////////////////////////////////////////////
00698 void GraphicsWindow::
00699 process_events() {
00700   if (_requested_properties.is_any_specified()) {
00701     // We don't bother to grab the mutex until after we have already
00702     // checked whether any properties have been specified.  This is
00703     // technically sloppy, but it ought to be o.k. since it's just a
00704     // bitmask after all.
00705     WindowProperties properties;
00706     {
00707       MutexHolder holder(_lock);
00708       properties = _requested_properties;
00709       _requested_properties.clear();
00710 
00711       set_properties_now(properties);
00712       if (properties.is_any_specified()) {
00713         display_cat.info()
00714           << "Unable to set window properties: " << properties << "\n";
00715         _rejected_properties.add_properties(properties);
00716       }
00717     }
00718   }
00719 }
00720 
00721 ////////////////////////////////////////////////////////////////////
00722 //     Function: GraphicsWindow::set_properties_now
00723 //       Access: Public, Virtual
00724 //  Description: Applies the requested set of properties to the
00725 //               window, if possible, for instance to request a change
00726 //               in size or minimization status.
00727 //
00728 //               The window properties are applied immediately, rather
00729 //               than waiting until the next frame.  This implies that
00730 //               this method may *only* be called from within the
00731 //               window thread.
00732 //
00733 //               The properties that have been applied are cleared
00734 //               from the structure by this function; so on return,
00735 //               whatever remains in the properties structure are
00736 //               those that were unchanged for some reason (probably
00737 //               because the underlying interface does not support
00738 //               changing that property on an open window).
00739 ////////////////////////////////////////////////////////////////////
00740 void GraphicsWindow::
00741 set_properties_now(WindowProperties &properties) {
00742   if (properties.has_open() && 
00743       properties.get_open() != _properties.get_open()) {
00744     // Open or close a new window.  In this case we can get all of the
00745     // properties at once.
00746     _properties.add_properties(properties);
00747     properties.clear();
00748 
00749     if (_properties.get_open()) {
00750       if (open_window()) {
00751         // When the window is first opened, force its size to be
00752         // broadcast to its display regions.
00753         Channels::iterator ci;
00754         for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
00755           GraphicsChannel *chan = (*ci);
00756           chan->window_resized(_properties.get_x_size(), 
00757                                _properties.get_y_size());
00758         }
00759 
00760       } else {
00761         // Since we can't even open the window, tag the
00762         // _rejected_properties with all of the window properties that
00763         // failed.
00764         _rejected_properties.add_properties(_properties);
00765 
00766         // And mark the window closed.
00767         _properties.set_open(false);
00768       }
00769 
00770     } else {
00771       // We can't close the window if its GSG hasn't been released
00772       // yet.
00773       nassertv(_gsg == (GraphicsStateGuardian *)NULL);
00774       close_window();
00775     }
00776     return;
00777   }
00778 
00779   if (!_properties.get_open()) {
00780     // The window is not currently open; we can set properties at
00781     // will.
00782     _properties.add_properties(properties);
00783     properties.clear();
00784     return;
00785   }
00786 
00787   // The window is already open; we are limited to what we can change
00788   // on the fly.
00789 
00790   if (properties.has_size() || properties.has_origin()) {
00791     // Consider changing the window's size and/or position.
00792     WindowProperties reshape_props;
00793     if (properties.has_size()) {
00794       reshape_props.set_size(properties.get_x_size(), properties.get_y_size());
00795     } else {
00796       reshape_props.set_size(_properties.get_x_size(), _properties.get_y_size());
00797     }
00798     if (properties.has_origin() && !is_fullscreen()) {
00799       reshape_props.set_origin(properties.get_x_origin(), properties.get_y_origin());
00800     } else {
00801       reshape_props.set_origin(_properties.get_x_origin(), _properties.get_y_origin());
00802     }
00803     
00804     if (reshape_props.get_x_size() != _properties.get_x_size() ||
00805         reshape_props.get_y_size() != _properties.get_y_size() ||
00806         reshape_props.get_x_origin() != _properties.get_x_origin() ||
00807         reshape_props.get_y_origin() != _properties.get_y_origin()) {
00808       if (do_reshape_request(reshape_props.get_x_origin(),
00809                              reshape_props.get_y_origin(),
00810                              reshape_props.get_x_size(),
00811                              reshape_props.get_y_size())) {
00812         system_changed_size(reshape_props.get_x_size(), 
00813                             reshape_props.get_y_size());
00814         _properties.add_properties(reshape_props);
00815         properties.clear_size();
00816         properties.clear_origin();
00817       }
00818     }
00819   }
00820 
00821   if (properties.has_fullscreen() && 
00822       properties.get_fullscreen() == _properties.get_fullscreen()) {
00823     // Fullscreen property specified, but unchanged.
00824     properties.clear_fullscreen();
00825   }
00826 }
00827 
00828 ////////////////////////////////////////////////////////////////////
00829 //     Function: GraphicsWindow::close_window
00830 //       Access: Protected, Virtual
00831 //  Description: Closes the window right now.  Called from the window
00832 //               thread.
00833 ////////////////////////////////////////////////////////////////////
00834 void GraphicsWindow::
00835 close_window() {
00836 }
00837 
00838 ////////////////////////////////////////////////////////////////////
00839 //     Function: GraphicsWindow::open_window
00840 //       Access: Protected, Virtual
00841 //  Description: Opens the window right now.  Called from the window
00842 //               thread.  Returns true if the window is successfully
00843 //               opened, or false if there was a problem.
00844 ////////////////////////////////////////////////////////////////////
00845 bool GraphicsWindow::
00846 open_window() {
00847   return false;
00848 }
00849 
00850 ////////////////////////////////////////////////////////////////////
00851 //     Function: GraphicsWindow::open_window
00852 //       Access: Protected, Virtual
00853 //  Description: Called from the window thread in response to a request
00854 //               from within the code (via request_properties()) to
00855 //               change the size and/or position of the window.
00856 //               Returns true if the window is successfully changed,
00857 //               or false if there was a problem.
00858 ////////////////////////////////////////////////////////////////////
00859 bool GraphicsWindow::
00860 do_reshape_request(int x_origin, int y_origin, int x_size, int y_size) {
00861   return false;
00862 }
00863 
00864 ////////////////////////////////////////////////////////////////////
00865 //     Function: GraphicsWindow::system_changed_properties
00866 //       Access: Protected
00867 //  Description: Should be called (from within the window thread) when
00868 //               process_events() detects an external change in some
00869 //               important window property; for instance, when the
00870 //               user resizes the window.
00871 ////////////////////////////////////////////////////////////////////
00872 void GraphicsWindow::
00873 system_changed_properties(const WindowProperties &properties) {
00874   MutexHolder holder(_lock);
00875 
00876   if (properties.has_size()) {
00877     system_changed_size(properties.get_x_size(), properties.get_y_size());
00878   }
00879 
00880   WindowProperties old_properties = _properties;
00881   _properties.add_properties(properties);
00882   if (_properties != old_properties) {
00883     throw_event(_window_event, this);
00884   }
00885 }
00886 
00887 ////////////////////////////////////////////////////////////////////
00888 //     Function: GraphicsWindow::system_changed_size
00889 //       Access: Protected
00890 //  Description: An internal function to update all the channels with
00891 //               the new size of the window.  This should always be
00892 //               called before changing the _size members of the
00893 //               _properties structure.
00894 ////////////////////////////////////////////////////////////////////
00895 void GraphicsWindow::
00896 system_changed_size(int x_size, int y_size) {
00897   if (x_size != _properties.get_x_size() || 
00898       y_size != _properties.get_y_size()) {
00899     Channels::iterator ci;
00900     for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
00901       GraphicsChannel *chan = (*ci);
00902       chan->window_resized(x_size, y_size);
00903     }
00904   }
00905 }
00906 
00907 ////////////////////////////////////////////////////////////////////
00908 //     Function: GraphicsWindow::declare_channel
00909 //       Access: Protected
00910 //  Description: An internal function to add the indicated
00911 //               newly-created channel to the list at the indicated
00912 //               channel number.
00913 //
00914 //               The caller must grab and hold _lock before making
00915 //               this call.
00916 ////////////////////////////////////////////////////////////////////
00917 void GraphicsWindow::
00918 declare_channel(int index, GraphicsChannel *chan) {
00919   nassertv(index >= 0);
00920   if (index >= (int)_channels.size()) {
00921     _channels.reserve(index);
00922     while (index >= (int)_channels.size()) {
00923       _channels.push_back(NULL);
00924     }
00925   }
00926 
00927   nassertv(index < (int)_channels.size());
00928   _channels[index] = chan;
00929 }
00930 
00931 ////////////////////////////////////////////////////////////////////
00932 //     Function: GraphicsWindow::do_determine_display_regions
00933 //       Access: Private
00934 //  Description: Recomputes the list of active DisplayRegions within
00935 //               the window.
00936 ////////////////////////////////////////////////////////////////////
00937 void GraphicsWindow::
00938 do_determine_display_regions() {
00939   MutexHolder holder(_lock);
00940   _display_regions_stale = false;
00941   _display_regions.clear();
00942   Channels::const_iterator ci;
00943   for (ci = _channels.begin(); ci != _channels.end(); ++ci) {
00944     GraphicsChannel *chan = (*ci);
00945     if (chan->is_active()) {
00946       GraphicsChannel::GraphicsLayers::const_iterator li;
00947       for (li = chan->_layers.begin(); li != chan->_layers.end(); ++li) {
00948         GraphicsLayer *layer = (*li);
00949         if (layer->is_active()) {
00950           GraphicsLayer::DisplayRegions::const_iterator dri;
00951           for (dri = layer->_display_regions.begin(); 
00952                dri != layer->_display_regions.end(); 
00953                ++dri) {
00954             DisplayRegion *dr = (*dri);
00955             if (dr->is_active()) {
00956               _display_regions.push_back(dr);
00957             }
00958           }
00959         }
00960       }
00961     }
00962   }
00963 }

Generated on Fri May 2 00:36:32 2003 for Panda by doxygen1.3