1 /* fxwgl.c - Microsoft wgl functions emulation for
2 * 3Dfx VooDoo/Mesa interface
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * See the file fxapi.c for more informations about authors
39 #include <GL/fxmesa.h>
42 #define MAX_MESA_ATTRS 20
50 struct __pixelformat__
52 PIXELFORMATDESCRIPTOR pfd
;
53 GLint mesaAttr
[MAX_MESA_ATTRS
];
56 WINGDIAPI
void GLAPIENTRY
gl3DfxSetPaletteEXT(GLuint
*);
58 static struct __extensions__ ext
[] = {
60 #ifdef GL_EXT_polygon_offset
61 { (PROC
)glPolygonOffsetEXT
, "glPolygonOffsetEXT" },
63 { (PROC
)glBlendEquationEXT
, "glBlendEquationEXT" },
64 { (PROC
)glBlendColorEXT
, "glBlendColorExt" },
65 { (PROC
)glVertexPointerEXT
, "glVertexPointerEXT" },
66 { (PROC
)glNormalPointerEXT
, "glNormalPointerEXT" },
67 { (PROC
)glColorPointerEXT
, "glColorPointerEXT" },
68 { (PROC
)glIndexPointerEXT
, "glIndexPointerEXT" },
69 { (PROC
)glTexCoordPointerEXT
, "glTexCoordPointer" },
70 { (PROC
)glEdgeFlagPointerEXT
, "glEdgeFlagPointerEXT" },
71 { (PROC
)glGetPointervEXT
, "glGetPointervEXT" },
72 { (PROC
)glArrayElementEXT
, "glArrayElementEXT" },
73 { (PROC
)glDrawArraysEXT
, "glDrawArrayEXT" },
74 { (PROC
)glAreTexturesResidentEXT
, "glAreTexturesResidentEXT" },
75 { (PROC
)glBindTextureEXT
, "glBindTextureEXT" },
76 { (PROC
)glDeleteTexturesEXT
, "glDeleteTexturesEXT" },
77 { (PROC
)glGenTexturesEXT
, "glGenTexturesEXT" },
78 { (PROC
)glIsTextureEXT
, "glIsTextureEXT" },
79 { (PROC
)glPrioritizeTexturesEXT
, "glPrioritizeTexturesEXT" },
80 { (PROC
)glCopyTexSubImage3DEXT
, "glCopyTexSubImage3DEXT" },
81 { (PROC
)glTexImage3DEXT
, "glTexImage3DEXT" },
82 { (PROC
)glTexSubImage3DEXT
, "glTexSubImage3DEXT" },
83 { (PROC
)gl3DfxSetPaletteEXT
, "3DFX_set_global_palette" },
84 { (PROC
)glColorTableEXT
, "glColorTableEXT" },
85 { (PROC
)glColorSubTableEXT
, "glColorSubTableEXT" },
86 { (PROC
)glGetColorTableEXT
, "glGetColorTableEXT" },
87 { (PROC
)glGetColorTableParameterfvEXT
, "glGetColorTableParameterfvEXT" },
88 { (PROC
)glGetColorTableParameterivEXT
, "glGetColorTableParameterivEXT" },
89 { (PROC
)glPointParameterfEXT
, "glPointParameterfEXT" },
90 { (PROC
)glPointParameterfvEXT
, "glPointParameterfvEXT" },
91 { (PROC
)glBlendFuncSeparateINGR
, "glBlendFuncSeparateINGR" },
92 { (PROC
)glLockArraysEXT
, "glLockArraysEXT" },
93 { (PROC
)glUnlockArraysEXT
, "glUnlockArraysEXT" }
96 static int qt_ext
= sizeof(ext
) / sizeof(ext
[0]);
98 struct __pixelformat__ pix
[] =
103 sizeof(PIXELFORMATDESCRIPTOR
), 1,
104 PFD_DRAW_TO_WINDOW
|PFD_SUPPORT_OPENGL
|
105 PFD_DOUBLEBUFFER
|PFD_SWAP_COPY
,
118 FXMESA_ALPHA_SIZE
, 0,
119 FXMESA_DEPTH_SIZE
, 0,
120 FXMESA_STENCIL_SIZE
, 0,
121 FXMESA_ACCUM_SIZE
, 0,
129 sizeof(PIXELFORMATDESCRIPTOR
), 1,
130 PFD_DRAW_TO_WINDOW
|PFD_SUPPORT_OPENGL
|
131 PFD_DOUBLEBUFFER
|PFD_SWAP_COPY
,
144 FXMESA_ALPHA_SIZE
, 8,
145 FXMESA_DEPTH_SIZE
, 0,
146 FXMESA_STENCIL_SIZE
, 0,
147 FXMESA_ACCUM_SIZE
, 0,
155 sizeof(PIXELFORMATDESCRIPTOR
), 1,
156 PFD_DRAW_TO_WINDOW
|PFD_SUPPORT_OPENGL
|
157 PFD_DOUBLEBUFFER
|PFD_SWAP_COPY
,
170 FXMESA_ALPHA_SIZE
, 0,
171 FXMESA_DEPTH_SIZE
, 16,
172 FXMESA_STENCIL_SIZE
, 0,
173 FXMESA_ACCUM_SIZE
, 0,
178 static int qt_pix
= sizeof(pix
) / sizeof(pix
[0]);
180 static fxMesaContext ctx
= NULL
;
181 static WNDPROC hWNDOldProc
;
182 static int curPFD
= 0;
186 static GLboolean haveDualHead
;
188 /* For the in-window-rendering hack */
190 static GLboolean gdiWindowHack
;
191 static GLboolean gdiWindowHackEna
;
192 static void *dibSurfacePtr
;
193 static BITMAPINFO
*dibBMI
;
194 static HBITMAP dibHBM
;
197 LONG GLAPIENTRY
__wglMonitor(HWND hwnd
,UINT message
,UINT wParam
,LONG lParam
)
200 long ret
; /* Now gives the resized window at the end to hWNDOldProc */
202 if(ctx
&& hwnd
== hWND
) {
207 case WM_DISPLAYCHANGE
:
209 if (wParam
!= SIZE_MINIMIZED
) {
210 static int moving
= 0;
212 if(fxQueryHardware()!=GR_SSTTYPE_VOODOO
) {
213 if(!grSstControl(GR_CONTROL_RESIZE
)) {
215 SetWindowPos(hwnd
, 0, 0, 0, 300, 300, SWP_NOMOVE
|SWP_NOZORDER
);
217 if(!grSstControl(GR_CONTROL_RESIZE
)) {
218 /*MessageBox(0,_T("Error changing windowsize"),_T("fxMESA"),MB_OK);*/
219 PostMessage(hWND
,WM_CLOSE
,0,0);
224 /* Do the clipping in the glide library */
225 grClipWindow(0,0,grSstScreenWidth(),grSstScreenHeight());
226 /* And let the new size set in the context */
227 fxMesaUpdateScreenSize(ctx
);
232 if((fxQueryHardware()==GR_SSTTYPE_VOODOO
) &&
235 WORD fActive
= LOWORD(wParam
);
236 BOOL fMinimized
= (BOOL
) HIWORD(wParam
);
238 if((fActive
== WA_INACTIVE
) || fMinimized
)
239 grSstControl(GR_CONTROL_DEACTIVATE
);
241 grSstControl(GR_CONTROL_ACTIVATE
);
247 if(gdiWindowHackEna
&& (VK_RETURN
== wParam
)) {
249 gdiWindowHack
= GL_FALSE
;
250 grSstControl(GR_CONTROL_ACTIVATE
);
252 gdiWindowHack
= GL_TRUE
;
253 grSstControl(GR_CONTROL_DEACTIVATE
);
260 /* Finaly call the hWNDOldProc, which handles the resize witch the
261 now changed window sizes */
262 ret
= CallWindowProc( hWNDOldProc
, hwnd
, message
, wParam
, lParam
);
267 BOOL GLAPIENTRY
wglCopyContext(HGLRC hglrcSrc
,HGLRC hglrcDst
,UINT mask
)
272 HGLRC GLAPIENTRY
wglCreateContext(HDC hdc
)
283 if(!(hWnd
= WindowFromDC(hdc
))) {
293 if((oldProc
= (WNDPROC
)GetWindowLong(hWnd
,GWL_WNDPROC
)) != __wglMonitor
) {
294 hWNDOldProc
= oldProc
;
295 SetWindowLong(hWnd
,GWL_WNDPROC
,(LONG
)__wglMonitor
);
299 freopen("MESA.LOG","w",stderr
);
302 ShowWindow(hWnd
, SW_SHOWNORMAL
);
303 SetForegroundWindow(hWnd
);
304 Sleep(100); /* an hack for win95 */
306 if(fxQueryHardware() == GR_SSTTYPE_VOODOO
) {
309 GetClientRect(hWnd
,&cliRect
);
310 error
= !(ctx
= fxMesaCreateBestContext((GLuint
)hWnd
,cliRect
.right
,cliRect
.bottom
,
311 pix
[curPFD
- 1].mesaAttr
));
314 /* create the DIB section for windowed rendering */
321 dibBMI
= (BITMAPINFO
*) malloc( sizeof(BITMAPINFO
) + (256*sizeof(RGBQUAD
)));
323 memset(dibBMI
,0,sizeof(BITMAPINFO
) + (256*sizeof(RGBQUAD
)));
325 dibBMI
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
326 dibBMI
->bmiHeader
.biWidth
= ctx
->width
;
327 dibBMI
->bmiHeader
.biHeight
= -ctx
->height
;
328 dibBMI
->bmiHeader
.biPlanes
= (short)1;
329 dibBMI
->bmiHeader
.biBitCount
= (short)16;
330 dibBMI
->bmiHeader
.biCompression
= BI_BITFIELDS
;
331 dibBMI
->bmiHeader
.biSizeImage
= 0;
332 dibBMI
->bmiHeader
.biXPelsPerMeter
= 0;
333 dibBMI
->bmiHeader
.biYPelsPerMeter
= 0;
334 dibBMI
->bmiHeader
.biClrUsed
= 3;
335 dibBMI
->bmiHeader
.biClrImportant
= 3;
337 p
= (DWORD
*)dibBMI
->bmiColors
;
342 dibHBM
= CreateDIBSection(hDC
, dibBMI
, DIB_RGB_COLORS
, &dibSurfacePtr
, NULL
, 0);
344 ReleaseDC(dibWnd
, hDC
);
346 gdiWindowHackEna
= (dibHBM
!= NULL
? GL_TRUE
: GL_FALSE
);
348 if (!getenv("MESA_WGL_FX") || !strcmp(getenv("MESA_WGL_FX"),"fullscreen"))
349 gdiWindowHack
= GL_FALSE
;
351 gdiWindowHack
= GL_TRUE
;
352 grSstControl(GR_CONTROL_DEACTIVATE
);
356 /* For the Voodoo Rush */
358 if(getenv("MESA_WGL_FX") && !strcmp(getenv("MESA_WGL_FX"),"fullscreen")) {
361 GetClientRect(hWnd
,&cliRect
);
362 error
= !(ctx
= fxMesaCreateBestContext((GLuint
)hWnd
,cliRect
.right
,cliRect
.bottom
,
363 pix
[curPFD
- 1].mesaAttr
));
365 error
= !(ctx
= fxMesaCreateContext((GLuint
)hWnd
,GR_RESOLUTION_NONE
,GR_REFRESH_75Hz
,
366 pix
[curPFD
- 1].mesaAttr
));
369 if(getenv("SST_DUALHEAD"))
370 haveDualHead
=((atoi(getenv("SST_DUALHEAD"))==1) ? GL_TRUE
:GL_FALSE
);
372 haveDualHead
=GL_FALSE
;
382 /* Required by the OpenGL Optimizer 1.1 (is it a Optimizer bug ?) */
383 wglMakeCurrent(hdc
,(HGLRC
)1);
388 HGLRC GLAPIENTRY
wglCreateLayerContext(HDC hdc
,int iLayerPlane
)
394 BOOL GLAPIENTRY
wglDeleteContext(HGLRC hglrc
)
396 if(ctx
&& hglrc
== (HGLRC
)1) {
397 if (gdiWindowHackEna
) {
398 DeleteObject(dibHBM
);
401 dibSurfacePtr
= NULL
;
407 fxMesaDestroyContext(ctx
);
409 SetWindowLong(WindowFromDC(hDC
),GWL_WNDPROC
,(LONG
)hWNDOldProc
);
421 HGLRC GLAPIENTRY
wglGetCurrentContext(VOID
)
430 HDC GLAPIENTRY
wglGetCurrentDC(VOID
)
439 PROC GLAPIENTRY
wglGetProcAddress(LPCSTR lpszProc
)
443 /*fprintf(stderr,"fxMesa: looking for extension %s\n",lpszProc);
446 for(i
= 0;i
< qt_ext
;i
++)
447 if(!strcmp(lpszProc
,ext
[i
].name
)) {
448 /*fprintf(stderr,"fxMesa: found extension %s\n",lpszProc);
457 BOOL GLAPIENTRY
wglMakeCurrent(HDC hdc
,HGLRC hglrc
)
459 if((hdc
==NULL
) && (hglrc
==NULL
))
462 if(!ctx
|| hglrc
!= (HGLRC
)1 || WindowFromDC(hdc
) != hWND
) {
469 fxMesaMakeCurrent(ctx
);
474 BOOL GLAPIENTRY
wglShareLists(HGLRC hglrc1
,HGLRC hglrc2
)
476 if(!ctx
|| hglrc1
!= (HGLRC
)1 || hglrc1
!= hglrc2
) {
484 BOOL GLAPIENTRY
wglUseFontBitmaps(HDC fontDevice
, DWORD firstChar
, DWORD numChars
, DWORD listBase
)
494 VERIFY(GetTextMetrics(fontDevice
, &metric
));
496 dibInfo
= (BITMAPINFO
*) calloc(sizeof(BITMAPINFO
) + sizeof(RGBQUAD
), 1);
497 dibInfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
498 dibInfo
->bmiHeader
.biPlanes
= 1;
499 dibInfo
->bmiHeader
.biBitCount
= 1;
500 dibInfo
->bmiHeader
.biCompression
= BI_RGB
;
502 bitDevice
= CreateCompatibleDC(fontDevice
);
503 // HDC bitDevice = CreateDC("DISPLAY", NULL, NULL, NULL);
504 // VERIFY(bitDevice);
506 // Swap fore and back colors so the bitmap has the right polarity
507 tempColor
= GetBkColor(bitDevice
);
508 SetBkColor(bitDevice
, GetTextColor(bitDevice
));
509 SetTextColor(bitDevice
, tempColor
);
511 // Place chars based on base line
512 VERIFY(SetTextAlign(bitDevice
, TA_BASELINE
) >= 0);
514 for(i
= 0; i
< numChars
; i
++) {
517 int charWidth
,charHeight
,bmapWidth
,bmapHeight
,numBytes
,res
;
522 curChar
= i
+ firstChar
;
524 // Find how high/wide this character is
525 VERIFY(GetTextExtentPoint32(bitDevice
, &curChar
, 1, &size
));
527 // Create the output bitmap
529 charHeight
= size
.cy
;
530 bmapWidth
= ((charWidth
+ 31) / 32) * 32; // Round up to the next multiple of 32 bits
531 bmapHeight
= charHeight
;
532 bitObject
= CreateCompatibleBitmap(bitDevice
,
537 // Assign the output bitmap to the device
538 origBmap
= SelectObject(bitDevice
, bitObject
);
541 VERIFY( PatBlt( bitDevice
, 0, 0, bmapWidth
, bmapHeight
,BLACKNESS
) );
543 // Use our source font on the device
544 VERIFY(SelectObject(bitDevice
, GetCurrentObject(fontDevice
,OBJ_FONT
)));
546 // Draw the character
547 VERIFY(TextOut(bitDevice
, 0, metric
.tmAscent
, &curChar
, 1));
549 // Unselect our bmap object
550 VERIFY(SelectObject(bitDevice
, origBmap
));
552 // Convert the display dependant representation to a 1 bit deep DIB
553 numBytes
= (bmapWidth
* bmapHeight
) / 8;
554 bmap
= malloc(numBytes
);
555 dibInfo
->bmiHeader
.biWidth
= bmapWidth
;
556 dibInfo
->bmiHeader
.biHeight
= bmapHeight
;
557 res
= GetDIBits(bitDevice
, bitObject
, 0, bmapHeight
, bmap
,
562 // Create the GL object
563 glNewList(i
+ listBase
, GL_COMPILE
);
564 glBitmap(bmapWidth
, bmapHeight
, 0.0, metric
.tmDescent
,
570 // Destroy the bmap object
571 DeleteObject(bitObject
);
573 // Deallocate the bitmap data
578 VERIFY(DeleteDC(bitDevice
));
586 BOOL GLAPIENTRY
wglUseFontBitmapsW(HDC hdc
,DWORD first
,DWORD count
,DWORD listBase
)
591 BOOL GLAPIENTRY
wglUseFontOutlinesA(HDC hdc
,DWORD first
,DWORD count
,
592 DWORD listBase
,FLOAT deviation
,
593 FLOAT extrusion
,int format
,
594 LPGLYPHMETRICSFLOAT lpgmf
)
600 BOOL GLAPIENTRY
wglUseFontOutlinesW(HDC hdc
,DWORD first
,DWORD count
,
601 DWORD listBase
,FLOAT deviation
,
602 FLOAT extrusion
,int format
,
603 LPGLYPHMETRICSFLOAT lpgmf
)
610 BOOL GLAPIENTRY
wglSwapLayerBuffers(HDC hdc
,UINT fuPlanes
)
612 if(ctx
&& WindowFromDC(hdc
) == hWND
) {
622 int GLAPIENTRY
wglChoosePixelFormat(HDC hdc
,
623 CONST PIXELFORMATDESCRIPTOR
*ppfd
)
625 int i
,best
=-1,qt_valid_pix
;
627 qt_valid_pix
= qt_pix
;
629 if(ppfd
->nSize
!= sizeof(PIXELFORMATDESCRIPTOR
) || ppfd
->nVersion
!= 1) {
634 for(i
= 0;i
< qt_valid_pix
;i
++) {
635 if((ppfd
->dwFlags
& PFD_DRAW_TO_WINDOW
) && !(pix
[i
].pfd
.dwFlags
& PFD_DRAW_TO_WINDOW
))
637 if((ppfd
->dwFlags
& PFD_DRAW_TO_BITMAP
) && !(pix
[i
].pfd
.dwFlags
& PFD_DRAW_TO_BITMAP
))
639 if((ppfd
->dwFlags
& PFD_SUPPORT_GDI
) && !(pix
[i
].pfd
.dwFlags
& PFD_SUPPORT_GDI
))
641 if((ppfd
->dwFlags
& PFD_SUPPORT_OPENGL
) && !(pix
[i
].pfd
.dwFlags
& PFD_SUPPORT_OPENGL
))
643 if(!(ppfd
->dwFlags
& PFD_DOUBLEBUFFER_DONTCARE
) &&
644 ((ppfd
->dwFlags
& PFD_DOUBLEBUFFER
) != (pix
[i
].pfd
.dwFlags
& PFD_DOUBLEBUFFER
)))
646 if(!(ppfd
->dwFlags
& PFD_STEREO_DONTCARE
) &&
647 ((ppfd
->dwFlags
& PFD_STEREO
) != (pix
[i
].pfd
.dwFlags
& PFD_STEREO
)))
650 if (ppfd
->cDepthBits
> 0 && pix
[i
].pfd
.cDepthBits
== 0)
651 continue; /* need depth buffer */
653 if (ppfd
->cAlphaBits
> 0 && pix
[i
].pfd
.cAlphaBits
== 0)
654 continue; /* need alpha buffer */
656 if(ppfd
->iPixelType
== pix
[i
].pfd
.iPixelType
) {
670 int GLAPIENTRY
ChoosePixelFormat(HDC hdc
,
671 CONST PIXELFORMATDESCRIPTOR
*ppfd
)
673 return wglChoosePixelFormat(hdc
,ppfd
);
676 int GLAPIENTRY
wglDescribePixelFormat(HDC hdc
,int iPixelFormat
,UINT nBytes
,
677 LPPIXELFORMATDESCRIPTOR ppfd
)
681 qt_valid_pix
= qt_pix
;
683 if(iPixelFormat
< 1 || iPixelFormat
> qt_valid_pix
||
684 ((nBytes
!= sizeof(PIXELFORMATDESCRIPTOR
)) && (nBytes
!= 0))) {
690 *ppfd
= pix
[iPixelFormat
- 1].pfd
;
692 return(qt_valid_pix
);
695 int GLAPIENTRY
DescribePixelFormat(HDC hdc
,int iPixelFormat
,UINT nBytes
,
696 LPPIXELFORMATDESCRIPTOR ppfd
)
698 return wglDescribePixelFormat(hdc
,iPixelFormat
,nBytes
,ppfd
);
701 int GLAPIENTRY
wglGetPixelFormat(HDC hdc
)
711 int GLAPIENTRY
GetPixelFormat(HDC hdc
)
713 return wglGetPixelFormat(hdc
);
716 BOOL GLAPIENTRY
wglSetPixelFormat(HDC hdc
,int iPixelFormat
,
717 CONST PIXELFORMATDESCRIPTOR
*ppfd
)
721 qt_valid_pix
= qt_pix
;
723 if(iPixelFormat
< 1 || iPixelFormat
> qt_valid_pix
|| ppfd
->nSize
!= sizeof(PIXELFORMATDESCRIPTOR
)) {
727 curPFD
= iPixelFormat
;
732 BOOL GLAPIENTRY
wglSwapBuffers(HDC hdc
)
742 GLuint width
=ctx
->width
;
743 GLuint height
=ctx
->height
;
745 HDC hdcScreen
= GetDC(dibWnd
);
746 HDC hdcDIBSection
= CreateCompatibleDC(hdcScreen
);
747 HBITMAP holdBitmap
= (HBITMAP
) SelectObject(hdcDIBSection
, dibHBM
);
749 grLfbReadRegion(GR_BUFFER_FRONTBUFFER
, 0, 0,
754 /* Since the hardware is configured for GR_COLORFORMAT_ABGR the pixel data is
755 * going to come out as BGR 565, which is reverse of what we need for blitting
756 * to screen, so we need to convert it here pixel-by-pixel (ick). This loop would NOT
757 * be required if the color format was changed to GR_COLORFORMAT_ARGB, but I do
758 * not know the ramifications of that, so this will work until that is resolved.
760 * This routine CRIES out for MMX implementation, however since that's not
761 * guaranteed to be running on MMX enabled hardware so I'm not going to do
762 * that. I'm just going to try to make a reasonably efficient C
765 * This routine drops frame rate by <1 fps on a 200Mhz MMX processor with a 640x480
766 * display. Obviously, it's performance hit will be higher on larger displays and
767 * less on smaller displays. To support the window-hack display this is probably fine.
770 unsigned long *pixel
= dibSurfacePtr
;
771 unsigned long count
= (width
* height
) / 2;
775 *pixel
++ = (*pixel
& 0x07e007e0) /* greens */
776 | ((*pixel
& 0xf800f800) >> 11) /* swap blues */
777 | ((*pixel
& 0x001f001f) << 11) /* swap reds */
782 BitBlt(hdcScreen
, 0, 0,
787 ReleaseDC(dibWnd
, hdcScreen
);
788 SelectObject(hdcDIBSection
, holdBitmap
);
789 DeleteDC(hdcDIBSection
);
795 BOOL GLAPIENTRY
SetPixelFormat(HDC hdc
, int iPixelFormat
,
796 CONST PIXELFORMATDESCRIPTOR
*ppfd
)
798 return wglSetPixelFormat(hdc
,iPixelFormat
,ppfd
);
801 BOOL GLAPIENTRY
SwapBuffers(HDC hdc
)
803 return wglSwapBuffers(hdc
);