|
|
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 <signal.h>
7: #include <stdlib.h>
8: #include <stdio.h>
9: #include <string.h>
10: #include <sys/ipc.h>
11: #include <sys/shm.h>
12: #include <X11/Xlib.h>
13: #include <X11/Xutil.h>
14: #include <X11/Xatom.h>
15: #include <X11/keysym.h>
16: #include <X11/extensions/XShm.h>
17: #include <GL/gl.h>
18: #include <GL/glx.h>
19: #include <GL/glu.h>
20:
21: #include "quakedef.h"
22: #include "vid_256.h"
23:
24: typedef struct
25: {
26: int input;
27: int output;
28: } keymap_t;
29:
30: viddef_t vid; // global video state
31:
32: int num_shades=32;
33:
34: static qboolean doShm;
35: static Display *x_disp;
36: static Colormap x_cmap;
37: static Window x_win;
38: static GC x_gc;
39: static Visual *x_vis;
40: static XVisualInfo *x_visinfo=0;
41: //static XImage *x_image;
42: static int x_screen;
43:
44: static int x_shmeventtype;
45: //static XShmSegmentInfo x_shminfo;
46:
47: static qboolean oktodraw = false;
48:
49: static unsigned char *framebuffer=0;
50:
51: static int verbose=0;
52:
53: static short *jcspace=0;
54:
55: static qboolean doGLX;
56: static int glX_errorBase, glX_eventBase;
57: static GLXContext glX_context;
58:
59: static qboolean glX_scaled=0;
60: static GLfloat glX_scale_width;
61: static GLfloat glX_scale_height;
62:
63: static int config_notify=0;
64: static int config_notify_width;
65: static int config_notify_height;
66:
67: int d_con_indirect = 0;
68:
69: void Scaled_f(void)
70: {
71: config_notify = 1;
72: glX_scaled = 1;
73: }
74:
75: void UnScaled_f(void)
76: {
77: config_notify = 1;
78: glX_scaled = 0;
79: }
80:
81: // ========================================================================
82: // Tragic death handler
83: // ========================================================================
84:
85: void TragicDeath(int signal_num)
86: {
87: XAutoRepeatOn(x_disp);
88: XCloseDisplay(x_disp);
89: I_Error("This death brought to you by the number %d\n", signal_num);
90: }
91:
92: // ========================================================================
93: // makes a null cursor
94: // ========================================================================
95:
96: static Cursor CreateNullCursor(Display *display, Window root)
97: {
98: Pixmap cursormask;
99: XGCValues xgc;
100: GC gc;
101: XColor dummycolour;
102: Cursor cursor;
103:
104: cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
105: xgc.function = GXclear;
106: gc = XCreateGC(display, cursormask, GCFunction, &xgc);
107: XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
108: dummycolour.pixel = 0;
109: dummycolour.red = 0;
110: dummycolour.flags = 04;
111: cursor = XCreatePixmapCursor(display, cursormask, cursormask,
112: &dummycolour,&dummycolour, 0,0);
113: XFreePixmap(display,cursormask);
114: XFreeGC(display,gc);
115: return cursor;
116: }
117:
118: void ResetFrameBuffer(void)
119: {
120:
121: int mem;
122: int pwidth;
123:
124: if (!glX_scaled)
125: {
126:
127: if (framebuffer)
128: Z_Free(framebuffer);
129:
130: pwidth = 4;
131: mem = vid.width*4 * vid.height;
132:
133: framebuffer = Z_Malloc(mem);
134:
135: vid.rowbytes = 2 * vid.width;
136: if (jcspace) Z_Free(jcspace);
137: jcspace = Z_Malloc(vid.rowbytes * vid.height);
138: vid.buffer = (pixel_t *) jcspace;
139:
140: glViewport(0, 0, vid.width, vid.height);
141: glMatrixMode(GL_PROJECTION);
142: glLoadIdentity();
143: gluOrtho2D(0, vid.width, 0, vid.height);
144: glMatrixMode(GL_MODELVIEW);
145: glLoadIdentity();
146:
147: glPixelZoom(1.0, -1.0);
148: glRasterPos2i(0, vid.height);
149:
150: }
151: else
152: {
153: glViewport(0, 0, config_notify_width, config_notify_height);
154: glMatrixMode(GL_PROJECTION);
155: glLoadIdentity();
156: gluOrtho2D(0, config_notify_width, 0, config_notify_height);
157: glMatrixMode(GL_MODELVIEW);
158: glLoadIdentity();
159:
160: glX_scale_width = (float) config_notify_width / vid.width;
161: glX_scale_height = (float) config_notify_height / vid.height;
162: glPixelZoom(glX_scale_width, -glX_scale_height);
163:
164: glRasterPos2i(0, config_notify_height);
165:
166: }
167:
168: }
169:
170: int *lookup24;
171:
172: void InitLookup24(unsigned char *pal)
173: {
174:
175: int intensity;
176: int color;
177: int r, g, b;
178:
179: lookup24 = Z_Malloc(VID_GRADES * 256 * 4);
180:
181: // intensities go from 0 (bright) to VID_GRADES - 1 (dark)
182:
183: for (intensity = 0 ; intensity < VID_GRADES ; intensity++)
184: {
185: for (color = 0 ; color < 256 ; color++)
186: {
187: r = pal[color*3] * (VID_GRADES - intensity) / VID_GRADES;
188: g = pal[color*3+1] * (VID_GRADES - intensity) / VID_GRADES;
189: b = pal[color*3+2] * (VID_GRADES - intensity) / VID_GRADES;
190: r = (r<<24) + (r<<16) + (r<<8) + r;
191: g = (g<<24) + (g<<16) + (g<<8) + g;
192: b = (b<<24) + (b<<16) + (b<<8) + b;
193: r = r & 0xff000000;
194: g = g & 0x00ff0000;
195: b = b & 0x0000ff00;
196: /*
197: r = r & x_visinfo->red_mask;
198: g = g & x_visinfo->green_mask;
199: b = b & x_visinfo->blue_mask;
200: */
201: lookup24[intensity * 256 + color] = r + g + b;
202: }
203: }
204:
205: }
206:
207: void JCSpaceTo24(void)
208: {
209:
210: int rowcount;
211: int height;
212: short *from;
213: int *to;
214:
215: from = jcspace;
216: to = (int*) framebuffer;
217:
218: for (height = vid.height ; height ; height--)
219: {
220: for (rowcount = vid.width ; rowcount ; rowcount--)
221: {
222: *to = lookup24[*from];
223: from++;
224: to++;
225: }
226: }
227:
228: }
229:
230: void PickVisual(void)
231: {
232:
233: int attribList1[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8,
234: GLX_BLUE_SIZE, 8, GLX_GREEN_SIZE, 8, None };
235: int attribList2[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
236: GLX_BLUE_SIZE, 8, None };
237:
238: doGLX = glXQueryExtension(x_disp, &glX_errorBase, &glX_eventBase);
239: if (!doGLX) I_Error("OpenGL not supported\n");
240:
241: x_visinfo = glXChooseVisual(x_disp, x_screen, attribList1);
242: if (!x_visinfo)
243: x_visinfo = glXChooseVisual(x_disp, x_screen, attribList2);
244: else
245: printf("double-buffered\n");
246: if (!x_visinfo)
247: I_Error("Could not chose an RGB visual. Use X version.\n");
248: else
249: printf("single-buffered\n");
250:
251: // if (verbose)
252: {
253: printf("Using visualid %d:\n", (int)(x_visinfo->visualid));
254: printf(" screen %d\n", x_visinfo->screen);
255: printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask));
256: printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask));
257: printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask));
258: printf(" colormap_size %d\n", x_visinfo->colormap_size);
259: printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb);
260: }
261:
262: x_vis = x_visinfo->visual;
263:
264: }
265:
266: void CreateWindow(void)
267: {
268:
269: // setup attributes for main window
270: int attribmask = CWEventMask | CWColormap | CWBorderPixel;
271: XSetWindowAttributes attribs;
272: Colormap tmpcmap;
273:
274: tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp,
275: x_visinfo->screen), x_vis, AllocNone);
276:
277: attribs.event_mask = StructureNotifyMask | KeyPressMask
278: | KeyReleaseMask | ExposureMask;
279: attribs.border_pixel = 0;
280: attribs.colormap = tmpcmap;
281:
282: // create the main window
283: x_win = XCreateWindow( x_disp,
284: XRootWindow(x_disp, x_visinfo->screen),
285: 0, 0, // x, y
286: vid.width, vid.height,
287: 0, // borderwidth
288: x_visinfo->depth,
289: InputOutput,
290: x_vis,
291: attribmask,
292: &attribs );
293:
294: XFreeColormap(x_disp, tmpcmap);
295:
296: }
297:
298: // Called at startup to set up translation tables, takes 256 8 bit RGB values
299: // the palette data will go away after the call, so it must be copied off if
300: // the video driver will need it again
301:
302: void VID_Init (unsigned char *palette)
303: {
304:
305: int pnum, i;
306: int num_visuals;
307:
308: Cmd_AddCommand("glx_scaled", Scaled_f);
309: Cmd_AddCommand("glx_unscaled", UnScaled_f);
310:
311: vid.width = 320;
312: vid.height = 200;
313: vid.aspect = 1.0;
314: vid.numpages = 1;
315:
316: srandom(getpid());
317:
318: verbose=COM_CheckParm("-verbose");
319:
320: // open the display
321: x_disp = XOpenDisplay(0);
322: if (!x_disp)
323: {
324: if (getenv("DISPLAY"))
325: I_Error("VID: Could not open display [%s]\n",
326: getenv("DISPLAY"));
327: else
328: I_Error("VID: Could not open local display\n");
329: }
330:
331: x_screen = DefaultScreen(x_disp);
332:
333: // catch signals so i can turn on auto-repeat
334:
335: {
336: struct sigaction sa;
337: sigaction(SIGINT, 0, &sa);
338: sa.sa_handler = TragicDeath;
339: sigaction(SIGINT, &sa, 0);
340: sigaction(SIGTERM, &sa, 0);
341: }
342:
343: XAutoRepeatOff(x_disp);
344:
345: // for debugging only
346: XSynchronize(x_disp, True);
347:
348: // check for command-line window size
349: if ((pnum=COM_CheckParm("-winsize")))
350: {
351: if (pnum >= com_argc-2)
352: I_Error("VID: -winsize <width> <height>\n");
353: vid.width = Q_atoi(com_argv[pnum+1]);
354: vid.height = Q_atoi(com_argv[pnum+2]);
355: if (!vid.width || !vid.height)
356: I_Error("VID: Bad window width/height\n");
357: }
358:
359: PickVisual();
360:
361: CreateWindow();
362:
363: glX_context = glXCreateContext(x_disp, x_visinfo, 0, True);
364: glXMakeCurrent(x_disp, x_win, glX_context);
365: glPixelZoom(1.0, -1.0);
366:
367: // create the GC
368: {
369: XGCValues xgcvalues;
370: int valuemask = GCGraphicsExposures;
371: xgcvalues.graphics_exposures = False;
372: x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues );
373: }
374:
375: InitLookup24(palette);
376:
377: // inviso cursor
378: XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win));
379:
380: // map the window
381: XMapWindow(x_disp, x_win);
382:
383: // wait for first exposure event
384: {
385: XEvent event;
386: do
387: {
388: XNextEvent(x_disp, &event);
389: if (event.type == Expose && !event.xexpose.count)
390: oktodraw = true;
391: } while (!oktodraw);
392: }
393: // now safe to draw
394:
395: ResetFrameBuffer();
396:
397: XSynchronize(x_disp, False);
398:
399: }
400:
401: void VID_SetPalette(unsigned char *palette)
402: {
403:
404: if (lookup24)
405: Z_Free(lookup24);
406: InitLookup24(palette);
407:
408: }
409:
410: // Called at shutdown
411:
412: void VID_Shutdown (void)
413: {
414: I_Printf("VID_Shutdown\n");
415: XAutoRepeatOn(x_disp);
416: XCloseDisplay(x_disp);
417: }
418:
419: int XLateKey(XKeyEvent *ev)
420: {
421:
422: int key;
423: char buf[64];
424: KeySym keysym;
425:
426: XLookupString(ev, buf, sizeof buf, &keysym, 0);
427:
428: switch(keysym)
429: {
430: case XK_Left: key = K_LEFTARROW; break;
431: case XK_Right: key = K_RIGHTARROW; break;
432: case XK_Down: key = K_DOWNARROW; break;
433: case XK_Up: key = K_UPARROW; break;
434: case XK_Escape: key = K_ESCAPE; break;
435: case XK_Return: key = K_ENTER; break;
436: case XK_Tab: key = K_TAB; break;
437: case XK_F1: key = K_F1; break;
438: case XK_F2: key = K_F2; break;
439: case XK_F3: key = K_F3; break;
440: case XK_F4: key = K_F4; break;
441: case XK_F5: key = K_F5; break;
442: case XK_F6: key = K_F6; break;
443: case XK_F7: key = K_F7; break;
444: case XK_F8: key = K_F8; break;
445: case XK_F9: key = K_F9; break;
446: case XK_F10: key = K_F10; break;
447: case XK_F11: key = K_F11; break;
448: case XK_F12: key = K_F12; break;
449: case XK_BackSpace:
450: case XK_Delete: key = K_BACKSPACE; break;
451: case XK_Pause: key = K_PAUSE; break;
452: case XK_Shift_L:
453: case XK_Shift_R: key = K_SHIFT; break;
454: case XK_Control_L:
455: case XK_Control_R: key = K_CTRL; break;
456: case XK_Alt_L:
457: case XK_Meta_L:
458: case XK_Alt_R:
459: case XK_Meta_R: key = K_ALT; break;
460: default:
461: key = *buf;
462: break;
463: }
464:
465: return key;
466:
467: }
468:
469: void GetEvent(void)
470: {
471:
472: XEvent x_event;
473:
474: XNextEvent(x_disp, &x_event);
475: switch(x_event.type)
476: {
477: case KeyPress:
478: Key_Event(XLateKey(&x_event.xkey), true);
479: break;
480: case KeyRelease:
481: Key_Event(XLateKey(&x_event.xkey), false);
482: break;
483: case ConfigureNotify:
484: // printf("config notify\n");
485: config_notify_width = x_event.xconfigure.width;
486: config_notify_height = x_event.xconfigure.height;
487: config_notify = 1;
488: break;
489: }
490:
491: }
492:
493: // flushes the given rectangles from the view buffer to the screen
494:
495: void VID_Update (vrect_t *rects)
496: {
497:
498: // if the window changes dimension, skip this frame
499:
500: if (config_notify)
501: {
502: printf("config notify\n");
503: config_notify = 0;
504: if (!glX_scaled)
505: {
506: vid.width = config_notify_width & ~3;
507: vid.height = config_notify_height;
508: }
509: ResetFrameBuffer();
510: return;
511: }
512:
513: // slam that baby
514:
515: JCSpaceTo24();
516: glDrawPixels(vid.width, vid.height, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
517: glFlush();
518: glXSwapBuffers(x_disp, x_win);
519:
520: }
521:
522: static int dither;
523:
524: void VID_DitherOn(void)
525: {
526: if (dither == 0)
527: {
528: vid.recalc_refdef = 1;
529: dither = 1;
530: }
531: }
532:
533: void VID_DitherOff(void)
534: {
535: if (dither)
536: {
537: vid.recalc_refdef = 1;
538: dither = 0;
539: }
540: }
541:
542: int I_OpenWindow(void)
543: {
544: return 0;
545: }
546:
547: void I_EraseWindow(int window)
548: {
549: }
550:
551: void I_DrawCircle(int window, int x, int y, int r)
552: {
553: }
554:
555: void I_DisplayWindow(int window)
556: {
557: }
558:
559: void Sys_SendKeyEvents(void)
560: {
561: // get events from x server
562: while (XPending(x_disp)) GetEvent();
563: }
564:
565: char *Sys_ConsoleInput (void)
566: {
567:
568: static char text[256];
569: int len;
570: fd_set readfds;
571: int ready;
572: struct timeval timeout;
573:
574: timeout.tv_sec = 0;
575: timeout.tv_usec = 0;
576: FD_ZERO(&readfds);
577: FD_SET(0, &readfds);
578: ready = select(1, &readfds, 0, 0, &timeout);
579:
580: if (ready>0)
581: {
582: len = read (0, text, sizeof(text));
583: if (len >= 1)
584: {
585: text[len-1] = 0; // rip off the /n and terminate
586: return text;
587: }
588: }
589:
590: return 0;
591:
592: }
593:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.