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