📄 glw_imp.c
字号:
/*
Copyright (C) 1997-2001 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.
*/
/*
** GLW_IMP.C
**
** This file contains ALL Linux specific stuff having to do with the
** OpenGL refresh. When a port is being made the following functions
** must be implemented by the port:
**
** GLimp_EndFrame
** GLimp_Init
** GLimp_Shutdown
** GLimp_SwitchFullscreen
**
*/
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/extensions/XShm.h>
#include <Xm/MwmUtil.h>
#include <GL/glx.h>
#include "../ref_gl/gl_local.h"
#include "../client/keys.h"
#include "../linux/rw_linux.h"
GLXContext gl_cx;
static qboolean doShm;
static Display *x_disp;
static Colormap x_cmap;
static Window x_win;
static GC x_gc;
static Visual *x_vis;
static XVisualInfo *x_visinfo;
static int StudlyRGBattributes[] =
{
GLX_DOUBLEBUFFER,
GLX_RGBA,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 1,
GLX_SAMPLES_SGIS, 4, /* for better AA */
None,
};
static int RGBattributes[] =
{
GLX_DOUBLEBUFFER,
GLX_RGBA,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 1,
None,
};
#define STD_EVENT_MASK (StructureNotifyMask | KeyPressMask \
| KeyReleaseMask | ExposureMask | PointerMotionMask | \
ButtonPressMask | ButtonReleaseMask)
int current_framebuffer;
static int x_shmeventtype;
//static XShmSegmentInfo x_shminfo;
static qboolean oktodraw = false;
static qboolean X11_active = false;
struct
{
int key;
int down;
} keyq[64];
int keyq_head=0;
int keyq_tail=0;
static int mx, my;
static int p_mouse_x, p_mouse_y;
static cvar_t *_windowed_mouse;
static cvar_t *sensitivity;
static cvar_t *lookstrafe;
static cvar_t *m_side;
static cvar_t *m_yaw;
static cvar_t *m_pitch;
static cvar_t *m_forward;
static cvar_t *freelook;
int config_notify=0;
int config_notify_width;
int config_notify_height;
typedef unsigned short PIXEL;
// Console variables that we need to access from this module
/*****************************************************************************/
/* MOUSE */
/*****************************************************************************/
// this is inside the renderer shared lib, so these are called from vid_so
static qboolean mouse_avail;
static int mouse_buttonstate;
static int mouse_oldbuttonstate;
static int mouse_x, mouse_y;
static int old_mouse_x, old_mouse_y;
static float old_windowed_mouse;
static int p_mouse_x, p_mouse_y;
static cvar_t *_windowed_mouse;
static cvar_t *m_filter;
static cvar_t *in_mouse;
static qboolean mlooking;
// state struct passed in Init
static in_state_t *in_state;
int XShmQueryExtension(Display *);
int XShmGetEventBase(Display *);
static void signal_handler(int sig)
{
fprintf(stderr, "Received signal %d, exiting...\n", sig);
GLimp_Shutdown();
_exit(0);
}
static void InitSig(void)
{
struct sigaction sa;
sigaction(SIGINT, 0, &sa);
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, 0);
sigaction(SIGTERM, &sa, 0);
}
/*
** GLimp_SetMode
*/
int GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
{
int width, height;
GLint attribs[32];
fprintf(stderr, "GLimp_SetMode\n");
ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
{
ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
return rserr_invalid_mode;
}
ri.Con_Printf( PRINT_ALL, " %d %d\n", width, height );
// destroy the existing window
GLimp_Shutdown ();
*pwidth = width;
*pheight = height;
if ( !GLimp_InitGraphics( fullscreen ) ) {
// failed to set a valid mode in windowed mode
return rserr_invalid_mode;
}
/* gl_cx = glXCreateContext( x_disp, x_visinfo, 0, True ); */
// let the sound and input subsystems know about the new window
ri.Vid_NewWindow (width, height);
return rserr_ok;
}
/*
** GLimp_Shutdown
**
** This routine does all OS specific shutdown procedures for the OpenGL
** subsystem. Under OpenGL this means NULLing out the current DC and
** HGLRC, deleting the rendering context, and releasing the DC acquired
** for the window. The state structure is also nulled out.
**
*/
void GLimp_Shutdown( void )
{
fprintf(stderr, "GLimp_Shutdown\n");
if (!x_disp)
return;
XSynchronize( x_disp, True );
XAutoRepeatOn(x_disp);
XCloseDisplay(x_disp);
x_disp = NULL;
}
/*
** GLimp_Init
**
** This routine is responsible for initializing the OS specific portions
** of OpenGL.
*/
int GLimp_Init( void *hinstance, void *wndproc )
{
// catch signals so i can turn on auto-repeat and stuff
InitSig();
return true;
}
/*
** GLimp_BeginFrame
*/
void GLimp_BeginFrame( float camera_seperation )
{
}
/*
** GLimp_EndFrame
**
** Responsible for doing a swapbuffers and possibly for other stuff
** as yet to be determined. Probably better not to make this a GLimp
** function and instead do a call to GLimp_SwapBuffers.
*/
void GLimp_EndFrame (void)
{
glFlush();
glXSwapBuffers( x_disp, x_win );
}
/*
** GLimp_AppActivate
*/
void GLimp_AppActivate( qboolean active )
{
}
// ========================================================================
// makes a null cursor
// ========================================================================
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;
}
/*
** GLimp_InitGraphics
**
** This initializes the GL implementation specific
** graphics subsystem.
**
** The necessary width and height parameters are grabbed from
** vid.width and vid.height.
*/
qboolean GLimp_InitGraphics( qboolean fullscreen )
{
int pnum, i;
XVisualInfo template;
int num_visuals;
int template_mask;
fprintf(stderr, "GLimp_InitGraphics\n");
srandom(getpid());
// let the sound and input subsystems know about the new window
ri.Vid_NewWindow (vid.width, vid.height);
// open the display
x_disp = XOpenDisplay(NULL);
if (!x_disp)
{
if (getenv("DISPLAY"))
Sys_Error("VID: Could not open display [%s]\n",
getenv("DISPLAY"));
else
Sys_Error("VID: Could not open local display\n");
}
else
fprintf(stderr, "VID: Opened display %s\n", getenv("DISPLAY"));
XAutoRepeatOff(x_disp);
// for debugging only
XSynchronize(x_disp, True);
// check for command-line window size
template_mask = 0;
#if 0
// specify a visual id
if ((pnum=COM_CheckParm("-visualid")))
{
if (pnum >= com_argc-1)
Sys_Error("VID: -visualid <id#>\n");
template.visualid = Q_atoi(com_argv[pnum+1]);
template_mask = VisualIDMask;
}
// If not specified, use default visual
else
#endif
{
int screen;
screen = XDefaultScreen(x_disp);
template.visualid =
XVisualIDFromVisual(XDefaultVisual(x_disp, screen));
template_mask = VisualIDMask;
}
// pick a visual- warn if more than one was available
x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ),
StudlyRGBattributes );
if (!x_visinfo)
{
fprintf(stderr, "Using non studly RGB attributes\n");
x_visinfo = glXChooseVisual( x_disp, DefaultScreen( x_disp ),
RGBattributes );
if (!x_visinfo) Sys_Error( "No matching visual available!\n" );
}
ri.Con_Printf(PRINT_ALL, "Using visualid 0x%x:\n",
(int)(x_visinfo->visualid));
#if 0
if (verbose)
{
printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
printf(" screen %d\n", x_visinfo->screen);
printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
printf(" colormap_size %d\n", x_visinfo->colormap_size);
printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
}
#endif
x_vis = x_visinfo->visual;
// setup attributes for main window
{
int attribmask = CWEventMask | CWColormap | CWBorderPixel;
XSetWindowAttributes attribs;
Colormap tmpcmap;
Window root_win = XRootWindow(x_disp, x_visinfo->screen);
tmpcmap = XCreateColormap(x_disp, root_win, x_vis, AllocNone);
attribs.event_mask = STD_EVENT_MASK;
attribs.border_pixel = 0;
attribs.colormap = tmpcmap;
// create the main window
x_win = XCreateWindow( x_disp,
root_win,
0, 0, // x, y
vid.width, vid.height,
0, // borderwidth
x_visinfo->depth,
InputOutput,
x_vis,
attribmask,
&attribs );
XStoreName(x_disp, x_win, "Quake II");
if (x_visinfo->class != TrueColor)
XFreeColormap(x_disp, tmpcmap);
}
if (x_visinfo->depth == 8)
{
// create and upload the palette
if (x_visinfo->class == PseudoColor)
{
x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
XSetWindowColormap(x_disp, x_win, x_cmap);
}
}
// inviso cursor
XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
// create the GC
{
XGCValues xgcvalues;
int valuemask = GCGraphicsExposures;
xgcvalues.graphics_exposures = False;
x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
}
// set window properties for full screen
if (fullscreen) {
MotifWmHints wmhints;
Atom aHints;
XSizeHints sizehints;
XWindowChanges changes;
aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 );
if (aHints == None)
{
ri.Con_Printf( PRINT_ALL, "Could not intern X atom for _MOTIF_WM_HINTS." );
/* return( false ); */
}
else {
wmhints.flags = MWM_HINTS_DECORATIONS;
wmhints.decorations = 0; // Absolutely no decorations.
XChangeProperty(x_disp, x_win, aHints, aHints, 32,
PropModeReplace, (unsigned char *)&wmhints,
4 );
sizehints.flags = USPosition | USSize;
sizehints.x = 0;
sizehints.y = 0;
sizehints.width = vid.width;
sizehints.height = vid.height;
XSetWMNormalHints( x_disp, x_win, &sizehints );
changes.x = 0;
changes.y = 0;
changes.width = vid.width;
changes.height = vid.height;
changes.stack_mode = TopIf;
XConfigureWindow(x_disp, x_win,
CWX | CWY | CWWidth | CWHeight | CWStackMode,
&changes);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -