📄 dglcontext.c
字号:
// Search for DGL context matching window handle
for (i=0; i<DGL_MAX_CONTEXTS; i++) {
if (ctxlist[i].hWnd == hwnd) {
lpCtx = &ctxlist[i];
lpfnWndProc = lpCtx->lpfnWndProc;
break;
}
}
// Not one of ours...
if (!lpfnWndProc)
return DefWindowProc(hwnd, msg, wParam, lParam);
// Intercept messages amd process *before* passing on to window
switch (msg) {
#ifdef _USE_GLD3_WGL
case WM_DISPLAYCHANGE:
glb.bPixelformatsDirty = TRUE;
break;
#endif
case WM_ACTIVATEAPP:
glb.bAppActive = (BOOL)wParam;
ddlogPrintf(DDLOG_INFO, "Calling app has been %s", glb.bAppActive ? "activated" : "de-activated");
break;
case WM_ERASEBKGND:
// Eat the GDI erase event for the GL window
if (!lpCtx || !lpCtx->bHasBeenCurrent)
break;
lpCtx->bGDIEraseBkgnd = TRUE;
return TRUE;
case WM_PAINT:
// Eat the invalidated update region if render scene is in progress
if (!lpCtx || !lpCtx->bHasBeenCurrent)
break;
if (lpCtx->bFrameStarted) {
if (GetUpdateRect(hwnd, &rect, FALSE)) {
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
ValidateRect(hwnd, &rect);
return TRUE;
}
}
break;
}
// Call the appropriate window message handler
rc = CallWindowProc((WNDPROC)lpfnWndProc, hwnd, msg, wParam, lParam);
// Intercept messages and process *after* passing on to window
switch (msg) {
case WM_QUIT:
case WM_DESTROY:
bQuit = TRUE;
if (lpCtx && lpCtx->bAllocated) {
ddlogPrintf(DDLOG_WARN, "WM_DESTROY detected for HWND=%X, HDC=%X, HGLRC=%d", hwnd, lpCtx->hDC, i+1);
dglDeleteContext((HGLRC)(i+1));
}
break;
#if 0
case WM_SIZE:
// Resize surfaces to fit window but not viewport (in case app did not bother)
if (!lpCtx || !lpCtx->bHasBeenCurrent)
break;
w = LOWORD(lParam);
h = HIWORD(lParam);
if (lpCtx->dwWidth < w || lpCtx->dwHeight < h) {
if (!dglWglResizeBuffers(lpCtx->glCtx, TRUE))
dglWglResizeBuffers(lpCtx->glCtx, FALSE);
}
break;
#endif
}
// If the main window is quitting, then so should we...
if (bMain && bQuit) {
ddlogPrintf(DDLOG_SYSTEM, "shutting down after WM_DESTROY detected for main HWND=%X", hwnd);
dglDeleteContextState();
dglExitDriver();
}
return rc;
}
// ***********************************************************************
// Driver Window message handler
static LONG __stdcall GLD_EventWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
switch (msg) {
// May be sent by splash screen dialog on exit
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_ACTIVE && glb.hWndActive) {
SetForegroundWindow(glb.hWndActive);
return 0;
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ***********************************************************************
// Intercepted Keyboard handler for detecting hot keys.
LRESULT CALLBACK dglKeyProc(
int code,
WPARAM wParam,
LPARAM lParam)
{
HWND hWnd, hWndFrame;
HGLRC hGLRC = NULL;
DGL_ctx* lpCtx = NULL;
int cmd = 0, dx1 = 0, dx2 = 0, i;
static BOOL bAltPressed = FALSE;
static BOOL bCtrlPressed = FALSE;
static BOOL bShiftPressed = FALSE;
RECT r, rf, rc;
POINT pt;
BOOL bForceReshape = FALSE;
return CallNextHookEx(hKeyHook, code, wParam, lParam);
}
// ***********************************************************************
HWND hWndMatch;
// Window handle enumeration procedure.
BOOL CALLBACK dglEnumChildProc(
HWND hWnd,
LPARAM lParam)
{
RECT rect;
// Find window handle with matching client rect.
GetClientRect(hWnd, &rect);
if (EqualRect(&rect, (RECT*)lParam)) {
hWndMatch = hWnd;
return FALSE;
}
// Continue with next child window.
return TRUE;
}
// ***********************************************************************
// Find window handle with matching client rect.
HWND dglFindWindowRect(
RECT* pRect)
{
hWndMatch = NULL;
EnumChildWindows(GetForegroundWindow(), dglEnumChildProc, (LPARAM)pRect);
return hWndMatch;
}
// ***********************************************************************
#ifndef _USE_GLD3_WGL
void dglChooseDisplayMode(
DGL_ctx *lpCtx)
{
// Note: Choose an exact match if possible.
int i;
DWORD area;
DWORD bestarea;
DDSURFACEDESC2 *lpDDSD = NULL; // Mode list pointer
DDSURFACEDESC2 *lpBestDDSD = NULL; // Pointer to best
lpDDSD = glb.lpDisplayModes;
for (i=0; i<glb.nDisplayModeCount; i++, lpDDSD++) {
if ((lpDDSD->dwWidth == lpCtx->dwWidth) &&
(lpDDSD->dwHeight == lpCtx->dwHeight))
goto matched; // Mode has been exactly matched
// Choose modes that are larger in both dimensions than
// the window, but smaller in area than the current best.
if ( (lpDDSD->dwWidth >= lpCtx->dwWidth) &&
(lpDDSD->dwHeight >= lpCtx->dwHeight))
{
if (lpBestDDSD == NULL) {
lpBestDDSD = lpDDSD;
bestarea = lpDDSD->dwWidth * lpDDSD->dwHeight;
continue;
}
area = lpDDSD->dwWidth * lpDDSD->dwHeight;
if (area < bestarea) {
lpBestDDSD = lpDDSD;
bestarea = area;
}
}
}
// Safety check
if (lpBestDDSD == NULL) {
ddlogMessage(DDLOG_CRITICAL, "dglChooseDisplayMode");
return;
}
lpCtx->dwModeWidth = lpBestDDSD->dwWidth;
lpCtx->dwModeHeight = lpBestDDSD->dwHeight;
matched:
ddlogPrintf(DDLOG_INFO, "Matched (%ldx%ld) to (%ldx%ld)",
lpCtx->dwWidth, lpCtx->dwHeight, lpCtx->dwModeWidth, lpCtx->dwModeHeight);
}
#endif // _USE_GLD3_WGL
// ***********************************************************************
static BOOL IsDevice(
DWORD *lpDeviceIdList,
DWORD dwDeviceId,
int count)
{
int i;
for (i=0; i<count; i++)
if (dwDeviceId == lpDeviceIdList[i])
return TRUE;
return FALSE;
}
// ***********************************************************************
void dglTestForBrokenCards(
DGL_ctx *lpCtx)
{
#ifndef _GLD3
DDDEVICEIDENTIFIER dddi; // DX6 device identifier
// Sanity check.
if (lpCtx == NULL) {
// Testing for broken cards is sensitive area, so we don't want
// anything saying "broken cards" in the error message. ;)
ddlogMessage(DDLOG_ERROR, "Null context passed to TFBC\n");
return;
}
if (lpCtx->lpDD4 == NULL) {
// Testing for broken cards is sensitive area, so we don't want
// anything saying "broken cards" in the error message. ;)
ddlogMessage(DDLOG_ERROR, "Null DD4 passed to TFBC\n");
return;
}
// Microsoft really fucked up with the GetDeviceIdentifier function
// on Windows 2000, since it locks up on stock driers on the CD. Updated
// drivers from vendors appear to work, but we can't identify the drivers
// without this function!!! For now we skip these tests on Windows 2000.
if ((GetVersion() & 0x80000000UL) == 0)
return;
// Obtain device info
if (FAILED(IDirectDraw4_GetDeviceIdentifier(lpCtx->lpDD4, &dddi, 0)))
return;
// Useful info. Log it.
ddlogPrintf(DDLOG_INFO, "DirectDraw: VendorId=0x%x, DeviceId=0x%x", dddi.dwVendorId, dddi.dwDeviceId);
// Vendor 1: ATI
if (dddi.dwVendorId == VENDORID_ATI) {
// Test A: ATI Rage PRO
if (IsDevice(devATIRagePro, dddi.dwDeviceId, sizeof(devATIRagePro)))
glb.bUseMipmaps = FALSE;
// Test B: ATI Rage II+
if (IsDevice(devATIRageIIplus, dddi.dwDeviceId, sizeof(devATIRageIIplus)))
glb.bEmulateAlphaTest = TRUE;
}
// Vendor 2: Matrox
if (dddi.dwVendorId == 0x102B) {
// Test: Matrox G400 stencil buffer support does not work for AutoCAD
if (dddi.dwDeviceId == 0x0525) {
lpCtx->lpPF->pfd.cStencilBits = 0;
if (lpCtx->lpPF->iZBufferPF != -1) {
glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitDepth = 0;
glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwStencilBitMask = 0;
glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags &= ~DDPF_STENCILBUFFER;
}
}
}
#endif // _GLD3
}
// ***********************************************************************
BOOL dglCreateContextBuffers(
HDC a,
DGL_ctx *lpCtx,
BOOL bFallback)
{
HRESULT hResult;
int i;
// HGLRC hGLRC;
// DGL_ctx* lpCtx;
#ifndef _USE_GLD3_WGL
DWORD dwFlags;
DDSURFACEDESC2 ddsd2;
DDSCAPS2 ddscaps2;
LPDIRECTDRAWCLIPPER lpddClipper;
D3DDEVICEDESC D3DHWDevDesc; // Direct3D Hardware description
D3DDEVICEDESC D3DHELDevDesc; // Direct3D Hardware Emulation Layer
#endif // _USE_GLD3_WGL
float inv_aspect;
GLenum bDoubleBuffer; // TRUE if double buffer required
GLenum bDepthBuffer; // TRUE if depth buffer required
const PIXELFORMATDESCRIPTOR *lpPFD = &lpCtx->lpPF->pfd;
// Vars for Mesa visual
DWORD dwDepthBits = 0;
DWORD dwStencilBits = 0;
DWORD dwAlphaBits = 0;
DWORD bAlphaSW = GL_FALSE;
DWORD bDouble = GL_FALSE;
DDSURFACEDESC2 ddsd2DisplayMode;
BOOL bFullScrnWin = FALSE; // fullscreen-size window ?
DDBLTFX ddbltfx;
DWORD dwMemoryType = (bFallback) ? DDSCAPS_SYSTEMMEMORY : glb.dwMemoryType;
BOOL bBogusWindow = FALSE; // non-drawable window ?
DWORD dwColorRef = 0; // GDI background color
RECT rcDst; // GDI window rect
POINT pt; // GDI window point
// Palette used for creating default global palette
PALETTEENTRY ppe[256];
#ifndef _USE_GLD3_WGL
// Vertex buffer description. Used for creation of vertex buffers
D3DVERTEXBUFFERDESC vbufdesc;
#endif // _USE_GLD3_WGL
#define DDLOG_CRITICAL_OR_WARN (bFallback ? DDLOG_CRITICAL : DDLOG_WARN)
ddlogPrintf(DDLOG_SYSTEM, "dglCreateContextBuffers for HDC=%X", a);
nContextError = GLDERR_NONE;
#ifdef GLD_THREADS
// Serialize access to DirectDraw object creation or DDS start
if (glb.bMultiThreaded)
EnterCriticalSection(&CriticalSection);
#endif
// Check for back buffer
bDoubleBuffer = GL_TRUE; //(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? GL_TRUE : GL_FALSE;
// Since we always do back buffering, check if we emulate front buffering
lpCtx->EmulateSingle =
(lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
#if 0 // Don't have to mimic MS OpenGL behavior for front-buffering (DaveM)
lpCtx->EmulateSingle |=
(lpPFD->dwFlags & PFD_SUPPORT_GDI) ? TRUE : FALSE;
#endif
// Check for depth buffer
bDepthBuffer = (lpPFD->cDepthBits) ? GL_TRUE : GL_FALSE;
lpCtx->bDoubleBuffer = bDoubleBuffer;
lpCtx->bDepthBuffer = bDepthBuffer;
// Set the Fullscreen flag for the context.
// lpCtx->bFullscreen = glb.bFullscreen;
// Obtain the dimensions of the rendering window
lpCtx->hDC = a; // Cache DC
lpCtx->hWnd = WindowFromDC(lpCtx->hDC);
// Check for non-window DC = memory DC ?
if (lpCtx->hWnd == NULL) {
// bitmap memory contexts are always single-buffered
lpCtx->EmulateSingle = TRUE;
bBogusWindow = TRUE;
ddlogPrintf(DDLOG_INFO, "Non-Window Memory Device Context");
if (GetClipBox(lpCtx->hDC, &lpCtx->rcScreenRect) == ERROR) {
ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglCreateContext\n");
SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
}
}
else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
bBogusWindow = TRUE;
ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglCreateContext\n");
SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
}
lpCtx->dwWidth = lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left;
lpCtx->dwHeight = lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top;
ddlogPrintf(DDLOG_INFO, "Input window %X: w=%i, h=%i",
lpCtx->hWnd, lpCtx->dwWidth, lpCtx->dwHeight);
// What if app only zeroes one dimension instead of both? (DaveM)
if ( (lpCtx->dwWidth == 0) || (lpCtx->dwHeight == 0) ) {
// Make the buffer size something sensible
lpCtx->dwWidth = 8;
lpCtx->dwHeight = 8;
}
// Set defaults
lpCtx->dwModeWidth = lpCtx->dwWidth;
lpCtx->dwModeHeight = lpCtx->dwHeight;
/*
// Find best display mode for fullscreen
if (glb.bFullscreen || !glb.bPrimary) {
dglChooseDisplayMode(lpCtx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -