windows-nt/Source/XPSP1/NT/multimedia/opengl/client/wgl.c
2020-09-26 16:20:57 +08:00

1069 lines
33 KiB
C

/******************************Module*Header*******************************\
* Module Name: wgl.c
*
* Routines to integrate Windows NT and OpenGL.
*
* Created: 10-26-1993
* Author: Hock San Lee [hockl]
*
* Copyright (c) 1993 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <ntcsrdll.h>
#include <ntpsapi.h>
#include <wingdip.h>
#include <glscreen.h>
#include <glgenwin.h>
#include "batchinf.h"
#include "glapi.h"
#include "glsbcltu.h"
#include "wgldef.h"
#include "metasup.h"
#include "glclt.h"
#include "gencx.h"
#include "context.h"
#include "global.h"
#include "mcdcx.h"
// Static functions prototypes
static PROC pfnGenGlExtProc(LPCSTR lpszProc);
static PROC pfnSimGlExtProc(LPCSTR lpszProc);
/******************************Public*Routine******************************\
*
* wglObjectType
*
* Returns GetObjectType result with the exception that
* metafile-spooled printer DC's come back as metafile objects
*
* History:
* Fri Jun 16 12:10:07 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD APIENTRY wglObjectType(HDC hdc)
{
DWORD dwObjectType;
dwObjectType = GetObjectType(hdc);
#ifdef GL_METAFILE
if (dwObjectType == OBJ_DC &&
pfnGdiIsMetaPrintDC != NULL &&
GlGdiIsMetaPrintDC(hdc))
{
dwObjectType = OBJ_ENHMETADC;
}
#endif
// OBJ_DDRAW is reserved as a special identifier. Make sure
// we aren't returning it from here.
ASSERTOPENGL(dwObjectType != OBJ_DDRAW,
"Unexpected object type\n");
return dwObjectType;
}
/******************************Public*Routine******************************\
* wglDeleteContext(HGLRC hrc)
*
* Delete the rendering context
*
* Arguments:
* hrc - Rendering context.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Rewrote it.
\**************************************************************************/
BOOL WINAPI wglDeleteContext(HGLRC hrc)
{
PLHE plheRC;
ULONG irc;
PLRC plrc;
BOOL bRet = FALSE;
DBGENTRY("wglDeleteContext\n");
// Flush OpenGL calls.
GLFLUSH();
// Validate the RC.
if (cLockHandle((ULONG_PTR)hrc) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglDeleteContext: can't lock hrc 0x%lx\n", hrc);
return(bRet);
}
irc = MASKINDEX(hrc);
plheRC = pLocalTable + irc;
plrc = (PLRC) plheRC->pv;
ASSERTOPENGL(plrc->ident == LRC_IDENTIFIER, "wglDeleteContext: Bad plrc\n");
DBGLEVEL2(LEVEL_INFO, "wglDeleteContext: hrc: 0x%lx, plrc: 0x%lx\n", hrc, plrc);
if (plrc->tidCurrent != INVALID_THREAD_ID)
{
// The RC must be current to this thread because makecurrent locks
// down the handle.
ASSERTOPENGL(plrc->tidCurrent == GetCurrentThreadId(),
"wglDeleteCurrent: hrc is current to another thread\n");
// Make the RC inactive first.
if (!bMakeNoCurrent())
{
DBGERROR("wglDeleteCurrent: bMakeNoCurrent failed\n");
}
}
if (plrc->dhrc)
{
// If it is a device format, call the driver to delete its context.
bRet = plrc->pGLDriver->pfnDrvDeleteContext(plrc->dhrc);
plrc->dhrc = (DHGLRC) 0;
}
else
{
#ifdef GL_METAFILE
// If we have metafile state, clean it up
if (plrc->uiGlsCaptureContext != 0 ||
plrc->uiGlsPlaybackContext != 0)
{
DeleteMetaRc(plrc);
}
#endif
// If it is a generic format, call the server to delete its context.
bRet = __wglDeleteContext((HANDLE) plheRC->hgre);
}
// Always clean up local objects.
vFreeLRC(plrc);
vFreeHandle(irc); // it unlocks handle too
if (!bRet)
DBGERROR("wglDeleteContext failed\n");
return(bRet);
}
/******************************Public*Routine******************************\
* wglGetCurrentContext(VOID)
*
* Return the current rendering context
*
* Arguments:
* None
*
* Returns:
* hrc - Rendering context.
*
* History:
* Tue Oct 26 10:25:26 1993 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
HGLRC WINAPI wglGetCurrentContext(VOID)
{
DBGENTRY("wglGetCurrentContext\n");
if (GLTEB_CLTCURRENTRC())
return(GLTEB_CLTCURRENTRC()->hrc);
else
return((HGLRC) 0);
}
/******************************Public*Routine******************************\
* wglGetCurrentDC(VOID)
*
* Return the device context that is associated with the current rendering
* context
*
* Arguments:
* None
*
* Returns:
* hdc - device context.
*
* History:
* Mon Jan 31 12:15:12 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
HDC WINAPI wglGetCurrentDC(VOID)
{
PLRC plrc;
DBGENTRY("wglGetCurrentDC\n");
plrc = GLTEB_CLTCURRENTRC();
if (plrc != NULL)
{
return plrc->gwidCurrent.hdc;
}
else
{
return((HDC) 0);
}
}
/******************************Public*Routine******************************\
* wglUseFontBitmapsA
* wglUseFontBitmapsW
*
* Stubs that call wglUseFontBitmapsAW with the bUnicode flag set
* appropriately.
*
* History:
* 11-Mar-1994 gilmanw
* Changed to call wglUseFontBitmapsAW.
*
* 17-Dec-1993 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL WINAPI wglUseFontBitmapsAW(HDC hdc, DWORD first, DWORD count,
DWORD listBase, BOOL bUnicode);
BOOL WINAPI
wglUseFontBitmapsA(HDC hdc, DWORD first, DWORD count, DWORD listBase)
{
return wglUseFontBitmapsAW(hdc, first, count, listBase, FALSE);
}
BOOL WINAPI
wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase)
{
return wglUseFontBitmapsAW(hdc, first, count, listBase, TRUE);
}
/******************************Public*Routine******************************\
* wglUseFontBitmapsAW
*
* Uses the current font in the specified DC to generate a series of OpenGL
* display lists, each of which consists of a glyph bitmap.
*
* Each glyph bitmap is generated by calling ExtTextOut to draw the glyph
* into a memory DC. The contents of the memory DC are then copied into
* a buffer by GetDIBits and then put into the OpenGL display list.
*
* ABC spacing is used (if GetCharABCWidth() is supported by the font) to
* determine proper placement of the glyph origin and character advance width.
* Otherwise, A = C = 0 spacing is assumed and GetCharWidth() is used for the
* advance widths.
*
* Returns:
*
* TRUE if successful, FALSE otherwise.
*
* History:
* 17-Dec-1993 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
BOOL WINAPI
wglUseFontBitmapsAW(
HDC hdc, // use HFONT from this DC
DWORD first, // generate glyphs starting with this Unicode codepoint
DWORD count, // range is this long [first, first+count-1]
DWORD listBase, // starting display list number
BOOL bUnicode // TRUE for if in Unicode mode, FALSE if in Ansi mode
)
{
BOOL bRet = FALSE; // return value
HDC hdcMem; // render glyphs to this memory DC
HBITMAP hbm; // monochrome bitmap for memory DC
LPABC pabc, pabcTmp, pabcEnd; // array of ABC spacing
LPINT piWidth, piTmp, piWidthEnd; // array of char adv. widths
WCHAR wc; // current Unicode char to render
RECT rc; // background rectangle to clear
TEXTMETRICA tm; // metrics of the font
BOOL bTrueType; // TrueType supports ABC spacing
int iMaxWidth = 1; // maximum glyph width
int iBitmapWidth; // DWORD aligned bitmap width
BYTE ajBmi[sizeof(BITMAPINFO) + sizeof(RGBQUAD)];
BITMAPINFO *pbmi = (BITMAPINFO *)ajBmi;// bitmap info for GetDIBits
GLint iUnpackRowLength; // save GL_UNPACK_ROW_LENGTH
GLint iUnpackAlign; // save GL_UNPACK_ALIGNMENT
PVOID pv; // pointer to glyph bitmap buffer
// Return error if there is no current RC.
if (!GLTEB_CLTCURRENTRC())
{
WARNING("wglUseFontBitmapsAW: no current RC\n");
SetLastError(ERROR_INVALID_HANDLE);
return bRet;
}
// Get TEXTMETRIC. The only fields used are those that are invariant with
// respect to Unicode vs. ANSI. Therefore, we can call GetTextMetricsA for
// both cases.
if ( !GetTextMetricsA(hdc, &tm) )
{
WARNING("wglUseFontBitmapsAW: GetTextMetricsA failed\n");
return bRet;
}
// If its a TrueType font, we can get ABC spacing.
if ( bTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) )
{
// Allocate memory for array of ABC data.
if ( (pabc = (LPABC) ALLOC(sizeof(ABC) * count)) == (LPABC) NULL )
{
WARNING("wglUseFontBitmapsAW: Alloc of pabc failed\n");
return bRet;
}
// Get ABC metrics.
if ( bUnicode )
{
if ( !GetCharABCWidthsW(hdc, first, first + count - 1, pabc) )
{
WARNING("wglUseFontBitmapsAW: GetCharABCWidthsW failed\n");
FREE(pabc);
return bRet;
}
}
else
{
if ( !GetCharABCWidthsA(hdc, first, first + count - 1, pabc) )
{
WARNING("wglUseFontBitmapsAW: GetCharABCWidthsA failed\n");
FREE(pabc);
return bRet;
}
}
// Find max glyph width.
for (pabcTmp = pabc, pabcEnd = pabc + count;
pabcTmp < pabcEnd;
pabcTmp++)
{
if (iMaxWidth < (int) pabcTmp->abcB)
iMaxWidth = pabcTmp->abcB;
}
}
// Otherwise we will have to use just the advance width and assume
// A = C = 0.
else
{
// Allocate memory for array of ABC data.
if ( (piWidth = (LPINT) ALLOC(sizeof(INT) * count)) == (LPINT) NULL )
{
WARNING("wglUseFontBitmapsAW: Alloc of pabc failed\n");
return bRet;
}
// Get char widths.
if ( bUnicode )
{
if ( !GetCharWidthW(hdc, first, first + count - 1, piWidth) )
{
WARNING("wglUseFontBitmapsAW: GetCharWidthW failed\n");
FREE(piWidth);
return bRet;
}
}
else
{
if ( !GetCharWidthA(hdc, first, first + count - 1, piWidth) )
{
WARNING("wglUseFontBitmapsAW: GetCharWidthA failed\n");
FREE(piWidth);
return bRet;
}
}
// Find max glyph width.
for (piTmp = piWidth, piWidthEnd = piWidth + count;
piTmp < piWidthEnd;
piTmp++)
{
if (iMaxWidth < *piTmp)
iMaxWidth = *piTmp;
}
}
// Compute the dword aligned width. Bitmap scanlines must be aligned.
iBitmapWidth = (iMaxWidth + 31) & -32;
// Allocate memory for the DIB.
if ( (pv = (PVOID)
ALLOC((iBitmapWidth / 8) * tm.tmHeight)) == (PVOID) NULL )
{
WARNING("wglUseFontBitmapsAW: Alloc of pv failed\n");
(bTrueType) ? FREE(pabc) : FREE(piWidth);
return bRet;
}
// Create compatible DC/bitmap big enough to accomodate the biggest glyph
// in the range requested.
//!!!XXX -- Future optimization: use CreateDIBSection so that we
//!!!XXX don't need to do a GetDIBits for each glyph. Saves
//!!!XXX lots of CSR overhead.
hdcMem = CreateCompatibleDC(hdc);
if ( (hbm = CreateBitmap(iBitmapWidth, tm.tmHeight, 1, 1, (VOID *) NULL)) == (HBITMAP) NULL )
{
WARNING("wglUseFontBitmapsAW: CreateBitmap failed\n");
(bTrueType) ? FREE(pabc) : FREE(piWidth);
FREE(pv);
DeleteDC(hdcMem);
return bRet;
}
SelectObject(hdcMem, hbm);
SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT));
SetMapMode(hdcMem, MM_TEXT);
SetTextAlign(hdcMem, TA_TOP | TA_LEFT);
SetBkColor(hdcMem, RGB(0, 0, 0));
SetBkMode(hdcMem, OPAQUE);
SetTextColor(hdcMem, RGB(255, 255, 255));
// Setup bitmap info header to retrieve a DIB from the compatible bitmap.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = iBitmapWidth;
pbmi->bmiHeader.biHeight = tm.tmHeight;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 1;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
pbmi->bmiColors[0].rgbRed = 0;
pbmi->bmiColors[0].rgbGreen = 0;
pbmi->bmiColors[0].rgbBlue = 0;
pbmi->bmiColors[1].rgbRed = 0xff;
pbmi->bmiColors[1].rgbGreen = 0xff;
pbmi->bmiColors[1].rgbBlue = 0xff;
// Setup OpenGL to accept our bitmap format.
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &iUnpackRowLength);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &iUnpackAlign);
if (glGetError() != GL_NO_ERROR)
{
//XXX too noisy on debug builds running stress with mode changes
//WARNING("wglUseFontBitmapsAW: failed to get GL state\n");
goto wglUseFontBitmapsAW_exit;
}
glPixelStorei(GL_UNPACK_ROW_LENGTH, iBitmapWidth);
if (glGetError() != GL_NO_ERROR)
{
//XXX too noisy on debug builds running stress with mode changes
//WARNING("wglUseFontBitmapsAW: failed to set GL state, row length\n");
goto wglUseFontBitmapsAW_restore_state;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (glGetError() != GL_NO_ERROR)
{
//XXX too noisy on debug builds running stress with mode changes
//WARNING("wglUseFontBitmapsAW: failed to set GL state, alignment\n");
goto wglUseFontBitmapsAW_restore_state;
}
// Get the glyphs. Each glyph is rendered one at a time into the the
// memory DC with ExtTextOutW (notice that the optional rectangle is
// used to clear the background). Each glyph is then copied out of the
// memory DC's bitmap with GetDIBits into a buffer. This buffer is passed
// to glBitmap as each display list is created.
rc.left = 0;
rc.top = 0;
rc.right = iBitmapWidth;
rc.bottom = tm.tmHeight;
pabcTmp = pabc;
piTmp = piWidth;
for (wc = (WCHAR) first; wc < (WCHAR) (first + count); wc++, listBase++)
{
//!!!XXX -- Future optimization: grab all the glyphs with a single
//!!!XXX call to ExtTextOutA and GetDIBits into a large bitmap.
//!!!XXX This would save a lot of per glyph CSR and call overhead.
//!!!XXX A tall, thin bitmap with the glyphs arranged vertically
//!!!XXX would be convenient because then we wouldn't have to change
//!!!XXX the OpenGL pixel store row length for each glyph (which
//!!!XXX we would need to do if the glyphs were printed horizontal).
if ( bUnicode )
{
if ( !ExtTextOutW(hdcMem, bTrueType ? -pabcTmp->abcA : 0, 0, ETO_OPAQUE, &rc, &wc, 1, (INT *) NULL) ||
!GetDIBits(hdcMem, hbm, 0, tm.tmHeight, pv, pbmi, DIB_RGB_COLORS) )
{
WARNING("wglUseFontBitmapsAW: failed to render glyph\n");
goto wglUseFontBitmapsAW_restore_state;
}
}
else
{
if ( !ExtTextOutA(hdcMem, bTrueType ? -pabcTmp->abcA : 0, 0, ETO_OPAQUE, &rc, (LPCSTR) &wc, 1, (INT *) NULL) ||
!GetDIBits(hdcMem, hbm, 0, tm.tmHeight, pv, pbmi, DIB_RGB_COLORS) )
{
WARNING("wglUseFontBitmapsAW: failed to render glyph\n");
goto wglUseFontBitmapsAW_restore_state;
}
}
glNewList(listBase, GL_COMPILE);
glBitmap((GLsizei) iBitmapWidth,
(GLsizei) tm.tmHeight,
(GLfloat) (bTrueType ? -pabcTmp->abcA : 0),
(GLfloat) tm.tmDescent,
(GLfloat) (bTrueType ? (pabcTmp->abcA + pabcTmp->abcB + pabcTmp->abcC) : *piTmp),
(GLfloat) 0.0,
(GLubyte *) pv);
glEndList();
if (bTrueType)
pabcTmp++;
else
piTmp++;
}
// We can finally return success.
bRet = TRUE;
// Free resources.
wglUseFontBitmapsAW_restore_state:
glPixelStorei(GL_UNPACK_ROW_LENGTH, iUnpackRowLength);
glPixelStorei(GL_UNPACK_ALIGNMENT, iUnpackAlign);
wglUseFontBitmapsAW_exit:
(bTrueType) ? FREE(pabc) : FREE(piWidth);
FREE(pv);
DeleteDC(hdcMem);
DeleteObject(hbm);
return bRet;
}
/******************************Public*Routine******************************\
*
* wglShareLists
*
* Allows a rendering context to share the display lists of another RC
*
* Returns:
* TRUE if successful, FALSE otherwise
*
* History:
* Tue Dec 13 14:57:17 1994 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL WINAPI
wglShareLists(HGLRC hrcSource, HGLRC hrcShare)
{
BOOL fRet;
PLRC plrcSource, plrcShare;
ULONG irc;
PLHE plheRC;
HANDLE hrcSrvSource, hrcSrvShare;
GLFLUSH();
fRet = FALSE;
// Validate the contexts
if (cLockHandle((ULONG_PTR)hrcSource) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglShareLists: can't lock hrcSource 0x%lx\n",
hrcSource);
goto wglShareListsEnd_nolock;
}
irc = MASKINDEX(hrcSource);
plheRC = pLocalTable + irc;
plrcSource = (PLRC)plheRC->pv;
hrcSrvSource = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcSource->ident == LRC_IDENTIFIER,
"wglShareLists: Bad plrc\n");
if (cLockHandle((ULONG_PTR)hrcShare) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglShareLists: can't lock hrcShare 0x%lx\n",
hrcShare);
goto wglShareListsEnd_onelock;
}
irc = MASKINDEX(hrcShare);
plheRC = pLocalTable + irc;
plrcShare = (PLRC)plheRC->pv;
hrcSrvShare = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcShare->ident == LRC_IDENTIFIER,
"wglShareLists: Bad plrc\n");
#ifdef GL_METAFILE
// Metafile RC's can't share lists to ensure that metafiles are
// completely self-sufficient
if (plrcSource->uiGlsCaptureContext != 0 ||
plrcShare->uiGlsCaptureContext != 0 ||
plrcSource->uiGlsPlaybackContext != 0 ||
plrcShare->uiGlsPlaybackContext != 0)
{
DBGLEVEL(LEVEL_ERROR,
"wglShareLists: Attempt to share metafile RC\n");
SetLastError(ERROR_INVALID_HANDLE);
goto wglShareListsEnd;
}
#endif
// Lists can only be shared between like implementations so make
// sure that both contexts are either driver contexts or generic
// contexts
if ((plrcSource->dhrc != 0) != (plrcShare->dhrc != 0))
{
DBGLEVEL(LEVEL_ERROR, "wglShareLists: mismatched implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglShareListsEnd;
}
if (plrcSource->dhrc == 0)
{
PIXELFORMATDESCRIPTOR *ppfdShare, *ppfdSource;
// Fail sharing unless color parameters match for the two contexts
ppfdShare = &((__GLGENcontext *)hrcSrvShare)->gsurf.pfd;
ppfdSource = &((__GLGENcontext *)hrcSrvSource)->gsurf.pfd;
if (ppfdShare->iPixelType != ppfdSource->iPixelType ||
ppfdShare->cColorBits != ppfdSource->cColorBits ||
ppfdShare->cRedBits != ppfdSource->cRedBits ||
ppfdShare->cRedShift != ppfdSource->cRedShift ||
ppfdShare->cGreenBits != ppfdSource->cGreenBits ||
ppfdShare->cGreenShift != ppfdSource->cGreenShift ||
ppfdShare->cBlueBits != ppfdSource->cBlueBits ||
ppfdShare->cBlueShift != ppfdSource->cBlueShift ||
ppfdShare->cAlphaBits != ppfdSource->cAlphaBits ||
ppfdShare->cAlphaShift != ppfdSource->cAlphaShift ||
(ppfdShare->dwFlags & PFD_GENERIC_ACCELERATED) !=
(ppfdSource->dwFlags & PFD_GENERIC_ACCELERATED))
{
SetLastError(ERROR_INVALID_PIXEL_FORMAT);
goto wglShareListsEnd;
}
// For generic contexts, tell the server to share the lists
fRet = __wglShareLists(hrcSrvShare, hrcSrvSource);
if (!fRet)
{
DBGERROR("wglShareLists: server call failed\n");
}
}
else
{
// For device contexts tell the server to share the lists
// Ensure that both implementations are the same
if (plrcSource->pGLDriver != plrcShare->pGLDriver)
{
DBGLEVEL(LEVEL_ERROR, "wglShareLists: mismatched "
"implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglShareListsEnd;
}
ASSERTOPENGL(plrcSource->pGLDriver != NULL,
"wglShareLists: No GLDriver\n");
// Older drivers may not support this entry point, so
// fail the call if they don't
if (plrcSource->pGLDriver->pfnDrvShareLists == NULL)
{
WARNING("wglShareLists called on driver context "
"without driver support\n");
SetLastError(ERROR_NOT_SUPPORTED);
}
else
{
fRet = plrcSource->pGLDriver->pfnDrvShareLists(plrcSource->dhrc,
plrcShare->dhrc);
}
}
wglShareListsEnd:
vUnlockHandle((ULONG_PTR)hrcShare);
wglShareListsEnd_onelock:
vUnlockHandle((ULONG_PTR)hrcSource);
wglShareListsEnd_nolock:
return fRet;
}
/******************************Public*Routine******************************\
*
* wglGetDefaultProcAddress
*
* Returns generic extension functions for metafiling
*
* History:
* Tue Nov 28 16:40:35 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
PROC WINAPI wglGetDefaultProcAddress(LPCSTR lpszProc)
{
return pfnGenGlExtProc(lpszProc);
}
/******************************Public*Routine******************************\
* wglGetProcAddress
*
* The wglGetProcAddress function returns the address of an OpenGL extension
* function to be used with the current OpenGL rendering context.
*
* Arguments:
* lpszProc - Points to a null-terminated string containing the function
* name. The function must be an extension supported by the
* implementation.
*
* Returns:
* If the function succeeds, the return value is the address of the extension
* function. If no current context exists or the function fails, the return
* value is NULL. To get extended error information, call GetLastError.
*
* History:
* Thu Dec 01 13:50:22 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
PROC WINAPI wglGetProcAddress(LPCSTR lpszProc)
{
PLRC plrc = GLTEB_CLTCURRENTRC();
DBGENTRY("wglGetProcAddress\n");
// Flush OpenGL calls.
GLFLUSH();
// Return error if there is no current RC.
if (!plrc)
{
WARNING("wglGetProcAddress: no current RC\n");
SetLastError(ERROR_INVALID_HANDLE);
return((PROC) NULL);
}
// Handle generic RC.
// Return the generic extension function entry point
if (!plrc->dhrc)
return(pfnGenGlExtProc(lpszProc));
// Handle driver RC.
// There are 3 cases:
// 1. New drivers that support DrvGetProcAddress.
// 2. Old drivers that don't support DrvGetProcAddress but export the function
// 3. If we fail to obtain a function address in 1 and 2, it may still be
// simulated by the generic implemenation for the driver
// (e.g. glDrawArraysEXT). Return the simulated entry point if found.
if (plrc->pGLDriver->pfnDrvGetProcAddress)
{
// Case 1
PROC pfn = plrc->pGLDriver->pfnDrvGetProcAddress(lpszProc);
if (pfn)
return(pfn);
}
#ifdef OBSOLETE
else
{
// Case 2
PROC pfn = GetProcAddress(plrc->pGLDriver->hModule, lpszProc);
if (pfn)
return(pfn);
}
#endif
// Case 3
return (pfnSimGlExtProc(lpszProc));
}
/******************************Public*Routine******************************\
* pfnGenGlExtProc
*
* Return the generic implementation extension function address.
*
* Returns NULL if the function is not found.
*
* History:
* Thu Dec 01 13:50:22 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
typedef struct _GLEXTPROC {
LPCSTR szProc; // extension function name
PROC Proc; // extension function address
} GLEXTPROC, *PGLEXTPROC;
// Extension functions supported by the generic implementation
// See also genglExtProcsSim for simulations.
// NOTE: remember to update GL_EXTENSIONS in glGetString.
GLEXTPROC genglExtProcs[] =
{
{ "glAddSwapHintRectWIN" , (PROC) glAddSwapHintRectWIN },
{ "glColorTableEXT" , (PROC) glColorTableEXT },
{ "glColorSubTableEXT" , (PROC) glColorSubTableEXT },
{ "glGetColorTableEXT" , (PROC) glGetColorTableEXT },
{ "glGetColorTableParameterivEXT", (PROC) glGetColorTableParameterivEXT},
{ "glGetColorTableParameterfvEXT", (PROC) glGetColorTableParameterfvEXT},
{ "glDrawRangeElementsWIN", (PROC) glDrawRangeElementsWIN},
#ifdef GL_EXT_flat_paletted_lighting
{ "glColorTableParameterivEXT", (PROC) glColorTableParameterivEXT},
{ "glColorTableParameterfvEXT", (PROC) glColorTableParameterfvEXT},
#endif // GL_EXT_flat_paletted_lighting
#ifdef GL_WIN_multiple_textures
{ "glCurrentTextureIndexWIN", (PROC) glCurrentTextureIndexWIN },
{ "glMultiTexCoord1dWIN", (PROC) glMultiTexCoord1dWIN },
{ "glMultiTexCoord1dvWIN", (PROC) glMultiTexCoord1dvWIN },
{ "glMultiTexCoord1fWIN", (PROC) glMultiTexCoord1fWIN },
{ "glMultiTexCoord1fvWIN", (PROC) glMultiTexCoord1fvWIN },
{ "glMultiTexCoord1iWIN", (PROC) glMultiTexCoord1iWIN },
{ "glMultiTexCoord1ivWIN", (PROC) glMultiTexCoord1ivWIN },
{ "glMultiTexCoord1sWIN", (PROC) glMultiTexCoord1sWIN },
{ "glMultiTexCoord1svWIN", (PROC) glMultiTexCoord1svWIN },
{ "glMultiTexCoord2dWIN", (PROC) glMultiTexCoord2dWIN },
{ "glMultiTexCoord2dvWIN", (PROC) glMultiTexCoord2dvWIN },
{ "glMultiTexCoord2fWIN", (PROC) glMultiTexCoord2fWIN },
{ "glMultiTexCoord2fvWIN", (PROC) glMultiTexCoord2fvWIN },
{ "glMultiTexCoord2iWIN", (PROC) glMultiTexCoord2iWIN },
{ "glMultiTexCoord2ivWIN", (PROC) glMultiTexCoord2ivWIN },
{ "glMultiTexCoord2sWIN", (PROC) glMultiTexCoord2sWIN },
{ "glMultiTexCoord2svWIN", (PROC) glMultiTexCoord2svWIN },
{ "glMultiTexCoord3dWIN", (PROC) glMultiTexCoord3dWIN },
{ "glMultiTexCoord3dvWIN", (PROC) glMultiTexCoord3dvWIN },
{ "glMultiTexCoord3fWIN", (PROC) glMultiTexCoord3fWIN },
{ "glMultiTexCoord3fvWIN", (PROC) glMultiTexCoord3fvWIN },
{ "glMultiTexCoord3iWIN", (PROC) glMultiTexCoord3iWIN },
{ "glMultiTexCoord3ivWIN", (PROC) glMultiTexCoord3ivWIN },
{ "glMultiTexCoord3sWIN", (PROC) glMultiTexCoord3sWIN },
{ "glMultiTexCoord3svWIN", (PROC) glMultiTexCoord3svWIN },
{ "glMultiTexCoord4dWIN", (PROC) glMultiTexCoord4dWIN },
{ "glMultiTexCoord4dvWIN", (PROC) glMultiTexCoord4dvWIN },
{ "glMultiTexCoord4fWIN", (PROC) glMultiTexCoord4fWIN },
{ "glMultiTexCoord4fvWIN", (PROC) glMultiTexCoord4fvWIN },
{ "glMultiTexCoord4iWIN", (PROC) glMultiTexCoord4iWIN },
{ "glMultiTexCoord4ivWIN", (PROC) glMultiTexCoord4ivWIN },
{ "glMultiTexCoord4sWIN", (PROC) glMultiTexCoord4sWIN },
{ "glMultiTexCoord4svWIN", (PROC) glMultiTexCoord4svWIN },
{ "glBindNthTextureWIN", (PROC) glBindNthTextureWIN },
{ "glNthTexCombineFuncWIN", (PROC) glNthTexCombineFuncWIN },
#endif // GL_WIN_multiple_textures
};
static PROC pfnGenGlExtProc(LPCSTR lpszProc)
{
CONST CHAR *pch1, *pch2;
int i;
DBGENTRY("pfnGenGlExtProc\n");
// Return extension function address if it is found.
for (i = 0; i < sizeof(genglExtProcs) / sizeof(genglExtProcs[0]); i++)
{
// Compare names.
for (pch1 = lpszProc, pch2 = genglExtProcs[i].szProc;
*pch1 == *pch2 && *pch1;
pch1++, pch2++)
;
// If found, return the address.
if (*pch1 == *pch2 && !*pch1)
return genglExtProcs[i].Proc;
}
// Extension is not supported by the generic implementation, return NULL.
SetLastError(ERROR_PROC_NOT_FOUND);
return((PROC) NULL);
}
/******************************Public*Routine******************************\
* pfnSimGlExtProc
*
* Return the extension function address that is the generic implemenation's
* simulation for the client drivers. The simulation is used only if the
* driver does not support an extension that is desirable to apps.
*
* Returns NULL if the function is not found.
*
* History:
* Thu Dec 01 13:50:22 1994 -by- Hock San Lee [hockl]
* Wrote it.
\**************************************************************************/
// Extension functions simulated by the generic implementation for the client
// drivers
// NOTE: remember to update GL_EXTENSIONS in glGetString.
static PROC pfnSimGlExtProc(LPCSTR lpszProc)
{
// Extension is not supported by the generic implementation, return NULL.
SetLastError(ERROR_PROC_NOT_FOUND);
return((PROC) NULL);
}
/******************************Public*Routine******************************\
*
* wglCopyContext
*
* Copies all of one context's state to another one
*
* Returns:
* TRUE if successful, FALSE otherwise
*
* History:
* Fri May 26 14:57:17 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL WINAPI
wglCopyContext(HGLRC hrcSource, HGLRC hrcDest, UINT fuMask)
{
BOOL fRet;
PLRC plrcSource, plrcDest;
ULONG irc;
PLHE plheRC;
HANDLE hrcSrvSource, hrcSrvDest;
GLFLUSH();
fRet = FALSE;
// Validate the contexts
if (cLockHandle((ULONG_PTR)hrcSource) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglCopyContext: can't lock hrcSource 0x%lx\n",
hrcSource);
goto wglCopyContextEnd_nolock;
}
irc = MASKINDEX(hrcSource);
plheRC = pLocalTable + irc;
plrcSource = (PLRC)plheRC->pv;
hrcSrvSource = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcSource->ident == LRC_IDENTIFIER,
"wglCopyContext: Bad plrc\n");
if (cLockHandle((ULONG_PTR)hrcDest) <= 0)
{
DBGLEVEL1(LEVEL_ERROR, "wglCopyContext: can't lock hrcDest 0x%lx\n",
hrcDest);
goto wglCopyContextEnd_onelock;
}
irc = MASKINDEX(hrcDest);
plheRC = pLocalTable + irc;
plrcDest = (PLRC)plheRC->pv;
hrcSrvDest = (HANDLE) plheRC->hgre;
ASSERTOPENGL(plrcDest->ident == LRC_IDENTIFIER,
"wglCopyContext: Bad plrc\n");
// Context can only be copied between like implementations so make
// sure that both contexts are either driver contexts or generic
// contexts
if ((plrcSource->dhrc != 0) != (plrcDest->dhrc != 0))
{
DBGLEVEL(LEVEL_ERROR, "wglCopyContext: mismatched implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglCopyContextEnd;
}
// The destination context cannot be current to a thread
if (plrcDest->tidCurrent != INVALID_THREAD_ID)
{
DBGLEVEL(LEVEL_ERROR, "wglCopyContext: destination has tidCurrent\n");
SetLastError(ERROR_INVALID_HANDLE);
goto wglCopyContextEnd;
}
if (plrcSource->dhrc == 0)
{
// For generic contexts, tell the server to share the lists
fRet = __wglCopyContext(hrcSrvSource, hrcSrvDest, fuMask);
if (!fRet)
{
DBGERROR("wglCopyContext: server call failed\n");
}
}
else
{
// For device contexts tell the driver to copy the context
// Ensure that both implementations are the same
if (plrcSource->pGLDriver != plrcDest->pGLDriver)
{
DBGLEVEL(LEVEL_ERROR, "wglCopyContext: mismatched "
"implementations\n");
SetLastError(ERROR_INVALID_FUNCTION);
goto wglCopyContextEnd;
}
ASSERTOPENGL(plrcSource->pGLDriver != NULL,
"wglCopyContext: No GLDriver\n");
// Older drivers may not support this entry point, so
// fail the call if they don't
if (plrcSource->pGLDriver->pfnDrvCopyContext == NULL)
{
WARNING("wglCopyContext called on driver context "
"without driver support\n");
SetLastError(ERROR_NOT_SUPPORTED);
}
else
{
fRet = plrcSource->pGLDriver->pfnDrvCopyContext(plrcSource->dhrc,
plrcDest->dhrc,
fuMask);
}
}
wglCopyContextEnd:
vUnlockHandle((ULONG_PTR)hrcDest);
wglCopyContextEnd_onelock:
vUnlockHandle((ULONG_PTR)hrcSource);
wglCopyContextEnd_nolock:
return fRet;
}