blob: 4ad7a76e67f6d1217009463d1d9585256771a16a [file] [log] [blame]
/****************************************************************************
*
* Mesa 3-D graphics library
* Direct3D Driver Interface
*
* ========================================================================
*
* Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* ======================================================================
*
* Language: ANSI C
* Environment: Windows 9x (Win32)
*
* Description: Context handling.
*
****************************************************************************/
#include "dglcontext.h"
// Get compile errors without this. KeithH
//#include "scitech.h" // ibool, etc.
#ifdef _USE_GLD3_WGL
#include "gld_driver.h"
extern void _gld_mesa_warning(GLcontext *, char *);
extern void _gld_mesa_fatal(GLcontext *, char *);
#endif // _USE_GLD3_WGL
// TODO: Clean out old DX6-specific code from GLD 2.x CAD driver
// if it is no longer being built as part of GLDirect. (DaveM)
// ***********************************************************************
#define GLDERR_NONE 0
#define GLDERR_MEM 1
#define GLDERR_DDRAW 2
#define GLDERR_D3D 3
#define GLDERR_BPP 4
char szResourceWarning[] =
"GLDirect does not have enough video memory resources\n"
"to support the requested OpenGL rendering context.\n\n"
"You may have to reduce the current display resolution\n"
"to obtain satisfactory OpenGL performance.\n";
char szDDrawWarning[] =
"GLDirect is unable to initialize DirectDraw for the\n"
"requested OpenGL rendering context.\n\n"
"You will have to check the DirectX control panel\n"
"for further information.\n";
char szD3DWarning[] =
"GLDirect is unable to initialize Direct3D for the\n"
"requested OpenGL rendering context.\n\n"
"You may have to change the display mode resolution\n"
"color depth or check the DirectX control panel for\n"
"further information.\n";
char szBPPWarning[] =
"GLDirect is unable to use the selected color depth for\n"
"the requested OpenGL rendering context.\n\n"
"You will have to change the display mode resolution\n"
"color depth with the Display Settings control panel.\n";
int nContextError = GLDERR_NONE;
// ***********************************************************************
#define VENDORID_ATI 0x1002
static DWORD devATIRagePro[] = {
0x4742, // 3D RAGE PRO BGA AGP 1X/2X
0x4744, // 3D RAGE PRO BGA AGP 1X only
0x4749, // 3D RAGE PRO BGA PCI 33 MHz
0x4750, // 3D RAGE PRO PQFP PCI 33 MHz
0x4751, // 3D RAGE PRO PQFP PCI 33 MHz limited 3D
0x4C42, // 3D RAGE LT PRO BGA-312 AGP 133 MHz
0x4C44, // 3D RAGE LT PRO BGA-312 AGP 66 MHz
0x4C49, // 3D RAGE LT PRO BGA-312 PCI 33 MHz
0x4C50, // 3D RAGE LT PRO BGA-256 PCI 33 MHz
0x4C51, // 3D RAGE LT PRO BGA-256 PCI 33 MHz limited 3D
};
static DWORD devATIRageIIplus[] = {
0x4755, // 3D RAGE II+
0x4756, // 3D RAGE IIC PQFP PCI
0x4757, // 3D RAGE IIC BGA AGP
0x475A, // 3D RAGE IIC PQFP AGP
0x4C47, // 3D RAGE LT-G
};
// ***********************************************************************
#ifndef _USE_GLD3_WGL
extern DGL_mesaFuncs mesaFuncs;
#endif
extern DWORD dwLogging;
#ifdef GLD_THREADS
#pragma message("compiling DGLCONTEXT.C vars for multi-threaded support")
CRITICAL_SECTION CriticalSection; // for serialized access
DWORD dwTLSCurrentContext = 0xFFFFFFFF; // TLS index for current context
DWORD dwTLSPixelFormat = 0xFFFFFFFF; // TLS index for current pixel format
#endif
HGLRC iCurrentContext = 0; // Index of current context (static)
BOOL bContextReady = FALSE; // Context state ready ?
DGL_ctx ctxlist[DGL_MAX_CONTEXTS]; // Context list
// ***********************************************************************
static BOOL bHaveWin95 = FALSE;
static BOOL bHaveWinNT = FALSE;
static BOOL bHaveWin2K = FALSE;
/****************************************************************************
REMARKS:
Detect the installed OS type.
****************************************************************************/
static void DetectOS(void)
{
OSVERSIONINFO VersionInformation;
LPOSVERSIONINFO lpVersionInformation = &VersionInformation;
VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
GetVersionEx(lpVersionInformation);
switch (VersionInformation.dwPlatformId) {
case VER_PLATFORM_WIN32_WINDOWS:
bHaveWin95 = TRUE;
bHaveWinNT = FALSE;
bHaveWin2K = FALSE;
break;
case VER_PLATFORM_WIN32_NT:
bHaveWin95 = FALSE;
if (VersionInformation.dwMajorVersion <= 4) {
bHaveWinNT = TRUE;
bHaveWin2K = FALSE;
}
else {
bHaveWinNT = FALSE;
bHaveWin2K = TRUE;
}
break;
case VER_PLATFORM_WIN32s:
bHaveWin95 = FALSE;
bHaveWinNT = FALSE;
bHaveWin2K = FALSE;
break;
}
}
// ***********************************************************************
HWND hWndEvent = NULL; // event monitor window
HWND hWndLastActive = NULL; // last active client window
LONG __stdcall GLD_EventWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
// ***********************************************************************
// Checks if the HGLRC is valid in range of context list.
BOOL dglIsValidContext(
HGLRC a)
{
return ((int)a > 0 && (int)a <= DGL_MAX_CONTEXTS);
}
// ***********************************************************************
// Convert a HGLRC to a pointer into the context list.
DGL_ctx* dglGetContextAddress(
const HGLRC a)
{
if (dglIsValidContext(a))
return &ctxlist[(int)a-1];
return NULL;
}
// ***********************************************************************
// Return the current HGLRC (however it may be stored for multi-threading).
HGLRC dglGetCurrentContext(void)
{
#ifdef GLD_THREADS
HGLRC hGLRC;
// load from thread-specific instance
if (glb.bMultiThreaded) {
// protect against calls from arbitrary threads
__try {
hGLRC = (HGLRC)TlsGetValue(dwTLSCurrentContext);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
hGLRC = iCurrentContext;
}
}
// load from global static var
else {
hGLRC = iCurrentContext;
}
return hGLRC;
#else
return iCurrentContext;
#endif
}
// ***********************************************************************
// Set the current HGLRC (however it may be stored for multi-threading).
void dglSetCurrentContext(HGLRC hGLRC)
{
#ifdef GLD_THREADS
// store in thread-specific instance
if (glb.bMultiThreaded) {
// protect against calls from arbitrary threads
__try {
TlsSetValue(dwTLSCurrentContext, (LPVOID)hGLRC);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
iCurrentContext = hGLRC;
}
}
// store in global static var
else {
iCurrentContext = hGLRC;
}
#else
iCurrentContext = hGLRC;
#endif
}
// ***********************************************************************
// Return the current HDC only for a currently active HGLRC.
HDC dglGetCurrentDC(void)
{
HGLRC hGLRC;
DGL_ctx* lpCtx;
hGLRC = dglGetCurrentContext();
if (hGLRC) {
lpCtx = dglGetContextAddress(hGLRC);
return lpCtx->hDC;
}
return 0;
}
// ***********************************************************************
void dglInitContextState()
{
int i;
WNDCLASS wc;
#ifdef GLD_THREADS
// Allocate thread local storage indexes for current context and pixel format
dwTLSCurrentContext = TlsAlloc();
dwTLSPixelFormat = TlsAlloc();
#endif
dglSetCurrentContext(NULL); // No current rendering context
// Clear all context data
ZeroMemory(ctxlist, sizeof(ctxlist[0]) * DGL_MAX_CONTEXTS);
for (i=0; i<DGL_MAX_CONTEXTS; i++)
ctxlist[i].bAllocated = FALSE; // Flag context as unused
// This section of code crashes the dll in circumstances where the app
// creates and destroys contexts.
/*
// Register the class for our event monitor window
wc.style = 0;
wc.lpfnWndProc = GLD_EventWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(GetModuleHandle(NULL), IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "GLDIRECT";
RegisterClass(&wc);
// Create the non-visible window to monitor all broadcast messages
hWndEvent = CreateWindowEx(
WS_EX_TOOLWINDOW,"GLDIRECT","GLDIRECT",WS_POPUP,
0,0,0,0,
NULL,NULL,GetModuleHandle(NULL),NULL);
*/
#ifdef GLD_THREADS
// Create a critical section object for serializing access to
// DirectDraw and DDStereo create/destroy functions in multiple threads
if (glb.bMultiThreaded)
InitializeCriticalSection(&CriticalSection);
#endif
// Context state is now initialized and ready
bContextReady = TRUE;
}
// ***********************************************************************
void dglDeleteContextState()
{
int i;
static BOOL bOnceIsEnough = FALSE;
// Only call once, from either DGL_exitDriver(), or DLL_PROCESS_DETACH
if (bOnceIsEnough)
return;
bOnceIsEnough = TRUE;
for (i=0; i<DGL_MAX_CONTEXTS; i++) {
if (ctxlist[i].bAllocated == TRUE) {
ddlogPrintf(DDLOG_WARN, "** Context %i not deleted - cleaning up.", (i+1));
dglDeleteContext((HGLRC)(i+1));
}
}
// Context state is no longer ready
bContextReady = FALSE;
// If executed when DLL unloads, DDraw objects may be invalid.
// So catch any page faults with this exception handler.
__try {
// Release final DirectDraw interfaces
if (glb.bDirectDrawPersistant) {
// RELEASE(glb.lpGlobalPalette);
// RELEASE(glb.lpDepth4);
// RELEASE(glb.lpBack4);
// RELEASE(glb.lpPrimary4);
// RELEASE(glb.lpDD4);
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContextState.");
}
// Destroy our event monitor window
if (hWndEvent) {
DestroyWindow(hWndEvent);
hWndEvent = hWndLastActive = NULL;
}
#ifdef GLD_THREADS
// Destroy the critical section object
if (glb.bMultiThreaded)
DeleteCriticalSection(&CriticalSection);
// Release thread local storage indexes for current HGLRC and pixel format
TlsFree(dwTLSPixelFormat);
TlsFree(dwTLSCurrentContext);
#endif
}
// ***********************************************************************
// Application Window message handler interception
static LONG __stdcall dglWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
DGL_ctx* lpCtx = NULL;
LONG lpfnWndProc = 0L;
int i;
HGLRC hGLRC;
RECT rect;
PAINTSTRUCT ps;
BOOL bQuit = FALSE;
BOOL bMain = FALSE;
LONG rc;
// Get the window's message handler *before* it is unhooked in WM_DESTROY
// Is this the main window?
if (hwnd == glb.hWndActive) {
bMain = TRUE;
lpfnWndProc = glb.lpfnWndProc;
}
// 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);
}
*/
// Misc initialisation
lpCtx->bCanRender = FALSE; // No rendering allowed yet
lpCtx->bSceneStarted = FALSE;
lpCtx->bFrameStarted = FALSE;
// Detect OS (specifically 'Windows 2000' or 'Windows XP')
DetectOS();
// NOTE: WinNT not supported
ddlogPrintf(DDLOG_INFO, "OS: %s", bHaveWin95 ? "Win9x" : (bHaveWin2K ? "Win2000/XP" : "Unsupported") );
// Test for Fullscreen
if (bHaveWin95) { // Problems with fullscreen on Win2K/XP
if ((GetSystemMetrics(SM_CXSCREEN) == lpCtx->dwWidth) &&
(GetSystemMetrics(SM_CYSCREEN) == lpCtx->dwHeight))
{
// Workaround for some apps that crash when going fullscreen.
//lpCtx->bFullscreen = TRUE;
}
}
#ifdef _USE_GLD3_WGL
_gldDriver.CreateDrawable(lpCtx, glb.bDirectDrawPersistant, glb.bPersistantBuffers);
#else
// Check if DirectDraw has already been created by original GLRC (DaveM)
if (glb.bDirectDrawPersistant && glb.bDirectDraw) {
lpCtx->lpDD4 = glb.lpDD4;
IDirectDraw4_AddRef(lpCtx->lpDD4);
goto SkipDirectDrawCreate;
}
// Create DirectDraw object
if (glb.bPrimary)
hResult = DirectDrawCreate(NULL, &lpCtx->lpDD1, NULL);
else {
// A non-primary device is to be used.
// Force context to be Fullscreen, secondary adaptors can not
// be used in a window.
hResult = DirectDrawCreate(&glb.ddGuid, &lpCtx->lpDD1, NULL);
lpCtx->bFullscreen = TRUE;
}
if (FAILED(hResult)) {
MessageBox(NULL, "Unable to initialize DirectDraw", "GLDirect", MB_OK);
ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw interface", hResult);
nContextError = GLDERR_DDRAW;
goto return_with_error;
}
// Query for DX6 IDirectDraw4.
hResult = IDirectDraw_QueryInterface(lpCtx->lpDD1,
&IID_IDirectDraw4,
(void**)&lpCtx->lpDD4);
if (FAILED(hResult)) {
MessageBox(NULL, "GLDirect requires DirectX 6.0 or above", "GLDirect", MB_OK);
ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create DirectDraw4 interface", hResult);
nContextError = GLDERR_DDRAW;
goto return_with_error;
}
// Cache DirectDraw interface for subsequent GLRCs
if (glb.bDirectDrawPersistant && !glb.bDirectDraw) {
glb.lpDD4 = lpCtx->lpDD4;
IDirectDraw4_AddRef(glb.lpDD4);
glb.bDirectDraw = TRUE;
}
SkipDirectDrawCreate:
// Now we have a DD4 interface we can check for broken cards
dglTestForBrokenCards(lpCtx);
// Test if primary device can use flipping instead of blitting
ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode));
ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode);
hResult = IDirectDraw4_GetDisplayMode(
lpCtx->lpDD4,
&ddsd2DisplayMode);
if (SUCCEEDED(hResult)) {
if ( (lpCtx->dwWidth == ddsd2DisplayMode.dwWidth) &&
(lpCtx->dwHeight == ddsd2DisplayMode.dwHeight) ) {
// We have a fullscreen-size window
bFullScrnWin = TRUE;
// OK to use DirectDraw fullscreen mode ?
if (glb.bPrimary && !glb.bFullscreenBlit && !lpCtx->EmulateSingle && !glb.bDirectDrawPersistant) {
lpCtx->bFullscreen = TRUE;
ddlogMessage(DDLOG_INFO, "Primary upgraded to page flipping.\n");
}
}
// Cache the display mode dimensions
lpCtx->dwModeWidth = ddsd2DisplayMode.dwWidth;
lpCtx->dwModeHeight = ddsd2DisplayMode.dwHeight;
}
// Clamp the effective window dimensions to primary surface.
// We need to do this for D3D viewport dimensions even if wide
// surfaces are supported. This also is a good idea for handling
// whacked-out window dimensions passed for non-drawable windows
// like Solid Edge. (DaveM)
if (lpCtx->dwWidth > ddsd2DisplayMode.dwWidth)
lpCtx->dwWidth = ddsd2DisplayMode.dwWidth;
if (lpCtx->dwHeight > ddsd2DisplayMode.dwHeight)
lpCtx->dwHeight = ddsd2DisplayMode.dwHeight;
// Check for non-RGB desktop resolution
if (!lpCtx->bFullscreen && ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount <= 8) {
ddlogPrintf(DDLOG_CRITICAL_OR_WARN, "Desktop color depth %d bpp not supported",
ddsd2DisplayMode.ddpfPixelFormat.dwRGBBitCount);
nContextError = GLDERR_BPP;
goto return_with_error;
}
#endif // _USE_GLD3_WGL
ddlogPrintf(DDLOG_INFO, "Window: w=%i, h=%i (%s)",
lpCtx->dwWidth,
lpCtx->dwHeight,
lpCtx->bFullscreen ? "fullscreen" : "windowed");
#ifndef _USE_GLD3_WGL
// Obtain ddraw caps
ZeroMemory(&lpCtx->ddCaps, sizeof(DDCAPS));
lpCtx->ddCaps.dwSize = sizeof(DDCAPS);
if (glb.bHardware) {
// Get HAL caps
IDirectDraw4_GetCaps(lpCtx->lpDD4, &lpCtx->ddCaps, NULL);
} else {
// Get HEL caps
IDirectDraw4_GetCaps(lpCtx->lpDD4, NULL, &lpCtx->ddCaps);
}
// If this flag is present then we can't default to Mesa
// SW rendering between BeginScene() and EndScene().
if (lpCtx->ddCaps.dwCaps2 & DDCAPS2_NO2DDURING3DSCENE) {
ddlogMessage(DDLOG_INFO,
"Warning : No 2D allowed during 3D scene.\n");
}
// Query for DX6 Direct3D3 interface
hResult = IDirectDraw4_QueryInterface(lpCtx->lpDD4,
&IID_IDirect3D3,
(void**)&lpCtx->lpD3D3);
if (FAILED(hResult)) {
MessageBox(NULL, "Unable to initialize Direct3D", "GLDirect", MB_OK);
ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D interface", hResult);
nContextError = GLDERR_D3D;
goto return_with_error;
}
// Context creation
if (lpCtx->bFullscreen) {
// FULLSCREEN
// Disable warning popups when in fullscreen mode
ddlogWarnOption(FALSE);
// Have to release persistant primary surface if fullscreen mode
if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
RELEASE(glb.lpPrimary4);
glb.bDirectDrawPrimary = FALSE;
}
dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT;
if (glb.bFastFPU)
dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM)
hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, lpCtx->hWnd, dwFlags);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Exclusive Fullscreen mode", hResult);
goto return_with_error;
}
hResult = IDirectDraw4_SetDisplayMode(lpCtx->lpDD4,
lpCtx->dwModeWidth,
lpCtx->dwModeHeight,
lpPFD->cColorBits,
0,
0);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "SetDisplayMode failed", hResult);
goto return_with_error;
}
// ** The display mode has changed, so dont use MessageBox! **
ZeroMemory(&ddsd2, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
if (bDoubleBuffer) {
// Double buffered
// Primary surface
ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX |
DDSCAPS_3DDEVICE |
dwMemoryType;
ddsd2.dwBackBufferCount = 1;
hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
nContextError = GLDERR_MEM;
goto return_with_error;
}
// Render target surface
ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct.
ddscaps2.dwCaps = DDSCAPS_BACKBUFFER;
hResult = IDirectDrawSurface4_GetAttachedSurface(lpCtx->lpFront4, &ddscaps2, &lpCtx->lpBack4);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "GetAttachedSurface failed", hResult);
nContextError = GLDERR_MEM;
goto return_with_error;
}
} else {
// Single buffered
// Primary surface
ddsd2.dwFlags = DDSD_CAPS;
ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
//DDSCAPS_3DDEVICE |
dwMemoryType;
hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
nContextError = GLDERR_MEM;
goto return_with_error;
}
lpCtx->lpBack4 = NULL;
}
} else {
// WINDOWED
// OK to enable warning popups in windowed mode
ddlogWarnOption(glb.bMessageBoxWarnings);
dwFlags = DDSCL_NORMAL;
if (glb.bMultiThreaded)
dwFlags |= DDSCL_MULTITHREADED;
if (glb.bFastFPU)
dwFlags |= DDSCL_FPUSETUP; // fast FPU setup optional (DaveM)
hResult = IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4,
lpCtx->hWnd,
dwFlags);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to set Normal coop level", hResult);
goto return_with_error;
}
// Has Primary surface already been created for original GLRC ?
// Note this can only be applicable for windowed modes
if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) {
lpCtx->lpFront4 = glb.lpPrimary4;
IDirectDrawSurface4_AddRef(lpCtx->lpFront4);
// Update the window on the default clipper
IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
IDirectDrawClipper_Release(lpddClipper);
goto SkipPrimaryCreate;
}
// Primary surface
ZeroMemory(&ddsd2, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
ddsd2.dwFlags = DDSD_CAPS;
ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpFront4, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (primary) failed", hResult);
nContextError = GLDERR_MEM;
goto return_with_error;
}
// Cache Primary surface for subsequent GLRCs
// Note this can only be applicable to subsequent windowed modes
if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) {
glb.lpPrimary4 = lpCtx->lpFront4;
IDirectDrawSurface4_AddRef(glb.lpPrimary4);
glb.bDirectDrawPrimary = TRUE;
}
// Clipper object
hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateClipper failed", hResult);
goto return_with_error;
}
hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
if (FAILED(hResult)) {
RELEASE(lpddClipper);
ddlogError(DDLOG_CRITICAL_OR_WARN, "SetHWnd failed", hResult);
goto return_with_error;
}
hResult = IDirectDrawSurface4_SetClipper(lpCtx->lpFront4, lpddClipper);
RELEASE(lpddClipper); // We have finished with it.
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "SetClipper failed", hResult);
goto return_with_error;
}
SkipPrimaryCreate:
if (bDoubleBuffer) {
// Render target surface
ZeroMemory(&ddsd2, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd2.dwWidth = lpCtx->dwWidth;
ddsd2.dwHeight = lpCtx->dwHeight;
ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE |
DDSCAPS_OFFSCREENPLAIN |
dwMemoryType;
// Reserve the entire desktop size for persistant buffers option
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
}
// Re-use original back buffer if persistant buffers exist
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpBack4)
hResult = IDirectDrawSurface4_AddRef(lpCtx->lpBack4 = glb.lpBack4);
else
hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpBack4, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "Create Backbuffer failed", hResult);
nContextError = GLDERR_MEM;
goto return_with_error;
}
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpBack4)
IDirectDrawSurface4_AddRef(glb.lpBack4 = lpCtx->lpBack4);
} else {
lpCtx->lpBack4 = NULL;
}
}
//
// Now create the Z-buffer
//
lpCtx->bStencil = FALSE; // Default to no stencil buffer
if (bDepthBuffer && (lpCtx->lpPF->iZBufferPF != -1)) {
// Get z-buffer dimensions from the render target
// Setup the surface desc for the z-buffer.
ZeroMemory(&ddsd2, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType;
ddsd2.dwWidth = lpCtx->dwWidth;
ddsd2.dwHeight = lpCtx->dwHeight;
memcpy(&ddsd2.ddpfPixelFormat,
&glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF],
sizeof(DDPIXELFORMAT) );
// Reserve the entire desktop size for persistant buffers option
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) {
ddsd2.dwWidth = ddsd2DisplayMode.dwWidth;
ddsd2.dwHeight = ddsd2DisplayMode.dwHeight;
}
// Create a z-buffer
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4)
hResult = IDirectDrawSurface4_AddRef(lpCtx->lpDepth4 = glb.lpDepth4);
else
hResult = IDirectDraw4_CreateSurface(lpCtx->lpDD4, &ddsd2, &lpCtx->lpDepth4, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateSurface (ZBuffer) failed", hResult);
nContextError = GLDERR_MEM;
goto return_with_error;
}
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpDepth4)
IDirectDrawSurface4_AddRef(glb.lpDepth4 = lpCtx->lpDepth4);
else if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpDepth4 && glb.lpBack4)
IDirectDrawSurface4_DeleteAttachedSurface(glb.lpBack4, 0, glb.lpDepth4);
// Attach Zbuffer to render target
TRY(IDirectDrawSurface4_AddAttachedSurface(
bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
lpCtx->lpDepth4),
"dglCreateContext: Attach Zbuffer");
if (glb.lpZBufferPF[lpCtx->lpPF->iZBufferPF].dwFlags & DDPF_STENCILBUFFER) {
lpCtx->bStencil = TRUE;
ddlogMessage(DDLOG_INFO, "Depth buffer has stencil\n");
}
}
// Clear all back buffers and Z-buffers in case of memory recycling.
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
IDirectDrawSurface4_Blt(lpCtx->lpBack4, NULL, NULL, NULL,
DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
if (lpCtx->lpDepth4)
IDirectDrawSurface4_Blt(lpCtx->lpDepth4, NULL, NULL, NULL,
DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
// Now that we have a Z-buffer we can create the 3D device
hResult = IDirect3D3_CreateDevice(lpCtx->lpD3D3,
&glb.d3dGuid,
bDoubleBuffer ? lpCtx->lpBack4 : lpCtx->lpFront4,
&lpCtx->lpDev3,
NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "Unable to create Direct3D device", hResult);
nContextError = GLDERR_D3D;
goto return_with_error;
}
// We must do this as soon as the device is created
dglInitStateCaches(lpCtx);
// Obtain the D3D Device Description
D3DHWDevDesc.dwSize = D3DHELDevDesc.dwSize = sizeof(D3DDEVICEDESC);
TRY(IDirect3DDevice3_GetCaps(lpCtx->lpDev3,
&D3DHWDevDesc,
&D3DHELDevDesc),
"dglCreateContext: GetCaps failed");
// Choose the relevant description and cache it in the context.
// We will use this description later for caps checking
memcpy( &lpCtx->D3DDevDesc,
glb.bHardware ? &D3DHWDevDesc : &D3DHELDevDesc,
sizeof(D3DDEVICEDESC));
// Now we can examine the texture formats
if (!dglBuildTextureFormatList(lpCtx->lpDev3)) {
ddlogMessage(DDLOG_CRITICAL_OR_WARN, "dglBuildTextureFormatList failed\n");
goto return_with_error;
}
// Get the pixel format of the back buffer
lpCtx->ddpfRender.dwSize = sizeof(lpCtx->ddpfRender);
if (bDoubleBuffer)
hResult = IDirectDrawSurface4_GetPixelFormat(
lpCtx->lpBack4,
&lpCtx->ddpfRender);
else
hResult = IDirectDrawSurface4_GetPixelFormat(
lpCtx->lpFront4,
&lpCtx->ddpfRender);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "GetPixelFormat failed", hResult);
goto return_with_error;
}
// Find a pixel packing function suitable for this surface
pxClassifyPixelFormat(&lpCtx->ddpfRender,
&lpCtx->fnPackFunc,
&lpCtx->fnUnpackFunc,
&lpCtx->fnPackSpanFunc);
// Viewport
hResult = IDirect3D3_CreateViewport(lpCtx->lpD3D3, &lpCtx->lpViewport3, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateViewport failed", hResult);
goto return_with_error;
}
hResult = IDirect3DDevice3_AddViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "AddViewport failed", hResult);
goto return_with_error;
}
// Initialise the viewport
// Note screen coordinates are used for viewport clipping since D3D
// transform operations are not used in the GLD CAD driver. (DaveM)
inv_aspect = (float)lpCtx->dwHeight/(float)lpCtx->dwWidth;
lpCtx->d3dViewport.dwSize = sizeof(lpCtx->d3dViewport);
lpCtx->d3dViewport.dwX = 0;
lpCtx->d3dViewport.dwY = 0;
lpCtx->d3dViewport.dwWidth = lpCtx->dwWidth;
lpCtx->d3dViewport.dwHeight = lpCtx->dwHeight;
lpCtx->d3dViewport.dvClipX = 0; // -1.0f;
lpCtx->d3dViewport.dvClipY = 0; // inv_aspect;
lpCtx->d3dViewport.dvClipWidth = lpCtx->dwWidth; // 2.0f;
lpCtx->d3dViewport.dvClipHeight = lpCtx->dwHeight; // 2.0f * inv_aspect;
lpCtx->d3dViewport.dvMinZ = 0.0f;
lpCtx->d3dViewport.dvMaxZ = 1.0f;
TRY(IDirect3DViewport3_SetViewport2(lpCtx->lpViewport3, &lpCtx->d3dViewport), "dglCreateContext: SetViewport2");
hResult = IDirect3DDevice3_SetCurrentViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "SetCurrentViewport failed", hResult);
goto return_with_error;
}
lpCtx->dwBPP = lpPFD->cColorBits;
lpCtx->iZBufferPF = lpCtx->lpPF->iZBufferPF;
// Set last texture to NULL
for (i=0; i<MAX_TEXTURE_UNITS; i++) {
lpCtx->ColorOp[i] = D3DTOP_DISABLE;
lpCtx->AlphaOp[i] = D3DTOP_DISABLE;
lpCtx->tObj[i] = NULL;
}
// Default to perspective correct texture mapping
dglSetRenderState(lpCtx, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, "TexturePersp");
// Set the default culling mode
lpCtx->cullmode = D3DCULL_NONE;
dglSetRenderState(lpCtx, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, "CullMode");
// Disable specular
dglSetRenderState(lpCtx, D3DRENDERSTATE_SPECULARENABLE, FALSE, "SpecularEnable");
// Disable subpixel correction
// dglSetRenderState(lpCtx, D3DRENDERSTATE_SUBPIXEL, FALSE, "SubpixelEnable");
// Disable dithering
dglSetRenderState(lpCtx, D3DRENDERSTATE_DITHERENABLE, FALSE, "DitherEnable");
// Initialise the primitive caches
// lpCtx->dwNextLineVert = 0;
// lpCtx->dwNextTriVert = 0;
// Init the global texture palette
lpCtx->lpGlobalPalette = NULL;
// Init the HW/SW usage counters
// lpCtx->dwHWUsageCount = lpCtx->dwSWUsageCount = 0L;
//
// Create two D3D vertex buffers.
// One will hold the pre-transformed data with the other one
// being used to hold the post-transformed & clipped verts.
//
#if 0 // never used (DaveM)
vbufdesc.dwSize = sizeof(D3DVERTEXBUFFERDESC);
vbufdesc.dwCaps = D3DVBCAPS_WRITEONLY;
if (glb.bHardware == FALSE)
vbufdesc.dwCaps = D3DVBCAPS_SYSTEMMEMORY;
vbufdesc.dwNumVertices = 32768; // For the time being
// Source vertex buffer
vbufdesc.dwFVF = DGL_LVERTEX;
hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_vbuf, 0, NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(src) failed", hResult);
goto return_with_error;
}
// Destination vertex buffer
vbufdesc.dwFVF = (glb.bMultitexture == FALSE) ? D3DFVF_TLVERTEX : (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2);
hResult = IDirect3D3_CreateVertexBuffer(lpCtx->lpD3D3, &vbufdesc, &lpCtx->m_pvbuf, 0, NULL);
if(FAILED(hResult)) {
ddlogError(DDLOG_CRITICAL_OR_WARN, "CreateVertexBuffer(dst) failed", hResult);
goto return_with_error;
}
#endif
#endif _USE_GLD3_WGL
//
// Now create the Mesa context
//
// Create the Mesa visual
if (lpPFD->cDepthBits)
dwDepthBits = 16;
if (lpPFD->cStencilBits)
dwStencilBits = 8;
if (lpPFD->cAlphaBits) {
dwAlphaBits = 8;
bAlphaSW = GL_TRUE;
}
if (lpPFD->dwFlags & PFD_DOUBLEBUFFER)
bDouble = GL_TRUE;
// lpCtx->EmulateSingle =
// (lpPFD->dwFlags & PFD_DOUBLEBUFFER) ? FALSE : TRUE;
#ifdef _USE_GLD3_WGL
lpCtx->glVis = _mesa_create_visual(
GL_TRUE, // RGB mode
bDouble, /* double buffer */
GL_FALSE, // stereo
lpPFD->cRedBits,
lpPFD->cGreenBits,
lpPFD->cBlueBits,
dwAlphaBits,
0, // index bits
dwDepthBits,
dwStencilBits,
lpPFD->cAccumRedBits, // accum bits
lpPFD->cAccumGreenBits, // accum bits
lpPFD->cAccumBlueBits, // accum bits
lpPFD->cAccumAlphaBits, // accum alpha bits
1 // num samples
);
#else // _USE_GLD3_WGL
lpCtx->glVis = (*mesaFuncs.gl_create_visual)(
GL_TRUE, // RGB mode
bAlphaSW, // Is an alpha buffer required?
bDouble, // Is an double-buffering required?
GL_FALSE, // stereo
dwDepthBits, // depth_size
dwStencilBits, // stencil_size
lpPFD->cAccumBits, // accum_size
0, // colour-index bits
lpPFD->cRedBits, // Red bit count
lpPFD->cGreenBits, // Green bit count
lpPFD->cBlueBits, // Blue bit count
dwAlphaBits // Alpha bit count
);
#endif // _USE_GLD3_WGL
if (lpCtx->glVis == NULL) {
ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_visual failed\n");
goto return_with_error;
}
#ifdef _USE_GLD3_WGL
lpCtx->glCtx = _mesa_create_context(lpCtx->glVis, NULL, (void *)lpCtx, GL_TRUE);
#else
// Create the Mesa context
lpCtx->glCtx = (*mesaFuncs.gl_create_context)(
lpCtx->glVis, // Mesa visual
NULL, // share list context
(void *)lpCtx, // Pointer to our driver context
GL_TRUE // Direct context flag
);
#endif // _USE_GLD3_WGL
if (lpCtx->glCtx == NULL) {
ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_context failed\n");
goto return_with_error;
}
// Create the Mesa framebuffer
#ifdef _USE_GLD3_WGL
lpCtx->glBuffer = _mesa_create_framebuffer(
lpCtx->glVis,
lpCtx->glVis->depthBits > 0,
lpCtx->glVis->stencilBits > 0,
lpCtx->glVis->accumRedBits > 0,
GL_FALSE //swalpha
);
#else
lpCtx->glBuffer = (*mesaFuncs.gl_create_framebuffer)(lpCtx->glVis);
#endif // _USE_GLD3_WGL
if (lpCtx->glBuffer == NULL) {
ddlogMessage(DDLOG_CRITICAL_OR_WARN, "gl_create_framebuffer failed\n");
goto return_with_error;
}
#ifdef _USE_GLD3_WGL
// Init Mesa internals
_swrast_CreateContext( lpCtx->glCtx );
_vbo_CreateContext( lpCtx->glCtx );
_tnl_CreateContext( lpCtx->glCtx );
_swsetup_CreateContext( lpCtx->glCtx );
_gldDriver.InitialiseMesa(lpCtx);
lpCtx->glCtx->imports.warning = _gld_mesa_warning;
lpCtx->glCtx->imports.fatal = _gld_mesa_fatal;
#else
// Tell Mesa how many texture stages we have
glb.wMaxSimultaneousTextures = lpCtx->D3DDevDesc.wMaxSimultaneousTextures;
// Only use as many Units as the spec requires
if (glb.wMaxSimultaneousTextures > MAX_TEXTURE_UNITS)
glb.wMaxSimultaneousTextures = MAX_TEXTURE_UNITS;
lpCtx->glCtx->Const.MaxTextureUnits = glb.wMaxSimultaneousTextures;
ddlogPrintf(DDLOG_INFO, "Texture stages : %d", glb.wMaxSimultaneousTextures);
// Set the max texture size.
// NOTE: clamped to a max of 1024 for extra performance!
lpCtx->dwMaxTextureSize = (lpCtx->D3DDevDesc.dwMaxTextureWidth <= 1024) ? lpCtx->D3DDevDesc.dwMaxTextureWidth : 1024;
// Texture resize takes place elsewhere. KH
// NOTE: This was added to workaround an issue with the Intel app.
#if 0
lpCtx->glCtx->Const.MaxTextureSize = lpCtx->dwMaxTextureSize;
#else
lpCtx->glCtx->Const.MaxTextureSize = 1024;
#endif
// Setup the Display Driver pointers
dglSetupDDPointers(lpCtx->glCtx);
// Initialise all the Direct3D renderstates
dglInitStateD3D(lpCtx->glCtx);
#if 0
// Signal a reload of texture state on next glBegin
lpCtx->m_texHandleValid = FALSE;
lpCtx->m_mtex = FALSE;
lpCtx->m_texturing = FALSE;
#else
// Set default texture unit state
// dglSetTexture(lpCtx, 0, NULL);
// dglSetTexture(lpCtx, 1, NULL);
#endif
//
// Set the global texture palette to default values.
//
// Clear the entire palette
ZeroMemory(ppe, sizeof(PALETTEENTRY) * 256);
// Fill the palette with a default colour.
// A garish colour is used to catch bugs. Here Magenta is used.
for (i=0; i < 256; i++) {
ppe[i].peRed = 255;
ppe[i].peGreen = 0;
ppe[i].peBlue = 255;
}
RELEASE(lpCtx->lpGlobalPalette);
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && glb.lpGlobalPalette)
hResult = IDirectDrawPalette_AddRef(lpCtx->lpGlobalPalette = glb.lpGlobalPalette);
else
hResult = IDirectDraw4_CreatePalette(
lpCtx->lpDD4,
DDPCAPS_INITIALIZE | DDPCAPS_8BIT | DDPCAPS_ALLOW256,
ppe,
&(lpCtx->lpGlobalPalette),
NULL);
if (FAILED(hResult)) {
ddlogError(DDLOG_ERROR, "Default CreatePalette failed\n", hResult);
lpCtx->lpGlobalPalette = NULL;
goto return_with_error;
}
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers && !glb.lpGlobalPalette)
IDirectDrawPalette_AddRef(glb.lpGlobalPalette = lpCtx->lpGlobalPalette);
#endif // _USE_GLD3_WGL
// ** If we have made it to here then we can enable rendering **
lpCtx->bCanRender = TRUE;
// ddlogMessage(DDLOG_SYSTEM, "dglCreateContextBuffers succeded\n");
#ifdef GLD_THREADS
// Release serialized access
if (glb.bMultiThreaded)
LeaveCriticalSection(&CriticalSection);
#endif
return TRUE;
return_with_error:
// Clean up before returning.
// This is critical for secondary devices.
lpCtx->bCanRender = FALSE;
#ifdef _USE_GLD3_WGL
// Destroy the Mesa context
if (lpCtx->glBuffer)
_mesa_destroy_framebuffer(lpCtx->glBuffer);
if (lpCtx->glCtx)
_mesa_destroy_context(lpCtx->glCtx);
if (lpCtx->glVis)
_mesa_destroy_visual(lpCtx->glVis);
// Destroy driver data
_gldDriver.DestroyDrawable(lpCtx);
#else
// Destroy the Mesa context
if (lpCtx->glBuffer)
(*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
if (lpCtx->glCtx)
(*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
if (lpCtx->glVis)
(*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
RELEASE(lpCtx->m_pvbuf); // Release D3D vertex buffer
RELEASE(lpCtx->m_vbuf); // Release D3D vertex buffer
if (lpCtx->lpViewport3) {
if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
RELEASE(lpCtx->lpViewport3);
lpCtx->lpViewport3 = NULL;
}
RELEASE(lpCtx->lpDev3);
if (lpCtx->lpDepth4) {
if (lpCtx->lpBack4)
IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
else
IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
RELEASE(lpCtx->lpDepth4);
lpCtx->lpDepth4 = NULL;
}
RELEASE(lpCtx->lpBack4);
RELEASE(lpCtx->lpFront4);
else
if (lpCtx->bFullscreen) {
IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
}
RELEASE(lpCtx->lpD3D3);
RELEASE(lpCtx->lpDD4);
RELEASE(lpCtx->lpDD1);
#endif // _USE_GLD3_WGL
lpCtx->bAllocated = FALSE;
#ifdef GLD_THREADS
// Release serialized access
if (glb.bMultiThreaded)
LeaveCriticalSection(&CriticalSection);
#endif
return FALSE;
#undef DDLOG_CRITICAL_OR_WARN
}
// ***********************************************************************
HGLRC dglCreateContext(
HDC a,
const DGL_pixelFormat *lpPF)
{
int i;
HGLRC hGLRC;
DGL_ctx* lpCtx;
static BOOL bWarnOnce = TRUE;
DWORD dwThreadId = GetCurrentThreadId();
char szMsg[256];
HWND hWnd;
LONG lpfnWndProc;
// Validate license
if (!dglValidate())
return NULL;
// Is context state ready ?
if (!bContextReady)
return NULL;
ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext for HDC=%X, ThreadId=%X", a, dwThreadId);
// Find next free context.
// Also ensure that only one Fullscreen context is created at any one time.
hGLRC = 0; // Default to Not Found
for (i=0; i<DGL_MAX_CONTEXTS; i++) {
if (ctxlist[i].bAllocated) {
if (/*glb.bFullscreen && */ctxlist[i].bFullscreen)
break;
} else {
hGLRC = (HGLRC)(i+1);
break;
}
}
// Bail if no GLRC was found
if (!hGLRC)
return NULL;
// Set the context pointer
lpCtx = dglGetContextAddress(hGLRC);
// Make sure that context is zeroed before we do anything.
// MFC and C++ apps call wglCreateContext() and wglDeleteContext() multiple times,
// even though only one context is ever used by the app, so keep it clean. (DaveM)
ZeroMemory(lpCtx, sizeof(DGL_ctx));
lpCtx->bAllocated = TRUE;
// Flag that buffers need creating on next wglMakeCurrent call.
lpCtx->bHasBeenCurrent = FALSE;
lpCtx->lpPF = (DGL_pixelFormat *)lpPF; // cache pixel format
lpCtx->bCanRender = FALSE;
// Create all the internal resources here, not in dglMakeCurrent().
// We do a re-size check in dglMakeCurrent in case of re-allocations. (DaveM)
// We now try context allocations twice, first with video memory,
// then again with system memory. This is similar to technique
// used for dglWglResizeBuffers(). (DaveM)
if (lpCtx->bHasBeenCurrent == FALSE) {
if (!dglCreateContextBuffers(a, lpCtx, FALSE)) {
if (glb.bMessageBoxWarnings && bWarnOnce && dwLogging) {
bWarnOnce = FALSE;
switch (nContextError) {
case GLDERR_DDRAW: strcpy(szMsg, szDDrawWarning); break;
case GLDERR_D3D: strcpy(szMsg, szD3DWarning); break;
case GLDERR_MEM: strcpy(szMsg, szResourceWarning); break;
case GLDERR_BPP: strcpy(szMsg, szBPPWarning); break;
default: strcpy(szMsg, "");
}
if (strlen(szMsg))
MessageBox(NULL, szMsg, "GLDirect", MB_OK | MB_ICONWARNING);
}
// Only need to try again if memory error
if (nContextError == GLDERR_MEM) {
ddlogPrintf(DDLOG_WARN, "dglCreateContext failed 1st time with video memory");
}
else {
ddlogPrintf(DDLOG_ERROR, "dglCreateContext failed");
return NULL;
}
}
}
// Now that we have a hWnd, we can intercept the WindowProc.
hWnd = lpCtx->hWnd;
if (hWnd) {
// Only hook individual window handler once if not hooked before.
lpfnWndProc = GetWindowLong(hWnd, GWL_WNDPROC);
if (lpfnWndProc != (LONG)dglWndProc) {
lpCtx->lpfnWndProc = lpfnWndProc;
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)dglWndProc);
}
// Find the parent window of the app too.
if (glb.hWndActive == NULL) {
while (hWnd != NULL) {
glb.hWndActive = hWnd;
hWnd = GetParent(hWnd);
}
// Hook the parent window too.
lpfnWndProc = GetWindowLong(glb.hWndActive, GWL_WNDPROC);
if (glb.hWndActive == lpCtx->hWnd)
glb.lpfnWndProc = lpCtx->lpfnWndProc;
else if (lpfnWndProc != (LONG)dglWndProc)
glb.lpfnWndProc = lpfnWndProc;
if (glb.lpfnWndProc)
SetWindowLong(glb.hWndActive, GWL_WNDPROC, (LONG)dglWndProc);
}
}
ddlogPrintf(DDLOG_SYSTEM, "dglCreateContext succeeded for HGLRC=%d", (int)hGLRC);
return hGLRC;
}
// ***********************************************************************
// Make a DirectGL context current
// Used by wgl functions and dgl functions
BOOL dglMakeCurrent(
HDC a,
HGLRC b)
{
int context;
DGL_ctx* lpCtx;
HWND hWnd;
BOOL bNeedResize = FALSE;
BOOL bWindowChanged, bContextChanged;
LPDIRECTDRAWCLIPPER lpddClipper;
DWORD dwThreadId = GetCurrentThreadId();
LONG lpfnWndProc;
// Validate license
if (!dglValidate())
return FALSE;
// Is context state ready ?
if (!bContextReady)
return FALSE;
context = (int)b; // This is as a result of STRICT!
ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: HDC=%X, HGLRC=%d, ThreadId=%X", a, context, dwThreadId);
// If the HGLRC is NULL then make no context current;
// Ditto if the HDC is NULL either. (DaveM)
if (context == 0 || a == 0) {
// Corresponding Mesa operation
#ifdef _USE_GLD3_WGL
_mesa_make_current(NULL, NULL);
#else
(*mesaFuncs.gl_make_current)(NULL, NULL);
#endif
dglSetCurrentContext(0);
return TRUE;
}
// Make sure the HGLRC is in range
if ((context > DGL_MAX_CONTEXTS) || (context < 0)) {
ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: HGLRC out of range\n");
return FALSE;
}
// Find address of context and make sure that it has been allocated
lpCtx = dglGetContextAddress(b);
if (!lpCtx->bAllocated) {
ddlogMessage(DDLOG_ERROR, "dglMakeCurrent: Context not allocated\n");
// return FALSE;
return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
}
#ifdef GLD_THREADS
// Serialize access to DirectDraw or DDS operations
if (glb.bMultiThreaded)
EnterCriticalSection(&CriticalSection);
#endif
// Check if window has changed
hWnd = (a != lpCtx->hDC) ? WindowFromDC(a) : lpCtx->hWnd;
bWindowChanged = (hWnd != lpCtx->hWnd) ? TRUE : FALSE;
bContextChanged = (b != dglGetCurrentContext()) ? TRUE : FALSE;
// If the window has changed, make sure the clipper is updated. (DaveM)
if (glb.bDirectDrawPersistant && !lpCtx->bFullscreen && (bWindowChanged || bContextChanged)) {
lpCtx->hWnd = hWnd;
#ifndef _USE_GLD3_WGL
IDirectDrawSurface4_GetClipper(lpCtx->lpFront4, &lpddClipper);
IDirectDrawClipper_SetHWnd(lpddClipper, 0, lpCtx->hWnd);
IDirectDrawClipper_Release(lpddClipper);
#endif // _USE_GLD3_WGL
}
// Make sure hDC and hWnd is current. (DaveM)
// Obtain the dimensions of the rendering window
lpCtx->hDC = a; // Cache DC
lpCtx->hWnd = hWnd;
hWndLastActive = hWnd;
// Check for non-window DC = memory DC ?
if (hWnd == NULL) {
if (GetClipBox(a, &lpCtx->rcScreenRect) == ERROR) {
ddlogMessage(DDLOG_WARN, "GetClipBox failed in dglMakeCurrent\n");
SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
}
}
else if (!GetClientRect(lpCtx->hWnd, &lpCtx->rcScreenRect)) {
ddlogMessage(DDLOG_WARN, "GetClientRect failed in dglMakeCurrent\n");
SetRect(&lpCtx->rcScreenRect, 0, 0, 0, 0);
}
// Check if buffers need to be re-sized;
// If so, wait until Mesa GL stuff is setup before re-sizing;
if (lpCtx->dwWidth != lpCtx->rcScreenRect.right - lpCtx->rcScreenRect.left ||
lpCtx->dwHeight != lpCtx->rcScreenRect.bottom - lpCtx->rcScreenRect.top)
bNeedResize = TRUE;
// Now we can update our globals
dglSetCurrentContext(b);
// Corresponding Mesa operation
#ifdef _USE_GLD3_WGL
_mesa_make_current(lpCtx->glCtx, lpCtx->glBuffer);
lpCtx->glCtx->Driver.UpdateState(lpCtx->glCtx, _NEW_ALL);
if (bNeedResize) {
// Resize buffers (Note Mesa GL needs to be setup beforehand);
// Resize Mesa internal buffer too via glViewport() command,
// which subsequently calls dglWglResizeBuffers() too.
lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
lpCtx->bHasBeenCurrent = TRUE;
}
#else
(*mesaFuncs.gl_make_current)(lpCtx->glCtx, lpCtx->glBuffer);
dglSetupDDPointers(lpCtx->glCtx);
// Insure DirectDraw surfaces fit current window DC
if (bNeedResize) {
// Resize buffers (Note Mesa GL needs to be setup beforehand);
// Resize Mesa internal buffer too via glViewport() command,
// which subsequently calls dglWglResizeBuffers() too.
(*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
lpCtx->bHasBeenCurrent = TRUE;
}
#endif // _USE_GLD3_WGL
ddlogPrintf(DDLOG_SYSTEM, "dglMakeCurrent: width = %d, height = %d", lpCtx->dwWidth, lpCtx->dwHeight);
// We have to clear D3D back buffer and render state if emulated front buffering
// for different window (but not context) like in Solid Edge.
if (glb.bDirectDrawPersistant && glb.bPersistantBuffers
&& (bWindowChanged /* || bContextChanged */) && lpCtx->EmulateSingle) {
#ifdef _USE_GLD3_WGL
// IDirect3DDevice8_EndScene(lpCtx->pDev);
// lpCtx->bSceneStarted = FALSE;
lpCtx->glCtx->Driver.Clear(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
#else
IDirect3DDevice3_EndScene(lpCtx->lpDev3);
lpCtx->bSceneStarted = FALSE;
dglClearD3D(lpCtx->glCtx, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
GL_TRUE, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
#endif // _USE_GLD3_WGL
}
// The first time we call MakeCurrent we set the initial viewport size
if (lpCtx->bHasBeenCurrent == FALSE)
#ifdef _USE_GLD3_WGL
lpCtx->glCtx->Driver.Viewport(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
#else
(*mesaFuncs.gl_Viewport)(lpCtx->glCtx, 0, 0, lpCtx->dwWidth, lpCtx->dwHeight);
#endif // _USE_GLD3_WGL
lpCtx->bHasBeenCurrent = TRUE;
#ifdef GLD_THREADS
// Release serialized access
if (glb.bMultiThreaded)
LeaveCriticalSection(&CriticalSection);
#endif
return TRUE;
}
// ***********************************************************************
BOOL dglDeleteContext(
HGLRC a)
{
DGL_ctx* lpCtx;
DWORD dwThreadId = GetCurrentThreadId();
char argstr[256];
#if 0 // We have enough trouble throwing exceptions as it is... (DaveM)
// Validate license
if (!dglValidate())
return FALSE;
#endif
// Is context state ready ?
if (!bContextReady)
return FALSE;
ddlogPrintf(DDLOG_SYSTEM, "dglDeleteContext: Deleting context HGLRC=%d, ThreadId=%X", (int)a, dwThreadId);
// Make sure the HGLRC is in range
if (((int) a> DGL_MAX_CONTEXTS) || ((int)a < 0)) {
ddlogMessage(DDLOG_ERROR, "dglDeleteCurrent: HGLRC out of range\n");
return FALSE;
}
// Make sure context is valid
lpCtx = dglGetContextAddress(a);
if (!lpCtx->bAllocated) {
ddlogPrintf(DDLOG_WARN, "Tried to delete unallocated context HGLRC=%d", (int)a);
// return FALSE;
return TRUE; // HACK: Shuts up "WebLab Viewer Pro". KeithH
}
// Make sure context is de-activated
if (a == dglGetCurrentContext()) {
ddlogPrintf(DDLOG_WARN, "dglDeleteContext: context HGLRC=%d still active", (int)a);
dglMakeCurrent(NULL, NULL);
}
#ifdef GLD_THREADS
// Serialize access to DirectDraw or DDS operations
if (glb.bMultiThreaded)
EnterCriticalSection(&CriticalSection);
#endif
// We are about to destroy all Direct3D objects.
// Therefore we must disable rendering
lpCtx->bCanRender = FALSE;
// This exception handler was installed to catch some
// particularly nasty apps. Console apps that call exit()
// fall into this catagory (i.e. Win32 Glut).
// VC cannot successfully implement multiple exception handlers
// if more than one exception occurs. Therefore reverting back to
// single exception handler as Keith originally had it. (DaveM)
#define WARN_MESSAGE(p) strcpy(argstr, (#p));
#define SAFE_RELEASE(p) WARN_MESSAGE(p); RELEASE(p);
__try {
#ifdef _USE_GLD3_WGL
WARN_MESSAGE(gl_destroy_framebuffer);
if (lpCtx->glBuffer)
_mesa_destroy_framebuffer(lpCtx->glBuffer);
WARN_MESSAGE(gl_destroy_context);
if (lpCtx->glCtx)
_mesa_destroy_context(lpCtx->glCtx);
WARN_MESSAGE(gl_destroy_visual);
if (lpCtx->glVis)
_mesa_destroy_visual(lpCtx->glVis);
_gldDriver.DestroyDrawable(lpCtx);
#else
// Destroy the Mesa context
WARN_MESSAGE(gl_destroy_framebuffer);
if (lpCtx->glBuffer)
(*mesaFuncs.gl_destroy_framebuffer)(lpCtx->glBuffer);
WARN_MESSAGE(gl_destroy_context);
if (lpCtx->glCtx)
(*mesaFuncs.gl_destroy_context)(lpCtx->glCtx);
WARN_MESSAGE(gl_destroy_visual);
if (lpCtx->glVis)
(*mesaFuncs.gl_destroy_visual)(lpCtx->glVis);
SAFE_RELEASE(lpCtx->m_pvbuf); // release D3D vertex buffer
SAFE_RELEASE(lpCtx->m_vbuf); // release D3D vertex buffer
// Delete the global palette
SAFE_RELEASE(lpCtx->lpGlobalPalette);
// Clean up.
if (lpCtx->lpViewport3) {
if (lpCtx->lpDev3) IDirect3DDevice3_DeleteViewport(lpCtx->lpDev3, lpCtx->lpViewport3);
SAFE_RELEASE(lpCtx->lpViewport3);
lpCtx->lpViewport3 = NULL;
}
SAFE_RELEASE(lpCtx->lpDev3);
if (lpCtx->lpDepth4) {
if (lpCtx->lpBack4)
IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpBack4, 0L, lpCtx->lpDepth4);
else
IDirectDrawSurface4_DeleteAttachedSurface(lpCtx->lpFront4, 0L, lpCtx->lpDepth4);
SAFE_RELEASE(lpCtx->lpDepth4);
lpCtx->lpDepth4 = NULL;
}
SAFE_RELEASE(lpCtx->lpBack4);
SAFE_RELEASE(lpCtx->lpFront4);
if (lpCtx->bFullscreen) {
IDirectDraw4_RestoreDisplayMode(lpCtx->lpDD4);
IDirectDraw4_SetCooperativeLevel(lpCtx->lpDD4, NULL, DDSCL_NORMAL);
}
SAFE_RELEASE(lpCtx->lpD3D3);
SAFE_RELEASE(lpCtx->lpDD4);
SAFE_RELEASE(lpCtx->lpDD1);
#endif // _ULSE_GLD3_WGL
}
__except(EXCEPTION_EXECUTE_HANDLER) {
ddlogPrintf(DDLOG_WARN, "Exception raised in dglDeleteContext: %s", argstr);
}
// Restore the window message handler because this context may be used
// again by another window with a *different* message handler. (DaveM)
if (lpCtx->lpfnWndProc) {
SetWindowLong(lpCtx->hWnd, GWL_WNDPROC, (LONG)lpCtx->lpfnWndProc);
lpCtx->lpfnWndProc = (LONG)NULL;
}
lpCtx->bAllocated = FALSE; // This context is now free for use
#ifdef GLD_THREADS
// Release serialized access
if (glb.bMultiThreaded)
LeaveCriticalSection(&CriticalSection);
#endif
return TRUE;
}
// ***********************************************************************
BOOL dglSwapBuffers(
HDC hDC)
{
RECT rSrcRect; // Source rectangle
RECT rDstRect; // Destination rectangle
POINT pt;
HRESULT hResult;
DDBLTFX bltFX;
DWORD dwBlitFlags;
DDBLTFX *lpBltFX;
// DWORD dwThreadId = GetCurrentThreadId();
HGLRC hGLRC = dglGetCurrentContext();
DGL_ctx *lpCtx = dglGetContextAddress(hGLRC);
HWND hWnd;
HDC hDCAux; // for memory DC
int x,y,w,h; // for memory DC BitBlt
#if 0 // Perhaps not a good idea. Called too often. KH
// Validate license
if (!dglValidate())
return FALSE;
#endif
if (!lpCtx) {
return TRUE; //FALSE; // No current context
}
if (!lpCtx->bCanRender) {
// Don't return false else some apps will bail.
return TRUE;
}
hWnd = lpCtx->hWnd;
if (hDC != lpCtx->hDC) {
ddlogPrintf(DDLOG_WARN, "dglSwapBuffers: HDC=%X does not match HDC=%X for HGLRC=%d", hDC, lpCtx->hDC, hGLRC);
hWnd = WindowFromDC(hDC);
}
#ifndef _USE_GLD3_WGL
// Ensure that the surfaces exist before we tell
// the device to render to them.
IDirectDraw4_RestoreAllSurfaces(lpCtx->lpDD4);
// Make sure that the vertex caches have been emptied
// dglStateChange(lpCtx);
// Some OpenGL programs don't issue a glFinish - check for it here.
if (lpCtx->bSceneStarted) {
IDirect3DDevice3_EndScene(lpCtx->lpDev3);
lpCtx->bSceneStarted = FALSE;
}
#endif
#if 0
// If the calling app is not active then we don't need to Blit/Flip.
// We can therefore simply return TRUE.
if (!glb.bAppActive)
return TRUE;
// Addendum: This is WRONG! We should bail if the app is *minimized*,
// not merely if the app is just plain 'not active'.
// KeithH, 27/May/2000.
#endif
// Check for non-window DC = memory DC ?
if (hWnd == NULL) {
if (GetClipBox(hDC, &rSrcRect) == ERROR)
return TRUE;
// Use GDI BitBlt instead from compatible DirectDraw DC
x = rSrcRect.left;
y = rSrcRect.top;
w = rSrcRect.right - rSrcRect.left;
h = rSrcRect.bottom - rSrcRect.top;
// Ack. DX8 does not have a GetDC() function...
// TODO: Defer to DX7 or DX9 drivers... (DaveM)
return TRUE;
}
// Bail if window client region is not drawable, like in Solid Edge
if (!IsWindow(hWnd) /* || !IsWindowVisible(hWnd) */ || !GetClientRect(hWnd, &rSrcRect))
return TRUE;
#ifdef GLD_THREADS
// Serialize access to DirectDraw or DDS operations
if (glb.bMultiThreaded)
EnterCriticalSection(&CriticalSection);
#endif
#ifdef _USE_GLD3_WGL
// Notify Mesa of impending swap, so Mesa can flush internal buffers.
_mesa_notifySwapBuffers(lpCtx->glCtx);
// Now perform driver buffer swap
_gldDriver.SwapBuffers(lpCtx, hDC, hWnd);
#else
if (lpCtx->bFullscreen) {
// Sync with retrace if required
if (glb.bWaitForRetrace) {
IDirectDraw4_WaitForVerticalBlank(
lpCtx->lpDD4,
DDWAITVB_BLOCKBEGIN,
0);
}
// Perform the fullscreen flip
TRY(IDirectDrawSurface4_Flip(
lpCtx->lpFront4,
NULL,
DDFLIP_WAIT),
"dglSwapBuffers: Flip");
} else {
// Calculate current window position and size
pt.x = pt.y = 0;
ClientToScreen(hWnd, &pt);
GetClientRect(hWnd, &rDstRect);
if (rDstRect.right > lpCtx->dwModeWidth)
rDstRect.right = lpCtx->dwModeWidth;
if (rDstRect.bottom > lpCtx->dwModeHeight)
rDstRect.bottom = lpCtx->dwModeHeight;
OffsetRect(&rDstRect, pt.x, pt.y);
rSrcRect.left = rSrcRect.top = 0;
rSrcRect.right = lpCtx->dwWidth;
rSrcRect.bottom = lpCtx->dwHeight;
if (rSrcRect.right > lpCtx->dwModeWidth)
rSrcRect.right = lpCtx->dwModeWidth;
if (rSrcRect.bottom > lpCtx->dwModeHeight)
rSrcRect.bottom = lpCtx->dwModeHeight;
if (glb.bWaitForRetrace) {
// Sync the blit to the vertical retrace
ZeroMemory(&bltFX, sizeof(bltFX));
bltFX.dwSize = sizeof(bltFX);
bltFX.dwDDFX = DDBLTFX_NOTEARING;
dwBlitFlags = DDBLT_WAIT | DDBLT_DDFX;
lpBltFX = &bltFX;
} else {
dwBlitFlags = DDBLT_WAIT;
lpBltFX = NULL;
}
// Perform the actual blit
TRY(IDirectDrawSurface4_Blt(
lpCtx->lpFront4,
&rDstRect,
lpCtx->lpBack4, // Blit source
&rSrcRect,
dwBlitFlags,
lpBltFX),
"dglSwapBuffers: Blt");
}
#endif // _USE_GLD3_WGL
#ifdef GLD_THREADS
// Release serialized access
if (glb.bMultiThreaded)
LeaveCriticalSection(&CriticalSection);
#endif
// TODO: Re-instate rendering bitmap snapshot feature??? (DaveM)
// Render frame is completed
ValidateRect(hWnd, NULL);
lpCtx->bFrameStarted = FALSE;
return TRUE;
}
// ***********************************************************************