/* $Id: fxwgl.c,v 1.16 2002/10/24 23:57:23 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 #include "glheader.h" #include "fxdrv.h" #include "glapi.h" #ifdef __cplusplus } #endif #include #include "GL/fxmesa.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[] = { /* None */ { { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_COPY, PFD_TYPE_RGBA, 32, 8, 0, 8, 8, 8, 16, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { 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, 0, 8, 8, 8, 16, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { 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, 0, 8, 8, 8, 16, 0, 24, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0} , { FXMESA_DOUBLEBUFFER, FXMESA_ALPHA_SIZE, 0, FXMESA_DEPTH_SIZE, 16, 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 */ static GLboolean gdiWindowHack; static GLboolean gdiWindowHackEna; 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 (fxQueryHardware() != GR_SSTTYPE_VOODOO) { 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 */ FX_grClipWindow(0, 0, FX_grSstScreenWidth(), FX_grSstScreenHeight()); /* And let the new size set in the context */ fxMesaUpdateScreenSize(ctx); } } break; case WM_ACTIVATE: if ((fxQueryHardware() == GR_SSTTYPE_VOODOO) && (!gdiWindowHack) && (!haveDualHead)) { WORD fActive = LOWORD(wParam); BOOL fMinimized = (BOOL) HIWORD(wParam); if ((fActive == WA_INACTIVE) || fMinimized) FX_grSstControl(GR_CONTROL_DEACTIVATE); else FX_grSstControl(GR_CONTROL_ACTIVATE); } break; case WM_SHOWWINDOW: break; case WM_SYSKEYDOWN: case WM_SYSCHAR: if (gdiWindowHackEna && (VK_RETURN == wParam)) { if (gdiWindowHack) { gdiWindowHack = GL_FALSE; FX_grSstControl(GR_CONTROL_ACTIVATE); } else { gdiWindowHack = GL_TRUE; FX_grSstControl(GR_CONTROL_DEACTIVATE); } } 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 ShowWindow(hWnd, SW_SHOWNORMAL); SetForegroundWindow(hWnd); Sleep(100); /* an hack for win95 */ if (fxQueryHardware() == GR_SSTTYPE_VOODOO) { RECT cliRect; GetClientRect(hWnd, &cliRect); error = !(ctx = fxMesaCreateBestContext((GLuint) hWnd, cliRect.right, cliRect.bottom, pix[curPFD - 1].mesaAttr)); if (!error) { /* create the DIB section for windowed rendering */ DWORD *p; dibWnd = hWnd; hDC = GetDC(dibWnd); dibBMI = (BITMAPINFO *) MALLOC(sizeof(BITMAPINFO) + (256 * sizeof(RGBQUAD))); memset(dibBMI, 0, sizeof(BITMAPINFO) + (256 * sizeof(RGBQUAD))); dibBMI->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); dibBMI->bmiHeader.biWidth = ctx->width; dibBMI->bmiHeader.biHeight = -ctx->height; dibBMI->bmiHeader.biPlanes = (short) 1; dibBMI->bmiHeader.biBitCount = (short) 16; dibBMI->bmiHeader.biCompression = BI_BITFIELDS; dibBMI->bmiHeader.biSizeImage = 0; dibBMI->bmiHeader.biXPelsPerMeter = 0; dibBMI->bmiHeader.biYPelsPerMeter = 0; dibBMI->bmiHeader.biClrUsed = 3; dibBMI->bmiHeader.biClrImportant = 3; p = (DWORD *) dibBMI->bmiColors; p[0] = 0xF800; p[1] = 0x07E0; p[2] = 0x001F; dibHBM = CreateDIBSection(hDC, dibBMI, DIB_RGB_COLORS, &dibSurfacePtr, NULL, 0); ReleaseDC(dibWnd, hDC); gdiWindowHackEna = (dibHBM != NULL ? GL_TRUE : GL_FALSE); if (!getenv("MESA_WGL_FX") || !strcmp(getenv("MESA_WGL_FX"), "fullscreen")) gdiWindowHack = GL_FALSE; else { gdiWindowHack = GL_TRUE; FX_grSstControl(GR_CONTROL_DEACTIVATE); } } } else { /* For the Voodoo Rush */ if (getenv("MESA_WGL_FX") && !strcmp(getenv("MESA_WGL_FX"), "fullscreen")) { RECT cliRect; GetClientRect(hWnd, &cliRect); error = !(ctx = fxMesaCreateBestContext((GLuint) hWnd, cliRect.right, cliRect.bottom, pix[curPFD - 1].mesaAttr)); } else error = !(ctx = fxMesaCreateContext((GLuint) hWnd, GR_RESOLUTION_NONE, GR_REFRESH_75Hz, 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) { if (gdiWindowHackEna) { DeleteObject(dibHBM); FREE(dibBMI); dibSurfacePtr = NULL; dibBMI = NULL; dibHBM = NULL; dibWnd = NULL; } 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 < numChars; i++) { SIZE size; char curChar; int charWidth, charHeight, bmapWidth, bmapHeight, numBytes, res; HBITMAP bitObject; HGDIOBJ origBmap; unsigned char *bmap; curChar = i + firstChar; // 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->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(); if (gdiWindowHack) { GLuint width = ctx->width; GLuint height = ctx->height; HDC hdcScreen = GetDC(dibWnd); HDC hdcDIBSection = CreateCompatibleDC(hdcScreen); HBITMAP holdBitmap = (HBITMAP) SelectObject(hdcDIBSection, dibHBM); FX_grLfbReadRegion(GR_BUFFER_FRONTBUFFER, 0, 0, width, height, width * 2, dibSurfacePtr); /* Since the hardware is configured for GR_COLORFORMAT_ABGR the pixel data is * going to come out as BGR 565, which is reverse of what we need for blitting * to screen, so we need to convert it here pixel-by-pixel (ick). This loop would NOT * be required if the color format was changed to GR_COLORFORMAT_ARGB, but I do * not know the ramifications of that, so this will work until that is resolved. * * This routine CRIES out for MMX implementation, however since that's not * guaranteed to be running on MMX enabled hardware so I'm not going to do * that. I'm just going to try to make a reasonably efficient C * version. -TAJ * * This routine drops frame rate by <1 fps on a 200Mhz MMX processor with a 640x480 * display. Obviously, it's performance hit will be higher on larger displays and * less on smaller displays. To support the window-hack display this is probably fine. */ #if FXMESA_USE_ARGB { unsigned long *pixel = dibSurfacePtr; unsigned long count = (width * height) / 2; while (count--) { *pixel++ = (*pixel & 0x07e007e0) /* greens */ |((*pixel & 0xf800f800) >> 11) /* swap blues */ |((*pixel & 0x001f001f) << 11) /* swap reds */ ; } } #endif BitBlt(hdcScreen, 0, 0, width, height, hdcDIBSection, 0, 0, SRCCOPY); ReleaseDC(dibWnd, hdcScreen); SelectObject(hdcDIBSection, holdBitmap); DeleteDC(hdcDIBSection); } 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 */