//************************************************************************** //** //** ## ## ## ## ## #### #### ### ### //** ## ## ## ## ## ## ## ## ## ## #### #### //** ## ## ## ## ## ## ## ## ## ## ## ## ## ## //** ## ## ######## ## ## ## ## ## ## ## ### ## //** ### ## ## ### ## ## ## ## ## ## //** # ## ## # #### #### ## ## //** //** $Id: gl_x.cpp 1838 2006-10-31 21:00:59Z dj_jl $ //** //** Copyright (C) 1999-2006 Jānis Legzdiņš //** //** This program is free software; you can redistribute it and/or //** modify it under the terms of the GNU General Public License //** as published by the Free Software Foundation; either version 2 //** of the License, or (at your option) any later version. //** //** This program is distributed in the hope that it will be useful, //** but WITHOUT ANY WARRANTY; without even the implied warranty of //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //** GNU General Public License for more details. //** //************************************************************************** //** //** OpenGL driver for X-Windows //** //************************************************************************** // HEADER FILES ------------------------------------------------------------ #include #include #include #include "gl_local.h" #include #if defined(ALLEGRO_XWINDOWS_WITH_XF86DGA) || \ defined(ALLEGRO_XWINDOWS_WITH_XF86DGA2) #define USE_FULLSCREEN #include #endif // MACROS ------------------------------------------------------------------ // TYPES ------------------------------------------------------------------- class VAllgeroOpenGLDrawer : public VOpenGLDrawer { public: Display* RenderDisplay; int RenderScreen; Window RenderWindow; GLXContext RenderContext; #ifdef USE_FULLSCREEN bool vidmode_ext; XF86VidModeModeInfo** vidmodes; int num_vidmodes; bool vidmode_active; bool dgamouse; #endif void Init(); bool SetResolution(int, int, int, bool); void* GetExtFuncPtr(const char*); void Update(); void Shutdown(); }; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- IMPLEMENT_DRAWER(VAllegroOpenGLDrawer, DRAWER_OpenGL, "OpenGL", "Allegro OpenGL rasteriser device", "-opengl"); // PRIVATE DATA DEFINITIONS ------------------------------------------------ // CODE -------------------------------------------------------------------- //========================================================================== // // VAllgeroOpenGLDrawer::Init // // Determine the hardware configuration // //========================================================================== void VAllgeroOpenGLDrawer::Init() { RenderDisplay = NULL; RenderScreen = 0; RenderWindow = NULL; RenderContext = NULL; #ifdef USE_FULLSCREEN vidmode_ext = false; vidmodes = NULL; num_vidmodes = 0; vidmode_active = false; dgamouse = false; #endif } //========================================================================== // // VAllgeroOpenGLDrawer::SetResolution // // Set up the video mode // //========================================================================== bool VAllgeroOpenGLDrawer::SetResolution(int AWidth, int AHeight, int ABPP, bool Windowed) { guard(VAllgeroOpenGLDrawer::SetResolution); int Width = AWidth; int Height = AHeight; int BPP = ABPP; bool default_mode = false; if (!Width || !Height) { // Set defaults Width = 640; Height = 480; BPP = 16; default_mode = true; } if (BPP == 15) BPP = 16; if (BPP < 16) { // True-colour only GCon->Log(NAME_Init, "Attempt to set a paletized video mode for OpenGL"); return false; } // Shut down current mode Shutdown(); int attrib1[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None }; int attrib2[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None }; int *attrib = BPP < 24 ? attrib1 : attrib2; XSetWindowAttributes attr; unsigned long mask; Window root; XVisualInfo *visinfo; XLOCK(); RenderDisplay = _xwin.display; if (!RenderDisplay) { GCon->Log(NAME_Init, "No display - Allegro X-Windows driver not initialised"); XUNLOCK(); return false; } RenderScreen = _xwin.screen; root = RootWindow(RenderDisplay, RenderScreen); #ifdef USE_FULLSCREEN // Get video mode list int MajorVersion, MinorVersion; MajorVersion = MinorVersion = 0; if (!XF86VidModeQueryVersion(RenderDisplay, &MajorVersion, &MinorVersion)) { vidmode_ext = false; } else { GCon->Logf(NAME_Init, "Using XFree86-VidModeExtension Version %d.%d", MajorVersion, MinorVersion); vidmode_ext = true; } #endif visinfo = glXChooseVisual(RenderDisplay, RenderScreen, attrib); if (!visinfo) { GCon->Log(NAME_Init, "Failed to choose visual"); XUNLOCK(); return false; } #ifdef USE_FULLSCREEN if (vidmode_ext && !Windowed) { int best_fit; XF86VidModeGetAllModeLines(RenderDisplay, RenderScreen, &num_vidmodes, &vidmodes); // Let's change video mode best_fit = -1; int i; for (i = 0; i < num_vidmodes; i++) { if (Width != vidmodes[i]->hdisplay || Height != vidmodes[i]->vdisplay) continue; best_fit = i; } if (best_fit != -1) { // change to the mode XF86VidModeSwitchToMode(RenderDisplay, RenderScreen, vidmodes[best_fit]); vidmode_active = true; // Move the viewport to top left XF86VidModeSetViewPort(RenderDisplay, RenderScreen, 0, 0); } else if (!default_mode) { // No such mode, if we are trying to set default mode, // we will use windowed mode, otherwise complain. GCon->Log(NAME_Init, "No such video mode"); XUNLOCK(); return false; } } #endif /* window attributes */ attr.background_pixel = 0; attr.border_pixel = 0; attr.colormap = XCreateColormap(RenderDisplay, root, visinfo->visual, AllocNone); attr.event_mask = ( KeyPressMask | KeyReleaseMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask /*| MappingNotifyMask (SubstructureRedirectMask?)*/ ); #ifdef USE_FULLSCREEN if (vidmode_active) { mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | CWEventMask | CWOverrideRedirect; attr.override_redirect = True; attr.backing_store = NotUseful; attr.save_under = False; } else #endif { mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; } if (_xwin.window) { XDestroyWindow(_xwin.display, _xwin.window); _xwin.window = 0; } RenderWindow = XCreateWindow(RenderDisplay, root, 0, 0, Width, Height, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); _xwin.window = RenderWindow; // Set title. XStoreName(RenderDisplay, RenderWindow, "Vavoom"); XMapWindow(RenderDisplay, RenderWindow); #ifdef USE_FULLSCREEN if (vidmode_active) { XMoveWindow(RenderDisplay, RenderWindow, 0, 0); XRaiseWindow(RenderDisplay, RenderWindow); XWarpPointer(RenderDisplay, None, RenderWindow, 0, 0, 0, 0, 0, 0); XFlush(RenderDisplay); // Move the viewport to top left XF86VidModeSetViewPort(RenderDisplay, RenderScreen, 0, 0); } #endif XFlush(RenderDisplay); RenderContext = glXCreateContext(RenderDisplay, visinfo, NULL, True); if (!RenderContext) { GCon->Log(NAME_Dev, "Failed to create OpenGL context"); XUNLOCK(); return false; } glXMakeCurrent(RenderDisplay, RenderWindow, RenderContext); // Create invisible X cursor. Pixmap cursormask; XGCValues xgc; GC gc; XColor dummycolour; Cursor cursor; cursormask = XCreatePixmap(RenderDisplay, RenderWindow, 1, 1, 1); if (cursormask) { xgc.function = GXclear; gc = XCreateGC(RenderDisplay, cursormask, GCFunction, &xgc); XFillRectangle(RenderDisplay, cursormask, gc, 0, 0, 1, 1); XFreeGC(RenderDisplay, gc); dummycolour.pixel = 0; dummycolour.red = 0; dummycolour.flags = 04; cursor = XCreatePixmapCursor(RenderDisplay, cursormask, cursormask, &dummycolour, &dummycolour, 0, 0); XFreePixmap(RenderDisplay, cursormask); XDefineCursor(RenderDisplay, RenderWindow, cursor); } #ifdef USE_FULLSCREEN if (XF86DGAQueryVersion(RenderDisplay, &MajorVersion, &MinorVersion)) { dgamouse = true; _xwin.in_dga_mode = 2; XF86DGADirectVideo(RenderDisplay, RenderScreen, XF86DGADirectMouse); XWarpPointer(RenderDisplay, None, RenderWindow, 0, 0, 0, 0, 0, 0); } else { // unable to query, probalby not supported GCon->Log(NAME_Init, "Failed to detect XF86DGA Mouse"); XWarpPointer(RenderDisplay, None, RenderWindow, 0, 0, 0, 0, Width / 2, Height / 2); } #else XWarpPointer(RenderDisplay, None, RenderWindow, 0, 0, 0, 0, Width / 2, Height / 2); #endif #ifdef USE_FULLSCREEN if (vidmode_active) { if (XGrabPointer(RenderDisplay, RenderWindow, True, 0, GrabModeAsync, GrabModeAsync, RenderWindow, None, CurrentTime) != GrabSuccess) { GCon->Log(NAME_Init, "Failed to grab mouse"); return false; } _xwin.mouse_grabbed = 1; if (XGrabKeyboard(RenderDisplay, RenderWindow, False, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { GCon->Log(NAME_Init, "Failed to grab keyboard"); return false; } _xwin.keyboard_grabbed = 1; } #endif ScreenWidth = Width; ScreenHeight = Height; ScreenBPP = BPP; XUNLOCK(); return true; unguard; } //========================================================================== // // VAllgeroOpenGLDrawer::GetExtFuncPtr // //========================================================================== void* VAllgeroOpenGLDrawer::GetExtFuncPtr(const char *name) { guard(VAllgeroOpenGLDrawer::GetExtFuncPtr); void* prjobj = dlopen(NULL, RTLD_LAZY); if (!prjobj) { GCon->Log(NAME_Init, "Unable to open symbol list for main program."); return NULL; } void* ptr = dlsym(prjobj, name); dlclose(prjobj); return ptr; unguard; } //========================================================================== // // VAllgeroOpenGLDrawer::Update // // Blit to the screen / Flip surfaces // //========================================================================== void VAllgeroOpenGLDrawer::Update() { guard(VAllgeroOpenGLDrawer::Update); glFlush(); glXSwapBuffers(RenderDisplay, RenderWindow); unguard; } //========================================================================== // // VAllgeroOpenGLDrawer::Shutdown // // Close the graphics // //========================================================================== void VAllgeroOpenGLDrawer::Shutdown() { guard(VAllgeroOpenGLDrawer::Shutdown); XLOCK(); DeleteTextures(); if (RenderDisplay) { if (RenderContext) { glXDestroyContext(RenderDisplay, RenderContext); RenderContext = NULL; } if (RenderWindow) { #ifdef USE_FULLSCREEN if (dgamouse) { dgamouse = false; _xwin.in_dga_mode = 0; XF86DGADirectVideo(RenderDisplay, RenderScreen, 0); } #endif XUndefineCursor(RenderDisplay, RenderWindow); // XDestroyWindow(RenderDisplay, RenderWindow); RenderWindow = 0; } if (_xwin.mouse_grabbed) { XUngrabPointer(_xwin.display, CurrentTime); _xwin.mouse_grabbed = 0; } if (_xwin.keyboard_grabbed) { XUngrabKeyboard(_xwin.display, CurrentTime); _xwin.keyboard_grabbed = 0; } #ifdef USE_FULLSCREEN if (vidmode_active) { XF86VidModeSwitchToMode(RenderDisplay, RenderScreen, vidmodes[0]); vidmode_active = false; } #endif RenderDisplay = NULL; } XUNLOCK(); unguard; }