- moved the 'constructor' into a real DLL init function
[wine/hacks.git] / dlls / opengl32 / wgl.c
blob9aa66e9b7527687668199f322ca4dd43820cae88
1 /* Window-specific OpenGL functions implementation.
3 Copyright (c) 1999 Lionel Ulmer
4 */
6 #include <stdlib.h>
8 #include "wine/exception.h"
10 #include "config.h"
11 #include "debugtools.h"
12 #include "gdi.h"
13 #include "dc.h"
14 #include "windef.h"
15 #include "winerror.h"
16 #include "wine_gl.h"
17 #include "x11drv.h"
18 #include "x11font.h"
20 #include "wgl.h"
21 #include "opengl_ext.h"
23 DEFAULT_DEBUG_CHANNEL(opengl);
25 static GLXContext default_cx = NULL;
27 typedef struct wine_glcontext {
28 HDC hdc;
29 GLXContext ctx;
30 XVisualInfo *vis;
31 struct wine_glcontext *next;
32 struct wine_glcontext *prev;
33 } Wine_GLContext;
34 static Wine_GLContext *context_array;
36 static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx) {
37 Wine_GLContext *ret = context_array;
38 while (ret != NULL) if (ctx == ret->ctx) break; else ret = ret->next;
39 return ret;
42 static inline void free_context(Wine_GLContext *context) {
43 if (context->next != NULL) context->next->prev = context->prev;
44 if (context->prev != NULL) context->prev->next = context->next;
45 else context_array = context->next;
47 HeapFree(GetProcessHeap(), 0, context);
50 static inline Wine_GLContext *alloc_context(void) {
51 Wine_GLContext *ret;
53 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext));
54 ret->next = context_array;
55 if (context_array != NULL) context_array->prev = ret;
56 else context_array = ret;
58 return ret;
62 static int XGLErrorFlag = 0;
63 static int XGLErrorHandler(Display *dpy, XErrorEvent *event) {
64 XGLErrorFlag = 1;
65 return 0;
67 /* filter for page-fault exceptions */
68 static WINE_EXCEPTION_FILTER(page_fault)
70 return EXCEPTION_EXECUTE_HANDLER;
73 /***********************************************************************
74 * wglCreateContext
76 HGLRC WINAPI wglCreateContext(HDC hdc) {
77 DC * dc = DC_GetDCPtr( hdc );
78 X11DRV_PDEVICE *physDev;
79 XVisualInfo *vis;
80 Wine_GLContext *ret;
82 TRACE("(%08x)\n", hdc);
84 if (dc == NULL) {
85 ERR("Null DC !!!\n");
86 return NULL;
89 physDev = (X11DRV_PDEVICE *)dc->physDev;
91 /* First, get the visual for the choosen pixel format */
92 vis = physDev->visuals[physDev->current_pf - 1];
94 if (vis == NULL) {
95 ERR("NULL visual !!!\n");
96 /* Need to set errors here */
97 return NULL;
100 /* The context will be allocated in the wglMakeCurrent call */
101 ENTER_GL();
102 ret = alloc_context();
103 LEAVE_GL();
104 ret->hdc = hdc;
105 ret->vis = vis;
107 TRACE(" creating context %p (GL context creation delayed)\n", ret);
109 return (HGLRC) ret;
112 /***********************************************************************
113 * wglCreateLayerContext
115 HGLRC WINAPI wglCreateLayerContext(HDC hdc,
116 int iLayerPlane) {
117 FIXME("(%08x,%d): stub !\n", hdc, iLayerPlane);
119 return NULL;
122 /***********************************************************************
123 * wglCopyContext
125 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
126 HGLRC hglrcDst,
127 UINT mask) {
128 FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);
130 return FALSE;
133 /***********************************************************************
134 * wglDeleteContext
136 BOOL WINAPI wglDeleteContext(HGLRC hglrc) {
137 int (*WineXHandler)(Display *, XErrorEvent *);
138 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
139 BOOL ret;
141 TRACE("(%p)\n", hglrc);
143 ENTER_GL();
144 /* A game (Half Life not to name it) deletes twice the same context. To prevent
145 crashes, run with our own error function enabled */
146 XSync(display, False);
147 XGLErrorFlag = 0;
148 WineXHandler = XSetErrorHandler(XGLErrorHandler);
149 __TRY {
150 glXDestroyContext(display, ctx->ctx);
151 XSync(display, False);
152 XFlush(display);
154 if (XGLErrorHandler == 0) free_context(ctx);
156 __EXCEPT(page_fault) {
157 XGLErrorFlag = 1;
159 __ENDTRY
161 ret = TRUE;
162 XSetErrorHandler(WineXHandler);
163 if (XGLErrorFlag) {
164 WARN("Error deleting context !\n");
165 SetLastError(ERROR_INVALID_HANDLE);
166 ret = FALSE;
168 LEAVE_GL();
170 return ret;
173 /***********************************************************************
174 * wglDescribeLayerPlane
176 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
177 int iPixelFormat,
178 int iLayerPlane,
179 UINT nBytes,
180 LPLAYERPLANEDESCRIPTOR plpd) {
181 FIXME("(%08x,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
183 return FALSE;
186 /***********************************************************************
187 * wglGetCurrentContext
189 HGLRC WINAPI wglGetCurrentContext(void) {
190 GLXContext gl_ctx;
191 Wine_GLContext *ret;
193 TRACE("()\n");
195 ENTER_GL();
196 gl_ctx = glXGetCurrentContext();
197 ret = get_context_from_GLXContext(gl_ctx);
198 LEAVE_GL();
200 TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
202 return ret;
205 /***********************************************************************
206 * wglGetCurrentDC
208 HDC WINAPI wglGetCurrentDC(void) {
209 GLXContext gl_ctx;
210 Wine_GLContext *ret;
212 TRACE("()\n");
214 ENTER_GL();
215 gl_ctx = glXGetCurrentContext();
216 ret = get_context_from_GLXContext(gl_ctx);
217 LEAVE_GL();
219 if (ret) {
220 TRACE(" returning %08x (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
221 return ret->hdc;
222 } else {
223 TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
224 return 0;
228 /***********************************************************************
229 * wglGetLayerPaletteEntries
231 int WINAPI wglGetLayerPaletteEntries(HDC hdc,
232 int iLayerPlane,
233 int iStart,
234 int cEntries,
235 const COLORREF *pcr) {
236 FIXME("(): stub !\n");
238 return 0;
241 static int compar(const void *elt_a, const void *elt_b) {
242 return strcmp(((OpenGL_extension *) elt_a)->name,
243 ((OpenGL_extension *) elt_b)->name);
246 /***********************************************************************
247 * wglGetProcAddress
249 void* WINAPI wglGetProcAddress(LPCSTR lpszProc) {
250 void *local_func;
251 static HMODULE hm = 0;
253 TRACE("(%s)\n", lpszProc);
255 if (hm == 0)
256 hm = GetModuleHandleA("opengl32");
258 /* First, look if it's not already defined in the 'standard' OpenGL functions */
259 if ((local_func = GetProcAddress(hm, lpszProc)) != NULL) {
260 TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
261 return local_func;
264 /* After that, look at the extensions defined in the Linux OpenGL library */
265 if ((local_func = glXGetProcAddressARB(lpszProc)) == NULL) {
266 char buf[256];
267 void *ret = NULL;
269 /* Remove the 3 last letters (EXT, ARB, ...).
271 I know that some extensions have more than 3 letters (MESA, NV,
272 INTEL, ...), but this is only a stop-gap measure to fix buggy
273 OpenGL drivers (moreover, it is only useful for old 1.0 apps
274 that query the glBindTextureEXT extension).
276 strncpy(buf, lpszProc, strlen(lpszProc) - 3);
277 buf[strlen(lpszProc) - 3] = '\0';
278 TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
280 ret = GetProcAddress(hm, buf);
281 if (ret != NULL) {
282 TRACE(" found function in main OpenGL library (%p) !\n", ret);
285 return ret;
286 } else {
287 OpenGL_extension ext;
288 OpenGL_extension *ret;
290 ext.name = (char *) lpszProc;
291 ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
292 extension_registry_size, sizeof(OpenGL_extension), compar);
294 if (ret != NULL) {
295 TRACE(" returning function (%p)\n", ret->func);
296 *(ret->func_ptr) = local_func;
298 return ret->func;
299 } else {
300 ERR("Extension defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n");
301 return NULL;
306 /***********************************************************************
307 * wglMakeCurrent
309 BOOL WINAPI wglMakeCurrent(HDC hdc,
310 HGLRC hglrc) {
311 BOOL ret;
313 TRACE("(%08x,%p)\n", hdc, hglrc);
315 if (hglrc == NULL) {
316 ENTER_GL();
317 ret = glXMakeCurrent(display,
318 None,
319 NULL);
320 LEAVE_GL();
321 } else {
322 DC * dc = DC_GetDCPtr( hdc );
324 if (dc == NULL) {
325 ERR("Null DC !!!\n");
326 ret = FALSE;
327 } else {
328 X11DRV_PDEVICE *physDev;
329 Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
331 physDev =(X11DRV_PDEVICE *)dc->physDev;
333 if (ctx->ctx == NULL) {
334 ENTER_GL();
335 ctx->ctx = glXCreateContext(display, ctx->vis, NULL, True);
336 LEAVE_GL();
337 TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
340 ENTER_GL();
341 ret = glXMakeCurrent(display,
342 physDev->drawable,
343 ctx->ctx);
344 LEAVE_GL();
347 TRACE(" returning %s\n", (ret ? "True" : "False"));
348 return ret;
351 /***********************************************************************
352 * wglRealizeLayerPalette
354 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
355 int iLayerPlane,
356 BOOL bRealize) {
357 FIXME("()\n");
359 return FALSE;
362 /***********************************************************************
363 * wglSetLayerPaletteEntries
365 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
366 int iLayerPlane,
367 int iStart,
368 int cEntries,
369 const COLORREF *pcr) {
370 FIXME("(): stub !\n");
372 return 0;
375 /***********************************************************************
376 * wglShareLists
378 BOOL WINAPI wglShareLists(HGLRC hglrc1,
379 HGLRC hglrc2) {
380 Wine_GLContext *org = (Wine_GLContext *) hglrc1;
381 Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
383 TRACE("(%p, %p)\n", org, dest);
385 if (dest->ctx != NULL) {
386 ERR("Could not share display lists, context already created !\n");
387 return FALSE;
388 } else {
389 if (org->ctx == NULL) {
390 ENTER_GL();
391 org->ctx = glXCreateContext(display, org->vis, NULL, True);
392 LEAVE_GL();
393 TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
396 ENTER_GL();
397 /* Create the destination context with display lists shared */
398 dest->ctx = glXCreateContext(display, dest->vis, org->ctx, True);
399 LEAVE_GL();
400 TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
403 return TRUE;
406 /***********************************************************************
407 * wglSwapLayerBuffers
409 BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
410 UINT fuPlanes) {
411 FIXME("(): stub !\n");
413 return FALSE;
416 /***********************************************************************
417 * wglUseFontBitmapsA
419 BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
420 DWORD first,
421 DWORD count,
422 DWORD listBase) {
423 DC * dc = DC_GetDCPtr( hdc );
424 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
425 fontObject* pfo = XFONT_GetFontObject( physDev->font );
426 Font fid = pfo->fs->fid;
428 TRACE("(%08x, %ld, %ld, %ld)\n", hdc, first, count, listBase);
430 ENTER_GL();
431 /* I assume that the glyphs are at the same position for X and for Windows */
432 glXUseXFont(fid, first, count, listBase);
433 LEAVE_GL();
435 return TRUE;
438 /***********************************************************************
439 * wglUseFontOutlinesA
441 BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
442 DWORD first,
443 DWORD count,
444 DWORD listBase,
445 FLOAT deviation,
446 FLOAT extrusion,
447 int format,
448 LPGLYPHMETRICSFLOAT lpgmf) {
449 FIXME("(): stub !\n");
451 return FALSE;
455 /* This is for brain-dead applications that use OpenGL functions before even
456 creating a rendering context.... */
457 static void process_attach(void) {
458 int num;
459 XVisualInfo template;
460 XVisualInfo *vis = NULL;
462 if (!visual) {
463 ERR("X11DRV not loaded yet. Cannot create default context.\n");
464 return;
467 ENTER_GL();
468 template.visualid = XVisualIDFromVisual(visual);
469 vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
470 if (vis != NULL) default_cx = glXCreateContext(display, vis, 0, GL_TRUE);
471 if (default_cx != NULL) glXMakeCurrent(display, X11DRV_GetXRootWindow(), default_cx);
472 XFree(vis);
473 LEAVE_GL();
475 if (default_cx == NULL) {
476 ERR("Could not create default context.\n");
479 context_array = NULL;
482 static void process_detach(void) {
483 glXDestroyContext(display, default_cx);
486 /***********************************************************************
487 * OpenGL initialisation routine
489 BOOL WINAPI OpenGL32_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
491 static int process_count;
493 switch(reason) {
494 case DLL_PROCESS_ATTACH:
495 if (!process_count++) process_attach();
496 break;
497 case DLL_PROCESS_DETACH:
498 if (!--process_count) process_detach();
499 break;
502 return TRUE;