/* $Id: fxwgl.c,v 1.17 2003/08/19 15:52:53 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 4.0 * * Copyright (C) 1999-2001 Brian Paul 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 * BRIAN PAUL 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. */ /* Authors: * David Bucciarelli * Brian Paul * Keith Whitwell */ /* fxwgl.c - Microsoft wgl functions emulation for * 3Dfx VooDoo/Mesa interface */ #ifdef __WIN32__ #ifdef __cplusplus extern "C" { #endif #include #define GL_GLEXT_PROTOTYPES #include "GL/gl.h" #include "GL/glext.h" #ifdef __cplusplus } #endif #include #include "GL/fxmesa.h" #include "glheader.h" #include "fxdrv.h" #include "glapi.h" #define MAX_MESA_ATTRS 20 struct __extensions__ { PROC proc; char *name; }; struct __pixelformat__ { PIXELFORMATDESCRIPTOR pfd; GLint mesaAttr[MAX_MESA_ATTRS]; }; WINGDIAPI void GLAPIENTRY gl3DfxSetPaletteEXT(GLuint *); struct __pixelformat__ pix[] = { #if 0 /* None */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_COLORDEPTH, 16, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 0, FXMESA_DEPTH_SIZE, 0, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* Alpha */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 1, 15, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_COLORDEPTH, 15, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 1, FXMESA_DEPTH_SIZE, 0, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* Depth */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_COLORDEPTH, 16, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 0, FXMESA_DEPTH_SIZE, 16, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* None */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_COLORDEPTH, 32, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 0, FXMESA_DEPTH_SIZE, 0, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* Alpha */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_COLORDEPTH, 32, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 8, FXMESA_DEPTH_SIZE, 0, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* Depth */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_COLORDEPTH, 32, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 0, FXMESA_DEPTH_SIZE, 16, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } #endif /* 16bit RGB565 */ { {sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 16, 5, 11, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , {FXMESA_COLORDEPTH, 16, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 0, FXMESA_DEPTH_SIZE, 16, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* 16bit ARGB1555 */ { {sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 16, 5, 10, 5, 5, 5, 0, 1, 15, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , {FXMESA_COLORDEPTH, 15, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 1, FXMESA_DEPTH_SIZE, 16, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } , /* 32bit ARGB8888 */ { {sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 32, 8, 16, 8, 8, 8, 0, 8, 24, 0, 0, 0, 0, 0, 24, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , {FXMESA_COLORDEPTH, 32, FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 8, FXMESA_DEPTH_SIZE, 24, FXMESA_STENCIL_SIZE, 0, FXMESA_ACCUM_SIZE, 0, FXMESA_NONE} } }; static int qt_pix = sizeof(pix) / sizeof(pix[0]); static fxMesaContext ctx = NULL; static WNDPROC hWNDOldProc; static int curPFD = 0; static HDC hDC; static HWND hWND; static GLboolean haveDualHead; /* For the in-window-rendering hack */ #ifndef GR_CONTROL_RESIZE /* Apparently GR_CONTROL_RESIZE can be ignored. OK? */ #define GR_CONTROL_RESIZE -1 #endif static GLboolean gdiWindowHack; static void *dibSurfacePtr; static BITMAPINFO *dibBMI; static HBITMAP dibHBM; static HWND dibWnd; LONG GLAPIENTRY __wglMonitor(HWND hwnd, UINT message, UINT wParam, LONG lParam) { long ret; /* Now gives the resized window at the end to hWNDOldProc */ if (ctx && hwnd == hWND) { switch (message) { case WM_PAINT: case WM_MOVE: break; case WM_DISPLAYCHANGE: case WM_SIZE: if (wParam != SIZE_MINIMIZED) { static int moving = 0; if (!moving) { if (!FX_grSstControl(GR_CONTROL_RESIZE)) { moving = 1; SetWindowPos(hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE | SWP_NOZORDER); moving = 0; if (!FX_grSstControl(GR_CONTROL_RESIZE)) { /*MessageBox(0,_T("Error changing windowsize"),_T("fxMESA"),MB_OK); */ PostMessage(hWND, WM_CLOSE, 0, 0); } } /* Do the clipping in the glide library */ grClipWindow(0, 0, FX_grSstScreenWidth(), FX_grSstScreenHeight()); /* And let the new size set in the context */ fxMesaUpdateScreenSize(ctx); } } break; case WM_ACTIVATE: break; case WM_SHOWWINDOW: break; case WM_SYSKEYDOWN: case WM_SYSCHAR: break; } } /* Finaly call the hWNDOldProc, which handles the resize witch the now changed window sizes */ ret = CallWindowProc(hWNDOldProc, hwnd, message, wParam, lParam); return (ret); } BOOL GLAPIENTRY wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask) { return (FALSE); } HGLRC GLAPIENTRY wglCreateContext(HDC hdc) { HWND hWnd; WNDPROC oldProc; int error; if (ctx) { SetLastError(0); return (NULL); } if (!(hWnd = WindowFromDC(hdc))) { SetLastError(0); return (NULL); } if (curPFD == 0) { SetLastError(0); return (NULL); } if ((oldProc = (WNDPROC) GetWindowLong(hWnd, GWL_WNDPROC)) != __wglMonitor) { hWNDOldProc = oldProc; SetWindowLong(hWnd, GWL_WNDPROC, (LONG) __wglMonitor); } #ifndef FX_SILENT freopen("MESA.LOG", "w", stderr); #endif { RECT cliRect; ShowWindow(hWnd, SW_SHOWNORMAL); SetForegroundWindow(hWnd); Sleep(100); /* a hack for win95 */ GetClientRect(hWnd, &cliRect); error = !(ctx = fxMesaCreateBestContext((GLuint) hWnd, cliRect.right, cliRect.bottom, pix[curPFD - 1].mesaAttr)); } if (getenv("SST_DUALHEAD")) haveDualHead = ((atoi(getenv("SST_DUALHEAD")) == 1) ? GL_TRUE : GL_FALSE); else haveDualHead = GL_FALSE; if (error) { SetLastError(0); return (NULL); } hDC = hdc; hWND = hWnd; /* Required by the OpenGL Optimizer 1.1 (is it a Optimizer bug ?) */ wglMakeCurrent(hdc, (HGLRC) 1); return ((HGLRC) 1); } HGLRC GLAPIENTRY wglCreateLayerContext(HDC hdc, int iLayerPlane) { SetLastError(0); return (NULL); } BOOL GLAPIENTRY wglDeleteContext(HGLRC hglrc) { if (ctx && hglrc == (HGLRC) 1) { fxMesaDestroyContext(ctx); SetWindowLong(WindowFromDC(hDC), GWL_WNDPROC, (LONG) hWNDOldProc); ctx = NULL; hDC = 0; return (TRUE); } SetLastError(0); return (FALSE); } HGLRC GLAPIENTRY wglGetCurrentContext(VOID) { if (ctx) return ((HGLRC) 1); SetLastError(0); return (NULL); } HDC GLAPIENTRY wglGetCurrentDC(VOID) { if (ctx) return (hDC); SetLastError(0); return (NULL); } PROC GLAPIENTRY wglGetProcAddress(LPCSTR lpszProc) { PROC p = (PROC) _glapi_get_proc_address((const char *) lpszProc); if (p) return p; SetLastError(0); return (NULL); } BOOL GLAPIENTRY wglMakeCurrent(HDC hdc, HGLRC hglrc) { if ((hdc == NULL) && (hglrc == NULL)) return (TRUE); if (!ctx || hglrc != (HGLRC) 1 || WindowFromDC(hdc) != hWND) { SetLastError(0); return (FALSE); } hDC = hdc; fxMesaMakeCurrent(ctx); return (TRUE); } BOOL GLAPIENTRY wglShareLists(HGLRC hglrc1, HGLRC hglrc2) { if (!ctx || hglrc1 != (HGLRC) 1 || hglrc1 != hglrc2) { SetLastError(0); return (FALSE); } return (TRUE); } BOOL GLAPIENTRY wglUseFontBitmaps(HDC fontDevice, DWORD firstChar, DWORD numChars, DWORD listBase) { #define VERIFY(a) a TEXTMETRIC metric; BITMAPINFO *dibInfo; HDC bitDevice; COLORREF tempColor; int i; VERIFY(GetTextMetrics(fontDevice, &metric)); dibInfo = (BITMAPINFO *) calloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD), 1); dibInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); dibInfo->bmiHeader.biPlanes = 1; dibInfo->bmiHeader.biBitCount = 1; dibInfo->bmiHeader.biCompression = BI_RGB; bitDevice = CreateCompatibleDC(fontDevice); // HDC bitDevice = CreateDC("DISPLAY", NULL, NULL, NULL); // VERIFY(bitDevice); // Swap fore and back colors so the bitmap has the right polarity tempColor = GetBkColor(bitDevice); SetBkColor(bitDevice, GetTextColor(bitDevice)); SetTextColor(bitDevice, tempColor); // Place chars based on base line VERIFY(SetTextAlign(bitDevice, TA_BASELINE) >= 0 ? 1 : 0); for (i = 0; i < (int)numChars; i++) { SIZE size; char curChar; int charWidth, charHeight, bmapWidth, bmapHeight, numBytes, res; HBITMAP bitObject; HGDIOBJ origBmap; unsigned char *bmap; curChar = (char)(i + firstChar); // [koolsmoky] explicit cast // Find how high/wide this character is VERIFY(GetTextExtentPoint32(bitDevice, &curChar, 1, &size)); // Create the output bitmap charWidth = size.cx; charHeight = size.cy; bmapWidth = ((charWidth + 31) / 32) * 32; // Round up to the next multiple of 32 bits bmapHeight = charHeight; bitObject = CreateCompatibleBitmap(bitDevice, bmapWidth, bmapHeight); //VERIFY(bitObject); // Assign the output bitmap to the device origBmap = SelectObject(bitDevice, bitObject); VERIFY(origBmap); VERIFY(PatBlt(bitDevice, 0, 0, bmapWidth, bmapHeight, BLACKNESS)); // Use our source font on the device VERIFY(SelectObject(bitDevice, GetCurrentObject(fontDevice, OBJ_FONT))); // Draw the character VERIFY(TextOut(bitDevice, 0, metric.tmAscent, &curChar, 1)); // Unselect our bmap object VERIFY(SelectObject(bitDevice, origBmap)); // Convert the display dependant representation to a 1 bit deep DIB numBytes = (bmapWidth * bmapHeight) / 8; bmap = MALLOC(numBytes); dibInfo->bmiHeader.biWidth = bmapWidth; dibInfo->bmiHeader.biHeight = bmapHeight; res = GetDIBits(bitDevice, bitObject, 0, bmapHeight, bmap, dibInfo, DIB_RGB_COLORS); //VERIFY(res); // Create the GL object glNewList(i + listBase, GL_COMPILE); glBitmap(bmapWidth, bmapHeight, 0.0, metric.tmDescent, charWidth, 0.0, bmap); glEndList(); // CheckGL(); // Destroy the bmap object DeleteObject(bitObject); // Deallocate the bitmap data FREE(bmap); } // Destroy the DC VERIFY(DeleteDC(bitDevice)); FREE(dibInfo); return TRUE; #undef VERIFY } BOOL GLAPIENTRY wglUseFontBitmapsW(HDC hdc, DWORD first, DWORD count, DWORD listBase) { return (FALSE); } BOOL GLAPIENTRY wglUseFontOutlinesA(HDC hdc, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf) { SetLastError(0); return (FALSE); } BOOL GLAPIENTRY wglUseFontOutlinesW(HDC hdc, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format, LPGLYPHMETRICSFLOAT lpgmf) { SetLastError(0); return (FALSE); } BOOL GLAPIENTRY wglSwapLayerBuffers(HDC hdc, UINT fuPlanes) { if (ctx && WindowFromDC(hdc) == hWND) { fxMesaSwapBuffers(); return (TRUE); } SetLastError(0); return (FALSE); } int GLAPIENTRY wglChoosePixelFormat(HDC hdc, CONST PIXELFORMATDESCRIPTOR * ppfd) { int i, best = -1, qt_valid_pix; qt_valid_pix = qt_pix; if (ppfd->nSize != sizeof(PIXELFORMATDESCRIPTOR) || ppfd->nVersion != 1) { SetLastError(0); return (0); } for (i = 0; i < qt_valid_pix; i++) { if (ppfd->cColorBits > 0 && pix[i].pfd.cColorBits != ppfd->cColorBits) continue; if ((ppfd->dwFlags & PFD_DRAW_TO_WINDOW) && !(pix[i].pfd.dwFlags & PFD_DRAW_TO_WINDOW)) continue; if ((ppfd->dwFlags & PFD_DRAW_TO_BITMAP) && !(pix[i].pfd.dwFlags & PFD_DRAW_TO_BITMAP)) continue; if ((ppfd->dwFlags & PFD_SUPPORT_GDI) && !(pix[i].pfd.dwFlags & PFD_SUPPORT_GDI)) continue; if ((ppfd->dwFlags & PFD_SUPPORT_OPENGL) && !(pix[i].pfd.dwFlags & PFD_SUPPORT_OPENGL)) continue; if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE) && ((ppfd->dwFlags & PFD_DOUBLEBUFFER) != (pix[i].pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE) && ((ppfd->dwFlags & PFD_STEREO) != (pix[i].pfd.dwFlags & PFD_STEREO))) continue; if (ppfd->cDepthBits > 0 && pix[i].pfd.cDepthBits == 0) continue; /* need depth buffer */ if (ppfd->cAlphaBits > 0 && pix[i].pfd.cAlphaBits == 0) continue; /* need alpha buffer */ if (ppfd->iPixelType == pix[i].pfd.iPixelType) { best = i + 1; break; } } if (best == -1) { SetLastError(0); return (0); } return (best); } int GLAPIENTRY ChoosePixelFormat(HDC hdc, CONST PIXELFORMATDESCRIPTOR * ppfd) { return wglChoosePixelFormat(hdc, ppfd); } int GLAPIENTRY wglDescribePixelFormat(HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) { int qt_valid_pix; qt_valid_pix = qt_pix; if (iPixelFormat < 1 || iPixelFormat > qt_valid_pix || ((nBytes != sizeof(PIXELFORMATDESCRIPTOR)) && (nBytes != 0))) { SetLastError(0); return (0); } if (nBytes != 0) *ppfd = pix[iPixelFormat - 1].pfd; return (qt_valid_pix); } int GLAPIENTRY DescribePixelFormat(HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd) { return wglDescribePixelFormat(hdc, iPixelFormat, nBytes, ppfd); } int GLAPIENTRY wglGetPixelFormat(HDC hdc) { if (curPFD == 0) { SetLastError(0); return (0); } return (curPFD); } int GLAPIENTRY GetPixelFormat(HDC hdc) { return wglGetPixelFormat(hdc); } BOOL GLAPIENTRY wglSetPixelFormat(HDC hdc, int iPixelFormat, CONST PIXELFORMATDESCRIPTOR * ppfd) { int qt_valid_pix; qt_valid_pix = qt_pix; if (iPixelFormat < 1 || iPixelFormat > qt_valid_pix || ppfd->nSize != sizeof(PIXELFORMATDESCRIPTOR)) { SetLastError(0); return (FALSE); } curPFD = iPixelFormat; return (TRUE); } BOOL GLAPIENTRY wglSwapBuffers(HDC hdc) { if (!ctx) { SetLastError(0); return (FALSE); } fxMesaSwapBuffers(); return (TRUE); } BOOL GLAPIENTRY SetPixelFormat(HDC hdc, int iPixelFormat, CONST PIXELFORMATDESCRIPTOR * ppfd) { return wglSetPixelFormat(hdc, iPixelFormat, ppfd); } BOOL GLAPIENTRY SwapBuffers(HDC hdc) { return wglSwapBuffers(hdc); } #endif /* FX */