/******************************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 #include #include #include #include #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; }