Files

1 line
18 KiB
C++

#include <stdlib.h>
#include <X11/keysym.h>
#include <stdarg.h>
/*#include <sys/socket.h>*/
/*#include <netinet/in.h>*/
#include <errno.h>
#define DEPTH 8
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <signal.h>
#include <sys/fbio.h>
#include <sys/cg14io.h>
#include <stropts.h>
#include <poll.h>
#define CG3_MMAP_OFFSET 0x04000000
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <sys/resource.h>
#include "dga/dga.h"
#include "doomdef.h"
static Display *display=0;
static int screen;
static int root;
static Visual *vis ;
static Window win;
static Colormap cmap ;
static sigset_t signalset;
static int input_pending;
static u_char * f_fb;
static Dga_window clientp ;
static int win_x, win_y, win_w, win_h;
static int f_dpy_pitch;
static int f_dpy_width;
static int f_dpy_height;
unsigned char *win_ptr;
int framecount = 0;
long long frametime;
#define POINTER_WARP_COUNTDOWN 1
XEvent report;
boolean grabMouse;
int doPointerWarp = POINTER_WARP_COUNTDOWN;
static int multiply=1;
unsigned exptable2[256];
unsigned exptable3[256];
// long long exptable8[256];
int showkeysym=0;
static void blocksigio(void)
{
if(sigprocmask(SIG_BLOCK,
& signalset,
NULL) < 0)
perror("sigprocmask");
}
static void unblocksigio(void)
{
if(sigprocmask(SIG_UNBLOCK,
& signalset,
NULL) < 0)
perror("sigprocmask");
}
static void gotio(void)
{
// fprintf(stderr, "got SIGPOLL\n");
input_pending = 1;
}
int xlatekey(void)
{
int rc;
rc = XKeycodeToKeysym(display, report.xkey.keycode, 0);
if (showkeysym)
printf("k=[%d] \r", rc);
switch(rc)
{
case XK_Left: rc = KEY_LEFTARROW; break;
case XK_Right: rc = KEY_RIGHTARROW; break;
case XK_Down: rc = KEY_DOWNARROW; break;
case XK_Up: rc = KEY_UPARROW; break;
case XK_Escape: rc = KEY_ESCAPE; break;
case XK_Return: rc = KEY_ENTER; break;
case XK_Tab: rc = KEY_TAB; break;
case XK_F1: rc = KEY_F1; break;
case XK_F2: rc = KEY_F2; break;
case XK_F3: rc = KEY_F3; break;
case XK_F4: rc = KEY_F4; break;
case XK_F5: rc = KEY_F5; break;
case XK_F6: rc = KEY_F6; break;
case XK_F7: rc = KEY_F7; break;
case XK_F8: rc = KEY_F8; break;
case XK_F9: rc = KEY_F9; break;
case XK_F10: rc = KEY_F10; break;
case XK_F11: rc = KEY_F11; break;
case XK_F12: rc = KEY_F12; break;
case XK_BackSpace:
case XK_Delete: rc = KEY_BACKSPACE; break;
case XK_Pause: rc = KEY_PAUSE; break;
case XK_KP_Equal:
case XK_equal: rc = KEY_EQUALS; break;
case XK_KP_Subtract:
case XK_minus: rc = KEY_MINUS; break;
case XK_Shift_L:
case XK_Shift_R: rc = KEY_RSHIFT; break;
case XK_Control_L:
case 65512:
case 65312:
case 65406:
case XK_Control_R: rc = KEY_RCTRL; break;
case XK_Alt_L:
case XK_Meta_L:
// case XK_Alt_R:
// case XK_Meta_R:
rc = KEY_RALT; break;
case 268828432: rc = KEY_F11; break;
case 268828433: rc = KEY_F12; break;
default:
if (rc >= XK_space && rc <= XK_asciitilde)
rc = rc - XK_space + ' ';
if (rc >= 'A' && rc <= 'Z')
rc = rc - 'A' + 'a';
break;
}
return rc;
}
void I_ShutdownGraphics(void)
{
dga_win_ungrab(clientp, 1) ;
XDgaUnGrabWindow(display, win) ;
XCloseDisplay(display);
}
/*
================
=
= I_Error
=
================
*/
extern boolean demorecording;
void I_Error (char *error, ...)
{
va_list argptr;
char string[1024];
if (demorecording)
G_CheckDemoStatus();
D_QuitNetGame ();
I_ShutdownGraphics();
va_start (argptr,error);
fprintf (stderr, "Error: ");
vfprintf (stderr,error,argptr);
fprintf (stderr, "\n");
va_end (argptr);
exit(-1);
}
/*
====================
=
= I_StartFrame
=
====================
*/
void I_StartFrame (void)
{
}
static int lastmousex = 0;
static int lastmousey = 0;
boolean mousemoved = false;
boolean shmFinished;
void I_GetEvent(void)
{
event_t event;
XNextEvent(display, &report);
switch (report.type)
{
case KeyPress:
event.type = ev_keydown;
event.data1 = xlatekey();
D_PostEvent(&event);
break;
case KeyRelease:
event.type = ev_keyup;
event.data1 = xlatekey();
D_PostEvent(&event);
break;
case ButtonPress:
event.type = ev_mouse;
event.data1 = (report.xbutton.state & Button1Mask)
| (report.xbutton.state & Button2Mask ? 2 : 0)
| (report.xbutton.state & Button3Mask ? 4 : 0)
| (report.xbutton.button == Button1)
| (report.xbutton.button == Button2 ? 2 : 0)
| (report.xbutton.button == Button3 ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
break;
case ButtonRelease:
event.type = ev_mouse;
event.data1 = (report.xbutton.state & Button1Mask)
| (report.xbutton.state & Button2Mask ? 2 : 0)
| (report.xbutton.state & Button3Mask ? 4 : 0)
^ (report.xbutton.button == Button1 ? 1 : 0)
^ (report.xbutton.button == Button2 ? 2 : 0)
^ (report.xbutton.button == Button3 ? 4 : 0);
event.data2 = event.data3 = 0;
D_PostEvent(&event);
break;
case MotionNotify:
event.type = ev_mouse;
event.data1 = (report.xmotion.state & Button1Mask)
| (report.xmotion.state & Button2Mask ? 2 : 0)
| (report.xmotion.state & Button3Mask ? 4 : 0);
event.data2 = (report.xmotion.x - lastmousex) << 2;
event.data3 = (lastmousey - report.xmotion.y) << 2;
if (event.data2 || event.data3)
{
lastmousex = report.xmotion.x;
lastmousey = report.xmotion.y;
if (report.xmotion.x != win_w/2 &&
report.xmotion.y != win_h/2)
{
D_PostEvent(&event);
mousemoved = false;
} else
{
mousemoved = true;
}
}
break;
case Expose:
case ConfigureNotify:
break;
default:
break;
}
}
/*
====================
=
= I_StartTic
=
====================
*/
void I_StartTic (void)
{
if (!display) return;
if(input_pending) {
blocksigio();
while( XEventsQueued(display, QueuedAfterFlush))
I_GetEvent();
input_pending = 0;
unblocksigio();
}
if (grabMouse)
{
if (!--doPointerWarp)
{
XWarpPointer( display,
None,
win,
0, 0,
0, 0,
win_w/2, win_h/2);
doPointerWarp = POINTER_WARP_COUNTDOWN;
}
}
mousemoved = false;
}
/*
====================
=
= I_UpdateNoBlit
=
====================
*/
void I_UpdateNoBlit (void)
{
}
void dgarender(void)
{
static int lasttic;
int tics, i;
static unsigned char *bigscreen=0;
int incamt;
long long *olineptrs[4];
unsigned int *ilineptr;
int x, y;
incamt = (multiply*f_dpy_pitch - win_w) / 8;
ilineptr = (unsigned int *) (screens[0]);
for (i=0 ; i<multiply ; i++)
olineptrs[i] = (long long *) &win_ptr[i*f_dpy_pitch];
if (devparm)
{
i = I_GetTime();
tics = i - lasttic;
lasttic = i;
if (tics > 20) tics = 20;
for (i=0 ; i<tics*2 ; i+=2)
screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
for ( ; i<20*2 ; i+=2)
screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
}
if (multiply == 2)
{
unsigned char *iptr = (unsigned char *) ilineptr;
y = SCREENHEIGHT;
while (y--)
{
x = SCREENWIDTH;
do
{
*(olineptrs[0]++) =
*(olineptrs[1]++) =
((long long) exptable2[iptr[0]] << 48)
| ((long long) exptable2[iptr[1]] << 32)
| (exptable2[iptr[2]] << 16)
| exptable2[iptr[3]];
iptr += 4;
} while (x-=4);
olineptrs[0] += incamt;
olineptrs[1] += incamt;
}
}
else if (multiply == 3)
{
unsigned char *iptr = (unsigned char *) ilineptr;
y = SCREENHEIGHT;
while (y--)
{
x = SCREENWIDTH;
do
{
*(olineptrs[0]++) = *(olineptrs[1]++) = *(olineptrs[2]++) =
((long long) exptable3[iptr[0]] << 40)
| ((long long) exptable3[iptr[1]] << 16)
| exptable2[iptr[2]];
*(olineptrs[0]++) = *(olineptrs[1]++) = *(olineptrs[2]++) =
((long long) exptable3[iptr[2]] << 56)
| ((long long) exptable3[iptr[3]] << 32)
| (exptable3[iptr[4]] << 8)
| iptr[5];
*(olineptrs[0]++) = *(olineptrs[1]++) = *(olineptrs[2]++) =
((long long) exptable3[iptr[5]] << 48)
| ((long long) exptable3[iptr[6]] << 24)
| exptable3[iptr[7]];
iptr += 8;
} while (x-=8);
olineptrs[0] += incamt;
olineptrs[1] += incamt;
olineptrs[2] += incamt;
}
}
else // multiply == 1
{
long long *iptr = (long long *) ilineptr;
y = SCREENHEIGHT;
while (y--)
{
x = SCREENWIDTH;
do
{
olineptrs[0][0] = iptr[0];
olineptrs[0][1] = iptr[1];
olineptrs[0][2] = iptr[2];
olineptrs[0][3] = iptr[3];
olineptrs[0] += 4;
iptr += 4;
} while (x-=8*4);
olineptrs[0] += incamt;
}
}
}
/*
====================
=
= I_ReadScreen
=
====================
*/
void I_ReadScreen (byte *scr)
{
memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
}
static XColor colors[256];
void UploadNewPalette(byte *palette)
{
register int i, c;
static boolean firstcall = true;
if (firstcall)
{
firstcall = false;
for (i=0 ; i<256 ; i++)
{
colors[i].pixel = i;
colors[i].flags = DoRed|DoGreen|DoBlue;
}
}
for (i=0 ; i<256 ; i++)
{
c = gammatable[usegamma][*palette++];
colors[i].red = (c<<8) + c;
c = gammatable[usegamma][*palette++];
colors[i].green = (c<<8) + c;
c = gammatable[usegamma][*palette++];
colors[i].blue = (c<<8) + c;
}
XStoreColors(display, cmap, colors, 256);
}
/*
====================
=
= I_SetPalette
=
====================
*/
void I_SetPalette (byte *palette)
{
UploadNewPalette(palette);
}
void I_InitExpTable(void)
{
long long i;
for (i=0 ; i<256 ; i++)
exptable3[i] = i | (i<<8) | (i<<16);
for (i=0 ; i<256 ; i++)
exptable2[i] = i | (i<<8);
/*
for (i=0 ; i<256 ; i++)
exptable8[i] = i | (i<<8) | (i<<16) | (i<<24)
| (i<<32) | (i<<40) | (i<<48) | (i<<56);
*/
}
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;
}
/*
An example of how to render directly on the screen using
dga.
This example just stops rendering when window is obscured;
this isn't the neatest but for a video game may be the best
interface.
This code appears to work on all flavors of GX, CG3 and SX.
I've got this using signals so that the code never has to call
poll(2) in the rendering loop unless data has arrived. This
seems to max out the frame rate.
*/
void I_InitGraphics(void)
{
XWindowAttributes wattr;
/* window-grabber stuff */
Dga_token token ;
/* frame buffer info */
struct fbgattr a;
int issx = 0;
int fd;
int f_fb_size;
caddr_t fb_fd;
int pnum;
struct pollfd fds[1];
static int firsttime=1;
if (!firsttime) return;
else firsttime = 0;
if (M_CheckParm("-showkeysym")) showkeysym = 1;
if (M_CheckParm("-2")) multiply = 2;
if (M_CheckParm("-3")) multiply = 3;
if (M_CheckParm("-4")) I_Error("multiply 4 not supported");
I_InitExpTable();
grabMouse = !!M_CheckParm("-grabmouse");
if ( ( display = XOpenDisplay(NULL) ) == NULL) {
(void) fprintf(stderr, "Cannot open display %X\n", display);
exit(-1);
}
screen = DefaultScreen(display);
root = DefaultRootWindow(display);
get_visual() ;
create_colormap() ;
create_window() ;
set_properties();
XMapWindow(display, win);
XDefineCursor(display, win, createnullcursor( display, win ));
XSync(display, True) ; /* wait for map */
/* test window-grabber */
DGA_INIT();
/* grab it */
token = XDgaGrabWindow(display, win) ;
if( token == 0 )
I_Error("XDgaGrabWindow returns 0\n") ;
clientp = dga_win_grab(-1, token) ;
if( clientp == NULL )
I_Error("dga_win_grab returns NULL\n") ;
/* ungrab it */
dga_win_ungrab(clientp, 1) ;
XDgaUnGrabWindow(display, win) ;
/* grab it again */
token = XDgaGrabWindow(display, win) ;
if( token == 0 )
I_Error("XDgaGrabWindow returns 0\n") ;
clientp = dga_win_grab(-1, token) ;
if( clientp == NULL )
I_Error("dga_win_grab returns NULL\n") ;
if(XGetWindowAttributes(display, win, & wattr) == 0) {
I_Error("can't get win attributes");
}
f_dpy_width = WidthOfScreen(wattr.screen);
f_dpy_height = HeightOfScreen(wattr.screen);
DGA_WIN_LOCK(clientp);
/* get frame buffer fd */
if((fd = dga_win_devfd(clientp)) < 0) {
I_Error("cannot map frame buffer");
}
/*
attempt to map framebuffer into our address space
*/
if(ioctl(fd, FBIOGATTR, &a) < 0) {
I_Error("failed to get display attributes");
}
else if (a.fbtype.fb_depth != 8
&& !(issx = (a.fbtype.fb_type==FBTYPE_MDICOLOR))) {
I_Error("display depth isn't 8");
}
else {
f_fb_size = a.fbtype.fb_size;
f_dpy_pitch
= a.sattr.dev_specific[FB_ATTR_NDEVSPECIFIC-1];
if (f_dpy_pitch == 0)
f_dpy_pitch = f_dpy_width;
f_fb = (unsigned char *)mmap(0, f_fb_size,
PROT_READ|PROT_WRITE,
MAP_SHARED, fd,
issx?MDI_PLANAR_B32_MAP:
CG3_MMAP_OFFSET);
if (f_fb == NULL) {
I_Error("couldn't map display");
}
}
dga_win_bbox(clientp, &win_x, & win_y,
& win_w, & win_h);
DGA_WIN_UNLOCK(clientp);
/* install signal handler */
{
struct sigaction act;
static void gotio();
act.sa_handler = gotio;
act.sa_flags = 0;
input_pending = 0;
if(sigaction(SIGPOLL, &act, NULL) < 0) {
I_Error("sigaction");
}
sigemptyset(&signalset);
sigaddset(&signalset, SIGPOLL);
}
fds[0].fd = ConnectionNumber(display);
fds[0].events = POLLIN|POLLHUP;
if(ioctl(ConnectionNumber(display),
I_SETSIG, S_INPUT) < 0) {
I_Error("ioctl: setsig");
}
fprintf(stderr, "Graphics inited\n");
}
/*
====================
=
= I_FinishUpdate
=
====================
*/
void I_FinishUpdate(void)
{
long long gethrtime();
register int j, k, l, m, n;
frametime = gethrtime();
DGA_WIN_LOCK(clientp);
/* Checks to see if window has moved. If so, get the new x,y,
width, height so that the next render works in the right spot */
if(dga_win_clipchg(clientp)) {
printf("size change\n");
framecount = 0;
frametime = gethrtime();
dga_win_bbox(clientp, &win_x, & win_y,
& win_w, & win_h);
win_x = (win_x + 7) & ~7;
win_w = SCREENWIDTH * multiply;
j = (int)f_fb + f_dpy_pitch * win_y + win_x;
m = (int)f_fb + f_dpy_pitch * (win_y + win_h) + win_x + win_w;
win_ptr = j;
}
if(dga_draw_visibility(clientp) == DGA_VIS_UNOBSCURED
&&
dga_win_singlerect(clientp)) {
/* can only draw if not obscured at all */
framecount++;
dgarender();
}
else {
/* obscured */
}
DGA_WIN_UNLOCK(clientp);
}
static
get_visual()
{
Status status ;
XVisualInfo vinfo_ret ;
status = XMatchVisualInfo(display, screen, 8,
PseudoColor, &vinfo_ret) ;
if( !status )
I_Error("could not get visual\n") ;
vis = vinfo_ret.visual ;
}
static
create_window()
{
Status status ;
XSetWindowAttributes attributes ;
Pixmap enter, enter_mask;
Cursor cursor;
XColor fg, bg;
win_w = SCREENWIDTH * multiply + 8;
win_h = SCREENHEIGHT * multiply;
attributes.colormap = cmap ;
win = XCreateWindow(display, DefaultRootWindow(display),
100,100, win_w,win_h, 5, DEPTH, InputOutput, vis,
CWColormap, &attributes) ;
}
static
create_colormap()
{
cmap = XCreateColormap(display, DefaultRootWindow(display),
vis, AllocAll);
}
static
set_properties(void)
{
Status status ;
XSizeHints size_hints ;
static Pixmap icon_pixmap;
static char xlogo64_bits[]={0x0};
icon_pixmap = XCreateBitmapFromData(display, win, xlogo64_bits,
1, 1);
size_hints.x = 90;
size_hints.y = 90;
size_hints.width = SCREENWIDTH * multiply + 8;
size_hints.height = SCREENHEIGHT * multiply + 8;
size_hints.flags = PPosition|PSize ;
XSetStandardProperties(display, win, myargv[0], myargv[0],
icon_pixmap, myargv, myargc, &size_hints );
XSelectInput(display, win, ExposureMask | VisibilityChangeMask |
KeyReleaseMask|
// KeyPressMask | ButtonPressMask | StructureNotifyMask );
KeyPressMask | StructureNotifyMask );
}