Panda3D

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   wglGraphicsStateGuardian *wglgsg;
00071   DCAST_INTO_R(wglgsg, _gsg, false);
00072   
00073   HGLRC context = wglgsg->get_context(_hdc);
00074   nassertr(context, false);
00075   
00076   wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
00077   wglgsg->reset_if_new();
00078 
00079   if (mode == FM_render) {
00080     clear_cube_map_selection();
00081   }
00082   
00083   _gsg->set_current_properties(&get_fb_properties());
00084   return _gsg->begin_frame(current_thread);
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: wglGraphicsWindow::end_frame
00089 //       Access: Public, Virtual
00090 //  Description: This function will be called within the draw thread
00091 //               after rendering is completed for a given frame.  It
00092 //               should do whatever finalization is required.
00093 ////////////////////////////////////////////////////////////////////
00094 void wglGraphicsWindow::
00095 end_frame(FrameMode mode, Thread *current_thread) {
00096 
00097   end_frame_spam(mode);
00098 
00099   nassertv(_gsg != (GraphicsStateGuardian *)NULL);
00100 
00101   if (mode == FM_render) {
00102     copy_to_textures();
00103   }
00104 
00105   _gsg->end_frame(current_thread);
00106 
00107   if (mode == FM_render) {
00108     trigger_flip();
00109     if (_one_shot) {
00110       prepare_for_deletion();
00111     }
00112     clear_cube_map_selection();
00113   }
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: wglGraphicsWindow::begin_flip
00118 //       Access: Public, Virtual
00119 //  Description: This function will be called within the draw thread
00120 //               after end_frame() has been called on all windows, to
00121 //               initiate the exchange of the front and back buffers.
00122 //
00123 //               This should instruct the window to prepare for the
00124 //               flip at the next video sync, but it should not wait.
00125 //
00126 //               We have the two separate functions, begin_flip() and
00127 //               end_flip(), to make it easier to flip all of the
00128 //               windows at the same time.
00129 ////////////////////////////////////////////////////////////////////
00130 void wglGraphicsWindow::
00131 begin_flip() {
00132   if (_hdc) {
00133     // The documentation on SwapBuffers() is not at all clear on
00134     // whether the GL context needs to be current before it can be
00135     // called.  Empirically, it appears that it is not necessary in
00136     // many cases, but it definitely is necessary at least in the case
00137     // of Mesa on Windows.
00138     wglGraphicsStateGuardian *wglgsg;
00139     DCAST_INTO_V(wglgsg, _gsg);
00140     HGLRC context = wglgsg->get_context(_hdc);
00141     nassertv(context);
00142     wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
00143     SwapBuffers(_hdc);
00144   }
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: wglGraphicsWindow::close_window
00149 //       Access: Protected, Virtual
00150 //  Description: Closes the window right now.  Called from the window
00151 //               thread.
00152 ////////////////////////////////////////////////////////////////////
00153 void wglGraphicsWindow::
00154 close_window() {
00155   if (_gsg != (GraphicsStateGuardian *)NULL) {
00156     wglGraphicsPipe::wgl_make_current(_hdc, NULL, &_make_current_pcollector);
00157     _gsg.clear();
00158     _active = false;
00159   }
00160   ReleaseDC(_hWnd, _hdc);
00161   _hdc = (HDC)0;
00162   WinGraphicsWindow::close_window();
00163 }
00164 
00165 ////////////////////////////////////////////////////////////////////
00166 //     Function: wglGraphicsWindow::open_window
00167 //       Access: Protected, Virtual
00168 //  Description: Opens the window right now.  Called from the window
00169 //               thread.  Returns true if the window is successfully
00170 //               opened, or false if there was a problem.
00171 ////////////////////////////////////////////////////////////////////
00172 bool wglGraphicsWindow::
00173 open_window() {
00174   if (!WinGraphicsWindow::open_window()) {
00175     return false;
00176   }
00177 
00178   // GSG creation/initialization.
00179 
00180   wglGraphicsStateGuardian *wglgsg;
00181   if (_gsg == 0) {
00182     // There is no old gsg.  Create a new one.
00183     wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, NULL);
00184     wglgsg->choose_pixel_format(_fb_properties, false);
00185     _gsg = wglgsg;
00186   } else {
00187     // If the old gsg has the wrong pixel format, create a
00188     // new one that shares with the old gsg.
00189     DCAST_INTO_R(wglgsg, _gsg, false);
00190     if (!wglgsg->get_fb_properties().subsumes(_fb_properties)) {
00191       wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg);
00192       wglgsg->choose_pixel_format(_fb_properties, false);
00193       _gsg = wglgsg;
00194     }
00195   }
00196   
00197   // Set up the pixel format of the window appropriately for GL.
00198 
00199   _hdc = GetDC(_hWnd);
00200   int pfnum = wglgsg->get_pfnum();
00201   PIXELFORMATDESCRIPTOR pixelformat;
00202   DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 
00203                       &pixelformat);
00204 
00205 #ifdef NOTIFY_DEBUG
00206   char msg[200];
00207   sprintf(msg, "Selected GL PixelFormat is #%d", pfnum);
00208   print_pfd(&pixelformat, msg);
00209 #endif
00210 
00211   BOOL set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat);
00212 
00213   if (!set_pfnum) {
00214     if (wglgsg->fail_pfnum()) {
00215       wgldisplay_cat.error()
00216         << "SetPixelFormat(" << pfnum << ") failed; trying " 
00217         << wglgsg->get_pfnum() << " instead\n";
00218 
00219       pfnum = wglgsg->get_pfnum();
00220       DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 
00221                           &pixelformat);
00222 
00223 #ifdef NOTIFY_DEBUG
00224       sprintf(msg, "Selected GL PixelFormat is #%d", pfnum);
00225       print_pfd(&pixelformat, msg);
00226 #endif
00227       
00228       DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), 
00229                           &pixelformat);
00230       set_pfnum = SetPixelFormat(_hdc, pfnum, &pixelformat);
00231     }
00232   }
00233 
00234   if (!set_pfnum) {
00235     wgldisplay_cat.error()
00236       << "SetPixelFormat(" << pfnum << ") failed after window create\n";
00237     close_window();
00238     return false;
00239   }
00240 
00241 #ifndef NDEBUG
00242   if (gl_force_invalid) {
00243     wgldisplay_cat.error()
00244       << "Artificially failing window.\n";
00245     close_window();
00246     return false;
00247   }
00248 #endif  // NDEBUG
00249 
00250   // Initializes _colormap
00251   setup_colormap(pixelformat);
00252 
00253   // Initialize the gsg.
00254   wglGraphicsPipe::wgl_make_current(_hdc, wglgsg->get_context(_hdc), &_make_current_pcollector);
00255   wglgsg->reset_if_new();
00256   wglgsg->report_my_gl_errors();
00257   if (!wglgsg->get_fb_properties().verify_hardware_software
00258       (_fb_properties,wglgsg->get_gl_renderer())) {
00259     close_window();
00260     return false;
00261   }
00262   _fb_properties = wglgsg->get_fb_properties();
00263 
00264   return true;
00265 }
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: wglGraphicsWindow::setup_colormap
00269 //       Access: Private
00270 //  Description: Sets up a colormap for the window matching the
00271 //               selected pixel format.  This is necessary before
00272 //               creating a GL context.
00273 ////////////////////////////////////////////////////////////////////
00274 void wglGraphicsWindow::
00275 setup_colormap(const PIXELFORMATDESCRIPTOR &pixelformat) {
00276   LOGPALETTE *logical;
00277   int n;
00278 
00279   if (!(pixelformat.dwFlags & PFD_NEED_PALETTE ||
00280       pixelformat.iPixelType == PFD_TYPE_COLORINDEX))
00281     return;
00282 
00283   n = 1 << pixelformat.cColorBits;
00284 
00285   /* allocate a bunch of memory for the logical palette (assume 256
00286      colors in a Win32 palette */
00287   logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
00288                                 sizeof(PALETTEENTRY) * n);
00289   memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
00290 
00291   /* set the entries in the logical palette */
00292   logical->palVersion = 0x300;
00293   logical->palNumEntries = n;
00294 
00295   /* start with a copy of the current system palette */
00296   GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]);
00297 
00298   if (pixelformat.iPixelType == PFD_TYPE_RGBA) {
00299     int redMask = (1 << pixelformat.cRedBits) - 1;
00300     int greenMask = (1 << pixelformat.cGreenBits) - 1;
00301     int blueMask = (1 << pixelformat.cBlueBits) - 1;
00302     int i;
00303 
00304     /* fill in an RGBA color palette */
00305     for (i = 0; i < n; ++i) {
00306       logical->palPalEntry[i].peRed =
00307         (((i >> pixelformat.cRedShift)   & redMask)   * 255) / redMask;
00308       logical->palPalEntry[i].peGreen =
00309         (((i >> pixelformat.cGreenShift) & greenMask) * 255) / greenMask;
00310         logical->palPalEntry[i].peBlue =
00311         (((i >> pixelformat.cBlueShift)  & blueMask)  * 255) / blueMask;
00312       logical->palPalEntry[i].peFlags = 0;
00313     }
00314   }
00315 
00316   _colormap = CreatePalette(logical);
00317   free(logical);
00318 
00319   SelectPalette(_hdc, _colormap, FALSE);
00320   RealizePalette(_hdc);
00321 }
00322 
00323 #ifdef NOTIFY_DEBUG
00324 
00325 //typedef enum {Software, MCD, ICD} OGLDriverType;
00326 static char *OGLDrvStrings[3] = {"Software","MCD","ICD"};
00327 
00328 ////////////////////////////////////////////////////////////////////
00329 //     Function: wglGraphicsWindow::print_pfd
00330 //       Access: Private, Static
00331 //  Description: Reports information about the selected pixel format
00332 //               descriptor, along with the indicated message.
00333 ////////////////////////////////////////////////////////////////////
00334 void wglGraphicsWindow::
00335 print_pfd(PIXELFORMATDESCRIPTOR *pfd, char *msg) {
00336   if (!wgldisplay_cat.is_debug()) {
00337     return;
00338   }
00339 
00340   OGLDriverType drvtype;
00341   if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) && 
00342       (pfd->dwFlags & PFD_GENERIC_FORMAT)) {
00343     drvtype=MCD;
00344   } else if (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT)) {
00345     drvtype=ICD;
00346   } else {
00347     drvtype=Software;
00348   }
00349 
00350 #define PRINT_FLAG(FLG) ((pfd->dwFlags &  PFD_##FLG) ? (" PFD_" #FLG "|") : "")
00351   wgldisplay_cat.debug()
00352     << "================================\n";
00353 
00354   wgldisplay_cat.debug()
00355     << msg << ", " << OGLDrvStrings[drvtype] << " driver\n"
00356     << "PFD flags: 0x" << (void*)pfd->dwFlags << " (" 
00357     << PRINT_FLAG(GENERIC_ACCELERATED) 
00358     << PRINT_FLAG(GENERIC_FORMAT)
00359     << PRINT_FLAG(DOUBLEBUFFER)
00360     << PRINT_FLAG(SUPPORT_OPENGL)
00361     << PRINT_FLAG(SUPPORT_GDI)
00362     << PRINT_FLAG(STEREO)
00363     << PRINT_FLAG(DRAW_TO_WINDOW)
00364     << PRINT_FLAG(DRAW_TO_BITMAP)
00365     << PRINT_FLAG(SWAP_EXCHANGE)
00366     << PRINT_FLAG(SWAP_COPY)
00367     << PRINT_FLAG(SWAP_LAYER_BUFFERS)
00368     << PRINT_FLAG(NEED_PALETTE)
00369     << PRINT_FLAG(NEED_SYSTEM_PALETTE)
00370     << PRINT_FLAG(SUPPORT_DIRECTDRAW) << ")\n"
00371     << "PFD iPixelType: "
00372     << ((pfd->iPixelType==PFD_TYPE_RGBA) ? "PFD_TYPE_RGBA":"PFD_TYPE_COLORINDEX")
00373     << endl
00374     << "PFD cColorBits: " << (DWORD)pfd->cColorBits
00375     << "  R: " << (DWORD)pfd->cRedBits
00376     <<" G: " << (DWORD)pfd->cGreenBits
00377     <<" B: " << (DWORD)pfd->cBlueBits << endl
00378     << "PFD cAlphaBits: " << (DWORD)pfd->cAlphaBits
00379     << "  DepthBits: " << (DWORD)pfd->cDepthBits
00380     <<" StencilBits: " << (DWORD)pfd->cStencilBits
00381     <<" AccumBits: " << (DWORD)pfd->cAccumBits
00382     << endl;
00383 }
00384 #endif
00385 
 All Classes Functions Variables Enumerations