📄 rw_imp.pas
字号:
{----------------------------------------------------------------------------}
{ }
{ File(s): rw_Imp.h }
{ }
{ Initial conversion by : Avatar.dx(Avatar.dx@libertysurf.fr) }
{ Initial conversion on : 23-Jan-2002 }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ Copyright (C) 1997-2001 Id Software, Inc. }
{ }
{ This program is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU General Public License }
{ as published by the Free Software Foundation; either version 2 }
{ of the License, or (at your option) any later version. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ See the GNU General Public License for more details. }
{ }
{----------------------------------------------------------------------------}
{ Updated on : }
{ Updated by : }
{ }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ ? }
{----------------------------------------------------------------------------}
{ * TODO: }
{ ? }
{----------------------------------------------------------------------------}
(*
**
** RW_IMP.C
**
** This file contains ALL Win32 specific stuff having to do with the
** software refresh. When a port is being made the following functions
** must be implemented by the port:
**
** SWimp_EndFrame
** SWimp_Init
** SWimp_SetPalette
** SWimp_Shutdown
*)
unit rw_Imp;
interface
uses
rw_Win,
r_Local;
procedure VID_CreateWindow(Width, Height, StyleBits : Integer);
function SWimp_Init( hInstance : Pointer; wndProc : Pointer ) : QBoolean;
function SWimp_InitGraphics(FullScreen : Boolean) : QBoolean;
procedure SWimp_EndFrame;
function SWimp_SetMode(pWidth,pHeight : PInteger; Mode : Integer; FullScreen : Boolean): rserr_t;
procedure SWimp_SetPalette(Palette : PChar);
procedure SWimp_ShutDown;
procedure SWimp_AppActivate(Active : qBoolean);
procedure Sys_MakeCodeWriteable(StartAddr, Length : Double);
// Console variables that we need to access from this module
var
sww_state : swwstate_t;
const
WINDOW_CLASS_NAME = 'Quake2';
implementation
(*
** VID_CreateWindow
*)
procedure VID_CreateWindow(Width, Height, StyleBits : Integer);
var
wc : WNDCLASS;
r : TRect;
x,y,w,h : Integer;
exStyle : Integer;
vid_xPos, vid_yPos , vid_FullScreen : cvar_p;
Begin
vid_xPos := Cvar_Get('Vid_xPos', '0', 0);
vid_yPos := Cvar_Get('Vid_yPos', '0', 0);
vid_FullScreen := Cvar_Get('Vid_Fullscreen','0', CVAR_ARCHIVE);
if Assigned(vid_FullScreen.Value) then exstyle := WS_EX_TOPMOST
else exstyle := 0;
(* Register the frame class *)
wc.Style := 0;
wc.lpfnWndProc := sww_state.wndProc;
wc.cbClsExtra := 0;
wc.cbWndExtra := 0;
wc.HInstance := sww_state.Hinstance;
wc.hIcon := 0;
wc.hCursor := LoadCursor (nil,IDC_ARROW);
wc.hbrBackground := COLOR_GRAYTEXT;
wc.lpszMenuName := 0;
wc.lpszClassName := WINDOW_CLASS_NAME;
if not RegisterClass(@wc) then ri.Sys_Error (ERR_FATAL, 'Couldn''t register window class');
r.Left :=0;
r.Top := 0;
r.Right := Width;
r.Bottom := Height;
AdjustWindowRect (@r, stylebits, FALSE);
w := r.right - r.left;
h := r.bottom - r.top;
x := vid_xpos.value;
y := vid_ypos.value;
sww_state.hWnd := CreateWindowEx(
exStyle,
WINDOW_CLASS_NAME,
'Quake2',
stylebits,
x,y,w,h,
nil,
nil,
sww_state.hInstance,
nil);
if not Assigned(sww_state.hWnd) then ri.SysError (ERR_FATAL, 'Couldn''t create device window');
ShowWindow( sww_state.hWnd, SW_SHOWNORMAL );
UpdateWindow( sww_state.hWnd );
SetForegroundWindow( sww_state.hWnd );
SetFocus( sww_state.hWnd );
// let the sound and input subsystems know about the new window
ri.Vid_NewWindow (width, height);
end;
(*
** SWimp_Init
**
** This routine is responsible for initializing the implementation
** specific stuff in a software rendering subsystem.
*)
function SWimp_Init( hInstance : Pointer; wndProc : Pointer ) : QBoolean;
Begin
sww_state.hInstance := hInstance;
sww_state.wndProc := wndProc;
Result := True;
end;
(*
** SWimp_InitGraphics
**
** This initializes the software refresh's implementation specific
** graphics subsystem. In the case of Windows it creates DIB or
** DDRAW surfaces.
**
** The necessary width and height parameters are grabbed from
** vid.width and vid.height.
*)
function SWimp_InitGraphics(FullScreen : Boolean) : QBoolean;
Begin
// free resources in use
SWimp_ShutDown;
// create a new window
VID_CreateWindow(vid.width, vid.height, WINDOW_STYLE);
// initialize the appropriate subsystem
if not Fullscreen then
Begin
if not Dib_Init(vid.Buffer, vid.rowBytes) then
Begin
vid.Buffer := 0;
vid.RowBytes := 0;
Result := False;
Exit;
end;
end
else
Begin
if not DDraw_Init(vid.Buffer, vid.RowBytes) then
Begin
vid.Buffer := 0;
vid.RowBytes := 0;
Result := False;
Exit;
end;
end;
Result := true;
end;
(*
** SWimp_EndFrame
**
** This does an implementation specific copy from the backbuffer to the
** front buffer. In the Win32 case it uses BitBlt or BltFast depending
** on whether we're using DIB sections/GDI or DDRAW.
*)
procedure SWimp_EndFrame;
var
r : TRect;
rVal : HResult;
ddsd : DDsurfaceDesc;
Begin
if not swState.FullScreen then
Begin
if ssw_state.palettized then
Begin
// holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE);
// RealizePalette(hdcScreen);
end;
BitBlt(sww_state.hDC, 0, 0,
vid.Width, vid.Height,
sww_state.hdcDIBSection,
0, 0,
SRCCOPY);
if sww_state.palettized then
Begin
// SelectPalette(hdcScreen, holdpal, FALSE);
end;
end
else
Begin
r.Left := 0;
r.Top := 0;
r.Right := vid.Width;
r.Bottom := vid.Height;
sww_state.lpddsOffScreenBuffer.lpVtbl.Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer);
if sww_State.Modex then
Begin
Rval := sww_state.lpddsBackBuffer.lpVtbl.BltFast(sww_state.lpddsBackBuffer, 0, 0,
sww_state.lpddsOffScreenBuffer,
@r,DDBLTFAST_WAIT);
if RVal := DDERR_SURFACELOST then
Begin
sww_state.lpddsBackBuffer.lpvtbl.Restore(sww_state.lpddsBackBuffer);
sww_state.lpddsBackBuffer.lpvtbl.BltFast(sww_state.lpddsBackBuffer,
0, 0, sww_state.lpddsOffScreenBuffer,
@r, DDBLTFAST_WAIT );
end;
Rval := sww_state.lpddsFrontBuffer.lpVtbl.Flip( sww_state.lpddsFrontBuffer, Nil, DDFLIP_WAIT );
if Rval := DDERR_SURFACELOST then
Begin
sww_state.lpddsFrontBuffer.lpVtbl.Restore( sww_state.lpddsFrontBuffer );
sww_state.lpddsFrontBuffer.lpVtbl.Flip( sww_state.lpddsFrontBuffer, Nil, DDFLIP_WAIT );
end;
end
Else
Begin
rval := lpddsBackBuffer.lpVtbl.BltFast(sww_state.lpddsFrontBuffer, 0, 0,
sww_state.lpddsOffScreenBuffer,
@r,
DDBLTFAST_WAIT);
if rval := DDERR_SURFACELOST then
Begin
sww_state.lpddsBackBuffer.lpVtbl.Restore(sww_state.lpddsFrontBuffer);
sww_state.lpddsBackBuffer.lpVtbl.BltFast(sww_state.lpddsFrontBuffer, 0, 0,
sww_state.lpddsOffScreenBuffer,
@r,
DDBLTFAST_WAIT);
end;
end;
FillChar(@ddsd,SizeOf(ddsd),0);
ddsd.dwSize := sizeOf(ddsd);
sww_state.lpddsOffScreenBuffer.lpVtbl.Lock(sww_state.lpddsOffScreenBuffer, nil, @ddsd, DDLOCK_WAIT, nil);
vid.Buffer := ddsd.lpSurface;
vid.RowBytes := ddsd.lPitch;
end;
end;
(*
** SWimp_SetMode
*)
function SWimp_SetMode(pWidth,pHeight : PInteger; Mode : Integer; FullScreen : QBoolean): rserr_t;
const
win_fs : array[0..1] of Pchar = ('W','FS');
var
retVal : rserr_t;
Begin
retval := rserr_ok
ri.Con_Printf (PRINT_ALL, 'setting mode %d:', mode );
if not Ri.Vid_GetModeInfo( pwidth, pheight, mode ) then
Begin
ri.Con_Printf( PRINT_ALL, ' invalid mode\n' );
Result := rserr_invalid_mode;
Exit;
end;
ri.Con_Printf( PRINT_ALL, ' %d %d %s\n', pwidth, pheight, win_fs[fullscreen] );
sww_state.Initializing := true;
if FullScreen then
Begin
if not SWimp_InitGraphics = 1 then
Begin
if SWimp_InitGraphics = 0 then
Begin
// mode is legal but not as fullscreen
fullscreen = 0;
retval = rserr_invalid_fullscreen;
end
else
Begin
// failed to set a valid mode in windowed mode
retval = rserr_unknown;
end;
end;
end
else
Begin
// failure to set a valid mode in windowed mode
if not SWimp_InitGraphics( fullscreen ) then
Begin
sww_state.initializing := true;
result := rserr_unknown;
exit;
end;
end;
sw_state.fullscreen := fullscreen;
R_GammaCorrectAndSetPalette(PCHAR( d_8to24table ));
sww_state.initializing := true;
Result := RetVal;
end;
(*
** SWimp_SetPalette
**
** System specific palette setting routine. A NULL palette means
** to use the existing palette. The palette is expected to be in
** a padded 4-byte xRGB format.
*)
procedure SWimp_SetPalette(Palette : PChar);
Begin
// MGL - what the fuck was kendall doing here?!
// clear screen to black and change palette
// for (i=0 ; i<vid.height ; i++)
// memset (vid.buffer + i*vid.rowbytes, 0, vid.width);
if not Assigned(Palette) then Palette := PCHAR(sw_state.currentpalette);
if not sw_state.FullScreen then DIB_SetPalette(PChar(Palette))
Else DDraw_SetPalette(PCHAR(Palette));
end;
(*
** SWimp_Shutdown
**
** System specific graphics subsystem shutdown routine. Destroys
** DIBs or DDRAW surfaces as appropriate.
*)
procedure SWimp_ShutDown;
Begin
ri.Con_Printf( PRINT_ALL, "Shutting down SW imp\n" );
DIB_Shutdown();
DDRAW_Shutdown();
if assigned(sww_state.hwnd) then
Begin
ri.Con_Printf(PRINT_ALL, '...destroying window\n' );
ShowWindow( sww_state.hWnd, SW_SHOWNORMAL ); // prevents leaving empty slots in the taskbar
DestroyWindow (sww_state.hWnd);
sww_state.hWnd = nil;
UnregisterClass (WINDOW_CLASS_NAME, sww_state.hInstance);
end;
end;
(*
** SWimp_AppActivate
*)
procedure SWimp_AppActivate(Active : qBoolean);
Begin
if Active then
Begin
if Assigned(sww_state.hwnd) then
Begin
SetForegroundWindow( sww_state.hWnd );
ShowWindow( sww_state.hWnd, SW_RESTORE );
end;
end
else
Begin
if Assigned(sww_state.hwnd) then
Begin
if sww_state.Initializing then Exit;
if Assigned(vid_fullscreen.Value) then ShowWindow(sww_state.hwnd, SW_MINIMIZE);
end;
end;
end;
//===============================================================================
(*
================
Sys_MakeCodeWriteable
================
*)
procedure Sys_MakeCodeWriteable(StartAddr, Length : Double);
var
flOldProtect : DWORD;
Begin
if not(VirtualProtect(startaddr, length, PAGE_READWRITE, @flOldProtect)) then
ri.sys_Error(ERR_FATAL, 'Protection change failed\n');
end;
(*
** Sys_SetFPCW
**
** For reference:
**
** 1
** 5 0
** xxxxRRPP.xxxxxxxx
**
** PP = 00 = 24-bit single precision
** PP = 01 = reserved
** PP = 10 = 53-bit double precision
** PP = 11 = 64-bit extended precision
**
** RR = 00 = round to nearest
** RR = 01 = round down (towards -inf, floor)
** RR = 10 = round up (towards +inf, ceil)
** RR = 11 = round to zero (truncate/towards 0)
**
*)
{$IFNDEF id386}
procedure Sys_SetFPCW;
Begin
end;
{$ELSE}
var
fpu_ceil_cwfpu_chop_cw, fpu_full_cw, fpu_cw, fpu_pushed_cw : Word;
fpu_sp24_cw, fpu_sp24_ceil_cw : Word;
procedure Sys_SetFPCW;
Begin
asm
xor eax, eax
fnstcw word ptr fpu_cw
mov ax, word ptr fpu_cw
and ah, 0f0h
or ah, 003h ; round to nearest mode, extended precision
mov fpu_full_cw, eax
and ah, 0f0h
or ah, 00fh ; RTZ/truncate/chop mode, extended precision
mov fpu_chop_cw, eax
and ah, 0f0h
or ah, 00bh ; ceil mode, extended precision
mov fpu_ceil_cw, eax
and ah, 0f0h ; round to nearest, 24-bit single precision
mov fpu_sp24_cw, eax
and ah, 0f0h ; ceil mode, 24-bit single precision
or ah, 008h ;
mov fpu_sp24_ceil_cw, eax
end;
{$ENDIF}
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -