wgl.c 22.4 KB
Newer Older
Lionel Ulmer's avatar
Lionel Ulmer committed
1
/* Window-specific OpenGL functions implementation.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * Copyright (c) 1999 Lionel Ulmer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
19

20
#include "config.h"
21
#include "wine/port.h"
22

23
#include <stdarg.h>
Lionel Ulmer's avatar
Lionel Ulmer committed
24
#include <stdlib.h>
25
#include <string.h>
Lionel Ulmer's avatar
Lionel Ulmer committed
26 27

#include "windef.h"
28 29
#include "winbase.h"
#include "winuser.h"
30
#include "winerror.h"
Lionel Ulmer's avatar
Lionel Ulmer committed
31 32

#include "wgl.h"
33
#include "wgl_ext.h"
Lionel Ulmer's avatar
Lionel Ulmer committed
34
#include "opengl_ext.h"
35
#include "wine/library.h"
36
#include "wine/debug.h"
Lionel Ulmer's avatar
Lionel Ulmer committed
37

38
WINE_DEFAULT_DEBUG_CHANNEL(opengl);
Lionel Ulmer's avatar
Lionel Ulmer committed
39

40 41 42 43 44 45 46 47 48
/* x11drv GDI escapes */
#define X11DRV_ESCAPE 6789
enum x11drv_escape_codes
{
    X11DRV_GET_DISPLAY,   /* get X11 display for a DC */
    X11DRV_GET_DRAWABLE,  /* get current drawable for a DC */
    X11DRV_GET_FONT,      /* get current X font for a DC */
};

49 50 51
void (*wine_tsx11_lock_ptr)(void) = NULL;
void (*wine_tsx11_unlock_ptr)(void) = NULL;

52
static GLXContext default_cx = NULL;
53
static Display *default_display;  /* display to use for default context */
54

55 56
static HMODULE opengl32_handle;

57 58
static void *(*p_glXGetProcAddressARB)(const GLubyte *);

59 60
typedef struct wine_glcontext {
  HDC hdc;
61
  Display *display;
62 63 64 65 66
  GLXContext ctx;
  XVisualInfo *vis;
  struct wine_glcontext *next;
  struct wine_glcontext *prev;
} Wine_GLContext;
67
static Wine_GLContext *context_list;
68

69 70 71 72 73
static inline Wine_GLContext *get_context_from_GLXContext(GLXContext ctx)
{
    Wine_GLContext *ret;
    for (ret = context_list; ret; ret = ret->next) if (ctx == ret->ctx) break;
    return ret;
74
}
75 76 77

static inline void free_context(Wine_GLContext *context)
{
78 79
  if (context->next != NULL) context->next->prev = context->prev;
  if (context->prev != NULL) context->prev->next = context->next;
80
  else context_list = context->next;
81 82 83 84

  HeapFree(GetProcessHeap(), 0, context);
}

85 86
static inline Wine_GLContext *alloc_context(void)
{
87 88
  Wine_GLContext *ret;

89 90 91 92 93 94
  if ((ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Wine_GLContext))))
  {
      ret->next = context_list;
      if (context_list) context_list->prev = ret;
      context_list = ret;
  }
95 96 97
  return ret;
}

98 99 100 101 102 103
inline static BOOL is_valid_context( Wine_GLContext *ctx )
{
    Wine_GLContext *ptr;
    for (ptr = context_list; ptr; ptr = ptr->next) if (ptr == ctx) break;
    return (ptr != NULL);
}
104

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
/* retrieve the X display to use on a given DC */
inline static Display *get_display( HDC hdc )
{
    Display *display;
    enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;

    if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
                    sizeof(display), (LPSTR)&display )) display = NULL;
    return display;
}


/* retrieve the X drawable to use on a given DC */
inline static Drawable get_drawable( HDC hdc )
{
    Drawable drawable;
    enum x11drv_escape_codes escape = X11DRV_GET_DRAWABLE;

    if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
                    sizeof(drawable), (LPSTR)&drawable )) drawable = 0;
    return drawable;
126
}
127 128 129 130


/* retrieve the X drawable to use on a given DC */
inline static Font get_font( HDC hdc )
131
{
132 133 134 135 136 137
    Font font;
    enum x11drv_escape_codes escape = X11DRV_GET_FONT;

    if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
                    sizeof(font), (LPSTR)&font )) font = 0;
    return font;
138 139
}

140

141
/***********************************************************************
142
 *		wglCreateContext (OPENGL32.@)
143
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
144 145
HGLRC WINAPI wglCreateContext(HDC hdc)
{
Lionel Ulmer's avatar
Lionel Ulmer committed
146
  XVisualInfo *vis;
147
  Wine_GLContext *ret;
148 149
  int num;
  XVisualInfo template;
150
  Display *display = get_display( hdc );
Lionel Ulmer's avatar
Lionel Ulmer committed
151

152
  TRACE("(%p)\n", hdc);
Lionel Ulmer's avatar
Lionel Ulmer committed
153

154
  /* First, get the visual in use by the X11DRV */
155
  if (!display) return 0;
156
  template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" );
157
  vis = XGetVisualInfo(display, VisualIDMask, &template, &num);
Lionel Ulmer's avatar
Lionel Ulmer committed
158 159 160 161 162 163

  if (vis == NULL) {
    ERR("NULL visual !!!\n");
    /* Need to set errors here */
    return NULL;
  }
164 165

  /* The context will be allocated in the wglMakeCurrent call */
Lionel Ulmer's avatar
Lionel Ulmer committed
166
  ENTER_GL();
167
  ret = alloc_context();
Lionel Ulmer's avatar
Lionel Ulmer committed
168
  LEAVE_GL();
169
  ret->hdc = hdc;
170
  ret->display = display;
171
  ret->vis = vis;
Lionel Ulmer's avatar
Lionel Ulmer committed
172

173
  TRACE(" creating context %p (GL context creation delayed)\n", ret);
Lionel Ulmer's avatar
Lionel Ulmer committed
174 175 176
  return (HGLRC) ret;
}

177
/***********************************************************************
178
 *		wglCreateLayerContext (OPENGL32.@)
179
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
180 181
HGLRC WINAPI wglCreateLayerContext(HDC hdc,
				   int iLayerPlane) {
182 183 184 185 186 187
  TRACE("(%p,%d)\n", hdc, iLayerPlane);

  if (iLayerPlane == 0) {
      return wglCreateContext(hdc);
  }
  FIXME(" no handler for layer %d\n", iLayerPlane);
Lionel Ulmer's avatar
Lionel Ulmer committed
188 189 190 191

  return NULL;
}

192
/***********************************************************************
193
 *		wglCopyContext (OPENGL32.@)
194
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
195 196 197 198 199 200 201 202
BOOL WINAPI wglCopyContext(HGLRC hglrcSrc,
			   HGLRC hglrcDst,
			   UINT mask) {
  FIXME("(%p,%p,%d)\n", hglrcSrc, hglrcDst, mask);

  return FALSE;
}

203
/***********************************************************************
204
 *		wglDeleteContext (OPENGL32.@)
205
 */
206 207
BOOL WINAPI wglDeleteContext(HGLRC hglrc)
{
208
  Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
209 210
  BOOL ret = TRUE;

211
  TRACE("(%p)\n", hglrc);
212

213
  ENTER_GL();
214 215 216 217 218 219
  /* A game (Half Life not to name it) deletes twice the same context,
   * so make sure it is valid first */
  if (is_valid_context( ctx ))
  {
      if (ctx->ctx) glXDestroyContext(ctx->display, ctx->ctx);
      free_context(ctx);
220
  }
221 222
  else
  {
223
    WARN("Error deleting context !\n");
224 225 226
    SetLastError(ERROR_INVALID_HANDLE);
    ret = FALSE;
  }
227
  LEAVE_GL();
228

229
  return ret;
Lionel Ulmer's avatar
Lionel Ulmer committed
230 231
}

232
/***********************************************************************
233
 *		wglDescribeLayerPlane (OPENGL32.@)
234
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
235 236 237 238 239
BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
				  int iPixelFormat,
				  int iLayerPlane,
				  UINT nBytes,
				  LPLAYERPLANEDESCRIPTOR plpd) {
240
  FIXME("(%p,%d,%d,%d,%p)\n", hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
Lionel Ulmer's avatar
Lionel Ulmer committed
241 242 243 244

  return FALSE;
}

245
/***********************************************************************
246
 *		wglGetCurrentContext (OPENGL32.@)
247
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
248
HGLRC WINAPI wglGetCurrentContext(void) {
249 250
  GLXContext gl_ctx;
  Wine_GLContext *ret;
Lionel Ulmer's avatar
Lionel Ulmer committed
251 252 253 254

  TRACE("()\n");

  ENTER_GL();
255 256
  gl_ctx = glXGetCurrentContext();
  ret = get_context_from_GLXContext(gl_ctx);
Lionel Ulmer's avatar
Lionel Ulmer committed
257 258
  LEAVE_GL();

259
  TRACE(" returning %p (GL context %p)\n", ret, gl_ctx);
260

Lionel Ulmer's avatar
Lionel Ulmer committed
261 262 263
  return ret;
}

264
/***********************************************************************
265
 *		wglGetCurrentDC (OPENGL32.@)
266
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
267
HDC WINAPI wglGetCurrentDC(void) {
268 269
  GLXContext gl_ctx;
  Wine_GLContext *ret;
Lionel Ulmer's avatar
Lionel Ulmer committed
270

271
  TRACE("()\n");
272

Lionel Ulmer's avatar
Lionel Ulmer committed
273
  ENTER_GL();
274 275
  gl_ctx = glXGetCurrentContext();
  ret = get_context_from_GLXContext(gl_ctx);
Lionel Ulmer's avatar
Lionel Ulmer committed
276 277
  LEAVE_GL();

278
  if (ret) {
279
    TRACE(" returning %p (GL context %p - Wine context %p)\n", ret->hdc, gl_ctx, ret);
280
    return ret->hdc;
Lionel Ulmer's avatar
Lionel Ulmer committed
281
  } else {
282
    TRACE(" no Wine context found for GLX context %p\n", gl_ctx);
Lionel Ulmer's avatar
Lionel Ulmer committed
283 284 285 286
    return 0;
  }
}

287
/***********************************************************************
288
 *		wglGetLayerPaletteEntries (OPENGL32.@)
289
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
290 291 292 293 294 295 296 297 298 299
int WINAPI wglGetLayerPaletteEntries(HDC hdc,
				     int iLayerPlane,
				     int iStart,
				     int cEntries,
				     const COLORREF *pcr) {
  FIXME("(): stub !\n");

  return 0;
}

300 301 302
/***********************************************************************
 *		wglGetProcAddress (OPENGL32.@)
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
303 304 305 306 307
static int compar(const void *elt_a, const void *elt_b) {
  return strcmp(((OpenGL_extension *) elt_a)->name,
		((OpenGL_extension *) elt_b)->name);
}

308 309 310 311 312
static int wgl_compar(const void *elt_a, const void *elt_b) {
  return strcmp(((WGL_extension *) elt_a)->func_name,
		((WGL_extension *) elt_b)->func_name);
}

Lionel Ulmer's avatar
Lionel Ulmer committed
313 314
void* WINAPI wglGetProcAddress(LPCSTR  lpszProc) {
  void *local_func;
315 316 317
  OpenGL_extension  ext;
  OpenGL_extension *ext_ret;

Lionel Ulmer's avatar
Lionel Ulmer committed
318 319 320
  TRACE("(%s)\n", lpszProc);

  /* First, look if it's not already defined in the 'standard' OpenGL functions */
321
  if ((local_func = GetProcAddress(opengl32_handle, lpszProc)) != NULL) {
322
    TRACE(" found function in 'standard' OpenGL functions (%p)\n", local_func);
Lionel Ulmer's avatar
Lionel Ulmer committed
323 324 325
    return local_func;
  }

326
  if (p_glXGetProcAddressARB == NULL) {
327
    ERR("Warning : dynamic GL extension loading not supported by native GL library.\n");
328 329 330
    return NULL;
  }
  
331 332 333 334 335 336
  /* After that, search in the thunks to find the real name of the extension */
  ext.name = (char *) lpszProc;
  ext_ret = (OpenGL_extension *) bsearch(&ext, extension_registry,
					 extension_registry_size, sizeof(OpenGL_extension), compar);

  if (ext_ret == NULL) {
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
    WGL_extension wgl_ext, *wgl_ext_ret;

    /* Try to find the function in the WGL extensions ... */
    wgl_ext.func_name = (char *) lpszProc;
    wgl_ext_ret = (WGL_extension *) bsearch(&wgl_ext, wgl_extension_registry,
					    wgl_extension_registry_size, sizeof(WGL_extension), wgl_compar);

    if (wgl_ext_ret == NULL) {
      /* Some sanity checks :-) */
      ENTER_GL();
      local_func = p_glXGetProcAddressARB(lpszProc);
      LEAVE_GL();
      if (local_func != NULL) {
	ERR("Extension %s defined in the OpenGL library but NOT in opengl_ext.c... Please report (lionel.ulmer@free.fr) !\n", lpszProc);
	return NULL;
      }
      
      WARN("Did not find extension %s in either Wine or your OpenGL library.\n", lpszProc);
355
      return NULL;
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    } else {
	void *ret = NULL;

	if (wgl_ext_ret->func_init != NULL) {
	    const char *err_msg;
	    if ((err_msg = wgl_ext_ret->func_init(p_glXGetProcAddressARB,
						  wgl_ext_ret->context)) == NULL) {
		ret = wgl_ext_ret->func_address;
	    } else {
		WARN("Error when getting WGL extension '%s' : %s.\n", debugstr_a(lpszProc), err_msg);
		return NULL;
	    }
	} else {
	  ret = wgl_ext_ret->func_address;
	}
Lionel Ulmer's avatar
Lionel Ulmer committed
371

372 373 374 375
	if (ret)
	    TRACE(" returning WGL function  (%p)\n", ret);
	return ret;
    }
Lionel Ulmer's avatar
Lionel Ulmer committed
376
  } else {
377 378 379 380
    ENTER_GL();
    local_func = p_glXGetProcAddressARB(ext_ret->glx_name);
    LEAVE_GL();
    
381
    /* After that, look at the extensions defined in the Linux OpenGL library */
382
    if (local_func == NULL) {
383 384
      char buf[256];
      void *ret = NULL;
385

386
      /* Remove the 3 last letters (EXT, ARB, ...).
387

388 389 390 391 392 393 394 395
	 I know that some extensions have more than 3 letters (MESA, NV,
	 INTEL, ...), but this is only a stop-gap measure to fix buggy
	 OpenGL drivers (moreover, it is only useful for old 1.0 apps
	 that query the glBindTextureEXT extension).
      */
      strncpy(buf, ext_ret->glx_name, strlen(ext_ret->glx_name) - 3);
      buf[strlen(ext_ret->glx_name) - 3] = '\0';
      TRACE(" extension not found in the Linux OpenGL library, checking against libGL bug with %s..\n", buf);
396

397
      ret = GetProcAddress(opengl32_handle, buf);
398 399 400 401
      if (ret != NULL) {
	TRACE(" found function in main OpenGL library (%p) !\n", ret);
      } else {
	WARN("Did not find function %s (%s) in your OpenGL library !\n", lpszProc, ext_ret->glx_name);
402 403
      }

404
      return ret;
Lionel Ulmer's avatar
Lionel Ulmer committed
405
    } else {
406 407
      TRACE(" returning function  (%p)\n", ext_ret->func);
      *(ext_ret->func_ptr) = local_func;
408

409
      return ext_ret->func;
Lionel Ulmer's avatar
Lionel Ulmer committed
410 411 412 413
    }
  }
}

414
/***********************************************************************
415
 *		wglMakeCurrent (OPENGL32.@)
416
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
417 418 419 420
BOOL WINAPI wglMakeCurrent(HDC hdc,
			   HGLRC hglrc) {
  BOOL ret;

421
  TRACE("(%p,%p)\n", hdc, hglrc);
422

423
  ENTER_GL();
424
  if (hglrc == NULL) {
425
      ret = glXMakeCurrent(default_display, None, NULL);
426
  } else {
427
      Wine_GLContext *ctx = (Wine_GLContext *) hglrc;
428
      Drawable drawable = get_drawable( hdc );
429 430

      if (ctx->ctx == NULL) {
431
	ctx->ctx = glXCreateContext(ctx->display, ctx->vis, NULL, True);
432 433
	TRACE(" created a delayed OpenGL context (%p)\n", ctx->ctx);
      }
434
      ret = glXMakeCurrent(ctx->display, drawable, ctx->ctx);
435
  }
436
  LEAVE_GL();
437
  TRACE(" returning %s\n", (ret ? "True" : "False"));
Lionel Ulmer's avatar
Lionel Ulmer committed
438 439 440
  return ret;
}

441
/***********************************************************************
442
 *		wglRealizeLayerPalette (OPENGL32.@)
443
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
444 445 446 447 448 449 450 451
BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
				   int iLayerPlane,
				   BOOL bRealize) {
  FIXME("()\n");

  return FALSE;
}

452
/***********************************************************************
453
 *		wglSetLayerPaletteEntries (OPENGL32.@)
454
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
455 456 457 458 459 460 461 462 463 464
int WINAPI wglSetLayerPaletteEntries(HDC hdc,
				     int iLayerPlane,
				     int iStart,
				     int cEntries,
				     const COLORREF *pcr) {
  FIXME("(): stub !\n");

  return 0;
}

465
/***********************************************************************
466
 *		wglShareLists (OPENGL32.@)
467
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
468 469
BOOL WINAPI wglShareLists(HGLRC hglrc1,
			  HGLRC hglrc2) {
470 471
  Wine_GLContext *org  = (Wine_GLContext *) hglrc1;
  Wine_GLContext *dest = (Wine_GLContext *) hglrc2;
472

473
  TRACE("(%p, %p)\n", org, dest);
Lionel Ulmer's avatar
Lionel Ulmer committed
474

475 476 477 478 479 480
  if (dest->ctx != NULL) {
    ERR("Could not share display lists, context already created !\n");
    return FALSE;
  } else {
    if (org->ctx == NULL) {
      ENTER_GL();
481
      org->ctx = glXCreateContext(org->display, org->vis, NULL, True);
482 483 484 485 486 487
      LEAVE_GL();
      TRACE(" created a delayed OpenGL context (%p) for Wine context %p\n", org->ctx, org);
    }

    ENTER_GL();
    /* Create the destination context with display lists shared */
488
    dest->ctx = glXCreateContext(org->display, dest->vis, org->ctx, True);
489 490 491
    LEAVE_GL();
    TRACE(" created a delayed OpenGL context (%p) for Wine context %p sharing lists with OpenGL ctx %p\n", dest->ctx, dest, org->ctx);
  }
492

493
  return TRUE;
Lionel Ulmer's avatar
Lionel Ulmer committed
494 495
}

496
/***********************************************************************
497
 *		wglSwapLayerBuffers (OPENGL32.@)
498
 */
Lionel Ulmer's avatar
Lionel Ulmer committed
499 500
BOOL WINAPI wglSwapLayerBuffers(HDC hdc,
				UINT fuPlanes) {
501
  TRACE("(%p, %08x)\n", hdc, fuPlanes);
Lionel Ulmer's avatar
Lionel Ulmer committed
502

503 504 505 506 507 508 509 510
  if (fuPlanes & WGL_SWAP_MAIN_PLANE) {
    if (!SwapBuffers(hdc)) return FALSE;
    fuPlanes &= ~WGL_SWAP_MAIN_PLANE;
  }

  if (fuPlanes) {
    WARN("Following layers unhandled : %08x\n", fuPlanes);
  }
511

512
  return TRUE;
Lionel Ulmer's avatar
Lionel Ulmer committed
513 514
}

515 516 517 518 519
static BOOL internal_wglUseFontBitmaps(HDC hdc,
				       DWORD first,
				       DWORD count,
				       DWORD listBase,
				       DWORD WINAPI (*GetGlyphOutline_ptr)(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,LPVOID,const MAT2*))
520
{
521 522 523 524 525 526 527 528 529 530 531 532 533
    /* We are running using client-side rendering fonts... */
    GLYPHMETRICS gm;
    int glyph;
    int size = 0;
    void *bitmap = NULL, *gl_bitmap = NULL;
    int org_alignment;

    ENTER_GL();
    glGetIntegerv(GL_UNPACK_ALIGNMENT, &org_alignment);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    LEAVE_GL();

    for (glyph = first; glyph < first + count; glyph++) {
534
	int needed_size = GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, 0, NULL, NULL);
535
	int height, width_int;
536

Lionel Ulmer's avatar
Lionel Ulmer committed
537
	TRACE("Glyph : %3d / List : %ld\n", glyph, listBase);
538 539 540 541 542 543 544
	if (needed_size == GDI_ERROR) {
	    TRACE("  - needed size : %d (GDI_ERROR)\n", needed_size);
	    goto error;
	} else {
	    TRACE("  - needed size : %d\n", needed_size);
	}

545 546 547 548 549 550 551
	if (needed_size > size) {
	    size = needed_size;
	    if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
	    if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
	    bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
	    gl_bitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
	}
552
	if (GetGlyphOutline_ptr(hdc, glyph, GGO_BITMAP, &gm, size, bitmap, NULL) == GDI_ERROR) goto error;
553 554 555 556
	if (TRACE_ON(opengl)) {
	    unsigned int height, width, bitmask;
	    unsigned char *bitmap_ = (unsigned char *) bitmap;
	    
Lionel Ulmer's avatar
Lionel Ulmer committed
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
	    TRACE("  - bbox : %d x %d\n", gm.gmBlackBoxX, gm.gmBlackBoxY);
	    TRACE("  - origin : (%ld , %ld)\n", gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
	    TRACE("  - increment : %d - %d\n", gm.gmCellIncX, gm.gmCellIncY);
	    if (needed_size != 0) {
		TRACE("  - bitmap : \n");
		for (height = 0; height < gm.gmBlackBoxY; height++) {
		    TRACE("      ");
		    for (width = 0, bitmask = 0x80; width < gm.gmBlackBoxX; width++, bitmask >>= 1) {
			if (bitmask == 0) {
			    bitmap_ += 1;
			    bitmask = 0x80;
			}
			if (*bitmap_ & bitmask)
			    DPRINTF("*");
			else
			    DPRINTF(" ");
573
		    }
Lionel Ulmer's avatar
Lionel Ulmer committed
574 575
		    bitmap_ += (4 - (((unsigned int) bitmap_) & 0x03));
		    DPRINTF("\n");
576
		}
577 578
	    }
	}
579
	
Lionel Ulmer's avatar
Lionel Ulmer committed
580 581 582 583 584 585 586 587 588 589 590
	/* In OpenGL, the bitmap is drawn from the bottom to the top... So we need to invert the
	 * glyph for it to be drawn properly.
	 */
	if (needed_size != 0) {
	    width_int = (gm.gmBlackBoxX + 31) / 32;
	    for (height = 0; height < gm.gmBlackBoxY; height++) {
		int width;
		for (width = 0; width < width_int; width++) {
		    ((int *) gl_bitmap)[(gm.gmBlackBoxY - height - 1) * width_int + width] =
			((int *) bitmap)[height * width_int + width];
		}
591
	    }
592
	}
593 594 595
	
	ENTER_GL();
	glNewList(listBase++, GL_COMPILE);
Lionel Ulmer's avatar
Lionel Ulmer committed
596 597
	if (needed_size != 0) {
	    glBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY,
598
		     0 - (int) gm.gmptGlyphOrigin.x, (int) gm.gmBlackBoxY - (int) gm.gmptGlyphOrigin.y,
Lionel Ulmer's avatar
Lionel Ulmer committed
599 600 601 602 603 604
		     gm.gmCellIncX, gm.gmCellIncY,
		     gl_bitmap);
	} else {
	    /* This is the case of 'empty' glyphs like the space character */
	    glBitmap(0, 0, 0, 0, gm.gmCellIncX, gm.gmCellIncY, NULL);
	}
605 606
	glEndList();
	LEAVE_GL();
607
    }
608
    
609 610 611
    ENTER_GL();
    glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
    LEAVE_GL();
612
    
613 614 615 616 617 618 619 620 621 622 623
    if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
    if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
    return TRUE;

  error:
    ENTER_GL();
    glPixelStorei(GL_UNPACK_ALIGNMENT, org_alignment);
    LEAVE_GL();

    if (bitmap) HeapFree(GetProcessHeap(), 0, bitmap);
    if (gl_bitmap) HeapFree(GetProcessHeap(), 0, gl_bitmap);
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
    return FALSE;    
}

/***********************************************************************
 *		wglUseFontBitmapsA (OPENGL32.@)
 */
BOOL WINAPI wglUseFontBitmapsA(HDC hdc,
			       DWORD first,
			       DWORD count,
			       DWORD listBase)
{
  Font fid = get_font( hdc );

  TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);

  if (fid == 0) {
      return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineA);
  }

  ENTER_GL();
  /* I assume that the glyphs are at the same position for X and for Windows */
  glXUseXFont(fid, first, count, listBase);
  LEAVE_GL();
  return TRUE;
}

/***********************************************************************
 *		wglUseFontBitmapsW (OPENGL32.@)
 */
BOOL WINAPI wglUseFontBitmapsW(HDC hdc,
			       DWORD first,
			       DWORD count,
			       DWORD listBase)
{
  Font fid = get_font( hdc );

  TRACE("(%p, %ld, %ld, %ld) using font %ld\n", hdc, first, count, listBase, fid);

  if (fid == 0) {
      return internal_wglUseFontBitmaps(hdc, first, count, listBase, GetGlyphOutlineW);
664
  }
665

666 667
  WARN("Using the glX API for the WCHAR variant - some characters may come out incorrectly !\n");
  
668 669 670 671 672
  ENTER_GL();
  /* I assume that the glyphs are at the same position for X and for Windows */
  glXUseXFont(fid, first, count, listBase);
  LEAVE_GL();
  return TRUE;
Lionel Ulmer's avatar
Lionel Ulmer committed
673
}
674

675
/***********************************************************************
676
 *		wglUseFontOutlinesA (OPENGL32.@)
677
 */
678 679 680 681 682 683 684 685
BOOL WINAPI wglUseFontOutlinesA(HDC hdc,
				DWORD first,
				DWORD count,
				DWORD listBase,
				FLOAT deviation,
				FLOAT extrusion,
				int format,
				LPGLYPHMETRICSFLOAT lpgmf) {
Lionel Ulmer's avatar
Lionel Ulmer committed
686 687 688 689 690
  FIXME("(): stub !\n");

  return FALSE;
}

691 692 693 694 695 696
/* No need to load any other libraries as according to the ABI, libGL should be self-sufficient and
   include all dependencies
*/
#ifndef SONAME_LIBGL
#define SONAME_LIBGL "libGL.so"
#endif
697

Lionel Ulmer's avatar
Lionel Ulmer committed
698 699
/* This is for brain-dead applications that use OpenGL functions before even
   creating a rendering context.... */
700 701
static BOOL process_attach(void)
{
702 703
  XWindowAttributes win_attr;
  Visual *rootVisual;
Lionel Ulmer's avatar
Lionel Ulmer committed
704 705
  int num;
  XVisualInfo template;
706
  HDC hdc;
707
  XVisualInfo *vis = NULL;
708
  Window root = (Window)GetPropA( GetDesktopWindow(), "__wine_x11_whole_window" );
709
  HMODULE mod = GetModuleHandleA( "x11drv.dll" );
710
  void *opengl_handle;
711

712
  if (!root || !mod)
713 714
  {
      ERR("X11DRV not loaded. Cannot create default context.\n");
715 716 717
      return FALSE;
  }

718 719 720
  wine_tsx11_lock_ptr   = (void *)GetProcAddress( mod, "wine_tsx11_lock" );
  wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" );

721 722 723 724 725 726 727
  hdc = GetDC(0);
  default_display = get_display( hdc );
  ReleaseDC( 0, hdc );
  if (!default_display)
  {
      ERR("X11DRV not loaded. Cannot get display for screen DC.\n");
      return FALSE;
728
  }
729

Lionel Ulmer's avatar
Lionel Ulmer committed
730
  ENTER_GL();
731 732 733

  /* Try to get the visual from the Root Window.  We can't use the standard (presumably
     double buffered) X11DRV visual with the Root Window, since we don't know if the Root
734 735
     Window was created using the standard X11DRV visual, and glXMakeCurrent can't deal
     with mismatched visuals.  Note that the Root Window visual may not be double
736
     buffered, so apps actually attempting to render this way may flicker */
737
  if (XGetWindowAttributes( default_display, root, &win_attr ))
738
  {
739
    rootVisual = win_attr.visual;
740 741 742
  }
  else
  {
743
    /* Get the default visual, since we can't seem to get the attributes from the
744
       Root Window.  Let's hope that the Root Window Visual matches the DefaultVisual */
745
    rootVisual = DefaultVisual( default_display, DefaultScreen(default_display) );
746 747 748
  }

  template.visualid = XVisualIDFromVisual(rootVisual);
749 750 751
  vis = XGetVisualInfo(default_display, VisualIDMask, &template, &num);
  if (vis != NULL) default_cx = glXCreateContext(default_display, vis, 0, GL_TRUE);
  if (default_cx != NULL) glXMakeCurrent(default_display, root, default_cx);
752
  XFree(vis);
Lionel Ulmer's avatar
Lionel Ulmer committed
753
  LEAVE_GL();
754

755 756 757 758 759 760
  opengl_handle = wine_dlopen(SONAME_LIBGL, RTLD_NOW|RTLD_GLOBAL, NULL, 0);
  if (opengl_handle != NULL) {
   p_glXGetProcAddressARB = wine_dlsym(opengl_handle, "glXGetProcAddressARB", NULL, 0);
   wine_dlclose(opengl_handle, NULL, 0);
   if (p_glXGetProcAddressARB == NULL)
	   TRACE("could not find glXGetProcAddressARB in libGL.\n");
761
  }
762 763 764

  /* Initialize also the list of supported WGL extensions. */
  wgl_ext_initialize_extensions(default_display, DefaultScreen(default_display));
765
  
766 767 768
  if (default_cx == NULL) {
    ERR("Could not create default context.\n");
  }
769
  return TRUE;
Lionel Ulmer's avatar
Lionel Ulmer committed
770
}
771

772

773 774
/**********************************************************************/

775 776 777
static void process_detach(void)
{
  glXDestroyContext(default_display, default_cx);
778

779 780
  /* Do not leak memory... */
  wgl_ext_finalize_extensions();
781 782
}

783 784 785
/***********************************************************************
 *           OpenGL initialisation routine
 */
786
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
787
{
788 789 790
    switch(reason)
    {
    case DLL_PROCESS_ATTACH:
791
        opengl32_handle = hinst;
792
        DisableThreadLibraryCalls(hinst);
793 794 795 796 797 798
        return process_attach();
    case DLL_PROCESS_DETACH:
        process_detach();
        break;
    }
    return TRUE;
799
}