AllegroGL 0.4.4
|
00001 /* This code is (C) AllegroGL contributors, and double licensed under 00002 * the GPL and zlib licenses. See gpl.txt or zlib.txt for details. 00003 */ 00004 /*---------------------------------------------------------------- 00005 * x.c -- Allegro-GLX interfacing 00006 *---------------------------------------------------------------- 00007 * This is the interface module for use under X. 00008 */ 00009 #include <string.h> 00010 #include <stdio.h> 00011 00012 #include <allegro.h> 00013 #include <xalleg.h> 00014 00015 #include <allegro/platform/aintunix.h> 00016 00017 #include "alleggl.h" 00018 #include "allglint.h" 00019 #include "glvtable.h" 00020 00021 00022 #ifndef XLOCK 00023 #define OLD_ALLEGRO 00024 #define XLOCK() DISABLE() 00025 #undef XUNLOCK 00026 #define XUNLOCK() ENABLE() 00027 #endif 00028 00029 #define PREFIX_I "agl-x INFO: " 00030 #define PREFIX_E "agl-x ERROR: " 00031 00032 00033 #ifdef ALLEGRO_XWINDOWS_WITH_XPM 00034 #include <X11/xpm.h> 00035 extern void *allegro_icon; 00036 #endif 00037 00038 00039 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh, 00040 int color_depth); 00041 static void allegro_gl_x_exit(BITMAP *bmp); 00042 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 00043 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void); 00044 #endif 00045 static void allegro_gl_x_vsync(void); 00046 static void allegro_gl_x_hide_mouse(void); 00047 00048 static BITMAP *allegro_gl_screen = NULL; 00049 00050 /* TODO: Revamp the whole window handling under X11 in Allegro and 00051 * AllegroGL. We really shouldn't have to duplicate code or hack on 00052 * Allegro internals in AllegroGL - the *only* difference for the AllegroGL 00053 * window should be the GLX visual (e.g. cursor, icon, VidModeExtension and 00054 * so on should never have been touched in this file). 00055 */ 00056 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 00057 static Window backup_allegro_window = None; 00058 static Colormap backup_allegro_colormap = None; 00059 #endif 00060 00061 00062 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh, 00063 int color_depth); 00064 00065 GFX_DRIVER gfx_allegro_gl_fullscreen = 00066 { 00067 GFX_OPENGL_FULLSCREEN, 00068 empty_string, 00069 empty_string, 00070 "AllegroGL Fullscreen (X)", 00071 allegro_gl_x_fullscreen_init, 00072 allegro_gl_x_exit, 00073 NULL, 00074 allegro_gl_x_vsync, 00075 NULL, 00076 NULL, NULL, NULL, 00077 allegro_gl_create_video_bitmap, 00078 allegro_gl_destroy_video_bitmap, 00079 NULL, NULL, /* No show/request video bitmaps */ 00080 NULL, NULL, 00081 allegro_gl_set_mouse_sprite, 00082 allegro_gl_show_mouse, 00083 allegro_gl_x_hide_mouse, 00084 allegro_gl_move_mouse, 00085 allegro_gl_drawing_mode, 00086 NULL, NULL, 00087 allegro_gl_set_blender_mode, 00088 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 00089 allegro_gl_x_fetch_mode_list, 00090 #else 00091 NULL, 00092 #endif 00093 0, 0, 00094 0, 00095 0, 0, 00096 0, 00097 0, 00098 FALSE /* Windowed mode */ 00099 }; 00100 00101 00102 00103 GFX_DRIVER gfx_allegro_gl_windowed = 00104 { 00105 GFX_OPENGL_WINDOWED, 00106 empty_string, 00107 empty_string, 00108 "AllegroGL Windowed (X)", 00109 allegro_gl_x_windowed_init, 00110 allegro_gl_x_exit, 00111 NULL, 00112 allegro_gl_x_vsync, 00113 NULL, 00114 NULL, NULL, NULL, 00115 allegro_gl_create_video_bitmap, 00116 allegro_gl_destroy_video_bitmap, 00117 NULL, NULL, /* No show/request video bitmaps */ 00118 NULL, NULL, 00119 allegro_gl_set_mouse_sprite, 00120 allegro_gl_show_mouse, 00121 allegro_gl_x_hide_mouse, 00122 allegro_gl_move_mouse, 00123 allegro_gl_drawing_mode, 00124 NULL, NULL, 00125 allegro_gl_set_blender_mode, 00126 NULL, /* No fetch_mode_list */ 00127 0, 0, 00128 0, 00129 0, 0, 00130 0, 00131 0, 00132 TRUE /* Windowed mode */ 00133 }; 00134 00135 00136 00137 static struct allegro_gl_driver allegro_gl_x; 00138 00139 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void); 00140 static int allegro_gl_x_create_window (int fullscreen); 00141 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth); 00142 00143 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i); 00144 struct { 00145 int fullscreen; 00146 GLXContext ctx; 00147 int major, minor; /* Major and minor GLX version */ 00148 int error_base, event_base; 00149 int use_glx_window; 00150 GLXWindow window; 00151 } _glxwin; 00152 00153 static void (*old_window_redrawer)(int, int, int, int); 00154 extern void (*_xwin_window_redrawer)(int, int, int, int); 00155 static int (*old_x_error_handler)(Display*, XErrorEvent*); 00156 00157 00158 00159 /* allegro_gl_redraw_window : 00160 * Redraws the window when an Expose event is processed 00161 * Important note : no GL commands should be processed in this function 00162 * since it may be called by a thread which is different from the main thread. 00163 * In order to be able to process GL commands, we should create another context 00164 * and make it current to the other thread. IMHO it would be overkill. 00165 */ 00166 static void allegro_gl_redraw_window(int x, int y, int w, int h) 00167 { 00168 /* Does nothing */ 00169 return; 00170 } 00171 00172 00173 00174 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR 00175 /* _xwin_hide_x_mouse: 00176 * Create invisible X cursor 00177 */ 00178 static void _xwin_hide_x_mouse(void) 00179 { 00180 unsigned long gcmask; 00181 XGCValues gcvalues; 00182 Pixmap pixmap; 00183 00184 XUndefineCursor(_xwin.display, _xwin.window); 00185 00186 if (_xwin.cursor != None) { 00187 XFreeCursor(_xwin.display, _xwin.cursor); 00188 _xwin.cursor = None; 00189 } 00190 00191 if (_xwin.xcursor_image != None) { 00192 XcursorImageDestroy(_xwin.xcursor_image); 00193 _xwin.xcursor_image = None; 00194 } 00195 00196 pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1); 00197 if (pixmap != None) { 00198 GC temp_gc; 00199 XColor color; 00200 00201 gcmask = GCFunction | GCForeground | GCBackground; 00202 gcvalues.function = GXcopy; 00203 gcvalues.foreground = 0; 00204 gcvalues.background = 0; 00205 temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues); 00206 XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0); 00207 XFreeGC(_xwin.display, temp_gc); 00208 color.pixel = 0; 00209 color.red = color.green = color.blue = 0; 00210 color.flags = DoRed | DoGreen | DoBlue; 00211 _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0); 00212 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor); 00213 XFreePixmap(_xwin.display, pixmap); 00214 } 00215 else { 00216 _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape); 00217 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor); 00218 } 00219 } 00220 #endif 00221 00222 00223 00224 /* hide_mouse: 00225 * Hide the custom X cursor (if supported) 00226 */ 00227 static void hide_mouse(void) 00228 { 00229 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR 00230 if (_xwin.support_argb_cursor) { 00231 XLOCK(); 00232 _xwin_hide_x_mouse(); 00233 XUNLOCK(); 00234 } 00235 #endif 00236 return; 00237 } 00238 00239 00240 00241 /* If Allegro's X11 mouse driver enabled hw cursors, we shouldn't use 00242 * allegro_gl_hide_mouse(); 00243 */ 00244 static void allegro_gl_x_hide_mouse(void) 00245 { 00246 if (_xwin.hw_cursor_ok) { 00247 hide_mouse(); 00248 } 00249 else { 00250 allegro_gl_hide_mouse(); 00251 } 00252 } 00253 00254 00255 00256 /* allegro_gl_x_windowed_init: 00257 * Creates screen bitmap. 00258 */ 00259 static BITMAP *allegro_gl_x_create_screen(int w, int h, int vw, int vh, 00260 int depth, int fullscreen) 00261 { 00262 int _keyboard_was_installed = FALSE; 00263 int _mouse_was_installed = FALSE; 00264 int create_window_ret; 00265 00266 /* test if Allegro have pthread support enabled */ 00267 if (!_unix_bg_man->multi_threaded) { 00268 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 00269 get_config_text("Fatal Error : pthread support is not enabled")); 00270 return NULL; 00271 } 00272 00273 if (keyboard_driver) { 00274 _keyboard_was_installed = TRUE; 00275 remove_keyboard(); 00276 TRACE(PREFIX_I "x_create_screen: Removing Keyboard...\n"); 00277 } 00278 00279 if (mouse_driver) { 00280 _mouse_was_installed = TRUE; 00281 remove_mouse(); 00282 TRACE(PREFIX_I "x_create_screen: Removing Mouse...\n"); 00283 } 00284 00285 XLOCK(); 00286 00287 if (!glXQueryExtension(_xwin.display, &_glxwin.error_base, 00288 &_glxwin.event_base)) { 00289 00290 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00291 get_config_text("GLX Extension not supported by display")); 00292 XUNLOCK(); 00293 goto failure; 00294 } 00295 00296 sscanf(glXQueryServerString(_xwin.display, _xwin.screen, GLX_VERSION), 00297 "%i.%i", &_glxwin.major, &_glxwin.minor); 00298 00299 if ((w == 0) && (h == 0)) { 00300 w = 640; 00301 h = 480; 00302 } 00303 00304 if ((vw > w) || (vh > h)) { 00305 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00306 get_config_text ("OpenGL drivers do not support virtual screens")); 00307 XUNLOCK(); 00308 goto failure; 00309 } 00310 00311 allegro_gl_display_info.w = w; 00312 allegro_gl_display_info.h = h; 00313 00314 old_window_redrawer = _xwin_window_redrawer; 00315 _xwin_window_redrawer = allegro_gl_redraw_window; 00316 _glxwin.fullscreen = FALSE; 00317 _glxwin.use_glx_window = FALSE; 00318 00319 create_window_ret = allegro_gl_x_create_window(fullscreen); 00320 if (create_window_ret) { 00321 if (fullscreen && create_window_ret == -2) { 00322 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00323 get_config_text ("Unable to switch in GLX fullscreen")); 00324 } 00325 else if (create_window_ret == -2) { 00326 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00327 get_config_text ("Unable to create GLX window")); 00328 } 00329 XUNLOCK(); 00330 allegro_gl_x_exit(NULL); 00331 goto failure; 00332 } 00333 00334 /* If pixel format is Allegro compatible, set up Allegro correctly. */ 00335 set_color_depth(allegro_gl_display_info.colour_depth); 00336 00337 /* XXX <rohannessian> X can run on Big-Endian systems. We need to 00338 * make a check for that and pass TRUE to 00339 * __allegro_gl_set_allegro_image_format() in that case. 00340 */ 00341 __allegro_gl_set_allegro_image_format(FALSE); 00342 00343 if (fullscreen) { 00344 allegro_gl_screen = 00345 allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_fullscreen, 00346 allegro_gl_display_info.w, allegro_gl_display_info.h, 00347 _color_depth); 00348 } 00349 else { 00350 allegro_gl_screen = 00351 allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_windowed, 00352 allegro_gl_display_info.w, allegro_gl_display_info.h, 00353 _color_depth); 00354 } 00355 00356 if (!allegro_gl_screen) { 00357 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00358 get_config_text ("Error creating screen bitmap")); 00359 XUNLOCK(); 00360 allegro_gl_x_exit(NULL); 00361 goto failure; 00362 } 00363 00364 __allegro_gl_valid_context = TRUE; 00365 __allegro_gl_driver = &allegro_gl_x; 00366 00367 /* Print out OpenGL version info */ 00368 TRACE(PREFIX_I "OpenGL Version: %s\n", (AL_CONST char*)glGetString(GL_VERSION)); 00369 TRACE(PREFIX_I "OpenGL Vendor: %s\n", (AL_CONST char*)glGetString(GL_VENDOR)); 00370 TRACE(PREFIX_I "OpenGL Renderer: %s\n", (AL_CONST char*)glGetString(GL_RENDERER)); 00371 00372 /* Detect if the GL driver is based on Mesa */ 00373 allegro_gl_info.is_mesa_driver = FALSE; 00374 if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) { 00375 AGL_LOG(1, "OpenGL driver based on Mesa\n"); 00376 allegro_gl_info.is_mesa_driver = TRUE; 00377 } 00378 00379 /* Print out GLX version info */ 00380 TRACE(PREFIX_I "GLX Version: %d.%d\n", _glxwin.major, _glxwin.minor); 00381 00382 #ifdef LOGLEVEL 00383 if (glXIsDirect(_xwin.display, _glxwin.ctx)) { 00384 AGL_LOG(1, "GLX Direct Rendering is enabled\n"); 00385 } 00386 else { 00387 AGL_LOG(1, "GLX Direct Rendering is disabled\n"); 00388 } 00389 #endif 00390 00391 /* Prints out GLX extensions info */ 00392 AGL_LOG(1, "glX Extensions:\n"); 00393 #ifdef LOGLEVEL 00394 __allegro_gl_print_extensions( 00395 (AL_CONST char*)glXQueryExtensionsString(_xwin.display, _xwin.screen)); 00396 #endif 00397 /* Prints out OpenGL extensions info and activates needed extensions */ 00398 __allegro_gl_manage_extensions(); 00399 00400 /* Update screen vtable in order to use AGL's */ 00401 __allegro_gl__glvtable_update_vtable (&allegro_gl_screen->vtable); 00402 memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE)); 00403 allegro_gl_screen->vtable = &_screen_vtable; 00404 00405 XUNLOCK(); 00406 00407 if (_keyboard_was_installed) { 00408 TRACE(PREFIX_I "x_create_screen: Installing Keyboard...\n"); 00409 install_keyboard(); 00410 } 00411 00412 if (_mouse_was_installed) { 00413 TRACE(PREFIX_I "x_create_screen: Installing Mouse...\n"); 00414 install_mouse(); 00415 } 00416 gfx_capabilities |= GFX_HW_CURSOR; 00417 00418 return allegro_gl_screen; 00419 00420 failure: 00421 if (_keyboard_was_installed) { 00422 install_keyboard(); 00423 } 00424 00425 if (_mouse_was_installed) { 00426 install_mouse(); 00427 } 00428 00429 return NULL; 00430 } 00431 00432 00433 00434 /* allegro_gl_x_windowed_init: 00435 * Creates screen bitmap for windowed driver. 00436 */ 00437 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh, 00438 int depth) 00439 { 00440 return allegro_gl_x_create_screen(w, h, vw, vh, depth, FALSE); 00441 } 00442 00443 00444 00445 /* allegro_gl_x_fullscreen_init: 00446 * Creates screen bitmap for fullscreen driver. 00447 */ 00448 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh, 00449 int depth) 00450 { 00451 return allegro_gl_x_create_screen(w, h, vw, vh, depth, TRUE); 00452 } 00453 00454 00455 00456 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 00457 /* free_modelines: 00458 * Free mode lines. 00459 */ 00460 static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes) 00461 { 00462 int i; 00463 00464 for (i = 0; i < num_modes; i++) 00465 if (modesinfo[i]->privsize > 0) 00466 XFree(modesinfo[i]->private); 00467 XFree(modesinfo); 00468 } 00469 #endif 00470 00471 00472 00473 /* allegro_gl_x_exit: 00474 * Shuts down the driver (shared between windowed and full-screen) 00475 */ 00476 static void allegro_gl_x_exit(BITMAP *bmp) 00477 { 00478 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 00479 XSetWindowAttributes setattr; 00480 #endif 00481 00482 XLOCK(); 00483 /* We politely wait for OpenGL to finish its current operations before 00484 shutting down the driver */ 00485 glXWaitGL(); 00486 00487 __allegro_gl_unmanage_extensions(); 00488 00489 if (_glxwin.ctx) { 00490 if (!allegro_gl_info.is_ati_r200_chip) { 00491 /* The DRI drivers for ATI cards with R200 chip 00492 * seem to be broken since they crash at this point. 00493 * As a workaround AGL does not release the GLX context 00494 * here. This should not hurt since the GLX specs don't 00495 * require the context to be released before the program 00496 * ends or before another context is made current to the 00497 * thread. 00498 */ 00499 if (!glXMakeCurrent(_xwin.display, None, NULL)) { 00500 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, 00501 get_config_text ("Could not release drawing context.\n")); 00502 } 00503 } 00504 00505 glXDestroyContext(_xwin.display, _glxwin.ctx); 00506 _glxwin.ctx = NULL; 00507 } 00508 00509 if (_xwin.mouse_grabbed) { 00510 XUngrabPointer(_xwin.display, CurrentTime); 00511 _xwin.mouse_grabbed = 0; 00512 } 00513 00514 if (_xwin.keyboard_grabbed) { 00515 XUngrabKeyboard(_xwin.display, CurrentTime); 00516 _xwin.keyboard_grabbed = 0; 00517 } 00518 00519 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 00520 if (_glxwin.fullscreen) { 00521 if (_xwin.mode_switched) { 00522 XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False); 00523 XF86VidModeSwitchToMode(_xwin.display, _xwin.screen, 00524 _xwin.modesinfo[0]); 00525 XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0); 00526 _xwin.mode_switched = 0; 00527 } 00528 if (_xwin.override_redirected) { 00529 setattr.override_redirect = False; 00530 XChangeWindowAttributes(_xwin.display, _xwin.window, 00531 CWOverrideRedirect, &setattr); 00532 _xwin.override_redirected = 0; 00533 } 00534 00535 /* Free modelines. */ 00536 free_modelines(_xwin.modesinfo, _xwin.num_modes); 00537 _xwin.num_modes = 0; 00538 _xwin.modesinfo = NULL; 00539 } 00540 #endif 00541 00542 /* Note: Allegro will destroy screen (== allegro_gl_screen), 00543 * so don't destroy it here. 00544 */ 00545 //destroy_bitmap(allegro_gl_screen); 00546 ASSERT(allegro_gl_screen == screen); 00547 allegro_gl_screen = NULL; 00548 00549 /* Unmap the window in order not to see the cursor when quitting. 00550 The window *must not* be destroyed and _xwin.visual must be left 00551 to its current value otherwise the program will crash when exiting */ 00552 if (_xwin.window != None) 00553 XUnmapWindow(_xwin.display, _xwin.window); 00554 00555 if (_glxwin.use_glx_window) { 00556 glXDestroyWindow(_xwin.display, _glxwin.window); 00557 _glxwin.window = 0; 00558 _glxwin.use_glx_window = FALSE; 00559 } 00560 00561 __allegro_gl_valid_context = FALSE; 00562 00563 _xwin_window_redrawer = old_window_redrawer; 00564 XSetErrorHandler(old_x_error_handler); 00565 00566 00567 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 00568 /* Hack: Allegro 4.2.1 uses a persistent window, we need to restore it. */ 00569 if (backup_allegro_window != None) { 00570 if (_xwin.colormap != None) { 00571 XUninstallColormap(_xwin.display, _xwin.colormap); 00572 XFreeColormap(_xwin.display, _xwin.colormap); 00573 } 00574 _xwin.colormap = backup_allegro_colormap; 00575 00576 if (_xwin.window != None) 00577 XDestroyWindow(_xwin.display, _xwin.window); 00578 _xwin.window = backup_allegro_window; 00579 backup_allegro_window = None; 00580 XMapWindow(_xwin.display, _xwin.window); 00581 } 00582 #endif 00583 00584 XUNLOCK(); 00585 } 00586 00587 00588 00589 /* get_shift: 00590 * Returns the shift value for a given mask. 00591 */ 00592 static int get_shift (int mask) 00593 { 00594 int i = 0, j = 1; 00595 if (!mask) return -1; 00596 while (!(j & mask)) { 00597 i++; 00598 j <<= 1; 00599 } 00600 return i; 00601 } 00602 00603 00604 00605 static int decode_fbconfig (GLXFBConfig fbc, struct allegro_gl_display_info *i) { 00606 int render_type, visual_type, buffer_size, sbuffers, samples; 00607 int drawable_type, renderable; 00608 XVisualInfo *v; 00609 00610 TRACE(PREFIX_I "decode_fbconfig: Decoding:\n"); 00611 i->rmethod = 2; 00612 00613 if (glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RENDER_TYPE, 00614 &render_type) 00615 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_RENDERABLE, 00616 &renderable) 00617 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DRAWABLE_TYPE, 00618 &drawable_type) 00619 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_VISUAL_TYPE, 00620 &visual_type) 00621 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BUFFER_SIZE, 00622 &buffer_size) 00623 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DEPTH_SIZE, 00624 &i->depth_size) 00625 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STEREO, 00626 &i->stereo) 00627 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RED_SIZE, 00628 &i->pixel_size.rgba.r) 00629 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_GREEN_SIZE, 00630 &i->pixel_size.rgba.g) 00631 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BLUE_SIZE, 00632 &i->pixel_size.rgba.b) 00633 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ALPHA_SIZE, 00634 &i->pixel_size.rgba.a) 00635 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DOUBLEBUFFER, 00636 &i->doublebuffered) 00637 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_AUX_BUFFERS, 00638 &i->aux_buffers) 00639 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STENCIL_SIZE, 00640 &i->stencil_size) 00641 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_RED_SIZE, 00642 &i->accum_size.rgba.r) 00643 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_GREEN_SIZE, 00644 &i->accum_size.rgba.g) 00645 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_BLUE_SIZE, 00646 &i->accum_size.rgba.b) 00647 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_ALPHA_SIZE, 00648 &i->accum_size.rgba.a)) { 00649 TRACE(PREFIX_I "decode_fbconfig: Incomplete glX mode ...\n"); 00650 return -1; 00651 } 00652 00653 if (!(render_type & GLX_RGBA_BIT) && !(render_type & GLX_RGBA_FLOAT_BIT)) { 00654 TRACE(PREFIX_I "decode_fbconfig: Not RGBA mode\n"); 00655 return -1; 00656 } 00657 00658 if (!(drawable_type & GLX_WINDOW_BIT)) { 00659 TRACE(PREFIX_I "decode_fbconfig: Cannot render to a window.\n"); 00660 return -1; 00661 } 00662 00663 if (renderable == False) { 00664 TRACE(PREFIX_I "decode_fbconfig: GLX windows not supported.\n"); 00665 return -1; 00666 } 00667 00668 if (visual_type != GLX_TRUE_COLOR && visual_type != GLX_DIRECT_COLOR) { 00669 TRACE(PREFIX_I "decode_fbconfig: visual type other than TrueColor and " 00670 "DirectColor.\n"); 00671 return -1; 00672 } 00673 00674 /* Floating-point depth is not supported as glx extension (yet). */ 00675 i->float_depth = 0; 00676 00677 i->float_color = (render_type & GLX_RGBA_FLOAT_BIT); 00678 00679 v = glXGetVisualFromFBConfig(_xwin.display, fbc); 00680 if (!v) { 00681 TRACE(PREFIX_I "decode_fbconfig: Cannot get associated visual for the " 00682 "FBConfig.\n"); 00683 return -1; 00684 } 00685 i->r_shift = get_shift (v->red_mask); 00686 i->g_shift = get_shift (v->green_mask); 00687 i->b_shift = get_shift (v->blue_mask); 00688 i->a_shift = 0; 00689 00690 /* If we are going to need to setup a palette we need bit shifts */ 00691 if ((visual_type == GLX_DIRECT_COLOR) 00692 && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1)) 00693 && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b 00694 <= 12)) { 00695 /* XXX <rohannessian> Report something here? */ 00696 XFree(v); 00697 return -1; 00698 } 00699 00700 i->colour_depth = 0; 00701 00702 if (i->pixel_size.rgba.r == 3 00703 && i->pixel_size.rgba.g == 3 00704 && i->pixel_size.rgba.b == 2) { 00705 i->colour_depth = 8; 00706 } 00707 00708 if (i->pixel_size.rgba.r == 5 00709 && i->pixel_size.rgba.b == 5) { 00710 if (i->pixel_size.rgba.g == 5) { 00711 i->colour_depth = 15; 00712 } 00713 if (i->pixel_size.rgba.g == 6) { 00714 i->colour_depth = 16; 00715 } 00716 } 00717 00718 if (i->pixel_size.rgba.r == 8 00719 && i->pixel_size.rgba.g == 8 00720 && i->pixel_size.rgba.b == 8) { 00721 if (i->pixel_size.rgba.a == 0) { 00722 i->colour_depth = 24; 00723 } 00724 if (i->pixel_size.rgba.a == 8) { 00725 i->colour_depth = 32; 00726 /* small hack that tries to guess alpha shifting */ 00727 i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift; 00728 } 00729 } 00730 00731 i->allegro_format = (i->colour_depth != 0) 00732 && (i->g_shift == i->pixel_size.rgba.b) 00733 && (i->r_shift * i->b_shift == 0) 00734 && (i->r_shift + i->b_shift 00735 == i->pixel_size.rgba.b + i->pixel_size.rgba.g); 00736 00737 if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)) { 00738 /* Multisample extension is not supported */ 00739 i->sample_buffers = 0; 00740 } 00741 else { 00742 i->sample_buffers = sbuffers; 00743 } 00744 if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)) { 00745 /* Multisample extension is not supported */ 00746 i->samples = 0; 00747 } 00748 else { 00749 i->samples = samples; 00750 } 00751 00752 XFree(v); 00753 00754 TRACE(PREFIX_I "Color Depth: %i\n", buffer_size); 00755 TRACE(PREFIX_I "RGBA Type: %s point\n", i->float_color ? "floating" : "fixed"); 00756 TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g, 00757 i->pixel_size.rgba.b, i->pixel_size.rgba.a); 00758 TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g, 00759 i->accum_size.rgba.b, i->accum_size.rgba.a); 00760 TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n", 00761 i->doublebuffered, i->depth_size, i->stereo, 00762 i->aux_buffers, i->stencil_size); 00763 TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift, 00764 i->a_shift); 00765 TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples); 00766 TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth); 00767 00768 return 0; 00769 } 00770 00771 00772 00773 int allegro_gl_x_windowed_choose_fbconfig (GLXFBConfig *ret_fbconfig) { 00774 int num_fbconfigs, i; 00775 GLXFBConfig *fbconfig; 00776 struct allegro_gl_display_info dinfo; 00777 00778 fbconfig = glXGetFBConfigs (_xwin.display, _xwin.screen, &num_fbconfigs); 00779 if (!fbconfig || !num_fbconfigs) 00780 return FALSE; 00781 00782 TRACE(PREFIX_I "x_windowed_choose_fbconfig: %i formats.\n", num_fbconfigs); 00783 __allegro_gl_reset_scorer(); 00784 00785 for (i = 0; i < num_fbconfigs; i++) { 00786 TRACE(PREFIX_I "x_windowed_choose_fbconfig: Mode %i\n", i); 00787 if (decode_fbconfig (*(fbconfig + i), &dinfo) != -1) { 00788 __allegro_gl_score_config (i, &dinfo); 00789 } 00790 } 00791 00792 i = __allegro_gl_best_config(); 00793 TRACE(PREFIX_I "x_windowed_choose_fbconfig: Best FBConfig is: %i\n", i); 00794 00795 if (i < 0) { 00796 XFree(fbconfig); 00797 return FALSE; 00798 } 00799 00800 *ret_fbconfig = *(fbconfig + i); 00801 XFree(fbconfig); 00802 00803 return TRUE; 00804 } 00805 00806 00807 00808 /* windowed_choose_visual: 00809 * Chooses a visual to use. 00810 */ 00811 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void) 00812 { 00813 int num_visuals, i; 00814 XVisualInfo *vinfo; 00815 struct allegro_gl_display_info dinfo; 00816 static XVisualInfo ret_vinfo; 00817 00818 vinfo = XGetVisualInfo (_xwin.display, 0, NULL, &num_visuals); 00819 if (!vinfo) return NULL; 00820 00821 TRACE(PREFIX_I "x_windowed_choose_visual: %i formats.\n", num_visuals); 00822 __allegro_gl_reset_scorer(); 00823 00824 for (i = 0; i < num_visuals; i++) { 00825 TRACE(PREFIX_I "x_windowed_choose_visual: Mode %i\n", i); 00826 if (decode_visual (vinfo + i, &dinfo) != -1) { 00827 __allegro_gl_score_config (i, &dinfo); 00828 } 00829 } 00830 00831 i = __allegro_gl_best_config(); 00832 TRACE(PREFIX_I "x_windowed_choose_visual: Best config is: %i\n", i); 00833 00834 if (i < 0) return NULL; 00835 00836 memcpy (&ret_vinfo, vinfo+i, sizeof ret_vinfo); 00837 XFree (vinfo); 00838 00839 return &ret_vinfo; 00840 } 00841 00842 00843 00844 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 00845 /* get_xf86_modes: 00846 * Test if the XF86VidMode extension is available and get the gfx modes 00847 * that can be queried. 00848 */ 00849 static int get_xf86_modes(XF86VidModeModeInfo ***modesinfo, int *num_modes) 00850 { 00851 int vid_event_base, vid_error_base; 00852 int vid_major_version, vid_minor_version; 00853 00854 /* Test for presence of VidMode extension. */ 00855 if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base, 00856 &vid_error_base) 00857 || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version, 00858 &vid_minor_version)) { 00859 00860 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 00861 get_config_text("VidMode extension is not supported")); 00862 return -1; 00863 } 00864 00865 if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, num_modes, 00866 modesinfo)) { 00867 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 00868 get_config_text("Can not Get ModeLines")); 00869 return -1; 00870 } 00871 00872 return 0; 00873 } 00874 #endif 00875 00876 00877 static int allegro_gl_x_error_handler(Display *display, XErrorEvent *err_event) 00878 { 00879 char buffer[256]; 00880 00881 XGetErrorText(display, err_event->error_code, buffer, 256); 00882 TRACE(PREFIX_E "%s\n", buffer); 00883 return 0; 00884 } 00885 00886 00887 /* create_window: 00888 * Based on Michael's `_xwin[_private]_create_window' and the xdemos 00889 * from the Mesa distribution (I don't remember which one). 00890 */ 00891 static int allegro_gl_x_create_window (int fullscreen) 00892 { 00893 Window root; 00894 XVisualInfo *visinfo; 00895 XSetWindowAttributes setattr; 00896 unsigned long valuemask = CWBackPixel | CWBorderPixel | CWColormap 00897 | CWEventMask; 00898 XSizeHints *hints; 00899 GLXFBConfig fbconfig; 00900 int use_fbconfig; 00901 00902 if (_xwin.display == 0) { 00903 return -2; 00904 } 00905 00906 old_x_error_handler = XSetErrorHandler(allegro_gl_x_error_handler); 00907 00908 /* Fill in missing color depth info */ 00909 __allegro_gl_fill_in_info(); 00910 00911 use_fbconfig = (_glxwin.major > 1 || (_glxwin.major == 1 && _glxwin.minor >= 3)); 00912 00913 if (use_fbconfig) { 00914 TRACE(PREFIX_I "x_create_window: using FBConfig routines\n"); 00915 00916 if (!allegro_gl_x_windowed_choose_fbconfig(&fbconfig)) { 00917 TRACE(PREFIX_I "x_create_window: Failed using FBConfig, switching " 00918 "back to VisualInfo routines\n"); 00919 use_fbconfig = FALSE; 00920 goto old_choose_visual; 00921 } 00922 00923 /* Query back FBConfig components */ 00924 if (decode_fbconfig(fbconfig, &allegro_gl_display_info)) { 00925 TRACE(PREFIX_E "x_create_window: Cannot decode FBConfig, switching " 00926 "back to VisualInfo routines\n"); 00927 use_fbconfig = FALSE; 00928 goto old_choose_visual; 00929 } 00930 00931 visinfo = glXGetVisualFromFBConfig(_xwin.display, fbconfig); 00932 if (!visinfo) { 00933 TRACE(PREFIX_I "x_create_window: Failed to convert FBConfig to " 00934 "visual, switching back to VisualInfo routines\n"); 00935 use_fbconfig = FALSE; 00936 goto old_choose_visual; 00937 } 00938 } 00939 else { 00940 old_choose_visual: 00941 TRACE(PREFIX_I "x_create_window: using VisualInfo routines\n"); 00942 00943 /* Find best visual */ 00944 visinfo = allegro_gl_x_windowed_choose_visual(); 00945 if (!visinfo) { 00946 TRACE(PREFIX_E "x_create_window: Can not get visual.\n"); 00947 XSetErrorHandler(old_x_error_handler); 00948 return -2; 00949 } 00950 00951 /* Query back visual components */ 00952 if (decode_visual (visinfo, &allegro_gl_display_info)) { 00953 TRACE(PREFIX_E "x_create_window: Can not decode visual.\n"); 00954 XSetErrorHandler(old_x_error_handler); 00955 return -2; 00956 } 00957 } 00958 00959 /* Log some information about it */ 00960 switch (visinfo->class) { 00961 case TrueColor: 00962 AGL_LOG (1, "x.c: visual class: TrueColor\n"); 00963 break; 00964 case DirectColor: 00965 AGL_LOG (1, "x.c: visual class: DirectColor\n"); 00966 break; 00967 default: 00968 AGL_LOG (1, "x.c: visual class: invalid(!)\n"); 00969 } 00970 00971 00972 /* Begin window creation. */ 00973 00974 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 00975 /* Hack: For Allegro 4.2.1, we need to keep the existing window. */ 00976 if (backup_allegro_window == None) { 00977 backup_allegro_window = _xwin.window; 00978 backup_allegro_colormap = _xwin.colormap; 00979 _xwin.colormap = None; 00980 XUnmapWindow(_xwin.display, _xwin.window); 00981 } 00982 else 00983 #endif 00984 XDestroyWindow (_xwin.display, _xwin.window); 00985 00986 _xwin.window = None; 00987 00988 root = RootWindow (_xwin.display, _xwin.screen); 00989 00990 /* Recreate window. */ 00991 setattr.background_pixel = XBlackPixel (_xwin.display, _xwin.screen); 00992 setattr.border_pixel = XBlackPixel (_xwin.display, _xwin.screen); 00993 setattr.colormap = XCreateColormap (_xwin.display, root, visinfo->visual, AllocNone); 00994 setattr.event_mask = 00995 ( KeyPressMask | KeyReleaseMask 00996 | EnterWindowMask | LeaveWindowMask 00997 | FocusChangeMask | ExposureMask 00998 | ButtonPressMask | ButtonReleaseMask | PointerMotionMask 00999 /*| MappingNotifyMask (SubstructureRedirectMask?)*/ 01000 ); 01001 01002 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 01003 if (fullscreen) { 01004 int i; 01005 int bestmode = 0; 01006 _xwin.num_modes = 0; 01007 _xwin.modesinfo = NULL; 01008 _glxwin.fullscreen = TRUE; 01009 01010 if (get_xf86_modes(&_xwin.modesinfo, &_xwin.num_modes)) { 01011 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01012 get_config_text("x_create_window: Can't get" 01013 "XF86VidMode info.\n")); 01014 XSetErrorHandler(old_x_error_handler); 01015 return -2; 01016 } 01017 01018 /* look for mode with requested resolution */ 01019 for (i = 0; i < _xwin.num_modes; i++) 01020 { 01021 if ((_xwin.modesinfo[i]->hdisplay == allegro_gl_display_info.w) 01022 && (_xwin.modesinfo[i]->vdisplay == allegro_gl_display_info.h)) 01023 bestmode = i; 01024 } 01025 01026 setattr.override_redirect = True; 01027 if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen, 01028 _xwin.modesinfo[bestmode])) { 01029 01030 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01031 get_config_text("Can not set XF86VidMode mode")); 01032 XSetErrorHandler(old_x_error_handler); 01033 return -1; 01034 } 01035 01036 XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0); 01037 01038 /* Lock Mode switching */ 01039 XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True); 01040 _xwin.mode_switched = 1; 01041 01042 allegro_gl_display_info.x = 0; 01043 allegro_gl_display_info.y = 0; 01044 allegro_gl_display_info.w = _xwin.modesinfo[bestmode]->hdisplay; 01045 allegro_gl_display_info.h = _xwin.modesinfo[bestmode]->vdisplay; 01046 01047 valuemask |= CWOverrideRedirect; 01048 _xwin.override_redirected = 1; 01049 } 01050 01051 _xwin.window = XCreateWindow ( 01052 _xwin.display, root, 01053 allegro_gl_display_info.x, allegro_gl_display_info.y, 01054 allegro_gl_display_info.w, allegro_gl_display_info.h, 0, 01055 visinfo->depth, 01056 InputOutput, 01057 visinfo->visual, 01058 valuemask, &setattr 01059 ); 01060 01061 #else //ALLEGROGL_HAVE_XF86VIDMODE 01062 if (fullscreen) { 01063 /* Without Xf86VidMode extension we support only fullscreen modes which 01064 * match current resolution. */ 01065 int fs_width = DisplayWidth(_xwin.display, _xwin.screen); 01066 int fs_height = DisplayHeight(_xwin.display, _xwin.screen); 01067 01068 if (fs_width != allegro_gl_display_info.w 01069 || fs_height != allegro_gl_display_info.h) { 01070 TRACE(PREFIX_E "Only desktop resolution fullscreen available."); 01071 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01072 get_config_text("Compiled without Xf86VidMode extension support.\n" 01073 "Only desktop resolution fullscreen available.")); 01074 XSetErrorHandler(old_x_error_handler); 01075 return -1; 01076 } 01077 01078 _glxwin.fullscreen = TRUE; 01079 01080 /* Create the fullscreen window. */ 01081 _xwin.window = XCreateWindow(_xwin.display, root, 01082 allegro_gl_display_info.x, allegro_gl_display_info.y, 01083 fs_width, fs_height, 0, 01084 visinfo->depth, 01085 InputOutput, 01086 visinfo->visual, 01087 valuemask, &setattr); 01088 01089 /* Map the fullscreen window. */ 01090 XMapRaised(_xwin.display, _xwin.window); 01091 01092 /* Make sure we got to the top of the window stack. */ 01093 XRaiseWindow(_xwin.display, _xwin.fs_window); 01094 } 01095 else { 01096 _xwin.window = XCreateWindow ( 01097 _xwin.display, root, 01098 allegro_gl_display_info.x, allegro_gl_display_info.y, 01099 allegro_gl_display_info.w, allegro_gl_display_info.h, 0, 01100 visinfo->depth, 01101 InputOutput, 01102 visinfo->visual, 01103 valuemask, &setattr 01104 ); 01105 } 01106 #endif //ALLEGROGL_HAVE_XF86VIDMODE 01107 01108 /* Set size and position hints for Window Manager : 01109 * prevents the window to be resized 01110 */ 01111 hints = XAllocSizeHints(); 01112 if (hints) { 01113 /* This code chunk comes from Allegro's src/x/xwin.c */ 01114 hints->flags = PMinSize | PMaxSize | PBaseSize; 01115 hints->min_width = hints->max_width = hints->base_width 01116 = allegro_gl_display_info.w; 01117 hints->min_height = hints->max_height = hints->base_height 01118 = allegro_gl_display_info.h; 01119 01120 XSetWMNormalHints(_xwin.display, _xwin.window, hints); 01121 XFree(hints); 01122 } 01123 01124 01125 /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property 01126 * (to get window_delete requests). 01127 */ 01128 { 01129 Atom wm_delete_window = XInternAtom(_xwin.display, "WM_DELETE_WINDOW", False); 01130 XSetWMProtocols(_xwin.display, _xwin.window, &wm_delete_window, 1); 01131 } 01132 01133 /* Finish off the GLX setup */ 01134 if (use_fbconfig) 01135 _glxwin.ctx = glXCreateNewContext (_xwin.display, fbconfig, GLX_RGBA_TYPE, NULL, True); 01136 else 01137 _glxwin.ctx = glXCreateContext (_xwin.display, visinfo, NULL, True); 01138 01139 if (use_fbconfig) { 01140 _glxwin.window = glXCreateWindow(_xwin.display, fbconfig, _xwin.window, 0); 01141 if (!_glxwin.window) { 01142 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01143 get_config_text("Cannot create GLX window.")); 01144 XSetErrorHandler(old_x_error_handler); 01145 return -1; 01146 } 01147 _glxwin.use_glx_window = TRUE; 01148 } 01149 01150 if (!_glxwin.ctx) { 01151 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01152 get_config_text("Can not create GLX context.")); 01153 XSetErrorHandler(old_x_error_handler); 01154 return -1; 01155 } 01156 else { 01157 Bool ret; 01158 01159 if (use_fbconfig) 01160 ret = glXMakeContextCurrent(_xwin.display, _glxwin.window, _glxwin.window, _glxwin.ctx); 01161 else 01162 ret = glXMakeCurrent (_xwin.display, _xwin.window, _glxwin.ctx); 01163 01164 if (!ret) { 01165 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01166 get_config_text("Cannot make GLX context current.")); 01167 XSetErrorHandler(old_x_error_handler); 01168 return -1; 01169 } 01170 } 01171 01172 /* Finish off the Allegro setup */ 01173 01174 /* Get associated visual and window depth (bits per pixel), and 01175 * store window size */ 01176 { 01177 XWindowAttributes getattr; 01178 XGetWindowAttributes(_xwin.display, _xwin.window, &getattr); 01179 _xwin.visual = getattr.visual; 01180 _xwin.window_depth = getattr.depth; 01181 _xwin.window_width = allegro_gl_display_info.w; 01182 _xwin.window_height = allegro_gl_display_info.h; 01183 _xwin.screen_depth = getattr.depth; 01184 _xwin.screen_width = allegro_gl_display_info.w; 01185 _xwin.screen_height = allegro_gl_display_info.h; 01186 } 01187 01188 /* Destroy the current colormap (if any) */ 01189 if (_xwin.colormap != None) { 01190 XUninstallColormap(_xwin.display, _xwin.colormap); 01191 XFreeColormap(_xwin.display, _xwin.colormap); 01192 } 01193 01194 /* Create and install colormap. */ 01195 if (_xwin.visual->class == DirectColor) { 01196 _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window, 01197 _xwin.visual, AllocAll); 01198 } 01199 else { /* must be TrueColor */ 01200 _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window, 01201 _xwin.visual, AllocNone); 01202 } 01203 XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap); 01204 XInstallColormap(_xwin.display, _xwin.colormap); 01205 01206 /* Setup a palette if needed */ 01207 if (_xwin.visual->class == DirectColor) { 01208 XColor color; 01209 int rsize, gsize, bsize; 01210 int rmax, gmax, bmax; 01211 int rshift, gshift, bshift; 01212 int r, g, b; 01213 01214 AGL_LOG (1, "x.c: Using DirectColor visual, setting palette...\n"); 01215 01216 rsize = 1 << allegro_gl_display_info.pixel_size.rgba.r; 01217 gsize = 1 << allegro_gl_display_info.pixel_size.rgba.g; 01218 bsize = 1 << allegro_gl_display_info.pixel_size.rgba.b; 01219 01220 rshift = allegro_gl_display_info.r_shift; 01221 bshift = allegro_gl_display_info.b_shift; 01222 gshift = allegro_gl_display_info.g_shift; 01223 01224 rmax = rsize - 1; 01225 gmax = gsize - 1; 01226 bmax = bsize - 1; 01227 01228 color.flags = DoRed | DoGreen | DoBlue; 01229 for (r = 0; r < rsize; r++) { 01230 for (g = 0; g < gsize; g++) { 01231 for (b = 0; b < bsize; b++) { 01232 color.pixel = (r << rshift) | (g << gshift) | (b << bshift); 01233 color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax)); 01234 color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax)); 01235 color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax)); 01236 XStoreColor(_xwin.display, _xwin.colormap, &color); 01237 } 01238 } 01239 } 01240 } 01241 01242 /* Configure the window a bit */ 01243 { 01244 XClassHint hint; 01245 XWMHints wm_hints; 01246 01247 /* Set title. */ 01248 XStoreName(_xwin.display, _xwin.window, _xwin.window_title); 01249 01250 /* Set hints. */ 01251 hint.res_name = _xwin.application_name; 01252 hint.res_class = _xwin.application_class; 01253 XSetClassHint(_xwin.display, _xwin.window, &hint); 01254 01255 wm_hints.flags = InputHint | StateHint; 01256 wm_hints.input = True; 01257 wm_hints.initial_state = NormalState; 01258 01259 #ifdef ALLEGRO_XWINDOWS_WITH_XPM 01260 if (allegro_icon) { 01261 wm_hints.flags |= IconPixmapHint | IconMaskHint | WindowGroupHint; 01262 XpmCreatePixmapFromData(_xwin.display, _xwin.window, allegro_icon,&wm_hints.icon_pixmap, &wm_hints.icon_mask, NULL); 01263 } 01264 #endif 01265 01266 XSetWMHints(_xwin.display, _xwin.window, &wm_hints); 01267 } 01268 01269 /* Map window. */ 01270 XMapWindow(_xwin.display, _xwin.window); 01271 01272 01273 if (fullscreen) { 01274 AL_CONST char *fc = NULL; 01275 char tmp1[64], tmp2[128]; 01276 int c = 0; 01277 int h = allegro_gl_display_info.h; 01278 int w = allegro_gl_display_info.w; 01279 01280 /* This chunk is disabled by default because of problems on KDE 01281 desktops. */ 01282 fc = get_config_string(uconvert_ascii("graphics", tmp1), 01283 uconvert_ascii("force_centering", tmp2), NULL); 01284 if ((fc) && ((c = ugetc(fc)) != 0) && ((c == 'y') || (c == 'Y') 01285 || (c == '1'))) { 01286 /* Hack: make the window fully visible and center cursor. */ 01287 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0); 01288 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 01289 w - 1, 0); 01290 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 01291 0, h - 1); 01292 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 01293 w - 1, h - 1); 01294 } 01295 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 01296 w / 2, h / 2); 01297 XSync(_xwin.display, False); 01298 01299 /* Grab keyboard and mouse. */ 01300 if (XGrabKeyboard(_xwin.display, _xwin.window, False, GrabModeAsync, 01301 GrabModeAsync, CurrentTime) != GrabSuccess) { 01302 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01303 get_config_text("Can not grab keyboard")); 01304 XSetErrorHandler(old_x_error_handler); 01305 return -1; 01306 } 01307 _xwin.keyboard_grabbed = 1; 01308 01309 if (XGrabPointer(_xwin.display, _xwin.window, False, 01310 PointerMotionMask | ButtonPressMask | ButtonReleaseMask, 01311 GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime) 01312 != GrabSuccess) { 01313 01314 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01315 get_config_text("Can not grab mouse")); 01316 XSetErrorHandler(old_x_error_handler); 01317 return -1; 01318 } 01319 _xwin.mouse_grabbed = 1; 01320 } 01321 01322 01323 /* Destroy current cursor (if any) */ 01324 if (_xwin.cursor != None) { 01325 XUndefineCursor(_xwin.display, _xwin.window); 01326 XFreeCursor(_xwin.display, _xwin.cursor); 01327 } 01328 01329 { 01330 /* Create invisible X cursor. */ 01331 Pixmap pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1); 01332 if (pixmap != None) { 01333 GC temp_gc; 01334 XColor color; 01335 XGCValues gcvalues; 01336 01337 int gcmask = GCFunction | GCForeground | GCBackground; 01338 gcvalues.function = GXcopy; 01339 gcvalues.foreground = 0; 01340 gcvalues.background = 0; 01341 temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues); 01342 XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0); 01343 XFreeGC(_xwin.display, temp_gc); 01344 color.pixel = 0; 01345 color.red = color.green = color.blue = 0; 01346 color.flags = DoRed | DoGreen | DoBlue; 01347 _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, 01348 &color, &color, 0, 0); 01349 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor); 01350 XFreePixmap(_xwin.display, pixmap); 01351 } 01352 else { 01353 _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape); 01354 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor); 01355 } 01356 } 01357 01358 /* Wait for the first exposure event. See comment in Allegro's 01359 * xwin.c about why no blocking X11 function is used. 01360 */ 01361 while (1) { 01362 XEvent e; 01363 if (XCheckTypedEvent(_xwin.display, Expose, &e)) { 01364 if (e.xexpose.count == 0) break; 01365 } 01366 rest(1); 01367 } 01368 01369 return 0; 01370 } 01371 01372 01373 01374 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth) 01375 { 01376 BITMAP *bmp; 01377 int is_linear = drv->linear; 01378 01379 drv->linear = 1; 01380 bmp = _make_bitmap (w, h, 0, drv, depth, 0); 01381 bmp->id = BMP_ID_VIDEO | BMP_ID_MASK; 01382 drv->linear = is_linear; 01383 01384 if (bmp == 0) { 01385 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01386 get_config_text("Not enough memory")); 01387 return NULL; 01388 } 01389 01390 drv->w = w; 01391 drv->h = h; 01392 01393 return bmp; 01394 } 01395 01396 01397 01398 /* decode_visual: 01399 * Used to read back the information in the visual. 0 = ok. 01400 */ 01401 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i) 01402 { 01403 int rgba, buffer_size, use_gl, sbuffers, samples; 01404 01405 TRACE(PREFIX_I "decode_visual: Decoding:\n"); 01406 i->rmethod = 2; 01407 01408 /* We can only support TrueColor and DirectColor visuals -- 01409 * we only support RGBA mode */ 01410 if (v->class != TrueColor && v->class != DirectColor) 01411 return -1; 01412 01413 if (glXGetConfig (_xwin.display, v, GLX_RGBA, &rgba) 01414 || glXGetConfig (_xwin.display, v, GLX_USE_GL, &use_gl) 01415 || glXGetConfig (_xwin.display, v, GLX_BUFFER_SIZE, &buffer_size) 01416 || glXGetConfig (_xwin.display, v, GLX_RED_SIZE, &i->pixel_size.rgba.r) 01417 || glXGetConfig (_xwin.display, v, GLX_GREEN_SIZE, &i->pixel_size.rgba.g) 01418 || glXGetConfig (_xwin.display, v, GLX_BLUE_SIZE, &i->pixel_size.rgba.b) 01419 || glXGetConfig (_xwin.display, v, GLX_ALPHA_SIZE, &i->pixel_size.rgba.a) 01420 || glXGetConfig (_xwin.display, v, GLX_DOUBLEBUFFER, &i->doublebuffered) 01421 || glXGetConfig (_xwin.display, v, GLX_STEREO, &i->stereo) 01422 || glXGetConfig (_xwin.display, v, GLX_AUX_BUFFERS, &i->aux_buffers) 01423 || glXGetConfig (_xwin.display, v, GLX_DEPTH_SIZE, &i->depth_size) 01424 || glXGetConfig (_xwin.display, v, GLX_STENCIL_SIZE, &i->stencil_size) 01425 || glXGetConfig (_xwin.display, v, GLX_ACCUM_RED_SIZE, 01426 &i->accum_size.rgba.r) 01427 || glXGetConfig (_xwin.display, v, GLX_ACCUM_GREEN_SIZE, 01428 &i->accum_size.rgba.g) 01429 || glXGetConfig (_xwin.display, v, GLX_ACCUM_BLUE_SIZE, 01430 &i->accum_size.rgba.b) 01431 || glXGetConfig (_xwin.display, v, GLX_ACCUM_ALPHA_SIZE, 01432 &i->accum_size.rgba.a)) { 01433 TRACE(PREFIX_I "x_create_window: Incomplete glX mode ...\n"); 01434 return -1; 01435 } 01436 01437 if (!rgba) { 01438 TRACE(PREFIX_I "x_create_window: Not RGBA mode\n"); 01439 return -1; 01440 } 01441 01442 if (!use_gl) { 01443 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE, 01444 get_config_text("OpenGL Unsupported")); 01445 return -1; 01446 } 01447 01448 i->r_shift = get_shift (v->red_mask); 01449 i->g_shift = get_shift (v->green_mask); 01450 i->b_shift = get_shift (v->blue_mask); 01451 i->a_shift = 0; 01452 01453 /* If we are going to need to setup a palette we need bit shifts */ 01454 if ((v->class == DirectColor) 01455 && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1)) 01456 && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b 01457 <= 12)) { 01458 /* XXX <rohannessian> Report something here? */ 01459 return -1; 01460 } 01461 01462 i->float_color = 0; 01463 i->float_depth = 0; 01464 01465 i->colour_depth = 0; 01466 01467 if (i->pixel_size.rgba.r == 3 01468 && i->pixel_size.rgba.g == 3 01469 && i->pixel_size.rgba.b == 2) { 01470 i->colour_depth = 8; 01471 } 01472 01473 if (i->pixel_size.rgba.r == 5 01474 && i->pixel_size.rgba.b == 5) { 01475 if (i->pixel_size.rgba.g == 5) { 01476 i->colour_depth = 15; 01477 } 01478 if (i->pixel_size.rgba.g == 6) { 01479 i->colour_depth = 16; 01480 } 01481 } 01482 01483 if (i->pixel_size.rgba.r == 8 01484 && i->pixel_size.rgba.g == 8 01485 && i->pixel_size.rgba.b == 8) { 01486 if (i->pixel_size.rgba.a == 0) { 01487 i->colour_depth = 24; 01488 } 01489 if (i->pixel_size.rgba.a == 8) { 01490 i->colour_depth = 32; 01491 /* small hack that tries to guess alpha shifting */ 01492 i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift; 01493 } 01494 } 01495 01496 i->allegro_format = (i->colour_depth != 0) 01497 && (i->g_shift == i->pixel_size.rgba.b) 01498 && (i->r_shift * i->b_shift == 0) 01499 && (i->r_shift + i->b_shift 01500 == i->pixel_size.rgba.b + i->pixel_size.rgba.g); 01501 01502 if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers) 01503 == GLX_BAD_ATTRIBUTE) { 01504 /* Multisample extension is not supported */ 01505 i->sample_buffers = 0; 01506 } 01507 else { 01508 i->sample_buffers = sbuffers; 01509 } 01510 if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples) 01511 == GLX_BAD_ATTRIBUTE) { 01512 /* Multisample extension is not supported */ 01513 i->samples = 0; 01514 } 01515 else { 01516 i->samples = samples; 01517 } 01518 01519 01520 TRACE(PREFIX_I "Color Depth: %i\n", buffer_size); 01521 TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g, 01522 i->pixel_size.rgba.b, i->pixel_size.rgba.a); 01523 TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g, 01524 i->accum_size.rgba.b, i->accum_size.rgba.a); 01525 TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n", 01526 i->doublebuffered, i->depth_size, i->stereo, 01527 i->aux_buffers, i->stencil_size); 01528 TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift, 01529 i->a_shift); 01530 TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples); 01531 TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth); 01532 01533 return 0; 01534 } 01535 01536 01537 01538 #ifdef ALLEGROGL_HAVE_XF86VIDMODE 01539 /* allegro_gl_x_fetch_mode_list: 01540 * Generates a list of valid video modes (made after 01541 * _xvidmode_private_fetch_mode_list of Allegro) 01542 */ 01543 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void) 01544 { 01545 int num_modes = 0; 01546 XF86VidModeModeInfo **modesinfo = NULL; 01547 GFX_MODE_LIST *mode_list; 01548 int i; 01549 01550 XLOCK(); 01551 01552 if (get_xf86_modes(&modesinfo, &num_modes)) { 01553 XUNLOCK(); 01554 return NULL; 01555 } 01556 01557 /* Allocate space for mode list. */ 01558 mode_list = malloc(sizeof(GFX_MODE_LIST)); 01559 if (!mode_list) { 01560 free_modelines(modesinfo, num_modes); 01561 XUNLOCK(); 01562 return NULL; 01563 } 01564 01565 mode_list->mode = malloc(sizeof(GFX_MODE) * (num_modes + 1)); 01566 if (!mode_list->mode) { 01567 free(mode_list); 01568 free_modelines(modesinfo, num_modes); 01569 XUNLOCK(); 01570 return NULL; 01571 } 01572 01573 /* Fill in mode list. */ 01574 for (i = 0; i < num_modes; i++) { 01575 mode_list->mode[i].width = modesinfo[i]->hdisplay; 01576 mode_list->mode[i].height = modesinfo[i]->vdisplay; 01577 /* Since XF86VidMode can not change the color depth of 01578 * the screen, there is no need to define modes for other 01579 * color depth than the desktop's. 01580 */ 01581 mode_list->mode[i].bpp = desktop_color_depth(); 01582 } 01583 01584 mode_list->mode[num_modes].width = 0; 01585 mode_list->mode[num_modes].height = 0; 01586 mode_list->mode[num_modes].bpp = 0; 01587 mode_list->num_modes = num_modes; 01588 01589 free_modelines(modesinfo, num_modes); 01590 01591 XUNLOCK(); 01592 return mode_list; 01593 } 01594 #endif 01595 01596 01597 01598 /* allegro_gl_x_vsync: 01599 * Wait for a vertical retrace. GLX_SGI_video_sync is needed. 01600 */ 01601 static void allegro_gl_x_vsync(void) 01602 { 01603 XLOCK(); 01604 if (allegro_gl_extensions_GLX.SGI_video_sync) { 01605 unsigned int count; 01606 01607 glXGetVideoSyncSGI(&count); 01608 glXWaitVideoSyncSGI(2, (count+1) & 1, &count); 01609 } 01610 XUNLOCK(); 01611 } 01612 01613 01614 01615 /******************************/ 01616 /* AllegroGL driver functions */ 01617 /******************************/ 01618 01619 /* flip: 01620 * Does a page flip / double buffer copy / whatever it really is. 01621 */ 01622 static void flip (void) 01623 { 01624 XLOCK(); 01625 if (_glxwin.use_glx_window) 01626 glXSwapBuffers (_xwin.display, _glxwin.window); 01627 else 01628 glXSwapBuffers (_xwin.display, _xwin.window); 01629 XUNLOCK(); 01630 } 01631 01632 01633 01634 /* gl_on, gl_off: 01635 * Switches to/from GL mode. 01636 */ 01637 static void gl_on (void) 01638 { 01639 #ifdef OLD_ALLEGRO 01640 DISABLE(); 01641 #endif 01642 } 01643 01644 01645 01646 static void gl_off (void) 01647 { 01648 #ifdef OLD_ALLEGRO 01649 ENABLE(); 01650 _xwin_handle_input(); 01651 #endif 01652 } 01653 01654 01655 01656 /*****************/ 01657 /* Driver struct */ 01658 /*****************/ 01659 01660 static struct allegro_gl_driver allegro_gl_x = { 01661 flip, 01662 gl_on, 01663 gl_off, 01664 NULL 01665 }; 01666