wglGraphicsWindow.cxx

00001 // Filename: wglGraphicsWindow.cxx
00002 // Created by:  drose (20Dec02)
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 "wglGraphicsWindow.h"
00016 #include "config_wgldisplay.h"
00017 #include "config_windisplay.h"
00018 #include "wglGraphicsPipe.h"
00019 #include "pStatTimer.h"
00020 #include "glgsg.h"
00021 
00022 #include <wingdi.h>
00023 
00024 TypeHandle wglGraphicsWindow::_type_handle;
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: wglGraphicsWindow::Constructor
00028 //       Access: Public
00029 //  Description:
00030 ////////////////////////////////////////////////////////////////////
00031 wglGraphicsWindow::
00032 wglGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, 
00033                   const string &name,
00034                   const FrameBufferProperties &fb_prop,
00035                   const WindowProperties &win_prop,
00036                   int flags,
00037                   GraphicsStateGuardian *gsg,
00038                   GraphicsOutput *host) :
00039   WinGraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
00040 {
00041   _hdc = (HDC)0;
00042 }
00043 
00044 ////////////////////////////////////////////////////////////////////
00045 //     Function: wglGraphicsWindow::Destructor
00046 //       Access: Public, Virtual
00047 //  Description:
00048 ////////////////////////////////////////////////////////////////////
00049 wglGraphicsWindow::
00050 ~wglGraphicsWindow() {
00051 }
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: wglGraphicsWindow::begin_frame
00055 //       Access: Public, Virtual
00056 //  Description: This function will be called within the draw thread
00057 //               before beginning rendering for a given frame.  It
00058 //               should do whatever setup is required, and return true
00059 //               if the frame should be rendered, or false if it
00060 //               should be skipped.
00061 ////////////////////////////////////////////////////////////////////
00062 bool wglGraphicsWindow::
00063 begin_frame(FrameMode mode, Thread *current_thread) {
00064 
00065   begin_frame_spam(mode);
00066   if (_gsg == (GraphicsStateGuardian *)NULL) {
00067     return false;
00068   }
00069 
00070   if (!get_unexposed_draw() && !_got_expose_event) {
00071     if (wgldisplay_cat.is_spam()) {
00072       wgldisplay_cat.spam()
00073         << "Not drawing " << this << ": unexposed.\n";
00074     }
00075     return false;
00076   }
00077 
00078   if (wgldisplay_cat.is_spam()) {
00079     wgldisplay_cat.spam()
00080       << "Drawing " << this << ": exposed.\n";
00081   }
00082   
00083   wglGraphicsStateGuardian *wglgsg;
00084   DCAST_INTO_R(wglgsg, _gsg, false);
00085   
00086   HGLRC context = wglgsg->get_context(_hdc);
00087   nassertr(context, false);
00088   
00089   wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
00090   wglgsg->reset_if_new();
00091 
00092   if (mode == FM_render) {
00093     clear_cube_map_selection();
00094   }
00095   
00096   _gsg->set_current_properties(&get_fb_properties());
00097   return _gsg->begin_frame(current_thread);
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: wglGraphicsWindow::end_frame
00102 //       Access: Public, Virtual
00103 //  Description: This function will be called within the draw thread
00104 //               after rendering is completed for a given frame.  It
00105 //               should do whatever finalization is required.
00106 ////////////////////////////////////////////////////////////////////
00107 void wglGraphicsWindow::
00108 end_frame(FrameMode mode, Thread *current_thread) {
00109   end_frame_spam(mode);
00110 
00111   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00112 
00113   if (mode == FM_render) {
00114     copy_to_textures();
00115   }
00116 
00117   _gsg->end_frame(current_thread);
00118 
00119   if (mode == FM_render) {
00120     trigger_flip();
00121     clear_cube_map_selection();
00122   }
00123 }
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: wglGraphicsWindow::begin_flip
00127 //       Access: Public, Virtual
00128 //  Description: This function will be called within the draw thread
00129 //               after end_frame() has been called on all windows, to
00130 //               initiate the exchange of the front and back buffers.
00131 //
00132 //               This should instruct the window to prepare for the
00133 //               flip at the next video sync, but it should not wait.
00134 //
00135 //               We have the two separate functions, begin_flip() and
00136 //               end_flip(), to make it easier to flip all of the
00137 //               windows at the same time.
00138 ////////////////////////////////////////////////////////////////////
00139 void wglGraphicsWindow::
00140 begin_flip() {
00141 }
00142 
00143 ////////////////////////////////////////////////////////////////////
00144 //     Function: wglGraphicsWindow::ready_flip
00145 //       Access: Public, Virtual
00146 //  Description: This function will be called within the draw thread
00147 //               after end_frame() has been called on all windows, to
00148 //               initiate the exchange of the front and back buffers.
00149 //
00150 //               This should instruct the window to prepare for the
00151 //               flip when command, but will not actually flip
00152 //
00153 //               We have the two separate functions, begin_flip() and
00154 //               end_flip(), to make it easier to flip all of the
00155 //               windows at the same time.
00156 ////////////////////////////////////////////////////////////////////
00157 void wglGraphicsWindow::
00158 ready_flip() {
00159   if (_hdc) {
00160     // The documentation on SwapBuffers() is not at all clear on
00161     // whether the GL context needs to be current before it can be
00162     // called.  Empirically, it appears that it is not necessary in
00163     // many cases, but it definitely is necessary at least in the case
00164     // of Mesa on Windows.
00165     wglGraphicsStateGuardian *wglgsg;
00166     DCAST_INTO_V(wglgsg, _gsg);
00167     HGLRC context = wglgsg->get_context(_hdc);
00168     nassertv(context);
00169     wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
00170     wglgsg->finish();
00171   }
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: wglGraphicsWindow::end_flip
00176 //       Access: Public, Virtual
00177 //  Description: This function will be called within the draw thread
00178 //               after begin_flip() has been called on all windows, to
00179 //               finish the exchange of the front and back buffers.
00180 //
00181 //               This should cause the window to wait for the flip, if
00182 //               necessary.
00183 ////////////////////////////////////////////////////////////////////
00184 void wglGraphicsWindow::
00185 end_flip() {
00186   if (_hdc != NULL && _flip_ready) {
00187     // The documentation on SwapBuffers() is not at all clear on
00188     // whether the GL context needs to be current before it can be
00189     // called.  Empirically, it appears that it is not necessary in
00190     // many cases, but it definitely is necessary at least in the case
00191     // of Mesa on Windows.
00192     wglGraphicsStateGuardian *wglgsg;
00193     DCAST_INTO_V(wglgsg, _gsg);
00194     HGLRC context = wglgsg->get_context(_hdc);
00195     nassertv(context);
00196     wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
00197     SwapBuffers(_hdc);
00198   }
00199   WinGraphicsWindow::end_flip();
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: wglGraphicsWindow::close_window
00204 //       Access: Protected, Virtual
00205 //  Description: Closes the window right now.  Called from the window
00206 //               thread.
00207 ////////////////////////////////////////////////////////////////////
00208 void wglGraphicsWindow::
00209 close_window() {
00210   if (_gsg != (GraphicsStateGuardian *)NULL) {
00211     wglGraphicsPipe::wgl_make_current(_hdc, NULL, &_make_current_pcollector);
00212     _gsg.clear();
00213   }
00214   ReleaseDC(_hWnd, _hdc);
00215   _hdc = (HDC)0;
00216   WinGraphicsWindow::close_window();
00217 }
00218 
00219 ////////////////////////////////////////////////////////////////////
00220 //     Function: wglGraphicsWindow::open_window
00221 //       Access: Protected, Virtual
00222 //  Description: Opens the window right now.  Called from the window
00223 //               thread.  Returns true if the window is successfully
00224 //               opened, or false if there was a problem.
00225 ////////////////////////////////////////////////////////////////////
00226 bool wglGraphicsWindow::
00227 open_window() {
00228   if (!WinGraphicsWindow::open_window()) {
00229     return false;
00230   }
00231 
00232   // GSG creation/initialization.
00233 
00234   wglGraphicsStateGuardian *wglgsg;
00235   if (_gsg == 0) {
00236     // There is no old gsg.  Create a new one.
00237     wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, NULL);
00238     wglgsg->choose_pixel_format(_fb_properties, false);
00239     _gsg = wglgsg;
00240   } else {
00241     // If the old gsg has the wrong pixel format, create a
00242     // new one that shares with the old gsg.
00243     DCAST_INTO_R(wglgsg, _gsg, false);
00244     if (!wglgsg->get_fb_properties().subsumes(_fb_properties)) {
00245       wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg);
00246       wglgsg->choose_pixel_format(_fb_properties, false);
00247       _gsg = wglgsg;
00248     }
00249   }
00250   
00251   // Set up the pixel format of the window appropriately for GL.
00252 
00253   _hdc = GetDC(_hWnd);
00254   int pfnum = wglgsg->get_pfnum();
00255   PIXELFORMATDESCRIPTOR pixelformat;
00256   DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 
00257                       &pixelformat);
00258 
00259 #ifdef NOTIFY_DEBUG
00260   char msg[200];
00261   sprintf(msg, "Selected GL PixelFormat is #%d", pfnum);
00262   print_pfd(&pixelformat, msg);
00263 #endif
00264 
00265   BOOL set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat);
00266 
00267   if (!set_pfnum) {
00268     if (wglgsg->fail_pfnum()) {
00269       wgldisplay_cat.error()
00270         << "SetPixelFormat(" << pfnum << ") failed; trying " 
00271         << wglgsg->get_pfnum() << " instead\n";
00272 
00273       pfnum = wglgsg->get_pfnum();
00274       DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 
00275                           &pixelformat);
00276 
00277 #ifdef NOTIFY_DEBUG
00278       sprintf(msg, "Selected GL PixelFormat is #%d", pfnum);
00279       print_pfd(&pixelformat, msg);
00280 #endif
00281       
00282       DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 
00283                           &pixelformat);
00284       set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat);
00285     }
00286   }
00287 
00288   if (!set_pfnum) {
00289     wgldisplay_cat.error()
00290       << "SetPixelFormat(" << pfnum << ") failed after window create\n";
00291     close_window();
00292     return false;
00293   }
00294 
00295 #ifndef NDEBUG
00296   if (gl_force_invalid) {
00297     wgldisplay_cat.error()
00298       << "Artificially failing window.\n";
00299     close_window();
00300     return false;
00301   }
00302 #endif  // NDEBUG
00303 
00304   // Initializes _colormap
00305   setup_colormap(pixelformat);
00306 
00307   // Initialize the gsg.
00308   wglGraphicsPipe::wgl_make_current(_hdc, wglgsg->get_context(_hdc), &_make_current_pcollector);
00309   wglgsg->reset_if_new();
00310   wglgsg->report_my_gl_errors();
00311   if (!wglgsg->get_fb_properties().verify_hardware_software
00312       (_fb_properties,wglgsg->get_gl_renderer())) {
00313     close_window();
00314     return false;
00315   }
00316   _fb_properties = wglgsg->get_fb_properties();
00317 
00318   return true;
00319 }
00320 
00321 ////////////////////////////////////////////////////////////////////
00322 //     Function: wglGraphicsWindow::setup_colormap
00323 //       Access: Private
00324 //  Description: Sets up a colormap for the window matching the
00325 //               selected pixel format.  This is necessary before
00326 //               creating a GL context.
00327 ////////////////////////////////////////////////////////////////////
00328 void wglGraphicsWindow::
00329 setup_colormap(const PIXELFORMATDESCRIPTOR &pixelformat) {
00330   LOGPALETTE *logical;
00331   int n;
00332 
00333   if (!(pixelformat.dwFlags & PFD_NEED_PALETTE ||
00334       pixelformat.iPixelType == PFD_TYPE_COLORINDEX))
00335     return;
00336 
00337   n = 1 << pixelformat.cColorBits;
00338 
00339   /* allocate a bunch of memory for the logical palette (assume 256
00340      colors in a Win32 palette */
00341   logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
00342                                 sizeof(PALETTEENTRY) * n);
00343   memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
00344 
00345   /* set the entries in the logical palette */
00346   logical->palVersion = 0x300;
00347   logical->palNumEntries = n;
00348 
00349   /* start with a copy of the current system palette */
00350   GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]);
00351 
00352   if (pixelformat.iPixelType == PFD_TYPE_RGBA) {
00353     int redMask = (1 << pixelformat.cRedBits) - 1;
00354     int greenMask = (1 << pixelformat.cGreenBits) - 1;
00355     int blueMask = (1 << pixelformat.cBlueBits) - 1;
00356     int i;
00357 
00358     /* fill in an RGBA color palette */
00359     for (i = 0; i < n; ++i) {
00360       logical->palPalEntry[i].peRed =
00361         (((i >> pixelformat.cRedShift)   & redMask)   * 255) / redMask;
00362       logical->palPalEntry[i].peGreen =
00363         (((i >> pixelformat.cGreenShift) & greenMask) * 255) / greenMask;
00364         logical->palPalEntry[i].peBlue =
00365         (((i >> pixelformat.cBlueShift)  & blueMask)  * 255) / blueMask;
00366       logical->palPalEntry[i].peFlags = 0;
00367     }
00368   }
00369 
00370   _colormap = CreatePalette(logical);
00371   free(logical);
00372 
00373   SelectPalette(_hdc, _colormap, FALSE);
00374   RealizePalette(_hdc);
00375 }
00376 
00377 #ifdef NOTIFY_DEBUG
00378 
00379 //typedef enum {Software, MCD, ICD} OGLDriverType;
00380 static char *OGLDrvStrings[3] = {"Software","MCD","ICD"};
00381 
00382 ////////////////////////////////////////////////////////////////////
00383 //     Function: wglGraphicsWindow::print_pfd
00384 //       Access: Private, Static
00385 //  Description: Reports information about the selected pixel format
00386 //               descriptor, along with the indicated message.
00387 ////////////////////////////////////////////////////////////////////
00388 void wglGraphicsWindow::
00389 print_pfd(PIXELFORMATDESCRIPTOR *pfd, char *msg) {
00390   if (!wgldisplay_cat.is_debug()) {
00391     return;
00392   }
00393 
00394   OGLDriverType drvtype;
00395   if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) && 
00396       (pfd->dwFlags & PFD_GENERIC_FORMAT)) {
00397     drvtype=MCD;
00398   } else if (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT)) {
00399     drvtype=ICD;
00400   } else {
00401     drvtype=Software;
00402   }
00403 
00404 #define PRINT_FLAG(FLG) ((pfd->dwFlags &  PFD_##FLG) ? (" PFD_" #FLG "|") : "")
00405   wgldisplay_cat.debug()
00406     << "================================\n";
00407 
00408   wgldisplay_cat.debug()
00409     << msg << ", " << OGLDrvStrings[drvtype] << " driver\n"
00410     << "PFD flags: 0x" << (void*)pfd->dwFlags << " (" 
00411     << PRINT_FLAG(GENERIC_ACCELERATED) 
00412     << PRINT_FLAG(GENERIC_FORMAT)
00413     << PRINT_FLAG(DOUBLEBUFFER)
00414     << PRINT_FLAG(SUPPORT_OPENGL)
00415     << PRINT_FLAG(SUPPORT_GDI)
00416     << PRINT_FLAG(STEREO)
00417     << PRINT_FLAG(DRAW_TO_WINDOW)
00418     << PRINT_FLAG(DRAW_TO_BITMAP)
00419     << PRINT_FLAG(SWAP_EXCHANGE)
00420     << PRINT_FLAG(SWAP_COPY)
00421     << PRINT_FLAG(SWAP_LAYER_BUFFERS)
00422     << PRINT_FLAG(NEED_PALETTE)
00423     << PRINT_FLAG(NEED_SYSTEM_PALETTE)
00424     << PRINT_FLAG(SUPPORT_DIRECTDRAW) << ")\n"
00425     << "PFD iPixelType: "
00426     << ((pfd->iPixelType==PFD_TYPE_RGBA) ? "PFD_TYPE_RGBA":"PFD_TYPE_COLORINDEX")
00427     << endl
00428     << "PFD cColorBits: " << (DWORD)pfd->cColorBits
00429     << "  R: " << (DWORD)pfd->cRedBits
00430     <<" G: " << (DWORD)pfd->cGreenBits
00431     <<" B: " << (DWORD)pfd->cBlueBits << endl
00432     << "PFD cAlphaBits: " << (DWORD)pfd->cAlphaBits
00433     << "  DepthBits: " << (DWORD)pfd->cDepthBits
00434     <<" StencilBits: " << (DWORD)pfd->cStencilBits
00435     <<" AccumBits: " << (DWORD)pfd->cAccumBits
00436     << endl;
00437 }
00438 #endif
00439