1 /****************************************************************************
3 * Mesa 3-D graphics library
4 * Direct3D Driver Interface
6 * ========================================================================
8 * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
25 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * ======================================================================
31 * Environment: Windows 9x (Win32)
33 * Description: Context handling.
35 ****************************************************************************/
37 #include "dglcontext.h"
39 // Get compile errors without this. KeithH
40 //#include "scitech.h" // ibool, etc.
43 #include "gld_driver.h"
45 extern void _gld_mesa_warning(struct gl_context *, char *);
46 extern void _gld_mesa_fatal(struct gl_context *, char *);
47 #endif // _USE_GLD3_WGL
49 // TODO: Clean out old DX6-specific code from GLD 2.x CAD driver
50 // if it is no longer being built as part of GLDirect. (DaveM)
52 // ***********************************************************************
56 #define GLDERR_DDRAW 2
60 char szResourceWarning[] =
61 "GLDirect does not have enough video memory resources\n"
62 "to support the requested OpenGL rendering context.\n\n"
63 "You may have to reduce the current display resolution\n"
64 "to obtain satisfactory OpenGL performance.\n";
66 char szDDrawWarning[] =
67 "GLDirect is unable to initialize DirectDraw for the\n"
68 "requested OpenGL rendering context.\n\n"
69 "You will have to check the DirectX control panel\n"
70 "for further information.\n";
73 "GLDirect is unable to initialize Direct3D for the\n"
74 "requested OpenGL rendering context.\n\n"
75 "You may have to change the display mode resolution\n"
76 "color depth or check the DirectX control panel for\n"
77 "further information.\n";
80 "GLDirect is unable to use the selected color depth for\n"
81 "the requested OpenGL rendering context.\n\n"
82 "You will have to change the display mode resolution\n"
83 "color depth with the Display Settings control panel.\n";
85 int nContextError = GLDERR_NONE;
87 // ***********************************************************************
89 #define VENDORID_ATI 0x1002
91 static DWORD devATIRagePro[] = {
92 0x4742, // 3D RAGE PRO BGA AGP 1X/2X
93 0x4744, // 3D RAGE PRO BGA AGP 1X only
94 0x4749, // 3D RAGE PRO BGA PCI 33 MHz
95 0x4750, // 3D RAGE PRO PQFP PCI 33 MHz
96 0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D
97 0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz
98 0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz
99 0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz
100 0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz
101 0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D
104 static DWORD devATIRageIIplus[] = {
105 0x4755, // 3D RAGE II+
106 0x4756, // 3D RAGE IIC PQFP PCI
107 0x4757, // 3D RAGE IIC BGA AGP
108 0x475A, // 3D RAGE IIC PQFP AGP
109 0x4C47, // 3D RAGE LT-G
112 // ***********************************************************************
114 #ifndef _USE_GLD3_WGL
115 extern DGL_mesaFuncs mesaFuncs;
118 extern DWORD dwLogging;
121 #pragma message("compiling DGLCONTEXT.C vars for multi-threaded support")
122 CRITICAL_SECTION CriticalSection; // for serialized access
123 DWORD dwTLSCurrentContext = 0xFFFFFFFF; // TLS index for current context
124 DWORD dwTLSPixelFormat = 0xFFFFFFFF; // TLS index for current pixel format
126 HGLRC iCurrentContext = 0; // Index of current context (static)
127 BOOL bContextReady = FALSE; // Context state ready ?
129 DGL_ctx ctxlist[DGL_MAX_CONTEXTS]; // Context list
131 // ***********************************************************************
133 static BOOL bHaveWin95 = FALSE;
134 static BOOL bHaveWinNT = FALSE;
135 static BOOL bHaveWin2K = FALSE;
137 /****************************************************************************
139 Detect the installed OS type.
140 ****************************************************************************/
141 static void DetectOS(void)
143 OSVERSIONINFO VersionInformation;
144 LPOSVERSIONINFO lpVersionInformation = &VersionInformation;
146 VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
148 GetVersionEx(lpVersionInformation);
150 switch (VersionInformation.dwPlatformId) {
151 case VER_PLATFORM_WIN32_WINDOWS:
156 case VER_PLATFORM_WIN32_NT:
158 if (VersionInformation.dwMajorVersion <= 4) {
167 case VER_PLATFORM_WIN32s:
175 // ***********************************************************************
177 HWND hWndEvent = NULL; // event monitor window
178 HWND hWndLastActive = NULL; // last active client window
179 LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
181 // ***********************************************************************
183 // Checks if the HGLRC is valid in range of context list.
184 BOOL dglIsValidContext(
187 return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS);
190 // ***********************************************************************
192 // Convert a HGLRC to a pointer into the context list.
193 DGL_ctx* dglGetContextAddress(
196 if (dglIsValidContext(a))
197 return &ctxlist[(int)a-1];
201 // ***********************************************************************
203 // Return the current HGLRC (however it may be stored for multi-threading).
204 HGLRC dglGetCurrentContext(void)
208 // load from thread-specific instance
209 if (glb.bMultiThreaded) {
210 // protect against calls from arbitrary threads
212 hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext);
214 __except(EXCEPTION_EXECUTE_HANDLER) {
215 hGLRC = iCurrentContext;
218 // load from global static var
220 hGLRC = iCurrentContext;
224 return iCurrentContext;
228 // ***********************************************************************
230 // Set the current HGLRC (however it may be stored for multi-threading).
231 void dglSetCurrentContext(HGLRC hGLRC)
234 // store in thread-specific instance
235 if (glb.bMultiThreaded) {
236 // protect against calls from arbitrary threads
238 TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC);
240 __except(EXCEPTION_EXECUTE_HANDLER) {
241 iCurrentContext = hGLRC;
244 // store in global static var
246 iCurrentContext = hGLRC;
249 iCurrentContext = hGLRC;
253 // ***********************************************************************
255 // Return the current HDC only for a currently active HGLRC.
256 HDC dglGetCurrentDC(void)
261 hGLRC = dglGetCurrentContext();
263 lpCtx = dglGetContextAddress(hGLRC);
269 // ***********************************************************************
271 void dglInitContextState()
277 // Allocate thread local storage indexes for current context and pixel format
278 dwTLSCurrentContext = TlsAlloc();
279 dwTLSPixelFormat = TlsAlloc();
282 dglSetCurrentContext(NULL); // No current rendering context
284 // Clear all context data
285 ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS);
287 for (i=0; i<DGL_MAX_CONTEXTS; i++)
288 ctxlist[i].bAllocated = FALSE; // Flag context as unused
290 // This section of code crashes the dll in circumstances where the app
291 // creates and destroys contexts.
293 // Register the class for our event monitor window
295 wc.lpfnWndProc = GLD_EventWndProc;
298 wc.hInstance = GetModuleHandle(NULL);
299 wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
300 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
301 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
302 wc.lpszMenuName = NULL;
303 wc.lpszClassName = "GLDIRECT";
306 // Create the non-visible window to monitor all broadcast messages
307 hWndEvent = CreateWindowEx(
308 WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP,
310 NULL,NULL,GetModuleHandle(NULL),NULL);
314 // Create a critical section object for serializing access to
315 // DirectDraw and DDStereo create/destroy functions in multiple threads
316 if (glb.bMultiThreaded)
317 InitializeCriticalSection(&CriticalSection);
320 // Context state is now initialized and ready
321 bContextReady = TRUE;
324 // ***********************************************************************
326 void dglDeleteContextState()
329 static BOOL bOnceIsEnough = FALSE;
331 // Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH
334 bOnceIsEnough = TRUE;
336 for (i=0; i<DGL_MAX_CONTEXTS; i++) {
337 if (ctxlist[i].bAllocated == TRUE) {
338 ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1));
339 dglDeleteContext((HGLRC)(i+1));
343 // Context state is no longer ready
344 bContextReady = FALSE;
346 // If executed when DLL unloads, DDraw objects may be invalid.
347 // So catch any page faults with this exception handler.
350 // Release final DirectDraw interfaces
351 if (glb.bDirectDrawPersistant) {
352 // RELEASE(glb.lpGlobalPalette);
353 // RELEASE(glb.lpDepth4);
354 // RELEASE(glb.lpBack4);
355 // RELEASE(glb.lpPrimary4);
356 // RELEASE(glb.lpDD4);
359 __except(EXCEPTION_EXECUTE_HANDLER) {
360 ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState.");
363 // Destroy our event monitor window
365 DestroyWindow(hWndEvent);
366 hWndEvent = hWndLastActive = NULL;
370 // Destroy the critical section object
371 if (glb.bMultiThreaded)
372 DeleteCriticalSection(&CriticalSection);
374 // Release thread local storage indexes for current HGLRC and pixel format
375 TlsFree(dwTLSPixelFormat);
376 TlsFree(dwTLSCurrentContext);
380 // ***********************************************************************
382 // Application Window message handler interception
383 static LONG __stdcall dglWndProc(
389 DGL_ctx* lpCtx = NULL;
390 LONG lpfnWndProc = 0L;
399 // Get the window's message handler *before* it is unhooked in WM_DESTROY
401 // Is this the main window?
402 if (hwnd == glb.hWndActive) {
404 lpfnWndProc = glb.lpfnWndProc;
406 // Search for DGL context matching window handle
407 for (i=0; i<DGL_MAX_CONTEXTS; i++) {
408 if (ctxlist[i].hWnd == hwnd) {
410 lpfnWndProc = lpCtx->lpfnWndProc;
414 // Not one of ours...
416 return DefWindowProc(hwnd, msg, wParam, lParam);
418 // Intercept messages amd process *before* passing on to window
421 case WM_DISPLAYCHANGE:
422 glb.bPixelformatsDirty = TRUE;
426 glb.bAppActive = (BOOL)wParam;
427 ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated");
430 // Eat the GDI erase event for the GL window
431 if (!lpCtx || !lpCtx->bHasBeenCurrent)
433 lpCtx->bGDIEraseBkgnd = TRUE;
436 // Eat the invalidated update region if render scene is in progress
437 if (!lpCtx || !lpCtx->bHasBeenCurrent)
439 if (lpCtx->bFrameStarted) {
440 if (GetUpdateRect(hwnd, &rect, FALSE)) {
441 BeginPaint(hwnd, &ps);
443 ValidateRect(hwnd, &rect);
449 // Call the appropriate window message handler
450 rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam);
452 // Intercept messages and process *after* passing on to window
457 if (lpCtx && lpCtx->bAllocated) {
458 ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1);
459 dglDeleteContext((HGLRC)(i+1));
464 // Resize surfaces to fit window but not viewport (in case app did not bother)
465 if (!lpCtx || !lpCtx->bHasBeenCurrent)
469 if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) {
470 if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE))
471 dglWglResizeBuffers(lpCtx->glCtx, FALSE);
477 // If the main window is quitting, then so should we...
478 if (bMain && bQuit) {
479 ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd);
480 dglDeleteContextState();
487 // ***********************************************************************
489 // Driver Window message handler
490 static LONG __stdcall GLD_EventWndProc(
497 // May be sent by splash screen dialog on exit
499 if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) {
500 SetForegroundWindow(glb.hWndActive);
505 return DefWindowProc(hwnd, msg, wParam, lParam);
508 // ***********************************************************************
510 // Intercepted Keyboard handler for detecting hot keys.
511 LRESULT CALLBACK dglKeyProc(
516 HWND hWnd, hWndFrame;
518 DGL_ctx* lpCtx = NULL;
519 int cmd = 0, dx1 = 0, dx2 = 0, i;
520 static BOOL bAltPressed = FALSE;
521 static BOOL bCtrlPressed = FALSE;
522 static BOOL bShiftPressed = FALSE;
525 BOOL bForceReshape = FALSE;
527 return CallNextHookEx(hKeyHook, code, wParam, lParam);
530 // ***********************************************************************
534 // Window handle enumeration procedure.
535 BOOL CALLBACK dglEnumChildProc(
541 // Find window handle with matching client rect.
542 GetClientRect(hWnd, &rect);
543 if (EqualRect(&rect, (RECT*)lParam)) {
547 // Continue with next child window.
551 // ***********************************************************************
553 // Find window handle with matching client rect.
554 HWND dglFindWindowRect(
558 EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect);
562 // ***********************************************************************
563 #ifndef _USE_GLD3_WGL
564 void dglChooseDisplayMode(
567 // Note: Choose an exact match if possible.
572 DDSURFACEDESC2 *lpDDSD = NULL; // Mode list pointer
573 DDSURFACEDESC2 *lpBestDDSD = NULL; // Pointer to best
575 lpDDSD = glb.lpDisplayModes;
576 for (i=0; i<glb.nDisplayModeCount; i++, lpDDSD++) {
577 if ((lpDDSD->dwWidth == lpCtx->dwWidth) &&
578 (lpDDSD->dwHeight == lpCtx->dwHeight))
579 goto matched; // Mode has been exactly matched
580 // Choose modes that are larger in both dimensions than
581 // the window, but smaller in area than the current best.
582 if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) &&
583 (lpDDSD->dwHeight >= lpCtx->dwHeight))
585 if (lpBestDDSD == NULL) {
587 bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight;
590 area = lpDDSD->dwWidth * lpDDSD->dwHeight;
591 if (area < bestarea) {
599 if (lpBestDDSD == NULL) {
600 ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode");
604 lpCtx->dwModeWidth = lpBestDDSD->dwWidth;
605 lpCtx->dwModeHeight = lpBestDDSD->dwHeight;
607 ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)",
608 lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight);
610 #endif // _USE_GLD3_WGL
611 // ***********************************************************************
613 static BOOL IsDevice(
614 DWORD *lpDeviceIdList,
620 for (i=0; i<count; i++)
621 if (dwDeviceId == lpDeviceIdList[i])
627 // ***********************************************************************
629 void dglTestForBrokenCards(
633 DDDEVICEIDENTIFIER dddi; // DX6 device identifier
637 // Testing for broken cards is sensitive area, so we don't want
638 // anything saying "broken cards" in the error message. ;)
639 ddlogMessage(DDLOG_ERROR, "Null context passed to TFBC\n");
643 if (lpCtx->lpDD4 == NULL) {
644 // Testing for broken cards is sensitive area, so we don't want
645 // anything saying "broken cards" in the error message. ;)
646 ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n");
650 // Microsoft really fucked up with the GetDeviceIdentifier function
651 // on Windows 2000, since it locks up on stock driers on the CD. Updated
652 // drivers from vendors appear to work, but we can't identify the drivers
653 // without this function!!! For now we skip these tests on Windows 2000.
654 if ((GetVersion() & 0x80000000UL) == 0)
657 // Obtain device info
658 if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0)))
661 // Useful info. Log it.
662 ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId);
665 if (dddi.dwVendorId == VENDORID_ATI) {
666 // Test A: ATI Rage PRO
667 if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro)))
668 glb.bUseMipmaps = FALSE;
669 // Test B: ATI Rage II+
670 if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus)))
671 glb.bEmulateAlphaTest = TRUE;
675 if (dddi.dwVendorId == 0x102B) {
676 // Test: Matrox G400 stencil buffer support does not work for AutoCAD
677 if (dddi.dwDeviceId == 0x0525) {
678 lpCtx->lpPF->pfd.cStencilBits = 0;
679 if (lpCtx->lpPF->iZBufferPF != -1) {
680 glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0;
681 glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0;
682 glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER;
689 // ***********************************************************************
691 BOOL dglCreateContextBuffers(
702 #ifndef _USE_GLD3_WGL
704 DDSURFACEDESC2 ddsd2;
706 LPDIRECTDRAWCLIPPER lpddClipper;
707 D3DDEVICEDESC D3DHWDevDesc; // Direct3D Hardware description
708 D3DDEVICEDESC D3DHELDevDesc; // Direct3D Hardware Emulation Layer
709 #endif // _USE_GLD3_WGL
713 GLenum bDoubleBuffer; // TRUE if double buffer required
714 GLenum bDepthBuffer; // TRUE if depth buffer required
716 const PIXELFORMATDESCRIPTOR *lpPFD = &lpCtx->lpPF->pfd;
718 // Vars for Mesa visual
719 DWORD dwDepthBits = 0;
720 DWORD dwStencilBits = 0;
721 DWORD dwAlphaBits = 0;
722 DWORD bAlphaSW = GL_FALSE;
723 DWORD bDouble = GL_FALSE;
725 DDSURFACEDESC2 ddsd2DisplayMode;
726 BOOL bFullScrnWin = FALSE; // fullscreen-size window ?
728 DWORD dwMemoryType = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType;
729 BOOL bBogusWindow = FALSE; // non-drawable window ?
730 DWORD dwColorRef = 0; // GDI background color
731 RECT rcDst; // GDI window rect
732 POINT pt; // GDI window point
734 // Palette used for creating default global palette
735 PALETTEENTRY ppe[256];
737 #ifndef _USE_GLD3_WGL
738 // Vertex buffer description. Used for creation of vertex buffers
739 D3DVERTEXBUFFERDESC vbufdesc;
740 #endif // _USE_GLD3_WGL
742 #define DDLOG_CRITICAL_OR_WARN (bFallback ? DDLOG_CRITICAL : DDLOG_WARN)
744 ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a);
745 nContextError = GLDERR_NONE;
748 // Serialize access to DirectDraw object creation or DDS start
749 if (glb.bMultiThreaded)
750 EnterCriticalSection(&CriticalSection);
753 // Check for back buffer
754 bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE;
755 // Since we always do back buffering, check if we emulate front buffering
756 lpCtx->EmulateSingle =
757 (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
758 #if 0 // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM)
759 lpCtx->EmulateSingle |=
760 (lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE;
763 // Check for depth buffer
764 bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE;
766 lpCtx->bDoubleBuffer = bDoubleBuffer;
767 lpCtx->bDepthBuffer = bDepthBuffer;
769 // Set the Fullscreen flag for the context.
770 // lpCtx->bFullscreen = glb.bFullscreen;
772 // Obtain the dimensions of the rendering window
773 lpCtx->hDC = a; // Cache DC
774 lpCtx->hWnd = WindowFromDC(lpCtx->hDC);
775 // Check for non-window DC = memory DC ?
776 if (lpCtx->hWnd == NULL) {
777 // bitmap memory contexts are always single-buffered
778 lpCtx->EmulateSingle = TRUE;
780 ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context");
781 if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) {
782 ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n");
783 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
786 else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
788 ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n");
789 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
791 lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left;
792 lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top;
794 ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i",
795 lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight);
797 // What if app only zeroes one dimension instead of both? (DaveM)
798 if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) {
799 // Make the buffer size something sensible
805 lpCtx->dwModeWidth = lpCtx->dwWidth;
806 lpCtx->dwModeHeight = lpCtx->dwHeight;
808 // Find best display mode for fullscreen
809 if (glb.bFullscreen || !glb.bPrimary) {
810 dglChooseDisplayMode(lpCtx);
813 // Misc initialisation
814 lpCtx->bCanRender = FALSE; // No rendering allowed yet
815 lpCtx->bSceneStarted = FALSE;
816 lpCtx->bFrameStarted = FALSE;
818 // Detect OS (specifically 'Windows 2000' or 'Windows XP')
821 // NOTE: WinNT not supported
822 ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") );
824 // Test for Fullscreen
825 if (bHaveWin95) { // Problems with fullscreen on Win2K/XP
826 if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) &&
827 (GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight))
829 // Workaround for some apps that crash when going fullscreen.
830 //lpCtx->bFullscreen = TRUE;
836 _gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers);
838 // Check if DirectDraw has already been created by original GLRC (DaveM)
839 if (glb.bDirectDrawPersistant && glb.bDirectDraw) {
840 lpCtx->lpDD4 = glb.lpDD4;
841 IDirectDraw4_AddRef(lpCtx->lpDD4);
842 goto SkipDirectDrawCreate;
845 // Create DirectDraw object
847 hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL);
849 // A non-primary device is to be used.
850 // Force context to be Fullscreen, secondary adaptors can not
851 // be used in a window.
852 hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL);
853 lpCtx->bFullscreen = TRUE;
855 if (FAILED(hResult)) {
856 MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK);
857 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult);
858 nContextError = GLDERR_DDRAW;
859 goto return_with_error;
862 // Query for DX6 IDirectDraw4.
863 hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1,
865 (void**)&lpCtx->lpDD4);
866 if (FAILED(hResult)) {
867 MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK);
868 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult);
869 nContextError = GLDERR_DDRAW;
870 goto return_with_error;
873 // Cache DirectDraw interface for subsequent GLRCs
874 if (glb.bDirectDrawPersistant && !glb.bDirectDraw) {
875 glb.lpDD4 = lpCtx->lpDD4;
876 IDirectDraw4_AddRef(glb.lpDD4);
877 glb.bDirectDraw = TRUE;
879 SkipDirectDrawCreate:
881 // Now we have a DD4 interface we can check for broken cards
882 dglTestForBrokenCards(lpCtx);
884 // Test if primary device can use flipping instead of blitting
885 ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode));
886 ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode);
887 hResult = IDirectDraw4_GetDisplayMode(
890 if (SUCCEEDED(hResult)) {
891 if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) &&
892 (lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) {
893 // We have a fullscreen-size window
895 // OK to use DirectDraw fullscreen mode ?
896 if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) {
897 lpCtx->bFullscreen = TRUE;
898 ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n");
901 // Cache the display mode dimensions
902 lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth;
903 lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight;
906 // Clamp the effective window dimensions to primary surface.
907 // We need to do this for D3D viewport dimensions even if wide
908 // surfaces are supported. This also is a good idea for handling
909 // whacked-out window dimensions passed for non-drawable windows
910 // like Solid Edge. (DaveM)
911 if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth)
912 lpCtx->dwWidth = ddsd2DisplayMode.dwWidth;
913 if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight)
914 lpCtx->dwHeight = ddsd2DisplayMode.dwHeight;
916 // Check for non-RGB desktop resolution
917 if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) {
918 ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported",
919 ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount);
920 nContextError = GLDERR_BPP;
921 goto return_with_error;
923 #endif // _USE_GLD3_WGL
925 ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)",
928 lpCtx->bFullscreen ? "fullscreen" : "windowed");
930 #ifndef _USE_GLD3_WGL
932 ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS));
933 lpCtx->ddCaps.dwSize = sizeof(DDCAPS);
936 IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL);
939 IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps);
942 // If this flag is present then we can't default to Mesa
943 // SW rendering between BeginScene() and EndScene().
944 if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) {
945 ddlogMessage(DDLOG_INFO,
946 "Warning : No 2D allowed during 3D scene.\n");
949 // Query for DX6 Direct3D3 interface
950 hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4,
952 (void**)&lpCtx->lpD3D3);
953 if (FAILED(hResult)) {
954 MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK);
955 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult);
956 nContextError = GLDERR_D3D;
957 goto return_with_error;
961 if (lpCtx->bFullscreen) {
964 // Disable warning popups when in fullscreen mode
965 ddlogWarnOption(FALSE);
967 // Have to release persistant primary surface if fullscreen mode
968 if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
969 RELEASE(glb.lpPrimary4);
970 glb.bDirectDrawPrimary = FALSE;
973 dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT;
975 dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM)
976 hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags);
977 if (FAILED(hResult)) {
978 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult);
979 goto return_with_error;
982 hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4,
988 if (FAILED(hResult)) {
989 ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult);
990 goto return_with_error;
993 // ** The display mode has changed, so dont use MessageBox! **
995 ZeroMemory(&ddsd2, sizeof(ddsd2));
996 ddsd2.dwSize = sizeof(ddsd2);
1001 ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
1002 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
1007 ddsd2.dwBackBufferCount = 1;
1009 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
1010 if (FAILED(hResult)) {
1011 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
1012 nContextError = GLDERR_MEM;
1013 goto return_with_error;
1016 // Render target surface
1017 ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct.
1018 ddscaps2.dwCaps = DDSCAPS_BACKBUFFER;
1019 hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4);
1020 if (FAILED(hResult)) {
1021 ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult);
1022 nContextError = GLDERR_MEM;
1023 goto return_with_error;
1028 ddsd2.dwFlags = DDSD_CAPS;
1029 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
1030 //DDSCAPS_3DDEVICE |
1033 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
1034 if (FAILED(hResult)) {
1035 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
1036 nContextError = GLDERR_MEM;
1037 goto return_with_error;
1040 lpCtx->lpBack4 = NULL;
1045 // OK to enable warning popups in windowed mode
1046 ddlogWarnOption(glb.bMessageBoxWarnings);
1048 dwFlags = DDSCL_NORMAL;
1049 if (glb.bMultiThreaded)
1050 dwFlags |= DDSCL_MULTITHREADED;
1052 dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM)
1053 hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4,
1056 if (FAILED(hResult)) {
1057 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult);
1058 goto return_with_error;
1060 // Has Primary surface already been created for original GLRC ?
1061 // Note this can only be applicable for windowed modes
1062 if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
1063 lpCtx->lpFront4 = glb.lpPrimary4;
1064 IDirectDrawSurface4_AddRef(lpCtx->lpFront4);
1065 // Update the window on the default clipper
1066 IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
1067 IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1068 IDirectDrawClipper_Release(lpddClipper);
1069 goto SkipPrimaryCreate;
1073 ZeroMemory(&ddsd2, sizeof(ddsd2));
1074 ddsd2.dwSize = sizeof(ddsd2);
1075 ddsd2.dwFlags = DDSD_CAPS;
1076 ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1077 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
1078 if (FAILED(hResult)) {
1079 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
1080 nContextError = GLDERR_MEM;
1081 goto return_with_error;
1084 // Cache Primary surface for subsequent GLRCs
1085 // Note this can only be applicable to subsequent windowed modes
1086 if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) {
1087 glb.lpPrimary4 = lpCtx->lpFront4;
1088 IDirectDrawSurface4_AddRef(glb.lpPrimary4);
1089 glb.bDirectDrawPrimary = TRUE;
1093 hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL);
1094 if (FAILED(hResult)) {
1095 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult);
1096 goto return_with_error;
1098 hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1099 if (FAILED(hResult)) {
1100 RELEASE(lpddClipper);
1101 ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult);
1102 goto return_with_error;
1104 hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper);
1105 RELEASE(lpddClipper); // We have finished with it.
1106 if (FAILED(hResult)) {
1107 ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult);
1108 goto return_with_error;
1112 if (bDoubleBuffer) {
1113 // Render target surface
1114 ZeroMemory(&ddsd2, sizeof(ddsd2));
1115 ddsd2.dwSize = sizeof(ddsd2);
1116 ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1117 ddsd2.dwWidth = lpCtx->dwWidth;
1118 ddsd2.dwHeight = lpCtx->dwHeight;
1119 ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE |
1120 DDSCAPS_OFFSCREENPLAIN |
1123 // Reserve the entire desktop size for persistant buffers option
1124 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
1125 ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
1126 ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
1128 // Re-use original back buffer if persistant buffers exist
1129 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4)
1130 hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4);
1132 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL);
1133 if (FAILED(hResult)) {
1134 ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult);
1135 nContextError = GLDERR_MEM;
1136 goto return_with_error;
1138 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4)
1139 IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4);
1141 lpCtx->lpBack4 = NULL;
1146 // Now create the Z-buffer
1148 lpCtx->bStencil = FALSE; // Default to no stencil buffer
1149 if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) {
1150 // Get z-buffer dimensions from the render target
1151 // Setup the surface desc for the z-buffer.
1152 ZeroMemory(&ddsd2, sizeof(ddsd2));
1153 ddsd2.dwSize = sizeof(ddsd2);
1154 ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
1155 ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType;
1156 ddsd2.dwWidth = lpCtx->dwWidth;
1157 ddsd2.dwHeight = lpCtx->dwHeight;
1158 memcpy(&ddsd2.ddpfPixelFormat,
1159 &glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF],
1160 sizeof(DDPIXELFORMAT) );
1162 // Reserve the entire desktop size for persistant buffers option
1163 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
1164 ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
1165 ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
1168 // Create a z-buffer
1169 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4)
1170 hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4);
1172 hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL);
1173 if (FAILED(hResult)) {
1174 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult);
1175 nContextError = GLDERR_MEM;
1176 goto return_with_error;
1178 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4)
1179 IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4);
1180 else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4)
1181 IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4);
1183 // Attach Zbuffer to render target
1184 TRY(IDirectDrawSurface4_AddAttachedSurface(
1185 bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
1187 "dglCreateContext: Attach Zbuffer");
1188 if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) {
1189 lpCtx->bStencil = TRUE;
1190 ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n");
1194 // Clear all back buffers and Z-buffers in case of memory recycling.
1195 ZeroMemory(&ddbltfx, sizeof(ddbltfx));
1196 ddbltfx.dwSize = sizeof(ddbltfx);
1197 IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL,
1198 DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1199 if (lpCtx->lpDepth4)
1200 IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL,
1201 DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
1203 // Now that we have a Z-buffer we can create the 3D device
1204 hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3,
1206 bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
1209 if (FAILED(hResult)) {
1210 ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult);
1211 nContextError = GLDERR_D3D;
1212 goto return_with_error;
1215 // We must do this as soon as the device is created
1216 dglInitStateCaches(lpCtx);
1218 // Obtain the D3D Device Description
1219 D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC);
1220 TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3,
1223 "dglCreateContext: GetCaps failed");
1225 // Choose the relevant description and cache it in the context.
1226 // We will use this description later for caps checking
1227 memcpy( &lpCtx->D3DDevDesc,
1228 glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc,
1229 sizeof(D3DDEVICEDESC));
1231 // Now we can examine the texture formats
1232 if (!dglBuildTextureFormatList(lpCtx->lpDev3)) {
1233 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n");
1234 goto return_with_error;
1237 // Get the pixel format of the back buffer
1238 lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender);
1240 hResult = IDirectDrawSurface4_GetPixelFormat(
1242 &lpCtx->ddpfRender);
1244 hResult = IDirectDrawSurface4_GetPixelFormat(
1246 &lpCtx->ddpfRender);
1248 if (FAILED(hResult)) {
1249 ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult);
1250 goto return_with_error;
1252 // Find a pixel packing function suitable for this surface
1253 pxClassifyPixelFormat(&lpCtx->ddpfRender,
1255 &lpCtx->fnUnpackFunc,
1256 &lpCtx->fnPackSpanFunc);
1259 hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL);
1260 if (FAILED(hResult)) {
1261 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult);
1262 goto return_with_error;
1265 hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1266 if (FAILED(hResult)) {
1267 ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult);
1268 goto return_with_error;
1271 // Initialise the viewport
1272 // Note screen coordinates are used for viewport clipping since D3D
1273 // transform operations are not used in the GLD CAD driver. (DaveM)
1274 inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth;
1276 lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport);
1277 lpCtx->d3dViewport.dwX = 0;
1278 lpCtx->d3dViewport.dwY = 0;
1279 lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth;
1280 lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight;
1281 lpCtx->d3dViewport.dvClipX = 0; // -1.0f;
1282 lpCtx->d3dViewport.dvClipY = 0; // inv_aspect;
1283 lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f;
1284 lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect;
1285 lpCtx->d3dViewport.dvMinZ = 0.0f;
1286 lpCtx->d3dViewport.dvMaxZ = 1.0f;
1287 TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2");
1289 hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1290 if (FAILED(hResult)) {
1291 ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult);
1292 goto return_with_error;
1295 lpCtx->dwBPP = lpPFD->cColorBits;
1296 lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF;
1298 // Set last texture to NULL
1299 for (i=0; i<MAX_TEXTURE_UNITS; i++) {
1300 lpCtx->ColorOp[i] = D3DTOP_DISABLE;
1301 lpCtx->AlphaOp[i] = D3DTOP_DISABLE;
1302 lpCtx->tObj[i] = NULL;
1305 // Default to perspective correct texture mapping
1306 dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp");
1308 // Set the default culling mode
1309 lpCtx->cullmode = D3DCULL_NONE;
1310 dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode");
1313 dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable");
1314 // Disable subpixel correction
1315 // dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable");
1316 // Disable dithering
1317 dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable");
1319 // Initialise the primitive caches
1320 // lpCtx->dwNextLineVert = 0;
1321 // lpCtx->dwNextTriVert = 0;
1323 // Init the global texture palette
1324 lpCtx->lpGlobalPalette = NULL;
1326 // Init the HW/SW usage counters
1327 // lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L;
1330 // Create two D3D vertex buffers.
1331 // One will hold the pre-transformed data with the other one
1332 // being used to hold the post-transformed & clipped verts.
1334 #if 0 // never used (DaveM)
1335 vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
1336 vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY;
1337 if (glb.bHardware == FALSE)
1338 vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
1339 vbufdesc.dwNumVertices = 32768; // For the time being
1341 // Source vertex buffer
1342 vbufdesc.dwFVF = DGL_LVERTEX;
1343 hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL);
1344 if (FAILED(hResult)) {
1345 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult);
1346 goto return_with_error;
1349 // Destination vertex buffer
1350 vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2);
1351 hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL);
1352 if(FAILED(hResult)) {
1353 ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult);
1354 goto return_with_error;
1358 #endif _USE_GLD3_WGL
1361 // Now create the Mesa context
1364 // Create the Mesa visual
1365 if (lpPFD->cDepthBits)
1367 if (lpPFD->cStencilBits)
1369 if (lpPFD->cAlphaBits) {
1373 if (lpPFD->dwFlags & PFD_DOUBLEBUFFER)
1375 // lpCtx->EmulateSingle =
1376 // (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
1378 #ifdef _USE_GLD3_WGL
1379 lpCtx->glVis = _mesa_create_visual(
1380 bDouble, /* double buffer */
1388 lpPFD->cAccumRedBits, // accum bits
1389 lpPFD->cAccumGreenBits, // accum bits
1390 lpPFD->cAccumBlueBits, // accum bits
1391 lpPFD->cAccumAlphaBits, // accum alpha bits
1394 #else // _USE_GLD3_WGL
1395 lpCtx->glVis = (*mesaFuncs.gl_create_visual)(
1396 GL_TRUE, // RGB mode
1397 bAlphaSW, // Is an alpha buffer required?
1398 bDouble, // Is an double-buffering required?
1400 dwDepthBits, // depth_size
1401 dwStencilBits, // stencil_size
1402 lpPFD->cAccumBits, // accum_size
1403 0, // colour-index bits
1404 lpPFD->cRedBits, // Red bit count
1405 lpPFD->cGreenBits, // Green bit count
1406 lpPFD->cBlueBits, // Blue bit count
1407 dwAlphaBits // Alpha bit count
1409 #endif // _USE_GLD3_WGL
1411 if (lpCtx->glVis == NULL) {
1412 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n");
1413 goto return_with_error;
1416 #ifdef _USE_GLD3_WGL
1417 lpCtx->glCtx = _mesa_create_context(API_OPENGL, lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE);
1419 // Create the Mesa context
1420 lpCtx->glCtx = (*mesaFuncs.gl_create_context)(
1421 lpCtx->glVis, // Mesa visual
1422 NULL, // share list context
1423 (void *)lpCtx, // Pointer to our driver context
1424 GL_TRUE // Direct context flag
1426 #endif // _USE_GLD3_WGL
1428 if (lpCtx->glCtx == NULL) {
1429 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n");
1430 goto return_with_error;
1433 // Create the Mesa framebuffer
1434 #ifdef _USE_GLD3_WGL
1435 lpCtx->glBuffer = _mesa_create_framebuffer(
1437 lpCtx->glVis->depthBits > 0,
1438 lpCtx->glVis->stencilBits > 0,
1439 lpCtx->glVis->accumRedBits > 0,
1443 lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis);
1444 #endif // _USE_GLD3_WGL
1446 if (lpCtx->glBuffer == NULL) {
1447 ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n");
1448 goto return_with_error;
1451 #ifdef _USE_GLD3_WGL
1452 // Init Mesa internals
1453 _swrast_CreateContext( lpCtx->glCtx );
1454 _vbo_CreateContext( lpCtx->glCtx );
1455 _tnl_CreateContext( lpCtx->glCtx );
1456 _swsetup_CreateContext( lpCtx->glCtx );
1458 _gldDriver.InitialiseMesa(lpCtx);
1460 lpCtx->glCtx->imports.warning = _gld_mesa_warning;
1461 lpCtx->glCtx->imports.fatal = _gld_mesa_fatal;
1464 // Tell Mesa how many texture stages we have
1465 glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures;
1466 // Only use as many Units as the spec requires
1467 if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS)
1468 glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS;
1469 lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures;
1470 ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures);
1472 // Set the max texture size.
1473 // NOTE: clamped to a max of 1024 for extra performance!
1474 lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024;
1476 // Texture resize takes place elsewhere. KH
1477 // NOTE: This was added to workaround an issue with the Intel app.
1479 lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize;
1481 lpCtx->glCtx->Const.MaxTextureSize = 1024;
1483 lpCtx->glCtx->Const.MaxDrawBuffers = 1;
1485 // Setup the Display Driver pointers
1486 dglSetupDDPointers(lpCtx->glCtx);
1488 // Initialise all the Direct3D renderstates
1489 dglInitStateD3D(lpCtx->glCtx);
1492 // Signal a reload of texture state on next glBegin
1493 lpCtx->m_texHandleValid = FALSE;
1494 lpCtx->m_mtex = FALSE;
1495 lpCtx->m_texturing = FALSE;
1497 // Set default texture unit state
1498 // dglSetTexture(lpCtx, 0, NULL);
1499 // dglSetTexture(lpCtx, 1, NULL);
1503 // Set the global texture palette to default values.
1506 // Clear the entire palette
1507 ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256);
1509 // Fill the palette with a default colour.
1510 // A garish colour is used to catch bugs. Here Magenta is used.
1511 for (i=0; i < 256; i++) {
1514 ppe[i].peBlue = 255;
1517 RELEASE(lpCtx->lpGlobalPalette);
1519 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette)
1520 hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette);
1522 hResult = IDirectDraw4_CreatePalette(
1524 DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256,
1526 &(lpCtx->lpGlobalPalette),
1528 if (FAILED(hResult)) {
1529 ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult);
1530 lpCtx->lpGlobalPalette = NULL;
1531 goto return_with_error;
1533 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette)
1534 IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette);
1536 #endif // _USE_GLD3_WGL
1538 // ** If we have made it to here then we can enable rendering **
1539 lpCtx->bCanRender = TRUE;
1541 // ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n");
1544 // Release serialized access
1545 if (glb.bMultiThreaded)
1546 LeaveCriticalSection(&CriticalSection);
1552 // Clean up before returning.
1553 // This is critical for secondary devices.
1555 lpCtx->bCanRender = FALSE;
1557 #ifdef _USE_GLD3_WGL
1558 // Destroy the Mesa context
1559 if (lpCtx->glBuffer)
1560 _mesa_destroy_framebuffer(lpCtx->glBuffer);
1562 _mesa_destroy_context(lpCtx->glCtx);
1564 _mesa_destroy_visual(lpCtx->glVis);
1566 // Destroy driver data
1567 _gldDriver.DestroyDrawable(lpCtx);
1569 // Destroy the Mesa context
1570 if (lpCtx->glBuffer)
1571 (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
1573 (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
1575 (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
1577 RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer
1578 RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer
1580 if (lpCtx->lpViewport3) {
1581 if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1582 RELEASE(lpCtx->lpViewport3);
1583 lpCtx->lpViewport3 = NULL;
1586 RELEASE(lpCtx->lpDev3);
1587 if (lpCtx->lpDepth4) {
1589 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
1591 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
1592 RELEASE(lpCtx->lpDepth4);
1593 lpCtx->lpDepth4 = NULL;
1595 RELEASE(lpCtx->lpBack4);
1596 RELEASE(lpCtx->lpFront4);
1598 if (lpCtx->bFullscreen) {
1599 IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
1600 IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
1602 RELEASE(lpCtx->lpD3D3);
1603 RELEASE(lpCtx->lpDD4);
1604 RELEASE(lpCtx->lpDD1);
1605 #endif // _USE_GLD3_WGL
1607 lpCtx->bAllocated = FALSE;
1610 // Release serialized access
1611 if (glb.bMultiThreaded)
1612 LeaveCriticalSection(&CriticalSection);
1617 #undef DDLOG_CRITICAL_OR_WARN
1620 // ***********************************************************************
1622 HGLRC dglCreateContext(
1624 const DGL_pixelFormat *lpPF)
1629 static BOOL bWarnOnce = TRUE;
1630 DWORD dwThreadId = GetCurrentThreadId();
1639 // Is context state ready ?
1643 ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId);
1645 // Find next free context.
1646 // Also ensure that only one Fullscreen context is created at any one time.
1647 hGLRC = 0; // Default to Not Found
1648 for (i=0; i<DGL_MAX_CONTEXTS; i++) {
1649 if (ctxlist[i].bAllocated) {
1650 if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
1653 hGLRC = (HGLRC)(i+1);
1658 // Bail if no GLRC was found
1662 // Set the context pointer
1663 lpCtx = dglGetContextAddress(hGLRC);
1664 // Make sure that context is zeroed before we do anything.
1665 // MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
1666 // even though only one context is ever used by the app, so keep it clean. (DaveM)
1667 ZeroMemory(lpCtx, sizeof(DGL_ctx));
1668 lpCtx->bAllocated = TRUE;
1669 // Flag that buffers need creating on next wglMakeCurrent call.
1670 lpCtx->bHasBeenCurrent = FALSE;
1671 lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format
1672 lpCtx->bCanRender = FALSE;
1674 // Create all the internal resources here, not in dglMakeCurrent().
1675 // We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM)
1676 // We now try context allocations twice, first with video memory,
1677 // then again with system memory. This is similar to technique
1678 // used for dglWglResizeBuffers(). (DaveM)
1679 if (lpCtx->bHasBeenCurrent == FALSE) {
1680 if (!dglCreateContextBuffers(a, lpCtx, FALSE)) {
1681 if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) {
1683 switch (nContextError) {
1684 case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break;
1685 case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break;
1686 case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break;
1687 case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break;
1688 default: strcpy(szMsg, "");
1691 MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING);
1693 // Only need to try again if memory error
1694 if (nContextError == GLDERR_MEM) {
1695 ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory");
1698 ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed");
1704 // Now that we have a hWnd, we can intercept the WindowProc.
1707 // Only hook individual window handler once if not hooked before.
1708 lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC);
1709 if (lpfnWndProc != (LONG)dglWndProc) {
1710 lpCtx->lpfnWndProc = lpfnWndProc;
1711 SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc);
1713 // Find the parent window of the app too.
1714 if (glb.hWndActive == NULL) {
1715 while (hWnd != NULL) {
1716 glb.hWndActive = hWnd;
1717 hWnd = GetParent(hWnd);
1719 // Hook the parent window too.
1720 lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC);
1721 if (glb.hWndActive == lpCtx->hWnd)
1722 glb.lpfnWndProc = lpCtx->lpfnWndProc;
1723 else if (lpfnWndProc != (LONG)dglWndProc)
1724 glb.lpfnWndProc = lpfnWndProc;
1725 if (glb.lpfnWndProc)
1726 SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc);
1730 ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC);
1735 // ***********************************************************************
1736 // Make a DirectGL context current
1737 // Used by wgl functions and dgl functions
1738 BOOL dglMakeCurrent(
1745 BOOL bNeedResize = FALSE;
1746 BOOL bWindowChanged, bContextChanged;
1747 LPDIRECTDRAWCLIPPER lpddClipper;
1748 DWORD dwThreadId = GetCurrentThreadId();
1755 // Is context state ready ?
1759 context = (int)b; // This is as a result of STRICT!
1760 ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId);
1762 // If the HGLRC is NULL then make no context current;
1763 // Ditto if the HDC is NULL either. (DaveM)
1764 if (context == 0 || a == 0) {
1765 // Corresponding Mesa operation
1766 #ifdef _USE_GLD3_WGL
1767 _mesa_make_current(NULL, NULL);
1769 (*mesaFuncs.gl_make_current)(NULL, NULL);
1771 dglSetCurrentContext(0);
1775 // Make sure the HGLRC is in range
1776 if ((context > DGL_MAX_CONTEXTS) || (context < 0)) {
1777 ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n");
1781 // Find address of context and make sure that it has been allocated
1782 lpCtx = dglGetContextAddress(b);
1783 if (!lpCtx->bAllocated) {
1784 ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n");
1786 return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
1790 // Serialize access to DirectDraw or DDS operations
1791 if (glb.bMultiThreaded)
1792 EnterCriticalSection(&CriticalSection);
1795 // Check if window has changed
1796 hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd;
1797 bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE;
1798 bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE;
1800 // If the window has changed, make sure the clipper is updated. (DaveM)
1801 if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) {
1803 #ifndef _USE_GLD3_WGL
1804 IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
1805 IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
1806 IDirectDrawClipper_Release(lpddClipper);
1807 #endif // _USE_GLD3_WGL
1810 // Make sure hDC and hWnd is current. (DaveM)
1811 // Obtain the dimensions of the rendering window
1812 lpCtx->hDC = a; // Cache DC
1814 hWndLastActive = hWnd;
1816 // Check for non-window DC = memory DC ?
1818 if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) {
1819 ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n");
1820 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
1823 else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
1824 ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n");
1825 SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
1827 // Check if buffers need to be re-sized;
1828 // If so, wait until Mesa GL stuff is setup before re-sizing;
1829 if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left ||
1830 lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top)
1833 // Now we can update our globals
1834 dglSetCurrentContext(b);
1836 // Corresponding Mesa operation
1837 #ifdef _USE_GLD3_WGL
1838 _mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer);
1839 lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL);
1841 // Resize buffers (Note Mesa GL needs to be setup beforehand);
1842 // Resize Mesa internal buffer too via glViewport() command,
1843 // which subsequently calls dglWglResizeBuffers() too.
1844 lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1845 lpCtx->bHasBeenCurrent = TRUE;
1848 (*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer);
1850 dglSetupDDPointers(lpCtx->glCtx);
1852 // Insure DirectDraw surfaces fit current window DC
1854 // Resize buffers (Note Mesa GL needs to be setup beforehand);
1855 // Resize Mesa internal buffer too via glViewport() command,
1856 // which subsequently calls dglWglResizeBuffers() too.
1857 (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1858 lpCtx->bHasBeenCurrent = TRUE;
1860 #endif // _USE_GLD3_WGL
1861 ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight);
1863 // We have to clear D3D back buffer and render state if emulated front buffering
1864 // for different window (but not context) like in Solid Edge.
1865 if (glb.bDirectDrawPersistant && glb.bPersistantBuffers
1866 && (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) {
1867 #ifdef _USE_GLD3_WGL
1868 // IDirect3DDevice8_EndScene(lpCtx->pDev);
1869 // lpCtx->bSceneStarted = FALSE;
1870 lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
1871 GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1873 IDirect3DDevice3_EndScene(lpCtx->lpDev3);
1874 lpCtx->bSceneStarted = FALSE;
1875 dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
1876 GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1877 #endif // _USE_GLD3_WGL
1880 // The first time we call MakeCurrent we set the initial viewport size
1881 if (lpCtx->bHasBeenCurrent == FALSE)
1882 #ifdef _USE_GLD3_WGL
1883 lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1885 (*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
1886 #endif // _USE_GLD3_WGL
1887 lpCtx->bHasBeenCurrent = TRUE;
1890 // Release serialized access
1891 if (glb.bMultiThreaded)
1892 LeaveCriticalSection(&CriticalSection);
1898 // ***********************************************************************
1900 BOOL dglDeleteContext(
1904 DWORD dwThreadId = GetCurrentThreadId();
1907 #if 0 // We have enough trouble throwing exceptions as it is... (DaveM)
1913 // Is context state ready ?
1917 ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId);
1919 // Make sure the HGLRC is in range
1920 if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) {
1921 ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n");
1925 // Make sure context is valid
1926 lpCtx = dglGetContextAddress(a);
1927 if (!lpCtx->bAllocated) {
1928 ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a);
1930 return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
1933 // Make sure context is de-activated
1934 if (a == dglGetCurrentContext()) {
1935 ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a);
1936 dglMakeCurrent(NULL, NULL);
1940 // Serialize access to DirectDraw or DDS operations
1941 if (glb.bMultiThreaded)
1942 EnterCriticalSection(&CriticalSection);
1945 // We are about to destroy all Direct3D objects.
1946 // Therefore we must disable rendering
1947 lpCtx->bCanRender = FALSE;
1949 // This exception handler was installed to catch some
1950 // particularly nasty apps. Console apps that call exit()
1951 // fall into this catagory (i.e. Win32 Glut).
1953 // VC cannot successfully implement multiple exception handlers
1954 // if more than one exception occurs. Therefore reverting back to
1955 // single exception handler as Keith originally had it. (DaveM)
1957 #define WARN_MESSAGE(p) strcpy(argstr, (#p));
1958 #define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p);
1961 #ifdef _USE_GLD3_WGL
1962 WARN_MESSAGE(gl_destroy_framebuffer);
1963 if (lpCtx->glBuffer)
1964 _mesa_destroy_framebuffer(lpCtx->glBuffer);
1965 WARN_MESSAGE(gl_destroy_context);
1967 _mesa_destroy_context(lpCtx->glCtx);
1968 WARN_MESSAGE(gl_destroy_visual);
1970 _mesa_destroy_visual(lpCtx->glVis);
1972 _gldDriver.DestroyDrawable(lpCtx);
1974 // Destroy the Mesa context
1975 WARN_MESSAGE(gl_destroy_framebuffer);
1976 if (lpCtx->glBuffer)
1977 (*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
1978 WARN_MESSAGE(gl_destroy_context);
1980 (*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
1981 WARN_MESSAGE(gl_destroy_visual);
1983 (*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
1985 SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer
1986 SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer
1988 // Delete the global palette
1989 SAFE_RELEASE(lpCtx->lpGlobalPalette);
1992 if (lpCtx->lpViewport3) {
1993 if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
1994 SAFE_RELEASE(lpCtx->lpViewport3);
1995 lpCtx->lpViewport3 = NULL;
1998 SAFE_RELEASE(lpCtx->lpDev3);
1999 if (lpCtx->lpDepth4) {
2001 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
2003 IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
2004 SAFE_RELEASE(lpCtx->lpDepth4);
2005 lpCtx->lpDepth4 = NULL;
2007 SAFE_RELEASE(lpCtx->lpBack4);
2008 SAFE_RELEASE(lpCtx->lpFront4);
2009 if (lpCtx->bFullscreen) {
2010 IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
2011 IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
2013 SAFE_RELEASE(lpCtx->lpD3D3);
2014 SAFE_RELEASE(lpCtx->lpDD4);
2015 SAFE_RELEASE(lpCtx->lpDD1);
2016 #endif // _ULSE_GLD3_WGL
2019 __except(EXCEPTION_EXECUTE_HANDLER) {
2020 ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr);
2023 // Restore the window message handler because this context may be used
2024 // again by another window with a *different* message handler. (DaveM)
2025 if (lpCtx->lpfnWndProc) {
2026 SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc);
2027 lpCtx->lpfnWndProc = (LONG)NULL;
2030 lpCtx->bAllocated = FALSE; // This context is now free for use
2033 // Release serialized access
2034 if (glb.bMultiThreaded)
2035 LeaveCriticalSection(&CriticalSection);
2041 // ***********************************************************************
2043 BOOL dglSwapBuffers(
2046 RECT rSrcRect; // Source rectangle
2047 RECT rDstRect; // Destination rectangle
2055 // DWORD dwThreadId = GetCurrentThreadId();
2056 HGLRC hGLRC = dglGetCurrentContext();
2057 DGL_ctx *lpCtx = dglGetContextAddress(hGLRC);
2060 HDC hDCAux; // for memory DC
2061 int x,y,w,h; // for memory DC BitBlt
2063 #if 0 // Perhaps not a good idea. Called too often. KH
2070 return TRUE; //FALSE; // No current context
2073 if (!lpCtx->bCanRender) {
2074 // Don't return false else some apps will bail.
2079 if (hDC != lpCtx->hDC) {
2080 ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC);
2081 hWnd = WindowFromDC(hDC);
2084 #ifndef _USE_GLD3_WGL
2085 // Ensure that the surfaces exist before we tell
2086 // the device to render to them.
2087 IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4);
2089 // Make sure that the vertex caches have been emptied
2090 // dglStateChange(lpCtx);
2092 // Some OpenGL programs don't issue a glFinish - check for it here.
2093 if (lpCtx->bSceneStarted) {
2094 IDirect3DDevice3_EndScene(lpCtx->lpDev3);
2095 lpCtx->bSceneStarted = FALSE;
2100 // If the calling app is not active then we don't need to Blit/Flip.
2101 // We can therefore simply return TRUE.
2102 if (!glb.bAppActive)
2104 // Addendum: This is WRONG! We should bail if the app is *minimized*,
2105 // not merely if the app is just plain 'not active'.
2106 // KeithH, 27/May/2000.
2109 // Check for non-window DC = memory DC ?
2111 if (GetClipBox(hDC, &rSrcRect) == ERROR)
2113 // Use GDI BitBlt instead from compatible DirectDraw DC
2116 w = rSrcRect.right - rSrcRect.left;
2117 h = rSrcRect.bottom - rSrcRect.top;
2119 // Ack. DX8 does not have a GetDC() function...
2120 // TODO: Defer to DX7 or DX9 drivers... (DaveM)
2124 // Bail if window client region is not drawable, like in Solid Edge
2125 if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect))
2129 // Serialize access to DirectDraw or DDS operations
2130 if (glb.bMultiThreaded)
2131 EnterCriticalSection(&CriticalSection);
2134 #ifdef _USE_GLD3_WGL
2135 // Notify Mesa of impending swap, so Mesa can flush internal buffers.
2136 _mesa_notifySwapBuffers(lpCtx->glCtx);
2137 // Now perform driver buffer swap
2138 _gldDriver.SwapBuffers(lpCtx, hDC, hWnd);
2140 if (lpCtx->bFullscreen) {
2141 // Sync with retrace if required
2142 if (glb.bWaitForRetrace) {
2143 IDirectDraw4_WaitForVerticalBlank(
2145 DDWAITVB_BLOCKBEGIN,
2149 // Perform the fullscreen flip
2150 TRY(IDirectDrawSurface4_Flip(
2154 "dglSwapBuffers: Flip");
2156 // Calculate current window position and size
2158 ClientToScreen(hWnd, &pt);
2159 GetClientRect(hWnd, &rDstRect);
2160 if (rDstRect.right > lpCtx->dwModeWidth)
2161 rDstRect.right = lpCtx->dwModeWidth;
2162 if (rDstRect.bottom > lpCtx->dwModeHeight)
2163 rDstRect.bottom = lpCtx->dwModeHeight;
2164 OffsetRect(&rDstRect, pt.x, pt.y);
2165 rSrcRect.left = rSrcRect.top = 0;
2166 rSrcRect.right = lpCtx->dwWidth;
2167 rSrcRect.bottom = lpCtx->dwHeight;
2168 if (rSrcRect.right > lpCtx->dwModeWidth)
2169 rSrcRect.right = lpCtx->dwModeWidth;
2170 if (rSrcRect.bottom > lpCtx->dwModeHeight)
2171 rSrcRect.bottom = lpCtx->dwModeHeight;
2173 if (glb.bWaitForRetrace) {
2174 // Sync the blit to the vertical retrace
2175 ZeroMemory(&bltFX, sizeof(bltFX));
2176 bltFX.dwSize = sizeof(bltFX);
2177 bltFX.dwDDFX = DDBLTFX_NOTEARING;
2178 dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX;
2181 dwBlitFlags = DDBLT_WAIT;
2185 // Perform the actual blit
2186 TRY(IDirectDrawSurface4_Blt(
2189 lpCtx->lpBack4, // Blit source
2193 "dglSwapBuffers: Blt");
2195 #endif // _USE_GLD3_WGL
2198 // Release serialized access
2199 if (glb.bMultiThreaded)
2200 LeaveCriticalSection(&CriticalSection);
2203 // TODO: Re-instate rendering bitmap snapshot feature??? (DaveM)
2205 // Render frame is completed
2206 ValidateRect(hWnd, NULL);
2207 lpCtx->bFrameStarted = FALSE;
2212 // ***********************************************************************