swimp_rhap.m (12234B)
1 #import <AppKit/AppKit.h> 2 #import <Interceptor/NSDirectScreen.h> 3 #import <AppKit/NSColor.h> 4 #include "../ref_soft/r_local.h" 5 6 @interface QuakeView : NSView 7 @end 8 9 NSWindow *vid_window_i; 10 QuakeView *vid_view_i; 11 NSDirectScreen *vid_screen; 12 byte *vid_buffer; // real framebuffer 13 int vid_rowbytes; // framebuffer rowbytes 14 15 unsigned *buffernative; // 24 bit off-screen back buffer for window 16 unsigned swimp_palette[256]; 17 18 typedef enum { 19 rhap_shutdown, 20 rhap_windowed, 21 rhap_fullscreen 22 } rhapMode_t; 23 24 rhapMode_t rhap_mode; 25 26 /* 27 ======================================================================= 28 29 FULLSCREEN 30 31 ======================================================================= 32 */ 33 34 /* 35 ** InitFullscreen 36 */ 37 rserr_t InitFullscreen (int width, int height) 38 { 39 NSDictionary *mode, *bestMode; 40 int modeWidth, bestWidth; 41 int modeHeight, bestHeight; 42 NSArray *modes; 43 int i; 44 NSString *string; 45 46 47 vid_screen = [[NSDirectScreen alloc] initWithScreen:[NSScreen mainScreen]]; 48 49 // search for an apropriate mode 50 modes = [vid_screen availableDisplayModes]; 51 bestMode = NULL; 52 bestWidth = 99999; 53 bestHeight = 99999; 54 for (i=0 ; i<[modes count] ; i++) { 55 mode = [modes objectAtIndex: i]; 56 string = [mode objectForKey: @"NSDirectScreenPixelEncoding"]; 57 if ( ![string isEqualToString: @"PPPPPPPP"] ) 58 continue; // only look at paletted modes 59 modeWidth = [[mode objectForKey: @"NSDirectScreenWidth"] intValue]; 60 modeHeight = [[mode objectForKey: @"NSDirectScreenHeight"] intValue]; 61 if (modeWidth < width || modeHeight < height) 62 continue; 63 if (modeWidth < bestWidth) { 64 bestWidth = modeWidth; 65 bestHeight = modeHeight; 66 bestMode = mode; 67 } 68 } 69 70 // if there wasn't any paletted mode of that res or greater, fail 71 if (!bestMode) 72 return rserr_invalid_fullscreen; 73 74 ri.Con_Printf (PRINT_ALL, "SheildDisplay\n"); 75 [vid_screen shieldDisplay]; 76 77 // hide the cursor in all fullscreen modes 78 [NSCursor hide]; 79 80 vid_window_i = [vid_screen shieldingWindow]; 81 82 ri.Con_Printf (PRINT_ALL, "switchToDisplayMode\n"); 83 [vid_screen switchToDisplayMode:bestMode]; 84 // [vid_screen fadeDisplayOutToColor:[NSColor blackColor]]; 85 // [vid_screen fadeDisplayInFromColor:[NSColor blackColor]]; 86 87 vid_buffer = [vid_screen data]; 88 vid_rowbytes = [vid_screen bytesPerRow]; 89 90 return rserr_ok; 91 } 92 93 void ShutdownFullscreen (void) 94 { 95 [vid_screen dealloc]; 96 [NSCursor unhide]; 97 } 98 99 void SetPaletteFullscreen (const unsigned char *palette) { 100 #if 0 101 byte *p; 102 int i; 103 NSDirectPalette *pal; 104 105 pal = [NSDirectPalette init]; 106 for (i=0 ; i<256 ; i++) 107 [pal setRed: palette[0]*(1.0/255) 108 green: palette[1]*(1.0/255) 109 blue: palette[2]*(1.0/255) 110 atIndex: i]; 111 [vid_screen setPalette: pal]; 112 [pal release]; 113 #endif 114 } 115 116 117 118 void BlitFullscreen (void) 119 { 120 int i, j; 121 int w; 122 int *dest, *source; 123 124 w = vid.width>>2; 125 126 source = (int *)vid.buffer; // off-screen buffer 127 dest = (int *)vid_buffer; // directly on screen 128 for (j=0 ; j<vid.height ; j++ 129 , source += (vid.rowbytes>>2), dest += (vid_rowbytes>>2) ) { 130 for (i=0 ; i<w ; i++ ) { 131 dest[i] = source[i]; 132 } 133 } 134 } 135 136 /* 137 ======================================================================= 138 139 WINDOWED 140 141 ======================================================================= 142 */ 143 144 /* 145 ** InitWindowed 146 */ 147 rserr_t InitWindowed (int width, int height) 148 { 149 rserr_t retval = rserr_ok; 150 NSRect content; 151 cvar_t *vid_xpos; 152 cvar_t *vid_ypos; 153 154 // 155 // open a window 156 // 157 vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0); 158 vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0); 159 160 content = NSMakeRect (vid_xpos->value,vid_ypos->value, width, height); 161 vid_window_i = [[NSWindow alloc] 162 initWithContentRect: content 163 styleMask: NSTitledWindowMask 164 backing: NSBackingStoreRetained 165 defer: NO 166 ]; 167 168 // [vid_window_i addToEventMask: NS_FLAGSCHANGEDMASK]; 169 [vid_window_i setTitle: @"Quake2"]; 170 171 buffernative = malloc(width * height * 4); 172 173 return retval; 174 } 175 176 void ShutdownWindowed (void) 177 { 178 if (vid_window_i) 179 { 180 [vid_window_i release]; 181 vid_window_i = NULL; 182 } 183 if (buffernative) 184 { 185 free (buffernative); 186 buffernative = NULL; 187 } 188 } 189 190 void SetPaletteWindowed (const unsigned char *palette) { 191 byte *p; 192 int i; 193 194 p = (byte *)swimp_palette; 195 for (i=0 ; i<256 ; i++, p+=4, palette+=4) 196 { 197 p[0] = palette[0]; 198 p[1] = palette[1]; 199 p[2] = palette[2]; 200 p[3] = 0xff; 201 } 202 } 203 204 205 void BlitWindowed (void) 206 { 207 int i, c; 208 int bps, spp, bpp, bpr; 209 unsigned char *planes[5]; 210 NSRect bounds; 211 212 if (!vid_view_i) 213 return; 214 215 // translate to 24 bit color 216 c = vid.width*vid.height; 217 for (i=0 ; i<c ; i++) 218 buffernative[i] = swimp_palette[vid.buffer[i]]; 219 220 bps = 8; 221 spp = 3; 222 bpp = 32; 223 bpr = vid.width * 4; 224 planes[0] = (unsigned char *)buffernative; 225 226 bounds = [vid_view_i bounds]; 227 228 [vid_view_i lockFocus]; 229 230 NSDrawBitmap( 231 bounds, 232 vid.width, 233 vid.height, 234 bps, 235 spp, 236 bpp, 237 bpr, 238 NO, 239 NO, 240 @"NSDeviceRGBColorSpace", 241 planes 242 ); 243 244 [vid_view_i unlockFocus]; 245 PSWait (); 246 } 247 248 249 //====================================================================== 250 251 /* 252 ** RW_IMP.C 253 ** 254 ** This file contains ALL Win32 specific stuff having to do with the 255 ** software refresh. When a port is being made the following functions 256 ** must be implemented by the port: 257 ** 258 ** SWimp_EndFrame 259 ** SWimp_Init 260 ** SWimp_SetPalette 261 ** SWimp_Shutdown 262 */ 263 264 265 /* 266 ** SWimp_Init 267 ** 268 ** This routine is responsible for initializing the implementation 269 ** specific stuff in a software rendering subsystem. 270 */ 271 int SWimp_Init( void *hInstance, void *wndProc ) 272 { 273 if (!NSApp) 274 { 275 [NSApplication sharedApplication]; 276 [NSApp finishLaunching]; 277 } 278 279 return true; 280 } 281 282 283 /* 284 ** SWimp_SetMode 285 */ 286 rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen) 287 { 288 const char *win_fs[] = { "W", "FS" }; 289 NSRect content; 290 rserr_t ret; 291 292 // free resources in use 293 SWimp_Shutdown (); 294 295 ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode ); 296 297 if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) ) 298 { 299 ri.Con_Printf( PRINT_ALL, " invalid mode\n" ); 300 return rserr_invalid_mode; 301 } 302 303 ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] ); 304 305 vid.buffer = malloc(*pwidth * *pheight); 306 vid.rowbytes = *pwidth; 307 308 if (fullscreen) { 309 rhap_mode = rhap_fullscreen; 310 ret = InitFullscreen (*pwidth, *pheight); 311 } else { 312 rhap_mode = rhap_windowed; 313 ret = InitWindowed (*pwidth, *pheight); 314 } 315 316 if (ret != rserr_ok) { 317 SWimp_Shutdown (); 318 return ret; 319 } 320 321 /* 322 ** the view is identical in windowed and fullscreen modes 323 */ 324 content.origin.x = content.origin.y = 0; 325 content.size.width = *pwidth; 326 content.size.height = *pheight; 327 vid_view_i = [[QuakeView alloc] initWithFrame: content]; 328 [vid_window_i setContentView: vid_view_i]; 329 [vid_window_i makeFirstResponder: vid_view_i]; 330 [vid_window_i setDelegate: vid_view_i]; 331 332 [NSApp activateIgnoringOtherApps: YES]; 333 [vid_window_i makeKeyAndOrderFront: nil]; 334 [vid_window_i display]; 335 336 return ret; 337 } 338 339 /* 340 ** SWimp_Shutdown 341 ** 342 ** System specific graphics subsystem shutdown routine 343 */ 344 void SWimp_Shutdown( void ) 345 { 346 if (rhap_mode == rhap_windowed) 347 ShutdownWindowed (); 348 else if (rhap_mode == rhap_fullscreen) 349 ShutdownFullscreen (); 350 351 rhap_mode = rhap_shutdown; 352 353 if (vid.buffer) 354 { 355 free (vid.buffer); 356 vid.buffer = NULL; 357 } 358 } 359 360 361 /* 362 ** SWimp_SetPalette 363 ** 364 ** System specific palette setting routine. A NULL palette means 365 ** to use the existing palette. The palette is expected to be in 366 ** a padded 4-byte xRGB format. 367 */ 368 void SWimp_SetPalette( const unsigned char *palette ) 369 { 370 if (rhap_mode == rhap_windowed) 371 SetPaletteWindowed (palette); 372 else if (rhap_mode == rhap_fullscreen) 373 SetPaletteFullscreen (palette); 374 } 375 376 377 /* 378 ** SWimp_EndFrame 379 ** 380 ** This does an implementation specific copy from the backbuffer to the 381 ** front buffer. In the Win32 case it uses BitBlt or BltFast depending 382 ** on whether we're using DIB sections/GDI or DDRAW. 383 */ 384 void SWimp_EndFrame (void) 385 { 386 if (rhap_mode == rhap_windowed) 387 BlitWindowed (); 388 else if (rhap_mode == rhap_fullscreen) 389 BlitFullscreen (); 390 } 391 392 393 /* 394 ** SWimp_AppActivate 395 */ 396 void SWimp_AppActivate( qboolean active ) 397 { 398 } 399 400 401 /* 402 ========================================================================== 403 404 NEXTSTEP VIEW CLASS 405 406 ========================================================================== 407 */ 408 #include "../client/keys.h" 409 410 void IN_ActivateMouse (void); 411 void IN_DeactivateMouse (void); 412 413 @implementation QuakeView 414 415 -(BOOL) acceptsFirstResponder 416 { 417 return YES; 418 } 419 420 - (void)windowDidMove: (NSNotification *)note 421 { 422 NSRect r; 423 424 r = [vid_window_i frame]; 425 ri.Cmd_ExecuteText (EXEC_NOW, va("vid_xpos %i", (int)r.origin.x+1)); 426 ri.Cmd_ExecuteText (EXEC_NOW, va("vid_ypos %i", (int)r.origin.y+1)); 427 } 428 429 - (void)becomeKeyWindow 430 { 431 IN_ActivateMouse (); 432 } 433 434 - (void)resignKeyWindow 435 { 436 IN_DeactivateMouse (); 437 } 438 439 440 typedef struct 441 { 442 int source, dest; 443 } keymap_t; 444 445 keymap_t keymaps[] = 446 { 447 {0xf703, K_RIGHTARROW}, 448 {0xf702, K_LEFTARROW}, 449 {0xf700, K_UPARROW}, 450 {0xf701, K_DOWNARROW}, 451 452 {0xf704, K_F1}, 453 {0xf705, K_F2}, 454 {0xf706, K_F3}, 455 {0xf707, K_F4}, 456 {0xf708, K_F5}, 457 {0xf709, K_F6}, 458 {0xf70a, K_F7}, 459 {0xf70b, K_F8}, 460 {0xf70c, K_F9}, 461 {0xf70d, K_F10}, 462 {0xf70e, K_F11}, 463 {0xf70f, K_F12}, 464 465 {-1,-1} 466 }; 467 468 keymap_t flagmaps[] = 469 { 470 {NSShiftKeyMask, K_SHIFT}, 471 {NSControlKeyMask, K_CTRL}, 472 {NSAlternateKeyMask, K_ALT}, 473 {NSCommandKeyMask, K_ALT}, 474 475 {-1,-1} 476 }; 477 478 - (void)mouseDown:(NSEvent *)theEvent 479 { 480 Key_Event (K_MOUSE1, true, 0); 481 } 482 - (void)mouseUp:(NSEvent *)theEvent 483 { 484 Key_Event (K_MOUSE1, false, 0); 485 } 486 - (void)rightMouseDown:(NSEvent *)theEvent 487 { 488 Key_Event (K_MOUSE2, true, 0); 489 } 490 - (void)rightMouseUp:(NSEvent *)theEvent 491 { 492 Key_Event (K_MOUSE2, false, 0); 493 } 494 495 496 /* 497 =================== 498 keyboard methods 499 =================== 500 */ 501 - (void)keyDown:(NSEvent *)theEvent 502 { 503 int ch; 504 keymap_t *km; 505 506 // PSobscurecursor (); 507 508 ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; 509 // check for non-ascii first 510 for (km=keymaps;km->source!=-1;km++) 511 if (ch == km->source) 512 { 513 Key_Event (km->dest, true, 0); 514 return; 515 } 516 517 if (ch >= 'A' && ch <= 'Z') 518 ch += 'a' - 'A'; 519 if (ch>=256) 520 return; 521 522 Key_Event (ch, true, 0); 523 } 524 525 - (void)flagsChanged:(NSEvent *)theEvent 526 { 527 static int oldflags; 528 int newflags; 529 int delta; 530 keymap_t *km; 531 int i; 532 533 // PSobscurecursor (); 534 newflags = [theEvent modifierFlags]; 535 delta = newflags ^ oldflags; 536 for (i=0 ; i<32 ; i++) 537 { 538 if ( !(delta & (1<<i))) 539 continue; 540 // changed 541 for (km=flagmaps;km->source!=-1;km++) 542 if ( (1<<i) == km->source) 543 { 544 if (newflags & (1<<i)) 545 Key_Event (km->dest, true, 0); 546 else 547 Key_Event (km->dest, false, 0); 548 } 549 550 } 551 552 oldflags = newflags; 553 } 554 555 556 - (void)keyUp:(NSEvent *)theEvent 557 { 558 int ch; 559 keymap_t *km; 560 561 ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; 562 563 // check for non-ascii first 564 for (km=keymaps;km->source!=-1;km++) 565 if (ch == km->source) 566 { 567 Key_Event (km->dest, false, 0); 568 return; 569 } 570 571 if (ch >= 'A' && ch <= 'Z') 572 ch += 'a' - 'A'; 573 if (ch>=256) 574 return; 575 Key_Event (ch, false, 0); 576 } 577 578 @end 579 580