Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

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