Added LGPL standard comment, and copyright notices where necessary.
[wine/multimedia.git] / dlls / opengl32 / wgl.c
blobf19f28e9dd27f86fb23e733cd296acf3b190be50
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 "wine/exception.h"
27 #include "wine/debug.h"
28 #include "gdi.h"
29 #include "windef.h"
30 #include "winerror.h"
31 #include "wine_gl.h"
32 #include "x11drv.h"
33 #include "x11font.h"
34 #include "msvcrt/excpt.h"
36 #include "wgl.h"
37 #include "opengl_ext.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(opengl);
41 static GLXContext default_cx = NULL;
43 typedef struct wine_glcontext {
44 HDC hdc;
45 GLXContext ctx;
46 XVisualInfo *vis;
47 struct wine_glcontext *next;
48 struct wine_glcontext *prev;
49 } Wine_GLContext;
50 static Wine_GLContext *context_array;
52 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx) {
53 Wine_GLContext *ret = context_array;
54 while (ret != NULL) if (ctx == ret->ctx) break; else ret = ret->next;
55 return ret;
58 static inline void free_context(Wine_GLContext *context) {
59 if (context->next != NULL) context->next->prev = context->prev;
60 if (context->prev != NULL) context->prev->next = context->next;
61 else context_array = context->next;
63 HeapFree(GetProcessHeap(), 0, context);
66 static inline Wine_GLContext *alloc_context(void) {
67 Wine_GLContext *ret;
69 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext));
70 ret->next = context_array;
71 if (context_array != NULL) context_array->prev = ret;
72 else context_array = ret;
74 return ret;
78 static int XGLErrorFlag = 0;
79 static int XGLErrorHandler(Display *dpy, XErrorEvent *event) {
80 XGLErrorFlag = 1;
81 return 0;
83 /* filter for page-fault exceptions */
84 static WINE_EXCEPTION_FILTER(page_fault)
86 return EXCEPTION_EXECUTE_HANDLER;
89 /***********************************************************************
90 * wglCreateContext (OPENGL32.@)
92 HGLRC WINAPI wglCreateContext(HDC hdc)
94 XVisualInfo *vis;
95 Wine_GLContext *ret;
96 int num;
97 XVisualInfo template;
99 TRACE("(%08x)\n", hdc);
101 /* First, get the visual in use by the X11DRV */
102 template.visualid = GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
103 vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
105 if (vis == NULL) {
106 ERR("NULL visual !!!\n");
107 /* Need to set errors here */
108 return NULL;
111 /* The context will be allocated in the wglMakeCurrent call */
112 ENTER_GL();
113 ret = alloc_context();
114 LEAVE_GL();
115 ret->hdc = hdc;
116 ret->vis = vis;
118 TRACE(" creating context %p (GL context creation delayed)\n", ret);
119 return (HGLRC) ret;
122 /***********************************************************************
123 * wglCreateLayerContext (OPENGL32.@)
125 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
126 int iLayerPlane) {
127 FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
129 return NULL;
132 /***********************************************************************
133 * wglCopyContext (OPENGL32.@)
135 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
136 HGLRC hglrcDst,
137 UINT mask) {
138 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
140 return FALSE;
143 /***********************************************************************
144 * wglDeleteContext (OPENGL32.@)
146 BOOL WINAPI wglDeleteContext(HGLRC hglrc) {
147 int (*WineXHandler)(Display *, XErrorEvent *);
148 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
149 BOOL ret;
151 TRACE("(%p)\n", hglrc);
153 ENTER_GL();
154 /* A game (Half Life not to name it) deletes twice the same context. To prevent
155 crashes, run with our own error function enabled */
156 XSync(gdi_display, False);
157 XGLErrorFlag = 0;
158 WineXHandler = XSetErrorHandler(XGLErrorHandler);
159 __TRY {
160 glXDestroyContext(gdi_display, ctx->ctx);
161 XSync(gdi_display, False);
162 XFlush(gdi_display);
164 if (XGLErrorHandler == 0) free_context(ctx);
166 __EXCEPT(page_fault) {
167 XGLErrorFlag = 1;
169 __ENDTRY
171 ret = TRUE;
172 XSetErrorHandler(WineXHandler);
173 if (XGLErrorFlag) {
174 WARN("Error deleting context !\n");
175 SetLastError(ERROR_INVALID_HANDLE);
176 ret = FALSE;
178 LEAVE_GL();
180 return ret;
183 /***********************************************************************
184 * wglDescribeLayerPlane (OPENGL32.@)
186 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
187 int iPixelFormat,
188 int iLayerPlane,
189 UINT nBytes,
190 LPLAYERPLANEDESCRIPTOR plpd) {
191 FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
193 return FALSE;
196 /***********************************************************************
197 * wglGetCurrentContext (OPENGL32.@)
199 HGLRC WINAPI wglGetCurrentContext(void) {
200 GLXContext gl_ctx;
201 Wine_GLContext *ret;
203 TRACE("()\n");
205 ENTER_GL();
206 gl_ctx = glXGetCurrentContext();
207 ret = get_context_from_GLXContext(gl_ctx);
208 LEAVE_GL();
210 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
212 return ret;
215 /***********************************************************************
216 * wglGetCurrentDC (OPENGL32.@)
218 HDC WINAPI wglGetCurrentDC(void) {
219 GLXContext gl_ctx;
220 Wine_GLContext *ret;
222 TRACE("()\n");
224 ENTER_GL();
225 gl_ctx = glXGetCurrentContext();
226 ret = get_context_from_GLXContext(gl_ctx);
227 LEAVE_GL();
229 if (ret) {
230 TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
231 return ret->hdc;
232 } else {
233 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
234 return 0;
238 /***********************************************************************
239 * wglGetLayerPaletteEntries (OPENGL32.@)
241 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
242 int iLayerPlane,
243 int iStart,
244 int cEntries,
245 const COLORREF *pcr) {
246 FIXME("(): stub !\n");
248 return 0;
251 /***********************************************************************
252 * wglGetProcAddress (OPENGL32.@)
254 static int compar(const void *elt_a, const void *elt_b) {
255 return strcmp(((OpenGL_extension *) elt_a)->name,
256 ((OpenGL_extension *) elt_b)->name);
259 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
260 void *local_func;
261 static HMODULE hm = 0;
262 OpenGL_extension ext;
263 OpenGL_extension *ext_ret;
266 TRACE("(%s)\n", lpszProc);
268 if (hm == 0)
269 hm = GetModuleHandleA("opengl32");
271 /* First, look if it's not already defined in the 'standard' OpenGL functions */
272 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
273 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
274 return local_func;
277 /* After that, search in the thunks to find the real name of the extension */
278 ext.name = (char *) lpszProc;
279 ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
280 extension_registry_size, sizeof(OpenGL_extension), compar);
282 if (ext_ret == NULL) {
283 /* Some sanity checks :-) */
284 if (glXGetProcAddressARB(lpszProc) != NULL) {
285 ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
286 return NULL;
289 WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
290 return NULL;
291 } else {
292 /* After that, look at the extensions defined in the Linux OpenGL library */
293 if ((local_func = glXGetProcAddressARB(ext_ret->glx_name)) == NULL) {
294 char buf[256];
295 void *ret = NULL;
297 /* Remove the 3 last letters (EXT, ARB, ...).
299 I know that some extensions have more than 3 letters (MESA, NV,
300 INTEL, ...), but this is only a stop-gap measure to fix buggy
301 OpenGL drivers (moreover, it is only useful for old 1.0 apps
302 that query the glBindTextureEXT extension).
304 strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
305 buf[strlen(ext_ret->glx_name) - 3] = '\0';
306 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
308 ret = GetProcAddress(hm, buf);
309 if (ret != NULL) {
310 TRACE(" found function in main OpenGL library (%p) !\n", ret);
311 } else {
312 WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
315 return ret;
316 } else {
317 TRACE(" returning function (%p)\n", ext_ret->func);
318 *(ext_ret->func_ptr) = local_func;
320 return ext_ret->func;
325 /***********************************************************************
326 * wglMakeCurrent (OPENGL32.@)
328 BOOL WINAPI wglMakeCurrent(HDC hdc,
329 HGLRC hglrc) {
330 BOOL ret;
332 TRACE("(%08x,%p)\n", hdc, hglrc);
334 if (hglrc == NULL) {
335 ENTER_GL();
336 ret = glXMakeCurrent(gdi_display,
337 None,
338 NULL);
339 LEAVE_GL();
340 } else {
341 DC * dc = DC_GetDCPtr( hdc );
343 if (dc == NULL) {
344 ERR("Null DC !!!\n");
345 ret = FALSE;
346 } else {
347 X11DRV_PDEVICE *physDev;
348 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
350 physDev =(X11DRV_PDEVICE *)dc->physDev;
352 if (ctx->ctx == NULL) {
353 ENTER_GL();
354 ctx->ctx = glXCreateContext(gdi_display, ctx->vis, NULL, True);
355 LEAVE_GL();
356 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
359 ENTER_GL();
360 ret = glXMakeCurrent(gdi_display,
361 physDev->drawable,
362 ctx->ctx);
363 LEAVE_GL();
364 GDI_ReleaseObj( hdc );
367 TRACE(" returning %s\n", (ret ? "True" : "False"));
368 return ret;
371 /***********************************************************************
372 * wglRealizeLayerPalette (OPENGL32.@)
374 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
375 int iLayerPlane,
376 BOOL bRealize) {
377 FIXME("()\n");
379 return FALSE;
382 /***********************************************************************
383 * wglSetLayerPaletteEntries (OPENGL32.@)
385 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
386 int iLayerPlane,
387 int iStart,
388 int cEntries,
389 const COLORREF *pcr) {
390 FIXME("(): stub !\n");
392 return 0;
395 /***********************************************************************
396 * wglShareLists (OPENGL32.@)
398 BOOL WINAPI wglShareLists(HGLRC hglrc1,
399 HGLRC hglrc2) {
400 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
401 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
403 TRACE("(%p, %p)\n", org, dest);
405 if (dest->ctx != NULL) {
406 ERR("Could not share display lists, context already created !\n");
407 return FALSE;
408 } else {
409 if (org->ctx == NULL) {
410 ENTER_GL();
411 org->ctx = glXCreateContext(gdi_display, org->vis, NULL, True);
412 LEAVE_GL();
413 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
416 ENTER_GL();
417 /* Create the destination context with display lists shared */
418 dest->ctx = glXCreateContext(gdi_display, dest->vis, org->ctx, True);
419 LEAVE_GL();
420 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
423 return TRUE;
426 /***********************************************************************
427 * wglSwapLayerBuffers (OPENGL32.@)
429 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
430 UINT fuPlanes) {
431 FIXME("(): stub !\n");
433 return FALSE;
436 /***********************************************************************
437 * wglUseFontBitmapsA (OPENGL32.@)
439 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
440 DWORD first,
441 DWORD count,
442 DWORD listBase) {
443 DC * dc = DC_GetDCPtr( hdc );
444 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
445 fontObject* pfo = XFONT_GetFontObject( physDev->font );
446 Font fid = pfo->fs->fid;
448 TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
450 ENTER_GL();
451 /* I assume that the glyphs are at the same position for X and for Windows */
452 glXUseXFont(fid, first, count, listBase);
453 LEAVE_GL();
454 GDI_ReleaseObj( hdc );
455 return TRUE;
458 /***********************************************************************
459 * wglUseFontOutlinesA (OPENGL32.@)
461 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
462 DWORD first,
463 DWORD count,
464 DWORD listBase,
465 FLOAT deviation,
466 FLOAT extrusion,
467 int format,
468 LPGLYPHMETRICSFLOAT lpgmf) {
469 FIXME("(): stub !\n");
471 return FALSE;
475 /* This is for brain-dead applications that use OpenGL functions before even
476 creating a rendering context.... */
477 static void process_attach(void) {
478 XWindowAttributes win_attr;
479 Visual *rootVisual;
480 int num;
481 XVisualInfo template;
482 XVisualInfo *vis = NULL;
483 Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
485 if (!root)
487 ERR("X11DRV not loaded. Cannot create default context.\n");
488 return;
491 ENTER_GL();
493 /* Try to get the visual from the Root Window. We can't use the standard (presumably
494 double buffered) X11DRV visual with the Root Window, since we don't know if the Root
495 Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
496 with mismatched visuals. Note that the Root Window visual may not be double
497 buffered, so apps actually attempting to render this way may flicker */
498 if (XGetWindowAttributes( gdi_display, root, &win_attr ))
500 rootVisual = win_attr.visual;
502 else
504 /* Get the default visual, since we can't seem to get the attributes from the
505 Root Window. Let's hope that the Root Window Visual matches the DefaultVisual */
506 rootVisual = DefaultVisual( gdi_display, DefaultScreen(gdi_display) );
509 template.visualid = XVisualIDFromVisual(rootVisual);
510 vis = XGetVisualInfo(gdi_display, VisualIDMask, &template, &num);
511 if (vis != NULL) default_cx = glXCreateContext(gdi_display, vis, 0, GL_TRUE);
512 if (default_cx != NULL) glXMakeCurrent(gdi_display, root, default_cx);
513 XFree(vis);
514 LEAVE_GL();
516 if (default_cx == NULL) {
517 ERR("Could not create default context.\n");
520 context_array = NULL;
523 static void process_detach(void) {
524 glXDestroyContext(gdi_display, default_cx);
527 /***********************************************************************
528 * OpenGL initialisation routine
530 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
532 switch(reason) {
533 case DLL_PROCESS_ATTACH:
534 process_attach();
535 break;
536 case DLL_PROCESS_DETACH:
537 process_detach();
538 break;
540 return TRUE;