i_video.c (17378B)
1 #include <stdlib.h> 2 #include <unistd.h> 3 #include <sys/ipc.h> 4 #include <sys/shm.h> 5 #include <X11/Xlib.h> 6 #include <X11/Xutil.h> 7 #include <X11/keysym.h> 8 #include <X11/extensions/XShm.h> 9 10 int XShmGetEventBase( Display* dpy ); 11 12 #include <stdarg.h> 13 #include <sys/time.h> 14 #include <sys/types.h> 15 #include <sys/socket.h> 16 #include <netinet/in.h> 17 #include <errno.h> 18 #include <signal.h> 19 #include "doomstat.h" 20 #include "i_system.h" 21 #include "v_video.h" 22 #include "m_argv.h" 23 #include "d_main.h" 24 #include "doomdef.h" 25 26 #define POINTER_WARP_COUNTDOWN 1 27 28 byte gammatable[5][256] = { 29 {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 30 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, 31 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48, 32 49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, 33 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80, 34 81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96, 35 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, 36 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, 37 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 38 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, 39 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, 40 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, 41 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, 42 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, 43 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 44 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}, 45 46 {2,4,5,7,8,10,11,12,14,15,16,18,19,20,21,23,24,25,26,27,29,30,31, 47 32,33,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,54,55, 48 56,57,58,59,60,61,62,63,64,65,66,67,69,70,71,72,73,74,75,76,77, 49 78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98, 50 99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114, 51 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,129, 52 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, 53 146,147,148,148,149,150,151,152,153,154,155,156,157,158,159,160, 54 161,162,163,163,164,165,166,167,168,169,170,171,172,173,174,175, 55 175,176,177,178,179,180,181,182,183,184,185,186,186,187,188,189, 56 190,191,192,193,194,195,196,196,197,198,199,200,201,202,203,204, 57 205,205,206,207,208,209,210,211,212,213,214,214,215,216,217,218, 58 219,220,221,222,222,223,224,225,226,227,228,229,230,230,231,232, 59 233,234,235,236,237,237,238,239,240,241,242,243,244,245,245,246, 60 247,248,249,250,251,252,252,253,254,255}, 61 62 {4,7,9,11,13,15,17,19,21,22,24,26,27,29,30,32,33,35,36,38,39,40,42, 63 43,45,46,47,48,50,51,52,54,55,56,57,59,60,61,62,63,65,66,67,68,69, 64 70,72,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,92,93, 65 94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112, 66 113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, 67 129,130,131,132,133,133,134,135,136,137,138,139,140,141,142,143,144, 68 144,145,146,147,148,149,150,151,152,153,153,154,155,156,157,158,159, 69 160,160,161,162,163,164,165,166,166,167,168,169,170,171,172,172,173, 70 174,175,176,177,178,178,179,180,181,182,183,183,184,185,186,187,188, 71 188,189,190,191,192,193,193,194,195,196,197,197,198,199,200,201,201, 72 202,203,204,205,206,206,207,208,209,210,210,211,212,213,213,214,215, 73 216,217,217,218,219,220,221,221,222,223,224,224,225,226,227,228,228, 74 229,230,231,231,232,233,234,235,235,236,237,238,238,239,240,241,241, 75 242,243,244,244,245,246,247,247,248,249,250,251,251,252,253,254,254, 76 255}, 77 78 {8,12,16,19,22,24,27,29,31,34,36,38,40,41,43,45,47,49,50,52,53,55, 79 57,58,60,61,63,64,65,67,68,70,71,72,74,75,76,77,79,80,81,82,84,85, 80 86,87,88,90,91,92,93,94,95,96,98,99,100,101,102,103,104,105,106,107, 81 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124, 82 125,126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140, 83 141,142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155, 84 155,156,157,158,159,160,160,161,162,163,164,165,165,166,167,168,169, 85 169,170,171,172,173,173,174,175,176,176,177,178,179,180,180,181,182, 86 183,183,184,185,186,186,187,188,189,189,190,191,192,192,193,194,195, 87 195,196,197,197,198,199,200,200,201,202,202,203,204,205,205,206,207, 88 207,208,209,210,210,211,212,212,213,214,214,215,216,216,217,218,219, 89 219,220,221,221,222,223,223,224,225,225,226,227,227,228,229,229,230, 90 231,231,232,233,233,234,235,235,236,237,237,238,238,239,240,240,241, 91 242,242,243,244,244,245,246,246,247,247,248,249,249,250,251,251,252, 92 253,253,254,254,255}, 93 94 {16,23,28,32,36,39,42,45,48,50,53,55,57,60,62,64,66,68,69,71,73,75,76, 95 78,80,81,83,84,86,87,89,90,92,93,94,96,97,98,100,101,102,103,105,106, 96 107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124, 97 125,126,128,128,129,130,131,132,133,134,135,136,137,138,139,140,141, 98 142,143,143,144,145,146,147,148,149,150,150,151,152,153,154,155,155, 99 156,157,158,159,159,160,161,162,163,163,164,165,166,166,167,168,169, 100 169,170,171,172,172,173,174,175,175,176,177,177,178,179,180,180,181, 101 182,182,183,184,184,185,186,187,187,188,189,189,190,191,191,192,193, 102 193,194,195,195,196,196,197,198,198,199,200,200,201,202,202,203,203, 103 204,205,205,206,207,207,208,208,209,210,210,211,211,212,213,213,214, 104 214,215,216,216,217,217,218,219,219,220,220,221,221,222,223,223,224, 105 224,225,225,226,227,227,228,228,229,229,230,230,231,232,232,233,233, 106 234,234,235,235,236,236,237,237,238,239,239,240,240,241,241,242,242, 107 243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251, 108 251,252,252,253,254,254,255,255} 109 }; 110 111 Display* X_display = 0; 112 Window X_mainWindow; 113 Colormap X_cmap; 114 Visual* X_visual; 115 GC X_gc; 116 XEvent X_event; 117 int X_screen; 118 XVisualInfo X_visualinfo; 119 XImage* image; 120 int X_width; 121 int X_height; 122 boolean doShm; 123 XShmSegmentInfo X_shminfo; 124 int X_shmeventtype; 125 boolean grabMouse; 126 int doPointerWarp = POINTER_WARP_COUNTDOWN; 127 static int multiply = 1; 128 129 int 130 xlatekey() 131 { 132 int rc; 133 134 switch (rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0)) { 135 case XK_Left: rc = KEY_LEFTARROW; break; 136 case XK_Right: rc = KEY_RIGHTARROW; break; 137 case XK_Down: rc = KEY_DOWNARROW; break; 138 case XK_Up: rc = KEY_UPARROW; break; 139 case XK_Escape: rc = KEY_ESCAPE; break; 140 case XK_Return: rc = KEY_ENTER; break; 141 case XK_Tab: rc = KEY_TAB; break; 142 case XK_F1: rc = KEY_F1; break; 143 case XK_F2: rc = KEY_F2; break; 144 case XK_F3: rc = KEY_F3; break; 145 case XK_F4: rc = KEY_F4; break; 146 case XK_F5: rc = KEY_F5; break; 147 case XK_F6: rc = KEY_F6; break; 148 case XK_F7: rc = KEY_F7; break; 149 case XK_F8: rc = KEY_F8; break; 150 case XK_F9: rc = KEY_F9; break; 151 case XK_F10: rc = KEY_F10; break; 152 case XK_F11: rc = KEY_F11; break; 153 case XK_F12: rc = KEY_F12; break; 154 case XK_BackSpace: 155 case XK_Delete: rc = KEY_BACKSPACE; break; 156 case XK_Pause: rc = KEY_PAUSE; break; 157 case XK_KP_Equal: 158 case XK_equal: rc = KEY_EQUALS; break; 159 case XK_KP_Subtract: 160 case XK_minus: rc = KEY_MINUS; break; 161 case XK_Shift_L: 162 case XK_Shift_R: rc = KEY_RSHIFT; break; 163 case XK_Control_L: 164 case XK_Control_R: rc = KEY_RCTRL; break; 165 case XK_Alt_L: 166 case XK_Meta_L: 167 case XK_Alt_R: 168 case XK_Meta_R: rc = KEY_RALT; break; 169 default: 170 if (rc >= XK_space && rc <= XK_asciitilde) 171 rc = rc - XK_space + 0x20; 172 if (rc >= 'A' && rc <= 'Z') 173 rc = rc - 0x41 + 0x61; 174 break; 175 } 176 return rc; 177 } 178 179 void 180 I_ShutdownGraphics() 181 { 182 if (!XShmDetach(X_display, &X_shminfo)) 183 I_Error("XShmDetach() failed in I_ShutdownGraphics()"); 184 shmdt(X_shminfo.shmaddr); 185 shmctl(X_shminfo.shmid, IPC_RMID, 0); 186 image->data = NULL; 187 } 188 189 static int lastmousex = 0; 190 static int lastmousey = 0; 191 boolean mousemoved = false; 192 boolean shmFinished; 193 194 void 195 I_GetEvent() 196 { 197 event_t event; 198 199 XNextEvent(X_display, &X_event); 200 switch (X_event.type) { 201 case KeyPress: 202 event.type = ev_keydown; 203 event.data1 = xlatekey(); 204 D_PostEvent(&event); 205 break; 206 case KeyRelease: 207 event.type = ev_keyup; 208 event.data1 = xlatekey(); 209 D_PostEvent(&event); 210 break; 211 case ButtonPress: 212 event.type = ev_mouse; 213 event.data1 = 214 (X_event.xbutton.state & Button1Mask) 215 | (X_event.xbutton.state & Button2Mask ? 2 : 0) 216 | (X_event.xbutton.state & Button3Mask ? 4 : 0) 217 | (X_event.xbutton.button == Button1) 218 | (X_event.xbutton.button == Button2 ? 2 : 0) 219 | (X_event.xbutton.button == Button3 ? 4 : 0); 220 event.data2 = event.data3 = 0; 221 D_PostEvent(&event); 222 break; 223 case ButtonRelease: 224 event.type = ev_mouse; 225 event.data1 = 226 (X_event.xbutton.state & Button1Mask) 227 | (X_event.xbutton.state & Button2Mask ? 2 : 0) 228 | (X_event.xbutton.state & Button3Mask ? 4 : 0); 229 event.data1 = 230 event.data1 231 ^ (X_event.xbutton.button == Button1 ? 1 : 0) 232 ^ (X_event.xbutton.button == Button2 ? 2 : 0) 233 ^ (X_event.xbutton.button == Button3 ? 4 : 0); 234 event.data2 = event.data3 = 0; 235 D_PostEvent(&event); 236 break; 237 case MotionNotify: 238 event.type = ev_mouse; 239 event.data1 = 240 (X_event.xmotion.state & Button1Mask) 241 | (X_event.xmotion.state & Button2Mask ? 2 : 0) 242 | (X_event.xmotion.state & Button3Mask ? 4 : 0); 243 event.data2 = (X_event.xmotion.x - lastmousex) << 2; 244 event.data3 = (lastmousey - X_event.xmotion.y) << 2; 245 if (event.data2 || event.data3) { 246 lastmousex = X_event.xmotion.x; 247 lastmousey = X_event.xmotion.y; 248 if (X_event.xmotion.x != X_width/2 && X_event.xmotion.y != X_height/2) { 249 D_PostEvent(&event); 250 mousemoved = false; 251 } else 252 mousemoved = true; 253 } 254 break; 255 case Expose: 256 case ConfigureNotify: 257 break; 258 default: 259 if (doShm && X_event.type == X_shmeventtype) 260 shmFinished = true; 261 break; 262 } 263 } 264 265 Cursor 266 createnullcursor(Display* display, Window root) 267 { 268 Pixmap cursormask; 269 XGCValues xgc; 270 GC gc; 271 XColor dummycolour; 272 Cursor cursor; 273 274 cursormask = XCreatePixmap(display, root, 1, 1, 1); 275 xgc.function = GXclear; 276 gc = XCreateGC(display, cursormask, GCFunction, &xgc); 277 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); 278 dummycolour.pixel = 0; 279 dummycolour.red = 0; 280 dummycolour.flags = 04; 281 cursor = XCreatePixmapCursor(display, cursormask, cursormask, &dummycolour,&dummycolour, 0,0); 282 XFreePixmap(display,cursormask); 283 XFreeGC(display,gc); 284 return cursor; 285 } 286 287 void 288 I_StartTic() 289 { 290 if (!X_display) 291 return; 292 while (XPending(X_display)) 293 I_GetEvent(); 294 if (grabMouse) { 295 if (!--doPointerWarp) { 296 XWarpPointer(X_display, None, X_mainWindow, 0, 0, 0, 0, X_width/2, X_height/2); 297 doPointerWarp = POINTER_WARP_COUNTDOWN; 298 } 299 } 300 mousemoved = false; 301 } 302 303 void 304 I_UpdateNoBlit() 305 { 306 } 307 308 double exptable2[256*256]; 309 310 void 311 InitExpand2() 312 { 313 double* exp; 314 int i, j; 315 union { 316 unsigned u[2]; 317 double d; 318 } pixel; 319 printf("building exptable2...\n"); 320 exp = exptable2; 321 for (i = 0; i < 256; ++i) { 322 pixel.u[0] = i | (i << 8) | (i << 16) | (i << 24); 323 for (j = 0; j < 256; ++j) { 324 pixel.u[1] = j | (j << 8) | (j << 16) | (j << 24); 325 *exp++ = pixel.d; 326 } 327 } 328 printf ("done.\n"); 329 } 330 331 static XColor colors[256]; 332 333 void 334 I_FinishUpdate() 335 { 336 XColor* color; 337 uchar* screen, *p; 338 uint x, y; 339 340 screen = screens[0]; 341 p = (uchar*)image->data; 342 for (y = 0; y < SCREENHEIGHT * multiply; ++y) { 343 for (x = 0; x < SCREENWIDTH * multiply; ++x) { 344 color = &colors[screen[x/multiply + (y/multiply) * SCREENWIDTH]]; 345 *p++ = (uchar)color->blue; 346 *p++ = (uchar)color->green; 347 *p++ = (uchar)color->red; 348 ++p; /*alpha*/ 349 } 350 } 351 if (doShm) { 352 if (!XShmPutImage(X_display, X_mainWindow, X_gc, image, 0, 0, 0, 0, X_width, X_height, True)) 353 I_Error("XShmPutImage() failed\n"); 354 shmFinished = false; 355 for (I_GetEvent(); !shmFinished; 356 I_GetEvent()); 357 } else { 358 XPutImage(X_display, X_mainWindow, X_gc, image, 0, 0, 0, 0, X_width, X_height); 359 XSync(X_display, False); 360 } 361 } 362 363 void 364 I_ReadScreen(byte* scr) 365 { 366 memcpy(scr, screens[0], SCREENWIDTH * SCREENHEIGHT); 367 } 368 369 370 void 371 I_SetPalette(byte* palette) 372 { 373 static boolean firstcall = true; 374 int i, c; 375 376 /* 377 if (X_visualinfo.class == PseudoColor && X_visualinfo.depth == 8) { 378 */ 379 if (firstcall) { 380 firstcall = false; 381 for (i = 0; i < 256; ++i) { 382 colors[i].pixel = i; 383 colors[i].flags = DoRed|DoGreen|DoBlue; 384 } 385 } 386 for (i = 0; i < 256; ++i) { 387 c = gammatable[usegamma][*palette++]; 388 colors[i].red = (c<<8) + c; 389 c = gammatable[usegamma][*palette++]; 390 colors[i].green = (c<<8) + c; 391 c = gammatable[usegamma][*palette++]; 392 colors[i].blue = (c<<8) + c; 393 } 394 /* 395 XStoreColors(X_display, X_cmap, colors, 256); 396 } 397 */ 398 } 399 400 void 401 grabsharedmemory(int size) 402 { 403 struct shmid_ds shminfo; 404 int key, minsize, id, rc, pollution; 405 406 key = ('d'<<24) | ('o'<<16) | ('o'<<8) | 'm'; 407 minsize = 320 * 200; 408 pollution = 5; 409 do { 410 id = shmget((key_t) key, minsize, 0777); 411 if (id != -1) { 412 rc = shmctl(id, IPC_STAT, &shminfo); 413 if (!rc) { 414 if (shminfo.shm_nattch) { 415 fprintf(stderr, "User %d appears to be running DOOM. Is that wise?\n", shminfo.shm_cpid); 416 ++key; 417 } else { 418 if (getuid() == shminfo.shm_perm.cuid) { 419 rc = shmctl(id, IPC_RMID, 0); 420 if (!rc) 421 fprintf(stderr, "Was able to kill my old shared memory\n"); 422 else 423 I_Error("Was NOT able to kill my old shared memory"); 424 id = shmget((key_t)key, size, IPC_CREAT|0777); 425 if (id == -1) 426 I_Error("Could not get shared memory"); 427 rc = shmctl(id, IPC_STAT, &shminfo); 428 break; 429 } 430 if (size >= shminfo.shm_segsz) { 431 fprintf(stderr, "will use %d's stale shared memory\n", shminfo.shm_cpid); 432 break; 433 } else { 434 fprintf(stderr, "warning: can't use stale shared memory belonging to id %d, key=0x%x\n", shminfo.shm_cpid, key); 435 ++key; 436 } 437 } 438 } else 439 I_Error("could not get stats on key=%d", key); 440 } else { 441 id = shmget((key_t)key, size, IPC_CREAT|0777); 442 if (id == -1) { 443 fprintf(stderr, "errno=%d\n", errno); 444 I_Error("Could not get any shared memory"); 445 } 446 break; 447 } 448 } while (--pollution); 449 if (!pollution) 450 I_Error("Sorry, system too polluted with stale shared memory segments.\n"); 451 X_shminfo.shmid = id; 452 image->data = X_shminfo.shmaddr = shmat(id, 0, 0); 453 fprintf(stderr, "shared memory id=%d, addr=%p\n", id, image->data); 454 } 455 456 void 457 I_InitGraphics() 458 { 459 XSetWindowAttributes attribs; 460 XGCValues xgcvalues; 461 char *displayname, *d; 462 ulong attribmask; 463 int pnum, oktodraw, valuemask; 464 465 signal(SIGINT, (void(*)(int))I_Quit); 466 if (M_CheckParm("-2")) 467 multiply = 2; 468 if (M_CheckParm("-3")) 469 multiply = 3; 470 if (M_CheckParm("-4")) 471 multiply = 4; 472 X_width = SCREENWIDTH * multiply; 473 X_height = SCREENHEIGHT * multiply; 474 if ((pnum = M_CheckParm("-disp"))) 475 displayname = myargv[pnum+1]; 476 else 477 displayname = 0; 478 grabMouse = !!M_CheckParm("-grabmouse"); 479 X_display = XOpenDisplay(displayname); 480 if (!X_display) { 481 if (displayname) 482 I_Error("Could not open display [%s]", displayname); 483 else 484 I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY")); 485 } 486 X_screen = DefaultScreen(X_display); 487 if (!XMatchVisualInfo(X_display, X_screen, 24, TrueColor, &X_visualinfo)) 488 I_Error("xdoom currently only supports 256-color PseudoColor screens"); 489 X_visual = X_visualinfo.visual; 490 doShm = XShmQueryExtension(X_display); 491 if (doShm) { 492 if (!displayname) 493 displayname = (char*)getenv("DISPLAY"); 494 if (displayname) { 495 d = displayname; 496 while (*d && (*d != ':')) 497 ++d; 498 if (*d) 499 *d = 0; 500 if (!(!strcasecmp(displayname, "unix") || !*displayname)) 501 doShm = false; 502 } 503 } 504 fprintf(stderr, "Using MITSHM extension\n"); 505 X_cmap = XCreateColormap(X_display, RootWindow(X_display, X_screen), X_visual, AllocNone); 506 attribmask = CWEventMask | CWColormap | CWBorderPixel; 507 attribs.event_mask = KeyPressMask | KeyReleaseMask | ExposureMask; 508 attribs.colormap = X_cmap; 509 attribs.border_pixel = 0; 510 X_mainWindow = XCreateWindow(X_display, RootWindow(X_display, X_screen), 0, 0, X_width, X_height, 0, 24, InputOutput, X_visual, attribmask, &attribs); 511 XDefineCursor(X_display, X_mainWindow, createnullcursor(X_display, X_mainWindow)); 512 valuemask = GCGraphicsExposures; 513 xgcvalues.graphics_exposures = False; 514 X_gc = XCreateGC(X_display, X_mainWindow, valuemask, &xgcvalues); 515 XMapWindow(X_display, X_mainWindow); 516 oktodraw = 0; 517 while (!oktodraw) { 518 XNextEvent(X_display, &X_event); 519 if (X_event.type == Expose && !X_event.xexpose.count) 520 oktodraw = 1; 521 } 522 if (grabMouse) 523 XGrabPointer(X_display, X_mainWindow, True, ButtonPressMask|ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, X_mainWindow, None, CurrentTime); 524 if (doShm) { 525 X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion; 526 image = XShmCreateImage(X_display, X_visual, 24, ZPixmap, 0, &X_shminfo, X_width, X_height); 527 grabsharedmemory(image->bytes_per_line * image->height); 528 if (!image->data) { 529 perror(""); 530 I_Error("shmat() failed in InitGraphics()"); 531 } 532 if (!XShmAttach(X_display, &X_shminfo)) 533 I_Error("XShmAttach() failed in InitGraphics()"); 534 } else 535 image = XCreateImage(X_display, X_visual, 24, ZPixmap, 0, (char*)malloc(4 * X_width * X_height), X_width, X_height, 8, X_width); 536 screens[0] = (uchar*)malloc(SCREENWIDTH * SCREENHEIGHT); 537 }