Release 20030408.
[wine/gsoc-2012-control.git] / dlls / opengl32 / wgl.c
blob8aab2aaa45af1b9295fbec3f9890bf9d2f827b43
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"
29 #include "x11drv.h"
31 #include "wgl.h"
32 #include "opengl_ext.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
37 void (*wine_tsx11_lock_ptr)(void) = NULL;
38 void (*wine_tsx11_unlock_ptr)(void) = NULL;
40 static GLXContext default_cx = NULL;
41 static Display *default_display; /* display to use for default context */
43 typedef struct wine_glcontext {
44 HDC hdc;
45 Display *display;
46 GLXContext ctx;
47 XVisualInfo *vis;
48 struct wine_glcontext *next;
49 struct wine_glcontext *prev;
50 } Wine_GLContext;
51 static Wine_GLContext *context_list;
53 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
55 Wine_GLContext *ret;
56 for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
57 return ret;
60 static inline void free_context(Wine_GLContext *context)
62 if (context->next != NULL) context->next->prev = context->prev;
63 if (context->prev != NULL) context->prev->next = context->next;
64 else context_list = context->next;
66 HeapFree(GetProcessHeap(), 0, context);
69 static inline Wine_GLContext *alloc_context(void)
71 Wine_GLContext *ret;
73 if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
75 ret->next = context_list;
76 if (context_list) context_list->prev = ret;
77 context_list = ret;
79 return ret;
82 inline static BOOL is_valid_context( Wine_GLContext *ctx )
84 Wine_GLContext *ptr;
85 for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
86 return (ptr != NULL);
89 /* retrieve the X display to use on a given DC */
90 inline static Display *get_display( HDC hdc )
92 Display *display;
93 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
95 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
96 sizeof(display), (LPSTR)&display )) display = NULL;
97 return display;
101 /* retrieve the X drawable to use on a given DC */
102 inline static Drawable get_drawable( HDC hdc )
104 Drawable drawable;
105 enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;
107 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
108 sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
109 return drawable;
113 /* retrieve the X drawable to use on a given DC */
114 inline static Font get_font( HDC hdc )
116 Font font;
117 enum x11drv_escape_codes escape = X11DRV_GET_FONT;
119 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
120 sizeof(font), (LPSTR)&font )) font = 0;
121 return font;
125 /***********************************************************************
126 * wglCreateContext (OPENGL32.@)
128 HGLRC WINAPI wglCreateContext(HDC hdc)
130 XVisualInfo *vis;
131 Wine_GLContext *ret;
132 int num;
133 XVisualInfo template;
134 Display *display = get_display( hdc );
136 TRACE("(%p)\n", hdc);
138 /* First, get the visual in use by the X11DRV */
139 if (!display) return 0;
140 template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
141 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
143 if (vis == NULL) {
144 ERR("NULL visual !!!\n");
145 /* Need to set errors here */
146 return NULL;
149 /* The context will be allocated in the wglMakeCurrent call */
150 ENTER_GL();
151 ret = alloc_context();
152 LEAVE_GL();
153 ret->hdc = hdc;
154 ret->display = display;
155 ret->vis = vis;
157 TRACE(" creating context %p (GL context creation delayed)\n", ret);
158 return (HGLRC) ret;
161 /***********************************************************************
162 * wglCreateLayerContext (OPENGL32.@)
164 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
165 int iLayerPlane) {
166 TRACE("(%p,%d)\n", hdc, iLayerPlane);
168 if (iLayerPlane == 0) {
169 return wglCreateContext(hdc);
171 FIXME(" no handler for layer %d\n", iLayerPlane);
173 return NULL;
176 /***********************************************************************
177 * wglCopyContext (OPENGL32.@)
179 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
180 HGLRC hglrcDst,
181 UINT mask) {
182 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
184 return FALSE;
187 /***********************************************************************
188 * wglDeleteContext (OPENGL32.@)
190 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
192 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
193 BOOL ret = TRUE;
195 TRACE("(%p)\n", hglrc);
197 ENTER_GL();
198 /* A game (Half Life not to name it) deletes twice the same context,
199 * so make sure it is valid first */
200 if (is_valid_context( ctx ))
202 if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
203 free_context(ctx);
205 else
207 WARN("Error deleting context !\n");
208 SetLastError(ERROR_INVALID_HANDLE);
209 ret = FALSE;
211 LEAVE_GL();
213 return ret;
216 /***********************************************************************
217 * wglDescribeLayerPlane (OPENGL32.@)
219 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
220 int iPixelFormat,
221 int iLayerPlane,
222 UINT nBytes,
223 LPLAYERPLANEDESCRIPTOR plpd) {
224 FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
226 return FALSE;
229 /***********************************************************************
230 * wglGetCurrentContext (OPENGL32.@)
232 HGLRC WINAPI wglGetCurrentContext(void) {
233 GLXContext gl_ctx;
234 Wine_GLContext *ret;
236 TRACE("()\n");
238 ENTER_GL();
239 gl_ctx = glXGetCurrentContext();
240 ret = get_context_from_GLXContext(gl_ctx);
241 LEAVE_GL();
243 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
245 return ret;
248 /***********************************************************************
249 * wglGetCurrentDC (OPENGL32.@)
251 HDC WINAPI wglGetCurrentDC(void) {
252 GLXContext gl_ctx;
253 Wine_GLContext *ret;
255 TRACE("()\n");
257 ENTER_GL();
258 gl_ctx = glXGetCurrentContext();
259 ret = get_context_from_GLXContext(gl_ctx);
260 LEAVE_GL();
262 if (ret) {
263 TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
264 return ret->hdc;
265 } else {
266 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
267 return 0;
271 /***********************************************************************
272 * wglGetLayerPaletteEntries (OPENGL32.@)
274 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
275 int iLayerPlane,
276 int iStart,
277 int cEntries,
278 const COLORREF *pcr) {
279 FIXME("(): stub !\n");
281 return 0;
284 /***********************************************************************
285 * wglGetProcAddress (OPENGL32.@)
287 static int compar(const void *elt_a, const void *elt_b) {
288 return strcmp(((OpenGL_extension *) elt_a)->name,
289 ((OpenGL_extension *) elt_b)->name);
292 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
293 void *local_func;
294 static HMODULE hm = 0;
295 OpenGL_extension ext;
296 OpenGL_extension *ext_ret;
299 TRACE("(%s)\n", lpszProc);
301 if (hm == 0)
302 hm = GetModuleHandleA("opengl32");
304 /* First, look if it's not already defined in the 'standard' OpenGL functions */
305 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
306 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
307 return local_func;
310 /* After that, search in the thunks to find the real name of the extension */
311 ext.name = (char *) lpszProc;
312 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
313 extension_registry_size, sizeof(OpenGL_extension), compar);
315 if (ext_ret == NULL) {
316 /* Some sanity checks :-) */
317 if (glXGetProcAddressARB(lpszProc) != NULL) {
318 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
319 return NULL;
322 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
323 return NULL;
324 } else {
325 /* After that, look at the extensions defined in the Linux OpenGL library */
326 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
327 char buf[256];
328 void *ret = NULL;
330 /* Remove the 3 last letters (EXT, ARB, ...).
332 I know that some extensions have more than 3 letters (MESA, NV,
333 INTEL, ...), but this is only a stop-gap measure to fix buggy
334 OpenGL drivers (moreover, it is only useful for old 1.0 apps
335 that query the glBindTextureEXT extension).
337 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
338 buf[strlen(ext_ret->glx_name) - 3] = '\0';
339 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
341 ret = GetProcAddress(hm, buf);
342 if (ret != NULL) {
343 TRACE(" found function in main OpenGL library (%p) !\n", ret);
344 } else {
345 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
348 return ret;
349 } else {
350 TRACE(" returning function (%p)\n", ext_ret->func);
351 *(ext_ret->func_ptr) = local_func;
353 return ext_ret->func;
358 /***********************************************************************
359 * wglMakeCurrent (OPENGL32.@)
361 BOOL WINAPI wglMakeCurrent(HDC hdc,
362 HGLRC hglrc) {
363 BOOL ret;
365 TRACE("(%p,%p)\n", hdc, hglrc);
367 ENTER_GL();
368 if (hglrc == NULL) {
369 ret = glXMakeCurrent(default_display, None, NULL);
370 } else {
371 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
372 Drawable drawable = get_drawable( hdc );
374 if (ctx->ctx == NULL) {
375 ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
376 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
378 ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
380 LEAVE_GL();
381 TRACE(" returning %s\n", (ret ? "True" : "False"));
382 return ret;
385 /***********************************************************************
386 * wglRealizeLayerPalette (OPENGL32.@)
388 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
389 int iLayerPlane,
390 BOOL bRealize) {
391 FIXME("()\n");
393 return FALSE;
396 /***********************************************************************
397 * wglSetLayerPaletteEntries (OPENGL32.@)
399 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
400 int iLayerPlane,
401 int iStart,
402 int cEntries,
403 const COLORREF *pcr) {
404 FIXME("(): stub !\n");
406 return 0;
409 /***********************************************************************
410 * wglShareLists (OPENGL32.@)
412 BOOL WINAPI wglShareLists(HGLRC hglrc1,
413 HGLRC hglrc2) {
414 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
415 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
417 TRACE("(%p, %p)\n", org, dest);
419 if (dest->ctx != NULL) {
420 ERR("Could not share display lists, context already created !\n");
421 return FALSE;
422 } else {
423 if (org->ctx == NULL) {
424 ENTER_GL();
425 org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
426 LEAVE_GL();
427 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
430 ENTER_GL();
431 /* Create the destination context with display lists shared */
432 dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
433 LEAVE_GL();
434 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
437 return TRUE;
440 /***********************************************************************
441 * wglSwapLayerBuffers (OPENGL32.@)
443 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
444 UINT fuPlanes) {
445 TRACE("(%p, %08x)\n", hdc, fuPlanes);
447 if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
448 if (!SwapBuffers(hdc)) return FALSE;
449 fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
452 if (fuPlanes) {
453 WARN("Following layers unhandled : %08x\n", fuPlanes);
456 return TRUE;
459 /***********************************************************************
460 * wglUseFontBitmapsA (OPENGL32.@)
462 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
463 DWORD first,
464 DWORD count,
465 DWORD listBase)
467 Font fid = get_font( hdc );
469 TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);
471 if (fid == 0) {
472 /* We are running using client-side rendering fonts... */
473 GLYPHMETRICS gm;
474 static const MAT2 id = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } };
475 int glyph;
476 int size = 0;
477 void *bitmap = NULL, *gl_bitmap = NULL;
478 int org_alignment;
480 ENTER_GL();
481 glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
482 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
483 LEAVE_GL();
485 for (glyph = first; glyph < first + count; glyph++) {
486 int needed_size = GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, &id);
487 int height, width_int;
489 if (needed_size == GDI_ERROR) goto error;
490 if (needed_size > size) {
491 size = needed_size;
492 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
493 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
494 bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
495 gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
497 if (GetGlyphOutlineA(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, &id) == GDI_ERROR) goto error;
498 if (TRACE_ON(opengl)) {
499 unsigned int height, width, bitmask;
500 unsigned char *bitmap_ = (unsigned char *) bitmap;
502 DPRINTF("Glyph : %d\n", glyph);
503 DPRINTF(" - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
504 DPRINTF(" - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
505 DPRINTF(" - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
506 DPRINTF(" - size : %d\n", needed_size);
507 DPRINTF(" - bitmap : \n");
508 for (height = 0; height < gm.gmBlackBoxY; height++) {
509 DPRINTF(" ");
510 for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
511 if (bitmask == 0) {
512 bitmap_ += 1;
513 bitmask = 0x80;
515 if (*bitmap_ & bitmask)
516 DPRINTF("*");
517 else
518 DPRINTF(" ");
520 bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
521 DPRINTF("\n");
525 /* For some obscure reasons, I seem to need to rotate the glyph for OpenGL to be happy.
526 As Wine does not seem to support the MAT2 field, I need to do it myself.... */
527 width_int = (gm.gmBlackBoxX + 31) / 32;
528 for (height = 0; height < gm.gmBlackBoxY; height++) {
529 int width;
530 for (width = 0; width < width_int; width++) {
531 ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
532 ((int *) bitmap)[height * width_int + width];
536 ENTER_GL();
537 glNewList(listBase++, GL_COMPILE);
538 glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x, gm.gmBlackBoxY - gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY, gl_bitmap);
539 glEndList();
540 LEAVE_GL();
543 ENTER_GL();
544 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
545 LEAVE_GL();
547 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
548 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
549 return TRUE;
551 error:
552 ENTER_GL();
553 glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
554 LEAVE_GL();
556 if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
557 if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
558 return FALSE;
561 ENTER_GL();
562 /* I assume that the glyphs are at the same position for X and for Windows */
563 glXUseXFont(fid, first, count, listBase);
564 LEAVE_GL();
565 return TRUE;
568 /***********************************************************************
569 * wglUseFontOutlinesA (OPENGL32.@)
571 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
572 DWORD first,
573 DWORD count,
574 DWORD listBase,
575 FLOAT deviation,
576 FLOAT extrusion,
577 int format,
578 LPGLYPHMETRICSFLOAT lpgmf) {
579 FIXME("(): stub !\n");
581 return FALSE;
585 /* This is for brain-dead applications that use OpenGL functions before even
586 creating a rendering context.... */
587 static BOOL process_attach(void)
589 XWindowAttributes win_attr;
590 Visual *rootVisual;
591 int num;
592 XVisualInfo template;
593 HDC hdc;
594 XVisualInfo *vis = NULL;
595 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
596 HMODULE mod = GetModuleHandleA( "x11drv.dll" );
598 if (!root || !mod)
600 ERR("X11DRV not loaded. Cannot create default context.\n");
601 return FALSE;
604 wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
605 wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );
607 hdc = GetDC(0);
608 default_display = get_display( hdc );
609 ReleaseDC( 0, hdc );
610 if (!default_display)
612 ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
613 return FALSE;
616 ENTER_GL();
618 /* Try to get the visual from the Root Window. We can't use the standard (presumably
619 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
620 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
621 with mismatched visuals. Note that the Root Window visual may not be double
622 buffered, so apps actually attempting to render this way may flicker */
623 if (XGetWindowAttributes( default_display, root, &win_attr ))
625 rootVisual = win_attr.visual;
627 else
629 /* Get the default visual, since we can't seem to get the attributes from the
630 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
631 rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
634 template.visualid = XVisualIDFromVisual(rootVisual);
635 vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
636 if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
637 if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
638 XFree(vis);
639 LEAVE_GL();
641 if (default_cx == NULL) {
642 ERR("Could not create default context.\n");
644 return TRUE;
647 /* Some WGL extensions... */
648 static const char *WGL_extensions = "";
650 const char * WINAPI wglGetExtensionsStringEXT(void) {
651 TRACE("() returning \"%s\"\n", WGL_extensions);
653 return WGL_extensions;
656 static void process_detach(void)
658 glXDestroyContext(default_display, default_cx);
661 /***********************************************************************
662 * OpenGL initialisation routine
664 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
666 switch(reason)
668 case DLL_PROCESS_ATTACH:
669 return process_attach();
670 case DLL_PROCESS_DETACH:
671 process_detach();
672 break;
674 return TRUE;