Moved x11drv.h to dlls/x11drv.
[wine/wine-kai.git] / dlls / opengl32 / wgl.c
blob9124565f189dfd7fa8a9f2beee8043bc758c19e9
1 /* Window-specific OpenGL functions implementation.
3 * Copyright (c) 1999 Lionel Ulmer
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "config.h"
22 #include <stdlib.h>
23 #include <string.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
30 #include "wgl.h"
31 #include "opengl_ext.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
36 /* x11drv GDI escapes */
37 #define X11DRV_ESCAPE 6789
38 enum x11drv_escape_codes
40 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
41 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
42 X11DRV_GET_FONT, /* get current X font for a DC */
45 void (*wine_tsx11_lock_ptr)(void) = NULL;
46 void (*wine_tsx11_unlock_ptr)(void) = NULL;
48 static GLXContext default_cx = NULL;
49 static Display *default_display; /* display to use for default context */
51 typedef struct wine_glcontext {
52 HDC hdc;
53 Display *display;
54 GLXContext ctx;
55 XVisualInfo *vis;
56 struct wine_glcontext *next;
57 struct wine_glcontext *prev;
58 } Wine_GLContext;
59 static Wine_GLContext *context_list;
61 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
63 Wine_GLContext *ret;
64 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
65 return ret;
68 static inline void free_context(Wine_GLContext *context)
70 if (context->next != NULL) context->next->prev = context->prev;
71 if (context->prev != NULL) context->prev->next = context->next;
72 else context_list = context->next;
74 HeapFree(GetProcessHeap(), 0, context);
77 static inline Wine_GLContext *alloc_context(void)
79 Wine_GLContext *ret;
81 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
83 ret->next = context_list;
84 if (context_list) context_list->prev = ret;
85 context_list = ret;
87 return ret;
90 inline static BOOL is_valid_context( Wine_GLContext *ctx )
92 Wine_GLContext *ptr;
93 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
94 return (ptr != NULL);
97 /* retrieve the X display to use on a given DC */
98 inline static Display *get_display( HDC hdc )
100 Display *display;
101 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
103 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
104 sizeof(display), (LPSTR)&display )) display = NULL;
105 return display;
109 /* retrieve the X drawable to use on a given DC */
110 inline static Drawable get_drawable( HDC hdc )
112 Drawable drawable;
113 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
115 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
116 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
117 return drawable;
121 /* retrieve the X drawable to use on a given DC */
122 inline static Font get_font( HDC hdc )
124 Font font;
125 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
127 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
128 sizeof(font), (LPSTR)&font )) font = 0;
129 return font;
133 /***********************************************************************
134 * wglCreateContext (OPENGL32.@)
136 HGLRC WINAPI wglCreateContext(HDC hdc)
138 XVisualInfo *vis;
139 Wine_GLContext *ret;
140 int num;
141 XVisualInfo template;
142 Display *display = get_display( hdc );
144 TRACE("(%p)\n", hdc);
146 /* First, get the visual in use by the X11DRV */
147 if (!display) return 0;
148 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
149 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
151 if (vis == NULL) {
152 ERR("NULL visual !!!\n");
153 /* Need to set errors here */
154 return NULL;
157 /* The context will be allocated in the wglMakeCurrent call */
158 ENTER_GL();
159 ret = alloc_context();
160 LEAVE_GL();
161 ret->hdc = hdc;
162 ret->display = display;
163 ret->vis = vis;
165 TRACE(" creating context %p (GL context creation delayed)\n", ret);
166 return (HGLRC) ret;
169 /***********************************************************************
170 * wglCreateLayerContext (OPENGL32.@)
172 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
173 int iLayerPlane) {
174 TRACE("(%p,%d)\n", hdc, iLayerPlane);
176 if (iLayerPlane == 0) {
177 return wglCreateContext(hdc);
179 FIXME(" no handler for layer %d\n", iLayerPlane);
181 return NULL;
184 /***********************************************************************
185 * wglCopyContext (OPENGL32.@)
187 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
188 HGLRC hglrcDst,
189 UINT mask) {
190 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
192 return FALSE;
195 /***********************************************************************
196 * wglDeleteContext (OPENGL32.@)
198 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
200 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
201 BOOL ret = TRUE;
203 TRACE("(%p)\n", hglrc);
205 ENTER_GL();
206 /* A game (Half Life not to name it) deletes twice the same context,
207 * so make sure it is valid first */
208 if (is_valid_context( ctx ))
210 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
211 free_context(ctx);
213 else
215 WARN("Error deleting context !\n");
216 SetLastError(ERROR_INVALID_HANDLE);
217 ret = FALSE;
219 LEAVE_GL();
221 return ret;
224 /***********************************************************************
225 * wglDescribeLayerPlane (OPENGL32.@)
227 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
228 int iPixelFormat,
229 int iLayerPlane,
230 UINT nBytes,
231 LPLAYERPLANEDESCRIPTOR plpd) {
232 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
234 return FALSE;
237 /***********************************************************************
238 * wglGetCurrentContext (OPENGL32.@)
240 HGLRC WINAPI wglGetCurrentContext(void) {
241 GLXContext gl_ctx;
242 Wine_GLContext *ret;
244 TRACE("()\n");
246 ENTER_GL();
247 gl_ctx = glXGetCurrentContext();
248 ret = get_context_from_GLXContext(gl_ctx);
249 LEAVE_GL();
251 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
253 return ret;
256 /***********************************************************************
257 * wglGetCurrentDC (OPENGL32.@)
259 HDC WINAPI wglGetCurrentDC(void) {
260 GLXContext gl_ctx;
261 Wine_GLContext *ret;
263 TRACE("()\n");
265 ENTER_GL();
266 gl_ctx = glXGetCurrentContext();
267 ret = get_context_from_GLXContext(gl_ctx);
268 LEAVE_GL();
270 if (ret) {
271 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
272 return ret->hdc;
273 } else {
274 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
275 return 0;
279 /***********************************************************************
280 * wglGetLayerPaletteEntries (OPENGL32.@)
282 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
283 int iLayerPlane,
284 int iStart,
285 int cEntries,
286 const COLORREF *pcr) {
287 FIXME("(): stub !\n");
289 return 0;
292 /***********************************************************************
293 * wglGetProcAddress (OPENGL32.@)
295 static int compar(const void *elt_a, const void *elt_b) {
296 return strcmp(((OpenGL_extension *) elt_a)->name,
297 ((OpenGL_extension *) elt_b)->name);
300 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
301 void *local_func;
302 static HMODULE hm = 0;
303 OpenGL_extension ext;
304 OpenGL_extension *ext_ret;
307 TRACE("(%s)\n", lpszProc);
309 if (hm == 0)
310 hm = GetModuleHandleA("opengl32");
312 /* First, look if it's not already defined in the 'standard' OpenGL functions */
313 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
314 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
315 return local_func;
318 /* After that, search in the thunks to find the real name of the extension */
319 ext.name = (char *) lpszProc;
320 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
321 extension_registry_size, sizeof(OpenGL_extension), compar);
323 if (ext_ret == NULL) {
324 /* Some sanity checks :-) */
325 if (glXGetProcAddressARB(lpszProc) != NULL) {
326 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
327 return NULL;
330 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
331 return NULL;
332 } else {
333 /* After that, look at the extensions defined in the Linux OpenGL library */
334 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
335 char buf[256];
336 void *ret = NULL;
338 /* Remove the 3 last letters (EXT, ARB, ...).
340 I know that some extensions have more than 3 letters (MESA, NV,
341 INTEL, ...), but this is only a stop-gap measure to fix buggy
342 OpenGL drivers (moreover, it is only useful for old 1.0 apps
343 that query the glBindTextureEXT extension).
345 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
346 buf[strlen(ext_ret->glx_name) - 3] = '\0';
347 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
349 ret = GetProcAddress(hm, buf);
350 if (ret != NULL) {
351 TRACE(" found function in main OpenGL library (%p) !\n", ret);
352 } else {
353 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
356 return ret;
357 } else {
358 TRACE(" returning function (%p)\n", ext_ret->func);
359 *(ext_ret->func_ptr) = local_func;
361 return ext_ret->func;
366 /***********************************************************************
367 * wglMakeCurrent (OPENGL32.@)
369 BOOL WINAPI wglMakeCurrent(HDC hdc,
370 HGLRC hglrc) {
371 BOOL ret;
373 TRACE("(%p,%p)\n", hdc, hglrc);
375 ENTER_GL();
376 if (hglrc == NULL) {
377 ret = glXMakeCurrent(default_display, None, NULL);
378 } else {
379 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
380 Drawable drawable = get_drawable( hdc );
382 if (ctx->ctx == NULL) {
383 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
384 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
386 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
388 LEAVE_GL();
389 TRACE(" returning %s\n", (ret ? "True" : "False"));
390 return ret;
393 /***********************************************************************
394 * wglRealizeLayerPalette (OPENGL32.@)
396 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
397 int iLayerPlane,
398 BOOL bRealize) {
399 FIXME("()\n");
401 return FALSE;
404 /***********************************************************************
405 * wglSetLayerPaletteEntries (OPENGL32.@)
407 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
408 int iLayerPlane,
409 int iStart,
410 int cEntries,
411 const COLORREF *pcr) {
412 FIXME("(): stub !\n");
414 return 0;
417 /***********************************************************************
418 * wglShareLists (OPENGL32.@)
420 BOOL WINAPI wglShareLists(HGLRC hglrc1,
421 HGLRC hglrc2) {
422 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
423 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
425 TRACE("(%p, %p)\n", org, dest);
427 if (dest->ctx != NULL) {
428 ERR("Could not share display lists, context already created !\n");
429 return FALSE;
430 } else {
431 if (org->ctx == NULL) {
432 ENTER_GL();
433 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
434 LEAVE_GL();
435 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
438 ENTER_GL();
439 /* Create the destination context with display lists shared */
440 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
441 LEAVE_GL();
442 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
445 return TRUE;
448 /***********************************************************************
449 * wglSwapLayerBuffers (OPENGL32.@)
451 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
452 UINT fuPlanes) {
453 TRACE("(%p, %08x)\n", hdc, fuPlanes);
455 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
456 if (!SwapBuffers(hdc)) return FALSE;
457 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
460 if (fuPlanes) {
461 WARN("Following layers unhandled : %08x\n", fuPlanes);
464 return TRUE;
467 /***********************************************************************
468 * wglUseFontBitmapsA (OPENGL32.@)
470 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
471 DWORD first,
472 DWORD count,
473 DWORD listBase)
475 Font fid = get_font( hdc );
477 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
479 if (fid == 0) {
480 /* We are running using client-side rendering fonts... */
481 GLYPHMETRICS gm;
482 static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
483 int glyph;
484 int size = 0;
485 void *bitmap = NULL, *gl_bitmap = NULL;
486 int org_alignment;
488 ENTER_GL();
489 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
490 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
491 LEAVE_GL();
493 for (glyph = first; glyph < first + count; glyph++) {
494 int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
495 int height, width_int;
497 if (needed_size == GDI_ERROR) goto error;
498 if (needed_size > size) {
499 size = needed_size;
500 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
501 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
502 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
503 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
505 if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
506 if (TRACE_ON(opengl)) {
507 unsigned int height, width, bitmask;
508 unsigned char *bitmap_ = (unsigned char *) bitmap;
510 DPRINTF("Glyph : %d\n", glyph);
511 DPRINTF(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
512 DPRINTF(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
513 DPRINTF(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
514 DPRINTF(" - size : %d\n", needed_size);
515 DPRINTF(" - bitmap : \n");
516 for (height = 0; height < gm.gmBlackBoxY; height++) {
517 DPRINTF(" ");
518 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
519 if (bitmask == 0) {
520 bitmap_ += 1;
521 bitmask = 0x80;
523 if (*bitmap_ & bitmask)
524 DPRINTF("*");
525 else
526 DPRINTF(" ");
528 bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
529 DPRINTF("\n");
533 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
534 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
535 width_int = (gm.gmBlackBoxX + 31) / 32;
536 for (height = 0; height < gm.gmBlackBoxY; height++) {
537 int width;
538 for (width = 0; width < width_int; width++) {
539 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
540 ((int *) bitmap)[height * width_int + width];
544 ENTER_GL();
545 glNewList(listBase++, GL_COMPILE);
546 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
547 glEndList();
548 LEAVE_GL();
551 ENTER_GL();
552 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
553 LEAVE_GL();
555 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
556 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
557 return TRUE;
559 error:
560 ENTER_GL();
561 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
562 LEAVE_GL();
564 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
565 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
566 return FALSE;
569 ENTER_GL();
570 /* I assume that the glyphs are at the same position for X and for Windows */
571 glXUseXFont(fid, first, count, listBase);
572 LEAVE_GL();
573 return TRUE;
576 /***********************************************************************
577 * wglUseFontOutlinesA (OPENGL32.@)
579 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
580 DWORD first,
581 DWORD count,
582 DWORD listBase,
583 FLOAT deviation,
584 FLOAT extrusion,
585 int format,
586 LPGLYPHMETRICSFLOAT lpgmf) {
587 FIXME("(): stub !\n");
589 return FALSE;
593 /* This is for brain-dead applications that use OpenGL functions before even
594 creating a rendering context.... */
595 static BOOL process_attach(void)
597 XWindowAttributes win_attr;
598 Visual *rootVisual;
599 int num;
600 XVisualInfo template;
601 HDC hdc;
602 XVisualInfo *vis = NULL;
603 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
604 HMODULE mod = GetModuleHandleA( "x11drv.dll" );
606 if (!root || !mod)
608 ERR("X11DRV not loaded. Cannot create default context.\n");
609 return FALSE;
612 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
613 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
615 hdc = GetDC(0);
616 default_display = get_display( hdc );
617 ReleaseDC( 0, hdc );
618 if (!default_display)
620 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
621 return FALSE;
624 ENTER_GL();
626 /* Try to get the visual from the Root Window. We can't use the standard (presumably
627 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
628 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
629 with mismatched visuals. Note that the Root Window visual may not be double
630 buffered, so apps actually attempting to render this way may flicker */
631 if (XGetWindowAttributes( default_display, root, &win_attr ))
633 rootVisual = win_attr.visual;
635 else
637 /* Get the default visual, since we can't seem to get the attributes from the
638 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
639 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
642 template.visualid = XVisualIDFromVisual(rootVisual);
643 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
644 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
645 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
646 XFree(vis);
647 LEAVE_GL();
649 if (default_cx == NULL) {
650 ERR("Could not create default context.\n");
652 return TRUE;
655 /* Some WGL extensions... */
656 static const char *WGL_extensions = "";
658 const char * WINAPI wglGetExtensionsStringEXT(void) {
659 TRACE("() returning \"%s\"\n", WGL_extensions);
661 return WGL_extensions;
664 static void process_detach(void)
666 glXDestroyContext(default_display, default_cx);
669 /***********************************************************************
670 * OpenGL initialisation routine
672 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
674 switch(reason)
676 case DLL_PROCESS_ATTACH:
677 return process_attach();
678 case DLL_PROCESS_DETACH:
679 process_detach();
680 break;
682 return TRUE;