windows-nt/Source/XPSP1/NT/windows/appcompat/shims/external/emulateopengl.cpp
2020-09-26 16:20:57 +08:00

309 lines
7.3 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
EmulateOpenGL.cpp
Abstract:
Notes:
This is a general purpose shim for Quake engine based games.
History:
09/02/2000 linstev Created
11/30/2000 a-brienw Converted to shim version 2.
03/02/2001 a-brienw Cleared data structure on allocation and checked
to see that DX was released on detach
--*/
#include "precomp.h"
#include "EmulateOpenGL_opengl32.hpp"
extern Globals *g_OpenGLValues;
extern BOOL g_bDoTexelAlignmentHack;
IMPLEMENT_SHIM_BEGIN(EmulateOpenGL)
#include "ShimHookMacro.h"
APIHOOK_ENUM_BEGIN
APIHOOK_ENUM_ENTRY(LoadLibraryA)
APIHOOK_ENUM_ENTRY(FreeLibrary)
APIHOOK_ENUM_END
/*++
Parse the command line.
--*/
BOOL ParseCommandLine(const char * commandLine)
{
// Force the default values
g_bDoTexelAlignmentHack = FALSE;
// Search the beginning of the command line for these switches
//
// Switch Default Meaning
//================ ======= =========================================================
// TexelAlignment No Translate geometry by (-0.5 pixels in x, -0.5 pixels in y)
// along the screen/viewport plane. This is achieved by
// fudging the projection matrix that is passed to D3D.
// The purpose of this hack is to allow D3D rendering to accomodate
// content that was authored for OpenGL with the dependency that
// sampled texels end up pixel-aligned when drawn. The root of the
// problem is that D3D and OpenGL definitions of texel center
// differ by 0.5.
// The "ideal" fix would have perturbed texture coordinates
// rather than geometry, perhaps using texture transform,
// but this would be more of a perf. issue than just mucking with
// the projection matrix. The drawback to mucking with the
// projection matrix is that all geometry gets
// drawn (very slightly) offset from the intended locations on screen.
// Hence, we make this hack optional.
// (it is currently needed by Kingpin: Life of Crime - Whistler bug 402471)
//
//
CSTRING_TRY
{
CString csCl(commandLine);
CStringParser csParser(csCl, L";");
int argc = csParser.GetCount();
if (csParser.GetCount() == 0)
{
return TRUE; // Not an error
}
for (int i = 0; i < argc; ++i)
{
CString & csArg = csParser[i];
DPFN( eDbgLevelSpew, "Argv[%d] == (%S)", i, csArg.Get());
if (csArg.CompareNoCase(L"TexelAlignment") == 0)
{
g_bDoTexelAlignmentHack = TRUE;
}
// else if(csArg.CompareNoCase(L"AddYourNewParametersHere") == 0) {}
}
}
CSTRING_CATCH
{
return FALSE;
}
return TRUE;
}
/*++
Determine if there are any accelerated pixel formats available. This is done
by enumerating the pixel formats and testing for acceleration.
--*/
BOOL
IsGLAccelerated()
{
HMODULE hMod = NULL;
HDC hdc = NULL;
int i;
PIXELFORMATDESCRIPTOR pfd;
_pfn_wglDescribePixelFormat pfnDescribePixelFormat;
//
// Cache the last result if we've been here before
//
static iFormat = -1;
if (iFormat != -1)
{
goto Exit;
}
//
// Load original opengl
//
hMod = LoadLibraryA("opengl32");
if (!hMod)
{
LOG("EmulateOpenGL", eDbgLevelError, "Failed to load OpenGL32");
goto Exit;
}
//
// Get wglDescribePixelFormat so we can enumerate pixel formats
//
pfnDescribePixelFormat = (_pfn_wglDescribePixelFormat) GetProcAddress(
hMod, "wglDescribePixelFormat");
if (!pfnDescribePixelFormat)
{
LOG("EmulateOpenGL", eDbgLevelError, "API wglDescribePixelFormat not found in OpenGL32");
goto Exit;
}
//
// Get a Display DC for enumeration
//
hdc = GetDC(NULL);
if (!hdc)
{
LOG("EmulateOpenGL", eDbgLevelError, "GetDC(NULL) Failed");
goto Exit;
}
//
// Run the list of pixel formats looking for any that are non-generic,
// i.e. accelerated by an ICD
//
i = 1;
iFormat = 0;
while ((*pfnDescribePixelFormat)(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd))
{
if ((pfd.dwFlags & PFD_DRAW_TO_WINDOW) &&
(pfd.dwFlags & PFD_SUPPORT_OPENGL) &&
(!(pfd.dwFlags & PFD_GENERIC_FORMAT)))
{
iFormat = i;
break;
}
i++;
}
Exit:
if (hdc)
{
ReleaseDC(NULL, hdc);
}
if (hMod)
{
FreeLibrary(hMod);
}
return (iFormat > 0);
}
/*++
Redirect OpenGL LoadLibrary to the current DLL. Note we don't have to call
LoadLibrary ourselves to increase the ref count, since we hook FreeLibrary to
make sure we don't get freed.
--*/
HINSTANCE
APIHOOK(LoadLibraryA)(LPCSTR lpLibFileName)
{
if (lpLibFileName &&
(stristr(lpLibFileName, "opengl32") || stristr(lpLibFileName, "glide2x")))
{
if (!IsGLAccelerated())
{
#ifdef DODPFS
LOG( "EmulateOpenGL",
eDbgLevelInfo,
"No OpenGL acceleration detected: QuakeGL wrapper enabled" );
#endif
return g_hinstDll;
}
else
{
#ifdef DODPFS
LOG( "EmulateOpenGL",
eDbgLevelInfo,
"OpenGL acceleration detected: Wrapper disabled" );
#endif
}
}
return ORIGINAL_API(LoadLibraryA)(lpLibFileName);
}
/*++
Since this module is the quake wrapper, make sure we don't free ourselves.
--*/
BOOL
APIHOOK(FreeLibrary)(HMODULE hLibModule)
{
BOOL bRet;
if (hLibModule == g_hinstDll)
{
bRet = TRUE;
}
else
{
bRet = ORIGINAL_API(FreeLibrary)(hLibModule);
}
return bRet;
}
/*++
Register hooked functions
--*/
BOOL
NOTIFY_FUNCTION(DWORD fdwReason)
{
BOOL bSuccess = TRUE;
if (fdwReason == DLL_PROCESS_ATTACH)
{
g_OpenGLValues = new Globals;
if (g_OpenGLValues != NULL)
{
memset(g_OpenGLValues, 0, sizeof(Globals));
}
bSuccess &= ParseCommandLine(COMMAND_LINE);
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
if (g_OpenGLValues != NULL)
{
if (g_OpenGLValues->m_d3ddev != NULL)
{
g_OpenGLValues->m_d3ddev->Release();
g_OpenGLValues->m_d3ddev = 0;
}
}
}
bSuccess &= (g_OpenGLValues != NULL);
return bSuccess;
}
HOOK_BEGIN
APIHOOK_ENTRY(KERNEL32.DLL, LoadLibraryA)
APIHOOK_ENTRY(KERNEL32.DLL, FreeLibrary)
CALL_NOTIFY_FUNCTION
HOOK_END
IMPLEMENT_SHIM_END