1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // vid_sunxil.c -- uses X to setup windows and XIL to copy images (scaled as needed) 21 // to screen 22 23 #define _BSD 24 #define BYTE_DEFINED 1 25 26 #include <sys/time.h> 27 #include <sys/types.h> 28 #include <errno.h> 29 #include <thread.h> 30 #include <unistd.h> 31 #include <signal.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <sys/ipc.h> 36 #include <sys/shm.h> 37 #include <X11/Xlib.h> 38 #include <X11/Xutil.h> 39 #include <X11/Xatom.h> 40 #include <X11/keysym.h> 41 #include <xil/xil.h> 42 43 #include "quakedef.h" 44 #include "d_local.h" 45 46 #define MIN_WIDTH 320 47 #define MIN_HEIGHT 200 48 49 cvar_t _windowed_mouse = {"_windowed_mouse","0", true}; 50 cvar_t m_filter = {"m_filter","0", true}; 51 float old_windowed_mouse; 52 53 // The following X property format is defined in Motif 1.1's 54 // Xm/MwmUtils.h, but QUAKE should not depend on that header 55 // file. Note: Motif 1.2 expanded this structure with 56 // uninteresting fields (to QUAKE) so just stick with the 57 // smaller Motif 1.1 structure. 58 59 #define MWM_HINTS_DECORATIONS 2 60 typedef struct 61 { 62 long flags; 63 long functions; 64 long decorations; 65 long input_mode; 66 } MotifWmHints; 67 68 #define MAX_COLUMN_SIZE 11 69 70 #define MAX_MODEDESCS (MAX_COLUMN_SIZE*3) 71 72 typedef struct 73 { 74 int modenum; 75 int iscur; 76 char desc[256]; 77 } modedesc_t; 78 79 extern void M_Menu_Options_f (void); 80 extern void M_Print (int cx, int cy, char *str); 81 extern void M_PrintWhite (int cx, int cy, char *str); 82 extern void M_DrawCharacter (int cx, int line, int num); 83 extern void M_DrawTransPic (int x, int y, qpic_t *pic); 84 extern void M_DrawPic (int x, int y, qpic_t *pic); 85 86 extern int sb_updates; 87 88 qboolean mouse_avail; 89 int mouse_buttons=3; 90 int mouse_oldbuttonstate; 91 int mouse_buttonstate; 92 float mouse_x, mouse_y; 93 float old_mouse_x, old_mouse_y; 94 int p_mouse_x; 95 int p_mouse_y; 96 97 typedef struct 98 { 99 int input; 100 int output; 101 } keymap_t; 102 103 viddef_t vid; // global video state 104 unsigned short d_8to16table[256]; 105 106 int num_shades=32; 107 108 int d_con_indirect = 0; 109 110 int vid_buffersize; 111 112 #define STD_EVENT_MASK \ 113 ( \ 114 StructureNotifyMask | \ 115 KeyPressMask | \ 116 KeyReleaseMask | \ 117 ButtonPressMask | \ 118 ButtonReleaseMask | \ 119 ExposureMask | \ 120 PointerMotionMask | \ 121 FocusChangeMask \ 122 ) 123 124 int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; 125 byte *VGA_pagebase; 126 127 qboolean x_fullscreen = true; 128 Display *x_disp = NULL; 129 int x_screen, x_screen_width, x_screen_height; 130 int x_center_width, x_center_height; 131 int x_std_event_mask = STD_EVENT_MASK; 132 Window x_win, x_root_win; 133 qboolean x_focus = true; 134 int global_dx, global_dy; 135 136 137 static Colormap x_cmap; 138 static GC x_gc; 139 static Visual *x_vis; 140 static XVisualInfo *x_visinfo; 141 static Atom aHints = NULL; 142 static Atom aWMDelete = NULL; 143 144 static qboolean oktodraw = false; 145 static qboolean X11_active = false; 146 147 148 static int verbose=1; 149 150 static byte current_palette[768]; 151 152 cvar_t pixel_multiply = {"pixel_multiply", "2", true}; 153 int current_pixel_multiply = 2; 154 155 #define PM(a) (int)((current_pixel_multiply)?((a)*current_pixel_multiply):(a)) 156 #define MP(a) (int)((current_pixel_multiply)?((a)/current_pixel_multiply):(a)) 157 158 static int render_pipeline[2]; 159 static XilSystemState state; 160 static XilImage display_image = NULL; 161 static XilImage quake_image = NULL; 162 static int use_mt = 0; 163 static int count_frames = 0; 164 165 /* 166 ================ 167 D_BeginDirectRect 168 ================ 169 */ 170 void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) 171 { 172 // direct drawing of the "accessing disk" icon isn't supported under Nextstep 173 } 174 175 176 /* 177 ================ 178 D_EndDirectRect 179 ================ 180 */ 181 void D_EndDirectRect (int x, int y, int width, int height) 182 { 183 // direct drawing of the "accessing disk" icon isnt supported under Nextstep 184 } 185 186 187 /* 188 ================= 189 VID_Gamma_f 190 191 Keybinding command 192 ================= 193 */ 194 195 byte vid_gamma[256]; 196 197 void VID_Gamma_f (void) 198 { 199 200 float g, f, inf; 201 int i; 202 203 if (Cmd_Argc () == 2) { 204 g = Q_atof (Cmd_Argv(1)); 205 206 for (i=0 ; i<255 ; i++) { 207 f = pow ((i+1)/256.0, g); 208 inf = f*255 + 0.5; 209 if (inf < 0) 210 inf = 0; 211 if (inf > 255) 212 inf = 255; 213 vid_gamma[i] = inf; 214 } 215 216 VID_SetPalette (current_palette); 217 218 vid.recalc_refdef = 1; // force a surface cache flush 219 } 220 221 } 222 223 qboolean CheckPixelMultiply (void) 224 { 225 int m; 226 int w, h; 227 XWindowAttributes wattr; 228 XWindowChanges chg; 229 unsigned int value_mask; 230 int old_pixel; 231 232 if ((m = (int)pixel_multiply.value) != current_pixel_multiply) { 233 if (m < 1) 234 m = 1; 235 if (m > 4) 236 m = 4; 237 238 old_pixel = current_pixel_multiply; 239 current_pixel_multiply = m; 240 Cvar_SetValue("pixel_multiply", m); 241 242 if(XGetWindowAttributes(x_disp, x_win, & wattr) == 0) 243 return true; // ??? 244 245 memset(&chg, 0, sizeof(chg)); 246 chg.width = wattr.width/old_pixel * current_pixel_multiply; 247 chg.height = wattr.height/old_pixel * current_pixel_multiply; 248 249 if (chg.width < MIN_WIDTH*current_pixel_multiply) 250 chg.width = MIN_WIDTH*current_pixel_multiply; 251 if (chg.height < MIN_HEIGHT*current_pixel_multiply) 252 chg.height = MIN_HEIGHT*current_pixel_multiply; 253 254 XConfigureWindow(x_disp, x_win, CWWidth | CWHeight, &chg); 255 256 vid.width = MP(wattr.width) & ~3; 257 vid.height = MP(wattr.height); 258 259 if (vid.width < 320) 260 vid.width = 320; 261 if (vid.height < 200) 262 vid.height = 200; 263 VID_ResetFramebuffer(); 264 265 return true; 266 } 267 return false; 268 } 269 270 // ======================================================================== 271 // Tragic death handler 272 // ======================================================================== 273 274 void TragicDeath(int signal_num) 275 { 276 //XAutoRepeatOn(x_disp); 277 XCloseDisplay(x_disp); 278 Sys_Error("This death brought to you by the number %d\n", signal_num); 279 } 280 281 // ======================================================================== 282 // makes a null cursor 283 // ======================================================================== 284 285 static Cursor CreateNullCursor(Display *display, Window root) 286 { 287 Pixmap cursormask; 288 XGCValues xgc; 289 GC gc; 290 XColor dummycolour; 291 Cursor cursor; 292 293 cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); 294 xgc.function = GXclear; 295 gc = XCreateGC(display, cursormask, GCFunction, &xgc); 296 XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); 297 dummycolour.pixel = 0; 298 dummycolour.red = 0; 299 dummycolour.flags = 04; 300 cursor = XCreatePixmapCursor(display, cursormask, cursormask, 301 &dummycolour,&dummycolour, 0,0); 302 XFreePixmap(display,cursormask); 303 XFreeGC(display,gc); 304 return cursor; 305 } 306 307 308 void VID_MenuDraw( void ) 309 { 310 qpic_t *p; 311 char *ptr; 312 int i, j, column, row, dup; 313 char temp[100]; 314 315 p = Draw_CachePic ("gfx/vidmodes.lmp"); 316 M_DrawPic ( (320-p->width)/2, 4, p); 317 M_Print (4*8, 36 + MAX_COLUMN_SIZE * 8 + 8, "Video mode switching unavailable"); 318 M_Print (9*8, 36 + MAX_COLUMN_SIZE * 8 + 8*6, "Press any key..."); 319 } 320 321 void VID_MenuKey( int key ) { M_Menu_Options_f (); } 322 323 // Called at startup to set up translation tables, takes 256 8 bit RGB values 324 // the palette data will go away after the call, so it must be copied off if 325 // the video driver will need it again 326 327 byte surfcache[1024*1024]; 328 329 // 330 // VID_SetWindowTitle - set the window and icon titles 331 // 332 333 void VID_SetWindowTitle( Window win, char *pszName ) 334 { 335 XTextProperty textprop; 336 XWMHints *wmHints; 337 338 // Setup ICCCM properties 339 textprop.value = (unsigned char *)pszName; 340 textprop.encoding = XA_STRING; 341 textprop.format = 8; 342 textprop.nitems = strlen(pszName); 343 wmHints = XAllocWMHints(); 344 wmHints->initial_state = NormalState; 345 wmHints->flags = StateHint; 346 XSetWMProperties( x_disp, win, &textprop, &textprop, 347 // Only put WM_COMMAND property on first window. 348 com_argv, com_argc, NULL, NULL, NULL ); 349 XFree( wmHints ); 350 351 aWMDelete = XInternAtom( x_disp, "WM_DELETE_WINDOW", False ); 352 XSetWMProtocols( x_disp, win, &aWMDelete, 1 ); 353 } 354 355 // 356 // VID_FullScreen - open the window in full screen mode 357 // 358 359 qboolean VID_FullScreen( Window win ) 360 { 361 MotifWmHints hints; 362 XWindowChanges changes; 363 364 aHints = XInternAtom( x_disp, "_MOTIF_WM_HINTS", 0 ); 365 if (aHints == None) { 366 Con_Printf( "Could not intern X atom for _MOTIF_WM_HINTS." ); 367 return( false ); 368 } 369 370 hints.flags = MWM_HINTS_DECORATIONS; 371 hints.decorations = 0; // Absolutely no decorations. 372 XChangeProperty( x_disp, win, aHints, aHints, 32, PropModeReplace, (unsigned char *)&hints, 4 ); 373 374 changes.x = 0; 375 changes.y = 0; 376 changes.width = x_screen_width; 377 changes.height = x_screen_height; 378 changes.stack_mode = TopIf; 379 XConfigureWindow( x_disp, win, CWX | CWY | CWWidth | CWHeight | CWStackMode, &changes); 380 return( true ); 381 } 382 383 void VID_Init (unsigned char *palette) 384 { 385 386 int pnum, i; 387 XVisualInfo template; 388 int num_visuals; 389 int template_mask; 390 int w, h; 391 392 int desired_width=320, desired_height=200; 393 394 Cmd_AddCommand ("gamma", VID_Gamma_f); 395 396 Cvar_RegisterVariable (&pixel_multiply); 397 398 if (pipe(render_pipeline) < 0) 399 Sys_Error("VID_Init: pipe"); 400 401 for (i=0 ; i<256 ; i++) 402 vid_gamma[i] = i; 403 404 vid.width = 320; 405 vid.height = 200; 406 vid.aspect = 1.0; 407 vid.numpages = 2; 408 vid.colormap = host_colormap; 409 vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); 410 //vid.cbits = VID_CBITS; 411 //vid.grades = VID_GRADES; 412 413 srandom(getpid()); 414 415 verbose = COM_CheckParm("-verbose"); 416 count_frames = COM_CheckParm("-count_frames"); 417 418 // 419 // open the display 420 // 421 x_disp = XOpenDisplay(0); 422 423 if (!x_disp) { 424 if (getenv("DISPLAY")) 425 Sys_Error("VID: Could not open display [%s]\n", 426 getenv("DISPLAY")); 427 else 428 Sys_Error("VID: Could not open local display\n"); 429 } 430 431 x_screen = DefaultScreen( x_disp ); 432 x_screen_width = WidthOfScreen( ScreenOfDisplay( x_disp, x_screen ) ); 433 x_screen_height = HeightOfScreen( ScreenOfDisplay( x_disp, x_screen ) ); 434 435 x_center_width = x_screen_width/2; 436 437 x_center_height = x_screen_height/2; 438 439 Con_Printf( "Using screen %d: %dx%d\n", x_screen, x_screen_width, x_screen_height ); 440 441 x_root_win = DefaultRootWindow( x_disp); 442 443 //XAutoRepeatOff(x_disp); 444 445 // for debugging only 446 if (verbose) 447 XSynchronize(x_disp, True); 448 449 // 450 // check for command-line window size 451 // 452 if ((pnum=COM_CheckParm("-winsize"))) { 453 if (pnum >= com_argc-2) 454 Sys_Error("VID: -winsize <width> <height>\n"); 455 desired_width = Q_atoi(com_argv[pnum+1]); 456 desired_height = Q_atoi(com_argv[pnum+2]); 457 if (desired_width < 1 || desired_height < 1) 458 Sys_Error("VID: Bad window width/height\n"); 459 } 460 461 template_mask = VisualScreenMask; // make sure we get the right one 462 template.screen = x_screen; 463 // 464 // specify a visual id 465 // 466 if ((pnum=COM_CheckParm("-visualid"))) { 467 if (pnum >= com_argc-1) 468 Sys_Error("VID: -visualid <id#>\n"); 469 template.visualid = Q_atoi(com_argv[pnum+1]); 470 template_mask |= VisualIDMask; 471 } else { 472 // If not specified, find an 8 bit visual since others don't work 473 // template.depth = 8; 474 // template_mask |= VisualDepthMask; 475 int screen; 476 screen = XDefaultScreen(x_disp); 477 template.visualid = 478 XVisualIDFromVisual(XDefaultVisual(x_disp, screen)); 479 template_mask = VisualIDMask; 480 } 481 // 482 // pick a visual- warn if more than one was available 483 // 484 x_visinfo = XGetVisualInfo(x_disp, template_mask, &template, &num_visuals); 485 if (num_visuals > 1) { 486 printf("Found more than one visual id at depth %d:\n", template.depth); 487 for (i=0 ; i<num_visuals ; i++) 488 printf(" -visualid %d\n", (int)(x_visinfo[i].visualid)); 489 } 490 else if (num_visuals == 0) { 491 if (template_mask == VisualIDMask) 492 Sys_Error("VID: Bad visual id %d\n", template.visualid); 493 else 494 Sys_Error("VID: No visuals at depth %d\n", template.depth); 495 } 496 497 if (verbose) { 498 printf("Using visualid %d:\n", (int)(x_visinfo->visualid)); 499 printf(" screen %d\n", x_visinfo->screen); 500 printf(" red_mask 0x%x\n", (int)(x_visinfo->red_mask)); 501 printf(" green_mask 0x%x\n", (int)(x_visinfo->green_mask)); 502 printf(" blue_mask 0x%x\n", (int)(x_visinfo->blue_mask)); 503 printf(" colormap_size %d\n", x_visinfo->colormap_size); 504 printf(" bits_per_rgb %d\n", x_visinfo->bits_per_rgb); 505 } 506 507 x_vis = x_visinfo->visual; 508 // 509 // See if we're going to do pixel multiply 510 // 511 if (pixel_multiply.value < 1 || pixel_multiply.value > 4) 512 Cvar_SetValue("pixel_multiply", 2); 513 current_pixel_multiply = pixel_multiply.value; 514 515 w = 320*current_pixel_multiply; // minimum width 516 h = 200*current_pixel_multiply; // minimum height 517 if (desired_width < w) 518 desired_width = w; 519 if (desired_height < h) 520 desired_height = h; 521 522 vid.width = MP(desired_width); 523 vid.height = MP(desired_height); 524 525 // 526 // patch things up so game doesn't fail if window is too small 527 // 528 529 if (vid.width < 320) 530 vid.width = 320; 531 if (vid.height < 200) 532 vid.height = 200; 533 534 // 535 // see if we're going to use threads 536 // 537 if(((sysconf(_SC_NPROCESSORS_ONLN) > 1) || COM_CheckParm("-mt")) && 538 (COM_CheckParm("-no_mt") == 0)) { 539 use_mt = 1; 540 printf("VID: Using multiple threads!\n"); 541 } 542 543 // setup attributes for main window 544 { 545 int attribmask = CWEventMask | CWColormap | CWBorderPixel; 546 XSetWindowAttributes attribs; 547 Colormap tmpcmap; 548 549 tmpcmap = XCreateColormap(x_disp, XRootWindow(x_disp, 550 x_visinfo->screen), x_vis, AllocNone); 551 552 attribs.event_mask = x_std_event_mask; 553 attribs.border_pixel = 0; 554 attribs.colormap = tmpcmap; 555 556 // create the main window 557 x_win = XCreateWindow( x_disp, 558 XRootWindow(x_disp, x_visinfo->screen), 559 0, 0, // x, y 560 desired_width, desired_height, 561 0, // borderwidth 562 x_visinfo->depth, 563 InputOutput, 564 x_vis, 565 attribmask, 566 &attribs ); 567 568 if (x_visinfo->class != TrueColor) 569 XFreeColormap(x_disp, tmpcmap); 570 571 } 572 573 if (x_visinfo->depth == 8) { 574 575 // create and upload the palette 576 if (x_visinfo->class == PseudoColor) { 577 x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll); 578 VID_SetPalette(palette); 579 XSetWindowColormap(x_disp, x_win, x_cmap); 580 } 581 582 } 583 584 VID_SetWindowTitle( x_win, "Quake" ); 585 586 // inviso cursor 587 XDefineCursor(x_disp, x_win, CreateNullCursor(x_disp, x_win)); 588 589 // create the GC 590 { 591 XGCValues xgcvalues; 592 int valuemask = GCGraphicsExposures; 593 xgcvalues.graphics_exposures = False; 594 x_gc = XCreateGC(x_disp, x_win, valuemask, &xgcvalues ); 595 } 596 597 // map the window 598 XMapWindow(x_disp, x_win); 599 XSync(x_disp, True) ; /* wait for map */ 600 // 601 // wait for first exposure event 602 // 603 { 604 XEvent event; 605 do{ 606 XNextEvent(x_disp, &event); 607 if (event.type == Expose && !event.xexpose.count) 608 oktodraw = true; 609 } while (!oktodraw); 610 } 611 // 612 // initialize XIL 613 // 614 615 state = xil_open(); 616 617 if(state == NULL) { 618 // 619 // XIL's default error handler will print an error msg on stderr 620 // 621 Sys_Error("xil_open failed\n"); 622 } 623 624 X11_active = true; 625 626 VID_ResetFramebuffer(); 627 628 D_InitCaches (surfcache, sizeof(surfcache)); 629 630 vid_menudrawfn = VID_MenuDraw; 631 vid_menukeyfn = VID_MenuKey; 632 } 633 634 VID_ResetFramebuffer() 635 { 636 XilMemoryStorage storage; 637 638 if (use_mt) { 639 VID_ResetFramebuffer_MT(); 640 return; 641 } 642 643 //printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height); 644 645 xil_destroy(display_image); 646 647 xil_destroy(quake_image); 648 649 display_image = xil_create_from_window(state, x_disp, x_win); 650 quake_image = xil_create(state, vid.width, vid.height, 1, XIL_BYTE); 651 652 xil_export(quake_image); 653 654 if (xil_get_memory_storage(quake_image, &storage) == FALSE) 655 Sys_Error("xil_get_memory_storage"); 656 657 xil_import(quake_image, TRUE); 658 xil_export(quake_image); 659 660 if (xil_get_memory_storage(quake_image, &storage) == FALSE) 661 Sys_Error("xil_get_memory_storage"); 662 663 vid.rowbytes = storage.byte.scanline_stride; 664 vid.buffer = storage.byte.data; 665 vid.conbuffer = vid.buffer; 666 vid.conrowbytes = vid.rowbytes; 667 vid.conwidth = vid.width; 668 vid.conheight = vid.height; 669 670 vid.maxwarpwidth = WARP_WIDTH; 671 vid.maxwarpheight = WARP_HEIGHT; 672 vid.recalc_refdef = 1; // force a surface cache flush 673 674 free(d_pzbuffer); 675 676 d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer)); 677 //Hunk_HighAllocName(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer),"zbuff"); 678 } 679 680 VID_ResetFramebuffer_MT() 681 { 682 XilMemoryStorage storage; 683 XilImage drain_renderpipeline(); 684 XilImage old_display_image; 685 686 void * update_thread(); 687 688 printf("VID_ResetFramebuffer: vid.width %d, vid.height %d\n", vid.width, vid.height); 689 690 old_display_image = display_image; 691 692 display_image = xil_create_from_window(state, x_disp, x_win); 693 694 if (quake_image == NULL) 695 if (thr_create(NULL, NULL, update_thread, NULL, THR_NEW_LWP, NULL) != 0) 696 Sys_Error("VID: thr_create"); 697 698 quake_image = drain_renderpipeline(quake_image); 699 700 xil_destroy(old_display_image); 701 702 free(d_pzbuffer); 703 704 d_pzbuffer = malloc(PM(vid.width)*PM(vid.height)*sizeof(*d_pzbuffer)); 705 } 706 707 void VID_ShiftPalette(unsigned char *p) 708 { 709 VID_SetPalette(p); 710 } 711 712 void VID_SetPalette(unsigned char *palette) 713 { 714 715 int i; 716 XColor colors[256]; 717 718 if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) { 719 if (palette != current_palette) 720 memcpy(current_palette, palette, 768); 721 for (i=0 ; i<256 ; i++) 722 { 723 colors[i].pixel = i; 724 colors[i].flags = DoRed|DoGreen|DoBlue; 725 colors[i].red = vid_gamma[palette[i*3]] * 257; 726 colors[i].green = vid_gamma[palette[i*3+1]] * 257; 727 colors[i].blue = vid_gamma[palette[i*3+2]] * 257; 728 } 729 XStoreColors(x_disp, x_cmap, colors, 256); 730 } 731 732 } 733 734 // Called at shutdown 735 736 void VID_Shutdown (void) 737 { 738 X11_active = false; 739 Con_Printf("VID_Shutdown\n"); 740 //XAutoRepeatOn(x_disp); 741 xil_destroy(display_image); 742 xil_destroy(quake_image); 743 display_image = NULL; 744 quake_image = NULL; 745 XCloseDisplay(x_disp); 746 } 747 748 int XLateKey(XKeyEvent *ev) 749 { 750 751 int key; 752 char buf[64]; 753 KeySym keysym; 754 755 XLookupString(ev, buf, sizeof buf, &keysym, 0); 756 757 switch(keysym) { 758 case XK_Page_Up: key = K_PGUP; break; 759 case XK_Page_Down: key = K_PGDN; break; 760 case XK_Home: key = K_HOME; break; 761 case XK_End: key = K_END; break; 762 case XK_Left: key = K_LEFTARROW; break; 763 case XK_Right: key = K_RIGHTARROW; break; 764 case XK_Down: key = K_DOWNARROW; break; 765 case XK_Up: key = K_UPARROW; break; 766 case XK_Escape: key = K_ESCAPE; break; 767 case XK_Return: key = K_ENTER; break; 768 case XK_Tab: key = K_TAB; break; 769 case XK_Help: 770 case XK_F1: key = K_F1; break; 771 case XK_F2: key = K_F2; break; 772 case XK_F3: key = K_F3; break; 773 case XK_F4: key = K_F4; break; 774 case XK_F5: key = K_F5; break; 775 case XK_F6: key = K_F6; break; 776 case XK_F7: key = K_F7; break; 777 case XK_F8: key = K_F8; break; 778 case XK_F9: key = K_F9; break; 779 case XK_F10: key = K_F10; break; 780 case XK_F11: key = K_F11; break; 781 case XK_F12: key = K_F12; break; 782 case XK_BackSpace: 783 case XK_Delete: key = K_BACKSPACE; break; 784 case XK_Pause: key = K_PAUSE; break; 785 case XK_Shift_L: 786 case XK_Shift_R: key = K_SHIFT; break; 787 case XK_Control_L: 788 case XK_Control_R: key = K_CTRL; break; 789 case XK_Alt_L: 790 case XK_Meta_L: 791 case XK_Alt_R: 792 case XK_Meta_R: key = K_ALT; break; 793 // various other keys on the keyboard 794 case XK_F27: key = K_HOME; break; 795 case XK_F29: key = K_PGUP; break; 796 case XK_F33: key = K_END; break; 797 case XK_F35: key = K_PGDN; break; 798 case XK_Insert: 799 case XK_KP_Insert: key = K_INS; break; 800 case XK_F24: key = '-'; break; 801 case XK_KP_Add: key = '+'; break; 802 case XK_KP_Subtract: key = '-'; break; 803 case XK_F25: key = '/'; break; 804 case XK_F26: key = '*'; break; 805 806 default: 807 key = (unsigned char)*buf; 808 break; 809 } 810 811 return key; 812 813 } 814 815 struct { 816 int key; 817 int down; 818 } keyq[64]; 819 820 int keyq_head=0; 821 int keyq_tail=0; 822 823 int config_notify=0; 824 int config_notify_width; 825 int config_notify_height; 826 827 void GetEvent(void) 828 { 829 XEvent x_event; 830 int b; 831 832 XNextEvent(x_disp, &x_event); 833 switch(x_event.type) { 834 case KeyPress: 835 Key_Event(XLateKey(&x_event.xkey), true); 836 break; 837 case KeyRelease: 838 Key_Event(XLateKey(&x_event.xkey), false); 839 break; 840 841 case MotionNotify: 842 843 if (_windowed_mouse.value) { 844 mouse_x = (float) ((int)x_event.xmotion.x - (int)(vid.width/2)); 845 mouse_y = (float) ((int)x_event.xmotion.y - (int)(vid.height/2)); 846 //printf("m: x=%d,y=%d, mx=%3.2f,my=%3.2f\n", 847 // x_event.xmotion.x, x_event.xmotion.y, mouse_x, mouse_y); 848 849 /* move the mouse to the window center again */ 850 XSelectInput( x_disp, x_win, x_std_event_mask & ~PointerMotionMask ); 851 XWarpPointer(x_disp,None,x_win,0,0,0,0, 852 (vid.width/2),(vid.height/2)); 853 XSelectInput( x_disp, x_win, x_std_event_mask ); 854 } else { 855 mouse_x = (float) (x_event.xmotion.x-p_mouse_x); 856 mouse_y = (float) (x_event.xmotion.y-p_mouse_y); 857 p_mouse_x=x_event.xmotion.x; 858 p_mouse_y=x_event.xmotion.y; 859 } 860 break; 861 862 case ButtonPress: 863 b=-1; 864 if (x_event.xbutton.button == 1) 865 b = 0; 866 else if (x_event.xbutton.button == 2) 867 b = 2; 868 else if (x_event.xbutton.button == 3) 869 b = 1; 870 if (b>=0) 871 mouse_buttonstate |= 1<<b; 872 break; 873 874 case ButtonRelease: 875 b=-1; 876 if (x_event.xbutton.button == 1) 877 b = 0; 878 else if (x_event.xbutton.button == 2) 879 b = 2; 880 else if (x_event.xbutton.button == 3) 881 b = 1; 882 if (b>=0) 883 mouse_buttonstate &= ~(1<<b); 884 break; 885 886 case ConfigureNotify: 887 // printf("config notify\n"); 888 config_notify_width = x_event.xconfigure.width; 889 config_notify_height = x_event.xconfigure.height; 890 config_notify = 1; 891 sb_updates = 0; 892 break; 893 case Expose: 894 sb_updates = 0; 895 break; 896 case ClientMessage: 897 if (x_event.xclient.data.l[0] == aWMDelete) Host_Quit_f(); 898 break; 899 #if 0 900 case FocusIn: 901 printf("FocusIn...\n"); 902 x_focus = true; 903 break; 904 case FocusOut: 905 printf("FocusOut...\n"); 906 x_focus = false; 907 break; 908 #endif 909 } 910 911 if (old_windowed_mouse != _windowed_mouse.value) { 912 old_windowed_mouse = _windowed_mouse.value; 913 914 if (!_windowed_mouse.value) { 915 /* ungrab the pointer */ 916 XUngrabPointer(x_disp,CurrentTime); 917 } else { 918 /* grab the pointer */ 919 XGrabPointer(x_disp,x_win,True,0,GrabModeAsync, 920 GrabModeAsync,x_win,None,CurrentTime); 921 } 922 } 923 } 924 925 // flushes the given rectangles from the view buffer to the screen 926 927 void 928 VID_Update (vrect_t *rects) 929 { 930 void VID_Update_MT(vrect_t *); 931 932 933 if (count_frames) { 934 static int count; 935 static long long s; 936 long long gethrtime(); 937 938 if (count == 0) 939 s = gethrtime(); 940 941 if (count++ == 200) { 942 long long n = gethrtime(); 943 count = 1; 944 printf("%lf frames/secs\n", 200.0/((double)(n-s) / 1e9)); 945 s = n; 946 } 947 } 948 949 if (use_mt) { 950 VID_Update_MT(rects); 951 return; 952 } 953 954 // if the window changes dimension, skip this frame 955 956 if (config_notify) { 957 int w, h; 958 XWindowChanges chg; 959 unsigned int value_mask; 960 961 w = 320*current_pixel_multiply; // minimum width 962 h = 200*current_pixel_multiply; // minimum height 963 964 if (config_notify_width < w || config_notify_height < h) { 965 // We must resize the window 966 memset(&chg, 0, sizeof(chg)); 967 value_mask = 0; 968 if (config_notify_width < w) { 969 config_notify_width = chg.width = w; 970 value_mask |= CWWidth; 971 } 972 if (config_notify_height < h) { 973 config_notify_height = chg.height = h; 974 value_mask |= CWHeight; 975 } 976 if (value_mask) 977 XConfigureWindow(x_disp, x_win, value_mask, &chg); 978 } 979 980 config_notify = 0; 981 982 vid.width = MP(config_notify_width) & ~3; 983 vid.height = MP(config_notify_height); 984 985 if (vid.width < 320) 986 vid.width = 320; 987 if (vid.height < 200) 988 vid.height = 200; 989 990 VID_ResetFramebuffer(); 991 992 return; 993 } 994 // if pixel multiply changed, skip this frame 995 if (CheckPixelMultiply()) 996 return; 997 998 while (rects) { // I've never seen more than one rect? 999 XilMemoryStorage storage; 1000 1001 xil_import(quake_image, TRUE); // let xil control the image 1002 1003 if (current_pixel_multiply < 2) 1004 xil_copy(quake_image, display_image); 1005 else 1006 xil_scale(quake_image, display_image, "nearest", 1007 (float)current_pixel_multiply, (float)current_pixel_multiply); 1008 1009 xil_export(quake_image); // back to quake 1010 1011 if (xil_get_memory_storage(quake_image, &storage) == FALSE) 1012 Sys_Error("xil_get_memory_storage"); 1013 1014 vid.buffer = storage.byte.data; 1015 vid.conbuffer = vid.buffer; 1016 1017 rects = rects->pnext; 1018 } 1019 } 1020 1021 void 1022 VID_Update_MT (vrect_t *rects) 1023 { 1024 XilImage sched_update(); 1025 1026 // if the window changes dimension, skip this frame 1027 1028 if (config_notify) { 1029 int w, h; 1030 XWindowChanges chg; 1031 unsigned int value_mask; 1032 1033 w = 320*current_pixel_multiply; // minimum width 1034 h = 200*current_pixel_multiply; // minimum height 1035 1036 if (config_notify_width < w || config_notify_height < h) { 1037 // We must resize the window 1038 memset(&chg, 0, sizeof(chg)); 1039 value_mask = 0; 1040 if (config_notify_width < w) { 1041 config_notify_width = chg.width = w; 1042 value_mask |= CWWidth; 1043 } 1044 if (config_notify_height < h) { 1045 config_notify_height = chg.height = h; 1046 value_mask |= CWHeight; 1047 } 1048 if (value_mask) 1049 XConfigureWindow(x_disp, x_win, value_mask, &chg); 1050 } 1051 1052 config_notify = 0; 1053 1054 vid.width = MP(config_notify_width) & ~3; 1055 vid.height = MP(config_notify_height); 1056 1057 if (vid.width < 320) 1058 vid.width = 320; 1059 if (vid.height < 200) 1060 vid.height = 200; 1061 1062 VID_ResetFramebuffer_MT(); 1063 1064 return; 1065 } 1066 // if pixel multiply changed, skip this frame 1067 if (CheckPixelMultiply()) 1068 return; 1069 1070 quake_image = sched_update(quake_image); 1071 } 1072 1073 XilImage 1074 drain_renderpipeline(XilImage old) 1075 { 1076 XilImage new; 1077 1078 XilMemoryStorage storage; 1079 1080 if (old) 1081 if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new)) { 1082 Sys_Error("drain_renderpipeline: read"); 1083 xil_destroy(new); 1084 } 1085 1086 xil_destroy(old); 1087 1088 1089 new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE); 1090 1091 if (write(render_pipeline[0], &new, sizeof (new)) != sizeof(new)) 1092 Sys_Error("drain_renderpipeline: write"); 1093 1094 new = xil_create(state, vid.width, vid.height, 1, XIL_BYTE); 1095 1096 xil_export(new); 1097 1098 if (xil_get_memory_storage(new, &storage) == FALSE) 1099 Sys_Error("xil_get_memory_storage"); 1100 1101 vid.rowbytes = storage.byte.scanline_stride; 1102 vid.buffer = storage.byte.data; 1103 vid.conbuffer = vid.buffer; 1104 vid.conrowbytes = vid.rowbytes; 1105 vid.conwidth = vid.width; 1106 vid.conheight = vid.height; 1107 1108 vid.maxwarpwidth = WARP_WIDTH; 1109 vid.maxwarpheight = WARP_HEIGHT; 1110 vid.recalc_refdef = 1; // force a surface cache flush 1111 1112 return(new); 1113 1114 } 1115 1116 XilImage 1117 sched_update(XilImage image) 1118 { 1119 XilImage new; 1120 XilMemoryStorage storage; 1121 1122 if (write(render_pipeline[1], &image, sizeof(image)) != sizeof (image)) 1123 Sys_Error("sched_update:write"); 1124 1125 if (read(render_pipeline[1], &new, sizeof(new)) != sizeof (new)) 1126 Sys_Error("sched_update:read"); 1127 1128 xil_export(new); 1129 1130 if (xil_get_memory_storage(new, &storage) == FALSE) 1131 Sys_Error("xil_get_memory_storage"); 1132 1133 vid.buffer = storage.byte.data; 1134 vid.conbuffer = vid.buffer; 1135 1136 return (new); 1137 } 1138 1139 void *update_thread() 1140 { 1141 XilImage image; 1142 1143 if (!X11_active) 1144 return; 1145 1146 while (read(render_pipeline[0], &image, sizeof (image)) == sizeof(image)) { 1147 1148 xil_import(image, TRUE); // let xil control the image 1149 1150 if (!display_image) 1151 return; 1152 1153 if (current_pixel_multiply < 2) 1154 xil_copy(image, display_image); 1155 else 1156 xil_scale(image, display_image, "nearest", 1157 (float)current_pixel_multiply, (float)current_pixel_multiply); 1158 1159 if (write(render_pipeline[0], &image, sizeof (image)) != sizeof(image)) 1160 Sys_Error("update_thread: write"); 1161 } 1162 } 1163 1164 1165 static int dither; 1166 1167 void VID_DitherOn(void) 1168 { 1169 if (dither == 0) { 1170 vid.recalc_refdef = 1; 1171 dither = 1; 1172 } 1173 } 1174 1175 void VID_DitherOff(void) 1176 { 1177 if (dither) { 1178 vid.recalc_refdef = 1; 1179 dither = 0; 1180 } 1181 } 1182 1183 void VID_SetDefaultMode( void ) 1184 { 1185 } 1186 1187 int I_OpenWindow(void) 1188 { 1189 return 0; 1190 } 1191 1192 void I_EraseWindow(int window) 1193 { 1194 1195 } 1196 1197 void I_DrawCircle(int window, int x, int y, int r) 1198 { 1199 } 1200 1201 void I_DisplayWindow(int window) 1202 { 1203 } 1204 1205 void Sys_SendKeyEvents(void) 1206 { 1207 // get events from x server 1208 if (x_disp) { 1209 while (XPending(x_disp)) GetEvent(); 1210 while (keyq_head != keyq_tail) { 1211 Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].down); 1212 keyq_tail = (keyq_tail + 1) & 63; 1213 } 1214 } 1215 } 1216 1217 void IN_Init (void) 1218 { 1219 Cvar_RegisterVariable (&_windowed_mouse); 1220 Cvar_RegisterVariable (&m_filter); 1221 if ( COM_CheckParm ("-nomouse") ) 1222 return; 1223 mouse_x = mouse_y = 0.0; 1224 mouse_avail = 1; 1225 } 1226 1227 void IN_Shutdown (void) 1228 { 1229 mouse_avail = 0; 1230 } 1231 1232 void IN_Commands (void) 1233 { 1234 int i; 1235 1236 if (!mouse_avail) return; 1237 1238 for (i=0 ; i<mouse_buttons ; i++) { 1239 if ( (mouse_buttonstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)) ) 1240 Key_Event (K_MOUSE1 + i, true); 1241 1242 if ( !(mouse_buttonstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) ) 1243 Key_Event (K_MOUSE1 + i, false); 1244 } 1245 mouse_oldbuttonstate = mouse_buttonstate; 1246 } 1247 1248 void IN_Move (usercmd_t *cmd) 1249 { 1250 if (!mouse_avail) 1251 return; 1252 1253 if (m_filter.value) { 1254 mouse_x = (mouse_x + old_mouse_x) * 0.5; 1255 mouse_y = (mouse_y + old_mouse_y) * 0.5; 1256 } 1257 1258 old_mouse_x = mouse_x; 1259 old_mouse_y = mouse_y; 1260 1261 mouse_x *= sensitivity.value; 1262 mouse_y *= sensitivity.value; 1263 1264 if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) 1265 cmd->sidemove += m_side.value * mouse_x; 1266 else 1267 cl.viewangles[YAW] -= m_yaw.value * mouse_x; 1268 if (in_mlook.state & 1) 1269 V_StopPitchDrift (); 1270 1271 if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) { 1272 cl.viewangles[PITCH] += m_pitch.value * mouse_y; 1273 if (cl.viewangles[PITCH] > 80) 1274 cl.viewangles[PITCH] = 80; 1275 if (cl.viewangles[PITCH] < -70) 1276 cl.viewangles[PITCH] = -70; 1277 } else { 1278 if ((in_strafe.state & 1) && noclip_anglehack) 1279 cmd->upmove -= m_forward.value * mouse_y; 1280 else 1281 cmd->forwardmove -= m_forward.value * mouse_y; 1282 } 1283 mouse_x = mouse_y = 0.0; 1284 } 1285 1286 //void VID_UnlockBuffer(void) { } 1287 //void VID_LockBuffer(void) { } 1288 1289