|
|
1.1 root 1: // vid_x.c -- general x video driver
2:
3: #include <sys/time.h>
4: #include <sys/types.h>
5: #include <unistd.h>
6: #include <fcntl.h>
7: #include <signal.h>
8: #include <stdlib.h>
9: #include <stdio.h>
10: #include <string.h>
11: #include <sys/ipc.h>
12: #include <sys/shm.h>
13: #include <X11/Xlib.h>
14: #include <X11/Xutil.h>
15: #include <X11/keysym.h>
16: #include <X11/Intrinsic.h>
17: #include <X11/Shell.h>
18: #include <X11/StringDefs.h>
19: #include <X11/Xatom.h>
20: #include <X11/Xmd.h>
21: #include <X11/extensions/xf86vmode.h>
22: #include <X11/extensions/xf86dga.h>
23:
24: #include "quakedef.h"
25: #include "d_local.h"
26:
27: cvar_t m_filter = {"m_filter","1"};
28:
29: qboolean mouse_avail;
30: int mouse_buttons=3;
31: int mouse_oldbuttonstate;
32: int mouse_buttonstate;
33: float mouse_x, mouse_y;
34: float old_mouse_x, old_mouse_y;
35:
36: typedef struct
37: {
38: int input;
39: int output;
40: } keymap_t;
41:
42: viddef_t vid; // global video state
43: unsigned short d_8to16table[256];
44:
45: int num_shades=32;
46: int d_con_indirect = 0;
47: int vid_buffersize;
48: int pixbytes;
49:
50: static Display *x_disp;
51: static Colormap x_cmap;
52: static Window x_win;
53: static GC x_gc;
54: static Visual *x_vis;
55: static XVisualInfo *x_visinfo;
56: //static XImage *x_image;
57:
58: static int vid_inited;
59: static int direct_video_inited;
60:
61: int work_buffer;
62: static int verbose=0;
63:
64: char *hw_fb_addr;
65: int hw_fb_width;
66: int hw_fb_banksize;
67: int hw_fb_ram;
68: int hw_fb_dotclock;
69: XF86VidModeModeLine hw_fb_modeline;
70:
71: static long X11_highhunkmark;
72: static long X11_buffersize;
73: int vid_surfcachesize;
74: void *vid_surfcache;
75:
76: static int flipy;
77: static char *flipaddr;
78:
79: void (*vid_menudrawfn)(void);
80: void (*vid_menukeyfn)(int key);
81:
82:
83: // ========================================================================
84: // Tragic death handler
85: // ========================================================================
86:
87: void TragicDeath(int signal_num)
88: {
89: VID_Shutdown();
90: Sys_Error("This death brought to you by the number %d\n", signal_num);
91: }
92:
93: // Called at startup to set up translation tables, takes 256 8 bit RGB values
94: // the palette data will go away after the call, so it must be copied off if
95: // the video driver will need it again
96:
97: void VID_Init (unsigned char *palette)
98: {
99:
100: int devmem;
101: int i;
102: XVisualInfo template;
103: XSetWindowAttributes xswa;
104: int MajorVersion, MinorVersion;
105: int EventBase, ErrorBase;
106: int MINMINOR=4;
107: int MINMAJOR=0;
108: struct sigaction sa;
109: XGCValues xgcvalues;
110: int valuemask = GCGraphicsExposures;
111: char *dispname;
112: Status xrc;
113: XSizeHints *x_hints;
114:
115: vid_inited = 0;
116: direct_video_inited = 0;
117:
118: devmem=open("/dev/mem", O_RDWR);
119: if (devmem<0)
120: fprintf(stderr, "You must run this as root or \"chmod 666 /dev/mem\"\n");
121: else
122: close(devmem);
123:
124: srandom(getpid());
125:
126: verbose=COM_CheckParm("-verbose");
127:
128: // open the display
129: dispname = getenv("DISPLAY");
130: if (!dispname) dispname = ":0.0";
131: x_disp = XOpenDisplay(dispname);
132: if (!x_disp)
133: {
134: if (getenv("DISPLAY"))
135: Sys_Error("VID: Could not open display [%s]\n",
136: getenv("DISPLAY"));
137: else
138: Sys_Error("VID: Could not open local display\n");
139: }
140: XSynchronize(x_disp, True);
141:
142: // use the root window for everything
143:
144: // x_win = RootWindow(x_disp, DefaultScreen(x_disp));
145: xswa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
146: PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
147:
148: x_win = XCreateWindow(x_disp, DefaultRootWindow(x_disp), 0, 0,
149: WidthOfScreen(ScreenOfDisplay(x_disp, 0)),
150: HeightOfScreen(ScreenOfDisplay(x_disp, 0)), 0,
151: CopyFromParent, InputOutput, CopyFromParent,
152: CWEventMask, &xswa);
153: XSetTransientForHint(x_disp, x_win, x_win);
154: x_hints = XAllocSizeHints();
155: x_hints->flags = USPosition;
156: XSetWMNormalHints(x_disp, x_win, x_hints);
157: // X_Free(x_hints);
158: XMapWindow(x_disp, x_win);
159: XRaiseWindow(x_disp, x_win);
160:
161: // check that vidmode extension is avail
162:
163: if (!XF86VidModeQueryVersion(x_disp, &MajorVersion, &MinorVersion))
164: Sys_Error("Unable to query VidMode version");
165: if (!XF86VidModeQueryExtension(x_disp, &EventBase, &ErrorBase))
166: Sys_Error("Unable to query VidMode extension");
167: if (MajorVersion < MINMAJOR || MinorVersion < MINMINOR)
168: Sys_Error("Minimum required VidMode extension version is %d.%d\n",
169: MINMAJOR, MINMINOR);
170:
171: // catch signals so i can die well
172:
173: sigaction(SIGINT, 0, &sa);
174: sa.sa_handler = TragicDeath;
175: sigaction(SIGINT, &sa, 0);
176: sigaction(SIGTERM, &sa, 0);
177:
178: // set up the mode and get info on the fb
179:
180: xrc = XF86DGAGetVideo(x_disp, DefaultScreen(x_disp), &hw_fb_addr,
181: &hw_fb_width, &hw_fb_banksize, &hw_fb_ram);
182: xrc = XF86DGADirectVideo(x_disp, DefaultScreen(x_disp),
183: XF86DGADirectGraphics|XF86DGADirectMouse|XF86DGADirectKeyb);
184: if (xrc != True)
185: Sys_Error("DirectVideo could not be setup\n");
186: direct_video_inited = 1;
187: setuid(getuid());
188: xrc = XF86DGASetViewPort(x_disp, DefaultScreen(x_disp), 0, 0);
189: xrc = XF86DGASetVidPage(x_disp, DefaultScreen(x_disp), 0);
190: xrc = XF86VidModeGetModeLine(x_disp, DefaultScreen(x_disp),
191: &hw_fb_dotclock, &hw_fb_modeline);
192:
193: vid.width = hw_fb_modeline.hdisplay;
194: vid.height = hw_fb_modeline.vdisplay;
195: vid.maxwarpwidth = WARP_WIDTH;
196: vid.maxwarpheight = WARP_HEIGHT;
197: vid.aspect = 1.0;
198: vid.numpages = 2;
199: vid.colormap = host_colormap;
200: vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
201:
202: // ritual for getting x_visinfo which basically just has the depth in it
203:
204: x_vis = DefaultVisual(x_disp, DefaultScreen(x_disp));
205: template.visualid = XVisualIDFromVisual(x_vis);
206: x_visinfo = XGetVisualInfo(x_disp, VisualIDMask, &template, &i);
207: pixbytes = x_visinfo->depth/8;
208:
209: // now know everything we need to know about the buffer
210:
211: work_buffer = 1;
212: vid.rowbytes = hw_fb_width * pixbytes;
213: flipaddr = hw_fb_addr + vid.rowbytes * vid.height;
214: flipy = vid.height;
215: vid.buffer = flipaddr;
216: vid.direct = hw_fb_addr;
217: vid.conbuffer = flipaddr;
218: vid.conrowbytes = vid.rowbytes;
219: vid.conwidth = vid.width;
220: vid.conheight = vid.height;
221:
222: Sys_Printf("VID: bank size = %d bytes\n", hw_fb_banksize);
223: Sys_Printf("VID: ram = %dkb\n", hw_fb_ram);
224:
225: if (hw_fb_banksize < vid.rowbytes * vid.height * 2)
226: Sys_Error("Video card bank size (%d bytes) too small for this res.", hw_fb_banksize);
227:
228: if (vid.rowbytes * vid.height * 2 > hw_fb_ram * 1024)
229: Sys_Error("Not enough video memory for this res");
230:
231: // create the GC
232:
233: xgcvalues.graphics_exposures = False;
234: x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
235:
236: // make input rawer
237:
238: XAutoRepeatOff(x_disp);
239: XGrabKeyboard(x_disp, x_win, True, GrabModeAsync,
240: GrabModeAsync, CurrentTime);
241: XGrabPointer(x_disp, x_win, True,
242: ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
243: None, None, CurrentTime);
244:
245: // setup colormap if necessary
246:
247: if (x_visinfo->depth == 8)
248: {
249:
250: if (x_visinfo->class == PseudoColor)
251: {
252: x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll);
253: VID_SetPalette(palette);
254: XInstallColormap(x_disp, x_cmap);
255: XSetWindowColormap(x_disp, x_win, x_cmap);
256: XSetWMColormapWindows(x_disp, x_win, &x_win, 1);
257: }
258:
259: }
260:
261: X11_highhunkmark = Hunk_HighMark ();
262: X11_buffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
263: vid_surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
264: X11_buffersize += vid_surfcachesize;
265: d_pzbuffer = Hunk_HighAllocName (X11_buffersize, "video");
266: if (d_pzbuffer == NULL)
267: Sys_Error ("Not enough memory for video mode\n");
268: vid_surfcache = (byte *) d_pzbuffer
269: + vid.width * vid.height * sizeof (*d_pzbuffer);
270: D_InitCaches(vid_surfcache, vid_surfcachesize);
271:
272: signal(SIGFPE, SIG_IGN);
273:
274: vid_inited = 1;
275:
276: }
277:
278: void VID_ShiftPalette(unsigned char *p)
279: {
280: if (!vid_inited) return;
281: VID_SetPalette(p);
282: }
283:
284: void VID_SetPalette(unsigned char *palette)
285: {
286:
287: int i;
288: XColor colors[256];
289:
290: if (!vid_inited) return;
291: if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8)
292: {
293: for (i=0 ; i<256 ; i++)
294: {
295: colors[i].pixel = i;
296: colors[i].flags = DoRed|DoGreen|DoBlue;
297: colors[i].red = palette[i*3] * 257;
298: colors[i].green = palette[i*3+1] * 257;
299: colors[i].blue = palette[i*3+2] * 257;
300: }
301: XStoreColors(x_disp, x_cmap, colors, 256);
302: }
303:
304: }
305:
306: // Called at shutdown
307:
308: void VID_Shutdown (void)
309: {
310: Con_Printf("VID_Shutdown\n");
311: if (x_disp)
312: {
313: XUngrabPointer(x_disp, CurrentTime);
314: XUngrabKeyboard(x_disp, CurrentTime);
315: XAutoRepeatOn(x_disp);
316: if (direct_video_inited)
317: XF86DGADirectVideo(x_disp, DefaultScreen(x_disp), 0);
318: direct_video_inited = 0;
319: XCloseDisplay(x_disp);
320: x_disp = 0;
321: }
322: vid_inited = 0;
323: }
324:
325: int XLateKey(XKeyEvent *ev)
326: {
327:
328: int key;
329: char buf[64];
330: KeySym keysym;
331:
332: key = 0;
333:
334: XLookupString(ev, buf, sizeof buf, &keysym, 0);
335:
336: switch(keysym)
337: {
338: case XK_Page_Up: key = K_PGUP; break;
339: case XK_Page_Down: key = K_PGDN; break;
340: case XK_Home: key = K_HOME; break;
341: case XK_End: key = K_END; break;
342: case XK_Left: key = K_LEFTARROW; break;
343: case XK_Right: key = K_RIGHTARROW; break;
344: case XK_Down: key = K_DOWNARROW; break;
345: case XK_Up: key = K_UPARROW; break;
346: case XK_Escape: key = K_ESCAPE; break;
347: case XK_Return: key = K_ENTER; break;
348: case XK_Tab: key = K_TAB; break;
349: case XK_F1: key = K_F1; break;
350: case XK_F2: key = K_F2; break;
351: case XK_F3: key = K_F3; break;
352: case XK_F4: key = K_F4; break;
353: case XK_F5: key = K_F5; break;
354: case XK_F6: key = K_F6; break;
355: case XK_F7: key = K_F7; break;
356: case XK_F8: key = K_F8; break;
357: case XK_F9: key = K_F9; break;
358: case XK_F10: key = K_F10; break;
359: case XK_F11: key = K_F11; break;
360: case XK_F12: key = K_F12; break;
361: case XK_BackSpace:
362: case XK_Delete: key = K_BACKSPACE; break;
363: case XK_Pause: key = K_PAUSE; break;
364: case XK_Shift_L:
365: case XK_Shift_R: key = K_SHIFT; break;
366: case XK_Execute:
367: case XK_Control_L:
368: case XK_Control_R: key = K_CTRL; break;
369: case XK_Alt_L:
370: case XK_Meta_L:
371: case XK_Alt_R:
372: case XK_Meta_R: key = K_ALT; break;
373:
374: case 0x07e: key = '`';break;/* [~] */
375: case 0x021: key = '1';break;/* [!] */
376: case 0x040: key = '2';break;/* [@] */
377: case 0x023: key = '3';break;/* [#] */
378: case 0x024: key = '4';break;/* [$] */
379: case 0x025: key = '5';break;/* [%] */
380: case 0x05e: key = '6';break;/* [^] */
381: case 0x026: key = '7';break;/* [&] */
382: case 0x02a: key = '8';break;/* [*] */
383: case 0x028: key = '9';;break;/* [(] */
384: case 0x029: key = '0';break;/* [)] */
385: case 0x05f: key = '-';break;/* [_] */
386: case 0x02b: key = '=';break;/* [+] */
387: case 0x07c: key = '\'';break;/* [|] */
388: case 0x07d: key = '[';break;/* [}] */
389: case 0x07b: key = ']';break;/* [{] */
390: case 0x022: key = '\'';break;/* ["] */
391: case 0x03a: key = ';';break;/* [:] */
392: case 0x03f: key = '/';break;/* [?] */
393: case 0x03e: key = '.';break;/* [>] */
394: case 0x03c: key = ',';break;/* [<] */
395:
396: default:
397: key = *(unsigned char*)buf;
398: if (key >= 'A' && key <= 'Z')
399: key = key - 'A' + 'a';
400: // fprintf(stderr, "case 0x0%x: key = ___;break;/* [%c] */\n", keysym);
401: break;
402: }
403:
404: return key;
405:
406: }
407:
408: struct
409: {
410: int key;
411: int down;
412: } keyq[64];
413: int keyq_head=0;
414: int keyq_tail=0;
415:
416: void GetEvent(void)
417: {
418:
419: XEvent x_event;
420: int b;
421:
422: XNextEvent(x_disp, &x_event);
423: switch(x_event.type)
424: {
425: case KeyPress:
426: keyq[keyq_head].key = XLateKey(&x_event.xkey);
427: keyq[keyq_head].down = true;
428: keyq_head = (keyq_head + 1) & 63;
429: break;
430: case KeyRelease:
431: keyq[keyq_head].key = XLateKey(&x_event.xkey);
432: keyq[keyq_head].down = false;
433: keyq_head = (keyq_head + 1) & 63;
434: break;
435: case MotionNotify:
436: mouse_x += (float) x_event.xmotion.x;
437: mouse_y += (float) x_event.xmotion.y;
438: break;
439: case ButtonPress:
440: b=-1;
441: if (x_event.xbutton.button == Button1)
442: b = 0;
443: else if (x_event.xbutton.button == Button2)
444: b = 2;
445: else if (x_event.xbutton.button == Button3)
446: b = 1;
447: if (b>=0)
448: mouse_buttonstate |= 1<<b;
449: break;
450: case ButtonRelease:
451: b=-1;
452: if (x_event.xbutton.button == Button1)
453: b = 0;
454: else if (x_event.xbutton.button == Button2)
455: b = 2;
456: else if (x_event.xbutton.button == Button3)
457: b = 1;
458: if (b>=0)
459: mouse_buttonstate &= ~(1<<b);
460: break;
461: }
462:
463: }
464:
465: // flushes the given rectangles from the view buffer to the screen
466:
467: void VID_Update (vrect_t *rects)
468: {
469:
470: if (!vid_inited) return;
471:
472: // flip pages
473:
474: XF86DGASetViewPort(x_disp, DefaultScreen(x_disp), 0,
475: flipy * work_buffer);
476:
477: work_buffer = !work_buffer;
478: if (work_buffer)
479: {
480: vid.buffer = flipaddr;
481: vid.conbuffer = flipaddr;
482: vid.direct = hw_fb_addr;
483: }
484: else
485: {
486: vid.buffer = hw_fb_addr;
487: vid.conbuffer = hw_fb_addr;
488: vid.direct = flipaddr;
489: }
490:
491: XSync(x_disp, False);
492:
493: }
494:
495: static int dither;
496:
497: void VID_DitherOn(void)
498: {
499: if (dither == 0)
500: {
501: vid.recalc_refdef = 1;
502: dither = 1;
503: }
504: }
505:
506: void VID_DitherOff(void)
507: {
508: if (dither)
509: {
510: vid.recalc_refdef = 1;
511: dither = 0;
512: }
513: }
514:
515: int Sys_OpenWindow(void)
516: {
517: return 0;
518: }
519:
520: void Sys_EraseWindow(int window)
521: {
522: }
523:
524: void Sys_DrawCircle(int window, int x, int y, int r)
525: {
526: }
527:
528: void Sys_DisplayWindow(int window)
529: {
530: }
531:
532: void Sys_SendKeyEvents(void)
533: {
534: if (!vid_inited) return;
535: // get events from x server
536: if (x_disp)
537: {
538: while (XPending(x_disp)) GetEvent();
539: while (keyq_head != keyq_tail)
540: {
541: Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down);
542: keyq_tail = (keyq_tail + 1) & 63;
543: }
544: }
545: }
546:
547: char *Sys_ConsoleInput (void)
548: {
549:
550: static char text[256];
551: int len;
552: fd_set readfds;
553: int ready;
554: struct timeval timeout;
555:
556: timeout.tv_sec = 0;
557: timeout.tv_usec = 0;
558: FD_ZERO(&readfds);
559: FD_SET(0, &readfds);
560: ready = select(1, &readfds, 0, 0, &timeout);
561:
562: if (ready>0)
563: {
564: len = read (0, text, sizeof(text));
565: if (len >= 1)
566: {
567: text[len-1] = 0; // rip off the /n and terminate
568: return text;
569: }
570: }
571:
572: return 0;
573:
574: }
575:
576:
577: static byte backingbuf[48*24];
578:
579: void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
580: {
581: int i, j, reps, repshift;
582:
583: if (!vid_inited) return;
584:
585: if (vid.aspect > 1.5)
586: {
587: reps = 2;
588: repshift = 1;
589: }
590: else
591: {
592: reps = 1;
593: repshift = 0;
594: }
595:
596: for (i=0 ; i<(height << repshift) ; i += reps)
597: {
598: for (j=0 ; j<reps ; j++)
599: {
600: memcpy (&backingbuf[(i + j) * 24],
601: vid.direct + x + ((y << repshift) + i + j) *
602: vid.rowbytes, width);
603: memcpy (vid.direct + x + ((y << repshift) + i + j) *
604: vid.rowbytes, &pbitmap[(i >> repshift) * width], width);
605: }
606: }
607:
608: }
609:
610: void D_EndDirectRect (int x, int y, int width, int height)
611: {
612: int i, j, reps, repshift;
613:
614: if (!vid_inited) return;
615:
616: if (vid.aspect > 1.5)
617: {
618: reps = 2;
619: repshift = 1;
620: }
621: else
622: {
623: reps = 1;
624: repshift = 0;
625: }
626:
627: for (i=0 ; i<(height << repshift) ; i += reps)
628: {
629: for (j=0 ; j<reps ; j++)
630: {
631: memcpy (vid.direct + x + ((y << repshift) + i + j) *
632: vid.rowbytes, &backingbuf[(i + j) * 24], width);
633: }
634: }
635:
636: }
637:
638: /*
639: ===========
640: IN_Init
641: ===========
642: */
643: void IN_Init (void)
644: {
645: Cvar_RegisterVariable (&m_filter);
646: if ( COM_CheckParm ("-nomouse") )
647: return;
648: mouse_x = mouse_y = 0.0;
649: mouse_avail = 1;
650: }
651:
652: /*
653: ===========
654: IN_Shutdown
655: ===========
656: */
657: void IN_Shutdown (void)
658: {
659: mouse_avail = 0;
660: }
661:
662:
663: /*
664: ===========
665: IN_Commands
666: ===========
667: */
668: void IN_Commands (void)
669: {
670: int i;
671:
672: if (!vid_inited || !mouse_avail) return;
673:
674: // perform button actions
675: for (i=0 ; i<mouse_buttons ; i++)
676: {
677: if ( (mouse_buttonstate & (1<<i)) &&
678: !(mouse_oldbuttonstate & (1<<i)) )
679: {
680: Key_Event (K_MOUSE1 + i, true);
681: }
682: if ( !(mouse_buttonstate & (1<<i)) &&
683: (mouse_oldbuttonstate & (1<<i)) )
684: {
685: Key_Event (K_MOUSE1 + i, false);
686: }
687: }
688:
689: mouse_oldbuttonstate = mouse_buttonstate;
690:
691: }
692:
693: /*
694: ===========
695: IN_Move
696: ===========
697: */
698: void IN_Move (usercmd_t *cmd)
699: {
700:
701: if (!vid_inited || !mouse_avail)
702: return;
703:
704: if (m_filter.value)
705: {
706: mouse_x = (mouse_x + old_mouse_x) * 0.5;
707: mouse_y = (mouse_y + old_mouse_y) * 0.5;
708: }
709: old_mouse_x = mouse_x;
710: old_mouse_y = mouse_y;
711:
712: mouse_x *= sensitivity.value;
713: mouse_y *= sensitivity.value;
714:
715: // add mouse X/Y movement to cmd
716: if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
717: cmd->sidemove += m_side.value * mouse_x;
718: else
719: cl.viewangles[YAW] -= m_yaw.value * mouse_x;
720:
721: if (in_mlook.state & 1)
722: V_StopPitchDrift ();
723:
724: if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
725: {
726: cl.viewangles[PITCH] += m_pitch.value * mouse_y;
727: if (cl.viewangles[PITCH] > 80)
728: cl.viewangles[PITCH] = 80;
729: if (cl.viewangles[PITCH] < -70)
730: cl.viewangles[PITCH] = -70;
731: }
732: else
733: {
734: if ((in_strafe.state & 1) && noclip_anglehack)
735: cmd->upmove -= m_forward.value * mouse_y;
736: else
737: cmd->forwardmove -= m_forward.value * mouse_y;
738: }
739:
740: mouse_x = mouse_y = 0.0;
741:
742: }
743:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.