Main Page | Modules | File List | Globals | Related Pages

x.c

00001 /*----------------------------------------------------------------
00002  * x.c -- Allegro-GLX interfacing
00003  *----------------------------------------------------------------
00004  *  This is the interface module for use under X.
00005  */
00006 #include <string.h>
00007 
00008 #include <allegro.h>
00009 #include <xalleg.h>
00010 
00011 #include <allegro/platform/aintunix.h>
00012 
00013 #include "alleggl.h"
00014 #include "allglint.h"
00015 #include "glvtable.h"
00016 
00017 
00018 #ifndef XLOCK
00019     #define OLD_ALLEGRO
00020     #define XLOCK() DISABLE()
00021     #undef XUNLOCK
00022     #define XUNLOCK() ENABLE()
00023 #endif
00024 
00025 
00026 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
00027                                           int color_depth);
00028 static void allegro_gl_x_exit(BITMAP *bmp);
00029 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void);
00030 static void allegro_gl_x_vsync(void);
00031 
00032 
00033 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00034 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
00035                                             int color_depth);
00036 
00037 GFX_DRIVER gfx_allegro_gl_fullscreen =
00038 {
00039    GFX_OPENGL_FULLSCREEN,
00040    empty_string,
00041    empty_string,
00042    "AllegroGL Fullscreen (X)",
00043    allegro_gl_x_fullscreen_init,
00044    allegro_gl_x_exit,
00045    NULL,
00046    allegro_gl_x_vsync,
00047    NULL,
00048    NULL, NULL, NULL,
00049    allegro_gl_create_video_bitmap,
00050    allegro_gl_destroy_video_bitmap,
00051    NULL, NULL,                  /* No show/request video bitmaps */
00052    NULL, NULL,
00053    allegro_gl_set_mouse_sprite,
00054    allegro_gl_show_mouse,
00055    allegro_gl_hide_mouse,
00056    allegro_gl_move_mouse,
00057    NULL,
00058    NULL, NULL,
00059    allegro_gl_x_fetch_mode_list,
00060    0, 0,
00061    0,
00062    0, 0,
00063    0,
00064    0,
00065    FALSE                        /* Windowed mode */
00066 };
00067 #endif /* HAVE_XF86VIDMODE */
00068 
00069 
00070 
00071 GFX_DRIVER gfx_allegro_gl_windowed =
00072 {
00073    GFX_OPENGL_WINDOWED,
00074    empty_string,
00075    empty_string,
00076    "AllegroGL Windowed (X)",
00077    allegro_gl_x_windowed_init,
00078    allegro_gl_x_exit,
00079    NULL,
00080    allegro_gl_x_vsync,
00081    NULL,
00082    NULL, NULL, NULL,
00083    allegro_gl_create_video_bitmap,
00084    allegro_gl_destroy_video_bitmap,
00085    NULL, NULL,                  /* No show/request video bitmaps */
00086    NULL, NULL,
00087    allegro_gl_set_mouse_sprite,
00088    allegro_gl_show_mouse,
00089    allegro_gl_hide_mouse,
00090    allegro_gl_move_mouse,
00091    NULL,
00092    NULL, NULL,
00093    NULL,                        /* No fetch_mode_list */
00094    0, 0,
00095    0,
00096    0, 0,
00097    0,
00098    0,
00099    TRUE                         /* Windowed mode */
00100 };
00101 
00102 
00103 
00104 static struct allegro_gl_driver allegro_gl_x;
00105 
00106 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void);
00107 static int allegro_gl_x_create_window (int fullscreen);
00108 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth);
00109 
00110 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i);
00111 struct {
00112     int fullscreen;
00113     GLXContext ctx;
00114     int major, minor;   /* Major and minor GLX version */
00115     int error_base, event_base;
00116 } _glxwin;
00117 
00118 static void (*old_window_redrawer)(int, int, int, int);
00119 extern void (*_xwin_window_redrawer)(int, int, int, int);
00120 static int (*old_x_error_handler)(Display*, XErrorEvent*);
00121 
00122 
00123 
00124 /* allegro_gl_redraw_window :
00125  *  Redraws the window when an Expose event is processed
00126  *  Important note : no GL commands should be processed in this function
00127  *  since it may be called by a thread which is different from the main thread.
00128  *  In order to be able to process GL commands, we should create another context
00129  *  and make it current to the other thread. IMHO it would be overkill.
00130  */
00131 static void allegro_gl_redraw_window(int x, int y, int w, int h)
00132 {
00133     /* Does nothing */
00134     return;
00135 }
00136 
00137 
00138 
00139 /* allegro_gl_x_windowed_init:
00140  *  Creates screen bitmap.
00141  */
00142 static BITMAP *allegro_gl_x_create_screen(int w, int h, int vw, int vh,
00143                                           int depth, int fullscreen)
00144 {
00145     int _keyboard_was_installed = FALSE;
00146     int _mouse_was_installed = FALSE;
00147 
00148     /* test if Allegro have pthread support enabled */
00149     if (!_unix_bg_man->multi_threaded) {
00150         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00151                get_config_text("Fatal Error : pthread support is not enabled"));
00152         return NULL;
00153     }
00154     
00155     if (keyboard_driver) {
00156         _keyboard_was_installed = TRUE;
00157         remove_keyboard();
00158         TRACE("* Note * x_create_screen: Removing Keyboard...\n");
00159     }
00160     
00161     if (mouse_driver) {
00162         _mouse_was_installed = TRUE;
00163         remove_mouse();
00164         TRACE("* Note * x_create_screen: Removing Mouse...\n");
00165     }
00166     
00167     XLOCK();
00168 
00169     if (!glXQueryExtension(_xwin.display, &_glxwin.error_base,
00170                           &_glxwin.event_base)) {
00171 
00172         ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00173                      get_config_text("GLX Extension not supported by display"));
00174         XUNLOCK();
00175         goto failure;
00176     }
00177     
00178     if ((w == 0) && (h == 0)) {
00179         w = 640;
00180         h = 480;
00181     }
00182 
00183     if ((vw > w) || (vh > h)) {
00184         ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00185              get_config_text ("OpenGL drivers do not support virtual screens"));
00186         XUNLOCK();
00187         goto failure;
00188     }
00189 
00190     allegro_gl_display_info.w = w;
00191     allegro_gl_display_info.h = h;
00192 
00193     old_window_redrawer = _xwin_window_redrawer;
00194     _xwin_window_redrawer = allegro_gl_redraw_window;
00195     _glxwin.fullscreen = FALSE;
00196     
00197     if (allegro_gl_x_create_window(fullscreen)) {
00198         if (fullscreen) {
00199             ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00200                       get_config_text ("Unable to switch in GLX fullscreen"));
00201         }
00202         else {
00203             ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00204                       get_config_text ("Unable to create GLX window"));
00205         }
00206         XUNLOCK();
00207         allegro_gl_x_exit(NULL);
00208         goto failure;
00209     }
00210 
00211     /* If pixel format is Allegro compatible, set up Allegro correctly. */
00212     set_color_depth(allegro_gl_display_info.colour_depth);
00213 
00214     /* XXX <rohannessian> X can run on Big-Endian systems. We need to 
00215      * make a check for that and pass TRUE to
00216      * __allegro_gl_set_allegro_image_format() in that case.
00217      */
00218     __allegro_gl_set_allegro_image_format(FALSE);
00219 
00220     if (fullscreen) {
00221 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00222         allegro_gl_screen =
00223                allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_fullscreen,
00224                        allegro_gl_display_info.w, allegro_gl_display_info.h,
00225                        _color_depth);
00226 #endif
00227     }
00228     else {
00229         allegro_gl_screen =
00230                 allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_windowed,
00231                         allegro_gl_display_info.w, allegro_gl_display_info.h,
00232                         _color_depth);
00233     }
00234 
00235     if (!allegro_gl_screen) {
00236         ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00237                   get_config_text ("Error creating screen bitmap"));
00238         XUNLOCK();
00239         allegro_gl_x_exit(NULL);
00240         goto failure;
00241     }
00242     
00243     XUNLOCK();
00244 
00245     __allegro_gl_valid_context = TRUE;
00246     __allegro_gl_driver = &allegro_gl_x;
00247 
00248     /* Print out OpenGL version info */
00249     TRACE("\n\nOpenGL Version: %s\nVendor: %s\nRenderer: %s\n",
00250          (AL_CONST char*)glGetString(GL_VERSION),
00251          (AL_CONST char*)glGetString(GL_VENDOR),
00252          (AL_CONST char*)glGetString(GL_RENDERER));
00253     
00254     /* Detect if the GL driver is based on Mesa */
00255     allegro_gl_info.is_mesa_driver = FALSE;
00256     if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) {
00257         AGL_LOG(1, "OpenGL driver based on Mesa\n");
00258         allegro_gl_info.is_mesa_driver = TRUE;
00259     }
00260 
00261     /* Print out GLX version info */
00262     glXQueryVersion(_xwin.display, &_glxwin.major, &_glxwin.minor);
00263     TRACE("GLX Version: %d.%d\n", _glxwin.major, _glxwin.minor);
00264     
00265 #ifdef LOGLEVEL
00266     if (glXIsDirect(_xwin.display, _glxwin.ctx)) {
00267         AGL_LOG(1, "GLX Direct Rendering is enabled\n\n");
00268     }
00269     else {
00270         AGL_LOG(1, "GLX Direct Rendering is disabled\n\n");
00271     }
00272 #endif
00273 
00274     /* Prints out GLX extensions info */
00275     AGL_LOG(1, "glX Extensions :\n");
00276 #ifdef LOGLEVEL
00277     __allegro_gl_print_extensions(
00278         (AL_CONST char*)glXQueryExtensionsString(_xwin.display, _xwin.screen));
00279 #endif
00280     /* Prints out OpenGL extensions info and activates needed extensions */
00281     __allegro_gl_manage_extensions();
00282     
00283     /* Update screen vtable in order to use AGL's */
00284     __allegro_gl__glvtable_update_vtable (&allegro_gl_screen->vtable);
00285     __allegro_gl_init_screen_mode();
00286     memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
00287     allegro_gl_screen->vtable = &_screen_vtable;
00288 
00289     if (_keyboard_was_installed) {
00290         install_keyboard();
00291         TRACE("* Note * x_create_screen: Installing Keyboard...\n");
00292     }
00293 
00294     if (_mouse_was_installed) {
00295         install_mouse();
00296         TRACE("* Note * x_create_screen: Installing Mouse...\n");
00297     }
00298     gfx_capabilities |= GFX_HW_CURSOR;
00299 
00300     return allegro_gl_screen;
00301 
00302 failure:
00303     if (_keyboard_was_installed) {
00304         install_keyboard();
00305     }
00306 
00307     if (_mouse_was_installed) {
00308         install_mouse();
00309     }
00310 
00311     return NULL;
00312 }
00313 
00314 
00315 
00316 /* allegro_gl_x_windowed_init:
00317  *  Creates screen bitmap for windowed driver.
00318  */
00319 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
00320                                           int depth)
00321 {
00322     return allegro_gl_x_create_screen(w, h, vw, vh, depth, FALSE);
00323 }
00324 
00325 
00326 
00327 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00328 /* allegro_gl_x_fullscreen_init:
00329  *  Creates screen bitmap for fullscreen driver.
00330  */
00331 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
00332                                             int depth)
00333 {
00334     return allegro_gl_x_create_screen(w, h, vw, vh, depth, TRUE);
00335 }
00336 
00337 
00338 
00339 /* free_modelines:
00340  *  Free mode lines.
00341  */
00342 static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes)
00343 {
00344    int i;
00345 
00346    for (i = 0; i < num_modes; i++)
00347       if (modesinfo[i]->privsize > 0)
00348      XFree(modesinfo[i]->private);
00349    XFree(modesinfo);
00350 }
00351 #endif
00352 
00353 
00354 
00355 /* allegro_gl_x_exit:
00356  *  Shuts down the driver (shared between windowed and full-screen)
00357  */
00358 static void allegro_gl_x_exit(BITMAP *bmp)
00359 {
00360 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00361     XSetWindowAttributes setattr;
00362 #endif
00363 
00364     /* We politely wait for OpenGL to finish its current operations before
00365        shutting down the driver */
00366     glXWaitGL();
00367     XLOCK();
00368 
00369     __allegro_gl_unmanage_extensions(); 
00370 
00371     if (_glxwin.ctx) {
00372         if (!allegro_gl_info.is_ati_r200_chip) {
00373             /* The DRI drivers for ATI cards with R200 chip
00374              * seem to be broken since they crash at this point.
00375              * As a workaround AGL does not release the GLX context
00376              * here. This should not hurt since the GLX specs don't
00377              * require the context to be released before the program
00378              * ends or before another context is made current to the
00379              * thread.
00380              */
00381             if (!glXMakeCurrent(_xwin.display, None, NULL)) {
00382                 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
00383                           get_config_text ("Could not release drawing context.\n"));
00384             }
00385         }
00386 
00387         glXDestroyContext(_xwin.display, _glxwin.ctx);
00388         _glxwin.ctx = NULL;
00389     }
00390 
00391     if (_xwin.mouse_grabbed) {
00392         XUngrabPointer(_xwin.display, CurrentTime);
00393         _xwin.mouse_grabbed = 0;
00394     }
00395 
00396     if (_xwin.keyboard_grabbed) {
00397         XUngrabKeyboard(_xwin.display, CurrentTime);
00398         _xwin.keyboard_grabbed = 0;
00399     }
00400 
00401 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00402     if (_glxwin.fullscreen) {
00403         if (_xwin.mode_switched) {
00404             XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
00405             XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
00406                                     _xwin.modesinfo[0]);
00407             XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
00408             _xwin.mode_switched = 0;
00409         }
00410         if (_xwin.override_redirected) {
00411             setattr.override_redirect = False;
00412             XChangeWindowAttributes(_xwin.display, _xwin.window,
00413                                     CWOverrideRedirect, &setattr);
00414             _xwin.override_redirected = 0;
00415         }
00416 
00417         /* Free modelines.  */
00418         free_modelines(_xwin.modesinfo, _xwin.num_modes);
00419         _xwin.num_modes = 0;
00420         _xwin.modesinfo = NULL;
00421     }
00422 #endif
00423     __allegro_gl_release_screen();
00424     
00425     /* Unmap the window in order not to see the cursor when quitting.
00426        The window *must not* be destroyed and _xwin.visual must be left
00427        to its current value otherwise the program will crash when exiting */
00428     XUnmapWindow(_xwin.display, _xwin.window);
00429 
00430     __allegro_gl_valid_context = FALSE;
00431 
00432     _xwin_window_redrawer = old_window_redrawer;
00433     XSetErrorHandler(old_x_error_handler);
00434     
00435     XUNLOCK();
00436 }
00437 
00438 
00439 
00440 /* windowed_choose_visual:
00441  *  Chooses a visual to use.
00442  */
00443 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void)
00444 {
00445     int num_visuals, i;
00446     XVisualInfo *vinfo;
00447     struct allegro_gl_display_info dinfo;
00448     static XVisualInfo ret_vinfo;
00449 
00450     vinfo = XGetVisualInfo (_xwin.display, 0, NULL, &num_visuals);
00451     if (!vinfo) return NULL;
00452     
00453     TRACE("* Note * x_windowed_choose_visual: %i formats.\n", num_visuals);
00454     __allegro_gl_reset_scorer();
00455 
00456     for (i = 0; i < num_visuals; i++) {
00457         TRACE("* Note * x_windowed_choose_visual: Mode %i\n", i);
00458         if (decode_visual (vinfo + i, &dinfo) != -1) {
00459             __allegro_gl_score_config (i, &dinfo);
00460         }
00461     }
00462 
00463     i = __allegro_gl_best_config();
00464     TRACE("* Note * x_windowed_choose_visual: Best config is: %i\n", i);
00465 
00466     if (i < 0) return NULL;
00467 
00468     memcpy (&ret_vinfo, vinfo+i, sizeof ret_vinfo);
00469     XFree (vinfo);
00470 
00471     return &ret_vinfo;
00472 }
00473 
00474 
00475 
00476 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00477 /* get_xf86_modes:
00478  *  Test if the XF86VidMode extension is available and get the gfx modes
00479  *  that can be queried.
00480  */
00481 static int get_xf86_modes(XF86VidModeModeInfo ***modesinfo, int *num_modes)
00482 {
00483     int vid_event_base, vid_error_base;
00484     int vid_major_version, vid_minor_version;
00485 
00486     /* Test for presence of VidMode extension.  */
00487     if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base,
00488                                    &vid_error_base)
00489      || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version,
00490                                  &vid_minor_version)) {
00491 
00492         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00493                   get_config_text("VidMode extension is not supported"));
00494         return -1;
00495     }
00496 
00497     if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, num_modes,
00498                                     modesinfo)) {
00499         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00500                   get_config_text("Can not Get ModeLines"));
00501         return -1;
00502     }
00503 
00504     return 0;
00505 }
00506 #endif
00507 
00508 
00509 static int allegro_gl_x_error_handler(Display *display, XErrorEvent *err_event)
00510 {
00511     char buffer[256];
00512 
00513     XGetErrorText(display, err_event->error_code, buffer, 256);
00514     TRACE("X Error caught : %s\n", buffer);
00515     return 0;
00516 }
00517 
00518 
00519 
00520 /* create_window:
00521  *  Based on Michael's `_xwin[_private]_create_window' and the xdemos
00522  *  from the Mesa distribution (I don't remember which one).
00523  */
00524 static int allegro_gl_x_create_window (int fullscreen)
00525 {
00526     Window root;
00527     XVisualInfo *visinfo;
00528     XSetWindowAttributes setattr;
00529     unsigned long valuemask = CWBackPixel | CWBorderPixel | CWColormap
00530                             | CWEventMask;
00531     XSizeHints *hints;
00532 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00533     int bestmode=0; 
00534 #endif
00535  
00536     if (_xwin.display == 0) {
00537         return -1;
00538     }
00539 
00540     old_x_error_handler = XSetErrorHandler(allegro_gl_x_error_handler);
00541 
00542     /* Fill in missing color depth info */
00543     __allegro_gl_fill_in_info();
00544 
00545 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00546     if (fullscreen) {
00547         int i;
00548         _xwin.num_modes = 0;
00549         _xwin.modesinfo = NULL;
00550         _glxwin.fullscreen = TRUE;
00551 
00552         if (get_xf86_modes(&_xwin.modesinfo, &_xwin.num_modes)) {
00553             TRACE("** ERROR ** x_create_window: Can't get XF86VidMode info.\n");
00554             XSetErrorHandler(old_x_error_handler);
00555             return -1;
00556         }
00557 
00558         /* look for mode with requested resolution */
00559         for (i = 0; i < _xwin.num_modes; i++)
00560         {
00561             if ((_xwin.modesinfo[i]->hdisplay == allegro_gl_display_info.w)
00562              && (_xwin.modesinfo[i]->vdisplay == allegro_gl_display_info.h))
00563                 bestmode = i;
00564         }
00565     }
00566 #endif
00567 
00568     /* Find best visual */
00569     root = RootWindow (_xwin.display, _xwin.screen);
00570     visinfo = allegro_gl_x_windowed_choose_visual();
00571     if (!visinfo) {
00572         TRACE("** ERROR ** x_create_window: Can not get visual.\n");
00573         XSetErrorHandler(old_x_error_handler);
00574         return -1;
00575     }
00576 
00577     /* Query back visual components */
00578     if (decode_visual (visinfo, &allegro_gl_display_info)) {
00579         TRACE("** ERROR ** x_create_window: Can not decode visual.\n");
00580         XSetErrorHandler(old_x_error_handler);
00581         return -1;
00582     }
00583     
00584 
00585     /* Log some information about it */
00586     switch (visinfo->class) {
00587         case TrueColor:
00588             AGL_LOG (1, "x.c: visual class: TrueColor\n");
00589             break;
00590         case DirectColor:
00591             AGL_LOG (1, "x.c: visual class: DirectColor\n");
00592             break;
00593         default:
00594             AGL_LOG (1, "x.c: visual class: invalid(!)\n");
00595     }
00596 
00597 
00598     /* Recreate window. */
00599     setattr.background_pixel = XBlackPixel (_xwin.display, _xwin.screen);
00600     setattr.border_pixel = XBlackPixel (_xwin.display, _xwin.screen);
00601     setattr.colormap = XCreateColormap (_xwin.display, root, visinfo->visual, AllocNone);
00602     setattr.event_mask =
00603         ( KeyPressMask | KeyReleaseMask
00604         | EnterWindowMask | LeaveWindowMask
00605         | FocusChangeMask | ExposureMask
00606         | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
00607         /*| MappingNotifyMask (SubstructureRedirectMask?)*/
00608     );
00609 
00610 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00611     if (fullscreen) {
00612         setattr.override_redirect = True;
00613         if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
00614                                      _xwin.modesinfo[bestmode])) {
00615 
00616             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00617                       get_config_text("Can not set XF86VidMode mode"));
00618             XSetErrorHandler(old_x_error_handler);
00619             return -1;
00620         }
00621 
00622         XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
00623 
00624         /* Lock Mode switching */
00625         XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
00626         _xwin.mode_switched = 1;
00627 
00628         allegro_gl_display_info.x = 0;
00629         allegro_gl_display_info.y = 0;
00630         allegro_gl_display_info.w = _xwin.modesinfo[bestmode]->hdisplay;
00631         allegro_gl_display_info.h = _xwin.modesinfo[bestmode]->vdisplay;
00632             
00633         valuemask |= CWOverrideRedirect;
00634         _xwin.override_redirected = 1;
00635     }
00636 #endif
00637     
00638     XDestroyWindow (_xwin.display, _xwin.window);
00639 
00640     _xwin.window = XCreateWindow (
00641         _xwin.display, root,
00642         allegro_gl_display_info.x, allegro_gl_display_info.y,
00643         allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
00644         visinfo->depth,
00645         InputOutput,
00646         visinfo->visual,
00647         valuemask, &setattr
00648     );
00649 
00650     /* Set size and position hints for Window Manager :
00651      * prevents the window to be resized
00652      */
00653     hints = XAllocSizeHints();
00654     if (hints) {
00655         /* This code chunk comes from Allegro's src/x/xwin.c */
00656         hints->flags = PMinSize | PMaxSize | PBaseSize;
00657         hints->min_width  = hints->max_width  = hints->base_width
00658                           = allegro_gl_display_info.w;
00659         hints->min_height = hints->max_height = hints->base_height
00660                           = allegro_gl_display_info.h;
00661 
00662         XSetWMNormalHints(_xwin.display, _xwin.window, hints);
00663         XFree(hints);
00664     }
00665 
00666     /* Finish off the GLX setup */
00667     _glxwin.ctx = glXCreateContext (_xwin.display, visinfo, NULL, True);
00668     if (!_glxwin.ctx) {
00669         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00670                   get_config_text("Can not create GLX context."));
00671         XSetErrorHandler(old_x_error_handler);
00672         return -1;
00673     }
00674     else {
00675         if (!glXMakeCurrent (_xwin.display, _xwin.window, _glxwin.ctx)) {
00676             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00677                       get_config_text("Can not make GLX context current."));
00678             XSetErrorHandler(old_x_error_handler);
00679             return -1;
00680         }
00681     }
00682 
00683 
00684     /* Finish off the Allegro setup */
00685 
00686     /* Get associated visual and window depth (bits per pixel), and
00687      * store window size  */
00688     {
00689         XWindowAttributes getattr;
00690         XGetWindowAttributes(_xwin.display, _xwin.window, &getattr);
00691         _xwin.visual = getattr.visual;
00692         _xwin.window_depth = getattr.depth;
00693         _xwin.window_width = allegro_gl_display_info.w;
00694         _xwin.window_height = allegro_gl_display_info.h;
00695         _xwin.screen_depth = getattr.depth;
00696         _xwin.screen_width = allegro_gl_display_info.w;
00697         _xwin.screen_height = allegro_gl_display_info.h;
00698     }
00699 
00700     /* Destroy the current colormap (if any) */
00701     if (_xwin.colormap != None) {
00702         XUninstallColormap(_xwin.display, _xwin.colormap);
00703         XFreeColormap(_xwin.display, _xwin.colormap);
00704     }
00705 
00706     /* Create and install colormap.  */
00707     if (_xwin.visual->class == DirectColor) {
00708         _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
00709                                          _xwin.visual, AllocAll);
00710     }
00711     else { /* must be TrueColor */
00712         _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
00713                                          _xwin.visual, AllocNone);
00714     }
00715     XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap);
00716     XInstallColormap(_xwin.display, _xwin.colormap);
00717 
00718     /* Setup a palette if needed */
00719     if (_xwin.visual->class == DirectColor) {
00720         XColor color;
00721         int rsize, gsize, bsize;
00722         int rmax, gmax, bmax;
00723         int rshift, gshift, bshift;
00724         int r, g, b;
00725 
00726         AGL_LOG (1, "x.c: Using DirectColor visual, setting palette...\n");
00727 
00728         rsize = 1 << allegro_gl_display_info.pixel_size.rgba.r;
00729         gsize = 1 << allegro_gl_display_info.pixel_size.rgba.g;
00730         bsize = 1 << allegro_gl_display_info.pixel_size.rgba.b;
00731 
00732         rshift = allegro_gl_display_info.r_shift;
00733         bshift = allegro_gl_display_info.b_shift;
00734         gshift = allegro_gl_display_info.g_shift;
00735 
00736         rmax = rsize - 1;
00737         gmax = gsize - 1;
00738         bmax = bsize - 1;
00739 
00740         color.flags = DoRed | DoGreen | DoBlue;
00741         for (r = 0; r < rsize; r++) {
00742             for (g = 0; g < gsize; g++) {
00743                 for (b = 0; b < bsize; b++) {
00744                     color.pixel = (r << rshift) | (g << gshift) | (b << bshift);
00745                     color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax));
00746                     color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax));
00747                     color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax));
00748                     XStoreColor(_xwin.display, _xwin.colormap, &color);
00749                 }
00750             }
00751         }
00752     }
00753 
00754     /* Configure the window a bit */
00755     {
00756         XClassHint hint;
00757         XWMHints wm_hints;
00758 
00759         /* Set title.  */
00760         XStoreName(_xwin.display, _xwin.window, _xwin.window_title);
00761 
00762         /* Set hints.  */
00763         hint.res_name = _xwin.application_name;
00764         hint.res_class = _xwin.application_class;
00765         XSetClassHint(_xwin.display, _xwin.window, &hint);
00766 
00767         wm_hints.flags = InputHint | StateHint;
00768         wm_hints.input = True;
00769         wm_hints.initial_state = NormalState;
00770         XSetWMHints(_xwin.display, _xwin.window, &wm_hints);
00771     }
00772 
00773 
00774     /* Map window.  */
00775     XMapWindow(_xwin.display, _xwin.window);
00776 
00777 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
00778     if (fullscreen) {
00779         AL_CONST char *fc = NULL;
00780         char tmp1[64], tmp2[128];
00781         int c = 0;
00782         int h = allegro_gl_display_info.h;
00783         int w = allegro_gl_display_info.w;
00784         
00785         /* This chunk is disabled by default because of problems on KDE
00786            desktops.  */
00787         fc = get_config_string(uconvert_ascii("graphics", tmp1),
00788             uconvert_ascii("force_centering", tmp2), NULL);
00789         if ((fc) && ((c = ugetc(fc)) != 0) && ((c == 'y') || (c == 'Y')
00790             || (c == '1'))) {
00791             /* Hack: make the window fully visible and center cursor.  */
00792             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0);
00793             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
00794                          w - 1, 0);
00795             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
00796                          0, h - 1);
00797             XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
00798                          w - 1, h - 1);
00799         }
00800         XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
00801                      w / 2, h / 2);
00802         XSync(_xwin.display, False);
00803         
00804         /* Grab keyboard and mouse.  */
00805         if (XGrabKeyboard(_xwin.display, _xwin.window, False, GrabModeAsync,
00806             GrabModeAsync, CurrentTime) != GrabSuccess) {
00807             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00808                       get_config_text("Can not grab keyboard"));
00809             XSetErrorHandler(old_x_error_handler);
00810             return -1;
00811         }
00812         _xwin.keyboard_grabbed = 1;
00813         
00814         if (XGrabPointer(_xwin.display, _xwin.window, False, 
00815             PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
00816             GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime)
00817          != GrabSuccess) {
00818 
00819             ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00820                       get_config_text("Can not grab mouse"));
00821             XSetErrorHandler(old_x_error_handler);
00822             return -1;
00823         }
00824         _xwin.mouse_grabbed = 1;
00825     }
00826 #endif
00827 
00828 
00829     /* Destroy current cursor (if any) */
00830     if (_xwin.cursor != None) {
00831         XUndefineCursor(_xwin.display, _xwin.window);
00832         XFreeCursor(_xwin.display, _xwin.cursor);
00833     }
00834 
00835     {
00836         /* Create invisible X cursor.  */
00837         Pixmap pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
00838         if (pixmap != None) {
00839             GC temp_gc;
00840             XColor color;
00841             XGCValues gcvalues;
00842 
00843             int gcmask = GCFunction | GCForeground | GCBackground;
00844             gcvalues.function = GXcopy;
00845             gcvalues.foreground = 0;
00846             gcvalues.background = 0;
00847             temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
00848             XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
00849             XFreeGC(_xwin.display, temp_gc);
00850             color.pixel = 0;
00851             color.red = color.green = color.blue = 0;
00852             color.flags = DoRed | DoGreen | DoBlue;
00853             _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap,
00854                                                &color, &color, 0, 0);
00855             XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
00856             XFreePixmap(_xwin.display, pixmap);
00857         }
00858         else {
00859             _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
00860             XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
00861         }
00862     }
00863 
00864     /* Wait for the first exposure event.  */
00865     {
00866         XEvent event;
00867         do {
00868             XNextEvent(_xwin.display, &event);
00869         } while ((event.type != Expose) || (event.xexpose.count != 0));
00870     }
00871 
00872     return 0;
00873 }
00874 
00875 
00876 
00877 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth)
00878 {
00879     BITMAP *bmp;
00880     int is_linear = drv->linear;
00881 
00882     drv->linear = 1;
00883     bmp = _make_bitmap (w, h, 0, drv, depth, 0);
00884     bmp->id = BMP_ID_VIDEO | BMP_ID_MASK;
00885     drv->linear = is_linear;
00886 
00887     if (bmp == 0) {
00888         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00889                   get_config_text("Not enough memory"));
00890         return NULL;
00891     }
00892     
00893     drv->w = w;
00894     drv->h = h;
00895 
00896     return bmp;
00897 }
00898 
00899 
00900 
00901 /* get_shift:
00902  *  Returns the shift value for a given mask.
00903  */
00904 static int get_shift (int mask)
00905 {
00906     int i = 0, j = 1;
00907     if (!mask) return -1;
00908     while (!(j & mask)) {
00909         i++;
00910         j <<= 1;
00911     }
00912     return i;
00913 }
00914 
00915 
00916 
00917 /* decode_visual:
00918  *  Used to read back the information in the visual.  0 = ok.
00919  */
00920 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i)
00921 {
00922     int rgba, buffer_size, use_gl, sbuffers, samples;
00923 
00924     TRACE("* Note * decode_visual: Decoding:\n");
00925     i->rmethod = 2;
00926 
00927     /* We can only support TrueColor and DirectColor visuals --
00928      * we only support RGBA mode */
00929     if (v->class != TrueColor && v->class != DirectColor)
00930         return -1;
00931 
00932     if (glXGetConfig (_xwin.display, v, GLX_RGBA, &rgba)
00933      || glXGetConfig (_xwin.display, v, GLX_USE_GL,       &use_gl)
00934      || glXGetConfig (_xwin.display, v, GLX_BUFFER_SIZE,  &buffer_size)
00935      || glXGetConfig (_xwin.display, v, GLX_RED_SIZE,     &i->pixel_size.rgba.r)
00936      || glXGetConfig (_xwin.display, v, GLX_GREEN_SIZE,   &i->pixel_size.rgba.g)
00937      || glXGetConfig (_xwin.display, v, GLX_BLUE_SIZE,    &i->pixel_size.rgba.b)
00938      || glXGetConfig (_xwin.display, v, GLX_ALPHA_SIZE,   &i->pixel_size.rgba.a)
00939      || glXGetConfig (_xwin.display, v, GLX_DOUBLEBUFFER, &i->doublebuffered)
00940      || glXGetConfig (_xwin.display, v, GLX_STEREO,       &i->stereo)
00941      || glXGetConfig (_xwin.display, v, GLX_AUX_BUFFERS,  &i->aux_buffers)
00942      || glXGetConfig (_xwin.display, v, GLX_DEPTH_SIZE,   &i->depth_size)
00943      || glXGetConfig (_xwin.display, v, GLX_STENCIL_SIZE, &i->stencil_size)
00944      || glXGetConfig (_xwin.display, v, GLX_ACCUM_RED_SIZE,
00945                       &i->accum_size.rgba.r)
00946      || glXGetConfig (_xwin.display, v, GLX_ACCUM_GREEN_SIZE,
00947                       &i->accum_size.rgba.g)
00948      || glXGetConfig (_xwin.display, v, GLX_ACCUM_BLUE_SIZE,
00949                       &i->accum_size.rgba.b)
00950      || glXGetConfig (_xwin.display, v, GLX_ACCUM_ALPHA_SIZE,
00951                       &i->accum_size.rgba.a)) {
00952         TRACE("* Note * x_create_window: Incomplete glX mode ...\n");
00953         return -1;
00954     }
00955 
00956     if (!rgba) {
00957         TRACE("* Note * x_create_window: Not RGBA mode\n");
00958         return -1;
00959     }
00960     
00961     if (!use_gl) {
00962         ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
00963                   get_config_text("OpenGL Unsupported"));
00964         return -1;
00965     }
00966     
00967     i->r_shift = get_shift (v->red_mask);
00968     i->g_shift = get_shift (v->green_mask);
00969     i->b_shift = get_shift (v->blue_mask);
00970     i->a_shift = 0;
00971     
00972     /* If we are going to need to setup a palette we need bit shifts */
00973     if ((v->class == DirectColor)
00974         && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
00975         && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
00976            <= 12)) {
00977         /* XXX <rohannessian> Report something here? */
00978         return -1;
00979     }
00980 
00981 
00982     i->colour_depth = 0;
00983 
00984     if (i->pixel_size.rgba.r == 3
00985      && i->pixel_size.rgba.g == 3
00986      && i->pixel_size.rgba.b == 2) {
00987         i->colour_depth = 8;
00988     }
00989 
00990     if (i->pixel_size.rgba.r == 5
00991      && i->pixel_size.rgba.b == 5) {
00992         if (i->pixel_size.rgba.g == 5) {
00993             i->colour_depth = 15;
00994         }
00995         if (i->pixel_size.rgba.g == 6) {
00996             i->colour_depth = 16;
00997         }
00998     }
00999 
01000     if (i->pixel_size.rgba.r == 8
01001      && i->pixel_size.rgba.g == 8
01002      && i->pixel_size.rgba.b == 8) {
01003         if (i->pixel_size.rgba.a == 0) {
01004             i->colour_depth = 24;
01005         }
01006         if (i->pixel_size.rgba.a == 8) {
01007             i->colour_depth = 32;
01008             /* small hack that tries to guess alpha shifting */
01009             i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
01010         }
01011     }
01012 
01013     i->allegro_format = (i->colour_depth != 0)
01014                      && (i->g_shift == i->pixel_size.rgba.b)
01015                      && (i->r_shift * i->b_shift == 0)
01016                      && (i->r_shift + i->b_shift
01017                                 == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
01018     
01019     if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)
01020                                                          == GLX_BAD_ATTRIBUTE) {
01021         /* Multisample extension is not supported */
01022         i->sample_buffers = 0;
01023     }
01024     else {
01025         i->sample_buffers = sbuffers;
01026     }
01027     if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)
01028                                                          == GLX_BAD_ATTRIBUTE) {
01029         /* Multisample extension is not supported */
01030         i->samples = 0;
01031     }
01032     else {
01033         i->samples = samples;
01034     }
01035 
01036     
01037     TRACE("\tColor Depth: %i ", buffer_size);
01038     TRACE("RGBA: %i.%i.%i.%i ", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
01039           i->pixel_size.rgba.b, i->pixel_size.rgba.a);
01040     TRACE("Accum: %i.%i.%i.%i\n\t", i->accum_size.rgba.r, i->accum_size.rgba.g,
01041           i->accum_size.rgba.b, i->accum_size.rgba.a);
01042     TRACE("DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i ",
01043           i->doublebuffered, i->depth_size, i->stereo,
01044           i->aux_buffers, i->stencil_size);
01045     TRACE("Shift: %i.%i.%i.%i\n\t", i->r_shift, i->g_shift, i->b_shift,
01046           i->a_shift);
01047     TRACE("Sample Buffers: %i Samples: %i\n\t", i->sample_buffers, i->samples);
01048     TRACE("Decoded bpp: %i\n", i->colour_depth);
01049     
01050     return 0;
01051 }
01052 
01053 
01054 
01055 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
01056 /* allegro_gl_x_fetch_mode_list:
01057  *  Generates a list of valid video modes (made after 
01058  *  _xvidmode_private_fetch_mode_list of Allegro)
01059  */
01060 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void)
01061 {
01062     int num_modes = 0;
01063     XF86VidModeModeInfo **modesinfo = NULL;
01064     GFX_MODE_LIST *mode_list;
01065     int i;
01066 
01067     XLOCK();
01068 
01069     if (get_xf86_modes(&modesinfo, &num_modes)) {
01070         XUNLOCK();
01071         return NULL;
01072     }
01073 
01074     /* Allocate space for mode list.  */
01075     mode_list = malloc(sizeof(GFX_MODE_LIST));
01076     if (!mode_list) {
01077         free_modelines(modesinfo, num_modes);
01078         XUNLOCK();
01079         return NULL;
01080     }
01081 
01082     mode_list->mode = malloc(sizeof(GFX_MODE) * (num_modes + 1));
01083     if (!mode_list->mode) {
01084         free(mode_list);
01085         free_modelines(modesinfo, num_modes);
01086         XUNLOCK();
01087         return NULL;
01088     }
01089 
01090     /* Fill in mode list.  */
01091     for (i = 0; i < num_modes; i++) {
01092         mode_list->mode[i].width = modesinfo[i]->hdisplay;
01093         mode_list->mode[i].height = modesinfo[i]->vdisplay;
01094         /* Since XF86VidMode can not change the color depth of
01095          * the screen, there is no need to define modes for other
01096          * color depth than the desktop's.
01097          */
01098         mode_list->mode[i].bpp = desktop_color_depth();
01099     }
01100 
01101     mode_list->mode[num_modes].width = 0;
01102     mode_list->mode[num_modes].height = 0;
01103     mode_list->mode[num_modes].bpp = 0;
01104     mode_list->num_modes = num_modes;
01105 
01106     free_modelines(modesinfo, num_modes);
01107 
01108     XUNLOCK();
01109     return mode_list;
01110 }
01111 #endif
01112 
01113 
01114 
01115 /* allegro_gl_x_vsync:
01116  *  Wait for a vertical retrace. GLX_SGI_video_sync is needed.
01117  */
01118 static void allegro_gl_x_vsync(void)
01119 {
01120     if (allegro_gl_extensions_GLX.SGI_video_sync) {
01121         unsigned int count;
01122 
01123         glXGetVideoSyncSGI(&count);
01124         glXWaitVideoSyncSGI(2, (count+1) & 1, &count);
01125     }
01126 }
01127 
01128 
01129 
01130 /******************************/
01131 /* AllegroGL driver functions */
01132 /******************************/
01133 
01134 /* flip:
01135  *  Does a page flip / double buffer copy / whatever it really is.
01136  */
01137 static void flip (void)
01138 {
01139     glXSwapBuffers (_xwin.display, _xwin.window);
01140 }
01141 
01142 
01143 
01144 /* gl_on, gl_off:
01145  *  Switches to/from GL mode.
01146  */
01147 static void gl_on (void)
01148 {
01149 #ifdef OLD_ALLEGRO
01150     DISABLE();
01151 #endif
01152 }
01153 
01154 
01155 
01156 static void gl_off (void)
01157 {
01158 #ifdef OLD_ALLEGRO
01159     ENABLE();
01160     _xwin_handle_input();
01161 #endif
01162 }
01163 
01164 
01165 
01166 /*****************/
01167 /* Driver struct */
01168 /*****************/
01169 
01170 static struct allegro_gl_driver allegro_gl_x = {
01171     flip,
01172     gl_on,
01173     gl_off,
01174     NULL
01175 };
01176 

Generated on Wed Jun 30 23:59:52 2004 for AllegroGL by doxygen 1.3.5