rw_imp.c (11075B)
1 /* 2 Copyright (C) 1997-2001 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 /* 21 ** RW_IMP.C 22 ** 23 ** This file contains ALL Win32 specific stuff having to do with the 24 ** software refresh. When a port is being made the following functions 25 ** must be implemented by the port: 26 ** 27 ** SWimp_EndFrame 28 ** SWimp_Init 29 ** SWimp_SetPalette 30 ** SWimp_Shutdown 31 */ 32 #include "..\ref_soft\r_local.h" 33 #include "rw_win.h" 34 #include "winquake.h" 35 36 // Console variables that we need to access from this module 37 38 swwstate_t sww_state; 39 40 /* 41 ** VID_CreateWindow 42 */ 43 #define WINDOW_CLASS_NAME "Quake 2" 44 45 void VID_CreateWindow( int width, int height, int stylebits ) 46 { 47 WNDCLASS wc; 48 RECT r; 49 cvar_t *vid_xpos, *vid_ypos, *vid_fullscreen; 50 int x, y, w, h; 51 int exstyle; 52 53 vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0); 54 vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0); 55 vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE ); 56 57 if ( vid_fullscreen->value ) 58 exstyle = WS_EX_TOPMOST; 59 else 60 exstyle = 0; 61 62 /* Register the frame class */ 63 wc.style = 0; 64 wc.lpfnWndProc = (WNDPROC)sww_state.wndproc; 65 wc.cbClsExtra = 0; 66 wc.cbWndExtra = 0; 67 wc.hInstance = sww_state.hInstance; 68 wc.hIcon = 0; 69 wc.hCursor = LoadCursor (NULL,IDC_ARROW); 70 wc.hbrBackground = (void *)COLOR_GRAYTEXT; 71 wc.lpszMenuName = 0; 72 wc.lpszClassName = WINDOW_CLASS_NAME; 73 74 if (!RegisterClass (&wc) ) 75 ri.Sys_Error (ERR_FATAL, "Couldn't register window class"); 76 77 r.left = 0; 78 r.top = 0; 79 r.right = width; 80 r.bottom = height; 81 82 AdjustWindowRect (&r, stylebits, FALSE); 83 84 w = r.right - r.left; 85 h = r.bottom - r.top; 86 x = vid_xpos->value; 87 y = vid_ypos->value; 88 89 sww_state.hWnd = CreateWindowEx ( 90 exstyle, 91 WINDOW_CLASS_NAME, 92 "Quake 2", 93 stylebits, 94 x, y, w, h, 95 NULL, 96 NULL, 97 sww_state.hInstance, 98 NULL); 99 100 if (!sww_state.hWnd) 101 ri.Sys_Error (ERR_FATAL, "Couldn't create window"); 102 103 ShowWindow( sww_state.hWnd, SW_SHOWNORMAL ); 104 UpdateWindow( sww_state.hWnd ); 105 SetForegroundWindow( sww_state.hWnd ); 106 SetFocus( sww_state.hWnd ); 107 108 // let the sound and input subsystems know about the new window 109 ri.Vid_NewWindow (width, height); 110 } 111 112 /* 113 ** SWimp_Init 114 ** 115 ** This routine is responsible for initializing the implementation 116 ** specific stuff in a software rendering subsystem. 117 */ 118 int SWimp_Init( void *hInstance, void *wndProc ) 119 { 120 sww_state.hInstance = ( HINSTANCE ) hInstance; 121 sww_state.wndproc = wndProc; 122 123 return true; 124 } 125 126 /* 127 ** SWimp_InitGraphics 128 ** 129 ** This initializes the software refresh's implementation specific 130 ** graphics subsystem. In the case of Windows it creates DIB or 131 ** DDRAW surfaces. 132 ** 133 ** The necessary width and height parameters are grabbed from 134 ** vid.width and vid.height. 135 */ 136 static qboolean SWimp_InitGraphics( qboolean fullscreen ) 137 { 138 // free resources in use 139 SWimp_Shutdown (); 140 141 // create a new window 142 VID_CreateWindow (vid.width, vid.height, WINDOW_STYLE); 143 144 // initialize the appropriate subsystem 145 if ( !fullscreen ) 146 { 147 if ( !DIB_Init( &vid.buffer, &vid.rowbytes ) ) 148 { 149 vid.buffer = 0; 150 vid.rowbytes = 0; 151 152 return false; 153 } 154 } 155 else 156 { 157 if ( !DDRAW_Init( &vid.buffer, &vid.rowbytes ) ) 158 { 159 vid.buffer = 0; 160 vid.rowbytes = 0; 161 162 return false; 163 } 164 } 165 166 return true; 167 } 168 169 /* 170 ** SWimp_EndFrame 171 ** 172 ** This does an implementation specific copy from the backbuffer to the 173 ** front buffer. In the Win32 case it uses BitBlt or BltFast depending 174 ** on whether we're using DIB sections/GDI or DDRAW. 175 */ 176 void SWimp_EndFrame (void) 177 { 178 if ( !sw_state.fullscreen ) 179 { 180 if ( sww_state.palettized ) 181 { 182 // holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE); 183 // RealizePalette(hdcScreen); 184 } 185 186 187 BitBlt( sww_state.hDC, 188 0, 0, 189 vid.width, 190 vid.height, 191 sww_state.hdcDIBSection, 192 0, 0, 193 SRCCOPY ); 194 195 if ( sww_state.palettized ) 196 { 197 // SelectPalette(hdcScreen, holdpal, FALSE); 198 } 199 } 200 else 201 { 202 RECT r; 203 HRESULT rval; 204 DDSURFACEDESC ddsd; 205 206 r.left = 0; 207 r.top = 0; 208 r.right = vid.width; 209 r.bottom = vid.height; 210 211 sww_state.lpddsOffScreenBuffer->lpVtbl->Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer ); 212 213 if ( sww_state.modex ) 214 { 215 if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer, 216 0, 0, 217 sww_state.lpddsOffScreenBuffer, 218 &r, 219 DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST ) 220 { 221 sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsBackBuffer ); 222 sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer, 223 0, 0, 224 sww_state.lpddsOffScreenBuffer, 225 &r, 226 DDBLTFAST_WAIT ); 227 } 228 229 if ( ( rval = sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer, 230 NULL, DDFLIP_WAIT ) ) == DDERR_SURFACELOST ) 231 { 232 sww_state.lpddsFrontBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer ); 233 sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer, NULL, DDFLIP_WAIT ); 234 } 235 } 236 else 237 { 238 if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer, 239 0, 0, 240 sww_state.lpddsOffScreenBuffer, 241 &r, 242 DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST ) 243 { 244 sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer ); 245 sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer, 246 0, 0, 247 sww_state.lpddsOffScreenBuffer, 248 &r, 249 DDBLTFAST_WAIT ); 250 } 251 } 252 253 memset( &ddsd, 0, sizeof( ddsd ) ); 254 ddsd.dwSize = sizeof( ddsd ); 255 256 sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ); 257 258 vid.buffer = ddsd.lpSurface; 259 vid.rowbytes = ddsd.lPitch; 260 } 261 } 262 263 /* 264 ** SWimp_SetMode 265 */ 266 rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) 267 { 268 const char *win_fs[] = { "W", "FS" }; 269 rserr_t retval = rserr_ok; 270 271 ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode ); 272 273 if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) ) 274 { 275 ri.Con_Printf( PRINT_ALL, " invalid mode\n" ); 276 return rserr_invalid_mode; 277 } 278 279 ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] ); 280 281 sww_state.initializing = true; 282 if ( fullscreen ) 283 { 284 if ( !SWimp_InitGraphics( 1 ) ) 285 { 286 if ( SWimp_InitGraphics( 0 ) ) 287 { 288 // mode is legal but not as fullscreen 289 fullscreen = 0; 290 retval = rserr_invalid_fullscreen; 291 } 292 else 293 { 294 // failed to set a valid mode in windowed mode 295 retval = rserr_unknown; 296 } 297 } 298 } 299 else 300 { 301 // failure to set a valid mode in windowed mode 302 if ( !SWimp_InitGraphics( fullscreen ) ) 303 { 304 sww_state.initializing = true; 305 return rserr_unknown; 306 } 307 } 308 309 sw_state.fullscreen = fullscreen; 310 #if 0 311 if ( retval != rserr_unknown ) 312 { 313 if ( retval == rserr_invalid_fullscreen || 314 ( retval == rserr_ok && !fullscreen ) ) 315 { 316 SetWindowLong( sww_state.hWnd, GWL_STYLE, WINDOW_STYLE ); 317 } 318 } 319 #endif 320 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); 321 sww_state.initializing = true; 322 323 return retval; 324 } 325 326 /* 327 ** SWimp_SetPalette 328 ** 329 ** System specific palette setting routine. A NULL palette means 330 ** to use the existing palette. The palette is expected to be in 331 ** a padded 4-byte xRGB format. 332 */ 333 void SWimp_SetPalette( const unsigned char *palette ) 334 { 335 // MGL - what the fuck was kendall doing here?! 336 // clear screen to black and change palette 337 // for (i=0 ; i<vid.height ; i++) 338 // memset (vid.buffer + i*vid.rowbytes, 0, vid.width); 339 340 if ( !palette ) 341 palette = ( const unsigned char * ) sw_state.currentpalette; 342 343 if ( !sw_state.fullscreen ) 344 { 345 DIB_SetPalette( ( const unsigned char * ) palette ); 346 } 347 else 348 { 349 DDRAW_SetPalette( ( const unsigned char * ) palette ); 350 } 351 } 352 353 /* 354 ** SWimp_Shutdown 355 ** 356 ** System specific graphics subsystem shutdown routine. Destroys 357 ** DIBs or DDRAW surfaces as appropriate. 358 */ 359 void SWimp_Shutdown( void ) 360 { 361 ri.Con_Printf( PRINT_ALL, "Shutting down SW imp\n" ); 362 DIB_Shutdown(); 363 DDRAW_Shutdown(); 364 365 if ( sww_state.hWnd ) 366 { 367 ri.Con_Printf( PRINT_ALL, "...destroying window\n" ); 368 ShowWindow( sww_state.hWnd, SW_SHOWNORMAL ); // prevents leaving empty slots in the taskbar 369 DestroyWindow (sww_state.hWnd); 370 sww_state.hWnd = NULL; 371 UnregisterClass (WINDOW_CLASS_NAME, sww_state.hInstance); 372 } 373 } 374 375 /* 376 ** SWimp_AppActivate 377 */ 378 void SWimp_AppActivate( qboolean active ) 379 { 380 if ( active ) 381 { 382 if ( sww_state.hWnd ) 383 { 384 SetForegroundWindow( sww_state.hWnd ); 385 ShowWindow( sww_state.hWnd, SW_RESTORE ); 386 } 387 } 388 else 389 { 390 if ( sww_state.hWnd ) 391 { 392 if ( sww_state.initializing ) 393 return; 394 if ( vid_fullscreen->value ) 395 ShowWindow( sww_state.hWnd, SW_MINIMIZE ); 396 } 397 } 398 } 399 400 //=============================================================================== 401 402 403 /* 404 ================ 405 Sys_MakeCodeWriteable 406 ================ 407 */ 408 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) 409 { 410 DWORD flOldProtect; 411 412 if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect)) 413 ri.Sys_Error(ERR_FATAL, "Protection change failed\n"); 414 } 415 416 /* 417 ** Sys_SetFPCW 418 ** 419 ** For reference: 420 ** 421 ** 1 422 ** 5 0 423 ** xxxxRRPP.xxxxxxxx 424 ** 425 ** PP = 00 = 24-bit single precision 426 ** PP = 01 = reserved 427 ** PP = 10 = 53-bit double precision 428 ** PP = 11 = 64-bit extended precision 429 ** 430 ** RR = 00 = round to nearest 431 ** RR = 01 = round down (towards -inf, floor) 432 ** RR = 10 = round up (towards +inf, ceil) 433 ** RR = 11 = round to zero (truncate/towards 0) 434 ** 435 */ 436 #if !id386 437 void Sys_SetFPCW (void) 438 { 439 } 440 #else 441 unsigned fpu_ceil_cw, fpu_chop_cw, fpu_full_cw, fpu_cw, fpu_pushed_cw; 442 unsigned fpu_sp24_cw, fpu_sp24_ceil_cw; 443 444 void Sys_SetFPCW( void ) 445 { 446 __asm xor eax, eax 447 448 __asm fnstcw word ptr fpu_cw 449 __asm mov ax, word ptr fpu_cw 450 451 __asm and ah, 0f0h 452 __asm or ah, 003h ; round to nearest mode, extended precision 453 __asm mov fpu_full_cw, eax 454 455 __asm and ah, 0f0h 456 __asm or ah, 00fh ; RTZ/truncate/chop mode, extended precision 457 __asm mov fpu_chop_cw, eax 458 459 __asm and ah, 0f0h 460 __asm or ah, 00bh ; ceil mode, extended precision 461 __asm mov fpu_ceil_cw, eax 462 463 __asm and ah, 0f0h ; round to nearest, 24-bit single precision 464 __asm mov fpu_sp24_cw, eax 465 466 __asm and ah, 0f0h ; ceil mode, 24-bit single precision 467 __asm or ah, 008h ; 468 __asm mov fpu_sp24_ceil_cw, eax 469 } 470 #endif 471