fteqw/engine/gl/gl_vidlinuxglx.c
Spoike 9cd988a836 Added csqc->ssqc requests.
Fixed up cl_indepphysics. Sending is fully independent, bar sync points.
Fixed so #if 0 works in qc code.
Fixed up error conditions in qclib when features are not supported.
The webpage generator will now refcount properly.
Fixed error conditions when using glsl shaders.
If MULTITHREAD is defined, r_loadlit will not light inside a separate thread.
We now generate VBOs for bsp objects. Shaders/rtlights don't use them yet.
Fixed up MVD/multiview playback a bit. It now looks like it works! (cl_hightrack will no longer track the same person in all views).
Fixed error conditions when attempting to download versioned csprogs.
Reduced the number of places that a q3-style marked up string is expanded. I think there are a couple places left still though. Approximated ezquake colour codes.
Memory mapped read file access in win32, where we can. Not sure about this. Lets see how things pan out.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3195 fc73d0e0-1445-4013-8a0c-d673dee63da5
2009-05-24 10:11:17 +00:00

1137 lines
26 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#ifdef __linux__
#include <sys/vt.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <dlfcn.h>
#include "quakedef.h"
#include "glquake.h"
#include <GL/glx.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#ifdef USE_DGA
#include <X11/extensions/xf86dga.h>
#endif
#ifdef __linux__
#define WITH_VMODE //undefine this if the following include fails.
#endif
#ifdef WITH_VMODE
#include <X11/extensions/xf86vmode.h>
#endif
#define WARP_WIDTH 320
#define WARP_HEIGHT 200
#ifdef SWQUAKE
Display *vid_dpy = NULL;
#else
static Display *vid_dpy = NULL;
#endif
static Window vid_window;
static GLXContext ctx = NULL;
int scrnum;
static float old_windowed_mouse = 0;
#ifdef USE_DGA
static int dgamouse = 0;
#endif
#define KEY_MASK (KeyPressMask | KeyReleaseMask)
#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \
PointerMotionMask)
#define X_MASK (KEY_MASK | MOUSE_MASK | ResizeRequest | StructureNotifyMask | FocusChangeMask | VisibilityChangeMask)
#ifdef WITH_VMODE
static int vidmode_ext = 0;
static XF86VidModeModeInfo **vidmodes;
static int num_vidmodes;
static qboolean vidmode_active = false;
static int vidmode_usemode = -1; //so that it can be reset if they switch away.
unsigned short originalramps[3][256];
qboolean originalapplied; //states that the origionalramps arrays are valid, and contain stuff that we should revert to on close
#endif
extern cvar_t _windowed_mouse;
#ifndef SWQUAKE
cvar_t m_filter = {"m_filter", "0"};
cvar_t m_accel = {"m_accel", "0"};
#ifdef IN_XFLIP
cvar_t in_xflip = {"in_xflip", "0"};
#endif
static float mouse_x, mouse_y;
static float old_mouse_x, old_mouse_y;
#else
extern float mouse_x, mouse_y;
extern float old_mouse_x, old_mouse_y;
#endif
/*-----------------------------------------------------------------------*/
float gldepthmin, gldepthmax;
const char *gl_vendor;
const char *gl_renderer;
const char *gl_version;
const char *gl_extensions;
qboolean is8bit = false;
qboolean isPermedia = false;
qboolean mouseactive = false;
qboolean ActiveApp = false;
int gl_canstencil;
/*-----------------------------------------------------------------------*/
static void *gllibrary;
XVisualInfo* (*qglXChooseVisual) (Display *dpy, int screen, int *attribList);
void (*qglXSwapBuffers) (Display *dpy, GLXDrawable drawable);
Bool (*qglXMakeCurrent) (Display *dpy, GLXDrawable drawable, GLXContext ctx);
GLXContext (*qglXCreateContext) (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct);
void (*qglXDestroyContext) (Display *dpy, GLXContext ctx);
void *(*qglXGetProcAddress) (char *name);
void GLX_CloseLibrary(void)
{
dlclose(gllibrary);
gllibrary = NULL;
}
qboolean GLX_InitLibrary(char *driver)
{
if (driver && *driver)
gllibrary = dlopen(driver, RTLD_LAZY);
else
gllibrary = NULL;
if (!gllibrary) //I hate this.
gllibrary = dlopen("libGL.so.1", RTLD_LAZY);
if (!gllibrary)
gllibrary = dlopen("libGL.so", RTLD_LAZY);
if (!gllibrary)
return false;
qglXChooseVisual = dlsym(gllibrary, "glXChooseVisual");
qglXSwapBuffers = dlsym(gllibrary, "glXSwapBuffers");
qglXMakeCurrent = dlsym(gllibrary, "glXMakeCurrent");
qglXCreateContext = dlsym(gllibrary, "glXCreateContext");
qglXDestroyContext = dlsym(gllibrary, "glXDestroyContext");
qglXDestroyContext = dlsym(gllibrary, "glXDestroyContext");
qglXGetProcAddress = dlsym(gllibrary, "glXGetProcAddress");
if (!qglXGetProcAddress)
qglXGetProcAddress = dlsym(gllibrary, "glXGetProcAddressARB");
if (!qglXSwapBuffers && !qglXDestroyContext && !qglXCreateContext && !qglXMakeCurrent && !qglXChooseVisual)
return false;
return true;
}
void *GLX_GetSymbol(char *name)
{
void *symb;
if (qglXGetProcAddress)
symb = qglXGetProcAddress(name);
else
symb = NULL;
if (!symb)
symb = dlsym(gllibrary, name);
return symb;
}
void GLD_BeginDirectRect (int x, int y, qbyte *pbitmap, int width, int height)
{
}
void GLD_EndDirectRect (int x, int y, int width, int height)
{
}
static int XLateKey(XKeyEvent *ev)
{
int key;
char buf[64];
KeySym keysym;
key = 0;
XLookupString(ev, buf, sizeof buf, &keysym, 0);
switch(keysym)
{
case XK_KP_Page_Up:
case XK_Page_Up: key = K_PGUP; break;
case XK_KP_Page_Down:
case XK_Page_Down: key = K_PGDN; break;
case XK_KP_Home:
case XK_Home: key = K_HOME; break;
case XK_KP_End:
case XK_End: key = K_END; break;
case XK_KP_Left:
case XK_Left: key = K_LEFTARROW; break;
case XK_KP_Right:
case XK_Right: key = K_RIGHTARROW; break;
case XK_KP_Down:
case XK_Down: key = K_DOWNARROW; break;
case XK_KP_Up:
case XK_Up: key = K_UPARROW; break;
case XK_Escape: key = K_ESCAPE; break;
case XK_KP_Enter:
case XK_Return: key = K_ENTER; break;
case XK_Tab: key = K_TAB; break;
case XK_F1: key = K_F1; break;
case XK_F2: key = K_F2; break;
case XK_F3: key = K_F3; break;
case XK_F4: key = K_F4; break;
case XK_F5: key = K_F5; break;
case XK_F6: key = K_F6; break;
case XK_F7: key = K_F7; break;
case XK_F8: key = K_F8; break;
case XK_F9: key = K_F9; break;
case XK_F10: key = K_F10; break;
case XK_F11: key = K_F11; break;
case XK_F12: key = K_F12; break;
case XK_BackSpace: key = K_BACKSPACE; break;
case XK_KP_Delete:
case XK_Delete: key = K_DEL; break;
case XK_Pause: key = K_PAUSE; break;
case XK_Shift_L:
case XK_Shift_R: key = K_SHIFT; break;
case XK_Execute:
case XK_Control_L:
case XK_Control_R: key = K_CTRL; break;
case XK_Alt_L:
case XK_Meta_L:
case XK_Alt_R:
case XK_Meta_R: key = K_ALT; break;
case XK_KP_Begin: key = '5'; break;
case XK_KP_Insert:
case XK_Insert:key = K_INS; break;
case XK_KP_Multiply: key = '*'; break;
case XK_KP_Add: key = '+'; break;
case XK_KP_Subtract: key = '-'; break;
case XK_KP_Divide: key = '/'; break;
#if 0
case 0x021: key = '1';break;/* [!] */
case 0x040: key = '2';break;/* [@] */
case 0x023: key = '3';break;/* [#] */
case 0x024: key = '4';break;/* [$] */
case 0x025: key = '5';break;/* [%] */
case 0x05e: key = '6';break;/* [^] */
case 0x026: key = '7';break;/* [&] */
case 0x02a: key = '8';break;/* [*] */
case 0x028: key = '9';;break;/* [(] */
case 0x029: key = '0';break;/* [)] */
case 0x05f: key = '-';break;/* [_] */
case 0x02b: key = '=';break;/* [+] */
case 0x07c: key = '\'';break;/* [|] */
case 0x07d: key = '[';break;/* [}] */
case 0x07b: key = ']';break;/* [{] */
case 0x022: key = '\'';break;/* ["] */
case 0x03a: key = ';';break;/* [:] */
case 0x03f: key = '/';break;/* [?] */
case 0x03e: key = '.';break;/* [>] */
case 0x03c: key = ',';break;/* [<] */
#endif
default:
key = *(unsigned char*)buf;
if (key >= 'A' && key <= 'Z')
key = key - 'A' + 'a';
break;
}
return key;
}
static void install_grabs(void)
{
XGrabPointer(vid_dpy, vid_window,
True,
0,
GrabModeAsync, GrabModeAsync,
vid_window,
None,
CurrentTime);
#ifdef USE_DGA
// TODO: make this into a cvar, like "in_dgamouse", instead of parameters
// TODO: inform the user when DGA is enabled
if (!COM_CheckParm("-nodga") && !COM_CheckParm("-nomdga"))
{
XF86DGADirectVideo(vid_dpy, DefaultScreen(vid_dpy), XF86DGADirectMouse);
dgamouse = 1;
}
else
#endif
{
XWarpPointer(vid_dpy, None, vid_window,
0, 0, 0, 0,
vid.width / 2, vid.height / 2);
}
// XSync(vid_dpy, True);
}
static void uninstall_grabs(void)
{
#ifdef USE_DGA
XF86DGADirectVideo(vid_dpy, DefaultScreen(vid_dpy), 0);
dgamouse = 0;
#endif
XUngrabPointer(vid_dpy, CurrentTime);
// XSync(vid_dpy, True);
}
void ClearAllStates (void)
{
int i;
// send an up event for each key, to make sure the server clears them all
for (i=0 ; i<256 ; i++)
{
Key_Event (i, false);
}
Key_ClearStates ();
// IN_ClearStates ();
}
static void GetEvent(void)
{
XEvent event;
int b;
qboolean wantwindowed;
qboolean x11violations = true;
if (!vid_dpy)
return;
XNextEvent(vid_dpy, &event);
switch (event.type) {
case ResizeRequest:
glwidth = event.xresizerequest.width;
glheight = event.xresizerequest.height;
break;
case ConfigureNotify:
glwidth = event.xconfigurerequest.width;
glheight = event.xconfigurerequest.height;
break;
case KeyPress:
case KeyRelease:
Key_Event(XLateKey(&event.xkey), event.type == KeyPress);
break;
case MotionNotify:
#ifdef USE_DGA
if (dgamouse && old_windowed_mouse)
{
mouse_x += event.xmotion.x_root;
mouse_y += event.xmotion.y_root;
}
else
#endif
{
if (old_windowed_mouse)
{
mouse_x = (float) ((int)event.xmotion.x - (int)(vid.width/2));
mouse_y = (float) ((int)event.xmotion.y - (int)(vid.height/2));
/* move the mouse to the window center again */
XSelectInput(vid_dpy, vid_window, X_MASK & ~PointerMotionMask);
XWarpPointer(vid_dpy, None, vid_window, 0, 0, 0, 0,
(vid.width/2), (vid.height/2));
XSelectInput(vid_dpy, vid_window, X_MASK);
}
}
break;
case ButtonPress:
b=-1;
if (event.xbutton.button == 1)
b = K_MOUSE1;
else if (event.xbutton.button == 2)
b = K_MOUSE3;
else if (event.xbutton.button == 3)
b = K_MOUSE2;
//note, the x11 protocol does not support a mousewheel
//we only support it because we follow convention. the actual protocol specifies 4+5 as regular buttons
else if (event.xbutton.button == 4)
b = x11violations?K_MWHEELUP:K_MOUSE4;
else if (event.xbutton.button == 5)
b = x11violations?K_MWHEELDOWN:K_MOUSE5;
//note, the x11 protocol does not support more than 5 mouse buttons
//which is a bit of a shame, but hey.
else if (event.xbutton.button == 6)
b = x11violations?K_MOUSE4:-1;
else if (event.xbutton.button == 7)
b = x11violations?K_MOUSE5:-1;
else if (event.xbutton.button == 8)
b = x11violations?K_MOUSE6:-1;
else if (event.xbutton.button == 9)
b = x11violations?K_MOUSE7:-1;
else if (event.xbutton.button == 10)
b = x11violations?K_MOUSE8:-1;
else if (event.xbutton.button == 11)
b = x11violations?K_MOUSE9:-1;
else if (event.xbutton.button == 12)
b = x11violations?K_MOUSE10:-1;
if (b>=0)
Key_Event(b, true);
#ifdef WITH_VMODE
if (vidmode_ext && vidmode_usemode>=0)
if (!ActiveApp)
{ //KDE doesn't seem to like us, in that you can't alt-tab back or click to activate.
//This allows us to steal input focus back from the window manager
XSetInputFocus(vid_dpy, vid_window, RevertToParent, CurrentTime);
}
#endif
break;
case ButtonRelease:
b=-1;
if (event.xbutton.button == 1)
b = K_MOUSE1;
else if (event.xbutton.button == 2)
b = K_MOUSE3;
else if (event.xbutton.button == 3)
b = K_MOUSE2;
//note, the x11 protocol does not support a mousewheel
//we only support it because we follow convention. the actual protocol specifies 4+5 as regular buttons
else if (event.xbutton.button == 4)
b = x11violations?K_MWHEELUP:K_MOUSE4;
else if (event.xbutton.button == 5)
b = x11violations?K_MWHEELDOWN:K_MOUSE5;
//note, the x11 protocol does not support more than 5 mouse buttons
//which is a bit of a shame, but hey.
else if (event.xbutton.button == 6)
b = x11violations?K_MOUSE4:-1;
else if (event.xbutton.button == 7)
b = x11violations?K_MOUSE5:-1;
else if (event.xbutton.button == 8)
b = x11violations?K_MOUSE6:-1;
else if (event.xbutton.button == 9)
b = x11violations?K_MOUSE7:-1;
else if (event.xbutton.button == 10)
b = x11violations?K_MOUSE8:-1;
else if (event.xbutton.button == 11)
b = x11violations?K_MOUSE9:-1;
else if (event.xbutton.button == 12)
b = x11violations?K_MOUSE10:-1;
if (b>=0)
Key_Event(b, false);
break;
case FocusIn:
ActiveApp = true;
#ifdef WITH_VMODE
if (vidmode_ext && vidmode_usemode>=0)
{
if (!vidmode_active)
{
// change to the mode
XF86VidModeSwitchToMode(vid_dpy, scrnum, vidmodes[vidmode_usemode]);
vidmode_active = true;
// Move the viewport to top left
}
XF86VidModeSetViewPort(vid_dpy, scrnum, 0, 0);
}
#endif
Cvar_ForceCallback(&v_gamma);
break;
case FocusOut:
#ifdef WITH_VMODE
if (originalapplied)
XF86VidModeSetGammaRamp(vid_dpy, scrnum, 256, originalramps[0], originalramps[1], originalramps[2]);
if (!COM_CheckParm("-stayactive"))
{ //a parameter that leaves the program fullscreen if you taskswitch.
//sounds pointless, works great with two moniters. :D
if (originalapplied)
XF86VidModeSetGammaRamp(vid_dpy, scrnum, 256, originalramps[0], originalramps[1], originalramps[2]);
if (vidmode_active)
{
XF86VidModeSwitchToMode(vid_dpy, scrnum, vidmodes[0]);
vidmode_active = false;
}
}
#endif
ActiveApp = false;
ClearAllStates();
break;
}
wantwindowed = !!_windowed_mouse.value;
if (!ActiveApp)
wantwindowed = false;
if (key_dest == key_console)
wantwindowed = false;
if (old_windowed_mouse != wantwindowed)
{
old_windowed_mouse = wantwindowed;
if (!wantwindowed)
{
Con_DPrintf("uninstall grabs\n");
/* ungrab the pointer */
uninstall_grabs();
}
else
{
Con_DPrintf("install grabs\n");
/* grab the pointer */
install_grabs();
}
}
}
void GLVID_Shutdown(void)
{
printf("GLVID_Shutdown\n");
if (!ctx)
return;
XUngrabKeyboard(vid_dpy, CurrentTime);
if (old_windowed_mouse)
uninstall_grabs();
if (ctx)
qglXDestroyContext(vid_dpy, ctx);
#ifdef WITH_VMODE
if (originalapplied)
XF86VidModeSetGammaRamp(vid_dpy, scrnum, 256, originalramps[0], originalramps[1], originalramps[2]);
#endif
if (vid_window)
XDestroyWindow(vid_dpy, vid_window);
#ifdef WITH_VMODE
if (vid_dpy) {
if (vidmode_active)
XF86VidModeSwitchToMode(vid_dpy, scrnum, vidmodes[0]);
vidmode_active = false;
}
#endif
XCloseDisplay(vid_dpy);
vid_dpy = NULL;
vid_window = (Window)NULL;
}
void GLVID_DeInit(void) //FIXME:....
{
GLVID_Shutdown();
}
void signal_handler(int sig)
{
printf("Received signal %d, exiting...\n", sig);
Sys_Quit();
exit(0);
}
void InitSig(void)
{
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGILL, signal_handler);
signal(SIGTRAP, signal_handler);
#ifndef __CYGWIN__
signal(SIGIOT, signal_handler);
#endif
signal(SIGBUS, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGSEGV, signal_handler);
signal(SIGTERM, signal_handler);
}
static Cursor CreateNullCursor(Display *display, Window root)
{
Pixmap cursormask;
XGCValues xgc;
GC gc;
XColor dummycolour;
Cursor cursor;
cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
xgc.function = GXclear;
gc = XCreateGC(display, cursormask, GCFunction, &xgc);
XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
dummycolour.pixel = 0;
dummycolour.red = 0;
dummycolour.flags = 04;
cursor = XCreatePixmapCursor(display, cursormask, cursormask,
&dummycolour,&dummycolour, 0,0);
XFreePixmap(display,cursormask);
XFreeGC(display,gc);
return cursor;
}
void GLVID_ShiftPalette (unsigned char *palette)
{
#ifdef WITH_VMODE
extern qboolean gammaworks;
extern cvar_t vid_hardwaregamma;
extern unsigned short ramps[3][256];
// VID_SetPalette (palette);
if (originalapplied && ActiveApp && vid_hardwaregamma.value) //this is needed because ATI drivers don't work properly (or when task-switched out).
{
if (gammaworks)
{ //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck)
XF86VidModeSetGammaRamp (vid_dpy, scrnum, 256, ramps[0], ramps[1], ramps[2]);
return;
}
gammaworks = !!XF86VidModeSetGammaRamp (vid_dpy, scrnum, 256, ramps[0], ramps[1], ramps[2]);
}
else
gammaworks = false;
#endif
}
void GLVID_SetPalette (unsigned char *palette)
{
qbyte *pal;
unsigned r,g,b;
unsigned short i;
unsigned *table;
unsigned *table2;
extern qbyte gammatable[256];
//
// 8 8 8 encoding
//
Con_Printf("Converting 8to24\n");
pal = palette;
table = d_8to24rgbtable;
table2 = d_8to24bgrtable;
for (i=0 ; i<256 ; i++)
{
r = gammatable[pal[0]];
g = gammatable[pal[1]];
b = gammatable[pal[2]];
pal += 3;
*table++ = BigLong((r<<24)|(g<<16)|(b<<8)|255);
*table2++ = BigLong((b<<24)|(g<<16)|(r<<8)|255);
}
d_8to24bgrtable[255] &= BigLong(0xffffff00); // 255 is transparent
d_8to24rgbtable[255] &= BigLong(0xffffff00); // 255 is transparent
}
/*
=================
GL_BeginRendering
=================
*/
void GL_BeginRendering (int *x, int *y, int *width, int *height)
{
*x = *y = 0;
*width = glwidth;
*height = glheight;
// if (!wglMakeCurrent( maindc, baseRC ))
// Sys_Error ("wglMakeCurrent failed");
// qglViewport (*x, *y, *width, *height);
}
void GL_EndRendering (void)
{
//return;
//we don't need the flush, XSawpBuffers does it for us.
//chances are, it's version is more suitable anyway. At least there's the chance that it might be.
qglXSwapBuffers(vid_dpy, vid_window);
}
qboolean GLVID_Is8bit(void)
{
return is8bit;
}
qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
{
int i;
int attrib[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DOUBLEBUFFER,
GLX_DEPTH_SIZE, 1,
None
};
XSetWindowAttributes attr;
unsigned long mask;
Window root;
XVisualInfo *visinfo;
#ifdef WITH_VMODE
qboolean fullscreen = false;
int MajorVersion, MinorVersion;
if (info->fullscreen)
fullscreen = true;
#endif
S_Startup();
if (!GLX_InitLibrary(info->glrenderer))
{
Con_Printf("Couldn't intialise GLX\nEither your drivers are not installed or you need to specify the library name with the gl_driver cvar\n");
return false;
}
vid.maxwarpwidth = WARP_WIDTH;
vid.maxwarpheight = WARP_HEIGHT;
vid.colormap = host_colormap;
// interpret command-line params
// set vid parameters
if ((i = COM_CheckParm("-conwidth")) != 0)
vid.conwidth = Q_atoi(com_argv[i+1]);
else
vid.conwidth = 640;
vid.conwidth &= ~7; // make it a multiple of eight
if (vid.conwidth < 320)
vid.conwidth = 320;
// pick a conheight that matches with correct aspect
vid.conheight = vid.conwidth*3 / 4;
if ((i = COM_CheckParm("-conheight")) != 0)
vid.conheight = Q_atoi(com_argv[i+1]);
if (vid.conheight < 200)
vid.conheight = 200;
if (!vid_dpy)
vid_dpy = XOpenDisplay(NULL);
if (!vid_dpy)
{
Con_Printf(CON_ERROR "Error: couldn't open the X display\n");
return false;
}
scrnum = DefaultScreen(vid_dpy);
root = RootWindow(vid_dpy, scrnum);
#ifdef WITH_VMODE //find out if it's supported on this pc.
MajorVersion = MinorVersion = 0;
if (COM_CheckParm("-novmode") || !XF86VidModeQueryVersion(vid_dpy, &MajorVersion, &MinorVersion))
{
vidmode_ext = 0;
}
else
{
Con_Printf("Using XF86-VidModeExtension Ver. %d.%d\n", MajorVersion, MinorVersion);
vidmode_ext = MajorVersion;
}
#endif
visinfo = qglXChooseVisual(vid_dpy, scrnum, attrib);
if (!visinfo)
{
Sys_Error("qkHack: Error couldn't get an RGB, Double-buffered, Depth visual\n");
}
#ifdef WITH_VMODE
vidmode_usemode = -1;
if (vidmode_ext)
{
int best_fit, best_dist, dist, x, y;
XF86VidModeGetAllModeLines(vid_dpy, scrnum, &num_vidmodes, &vidmodes);
// Are we going fullscreen? If so, let's change video mode
if (fullscreen)
{
best_dist = 9999999;
best_fit = -1;
for (i = 0; i < num_vidmodes; i++)
{
if (info->width > vidmodes[i]->hdisplay ||
info->height > vidmodes[i]->vdisplay)
continue;
x = info->width - vidmodes[i]->hdisplay;
y = info->height - vidmodes[i]->vdisplay;
dist = (x * x) + (y * y);
if (dist < best_dist)
{
best_dist = dist;
best_fit = i;
}
}
if (best_fit != -1 && (!best_dist || COM_CheckParm("-fullscreen")))
{
// change to the mode
XF86VidModeSwitchToMode(vid_dpy, scrnum, vidmodes[vidmode_usemode=best_fit]);
vidmode_active = true;
// Move the viewport to top left
XF86VidModeSetViewPort(vid_dpy, scrnum, 0, 0);
}
else
fullscreen = 0;
}
}
#endif
/* window attributes */
attr.background_pixel = 0;
attr.border_pixel = 0;
attr.colormap = XCreateColormap(vid_dpy, root, visinfo->visual, AllocNone);
attr.event_mask = X_MASK;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
#ifdef WITH_VMODE //get rid of borders
// fullscreen
if (vidmode_active) {
mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore |
CWEventMask | CWOverrideRedirect;
attr.override_redirect = True;
attr.backing_store = NotUseful;
attr.save_under = False;
}
#endif
ActiveApp = false;
vid_window = XCreateWindow(vid_dpy, root, 0, 0, info->width, info->height,
0, visinfo->depth, InputOutput,
visinfo->visual, mask, &attr);
XMapWindow(vid_dpy, vid_window);
XMoveWindow(vid_dpy, vid_window, 0, 0);
#ifdef WITH_VMODE
if (vidmode_active) {
XRaiseWindow(vid_dpy, vid_window);
XWarpPointer(vid_dpy, None, vid_window, 0, 0, 0, 0, 0, 0);
XFlush(vid_dpy);
// Move the viewport to top left
XF86VidModeSetViewPort(vid_dpy, scrnum, 0, 0);
}
#endif
XStoreName(vid_dpy, vid_window, "FTE QuakeWorld");
//hide the cursor.
XDefineCursor(vid_dpy, vid_window, CreateNullCursor(vid_dpy, vid_window));
XFlush(vid_dpy);
#ifdef WITH_VMODE
if (vidmode_ext >= 2)
{
int rampsize = 256;
XF86VidModeGetGammaRampSize(vid_dpy, scrnum, &rampsize);
if (rampsize != 256)
{
originalapplied = false;
Con_Printf("Gamma ramps are not of 256 components (but %i).\n", rampsize);
}
else
originalapplied = XF86VidModeGetGammaRamp(vid_dpy, scrnum, 256, originalramps[0], originalramps[1], originalramps[2]);
}
else
originalapplied = false;
#endif
ctx = qglXCreateContext(vid_dpy, visinfo, NULL, True);
if (!ctx)
{
Con_Printf("Failed to create GLX context.\n");
GLVID_Shutdown();
return false;
}
if (!qglXMakeCurrent(vid_dpy, vid_window, ctx))
{
Con_Printf("glXMakeCurrent failed\n");
GLVID_Shutdown();
return false;
}
glwidth = info->width;
glheight = info->height;
if (vid.conheight > info->height)
vid.conheight = info->height;
if (vid.conwidth > info->width)
vid.conwidth = info->width;
vid.width = vid.conwidth;
vid.height = vid.conheight;
vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
vid.numpages = 2;
InitSig(); // trap evil signals
GL_Init(&GLX_GetSymbol);
GLVID_SetPalette(palette);
GLVID_ShiftPalette(palette);
Con_SafePrintf ("Video mode %dx%d initialized.\n", info->width, info->height);
vid.recalc_refdef = 1; // force a surface cache flush
if (Cvar_Get("vidx_grabkeyboard", "0", 0, "Additional video options")->value)
XGrabKeyboard(vid_dpy, vid_window,
False,
GrabModeAsync, GrabModeAsync,
CurrentTime);
else
XSetInputFocus(vid_dpy, vid_window, RevertToParent, CurrentTime);
XRaiseWindow(vid_dpy, vid_window);
return true;
}
#ifdef SWQUAKE
void GLSys_SendKeyEvents(void)
#else
void Sys_SendKeyEvents(void)
#endif
{
if (vid_dpy && vid_window) {
while (XPending(vid_dpy))
GetEvent();
}
}
void Force_CenterView_f (void)
{
cl.viewangles[0][PITCH] = 0;
}
#ifndef SWQUAKE
void IN_ReInit(void)
{
}
void IN_Init(void)
{
#ifdef IN_XFLIP
Cvar_Register (&in_xflip, "Input variables");
#endif
IN_ReInit();
}
void IN_Shutdown(void)
{
}
/*
===========
IN_Commands
===========
*/
void IN_Commands (void)
{
}
/*
===========
IN_Move
===========
*/
void IN_MouseMove (float *movements, int pnum)
{
extern int mouseusedforgui, mousecursor_x, mousecursor_y;
extern int mousemove_x, mousemove_y;
float mx, my;
mx = mouse_x;
my = mouse_y;
if (mouseusedforgui || (key_dest == key_menu && (m_state == m_complex || m_state == m_plugin))
#ifdef VM_UI
|| UI_MenuState()
#endif
)
{
mousemove_x += mouse_x;
mousemove_y += mouse_y;
mousecursor_x += mouse_x;
mousecursor_y += mouse_y;
if (mousecursor_y<0)
mousecursor_y=0;
if (mousecursor_x<0)
mousecursor_x=0;
if (mousecursor_x >= vid.width)
mousecursor_x = vid.width - 1;
if (mousecursor_y >= vid.height)
mousecursor_y = vid.height - 1;
mouse_x=mouse_y=0;
#ifdef VM_UI
UI_MousePosition(mousecursor_x, mousecursor_y);
#endif
}
if (m_filter.value)
{
float fraction = bound(0, m_filter.value, 2) * 0.5;
mouse_x = (mouse_x*(1-fraction) + old_mouse_x*fraction);
mouse_y = (mouse_y*(1-fraction) + old_mouse_y*fraction);
}
old_mouse_x = mx;
old_mouse_y = my;
if (m_accel.value) {
float mouse_deltadist = sqrt(mx*mx + my*my);
mouse_x *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale);
mouse_y *= (mouse_deltadist*m_accel.value + sensitivity.value*in_sensitivityscale);
} else {
mouse_x *= sensitivity.value*in_sensitivityscale;
mouse_y *= sensitivity.value*in_sensitivityscale;
}
#ifdef IN_XFLIP
if(in_xflip.value) mouse_x *= -1;
#endif
if (movements)
{
// add mouse X/Y movement to cmd
if ( (in_strafe.state[pnum] & 1) || (lookstrafe.value && (in_mlook.state[pnum] & 1) ))
movements[1] += m_side.value * mouse_x;
else
cl.viewangles[pnum][YAW] -= m_yaw.value * mouse_x;
if (in_mlook.state[pnum] & 1)
V_StopPitchDrift (pnum);
if ( (in_mlook.state[pnum] & 1) && !(in_strafe.state[pnum] & 1))
{
cl.viewangles[pnum][PITCH] += m_pitch.value * mouse_y;
CL_ClampPitch(pnum);
}
else
{
if ((in_strafe.state[pnum] & 1) && noclip_anglehack)
movements[2] -= m_forward.value * mouse_y;
else
movements[0] -= m_forward.value * mouse_y;
}
}
mouse_x = mouse_y = 0.0;
}
void IN_Move (float *movements, int pnum)
{
IN_MouseMove(movements, pnum);
}
#endif
void GLVID_UnlockBuffer() {}
void GLVID_LockBuffer() {}
int GLVID_ForceUnlockedAndReturnState (void) {return 0;}
void GLVID_ForceLockState (int lk) {}
void GL_DoSwap(void) {}
void GLVID_SetCaption(char *text)
{
XStoreName(vid_dpy, vid_window, text);
}