mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-10 11:59:58 -05:00
Quack 3: Arena
This commit is contained in:
committed by
GitHub
parent
0bf99969fd
commit
40035fa235
107
3.15_Changes.txt
Normal file
107
3.15_Changes.txt
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
Quake2 3.15 Upgrade
|
||||
-------------------
|
||||
|
||||
This upgrade addresses several features, including security, playability, and
|
||||
enhancements.
|
||||
|
||||
A new map is also included (in baseq2\pak3.pak) called match1, Reckless
|
||||
Abandon. This map is designed for one on one deathmatch play. It was built
|
||||
by American McGee and Dave "Zoid" Kirsch.
|
||||
|
||||
This patch replaces the following files:
|
||||
|
||||
quake2.exe
|
||||
3dfxgl.dll
|
||||
pvrgl.dll
|
||||
ref_gl.dll
|
||||
ref_soft.dll
|
||||
baseq2\gamex86.dll
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Added visible weapons support. This is precached with a special symbol, i.e.
|
||||
gi.modelindex("#w_shotgun.md2") which causes the client to autobind it to
|
||||
the players current weapon model. Plug in player models can optionally
|
||||
support the visible weapons. Any that do not support it will use their
|
||||
default weapon.md2 files automatically.
|
||||
Visible weapons files for plug in player models are not downloaded
|
||||
automatically--only the default weapon.md2 (and skin) is.
|
||||
The Visible weapon models themselves are not included. They can be
|
||||
downloaded from http://www.telefragged.com/vwep/
|
||||
- Rewrote the some of the net code to use optimized network packets for
|
||||
projectiles. This is transparent to the game code, but improves netplay
|
||||
substancially. The hyperblaster doesn't flood modem players anymore.
|
||||
- Rewrote the packet checksum code to be more portable and defeat proxy bots
|
||||
yet again.
|
||||
- Autodownload support is in. The following items will be automatcally
|
||||
downloaded as needed:
|
||||
- world map (and textures)
|
||||
- models
|
||||
- sounds (precached ones)
|
||||
- plug in player model, skin, skin_i and weapon.md2
|
||||
downloads go to a temp file (maps/blah.tmp for example) and get renamed
|
||||
when done. autoresume is supported (if you lose connect during the
|
||||
download, just reconnect and resume). Server has fine control over
|
||||
the downloads with the following new cvars:
|
||||
allow_download - global download on/off
|
||||
allow_download_players - players download on/off
|
||||
allow_download_models - models download on/off
|
||||
allow_download_sounds - sounds download on/off
|
||||
allow_download_maps - maps download on/off
|
||||
maps that are in pak files will _not_ autodownload from the server, this
|
||||
is for copyright considerations.
|
||||
The QuakeWorld bug of the server map changing while download a map has
|
||||
been fixed.
|
||||
- New option in the Multiplayer/Player Setup menu for setting your connection
|
||||
speed. This sets a default rate for the player and can improve net
|
||||
performance for modem connections.
|
||||
- Rewrote some of the save game code to make it more portable. I wanted to
|
||||
completely rewrite the entire save game system and make it portable across
|
||||
versions and operating systems, but this would require an enormous amount
|
||||
of work.
|
||||
- Added another 512 configure strings for general usage for mod makers.
|
||||
This gives lots of room for general string displays on the HUD and in other
|
||||
data.
|
||||
- Player movement code re-written to be similiar to that of NetQuake and
|
||||
later versions of QuakeWorld. Player has more control in the air and
|
||||
gets a boost in vertical speed when jumping off the top of ramps.
|
||||
- Fixed up serverrecord so that it works correctly with the later versions.
|
||||
serverrecord lets the server do a recording of the current game that
|
||||
demo editors can use to make demos from any PVS in the level. Server
|
||||
recorded demos are BIG. Will look at using delta compression in them
|
||||
to cut down the size.
|
||||
- Copy protection CD check has been removed.
|
||||
- Quake2 3.15 has changed the protocol (so old servers will not run) but
|
||||
all existing game dlls can run on the new version (albiet without the
|
||||
new features such as visible weapons).
|
||||
- Added flood protection. Controlled from the following cvars:
|
||||
flood_msgs - maximum number of messages allowed in the time period
|
||||
specified by flood_persecond
|
||||
flood_persecond - time period that a maximum of flood_msgs messages are
|
||||
permitted
|
||||
flood_waitdelay - amount of time a client gets muzzled for flooding
|
||||
- fixed it so blaster/hyperblaster shots aren't treated as solid when
|
||||
predicting--you aren't clipped against them now.
|
||||
- gender support is now in. The userinfo cvar "gender" can be set to
|
||||
male/female/none (none for neutral messages). This doesn't affect sounds
|
||||
but does affect death messages in the game. The models male and cyborg
|
||||
default to gender male, and female and crackhor default to female.
|
||||
Everything else defaults to none, but you can set it by typing
|
||||
"gender male" or "gender female" as appropriate.
|
||||
- IP banning support ala QW. It's built into the game dll as 'sv' console
|
||||
commands. This list is:
|
||||
sv addip <ip-mask> - adds an ip to the ban list
|
||||
sv listip <ip-mask> - removes an ip from the ban list
|
||||
sv writeip - writes the ban list to <gamedir>/listip.cfg. You can
|
||||
exec this on a server load to load the list on subsequent server runs.
|
||||
like so: quake2 +set dedicated 1 +exec listip.cfg
|
||||
sv removeip <ip-mask> - remove an ip from the list
|
||||
the ip list is a simple mask system. Adding 192.168 to the list
|
||||
would block out everyone in the 192.168.*.* net block. You get 1024 bans,
|
||||
if you need more, recompile the game dll. :)
|
||||
A new cvar is also supported called 'filterban'. It defaults to one which
|
||||
means "allow everyone to connect _except_ those matching in the ban list."
|
||||
If you set it to zero, the meaning reverses like so, "don't allow anyone
|
||||
to connect unless they are in the list."
|
||||
812
ref_soft/r_polysa.asm
Normal file
812
ref_soft/r_polysa.asm
Normal file
@@ -0,0 +1,812 @@
|
||||
.386P
|
||||
.model FLAT
|
||||
;
|
||||
; d_polysa.s
|
||||
; x86 assembly-language polygon model drawing code
|
||||
;
|
||||
|
||||
include qasm.inc
|
||||
include d_if.inc
|
||||
|
||||
if id386
|
||||
|
||||
; !!! if this is changed, it must be changed in d_polyse.c too !!!
|
||||
;DPS_MAXSPANS equ (MAXHEIGHT+1)
|
||||
; 1 extra for spanpackage that marks end
|
||||
|
||||
;SPAN_SIZE equ (((DPS_MAXSPANS + 1 + ((CACHE_SIZE - 1) / spanpackage_t_size)) + 1) * spanpackage_t_size)
|
||||
|
||||
MASK_1K equ 03FFh
|
||||
|
||||
_DATA SEGMENT
|
||||
|
||||
align 4
|
||||
;p10_minus_p20 dd 0
|
||||
;p01_minus_p21 dd 0
|
||||
;temp0 dd 0
|
||||
;temp1 dd 0
|
||||
;Ltemp dd 0
|
||||
|
||||
aff8entryvec_table dd LDraw8, LDraw7, LDraw6, LDraw5
|
||||
dd LDraw4, LDraw3, LDraw2, LDraw1, LDraw8IR, LDraw7IR, LDraw6IR, LDraw5IR, LDraw4IR, LDraw3IR, LDraw2IR, LDraw1IR
|
||||
|
||||
lzistepx dd 0
|
||||
|
||||
externdef _rand1k:dword
|
||||
externdef _rand1k_index:dword
|
||||
externdef _alias_colormap:dword
|
||||
|
||||
;PGM
|
||||
externdef _irtable:dword
|
||||
externdef _iractive:byte
|
||||
;PGM
|
||||
|
||||
_DATA ENDS
|
||||
_TEXT SEGMENT
|
||||
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; 8-bpp horizontal span drawing code for affine polygons, with smooth
|
||||
; shading and no transparency
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
;===================================
|
||||
;===================================
|
||||
|
||||
pspans equ 4+8
|
||||
|
||||
public _D_PolysetAff8Start
|
||||
_D_PolysetAff8Start:
|
||||
|
||||
public _R_PolysetDrawSpans8_Opaque
|
||||
_R_PolysetDrawSpans8_Opaque:
|
||||
|
||||
push esi ; preserve register variables
|
||||
push ebx
|
||||
|
||||
mov esi,ds:dword ptr[pspans+esp] ; point to the first span descriptor
|
||||
mov ecx,ds:dword ptr[_r_zistepx]
|
||||
|
||||
push ebp ; preserve caller's stack frame
|
||||
push edi
|
||||
|
||||
ror ecx,16 ; put high 16 bits of 1/z step in low word
|
||||
mov edx,ds:dword ptr[spanpackage_t_count+esi]
|
||||
|
||||
mov ds:dword ptr[lzistepx],ecx
|
||||
|
||||
LSpanLoop:
|
||||
|
||||
; lcount = d_aspancount - pspanpackage->count;
|
||||
;
|
||||
; errorterm += erroradjustup;
|
||||
; if (errorterm >= 0)
|
||||
; {
|
||||
; d_aspancount += d_countextrastep;
|
||||
; errorterm -= erroradjustdown;
|
||||
; }
|
||||
; else
|
||||
; {
|
||||
; d_aspancount += ubasestep;
|
||||
; }
|
||||
|
||||
mov eax,ds:dword ptr[_d_aspancount]
|
||||
sub eax,edx
|
||||
|
||||
mov edx,ds:dword ptr[_erroradjustup]
|
||||
mov ebx,ds:dword ptr[_errorterm]
|
||||
add ebx,edx
|
||||
js LNoTurnover
|
||||
|
||||
mov edx,ds:dword ptr[_erroradjustdown]
|
||||
mov edi,ds:dword ptr[_d_countextrastep]
|
||||
sub ebx,edx
|
||||
mov ebp,ds:dword ptr[_d_aspancount]
|
||||
mov ds:dword ptr[_errorterm],ebx
|
||||
add ebp,edi
|
||||
mov ds:dword ptr[_d_aspancount],ebp
|
||||
jmp LRightEdgeStepped
|
||||
|
||||
LNoTurnover:
|
||||
mov edi,ds:dword ptr[_d_aspancount]
|
||||
mov edx,ds:dword ptr[_ubasestep]
|
||||
mov ds:dword ptr[_errorterm],ebx
|
||||
add edi,edx
|
||||
mov ds:dword ptr[_d_aspancount],edi
|
||||
|
||||
LRightEdgeStepped:
|
||||
cmp eax,1
|
||||
|
||||
jl LNextSpan
|
||||
jz LExactlyOneLong
|
||||
|
||||
;
|
||||
; set up advancetable
|
||||
;
|
||||
mov ecx,ds:dword ptr[_a_ststepxwhole]
|
||||
mov edx,ds:dword ptr[_r_affinetridesc+atd_skinwidth]
|
||||
|
||||
mov ds:dword ptr[advancetable+4],ecx ; advance base in t
|
||||
add ecx,edx
|
||||
|
||||
mov ds:dword ptr[advancetable],ecx ; advance extra in t
|
||||
mov ecx,ds:dword ptr[_a_tstepxfrac]
|
||||
|
||||
mov cx,ds:word ptr[_r_lstepx]
|
||||
mov edx,eax ; count
|
||||
|
||||
mov ds:dword ptr[tstep],ecx
|
||||
add edx,7
|
||||
|
||||
shr edx,3 ; count of full and partial loops
|
||||
mov ebx,ds:dword ptr[spanpackage_t_sfrac+esi]
|
||||
|
||||
mov bx,dx
|
||||
mov ecx,ds:dword ptr[spanpackage_t_pz+esi]
|
||||
|
||||
neg eax
|
||||
|
||||
mov edi,ds:dword ptr[spanpackage_t_pdest+esi]
|
||||
and eax,7 ; 0->0, 1->7, 2->6, ... , 7->1
|
||||
|
||||
sub edi,eax ; compensate for hardwired offsets
|
||||
sub ecx,eax
|
||||
|
||||
sub ecx,eax
|
||||
mov edx,ds:dword ptr[spanpackage_t_tfrac+esi]
|
||||
|
||||
mov dx,ds:word ptr[spanpackage_t_light+esi]
|
||||
mov ebp,ds:dword ptr[spanpackage_t_zi+esi]
|
||||
|
||||
ror ebp,16 ; put high 16 bits of 1/z in low word
|
||||
push esi
|
||||
|
||||
push eax
|
||||
mov al, [_iractive]
|
||||
cmp al, 0
|
||||
pop eax
|
||||
jne IRInsert
|
||||
|
||||
mov esi,ds:dword ptr[spanpackage_t_ptex+esi]
|
||||
jmp dword ptr[aff8entryvec_table+eax*4]
|
||||
|
||||
IRInsert:
|
||||
mov esi,ds:dword ptr[spanpackage_t_ptex+esi]
|
||||
add eax, 8
|
||||
jmp dword ptr[aff8entryvec_table+eax*4]
|
||||
|
||||
; %bx = count of full and partial loops
|
||||
; %ebx high word = sfrac
|
||||
; %ecx = pz
|
||||
; %dx = light
|
||||
; %edx high word = tfrac
|
||||
; %esi = ptex
|
||||
; %edi = pdest
|
||||
; %ebp = 1/z
|
||||
; tstep low word = C(r_lstepx)
|
||||
; tstep high word = C(a_tstepxfrac)
|
||||
; C(a_sstepxfrac) low word = 0
|
||||
; C(a_sstepxfrac) high word = C(a_sstepxfrac)
|
||||
|
||||
;===
|
||||
;Standard Draw Loop
|
||||
;===
|
||||
LDrawLoop:
|
||||
|
||||
mov al,[_iractive]
|
||||
cmp al,0
|
||||
jne LDrawLoopIR
|
||||
|
||||
; FIXME: do we need to clamp light? We may need at least a buffer bit to
|
||||
; keep it from poking into tfrac and causing problems
|
||||
|
||||
LDraw8:
|
||||
cmp bp,ds:word ptr[ecx]
|
||||
jl Lp1
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch8:
|
||||
mov ds:byte ptr[edi],al
|
||||
Lp1:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw7:
|
||||
cmp bp,ds:word ptr[2+ecx]
|
||||
jl Lp2
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[2+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch7:
|
||||
mov ds:byte ptr[1+edi],al
|
||||
Lp2:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw6:
|
||||
cmp bp,ds:word ptr[4+ecx]
|
||||
jl Lp3
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[4+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch6:
|
||||
mov ds:byte ptr[2+edi],al
|
||||
Lp3:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw5:
|
||||
cmp bp,ds:word ptr[6+ecx]
|
||||
jl Lp4
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[6+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch5:
|
||||
mov ds:byte ptr[3+edi],al
|
||||
Lp4:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw4:
|
||||
cmp bp,ds:word ptr[8+ecx]
|
||||
jl Lp5
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[8+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch4:
|
||||
mov ds:byte ptr[4+edi],al
|
||||
Lp5:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw3:
|
||||
cmp bp,ds:word ptr[10+ecx]
|
||||
jl Lp6
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[10+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch3:
|
||||
mov ds:byte ptr[5+edi],al
|
||||
Lp6:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw2:
|
||||
cmp bp,ds:word ptr[12+ecx]
|
||||
jl Lp7
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[12+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch2:
|
||||
mov ds:byte ptr[6+edi],al
|
||||
Lp7:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw1:
|
||||
cmp bp,ds:word ptr[14+ecx]
|
||||
jl Lp8
|
||||
xor eax,eax
|
||||
mov ah,dh
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov ds:word ptr[14+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch1:
|
||||
mov ds:byte ptr[7+edi],al
|
||||
Lp8:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
add edi,8
|
||||
add ecx,16
|
||||
|
||||
dec bx
|
||||
jnz LDrawLoop
|
||||
|
||||
pop esi ; restore spans pointer
|
||||
LNextSpan:
|
||||
add esi,offset spanpackage_t_size ; point to next span
|
||||
LNextSpanESISet:
|
||||
mov edx,ds:dword ptr[spanpackage_t_count+esi]
|
||||
cmp edx,offset -999999 ; any more spans?
|
||||
jnz LSpanLoop ; yes
|
||||
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
ret
|
||||
|
||||
;=======
|
||||
; IR active draw loop
|
||||
;=======
|
||||
LDrawLoopIR:
|
||||
|
||||
; FIXME: do we need to clamp light? We may need at least a buffer bit to
|
||||
; keep it from poking into tfrac and causing problems
|
||||
|
||||
LDraw8IR:
|
||||
cmp bp,ds:word ptr[ecx]
|
||||
jl Lp1IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch8IR:
|
||||
mov ds:byte ptr[edi],al
|
||||
Lp1IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw7IR:
|
||||
cmp bp,ds:word ptr[2+ecx]
|
||||
jl Lp2IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[2+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch7IR:
|
||||
mov ds:byte ptr[1+edi],al
|
||||
Lp2IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw6IR:
|
||||
cmp bp,ds:word ptr[4+ecx]
|
||||
jl Lp3IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[4+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch6IR:
|
||||
mov ds:byte ptr[2+edi],al
|
||||
Lp3IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw5IR:
|
||||
cmp bp,ds:word ptr[6+ecx]
|
||||
jl Lp4IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[6+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch5IR:
|
||||
mov ds:byte ptr[3+edi],al
|
||||
Lp4IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw4IR:
|
||||
cmp bp,ds:word ptr[8+ecx]
|
||||
jl Lp5IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[8+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch4IR:
|
||||
mov ds:byte ptr[4+edi],al
|
||||
Lp5IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw3IR:
|
||||
cmp bp,ds:word ptr[10+ecx]
|
||||
jl Lp6IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[10+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch3IR:
|
||||
mov ds:byte ptr[5+edi],al
|
||||
Lp6IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw2IR:
|
||||
cmp bp,ds:word ptr[12+ecx]
|
||||
jl Lp7IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[12+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch2IR:
|
||||
mov ds:byte ptr[6+edi],al
|
||||
Lp7IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LDraw1IR:
|
||||
cmp bp,ds:word ptr[14+ecx]
|
||||
jl Lp8IR
|
||||
xor eax,eax
|
||||
mov al,ds:byte ptr[esi]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[14+ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch1IR:
|
||||
mov ds:byte ptr[7+edi],al
|
||||
Lp8IR:
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebp,ds:dword ptr[lzistepx]
|
||||
adc ebp,0
|
||||
add ebx,ds:dword ptr[_a_sstepxfrac]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
add edi,8
|
||||
add ecx,16
|
||||
|
||||
dec bx
|
||||
jnz LDrawLoopIR
|
||||
|
||||
pop esi ; restore spans pointer
|
||||
LNextSpanIR:
|
||||
add esi,offset spanpackage_t_size ; point to next span
|
||||
LNextSpanESISetIR:
|
||||
mov edx,ds:dword ptr[spanpackage_t_count+esi]
|
||||
cmp edx,offset -999999 ; any more spans?
|
||||
jnz LSpanLoop ; yes
|
||||
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
ret
|
||||
|
||||
;=======
|
||||
; Standard One-Long Draw
|
||||
;=======
|
||||
; draw a one-long span
|
||||
|
||||
LExactlyOneLong:
|
||||
mov al,[_iractive]
|
||||
cmp al,0
|
||||
jne LExactlyOneLongIR
|
||||
|
||||
mov ecx,ds:dword ptr[spanpackage_t_pz+esi]
|
||||
mov ebp,ds:dword ptr[spanpackage_t_zi+esi]
|
||||
|
||||
ror ebp,16 ; put high 16 bits of 1/z in low word
|
||||
mov ebx,ds:dword ptr[spanpackage_t_ptex+esi]
|
||||
|
||||
cmp bp,ds:word ptr[ecx]
|
||||
jl LNextSpan
|
||||
xor eax,eax
|
||||
mov edi,ds:dword ptr[spanpackage_t_pdest+esi]
|
||||
mov ah,ds:byte ptr[spanpackage_t_light+1+esi]
|
||||
add esi,offset spanpackage_t_size ; point to next span
|
||||
mov al,ds:byte ptr[ebx]
|
||||
mov ds:word ptr[ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch9:
|
||||
mov ds:byte ptr[edi],al
|
||||
|
||||
jmp LNextSpanESISet
|
||||
|
||||
|
||||
;========
|
||||
;========
|
||||
; draw a one-long span
|
||||
|
||||
LExactlyOneLongIR:
|
||||
|
||||
mov ecx,ds:dword ptr[spanpackage_t_pz+esi]
|
||||
mov ebp,ds:dword ptr[spanpackage_t_zi+esi]
|
||||
|
||||
ror ebp,16 ; put high 16 bits of 1/z in low word
|
||||
mov ebx,ds:dword ptr[spanpackage_t_ptex+esi]
|
||||
|
||||
cmp bp,ds:word ptr[ecx]
|
||||
jl LNextSpanIR
|
||||
xor eax,eax
|
||||
mov edi,ds:dword ptr[spanpackage_t_pdest+esi]
|
||||
add esi,offset spanpackage_t_size ; point to next span
|
||||
mov al,ds:byte ptr[ebx]
|
||||
mov al,ds:byte ptr[_irtable+eax]
|
||||
mov ds:word ptr[ecx],bp
|
||||
mov al,ds:byte ptr[12345678h+eax]
|
||||
LPatch9IR:
|
||||
mov ds:byte ptr[edi],al
|
||||
|
||||
jmp LNextSpanESISetIR
|
||||
|
||||
;===================================
|
||||
;===================================
|
||||
public _D_Aff8Patch
|
||||
_D_Aff8Patch:
|
||||
mov eax,[_alias_colormap]
|
||||
mov ds:dword ptr[LPatch1-4],eax
|
||||
mov ds:dword ptr[LPatch2-4],eax
|
||||
mov ds:dword ptr[LPatch3-4],eax
|
||||
mov ds:dword ptr[LPatch4-4],eax
|
||||
mov ds:dword ptr[LPatch5-4],eax
|
||||
mov ds:dword ptr[LPatch6-4],eax
|
||||
mov ds:dword ptr[LPatch7-4],eax
|
||||
mov ds:dword ptr[LPatch8-4],eax
|
||||
mov ds:dword ptr[LPatch9-4],eax
|
||||
mov ds:dword ptr[LPatch1IR-4],eax
|
||||
mov ds:dword ptr[LPatch2IR-4],eax
|
||||
mov ds:dword ptr[LPatch3IR-4],eax
|
||||
mov ds:dword ptr[LPatch4IR-4],eax
|
||||
mov ds:dword ptr[LPatch5IR-4],eax
|
||||
mov ds:dword ptr[LPatch6IR-4],eax
|
||||
mov ds:dword ptr[LPatch7IR-4],eax
|
||||
mov ds:dword ptr[LPatch8IR-4],eax
|
||||
mov ds:dword ptr[LPatch9IR-4],eax
|
||||
|
||||
ret
|
||||
|
||||
|
||||
|
||||
;===================================
|
||||
;===================================
|
||||
|
||||
height equ 4+16
|
||||
|
||||
public _R_PolysetScanLeftEdge
|
||||
_R_PolysetScanLeftEdge:
|
||||
push ebp ; preserve caller stack frame pointer
|
||||
push esi ; preserve register variables
|
||||
push edi
|
||||
push ebx
|
||||
|
||||
mov eax,ds:dword ptr[height+esp]
|
||||
mov ecx,ds:dword ptr[_d_sfrac]
|
||||
|
||||
and eax,0FFFFh
|
||||
mov ebx,ds:dword ptr[_d_ptex]
|
||||
or ecx,eax
|
||||
mov esi,ds:dword ptr[_d_pedgespanpackage]
|
||||
mov edx,ds:dword ptr[_d_tfrac]
|
||||
mov edi,ds:dword ptr[_d_light]
|
||||
mov ebp,ds:dword ptr[_d_zi]
|
||||
|
||||
; %eax: scratch
|
||||
; %ebx: d_ptex
|
||||
; %ecx: d_sfrac in high word, count in low word
|
||||
; %edx: d_tfrac
|
||||
; %esi: d_pedgespanpackage, errorterm, scratch alternately
|
||||
; %edi: d_light
|
||||
; %ebp: d_zi
|
||||
|
||||
; do
|
||||
; {
|
||||
|
||||
LScanLoop:
|
||||
|
||||
; d_pedgespanpackage->ptex = ptex;
|
||||
; d_pedgespanpackage->pdest = d_pdest;
|
||||
; d_pedgespanpackage->pz = d_pz;
|
||||
; d_pedgespanpackage->count = d_aspancount;
|
||||
; d_pedgespanpackage->light = d_light;
|
||||
; d_pedgespanpackage->zi = d_zi;
|
||||
; d_pedgespanpackage->sfrac = d_sfrac << 16;
|
||||
; d_pedgespanpackage->tfrac = d_tfrac << 16;
|
||||
mov ds:dword ptr[spanpackage_t_ptex+esi],ebx
|
||||
mov eax,ds:dword ptr[_d_pdest]
|
||||
mov ds:dword ptr[spanpackage_t_pdest+esi],eax
|
||||
mov eax,ds:dword ptr[_d_pz]
|
||||
mov ds:dword ptr[spanpackage_t_pz+esi],eax
|
||||
mov eax,ds:dword ptr[_d_aspancount]
|
||||
mov ds:dword ptr[spanpackage_t_count+esi],eax
|
||||
mov ds:dword ptr[spanpackage_t_light+esi],edi
|
||||
mov ds:dword ptr[spanpackage_t_zi+esi],ebp
|
||||
mov ds:dword ptr[spanpackage_t_sfrac+esi],ecx
|
||||
mov ds:dword ptr[spanpackage_t_tfrac+esi],edx
|
||||
|
||||
; pretouch the next cache line
|
||||
mov al,ds:byte ptr[spanpackage_t_size+esi]
|
||||
|
||||
; d_pedgespanpackage++;
|
||||
add esi,offset spanpackage_t_size
|
||||
mov eax,ds:dword ptr[_erroradjustup]
|
||||
mov ds:dword ptr[_d_pedgespanpackage],esi
|
||||
|
||||
; errorterm += erroradjustup;
|
||||
mov esi,ds:dword ptr[_errorterm]
|
||||
add esi,eax
|
||||
mov eax,ds:dword ptr[_d_pdest]
|
||||
|
||||
; if (errorterm >= 0)
|
||||
; {
|
||||
js LNoLeftEdgeTurnover
|
||||
|
||||
; errorterm -= erroradjustdown;
|
||||
; d_pdest += d_pdestextrastep;
|
||||
sub esi,ds:dword ptr[_erroradjustdown]
|
||||
add eax,ds:dword ptr[_d_pdestextrastep]
|
||||
mov ds:dword ptr[_errorterm],esi
|
||||
mov ds:dword ptr[_d_pdest],eax
|
||||
|
||||
; d_pz += d_pzextrastep;
|
||||
; d_aspancount += d_countextrastep;
|
||||
; d_ptex += d_ptexextrastep;
|
||||
; d_sfrac += d_sfracextrastep;
|
||||
; d_ptex += d_sfrac >> 16;
|
||||
; d_sfrac &= 0xFFFF;
|
||||
; d_tfrac += d_tfracextrastep;
|
||||
mov eax,ds:dword ptr[_d_pz]
|
||||
mov esi,ds:dword ptr[_d_aspancount]
|
||||
add eax,ds:dword ptr[_d_pzextrastep]
|
||||
add ecx,ds:dword ptr[_d_sfracextrastep]
|
||||
adc ebx,ds:dword ptr[_d_ptexextrastep]
|
||||
add esi,ds:dword ptr[_d_countextrastep]
|
||||
mov ds:dword ptr[_d_pz],eax
|
||||
mov eax,ds:dword ptr[_d_tfracextrastep]
|
||||
mov ds:dword ptr[_d_aspancount],esi
|
||||
add edx,eax
|
||||
|
||||
; if (d_tfrac & 0x10000)
|
||||
; {
|
||||
jnc LSkip1
|
||||
|
||||
; d_ptex += r_affinetridesc.skinwidth;
|
||||
; d_tfrac &= 0xFFFF;
|
||||
add ebx,ds:dword ptr[_r_affinetridesc+atd_skinwidth]
|
||||
|
||||
; }
|
||||
|
||||
LSkip1:
|
||||
|
||||
; d_light += d_lightextrastep;
|
||||
; d_zi += d_ziextrastep;
|
||||
add edi,ds:dword ptr[_d_lightextrastep]
|
||||
add ebp,ds:dword ptr[_d_ziextrastep]
|
||||
|
||||
; }
|
||||
mov esi,ds:dword ptr[_d_pedgespanpackage]
|
||||
dec ecx
|
||||
test ecx,0FFFFh
|
||||
jnz LScanLoop
|
||||
|
||||
pop ebx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
; else
|
||||
; {
|
||||
|
||||
LNoLeftEdgeTurnover:
|
||||
mov ds:dword ptr[_errorterm],esi
|
||||
|
||||
; d_pdest += d_pdestbasestep;
|
||||
add eax,ds:dword ptr[_d_pdestbasestep]
|
||||
mov ds:dword ptr[_d_pdest],eax
|
||||
|
||||
; d_pz += d_pzbasestep;
|
||||
; d_aspancount += ubasestep;
|
||||
; d_ptex += d_ptexbasestep;
|
||||
; d_sfrac += d_sfracbasestep;
|
||||
; d_ptex += d_sfrac >> 16;
|
||||
; d_sfrac &= 0xFFFF;
|
||||
mov eax,ds:dword ptr[_d_pz]
|
||||
mov esi,ds:dword ptr[_d_aspancount]
|
||||
add eax,ds:dword ptr[_d_pzbasestep]
|
||||
add ecx,ds:dword ptr[_d_sfracbasestep]
|
||||
adc ebx,ds:dword ptr[_d_ptexbasestep]
|
||||
add esi,ds:dword ptr[_ubasestep]
|
||||
mov ds:dword ptr[_d_pz],eax
|
||||
mov ds:dword ptr[_d_aspancount],esi
|
||||
|
||||
; d_tfrac += d_tfracbasestep;
|
||||
mov esi,ds:dword ptr[_d_tfracbasestep]
|
||||
add edx,esi
|
||||
|
||||
; if (d_tfrac & 0x10000)
|
||||
; {
|
||||
jnc LSkip2
|
||||
|
||||
; d_ptex += r_affinetridesc.skinwidth;
|
||||
; d_tfrac &= 0xFFFF;
|
||||
add ebx,ds:dword ptr[_r_affinetridesc+atd_skinwidth]
|
||||
|
||||
; }
|
||||
|
||||
LSkip2:
|
||||
|
||||
; d_light += d_lightbasestep;
|
||||
; d_zi += d_zibasestep;
|
||||
add edi,ds:dword ptr[_d_lightbasestep]
|
||||
add ebp,ds:dword ptr[_d_zibasestep]
|
||||
|
||||
; }
|
||||
; } while (--height);
|
||||
mov esi,ds:dword ptr[_d_pedgespanpackage]
|
||||
dec ecx
|
||||
test ecx,0FFFFh
|
||||
jnz LScanLoop
|
||||
|
||||
pop ebx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
_TEXT ENDS
|
||||
endif ;id386
|
||||
END
|
||||
1539
ref_soft/r_polyse.c
Normal file
1539
ref_soft/r_polyse.c
Normal file
File diff suppressed because it is too large
Load Diff
852
ref_soft/r_rast.c
Normal file
852
ref_soft/r_rast.c
Normal file
@@ -0,0 +1,852 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_rast.c
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
#define MAXLEFTCLIPEDGES 100
|
||||
|
||||
// !!! if these are changed, they must be changed in asm_draw.h too !!!
|
||||
#define FULLY_CLIPPED_CACHED 0x80000000
|
||||
#define FRAMECOUNT_MASK 0x7FFFFFFF
|
||||
|
||||
unsigned int cacheoffset;
|
||||
|
||||
int c_faceclip; // number of faces clipped
|
||||
|
||||
|
||||
clipplane_t *entity_clipplanes;
|
||||
clipplane_t view_clipplanes[4];
|
||||
clipplane_t world_clipplanes[16];
|
||||
|
||||
medge_t *r_pedge;
|
||||
|
||||
qboolean r_leftclipped, r_rightclipped;
|
||||
static qboolean makeleftedge, makerightedge;
|
||||
qboolean r_nearzionly;
|
||||
|
||||
int sintable[1280];
|
||||
int intsintable[1280];
|
||||
int blanktable[1280]; // PGM
|
||||
|
||||
mvertex_t r_leftenter, r_leftexit;
|
||||
mvertex_t r_rightenter, r_rightexit;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float u,v;
|
||||
int ceilv;
|
||||
} evert_t;
|
||||
|
||||
int r_emitted;
|
||||
float r_nearzi;
|
||||
float r_u1, r_v1, r_lzi1;
|
||||
int r_ceilv1;
|
||||
|
||||
qboolean r_lastvertvalid;
|
||||
int r_skyframe;
|
||||
|
||||
msurface_t *r_skyfaces;
|
||||
mplane_t r_skyplanes[6];
|
||||
mtexinfo_t r_skytexinfo[6];
|
||||
mvertex_t *r_skyverts;
|
||||
medge_t *r_skyedges;
|
||||
int *r_skysurfedges;
|
||||
|
||||
// I just copied this data from a box map...
|
||||
int skybox_planes[12] = {2,-128, 0,-128, 2,128, 1,128, 0,128, 1,-128};
|
||||
|
||||
int box_surfedges[24] = { 1,2,3,4, -1,5,6,7, 8,9,-6,10, -2,-7,-9,11,
|
||||
12,-3,-11,-8, -12,-10,-5,-4};
|
||||
int box_edges[24] = { 1,2, 2,3, 3,4, 4,1, 1,5, 5,6, 6,2, 7,8, 8,6, 5,7, 8,3, 7,4};
|
||||
|
||||
int box_faces[6] = {0,0,2,2,2,0};
|
||||
|
||||
vec3_t box_vecs[6][2] = {
|
||||
{ {0,-1,0}, {-1,0,0} },
|
||||
{ {0,1,0}, {0,0,-1} },
|
||||
{ {0,-1,0}, {1,0,0} },
|
||||
{ {1,0,0}, {0,0,-1} },
|
||||
{ {0,-1,0}, {0,0,-1} },
|
||||
{ {-1,0,0}, {0,0,-1} }
|
||||
};
|
||||
|
||||
float box_verts[8][3] = {
|
||||
{-1,-1,-1},
|
||||
{-1,1,-1},
|
||||
{1,1,-1},
|
||||
{1,-1,-1},
|
||||
{-1,-1,1},
|
||||
{-1,1,1},
|
||||
{1,-1,1},
|
||||
{1,1,1}
|
||||
};
|
||||
|
||||
// down, west, up, north, east, south
|
||||
// {"rt", "bk", "lf", "ft", "up", "dn"};
|
||||
|
||||
/*
|
||||
================
|
||||
R_InitSkyBox
|
||||
|
||||
================
|
||||
*/
|
||||
void R_InitSkyBox (void)
|
||||
{
|
||||
int i;
|
||||
extern model_t *loadmodel;
|
||||
|
||||
r_skyfaces = loadmodel->surfaces + loadmodel->numsurfaces;
|
||||
loadmodel->numsurfaces += 6;
|
||||
r_skyverts = loadmodel->vertexes + loadmodel->numvertexes;
|
||||
loadmodel->numvertexes += 8;
|
||||
r_skyedges = loadmodel->edges + loadmodel->numedges;
|
||||
loadmodel->numedges += 12;
|
||||
r_skysurfedges = loadmodel->surfedges + loadmodel->numsurfedges;
|
||||
loadmodel->numsurfedges += 24;
|
||||
if (loadmodel->numsurfaces > MAX_MAP_FACES
|
||||
|| loadmodel->numvertexes > MAX_MAP_VERTS
|
||||
|| loadmodel->numedges > MAX_MAP_EDGES)
|
||||
ri.Sys_Error (ERR_DROP, "InitSkyBox: map overflow");
|
||||
|
||||
memset (r_skyfaces, 0, 6*sizeof(*r_skyfaces));
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
r_skyplanes[i].normal[skybox_planes[i*2]] = 1;
|
||||
r_skyplanes[i].dist = skybox_planes[i*2+1];
|
||||
|
||||
VectorCopy (box_vecs[i][0], r_skytexinfo[i].vecs[0]);
|
||||
VectorCopy (box_vecs[i][1], r_skytexinfo[i].vecs[1]);
|
||||
|
||||
r_skyfaces[i].plane = &r_skyplanes[i];
|
||||
r_skyfaces[i].numedges = 4;
|
||||
r_skyfaces[i].flags = box_faces[i] | SURF_DRAWSKYBOX;
|
||||
r_skyfaces[i].firstedge = loadmodel->numsurfedges-24+i*4;
|
||||
r_skyfaces[i].texinfo = &r_skytexinfo[i];
|
||||
r_skyfaces[i].texturemins[0] = -128;
|
||||
r_skyfaces[i].texturemins[1] = -128;
|
||||
r_skyfaces[i].extents[0] = 256;
|
||||
r_skyfaces[i].extents[1] = 256;
|
||||
}
|
||||
|
||||
for (i=0 ; i<24 ; i++)
|
||||
if (box_surfedges[i] > 0)
|
||||
r_skysurfedges[i] = loadmodel->numedges-13 + box_surfedges[i];
|
||||
else
|
||||
r_skysurfedges[i] = - (loadmodel->numedges-13 + -box_surfedges[i]);
|
||||
|
||||
for(i=0 ; i<12 ; i++)
|
||||
{
|
||||
r_skyedges[i].v[0] = loadmodel->numvertexes-9+box_edges[i*2+0];
|
||||
r_skyedges[i].v[1] = loadmodel->numvertexes-9+box_edges[i*2+1];
|
||||
r_skyedges[i].cachededgeoffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_EmitSkyBox
|
||||
================
|
||||
*/
|
||||
void R_EmitSkyBox (void)
|
||||
{
|
||||
int i, j;
|
||||
int oldkey;
|
||||
|
||||
if (insubmodel)
|
||||
return; // submodels should never have skies
|
||||
if (r_skyframe == r_framecount)
|
||||
return; // already set this frame
|
||||
|
||||
r_skyframe = r_framecount;
|
||||
|
||||
// set the eight fake vertexes
|
||||
for (i=0 ; i<8 ; i++)
|
||||
for (j=0 ; j<3 ; j++)
|
||||
r_skyverts[i].position[j] = r_origin[j] + box_verts[i][j]*128;
|
||||
|
||||
// set the six fake planes
|
||||
for (i=0 ; i<6 ; i++)
|
||||
if (skybox_planes[i*2+1] > 0)
|
||||
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]+128;
|
||||
else
|
||||
r_skyplanes[i].dist = r_origin[skybox_planes[i*2]]-128;
|
||||
|
||||
// fix texture offseets
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
r_skytexinfo[i].vecs[0][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[0]);
|
||||
r_skytexinfo[i].vecs[1][3] = -DotProduct (r_origin, r_skytexinfo[i].vecs[1]);
|
||||
}
|
||||
|
||||
// emit the six faces
|
||||
oldkey = r_currentkey;
|
||||
r_currentkey = 0x7ffffff0;
|
||||
for (i=0 ; i<6 ; i++)
|
||||
{
|
||||
R_RenderFace (r_skyfaces + i, 15);
|
||||
}
|
||||
r_currentkey = oldkey; // bsp sorting order
|
||||
}
|
||||
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
================
|
||||
R_EmitEdge
|
||||
================
|
||||
*/
|
||||
void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
|
||||
{
|
||||
edge_t *edge, *pcheck;
|
||||
int u_check;
|
||||
float u, u_step;
|
||||
vec3_t local, transformed;
|
||||
float *world;
|
||||
int v, v2, ceilv0;
|
||||
float scale, lzi0, u0, v0;
|
||||
int side;
|
||||
|
||||
if (r_lastvertvalid)
|
||||
{
|
||||
u0 = r_u1;
|
||||
v0 = r_v1;
|
||||
lzi0 = r_lzi1;
|
||||
ceilv0 = r_ceilv1;
|
||||
}
|
||||
else
|
||||
{
|
||||
world = &pv0->position[0];
|
||||
|
||||
// transform and project
|
||||
VectorSubtract (world, modelorg, local);
|
||||
TransformVector (local, transformed);
|
||||
|
||||
if (transformed[2] < NEAR_CLIP)
|
||||
transformed[2] = NEAR_CLIP;
|
||||
|
||||
lzi0 = 1.0 / transformed[2];
|
||||
|
||||
// FIXME: build x/yscale into transform?
|
||||
scale = xscale * lzi0;
|
||||
u0 = (xcenter + scale*transformed[0]);
|
||||
if (u0 < r_refdef.fvrectx_adj)
|
||||
u0 = r_refdef.fvrectx_adj;
|
||||
if (u0 > r_refdef.fvrectright_adj)
|
||||
u0 = r_refdef.fvrectright_adj;
|
||||
|
||||
scale = yscale * lzi0;
|
||||
v0 = (ycenter - scale*transformed[1]);
|
||||
if (v0 < r_refdef.fvrecty_adj)
|
||||
v0 = r_refdef.fvrecty_adj;
|
||||
if (v0 > r_refdef.fvrectbottom_adj)
|
||||
v0 = r_refdef.fvrectbottom_adj;
|
||||
|
||||
ceilv0 = (int) ceil(v0);
|
||||
}
|
||||
|
||||
world = &pv1->position[0];
|
||||
|
||||
// transform and project
|
||||
VectorSubtract (world, modelorg, local);
|
||||
TransformVector (local, transformed);
|
||||
|
||||
if (transformed[2] < NEAR_CLIP)
|
||||
transformed[2] = NEAR_CLIP;
|
||||
|
||||
r_lzi1 = 1.0 / transformed[2];
|
||||
|
||||
scale = xscale * r_lzi1;
|
||||
r_u1 = (xcenter + scale*transformed[0]);
|
||||
if (r_u1 < r_refdef.fvrectx_adj)
|
||||
r_u1 = r_refdef.fvrectx_adj;
|
||||
if (r_u1 > r_refdef.fvrectright_adj)
|
||||
r_u1 = r_refdef.fvrectright_adj;
|
||||
|
||||
scale = yscale * r_lzi1;
|
||||
r_v1 = (ycenter - scale*transformed[1]);
|
||||
if (r_v1 < r_refdef.fvrecty_adj)
|
||||
r_v1 = r_refdef.fvrecty_adj;
|
||||
if (r_v1 > r_refdef.fvrectbottom_adj)
|
||||
r_v1 = r_refdef.fvrectbottom_adj;
|
||||
|
||||
if (r_lzi1 > lzi0)
|
||||
lzi0 = r_lzi1;
|
||||
|
||||
if (lzi0 > r_nearzi) // for mipmap finding
|
||||
r_nearzi = lzi0;
|
||||
|
||||
// for right edges, all we want is the effect on 1/z
|
||||
if (r_nearzionly)
|
||||
return;
|
||||
|
||||
r_emitted = 1;
|
||||
|
||||
r_ceilv1 = (int) ceil(r_v1);
|
||||
|
||||
|
||||
// create the edge
|
||||
if (ceilv0 == r_ceilv1)
|
||||
{
|
||||
// we cache unclipped horizontal edges as fully clipped
|
||||
if (cacheoffset != 0x7FFFFFFF)
|
||||
{
|
||||
cacheoffset = FULLY_CLIPPED_CACHED |
|
||||
(r_framecount & FRAMECOUNT_MASK);
|
||||
}
|
||||
|
||||
return; // horizontal edge
|
||||
}
|
||||
|
||||
side = ceilv0 > r_ceilv1;
|
||||
|
||||
edge = edge_p++;
|
||||
|
||||
edge->owner = r_pedge;
|
||||
|
||||
edge->nearzi = lzi0;
|
||||
|
||||
if (side == 0)
|
||||
{
|
||||
// trailing edge (go from p1 to p2)
|
||||
v = ceilv0;
|
||||
v2 = r_ceilv1 - 1;
|
||||
|
||||
edge->surfs[0] = surface_p - surfaces;
|
||||
edge->surfs[1] = 0;
|
||||
|
||||
u_step = ((r_u1 - u0) / (r_v1 - v0));
|
||||
u = u0 + ((float)v - v0) * u_step;
|
||||
}
|
||||
else
|
||||
{
|
||||
// leading edge (go from p2 to p1)
|
||||
v2 = ceilv0 - 1;
|
||||
v = r_ceilv1;
|
||||
|
||||
edge->surfs[0] = 0;
|
||||
edge->surfs[1] = surface_p - surfaces;
|
||||
|
||||
u_step = ((u0 - r_u1) / (v0 - r_v1));
|
||||
u = r_u1 + ((float)v - r_v1) * u_step;
|
||||
}
|
||||
|
||||
edge->u_step = u_step*0x100000;
|
||||
edge->u = u*0x100000 + 0xFFFFF;
|
||||
|
||||
// we need to do this to avoid stepping off the edges if a very nearly
|
||||
// horizontal edge is less than epsilon above a scan, and numeric error causes
|
||||
// it to incorrectly extend to the scan, and the extension of the line goes off
|
||||
// the edge of the screen
|
||||
// FIXME: is this actually needed?
|
||||
if (edge->u < r_refdef.vrect_x_adj_shift20)
|
||||
edge->u = r_refdef.vrect_x_adj_shift20;
|
||||
if (edge->u > r_refdef.vrectright_adj_shift20)
|
||||
edge->u = r_refdef.vrectright_adj_shift20;
|
||||
|
||||
//
|
||||
// sort the edge in normally
|
||||
//
|
||||
u_check = edge->u;
|
||||
if (edge->surfs[0])
|
||||
u_check++; // sort trailers after leaders
|
||||
|
||||
if (!newedges[v] || newedges[v]->u >= u_check)
|
||||
{
|
||||
edge->next = newedges[v];
|
||||
newedges[v] = edge;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcheck = newedges[v];
|
||||
while (pcheck->next && pcheck->next->u < u_check)
|
||||
pcheck = pcheck->next;
|
||||
edge->next = pcheck->next;
|
||||
pcheck->next = edge;
|
||||
}
|
||||
|
||||
edge->nextremove = removeedges[v2];
|
||||
removeedges[v2] = edge;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_ClipEdge
|
||||
================
|
||||
*/
|
||||
void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
|
||||
{
|
||||
float d0, d1, f;
|
||||
mvertex_t clipvert;
|
||||
|
||||
if (clip)
|
||||
{
|
||||
do
|
||||
{
|
||||
d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
|
||||
d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
|
||||
|
||||
if (d0 >= 0)
|
||||
{
|
||||
// point 0 is unclipped
|
||||
if (d1 >= 0)
|
||||
{
|
||||
// both points are unclipped
|
||||
continue;
|
||||
}
|
||||
|
||||
// only point 1 is clipped
|
||||
|
||||
// we don't cache clipped edges
|
||||
cacheoffset = 0x7FFFFFFF;
|
||||
|
||||
f = d0 / (d0 - d1);
|
||||
clipvert.position[0] = pv0->position[0] +
|
||||
f * (pv1->position[0] - pv0->position[0]);
|
||||
clipvert.position[1] = pv0->position[1] +
|
||||
f * (pv1->position[1] - pv0->position[1]);
|
||||
clipvert.position[2] = pv0->position[2] +
|
||||
f * (pv1->position[2] - pv0->position[2]);
|
||||
|
||||
if (clip->leftedge)
|
||||
{
|
||||
r_leftclipped = true;
|
||||
r_leftexit = clipvert;
|
||||
}
|
||||
else if (clip->rightedge)
|
||||
{
|
||||
r_rightclipped = true;
|
||||
r_rightexit = clipvert;
|
||||
}
|
||||
|
||||
R_ClipEdge (pv0, &clipvert, clip->next);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// point 0 is clipped
|
||||
if (d1 < 0)
|
||||
{
|
||||
// both points are clipped
|
||||
// we do cache fully clipped edges
|
||||
if (!r_leftclipped)
|
||||
cacheoffset = FULLY_CLIPPED_CACHED |
|
||||
(r_framecount & FRAMECOUNT_MASK);
|
||||
return;
|
||||
}
|
||||
|
||||
// only point 0 is clipped
|
||||
r_lastvertvalid = false;
|
||||
|
||||
// we don't cache partially clipped edges
|
||||
cacheoffset = 0x7FFFFFFF;
|
||||
|
||||
f = d0 / (d0 - d1);
|
||||
clipvert.position[0] = pv0->position[0] +
|
||||
f * (pv1->position[0] - pv0->position[0]);
|
||||
clipvert.position[1] = pv0->position[1] +
|
||||
f * (pv1->position[1] - pv0->position[1]);
|
||||
clipvert.position[2] = pv0->position[2] +
|
||||
f * (pv1->position[2] - pv0->position[2]);
|
||||
|
||||
if (clip->leftedge)
|
||||
{
|
||||
r_leftclipped = true;
|
||||
r_leftenter = clipvert;
|
||||
}
|
||||
else if (clip->rightedge)
|
||||
{
|
||||
r_rightclipped = true;
|
||||
r_rightenter = clipvert;
|
||||
}
|
||||
|
||||
R_ClipEdge (&clipvert, pv1, clip->next);
|
||||
return;
|
||||
}
|
||||
} while ((clip = clip->next) != NULL);
|
||||
}
|
||||
|
||||
// add the edge
|
||||
R_EmitEdge (pv0, pv1);
|
||||
}
|
||||
|
||||
#endif // !id386
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_EmitCachedEdge
|
||||
================
|
||||
*/
|
||||
void R_EmitCachedEdge (void)
|
||||
{
|
||||
edge_t *pedge_t;
|
||||
|
||||
pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
|
||||
|
||||
if (!pedge_t->surfs[0])
|
||||
pedge_t->surfs[0] = surface_p - surfaces;
|
||||
else
|
||||
pedge_t->surfs[1] = surface_p - surfaces;
|
||||
|
||||
if (pedge_t->nearzi > r_nearzi) // for mipmap finding
|
||||
r_nearzi = pedge_t->nearzi;
|
||||
|
||||
r_emitted = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderFace
|
||||
================
|
||||
*/
|
||||
void R_RenderFace (msurface_t *fa, int clipflags)
|
||||
{
|
||||
int i, lindex;
|
||||
unsigned mask;
|
||||
mplane_t *pplane;
|
||||
float distinv;
|
||||
vec3_t p_normal;
|
||||
medge_t *pedges, tedge;
|
||||
clipplane_t *pclip;
|
||||
|
||||
// translucent surfaces are not drawn by the edge renderer
|
||||
if (fa->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||
{
|
||||
fa->nextalphasurface = r_alpha_surfaces;
|
||||
r_alpha_surfaces = fa;
|
||||
return;
|
||||
}
|
||||
|
||||
// sky surfaces encountered in the world will cause the
|
||||
// environment box surfaces to be emited
|
||||
if ( fa->texinfo->flags & SURF_SKY )
|
||||
{
|
||||
R_EmitSkyBox ();
|
||||
return;
|
||||
}
|
||||
|
||||
// skip out if no more surfs
|
||||
if ((surface_p) >= surf_max)
|
||||
{
|
||||
r_outofsurfaces++;
|
||||
return;
|
||||
}
|
||||
|
||||
// ditto if not enough edges left, or switch to auxedges if possible
|
||||
if ((edge_p + fa->numedges + 4) >= edge_max)
|
||||
{
|
||||
r_outofedges += fa->numedges;
|
||||
return;
|
||||
}
|
||||
|
||||
c_faceclip++;
|
||||
|
||||
// set up clip planes
|
||||
pclip = NULL;
|
||||
|
||||
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
|
||||
{
|
||||
if (clipflags & mask)
|
||||
{
|
||||
view_clipplanes[i].next = pclip;
|
||||
pclip = &view_clipplanes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// push the edges through
|
||||
r_emitted = 0;
|
||||
r_nearzi = 0;
|
||||
r_nearzionly = false;
|
||||
makeleftedge = makerightedge = false;
|
||||
pedges = currentmodel->edges;
|
||||
r_lastvertvalid = false;
|
||||
|
||||
for (i=0 ; i<fa->numedges ; i++)
|
||||
{
|
||||
lindex = currentmodel->surfedges[fa->firstedge + i];
|
||||
|
||||
if (lindex > 0)
|
||||
{
|
||||
r_pedge = &pedges[lindex];
|
||||
|
||||
// if the edge is cached, we can just reuse the edge
|
||||
if (!insubmodel)
|
||||
{
|
||||
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
|
||||
{
|
||||
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
|
||||
r_framecount)
|
||||
{
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
|
||||
r_pedge->cachededgeoffset) &&
|
||||
(((edge_t *)((unsigned long)r_edges +
|
||||
r_pedge->cachededgeoffset))->owner == r_pedge))
|
||||
{
|
||||
R_EmitCachedEdge ();
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assume it's cacheable
|
||||
cacheoffset = (byte *)edge_p - (byte *)r_edges;
|
||||
r_leftclipped = r_rightclipped = false;
|
||||
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
|
||||
&r_pcurrentvertbase[r_pedge->v[1]],
|
||||
pclip);
|
||||
r_pedge->cachededgeoffset = cacheoffset;
|
||||
|
||||
if (r_leftclipped)
|
||||
makeleftedge = true;
|
||||
if (r_rightclipped)
|
||||
makerightedge = true;
|
||||
r_lastvertvalid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lindex = -lindex;
|
||||
r_pedge = &pedges[lindex];
|
||||
// if the edge is cached, we can just reuse the edge
|
||||
if (!insubmodel)
|
||||
{
|
||||
if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
|
||||
{
|
||||
if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
|
||||
r_framecount)
|
||||
{
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's cached if the cached edge is valid and is owned
|
||||
// by this medge_t
|
||||
if ((((unsigned long)edge_p - (unsigned long)r_edges) >
|
||||
r_pedge->cachededgeoffset) &&
|
||||
(((edge_t *)((unsigned long)r_edges +
|
||||
r_pedge->cachededgeoffset))->owner == r_pedge))
|
||||
{
|
||||
R_EmitCachedEdge ();
|
||||
r_lastvertvalid = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assume it's cacheable
|
||||
cacheoffset = (byte *)edge_p - (byte *)r_edges;
|
||||
r_leftclipped = r_rightclipped = false;
|
||||
R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
|
||||
&r_pcurrentvertbase[r_pedge->v[0]],
|
||||
pclip);
|
||||
r_pedge->cachededgeoffset = cacheoffset;
|
||||
|
||||
if (r_leftclipped)
|
||||
makeleftedge = true;
|
||||
if (r_rightclipped)
|
||||
makerightedge = true;
|
||||
r_lastvertvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if there was a clip off the left edge, add that edge too
|
||||
// FIXME: faster to do in screen space?
|
||||
// FIXME: share clipped edges?
|
||||
if (makeleftedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
r_lastvertvalid = false;
|
||||
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
|
||||
}
|
||||
|
||||
// if there was a clip off the right edge, get the right r_nearzi
|
||||
if (makerightedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
r_lastvertvalid = false;
|
||||
r_nearzionly = true;
|
||||
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
|
||||
}
|
||||
|
||||
// if no edges made it out, return without posting the surface
|
||||
if (!r_emitted)
|
||||
return;
|
||||
|
||||
r_polycount++;
|
||||
|
||||
surface_p->msurf = fa;
|
||||
surface_p->nearzi = r_nearzi;
|
||||
surface_p->flags = fa->flags;
|
||||
surface_p->insubmodel = insubmodel;
|
||||
surface_p->spanstate = 0;
|
||||
surface_p->entity = currententity;
|
||||
surface_p->key = r_currentkey++;
|
||||
surface_p->spans = NULL;
|
||||
|
||||
pplane = fa->plane;
|
||||
// FIXME: cache this?
|
||||
TransformVector (pplane->normal, p_normal);
|
||||
// FIXME: cache this?
|
||||
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
|
||||
|
||||
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
|
||||
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
|
||||
surface_p->d_ziorigin = p_normal[2] * distinv -
|
||||
xcenter * surface_p->d_zistepu -
|
||||
ycenter * surface_p->d_zistepv;
|
||||
|
||||
surface_p++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_RenderBmodelFace
|
||||
================
|
||||
*/
|
||||
void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
|
||||
{
|
||||
int i;
|
||||
unsigned mask;
|
||||
mplane_t *pplane;
|
||||
float distinv;
|
||||
vec3_t p_normal;
|
||||
medge_t tedge;
|
||||
clipplane_t *pclip;
|
||||
|
||||
if (psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66))
|
||||
{
|
||||
psurf->nextalphasurface = r_alpha_surfaces;
|
||||
r_alpha_surfaces = psurf;
|
||||
return;
|
||||
}
|
||||
|
||||
// skip out if no more surfs
|
||||
if (surface_p >= surf_max)
|
||||
{
|
||||
r_outofsurfaces++;
|
||||
return;
|
||||
}
|
||||
|
||||
// ditto if not enough edges left, or switch to auxedges if possible
|
||||
if ((edge_p + psurf->numedges + 4) >= edge_max)
|
||||
{
|
||||
r_outofedges += psurf->numedges;
|
||||
return;
|
||||
}
|
||||
|
||||
c_faceclip++;
|
||||
|
||||
// this is a dummy to give the caching mechanism someplace to write to
|
||||
r_pedge = &tedge;
|
||||
|
||||
// set up clip planes
|
||||
pclip = NULL;
|
||||
|
||||
for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
|
||||
{
|
||||
if (r_clipflags & mask)
|
||||
{
|
||||
view_clipplanes[i].next = pclip;
|
||||
pclip = &view_clipplanes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// push the edges through
|
||||
r_emitted = 0;
|
||||
r_nearzi = 0;
|
||||
r_nearzionly = false;
|
||||
makeleftedge = makerightedge = false;
|
||||
// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
|
||||
// can be used?
|
||||
r_lastvertvalid = false;
|
||||
|
||||
for ( ; pedges ; pedges = pedges->pnext)
|
||||
{
|
||||
r_leftclipped = r_rightclipped = false;
|
||||
R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
|
||||
|
||||
if (r_leftclipped)
|
||||
makeleftedge = true;
|
||||
if (r_rightclipped)
|
||||
makerightedge = true;
|
||||
}
|
||||
|
||||
// if there was a clip off the left edge, add that edge too
|
||||
// FIXME: faster to do in screen space?
|
||||
// FIXME: share clipped edges?
|
||||
if (makeleftedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
|
||||
}
|
||||
|
||||
// if there was a clip off the right edge, get the right r_nearzi
|
||||
if (makerightedge)
|
||||
{
|
||||
r_pedge = &tedge;
|
||||
r_nearzionly = true;
|
||||
R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
|
||||
}
|
||||
|
||||
// if no edges made it out, return without posting the surface
|
||||
if (!r_emitted)
|
||||
return;
|
||||
|
||||
r_polycount++;
|
||||
|
||||
surface_p->msurf = psurf;
|
||||
surface_p->nearzi = r_nearzi;
|
||||
surface_p->flags = psurf->flags;
|
||||
surface_p->insubmodel = true;
|
||||
surface_p->spanstate = 0;
|
||||
surface_p->entity = currententity;
|
||||
surface_p->key = r_currentbkey;
|
||||
surface_p->spans = NULL;
|
||||
|
||||
pplane = psurf->plane;
|
||||
// FIXME: cache this?
|
||||
TransformVector (pplane->normal, p_normal);
|
||||
// FIXME: cache this?
|
||||
distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
|
||||
|
||||
surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
|
||||
surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
|
||||
surface_p->d_ziorigin = p_normal[2] * distinv -
|
||||
xcenter * surface_p->d_zistepu -
|
||||
ycenter * surface_p->d_zistepv;
|
||||
|
||||
surface_p++;
|
||||
}
|
||||
|
||||
591
ref_soft/r_scan.c
Normal file
591
ref_soft/r_scan.c
Normal file
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// d_scan.c
|
||||
//
|
||||
// Portable C scan-level rasterization code, all pixel depths.
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
unsigned char *r_turb_pbase, *r_turb_pdest;
|
||||
fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep;
|
||||
int *r_turb_turb;
|
||||
int r_turb_spancount;
|
||||
|
||||
void D_DrawTurbulent8Span (void);
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
D_WarpScreen
|
||||
|
||||
this performs a slight compression of the screen at the same time as
|
||||
the sine warp, to keep the edges from wrapping
|
||||
=============
|
||||
*/
|
||||
void D_WarpScreen (void)
|
||||
{
|
||||
int w, h;
|
||||
int u,v, u2, v2;
|
||||
byte *dest;
|
||||
int *turb;
|
||||
int *col;
|
||||
byte **row;
|
||||
|
||||
static int cached_width, cached_height;
|
||||
static byte *rowptr[1200+AMP2*2];
|
||||
static int column[1600+AMP2*2];
|
||||
|
||||
//
|
||||
// these are constant over resolutions, and can be saved
|
||||
//
|
||||
w = r_newrefdef.width;
|
||||
h = r_newrefdef.height;
|
||||
if (w != cached_width || h != cached_height)
|
||||
{
|
||||
cached_width = w;
|
||||
cached_height = h;
|
||||
for (v=0 ; v<h+AMP2*2 ; v++)
|
||||
{
|
||||
v2 = (int)((float)v/(h + AMP2 * 2) * r_refdef.vrect.height);
|
||||
rowptr[v] = r_warpbuffer + (WARP_WIDTH * v2);
|
||||
}
|
||||
|
||||
for (u=0 ; u<w+AMP2*2 ; u++)
|
||||
{
|
||||
u2 = (int)((float)u/(w + AMP2 * 2) * r_refdef.vrect.width);
|
||||
column[u] = u2;
|
||||
}
|
||||
}
|
||||
|
||||
turb = intsintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
|
||||
dest = vid.buffer + r_newrefdef.y * vid.rowbytes + r_newrefdef.x;
|
||||
|
||||
for (v=0 ; v<h ; v++, dest += vid.rowbytes)
|
||||
{
|
||||
col = &column[turb[v]];
|
||||
row = &rowptr[v];
|
||||
for (u=0 ; u<w ; u+=4)
|
||||
{
|
||||
dest[u+0] = row[turb[u+0]][col[u+0]];
|
||||
dest[u+1] = row[turb[u+1]][col[u+1]];
|
||||
dest[u+2] = row[turb[u+2]][col[u+2]];
|
||||
dest[u+3] = row[turb[u+3]][col[u+3]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
=============
|
||||
D_DrawTurbulent8Span
|
||||
=============
|
||||
*/
|
||||
void D_DrawTurbulent8Span (void)
|
||||
{
|
||||
int sturb, tturb;
|
||||
|
||||
do
|
||||
{
|
||||
sturb = ((r_turb_s + r_turb_turb[(r_turb_t>>16)&(CYCLE-1)])>>16)&63;
|
||||
tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63;
|
||||
*r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb);
|
||||
r_turb_s += r_turb_sstep;
|
||||
r_turb_t += r_turb_tstep;
|
||||
} while (--r_turb_spancount > 0);
|
||||
}
|
||||
|
||||
#endif // !id386
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
Turbulent8
|
||||
=============
|
||||
*/
|
||||
void Turbulent8 (espan_t *pspan)
|
||||
{
|
||||
int count;
|
||||
fixed16_t snext, tnext;
|
||||
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
|
||||
float sdivz16stepu, tdivz16stepu, zi16stepu;
|
||||
|
||||
r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
|
||||
|
||||
r_turb_sstep = 0; // keep compiler happy
|
||||
r_turb_tstep = 0; // ditto
|
||||
|
||||
r_turb_pbase = (unsigned char *)cacheblock;
|
||||
|
||||
sdivz16stepu = d_sdivzstepu * 16;
|
||||
tdivz16stepu = d_tdivzstepu * 16;
|
||||
zi16stepu = d_zistepu * 16;
|
||||
|
||||
do
|
||||
{
|
||||
r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
|
||||
(r_screenwidth * pspan->v) + pspan->u);
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
|
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
r_turb_s = (int)(sdivz * z) + sadjust;
|
||||
if (r_turb_s > bbextents)
|
||||
r_turb_s = bbextents;
|
||||
else if (r_turb_s < 0)
|
||||
r_turb_s = 0;
|
||||
|
||||
r_turb_t = (int)(tdivz * z) + tadjust;
|
||||
if (r_turb_t > bbextentt)
|
||||
r_turb_t = bbextentt;
|
||||
else if (r_turb_t < 0)
|
||||
r_turb_t = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 16)
|
||||
r_turb_spancount = 16;
|
||||
else
|
||||
r_turb_spancount = count;
|
||||
|
||||
count -= r_turb_spancount;
|
||||
|
||||
if (count)
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz16stepu;
|
||||
tdivz += tdivz16stepu;
|
||||
zi += zi16stepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
r_turb_sstep = (snext - r_turb_s) >> 4;
|
||||
r_turb_tstep = (tnext - r_turb_t) >> 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(r_turb_spancount - 1);
|
||||
sdivz += d_sdivzstepu * spancountminus1;
|
||||
tdivz += d_tdivzstepu * spancountminus1;
|
||||
zi += d_zistepu * spancountminus1;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
if (r_turb_spancount > 1)
|
||||
{
|
||||
r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
|
||||
r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
r_turb_s = r_turb_s & ((CYCLE<<16)-1);
|
||||
r_turb_t = r_turb_t & ((CYCLE<<16)-1);
|
||||
|
||||
D_DrawTurbulent8Span ();
|
||||
|
||||
r_turb_s = snext;
|
||||
r_turb_t = tnext;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
|
||||
//====================
|
||||
//PGM
|
||||
/*
|
||||
=============
|
||||
NonTurbulent8 - this is for drawing scrolling textures. they're warping water textures
|
||||
but the turbulence is automatically 0.
|
||||
=============
|
||||
*/
|
||||
void NonTurbulent8 (espan_t *pspan)
|
||||
{
|
||||
int count;
|
||||
fixed16_t snext, tnext;
|
||||
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
|
||||
float sdivz16stepu, tdivz16stepu, zi16stepu;
|
||||
|
||||
// r_turb_turb = sintable + ((int)(r_newrefdef.time*SPEED)&(CYCLE-1));
|
||||
r_turb_turb = blanktable;
|
||||
|
||||
r_turb_sstep = 0; // keep compiler happy
|
||||
r_turb_tstep = 0; // ditto
|
||||
|
||||
r_turb_pbase = (unsigned char *)cacheblock;
|
||||
|
||||
sdivz16stepu = d_sdivzstepu * 16;
|
||||
tdivz16stepu = d_tdivzstepu * 16;
|
||||
zi16stepu = d_zistepu * 16;
|
||||
|
||||
do
|
||||
{
|
||||
r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer +
|
||||
(r_screenwidth * pspan->v) + pspan->u);
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
|
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
r_turb_s = (int)(sdivz * z) + sadjust;
|
||||
if (r_turb_s > bbextents)
|
||||
r_turb_s = bbextents;
|
||||
else if (r_turb_s < 0)
|
||||
r_turb_s = 0;
|
||||
|
||||
r_turb_t = (int)(tdivz * z) + tadjust;
|
||||
if (r_turb_t > bbextentt)
|
||||
r_turb_t = bbextentt;
|
||||
else if (r_turb_t < 0)
|
||||
r_turb_t = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 16)
|
||||
r_turb_spancount = 16;
|
||||
else
|
||||
r_turb_spancount = count;
|
||||
|
||||
count -= r_turb_spancount;
|
||||
|
||||
if (count)
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz16stepu;
|
||||
tdivz += tdivz16stepu;
|
||||
zi += zi16stepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
r_turb_sstep = (snext - r_turb_s) >> 4;
|
||||
r_turb_tstep = (tnext - r_turb_t) >> 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(r_turb_spancount - 1);
|
||||
sdivz += d_sdivzstepu * spancountminus1;
|
||||
tdivz += d_tdivzstepu * spancountminus1;
|
||||
zi += d_zistepu * spancountminus1;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 16)
|
||||
snext = 16; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 16)
|
||||
tnext = 16; // guard against round-off error on <0 steps
|
||||
|
||||
if (r_turb_spancount > 1)
|
||||
{
|
||||
r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1);
|
||||
r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
r_turb_s = r_turb_s & ((CYCLE<<16)-1);
|
||||
r_turb_t = r_turb_t & ((CYCLE<<16)-1);
|
||||
|
||||
D_DrawTurbulent8Span ();
|
||||
|
||||
r_turb_s = snext;
|
||||
r_turb_t = tnext;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
//PGM
|
||||
//====================
|
||||
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
=============
|
||||
D_DrawSpans16
|
||||
|
||||
FIXME: actually make this subdivide by 16 instead of 8!!!
|
||||
=============
|
||||
*/
|
||||
void D_DrawSpans16 (espan_t *pspan)
|
||||
{
|
||||
int count, spancount;
|
||||
unsigned char *pbase, *pdest;
|
||||
fixed16_t s, t, snext, tnext, sstep, tstep;
|
||||
float sdivz, tdivz, zi, z, du, dv, spancountminus1;
|
||||
float sdivz8stepu, tdivz8stepu, zi8stepu;
|
||||
|
||||
sstep = 0; // keep compiler happy
|
||||
tstep = 0; // ditto
|
||||
|
||||
pbase = (unsigned char *)cacheblock;
|
||||
|
||||
sdivz8stepu = d_sdivzstepu * 8;
|
||||
tdivz8stepu = d_tdivzstepu * 8;
|
||||
zi8stepu = d_zistepu * 8;
|
||||
|
||||
do
|
||||
{
|
||||
pdest = (unsigned char *)((byte *)d_viewbuffer +
|
||||
(r_screenwidth * pspan->v) + pspan->u);
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial s/z, t/z, 1/z, s, and t and clamp
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
|
||||
tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
s = (int)(sdivz * z) + sadjust;
|
||||
if (s > bbextents)
|
||||
s = bbextents;
|
||||
else if (s < 0)
|
||||
s = 0;
|
||||
|
||||
t = (int)(tdivz * z) + tadjust;
|
||||
if (t > bbextentt)
|
||||
t = bbextentt;
|
||||
else if (t < 0)
|
||||
t = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// calculate s and t at the far end of the span
|
||||
if (count >= 8)
|
||||
spancount = 8;
|
||||
else
|
||||
spancount = count;
|
||||
|
||||
count -= spancount;
|
||||
|
||||
if (count)
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at far end of span,
|
||||
// calculate s and t steps across span by shifting
|
||||
sdivz += sdivz8stepu;
|
||||
tdivz += tdivz8stepu;
|
||||
zi += zi8stepu;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 8)
|
||||
snext = 8; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 8)
|
||||
tnext = 8; // guard against round-off error on <0 steps
|
||||
|
||||
sstep = (snext - s) >> 3;
|
||||
tstep = (tnext - t) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
|
||||
// can't step off polygon), clamp, calculate s and t steps across
|
||||
// span by division, biasing steps low so we don't run off the
|
||||
// texture
|
||||
spancountminus1 = (float)(spancount - 1);
|
||||
sdivz += d_sdivzstepu * spancountminus1;
|
||||
tdivz += d_tdivzstepu * spancountminus1;
|
||||
zi += d_zistepu * spancountminus1;
|
||||
z = (float)0x10000 / zi; // prescale to 16.16 fixed-point
|
||||
snext = (int)(sdivz * z) + sadjust;
|
||||
if (snext > bbextents)
|
||||
snext = bbextents;
|
||||
else if (snext < 8)
|
||||
snext = 8; // prevent round-off error on <0 steps from
|
||||
// from causing overstepping & running off the
|
||||
// edge of the texture
|
||||
|
||||
tnext = (int)(tdivz * z) + tadjust;
|
||||
if (tnext > bbextentt)
|
||||
tnext = bbextentt;
|
||||
else if (tnext < 8)
|
||||
tnext = 8; // guard against round-off error on <0 steps
|
||||
|
||||
if (spancount > 1)
|
||||
{
|
||||
sstep = (snext - s) / (spancount - 1);
|
||||
tstep = (tnext - t) / (spancount - 1);
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
|
||||
s += sstep;
|
||||
t += tstep;
|
||||
} while (--spancount > 0);
|
||||
|
||||
s = snext;
|
||||
t = tnext;
|
||||
|
||||
} while (count > 0);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
=============
|
||||
D_DrawZSpans
|
||||
=============
|
||||
*/
|
||||
void D_DrawZSpans (espan_t *pspan)
|
||||
{
|
||||
int count, doublecount, izistep;
|
||||
int izi;
|
||||
short *pdest;
|
||||
unsigned ltemp;
|
||||
float zi;
|
||||
float du, dv;
|
||||
|
||||
// FIXME: check for clamping/range problems
|
||||
// we count on FP exceptions being turned off to avoid range problems
|
||||
izistep = (int)(d_zistepu * 0x8000 * 0x10000);
|
||||
|
||||
do
|
||||
{
|
||||
pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
|
||||
|
||||
count = pspan->count;
|
||||
|
||||
// calculate the initial 1/z
|
||||
du = (float)pspan->u;
|
||||
dv = (float)pspan->v;
|
||||
|
||||
zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
|
||||
// we count on FP exceptions being turned off to avoid range problems
|
||||
izi = (int)(zi * 0x8000 * 0x10000);
|
||||
|
||||
if ((long)pdest & 0x02)
|
||||
{
|
||||
*pdest++ = (short)(izi >> 16);
|
||||
izi += izistep;
|
||||
count--;
|
||||
}
|
||||
|
||||
if ((doublecount = count >> 1) > 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
ltemp = izi >> 16;
|
||||
izi += izistep;
|
||||
ltemp |= izi & 0xFFFF0000;
|
||||
izi += izistep;
|
||||
*(int *)pdest = ltemp;
|
||||
pdest += 2;
|
||||
} while (--doublecount > 0);
|
||||
}
|
||||
|
||||
if (count & 1)
|
||||
*pdest = (short)(izi >> 16);
|
||||
|
||||
} while ((pspan = pspan->pnext) != NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
73
ref_soft/r_scana.asm
Normal file
73
ref_soft/r_scana.asm
Normal file
@@ -0,0 +1,73 @@
|
||||
.386P
|
||||
.model FLAT
|
||||
;
|
||||
; d_scana.s
|
||||
; x86 assembly-language turbulent texture mapping code
|
||||
;
|
||||
|
||||
include qasm.inc
|
||||
include d_if.inc
|
||||
|
||||
if id386
|
||||
|
||||
_DATA SEGMENT
|
||||
|
||||
_DATA ENDS
|
||||
_TEXT SEGMENT
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; turbulent texture mapping code
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
align 4
|
||||
public _D_DrawTurbulent8Span
|
||||
_D_DrawTurbulent8Span:
|
||||
push ebp ; preserve caller's stack frame pointer
|
||||
push esi ; preserve register variables
|
||||
push edi
|
||||
push ebx
|
||||
|
||||
mov esi,ds:dword ptr[_r_turb_s]
|
||||
mov ecx,ds:dword ptr[_r_turb_t]
|
||||
mov edi,ds:dword ptr[_r_turb_pdest]
|
||||
mov ebx,ds:dword ptr[_r_turb_spancount]
|
||||
|
||||
Llp:
|
||||
mov eax,ecx
|
||||
mov edx,esi
|
||||
sar eax,16
|
||||
mov ebp,ds:dword ptr[_r_turb_turb]
|
||||
sar edx,16
|
||||
and eax,offset CYCLE-1
|
||||
and edx,offset CYCLE-1
|
||||
mov eax,ds:dword ptr[ebp+eax*4]
|
||||
mov edx,ds:dword ptr[ebp+edx*4]
|
||||
add eax,esi
|
||||
sar eax,16
|
||||
add edx,ecx
|
||||
sar edx,16
|
||||
and eax,offset TURB_TEX_SIZE-1
|
||||
and edx,offset TURB_TEX_SIZE-1
|
||||
shl edx,6
|
||||
mov ebp,ds:dword ptr[_r_turb_pbase]
|
||||
add edx,eax
|
||||
inc edi
|
||||
add esi,ds:dword ptr[_r_turb_sstep]
|
||||
add ecx,ds:dword ptr[_r_turb_tstep]
|
||||
mov dl,ds:byte ptr[ebp+edx*1]
|
||||
dec ebx
|
||||
mov ds:byte ptr[-1+edi],dl
|
||||
jnz Llp
|
||||
|
||||
mov ds:dword ptr[_r_turb_pdest],edi
|
||||
|
||||
pop ebx ; restore register variables
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp ; restore caller's stack frame pointer
|
||||
ret
|
||||
|
||||
|
||||
_TEXT ENDS
|
||||
endif ;id386
|
||||
END
|
||||
884
ref_soft/r_spr8.asm
Normal file
884
ref_soft/r_spr8.asm
Normal file
@@ -0,0 +1,884 @@
|
||||
.386P
|
||||
.model FLAT
|
||||
;
|
||||
; d_spr8.s
|
||||
; x86 assembly-language horizontal 8-bpp transparent span-drawing code.
|
||||
;
|
||||
|
||||
include qasm.inc
|
||||
include d_if.inc
|
||||
|
||||
if id386
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; 8-bpp horizontal span drawing code for polygons, with transparency.
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
_TEXT SEGMENT
|
||||
|
||||
; out-of-line, rarely-needed clamping code
|
||||
|
||||
LClampHigh0:
|
||||
mov esi,ds:dword ptr[_bbextents]
|
||||
jmp LClampReentry0
|
||||
LClampHighOrLow0:
|
||||
jg LClampHigh0
|
||||
xor esi,esi
|
||||
jmp LClampReentry0
|
||||
|
||||
LClampHigh1:
|
||||
mov edx,ds:dword ptr[_bbextentt]
|
||||
jmp LClampReentry1
|
||||
LClampHighOrLow1:
|
||||
jg LClampHigh1
|
||||
xor edx,edx
|
||||
jmp LClampReentry1
|
||||
|
||||
LClampLow2:
|
||||
mov ebp,2048
|
||||
jmp LClampReentry2
|
||||
LClampHigh2:
|
||||
mov ebp,ds:dword ptr[_bbextents]
|
||||
jmp LClampReentry2
|
||||
|
||||
LClampLow3:
|
||||
mov ecx,2048
|
||||
jmp LClampReentry3
|
||||
LClampHigh3:
|
||||
mov ecx,ds:dword ptr[_bbextentt]
|
||||
jmp LClampReentry3
|
||||
|
||||
LClampLow4:
|
||||
mov eax,2048
|
||||
jmp LClampReentry4
|
||||
LClampHigh4:
|
||||
mov eax,ds:dword ptr[_bbextents]
|
||||
jmp LClampReentry4
|
||||
|
||||
LClampLow5:
|
||||
mov ebx,2048
|
||||
jmp LClampReentry5
|
||||
LClampHigh5:
|
||||
mov ebx,ds:dword ptr[_bbextentt]
|
||||
jmp LClampReentry5
|
||||
|
||||
|
||||
pspans equ 4+16
|
||||
|
||||
align 4
|
||||
public _D_SpriteDrawSpansXXX
|
||||
_D_SpriteDrawSpansXXX:
|
||||
push ebp ; preserve caller's stack frame
|
||||
push edi
|
||||
push esi ; preserve register variables
|
||||
push ebx
|
||||
|
||||
;
|
||||
; set up scaled-by-8 steps, for 8-long segments; also set up cacheblock
|
||||
; and span list pointers, and 1/z step in 0.32 fixed-point
|
||||
;
|
||||
; FIXME: any overlap from rearranging?
|
||||
fld ds:dword ptr[_d_sdivzstepu]
|
||||
fmul ds:dword ptr[fp_8]
|
||||
mov edx,ds:dword ptr[_cacheblock]
|
||||
fld ds:dword ptr[_d_tdivzstepu]
|
||||
fmul ds:dword ptr[fp_8]
|
||||
mov ebx,ds:dword ptr[pspans+esp] ; point to the first span descriptor
|
||||
fld ds:dword ptr[_d_zistepu]
|
||||
fmul ds:dword ptr[fp_8]
|
||||
mov ds:dword ptr[pbase],edx ; pbase = cacheblock
|
||||
fld ds:dword ptr[_d_zistepu]
|
||||
fmul ds:dword ptr[fp_64kx64k]
|
||||
fxch st(3)
|
||||
fstp ds:dword ptr[sdivz8stepu]
|
||||
fstp ds:dword ptr[zi8stepu]
|
||||
fstp ds:dword ptr[tdivz8stepu]
|
||||
fistp ds:dword ptr[izistep]
|
||||
mov eax,ds:dword ptr[izistep]
|
||||
ror eax,16 ; put upper 16 bits in low word
|
||||
mov ecx,ds:dword ptr[sspan_t_count+ebx]
|
||||
mov ds:dword ptr[izistep],eax
|
||||
|
||||
cmp ecx,0
|
||||
jle LNextSpan
|
||||
|
||||
LSpanLoop:
|
||||
|
||||
;
|
||||
; set up the initial s/z, t/z, and 1/z on the FP stack, and generate the
|
||||
; initial s and t values
|
||||
;
|
||||
; FIXME: pipeline FILD?
|
||||
fild ds:dword ptr[sspan_t_v+ebx]
|
||||
fild ds:dword ptr[sspan_t_u+ebx]
|
||||
|
||||
fld st(1) ; dv | du | dv
|
||||
fmul ds:dword ptr[_d_sdivzstepv] ; dv*d_sdivzstepv | du | dv
|
||||
fld st(1) ; du | dv*d_sdivzstepv | du | dv
|
||||
fmul ds:dword ptr[_d_sdivzstepu] ; du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
|
||||
fld st(2) ; du | du*d_sdivzstepu | dv*d_sdivzstepv | du | dv
|
||||
fmul ds:dword ptr[_d_tdivzstepu] ; du*d_tdivzstepu | du*d_sdivzstepu |
|
||||
; dv*d_sdivzstepv | du | dv
|
||||
fxch st(1) ; du*d_sdivzstepu | du*d_tdivzstepu |
|
||||
; dv*d_sdivzstepv | du | dv
|
||||
faddp st(2),st(0) ; du*d_tdivzstepu |
|
||||
; du*d_sdivzstepu + dv*d_sdivzstepv | du | dv
|
||||
fxch st(1) ; du*d_sdivzstepu + dv*d_sdivzstepv |
|
||||
; du*d_tdivzstepu | du | dv
|
||||
fld st(3) ; dv | du*d_sdivzstepu + dv*d_sdivzstepv |
|
||||
; du*d_tdivzstepu | du | dv
|
||||
fmul ds:dword ptr[_d_tdivzstepv] ; dv*d_tdivzstepv |
|
||||
; du*d_sdivzstepu + dv*d_sdivzstepv |
|
||||
; du*d_tdivzstepu | du | dv
|
||||
fxch st(1) ; du*d_sdivzstepu + dv*d_sdivzstepv |
|
||||
; dv*d_tdivzstepv | du*d_tdivzstepu | du | dv
|
||||
fadd ds:dword ptr[_d_sdivzorigin] ; sdivz = d_sdivzorigin + dv*d_sdivzstepv +
|
||||
; du*d_sdivzstepu; stays in %st(2) at end
|
||||
fxch st(4) ; dv | dv*d_tdivzstepv | du*d_tdivzstepu | du |
|
||||
; s/z
|
||||
fmul ds:dword ptr[_d_zistepv] ; dv*d_zistepv | dv*d_tdivzstepv |
|
||||
; du*d_tdivzstepu | du | s/z
|
||||
fxch st(1) ; dv*d_tdivzstepv | dv*d_zistepv |
|
||||
; du*d_tdivzstepu | du | s/z
|
||||
faddp st(2),st(0) ; dv*d_zistepv |
|
||||
; dv*d_tdivzstepv + du*d_tdivzstepu | du | s/z
|
||||
fxch st(2) ; du | dv*d_tdivzstepv + du*d_tdivzstepu |
|
||||
; dv*d_zistepv | s/z
|
||||
fmul ds:dword ptr[_d_zistepu] ; du*d_zistepu |
|
||||
; dv*d_tdivzstepv + du*d_tdivzstepu |
|
||||
; dv*d_zistepv | s/z
|
||||
fxch st(1) ; dv*d_tdivzstepv + du*d_tdivzstepu |
|
||||
; du*d_zistepu | dv*d_zistepv | s/z
|
||||
fadd ds:dword ptr[_d_tdivzorigin] ; tdivz = d_tdivzorigin + dv*d_tdivzstepv +
|
||||
; du*d_tdivzstepu; stays in %st(1) at end
|
||||
fxch st(2) ; dv*d_zistepv | du*d_zistepu | t/z | s/z
|
||||
faddp st(1),st(0) ; dv*d_zistepv + du*d_zistepu | t/z | s/z
|
||||
|
||||
fld ds:dword ptr[fp_64k] ; fp_64k | dv*d_zistepv + du*d_zistepu | t/z | s/z
|
||||
fxch st(1) ; dv*d_zistepv + du*d_zistepu | fp_64k | t/z | s/z
|
||||
fadd ds:dword ptr[_d_ziorigin] ; zi = d_ziorigin + dv*d_zistepv +
|
||||
; du*d_zistepu; stays in %st(0) at end
|
||||
; 1/z | fp_64k | t/z | s/z
|
||||
|
||||
fld st(0) ; FIXME: get rid of stall on FMUL?
|
||||
fmul ds:dword ptr[fp_64kx64k]
|
||||
fxch st(1)
|
||||
|
||||
;
|
||||
; calculate and clamp s & t
|
||||
;
|
||||
fdiv st(2),st(0) ; 1/z | z*64k | t/z | s/z
|
||||
fxch st(1)
|
||||
|
||||
fistp ds:dword ptr[izi] ; 0.32 fixed-point 1/z
|
||||
mov ebp,ds:dword ptr[izi]
|
||||
|
||||
;
|
||||
; set pz to point to the first z-buffer pixel in the span
|
||||
;
|
||||
ror ebp,16 ; put upper 16 bits in low word
|
||||
mov eax,ds:dword ptr[sspan_t_v+ebx]
|
||||
mov ds:dword ptr[izi],ebp
|
||||
mov ebp,ds:dword ptr[sspan_t_u+ebx]
|
||||
imul ds:dword ptr[_d_zrowbytes]
|
||||
shl ebp,1 ; a word per pixel
|
||||
add eax,ds:dword ptr[_d_pzbuffer]
|
||||
add eax,ebp
|
||||
mov ds:dword ptr[pz],eax
|
||||
|
||||
;
|
||||
; point %edi to the first pixel in the span
|
||||
;
|
||||
mov ebp,ds:dword ptr[_d_viewbuffer]
|
||||
mov eax,ds:dword ptr[sspan_t_v+ebx]
|
||||
push ebx ; preserve spans pointer
|
||||
mov edx,ds:dword ptr[_tadjust]
|
||||
mov esi,ds:dword ptr[_sadjust]
|
||||
mov edi,ds:dword ptr[_d_scantable+eax*4] ; v * screenwidth
|
||||
add edi,ebp
|
||||
mov ebp,ds:dword ptr[sspan_t_u+ebx]
|
||||
add edi,ebp ; pdest = &pdestspan[scans->u];
|
||||
|
||||
;
|
||||
; now start the FDIV for the end of the span
|
||||
;
|
||||
cmp ecx,8
|
||||
ja LSetupNotLast1
|
||||
|
||||
dec ecx
|
||||
jz LCleanup1 ; if only one pixel, no need to start an FDIV
|
||||
mov ds:dword ptr[spancountminus1],ecx
|
||||
|
||||
; finish up the s and t calcs
|
||||
fxch st(1) ; z*64k | 1/z | t/z | s/z
|
||||
|
||||
fld st(0) ; z*64k | z*64k | 1/z | t/z | s/z
|
||||
fmul st(0),st(4) ; s | z*64k | 1/z | t/z | s/z
|
||||
fxch st(1) ; z*64k | s | 1/z | t/z | s/z
|
||||
fmul st(0),st(3) ; t | s | 1/z | t/z | s/z
|
||||
fxch st(1) ; s | t | 1/z | t/z | s/z
|
||||
fistp ds:dword ptr[s] ; 1/z | t | t/z | s/z
|
||||
fistp ds:dword ptr[t] ; 1/z | t/z | s/z
|
||||
|
||||
fild ds:dword ptr[spancountminus1]
|
||||
|
||||
fld ds:dword ptr[_d_tdivzstepu] ; _d_tdivzstepu | spancountminus1
|
||||
fld ds:dword ptr[_d_zistepu] ; _d_zistepu | _d_tdivzstepu | spancountminus1
|
||||
fmul st(0),st(2) ; _d_zistepu*scm1 | _d_tdivzstepu | scm1
|
||||
fxch st(1) ; _d_tdivzstepu | _d_zistepu*scm1 | scm1
|
||||
fmul st(0),st(2) ; _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
|
||||
fxch st(2) ; scm1 | _d_zistepu*scm1 | _d_tdivzstepu*scm1
|
||||
fmul ds:dword ptr[_d_sdivzstepu] ; _d_sdivzstepu*scm1 | _d_zistepu*scm1 |
|
||||
; _d_tdivzstepu*scm1
|
||||
fxch st(1) ; _d_zistepu*scm1 | _d_sdivzstepu*scm1 |
|
||||
; _d_tdivzstepu*scm1
|
||||
faddp st(3),st(0) ; _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
|
||||
fxch st(1) ; _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
|
||||
faddp st(3),st(0) ; _d_sdivzstepu*scm1
|
||||
faddp st(3),st(0)
|
||||
|
||||
fld ds:dword ptr[fp_64k]
|
||||
fdiv st(0),st(1) ; this is what we've gone to all this trouble to
|
||||
; overlap
|
||||
jmp LFDIVInFlight1
|
||||
|
||||
LCleanup1:
|
||||
; finish up the s and t calcs
|
||||
fxch st(1) ; z*64k | 1/z | t/z | s/z
|
||||
|
||||
fld st(0) ; z*64k | z*64k | 1/z | t/z | s/z
|
||||
fmul st(0),st(4) ; s | z*64k | 1/z | t/z | s/z
|
||||
fxch st(1) ; z*64k | s | 1/z | t/z | s/z
|
||||
fmul st(0),st(3) ; t | s | 1/z | t/z | s/z
|
||||
fxch st(1) ; s | t | 1/z | t/z | s/z
|
||||
fistp ds:dword ptr[s] ; 1/z | t | t/z | s/z
|
||||
fistp ds:dword ptr[t] ; 1/z | t/z | s/z
|
||||
jmp LFDIVInFlight1
|
||||
|
||||
align 4
|
||||
LSetupNotLast1:
|
||||
; finish up the s and t calcs
|
||||
fxch st(1) ; z*64k | 1/z | t/z | s/z
|
||||
|
||||
fld st(0) ; z*64k | z*64k | 1/z | t/z | s/z
|
||||
fmul st(0),st(4) ; s | z*64k | 1/z | t/z | s/z
|
||||
fxch st(1) ; z*64k | s | 1/z | t/z | s/z
|
||||
fmul st(0),st(3) ; t | s | 1/z | t/z | s/z
|
||||
fxch st(1) ; s | t | 1/z | t/z | s/z
|
||||
fistp ds:dword ptr[s] ; 1/z | t | t/z | s/z
|
||||
fistp ds:dword ptr[t] ; 1/z | t/z | s/z
|
||||
|
||||
fadd ds:dword ptr[zi8stepu]
|
||||
fxch st(2)
|
||||
fadd ds:dword ptr[sdivz8stepu]
|
||||
fxch st(2)
|
||||
fld ds:dword ptr[tdivz8stepu]
|
||||
faddp st(2),st(0)
|
||||
fld ds:dword ptr[fp_64k]
|
||||
fdiv st(0),st(1) ; z = 1/1/z
|
||||
; this is what we've gone to all this trouble to
|
||||
; overlap
|
||||
LFDIVInFlight1:
|
||||
|
||||
add esi,ds:dword ptr[s]
|
||||
add edx,ds:dword ptr[t]
|
||||
mov ebx,ds:dword ptr[_bbextents]
|
||||
mov ebp,ds:dword ptr[_bbextentt]
|
||||
cmp esi,ebx
|
||||
ja LClampHighOrLow0
|
||||
LClampReentry0:
|
||||
mov ds:dword ptr[s],esi
|
||||
mov ebx,ds:dword ptr[pbase]
|
||||
shl esi,16
|
||||
cmp edx,ebp
|
||||
mov ds:dword ptr[sfracf],esi
|
||||
ja LClampHighOrLow1
|
||||
LClampReentry1:
|
||||
mov ds:dword ptr[t],edx
|
||||
mov esi,ds:dword ptr[s] ; sfrac = scans->sfrac;
|
||||
shl edx,16
|
||||
mov eax,ds:dword ptr[t] ; tfrac = scans->tfrac;
|
||||
sar esi,16
|
||||
mov ds:dword ptr[tfracf],edx
|
||||
|
||||
;
|
||||
; calculate the texture starting address
|
||||
;
|
||||
sar eax,16
|
||||
add esi,ebx
|
||||
imul eax,ds:dword ptr[_cachewidth] ; (tfrac >> 16) * cachewidth
|
||||
add esi,eax ; psource = pbase + (sfrac >> 16) +
|
||||
; ((tfrac >> 16) * cachewidth);
|
||||
|
||||
;
|
||||
; determine whether last span or not
|
||||
;
|
||||
cmp ecx,8
|
||||
jna LLastSegment
|
||||
|
||||
;
|
||||
; not the last segment; do full 8-wide segment
|
||||
;
|
||||
LNotLastSegment:
|
||||
|
||||
;
|
||||
; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
|
||||
; get there
|
||||
;
|
||||
|
||||
; pick up after the FDIV that was left in flight previously
|
||||
|
||||
fld st(0) ; duplicate it
|
||||
fmul st(0),st(4) ; s = s/z * z
|
||||
fxch st(1)
|
||||
fmul st(0),st(3) ; t = t/z * z
|
||||
fxch st(1)
|
||||
fistp ds:dword ptr[snext]
|
||||
fistp ds:dword ptr[tnext]
|
||||
mov eax,ds:dword ptr[snext]
|
||||
mov edx,ds:dword ptr[tnext]
|
||||
|
||||
sub ecx,8 ; count off this segments' pixels
|
||||
mov ebp,ds:dword ptr[_sadjust]
|
||||
push ecx ; remember count of remaining pixels
|
||||
mov ecx,ds:dword ptr[_tadjust]
|
||||
|
||||
add ebp,eax
|
||||
add ecx,edx
|
||||
|
||||
mov eax,ds:dword ptr[_bbextents]
|
||||
mov edx,ds:dword ptr[_bbextentt]
|
||||
|
||||
cmp ebp,2048
|
||||
jl LClampLow2
|
||||
cmp ebp,eax
|
||||
ja LClampHigh2
|
||||
LClampReentry2:
|
||||
|
||||
cmp ecx,2048
|
||||
jl LClampLow3
|
||||
cmp ecx,edx
|
||||
ja LClampHigh3
|
||||
LClampReentry3:
|
||||
|
||||
mov ds:dword ptr[snext],ebp
|
||||
mov ds:dword ptr[tnext],ecx
|
||||
|
||||
sub ebp,ds:dword ptr[s]
|
||||
sub ecx,ds:dword ptr[t]
|
||||
|
||||
;
|
||||
; set up advancetable
|
||||
;
|
||||
mov eax,ecx
|
||||
mov edx,ebp
|
||||
sar edx,19 ; sstep >>= 16;
|
||||
mov ebx,ds:dword ptr[_cachewidth]
|
||||
sar eax,19 ; tstep >>= 16;
|
||||
jz LIsZero
|
||||
imul eax,ebx ; (tstep >> 16) * cachewidth;
|
||||
LIsZero:
|
||||
add eax,edx ; add in sstep
|
||||
; (tstep >> 16) * cachewidth + (sstep >> 16);
|
||||
mov edx,ds:dword ptr[tfracf]
|
||||
mov ds:dword ptr[advancetable+4],eax ; advance base in t
|
||||
add eax,ebx ; ((tstep >> 16) + 1) * cachewidth +
|
||||
; (sstep >> 16);
|
||||
shl ebp,13 ; left-justify sstep fractional part
|
||||
mov ds:dword ptr[sstep],ebp
|
||||
mov ebx,ds:dword ptr[sfracf]
|
||||
shl ecx,13 ; left-justify tstep fractional part
|
||||
mov ds:dword ptr[advancetable],eax ; advance extra in t
|
||||
mov ds:dword ptr[tstep],ecx
|
||||
|
||||
mov ecx,ds:dword ptr[pz]
|
||||
mov ebp,ds:dword ptr[izi]
|
||||
|
||||
cmp bp,ds:word ptr[ecx]
|
||||
jl Lp1
|
||||
mov al,ds:byte ptr[esi] ; get first source texel
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp1
|
||||
mov ds:word ptr[ecx],bp
|
||||
mov ds:byte ptr[edi],al ; store first dest pixel
|
||||
Lp1:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep] ; advance tfrac fractional part by tstep frac
|
||||
|
||||
sbb eax,eax ; turn tstep carry into -1 (0 if none)
|
||||
add ebx,ds:dword ptr[sstep] ; advance sfrac fractional part by sstep frac
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4] ; point to next source texel
|
||||
|
||||
cmp bp,ds:word ptr[2+ecx]
|
||||
jl Lp2
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp2
|
||||
mov ds:word ptr[2+ecx],bp
|
||||
mov ds:byte ptr[1+edi],al
|
||||
Lp2:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
cmp bp,ds:word ptr[4+ecx]
|
||||
jl Lp3
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp3
|
||||
mov ds:word ptr[4+ecx],bp
|
||||
mov ds:byte ptr[2+edi],al
|
||||
Lp3:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
cmp bp,ds:word ptr[6+ecx]
|
||||
jl Lp4
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp4
|
||||
mov ds:word ptr[6+ecx],bp
|
||||
mov ds:byte ptr[3+edi],al
|
||||
Lp4:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
cmp bp,ds:word ptr[8+ecx]
|
||||
jl Lp5
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp5
|
||||
mov ds:word ptr[8+ecx],bp
|
||||
mov ds:byte ptr[4+edi],al
|
||||
Lp5:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
;
|
||||
; start FDIV for end of next segment in flight, so it can overlap
|
||||
;
|
||||
pop eax
|
||||
cmp eax,8 ; more than one segment after this?
|
||||
ja LSetupNotLast2 ; yes
|
||||
|
||||
dec eax
|
||||
jz LFDIVInFlight2 ; if only one pixel, no need to start an FDIV
|
||||
mov ds:dword ptr[spancountminus1],eax
|
||||
fild ds:dword ptr[spancountminus1]
|
||||
|
||||
fld ds:dword ptr[_d_zistepu] ; _d_zistepu | spancountminus1
|
||||
fmul st(0),st(1) ; _d_zistepu*scm1 | scm1
|
||||
fld ds:dword ptr[_d_tdivzstepu] ; _d_tdivzstepu | _d_zistepu*scm1 | scm1
|
||||
fmul st(0),st(2) ; _d_tdivzstepu*scm1 | _d_zistepu*scm1 | scm1
|
||||
fxch st(1) ; _d_zistepu*scm1 | _d_tdivzstepu*scm1 | scm1
|
||||
faddp st(3),st(0) ; _d_tdivzstepu*scm1 | scm1
|
||||
fxch st(1) ; scm1 | _d_tdivzstepu*scm1
|
||||
fmul ds:dword ptr[_d_sdivzstepu] ; _d_sdivzstepu*scm1 | _d_tdivzstepu*scm1
|
||||
fxch st(1) ; _d_tdivzstepu*scm1 | _d_sdivzstepu*scm1
|
||||
faddp st(3),st(0) ; _d_sdivzstepu*scm1
|
||||
fld ds:dword ptr[fp_64k] ; 64k | _d_sdivzstepu*scm1
|
||||
fxch st(1) ; _d_sdivzstepu*scm1 | 64k
|
||||
faddp st(4),st(0) ; 64k
|
||||
|
||||
fdiv st(0),st(1) ; this is what we've gone to all this trouble to
|
||||
; overlap
|
||||
jmp LFDIVInFlight2
|
||||
|
||||
align 4
|
||||
LSetupNotLast2:
|
||||
fadd ds:dword ptr[zi8stepu]
|
||||
fxch st(2)
|
||||
fadd ds:dword ptr[sdivz8stepu]
|
||||
fxch st(2)
|
||||
fld ds:dword ptr[tdivz8stepu]
|
||||
faddp st(2),st(0)
|
||||
fld ds:dword ptr[fp_64k]
|
||||
fdiv st(0),st(1) ; z = 1/1/z
|
||||
; this is what we've gone to all this trouble to
|
||||
; overlap
|
||||
LFDIVInFlight2:
|
||||
push eax
|
||||
|
||||
cmp bp,ds:word ptr[10+ecx]
|
||||
jl Lp6
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp6
|
||||
mov ds:word ptr[10+ecx],bp
|
||||
mov ds:byte ptr[5+edi],al
|
||||
Lp6:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
cmp bp,ds:word ptr[12+ecx]
|
||||
jl Lp7
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp7
|
||||
mov ds:word ptr[12+ecx],bp
|
||||
mov ds:byte ptr[6+edi],al
|
||||
Lp7:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
cmp bp,ds:word ptr[14+ecx]
|
||||
jl Lp8
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp8
|
||||
mov ds:word ptr[14+ecx],bp
|
||||
mov ds:byte ptr[7+edi],al
|
||||
Lp8:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
add edi,8
|
||||
add ecx,16
|
||||
mov ds:dword ptr[tfracf],edx
|
||||
mov edx,ds:dword ptr[snext]
|
||||
mov ds:dword ptr[sfracf],ebx
|
||||
mov ebx,ds:dword ptr[tnext]
|
||||
mov ds:dword ptr[s],edx
|
||||
mov ds:dword ptr[t],ebx
|
||||
|
||||
mov ds:dword ptr[pz],ecx
|
||||
mov ds:dword ptr[izi],ebp
|
||||
|
||||
pop ecx ; retrieve count
|
||||
|
||||
;
|
||||
; determine whether last span or not
|
||||
;
|
||||
cmp ecx,8 ; are there multiple segments remaining?
|
||||
ja LNotLastSegment ; yes
|
||||
|
||||
;
|
||||
; last segment of scan
|
||||
;
|
||||
LLastSegment:
|
||||
|
||||
;
|
||||
; advance s/z, t/z, and 1/z, and calculate s & t at end of span and steps to
|
||||
; get there. The number of pixels left is variable, and we want to land on the
|
||||
; last pixel, not step one past it, so we can't run into arithmetic problems
|
||||
;
|
||||
test ecx,ecx
|
||||
jz LNoSteps ; just draw the last pixel and we're done
|
||||
|
||||
; pick up after the FDIV that was left in flight previously
|
||||
|
||||
|
||||
fld st(0) ; duplicate it
|
||||
fmul st(0),st(4) ; s = s/z * z
|
||||
fxch st(1)
|
||||
fmul st(0),st(3) ; t = t/z * z
|
||||
fxch st(1)
|
||||
fistp ds:dword ptr[snext]
|
||||
fistp ds:dword ptr[tnext]
|
||||
|
||||
mov ebx,ds:dword ptr[_tadjust]
|
||||
mov eax,ds:dword ptr[_sadjust]
|
||||
|
||||
add eax,ds:dword ptr[snext]
|
||||
add ebx,ds:dword ptr[tnext]
|
||||
|
||||
mov ebp,ds:dword ptr[_bbextents]
|
||||
mov edx,ds:dword ptr[_bbextentt]
|
||||
|
||||
cmp eax,2048
|
||||
jl LClampLow4
|
||||
cmp eax,ebp
|
||||
ja LClampHigh4
|
||||
LClampReentry4:
|
||||
mov ds:dword ptr[snext],eax
|
||||
|
||||
cmp ebx,2048
|
||||
jl LClampLow5
|
||||
cmp ebx,edx
|
||||
ja LClampHigh5
|
||||
LClampReentry5:
|
||||
|
||||
cmp ecx,1 ; don't bother
|
||||
je LOnlyOneStep ; if two pixels in segment, there's only one step,
|
||||
; of the segment length
|
||||
sub eax,ds:dword ptr[s]
|
||||
sub ebx,ds:dword ptr[t]
|
||||
|
||||
add eax,eax ; convert to 15.17 format so multiply by 1.31
|
||||
add ebx,ebx ; reciprocal yields 16.48
|
||||
imul ds:dword ptr[reciprocal_table-8+ecx*4] ; sstep = (snext - s) / (spancount-1)
|
||||
mov ebp,edx
|
||||
|
||||
mov eax,ebx
|
||||
imul ds:dword ptr[reciprocal_table-8+ecx*4] ; tstep = (tnext - t) / (spancount-1)
|
||||
|
||||
LSetEntryvec:
|
||||
;
|
||||
; set up advancetable
|
||||
;
|
||||
mov ebx,ds:dword ptr[spr8entryvec_table+ecx*4]
|
||||
mov eax,edx
|
||||
push ebx ; entry point into code for RET later
|
||||
mov ecx,ebp
|
||||
sar ecx,16 ; sstep >>= 16;
|
||||
mov ebx,ds:dword ptr[_cachewidth]
|
||||
sar edx,16 ; tstep >>= 16;
|
||||
jz LIsZeroLast
|
||||
imul edx,ebx ; (tstep >> 16) * cachewidth;
|
||||
LIsZeroLast:
|
||||
add edx,ecx ; add in sstep
|
||||
; (tstep >> 16) * cachewidth + (sstep >> 16);
|
||||
mov ecx,ds:dword ptr[tfracf]
|
||||
mov ds:dword ptr[advancetable+4],edx ; advance base in t
|
||||
add edx,ebx ; ((tstep >> 16) + 1) * cachewidth +
|
||||
; (sstep >> 16);
|
||||
shl ebp,16 ; left-justify sstep fractional part
|
||||
mov ebx,ds:dword ptr[sfracf]
|
||||
shl eax,16 ; left-justify tstep fractional part
|
||||
mov ds:dword ptr[advancetable],edx ; advance extra in t
|
||||
|
||||
mov ds:dword ptr[tstep],eax
|
||||
mov ds:dword ptr[sstep],ebp
|
||||
mov edx,ecx
|
||||
|
||||
mov ecx,ds:dword ptr[pz]
|
||||
mov ebp,ds:dword ptr[izi]
|
||||
|
||||
ret ; jump to the number-of-pixels handler
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
LNoSteps:
|
||||
mov ecx,ds:dword ptr[pz]
|
||||
sub edi,7 ; adjust for hardwired offset
|
||||
sub ecx,14
|
||||
jmp LEndSpan
|
||||
|
||||
|
||||
LOnlyOneStep:
|
||||
sub eax,ds:dword ptr[s]
|
||||
sub ebx,ds:dword ptr[t]
|
||||
mov ebp,eax
|
||||
mov edx,ebx
|
||||
jmp LSetEntryvec
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry2_8
|
||||
Spr8Entry2_8:
|
||||
sub edi,6 ; adjust for hardwired offsets
|
||||
sub ecx,12
|
||||
mov al,ds:byte ptr[esi]
|
||||
jmp LLEntry2_8
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry3_8
|
||||
Spr8Entry3_8:
|
||||
sub edi,5 ; adjust for hardwired offsets
|
||||
sub ecx,10
|
||||
jmp LLEntry3_8
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry4_8
|
||||
Spr8Entry4_8:
|
||||
sub edi,4 ; adjust for hardwired offsets
|
||||
sub ecx,8
|
||||
jmp LLEntry4_8
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry5_8
|
||||
Spr8Entry5_8:
|
||||
sub edi,3 ; adjust for hardwired offsets
|
||||
sub ecx,6
|
||||
jmp LLEntry5_8
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry6_8
|
||||
Spr8Entry6_8:
|
||||
sub edi,2 ; adjust for hardwired offsets
|
||||
sub ecx,4
|
||||
jmp LLEntry6_8
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry7_8
|
||||
Spr8Entry7_8:
|
||||
dec edi ; adjust for hardwired offsets
|
||||
sub ecx,2
|
||||
jmp LLEntry7_8
|
||||
|
||||
;----------------------------------------
|
||||
|
||||
public Spr8Entry8_8
|
||||
Spr8Entry8_8:
|
||||
cmp bp,ds:word ptr[ecx]
|
||||
jl Lp9
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp9
|
||||
mov ds:word ptr[ecx],bp
|
||||
mov ds:byte ptr[edi],al
|
||||
Lp9:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
LLEntry7_8:
|
||||
cmp bp,ds:word ptr[2+ecx]
|
||||
jl Lp10
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp10
|
||||
mov ds:word ptr[2+ecx],bp
|
||||
mov ds:byte ptr[1+edi],al
|
||||
Lp10:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
LLEntry6_8:
|
||||
cmp bp,ds:word ptr[4+ecx]
|
||||
jl Lp11
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp11
|
||||
mov ds:word ptr[4+ecx],bp
|
||||
mov ds:byte ptr[2+edi],al
|
||||
Lp11:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
LLEntry5_8:
|
||||
cmp bp,ds:word ptr[6+ecx]
|
||||
jl Lp12
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp12
|
||||
mov ds:word ptr[6+ecx],bp
|
||||
mov ds:byte ptr[3+edi],al
|
||||
Lp12:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
LLEntry4_8:
|
||||
cmp bp,ds:word ptr[8+ecx]
|
||||
jl Lp13
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp13
|
||||
mov ds:word ptr[8+ecx],bp
|
||||
mov ds:byte ptr[4+edi],al
|
||||
Lp13:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
LLEntry3_8:
|
||||
cmp bp,ds:word ptr[10+ecx]
|
||||
jl Lp14
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp14
|
||||
mov ds:word ptr[10+ecx],bp
|
||||
mov ds:byte ptr[5+edi],al
|
||||
Lp14:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
LLEntry2_8:
|
||||
cmp bp,ds:word ptr[12+ecx]
|
||||
jl Lp15
|
||||
mov al,ds:byte ptr[esi]
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp15
|
||||
mov ds:word ptr[12+ecx],bp
|
||||
mov ds:byte ptr[6+edi],al
|
||||
Lp15:
|
||||
add ebp,ds:dword ptr[izistep]
|
||||
adc ebp,0
|
||||
add edx,ds:dword ptr[tstep]
|
||||
sbb eax,eax
|
||||
add ebx,ds:dword ptr[sstep]
|
||||
adc esi,ds:dword ptr[advancetable+4+eax*4]
|
||||
|
||||
LEndSpan:
|
||||
cmp bp,ds:word ptr[14+ecx]
|
||||
jl Lp16
|
||||
mov al,ds:byte ptr[esi] ; load first texel in segment
|
||||
cmp al,offset TRANSPARENT_COLOR
|
||||
jz Lp16
|
||||
mov ds:word ptr[14+ecx],bp
|
||||
mov ds:byte ptr[7+edi],al
|
||||
Lp16:
|
||||
|
||||
;
|
||||
; clear s/z, t/z, 1/z from FP stack
|
||||
;
|
||||
fstp st(0)
|
||||
fstp st(0)
|
||||
fstp st(0)
|
||||
|
||||
pop ebx ; restore spans pointer
|
||||
LNextSpan:
|
||||
add ebx,offset sspan_t_size ; point to next span
|
||||
mov ecx,ds:dword ptr[sspan_t_count+ebx]
|
||||
cmp ecx,0 ; any more spans?
|
||||
jg LSpanLoop ; yes
|
||||
jz LNextSpan ; yes, but this one's empty
|
||||
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
ret
|
||||
|
||||
_TEXT ENDS
|
||||
endif ; id386
|
||||
END
|
||||
123
ref_soft/r_sprite.c
Normal file
123
ref_soft/r_sprite.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_sprite.c
|
||||
#include "r_local.h"
|
||||
|
||||
extern polydesc_t r_polydesc;
|
||||
|
||||
void R_BuildPolygonFromSurface(msurface_t *fa);
|
||||
void R_PolygonCalculateGradients (void);
|
||||
|
||||
extern void R_PolyChooseSpanletRoutine( float alpha, qboolean isturbulent );
|
||||
|
||||
extern vec5_t r_clip_verts[2][MAXWORKINGVERTS+2];
|
||||
|
||||
extern void R_ClipAndDrawPoly( float alpha, qboolean isturbulent, qboolean textured );
|
||||
|
||||
/*
|
||||
** R_DrawSprite
|
||||
**
|
||||
** Draw currententity / currentmodel as a single texture
|
||||
** mapped polygon
|
||||
*/
|
||||
void R_DrawSprite (void)
|
||||
{
|
||||
vec5_t *pverts;
|
||||
vec3_t left, up, right, down;
|
||||
dsprite_t *s_psprite;
|
||||
dsprframe_t *s_psprframe;
|
||||
|
||||
|
||||
s_psprite = (dsprite_t *)currentmodel->extradata;
|
||||
#if 0
|
||||
if (currententity->frame >= s_psprite->numframes
|
||||
|| currententity->frame < 0)
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "No such sprite frame %i\n",
|
||||
currententity->frame);
|
||||
currententity->frame = 0;
|
||||
}
|
||||
#endif
|
||||
currententity->frame %= s_psprite->numframes;
|
||||
|
||||
s_psprframe = &s_psprite->frames[currententity->frame];
|
||||
|
||||
r_polydesc.pixels = currentmodel->skins[currententity->frame]->pixels[0];
|
||||
r_polydesc.pixel_width = s_psprframe->width;
|
||||
r_polydesc.pixel_height = s_psprframe->height;
|
||||
r_polydesc.dist = 0;
|
||||
|
||||
// generate the sprite's axes, completely parallel to the viewplane.
|
||||
VectorCopy (vup, r_polydesc.vup);
|
||||
VectorCopy (vright, r_polydesc.vright);
|
||||
VectorCopy (vpn, r_polydesc.vpn);
|
||||
|
||||
// build the sprite poster in worldspace
|
||||
VectorScale (r_polydesc.vright,
|
||||
s_psprframe->width - s_psprframe->origin_x, right);
|
||||
VectorScale (r_polydesc.vup,
|
||||
s_psprframe->height - s_psprframe->origin_y, up);
|
||||
VectorScale (r_polydesc.vright,
|
||||
-s_psprframe->origin_x, left);
|
||||
VectorScale (r_polydesc.vup,
|
||||
-s_psprframe->origin_y, down);
|
||||
|
||||
// invert UP vector for sprites
|
||||
VectorInverse( r_polydesc.vup );
|
||||
|
||||
pverts = r_clip_verts[0];
|
||||
|
||||
pverts[0][0] = r_entorigin[0] + up[0] + left[0];
|
||||
pverts[0][1] = r_entorigin[1] + up[1] + left[1];
|
||||
pverts[0][2] = r_entorigin[2] + up[2] + left[2];
|
||||
pverts[0][3] = 0;
|
||||
pverts[0][4] = 0;
|
||||
|
||||
pverts[1][0] = r_entorigin[0] + up[0] + right[0];
|
||||
pverts[1][1] = r_entorigin[1] + up[1] + right[1];
|
||||
pverts[1][2] = r_entorigin[2] + up[2] + right[2];
|
||||
pverts[1][3] = s_psprframe->width;
|
||||
pverts[1][4] = 0;
|
||||
|
||||
pverts[2][0] = r_entorigin[0] + down[0] + right[0];
|
||||
pverts[2][1] = r_entorigin[1] + down[1] + right[1];
|
||||
pverts[2][2] = r_entorigin[2] + down[2] + right[2];
|
||||
pverts[2][3] = s_psprframe->width;
|
||||
pverts[2][4] = s_psprframe->height;
|
||||
|
||||
pverts[3][0] = r_entorigin[0] + down[0] + left[0];
|
||||
pverts[3][1] = r_entorigin[1] + down[1] + left[1];
|
||||
pverts[3][2] = r_entorigin[2] + down[2] + left[2];
|
||||
pverts[3][3] = 0;
|
||||
pverts[3][4] = s_psprframe->height;
|
||||
|
||||
r_polydesc.nump = 4;
|
||||
r_polydesc.s_offset = ( r_polydesc.pixel_width >> 1);
|
||||
r_polydesc.t_offset = ( r_polydesc.pixel_height >> 1);
|
||||
VectorCopy( modelorg, r_polydesc.viewer_position );
|
||||
|
||||
r_polydesc.stipple_parity = 1;
|
||||
if ( currententity->flags & RF_TRANSLUCENT )
|
||||
R_ClipAndDrawPoly ( currententity->alpha, false, true );
|
||||
else
|
||||
R_ClipAndDrawPoly ( 1.0F, false, true );
|
||||
r_polydesc.stipple_parity = 0;
|
||||
}
|
||||
|
||||
651
ref_soft/r_surf.c
Normal file
651
ref_soft/r_surf.c
Normal file
@@ -0,0 +1,651 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// r_surf.c: surface-related refresh code
|
||||
|
||||
#include "r_local.h"
|
||||
|
||||
drawsurf_t r_drawsurf;
|
||||
|
||||
int lightleft, sourcesstep, blocksize, sourcetstep;
|
||||
int lightdelta, lightdeltastep;
|
||||
int lightright, lightleftstep, lightrightstep, blockdivshift;
|
||||
unsigned blockdivmask;
|
||||
void *prowdestbase;
|
||||
unsigned char *pbasesource;
|
||||
int surfrowbytes; // used by ASM files
|
||||
unsigned *r_lightptr;
|
||||
int r_stepback;
|
||||
int r_lightwidth;
|
||||
int r_numhblocks, r_numvblocks;
|
||||
unsigned char *r_source, *r_sourcemax;
|
||||
|
||||
void R_DrawSurfaceBlock8_mip0 (void);
|
||||
void R_DrawSurfaceBlock8_mip1 (void);
|
||||
void R_DrawSurfaceBlock8_mip2 (void);
|
||||
void R_DrawSurfaceBlock8_mip3 (void);
|
||||
|
||||
static void (*surfmiptable[4])(void) = {
|
||||
R_DrawSurfaceBlock8_mip0,
|
||||
R_DrawSurfaceBlock8_mip1,
|
||||
R_DrawSurfaceBlock8_mip2,
|
||||
R_DrawSurfaceBlock8_mip3
|
||||
};
|
||||
|
||||
void R_BuildLightMap (void);
|
||||
extern unsigned blocklights[1024]; // allow some very large lightmaps
|
||||
|
||||
float surfscale;
|
||||
qboolean r_cache_thrash; // set if surface cache is thrashing
|
||||
|
||||
int sc_size;
|
||||
surfcache_t *sc_rover, *sc_base;
|
||||
|
||||
/*
|
||||
===============
|
||||
R_TextureAnimation
|
||||
|
||||
Returns the proper texture for a given time and base texture
|
||||
===============
|
||||
*/
|
||||
image_t *R_TextureAnimation (mtexinfo_t *tex)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (!tex->next)
|
||||
return tex->image;
|
||||
|
||||
c = currententity->frame % tex->numframes;
|
||||
while (c)
|
||||
{
|
||||
tex = tex->next;
|
||||
c--;
|
||||
}
|
||||
|
||||
return tex->image;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_DrawSurface
|
||||
===============
|
||||
*/
|
||||
void R_DrawSurface (void)
|
||||
{
|
||||
unsigned char *basetptr;
|
||||
int smax, tmax, twidth;
|
||||
int u;
|
||||
int soffset, basetoffset, texwidth;
|
||||
int horzblockstep;
|
||||
unsigned char *pcolumndest;
|
||||
void (*pblockdrawer)(void);
|
||||
image_t *mt;
|
||||
|
||||
surfrowbytes = r_drawsurf.rowbytes;
|
||||
|
||||
mt = r_drawsurf.image;
|
||||
|
||||
r_source = mt->pixels[r_drawsurf.surfmip];
|
||||
|
||||
// the fractional light values should range from 0 to (VID_GRADES - 1) << 16
|
||||
// from a source range of 0 - 255
|
||||
|
||||
texwidth = mt->width >> r_drawsurf.surfmip;
|
||||
|
||||
blocksize = 16 >> r_drawsurf.surfmip;
|
||||
blockdivshift = 4 - r_drawsurf.surfmip;
|
||||
blockdivmask = (1 << blockdivshift) - 1;
|
||||
|
||||
r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1;
|
||||
|
||||
r_numhblocks = r_drawsurf.surfwidth >> blockdivshift;
|
||||
r_numvblocks = r_drawsurf.surfheight >> blockdivshift;
|
||||
|
||||
//==============================
|
||||
|
||||
pblockdrawer = surfmiptable[r_drawsurf.surfmip];
|
||||
// TODO: only needs to be set when there is a display settings change
|
||||
horzblockstep = blocksize;
|
||||
|
||||
smax = mt->width >> r_drawsurf.surfmip;
|
||||
twidth = texwidth;
|
||||
tmax = mt->height >> r_drawsurf.surfmip;
|
||||
sourcetstep = texwidth;
|
||||
r_stepback = tmax * twidth;
|
||||
|
||||
r_sourcemax = r_source + (tmax * smax);
|
||||
|
||||
soffset = r_drawsurf.surf->texturemins[0];
|
||||
basetoffset = r_drawsurf.surf->texturemins[1];
|
||||
|
||||
// << 16 components are to guarantee positive values for %
|
||||
soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax;
|
||||
basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip)
|
||||
+ (tmax << 16)) % tmax) * twidth)];
|
||||
|
||||
pcolumndest = r_drawsurf.surfdat;
|
||||
|
||||
for (u=0 ; u<r_numhblocks; u++)
|
||||
{
|
||||
r_lightptr = blocklights + u;
|
||||
|
||||
prowdestbase = pcolumndest;
|
||||
|
||||
pbasesource = basetptr + soffset;
|
||||
|
||||
(*pblockdrawer)();
|
||||
|
||||
soffset = soffset + blocksize;
|
||||
if (soffset >= smax)
|
||||
soffset = 0;
|
||||
|
||||
pcolumndest += horzblockstep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#if !id386
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip0
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip0 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 4;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 4;
|
||||
|
||||
for (i=0 ; i<16 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 4;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=15; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid.colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip1
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip1 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 3;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 3;
|
||||
|
||||
for (i=0 ; i<8 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 3;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=7; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid.colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip2
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip2 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 2;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 2;
|
||||
|
||||
for (i=0 ; i<4 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 2;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=3; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid.colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_DrawSurfaceBlock8_mip3
|
||||
================
|
||||
*/
|
||||
void R_DrawSurfaceBlock8_mip3 (void)
|
||||
{
|
||||
int v, i, b, lightstep, lighttemp, light;
|
||||
unsigned char pix, *psource, *prowdest;
|
||||
|
||||
psource = pbasesource;
|
||||
prowdest = prowdestbase;
|
||||
|
||||
for (v=0 ; v<r_numvblocks ; v++)
|
||||
{
|
||||
// FIXME: make these locals?
|
||||
// FIXME: use delta rather than both right and left, like ASM?
|
||||
lightleft = r_lightptr[0];
|
||||
lightright = r_lightptr[1];
|
||||
r_lightptr += r_lightwidth;
|
||||
lightleftstep = (r_lightptr[0] - lightleft) >> 1;
|
||||
lightrightstep = (r_lightptr[1] - lightright) >> 1;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
lighttemp = lightleft - lightright;
|
||||
lightstep = lighttemp >> 1;
|
||||
|
||||
light = lightright;
|
||||
|
||||
for (b=1; b>=0; b--)
|
||||
{
|
||||
pix = psource[b];
|
||||
prowdest[b] = ((unsigned char *)vid.colormap)
|
||||
[(light & 0xFF00) + pix];
|
||||
light += lightstep;
|
||||
}
|
||||
|
||||
psource += sourcetstep;
|
||||
lightright += lightrightstep;
|
||||
lightleft += lightleftstep;
|
||||
prowdest += surfrowbytes;
|
||||
}
|
||||
|
||||
if (psource >= r_sourcemax)
|
||||
psource -= r_stepback;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
R_InitCaches
|
||||
|
||||
================
|
||||
*/
|
||||
void R_InitCaches (void)
|
||||
{
|
||||
int size;
|
||||
int pix;
|
||||
|
||||
// calculate size to allocate
|
||||
if (sw_surfcacheoverride->value)
|
||||
{
|
||||
size = sw_surfcacheoverride->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = SURFCACHE_SIZE_AT_320X240;
|
||||
|
||||
pix = vid.width*vid.height;
|
||||
if (pix > 64000)
|
||||
size += (pix-64000)*3;
|
||||
}
|
||||
|
||||
// round up to page size
|
||||
size = (size + 8191) & ~8191;
|
||||
|
||||
ri.Con_Printf (PRINT_ALL,"%ik surface cache\n", size/1024);
|
||||
|
||||
sc_size = size;
|
||||
sc_base = (surfcache_t *)malloc(size);
|
||||
sc_rover = sc_base;
|
||||
|
||||
sc_base->next = NULL;
|
||||
sc_base->owner = NULL;
|
||||
sc_base->size = sc_size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
D_FlushCaches
|
||||
==================
|
||||
*/
|
||||
void D_FlushCaches (void)
|
||||
{
|
||||
surfcache_t *c;
|
||||
|
||||
if (!sc_base)
|
||||
return;
|
||||
|
||||
for (c = sc_base ; c ; c = c->next)
|
||||
{
|
||||
if (c->owner)
|
||||
*c->owner = NULL;
|
||||
}
|
||||
|
||||
sc_rover = sc_base;
|
||||
sc_base->next = NULL;
|
||||
sc_base->owner = NULL;
|
||||
sc_base->size = sc_size;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
D_SCAlloc
|
||||
=================
|
||||
*/
|
||||
surfcache_t *D_SCAlloc (int width, int size)
|
||||
{
|
||||
surfcache_t *new;
|
||||
qboolean wrapped_this_time;
|
||||
|
||||
if ((width < 0) || (width > 256))
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache width %d\n", width);
|
||||
|
||||
if ((size <= 0) || (size > 0x10000))
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: bad cache size %d\n", size);
|
||||
|
||||
size = (int)&((surfcache_t *)0)->data[size];
|
||||
size = (size + 3) & ~3;
|
||||
if (size > sc_size)
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: %i > cache size of %i",size, sc_size);
|
||||
|
||||
// if there is not size bytes after the rover, reset to the start
|
||||
wrapped_this_time = false;
|
||||
|
||||
if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size)
|
||||
{
|
||||
if (sc_rover)
|
||||
{
|
||||
wrapped_this_time = true;
|
||||
}
|
||||
sc_rover = sc_base;
|
||||
}
|
||||
|
||||
// colect and free surfcache_t blocks until the rover block is large enough
|
||||
new = sc_rover;
|
||||
if (sc_rover->owner)
|
||||
*sc_rover->owner = NULL;
|
||||
|
||||
while (new->size < size)
|
||||
{
|
||||
// free another
|
||||
sc_rover = sc_rover->next;
|
||||
if (!sc_rover)
|
||||
ri.Sys_Error (ERR_FATAL,"D_SCAlloc: hit the end of memory");
|
||||
if (sc_rover->owner)
|
||||
*sc_rover->owner = NULL;
|
||||
|
||||
new->size += sc_rover->size;
|
||||
new->next = sc_rover->next;
|
||||
}
|
||||
|
||||
// create a fragment out of any leftovers
|
||||
if (new->size - size > 256)
|
||||
{
|
||||
sc_rover = (surfcache_t *)( (byte *)new + size);
|
||||
sc_rover->size = new->size - size;
|
||||
sc_rover->next = new->next;
|
||||
sc_rover->width = 0;
|
||||
sc_rover->owner = NULL;
|
||||
new->next = sc_rover;
|
||||
new->size = size;
|
||||
}
|
||||
else
|
||||
sc_rover = new->next;
|
||||
|
||||
new->width = width;
|
||||
// DEBUG
|
||||
if (width > 0)
|
||||
new->height = (size - sizeof(*new) + sizeof(new->data)) / width;
|
||||
|
||||
new->owner = NULL; // should be set properly after return
|
||||
|
||||
if (d_roverwrapped)
|
||||
{
|
||||
if (wrapped_this_time || (sc_rover >= d_initial_rover))
|
||||
r_cache_thrash = true;
|
||||
}
|
||||
else if (wrapped_this_time)
|
||||
{
|
||||
d_roverwrapped = true;
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
D_SCDump
|
||||
=================
|
||||
*/
|
||||
void D_SCDump (void)
|
||||
{
|
||||
surfcache_t *test;
|
||||
|
||||
for (test = sc_base ; test ; test = test->next)
|
||||
{
|
||||
if (test == sc_rover)
|
||||
ri.Con_Printf (PRINT_ALL,"ROVER:\n");
|
||||
ri.Con_Printf (PRINT_ALL,"%p : %i bytes %i width\n",test, test->size, test->width);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// if the num is not a power of 2, assume it will not repeat
|
||||
|
||||
int MaskForNum (int num)
|
||||
{
|
||||
if (num==128)
|
||||
return 127;
|
||||
if (num==64)
|
||||
return 63;
|
||||
if (num==32)
|
||||
return 31;
|
||||
if (num==16)
|
||||
return 15;
|
||||
return 255;
|
||||
}
|
||||
|
||||
int D_log2 (int num)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = 0;
|
||||
|
||||
while (num>>=1)
|
||||
c++;
|
||||
return c;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
================
|
||||
D_CacheSurface
|
||||
================
|
||||
*/
|
||||
surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel)
|
||||
{
|
||||
surfcache_t *cache;
|
||||
|
||||
//
|
||||
// if the surface is animating or flashing, flush the cache
|
||||
//
|
||||
r_drawsurf.image = R_TextureAnimation (surface->texinfo);
|
||||
r_drawsurf.lightadj[0] = r_newrefdef.lightstyles[surface->styles[0]].white*128;
|
||||
r_drawsurf.lightadj[1] = r_newrefdef.lightstyles[surface->styles[1]].white*128;
|
||||
r_drawsurf.lightadj[2] = r_newrefdef.lightstyles[surface->styles[2]].white*128;
|
||||
r_drawsurf.lightadj[3] = r_newrefdef.lightstyles[surface->styles[3]].white*128;
|
||||
|
||||
//
|
||||
// see if the cache holds apropriate data
|
||||
//
|
||||
cache = surface->cachespots[miplevel];
|
||||
|
||||
if (cache && !cache->dlight && surface->dlightframe != r_framecount
|
||||
&& cache->image == r_drawsurf.image
|
||||
&& cache->lightadj[0] == r_drawsurf.lightadj[0]
|
||||
&& cache->lightadj[1] == r_drawsurf.lightadj[1]
|
||||
&& cache->lightadj[2] == r_drawsurf.lightadj[2]
|
||||
&& cache->lightadj[3] == r_drawsurf.lightadj[3] )
|
||||
return cache;
|
||||
|
||||
//
|
||||
// determine shape of surface
|
||||
//
|
||||
surfscale = 1.0 / (1<<miplevel);
|
||||
r_drawsurf.surfmip = miplevel;
|
||||
r_drawsurf.surfwidth = surface->extents[0] >> miplevel;
|
||||
r_drawsurf.rowbytes = r_drawsurf.surfwidth;
|
||||
r_drawsurf.surfheight = surface->extents[1] >> miplevel;
|
||||
|
||||
//
|
||||
// allocate memory if needed
|
||||
//
|
||||
if (!cache) // if a texture just animated, don't reallocate it
|
||||
{
|
||||
cache = D_SCAlloc (r_drawsurf.surfwidth,
|
||||
r_drawsurf.surfwidth * r_drawsurf.surfheight);
|
||||
surface->cachespots[miplevel] = cache;
|
||||
cache->owner = &surface->cachespots[miplevel];
|
||||
cache->mipscale = surfscale;
|
||||
}
|
||||
|
||||
if (surface->dlightframe == r_framecount)
|
||||
cache->dlight = 1;
|
||||
else
|
||||
cache->dlight = 0;
|
||||
|
||||
r_drawsurf.surfdat = (pixel_t *)cache->data;
|
||||
|
||||
cache->image = r_drawsurf.image;
|
||||
cache->lightadj[0] = r_drawsurf.lightadj[0];
|
||||
cache->lightadj[1] = r_drawsurf.lightadj[1];
|
||||
cache->lightadj[2] = r_drawsurf.lightadj[2];
|
||||
cache->lightadj[3] = r_drawsurf.lightadj[3];
|
||||
|
||||
//
|
||||
// draw and light the surface texture
|
||||
//
|
||||
r_drawsurf.surf = surface;
|
||||
|
||||
c_surf++;
|
||||
|
||||
// calculate the lightings
|
||||
R_BuildLightMap ();
|
||||
|
||||
// rasterize the surface into the cache
|
||||
R_DrawSurface ();
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
771
ref_soft/r_surf8.asm
Normal file
771
ref_soft/r_surf8.asm
Normal file
@@ -0,0 +1,771 @@
|
||||
.386P
|
||||
.model FLAT
|
||||
;
|
||||
; surf8.s
|
||||
; x86 assembly-language 8 bpp surface block drawing code.
|
||||
;
|
||||
|
||||
include qasm.inc
|
||||
|
||||
if id386
|
||||
|
||||
_DATA SEGMENT
|
||||
|
||||
sb_v dd 0
|
||||
|
||||
_DATA ENDS
|
||||
_TEXT SEGMENT
|
||||
|
||||
align 4
|
||||
public _R_Surf8Start
|
||||
_R_Surf8Start:
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; Surface block drawer for mip level 0
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
align 4
|
||||
public _R_DrawSurfaceBlock8_mip0
|
||||
_R_DrawSurfaceBlock8_mip0:
|
||||
push ebp ; preserve caller's stack frame
|
||||
push edi
|
||||
push esi ; preserve register variables
|
||||
push ebx
|
||||
|
||||
; for (v=0 ; v<numvblocks ; v++)
|
||||
; {
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
mov eax,ds:dword ptr[_r_numvblocks]
|
||||
|
||||
mov ds:dword ptr[sb_v],eax
|
||||
mov edi,ds:dword ptr[_prowdestbase]
|
||||
|
||||
mov esi,ds:dword ptr[_pbasesource]
|
||||
|
||||
Lv_loop_mip0:
|
||||
|
||||
; lightleft = lightptr[0];
|
||||
; lightright = lightptr[1];
|
||||
; lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
mov eax,ds:dword ptr[ebx] ; lightleft
|
||||
mov edx,ds:dword ptr[4+ebx] ; lightright
|
||||
|
||||
mov ebp,eax
|
||||
mov ecx,ds:dword ptr[_r_lightwidth]
|
||||
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
sub ebp,edx
|
||||
|
||||
and ebp,0FFFFFh
|
||||
lea ebx,ds:dword ptr[ebx+ecx*4]
|
||||
|
||||
; lightptr += lightwidth;
|
||||
mov ds:dword ptr[_r_lightptr],ebx
|
||||
|
||||
; lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
; lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
; lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
; 0xF0000000;
|
||||
mov ecx,ds:dword ptr[4+ebx] ; lightptr[1]
|
||||
mov ebx,ds:dword ptr[ebx] ; lightptr[0]
|
||||
|
||||
sub ebx,eax
|
||||
sub ecx,edx
|
||||
|
||||
sar ecx,4
|
||||
or ebp,0F0000000h
|
||||
|
||||
sar ebx,4
|
||||
mov ds:dword ptr[_lightrightstep],ecx
|
||||
|
||||
sub ebx,ecx
|
||||
and ebx,0FFFFFh
|
||||
|
||||
or ebx,0F0000000h
|
||||
sub ecx,ecx ; high word must be 0 in loop for addressing
|
||||
|
||||
mov ds:dword ptr[_lightdeltastep],ebx
|
||||
sub ebx,ebx ; high word must be 0 in loop for addressing
|
||||
|
||||
Lblockloop8_mip0:
|
||||
mov ds:dword ptr[_lightdelta],ebp
|
||||
mov cl,ds:byte ptr[14+esi]
|
||||
|
||||
sar ebp,4
|
||||
mov bh,dh
|
||||
|
||||
mov bl,ds:byte ptr[15+esi]
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch0:
|
||||
mov bl,ds:byte ptr[13+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch1:
|
||||
mov cl,ds:byte ptr[12+esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
add edx,ebp
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch2:
|
||||
|
||||
mov bl,ds:byte ptr[11+esi]
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch3:
|
||||
|
||||
mov cl,ds:byte ptr[10+esi]
|
||||
mov ds:dword ptr[12+edi],eax
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch4:
|
||||
mov bl,ds:byte ptr[9+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch5:
|
||||
mov cl,ds:byte ptr[8+esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
add edx,ebp
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch6:
|
||||
|
||||
mov bl,ds:byte ptr[7+esi]
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch7:
|
||||
|
||||
mov cl,ds:byte ptr[6+esi]
|
||||
mov ds:dword ptr[8+edi],eax
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch8:
|
||||
mov bl,ds:byte ptr[5+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch9:
|
||||
mov cl,ds:byte ptr[4+esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
add edx,ebp
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch10:
|
||||
|
||||
mov bl,ds:byte ptr[3+esi]
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch11:
|
||||
|
||||
mov cl,ds:byte ptr[2+esi]
|
||||
mov ds:dword ptr[4+edi],eax
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch12:
|
||||
mov bl,ds:byte ptr[1+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch13:
|
||||
mov cl,ds:byte ptr[esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch14:
|
||||
mov edx,ds:dword ptr[_lightright]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch15:
|
||||
mov ebp,ds:dword ptr[_lightdelta]
|
||||
|
||||
mov ds:dword ptr[edi],eax
|
||||
|
||||
add esi,ds:dword ptr[_sourcetstep]
|
||||
add edi,ds:dword ptr[_surfrowbytes]
|
||||
|
||||
add edx,ds:dword ptr[_lightrightstep]
|
||||
add ebp,ds:dword ptr[_lightdeltastep]
|
||||
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
jc Lblockloop8_mip0
|
||||
|
||||
; if (pbasesource >= r_sourcemax)
|
||||
; pbasesource -= stepback;
|
||||
|
||||
cmp esi,ds:dword ptr[_r_sourcemax]
|
||||
jb LSkip_mip0
|
||||
sub esi,ds:dword ptr[_r_stepback]
|
||||
LSkip_mip0:
|
||||
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
dec ds:dword ptr[sb_v]
|
||||
|
||||
jnz Lv_loop_mip0
|
||||
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; Surface block drawer for mip level 1
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
align 4
|
||||
public _R_DrawSurfaceBlock8_mip1
|
||||
_R_DrawSurfaceBlock8_mip1:
|
||||
push ebp ; preserve caller's stack frame
|
||||
push edi
|
||||
push esi ; preserve register variables
|
||||
push ebx
|
||||
|
||||
; for (v=0 ; v<numvblocks ; v++)
|
||||
; {
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
mov eax,ds:dword ptr[_r_numvblocks]
|
||||
|
||||
mov ds:dword ptr[sb_v],eax
|
||||
mov edi,ds:dword ptr[_prowdestbase]
|
||||
|
||||
mov esi,ds:dword ptr[_pbasesource]
|
||||
|
||||
Lv_loop_mip1:
|
||||
|
||||
; lightleft = lightptr[0];
|
||||
; lightright = lightptr[1];
|
||||
; lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
mov eax,ds:dword ptr[ebx] ; lightleft
|
||||
mov edx,ds:dword ptr[4+ebx] ; lightright
|
||||
|
||||
mov ebp,eax
|
||||
mov ecx,ds:dword ptr[_r_lightwidth]
|
||||
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
sub ebp,edx
|
||||
|
||||
and ebp,0FFFFFh
|
||||
lea ebx,ds:dword ptr[ebx+ecx*4]
|
||||
|
||||
; lightptr += lightwidth;
|
||||
mov ds:dword ptr[_r_lightptr],ebx
|
||||
|
||||
; lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
; lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
; lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
; 0xF0000000;
|
||||
mov ecx,ds:dword ptr[4+ebx] ; lightptr[1]
|
||||
mov ebx,ds:dword ptr[ebx] ; lightptr[0]
|
||||
|
||||
sub ebx,eax
|
||||
sub ecx,edx
|
||||
|
||||
sar ecx,3
|
||||
or ebp,070000000h
|
||||
|
||||
sar ebx,3
|
||||
mov ds:dword ptr[_lightrightstep],ecx
|
||||
|
||||
sub ebx,ecx
|
||||
and ebx,0FFFFFh
|
||||
|
||||
or ebx,0F0000000h
|
||||
sub ecx,ecx ; high word must be 0 in loop for addressing
|
||||
|
||||
mov ds:dword ptr[_lightdeltastep],ebx
|
||||
sub ebx,ebx ; high word must be 0 in loop for addressing
|
||||
|
||||
Lblockloop8_mip1:
|
||||
mov ds:dword ptr[_lightdelta],ebp
|
||||
mov cl,ds:byte ptr[6+esi]
|
||||
|
||||
sar ebp,3
|
||||
mov bh,dh
|
||||
|
||||
mov bl,ds:byte ptr[7+esi]
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch22:
|
||||
mov bl,ds:byte ptr[5+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch23:
|
||||
mov cl,ds:byte ptr[4+esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
add edx,ebp
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch24:
|
||||
|
||||
mov bl,ds:byte ptr[3+esi]
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch25:
|
||||
|
||||
mov cl,ds:byte ptr[2+esi]
|
||||
mov ds:dword ptr[4+edi],eax
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch26:
|
||||
mov bl,ds:byte ptr[1+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch27:
|
||||
mov cl,ds:byte ptr[esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch28:
|
||||
mov edx,ds:dword ptr[_lightright]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch29:
|
||||
mov ebp,ds:dword ptr[_lightdelta]
|
||||
|
||||
mov ds:dword ptr[edi],eax
|
||||
mov eax,ds:dword ptr[_sourcetstep]
|
||||
|
||||
add esi,eax
|
||||
mov eax,ds:dword ptr[_surfrowbytes]
|
||||
|
||||
add edi,eax
|
||||
mov eax,ds:dword ptr[_lightrightstep]
|
||||
|
||||
add edx,eax
|
||||
mov eax,ds:dword ptr[_lightdeltastep]
|
||||
|
||||
add ebp,eax
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
|
||||
jc Lblockloop8_mip1
|
||||
|
||||
; if (pbasesource >= r_sourcemax)
|
||||
; pbasesource -= stepback;
|
||||
|
||||
cmp esi,ds:dword ptr[_r_sourcemax]
|
||||
jb LSkip_mip1
|
||||
sub esi,ds:dword ptr[_r_stepback]
|
||||
LSkip_mip1:
|
||||
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
dec ds:dword ptr[sb_v]
|
||||
|
||||
jnz Lv_loop_mip1
|
||||
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; Surface block drawer for mip level 2
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
align 4
|
||||
public _R_DrawSurfaceBlock8_mip2
|
||||
_R_DrawSurfaceBlock8_mip2:
|
||||
push ebp ; preserve caller's stack frame
|
||||
push edi
|
||||
push esi ; preserve register variables
|
||||
push ebx
|
||||
|
||||
; for (v=0 ; v<numvblocks ; v++)
|
||||
; {
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
mov eax,ds:dword ptr[_r_numvblocks]
|
||||
|
||||
mov ds:dword ptr[sb_v],eax
|
||||
mov edi,ds:dword ptr[_prowdestbase]
|
||||
|
||||
mov esi,ds:dword ptr[_pbasesource]
|
||||
|
||||
Lv_loop_mip2:
|
||||
|
||||
; lightleft = lightptr[0];
|
||||
; lightright = lightptr[1];
|
||||
; lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
mov eax,ds:dword ptr[ebx] ; lightleft
|
||||
mov edx,ds:dword ptr[4+ebx] ; lightright
|
||||
|
||||
mov ebp,eax
|
||||
mov ecx,ds:dword ptr[_r_lightwidth]
|
||||
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
sub ebp,edx
|
||||
|
||||
and ebp,0FFFFFh
|
||||
lea ebx,ds:dword ptr[ebx+ecx*4]
|
||||
|
||||
; lightptr += lightwidth;
|
||||
mov ds:dword ptr[_r_lightptr],ebx
|
||||
|
||||
; lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
; lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
; lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
; 0xF0000000;
|
||||
mov ecx,ds:dword ptr[4+ebx] ; lightptr[1]
|
||||
mov ebx,ds:dword ptr[ebx] ; lightptr[0]
|
||||
|
||||
sub ebx,eax
|
||||
sub ecx,edx
|
||||
|
||||
sar ecx,2
|
||||
or ebp,030000000h
|
||||
|
||||
sar ebx,2
|
||||
mov ds:dword ptr[_lightrightstep],ecx
|
||||
|
||||
sub ebx,ecx
|
||||
|
||||
and ebx,0FFFFFh
|
||||
|
||||
or ebx,0F0000000h
|
||||
sub ecx,ecx ; high word must be 0 in loop for addressing
|
||||
|
||||
mov ds:dword ptr[_lightdeltastep],ebx
|
||||
sub ebx,ebx ; high word must be 0 in loop for addressing
|
||||
|
||||
Lblockloop8_mip2:
|
||||
mov ds:dword ptr[_lightdelta],ebp
|
||||
mov cl,ds:byte ptr[2+esi]
|
||||
|
||||
sar ebp,2
|
||||
mov bh,dh
|
||||
|
||||
mov bl,ds:byte ptr[3+esi]
|
||||
add edx,ebp
|
||||
|
||||
mov ch,dh
|
||||
add edx,ebp
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch18:
|
||||
mov bl,ds:byte ptr[1+esi]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch19:
|
||||
mov cl,ds:byte ptr[esi]
|
||||
|
||||
mov bh,dh
|
||||
add edx,ebp
|
||||
|
||||
ror eax,16
|
||||
mov ch,dh
|
||||
|
||||
mov ah,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch20:
|
||||
mov edx,ds:dword ptr[_lightright]
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch21:
|
||||
mov ebp,ds:dword ptr[_lightdelta]
|
||||
|
||||
mov ds:dword ptr[edi],eax
|
||||
mov eax,ds:dword ptr[_sourcetstep]
|
||||
|
||||
add esi,eax
|
||||
mov eax,ds:dword ptr[_surfrowbytes]
|
||||
|
||||
add edi,eax
|
||||
mov eax,ds:dword ptr[_lightrightstep]
|
||||
|
||||
add edx,eax
|
||||
mov eax,ds:dword ptr[_lightdeltastep]
|
||||
|
||||
add ebp,eax
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
|
||||
jc Lblockloop8_mip2
|
||||
|
||||
; if (pbasesource >= r_sourcemax)
|
||||
; pbasesource -= stepback;
|
||||
|
||||
cmp esi,ds:dword ptr[_r_sourcemax]
|
||||
jb LSkip_mip2
|
||||
sub esi,ds:dword ptr[_r_stepback]
|
||||
LSkip_mip2:
|
||||
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
dec ds:dword ptr[sb_v]
|
||||
|
||||
jnz Lv_loop_mip2
|
||||
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; Surface block drawer for mip level 3
|
||||
;----------------------------------------------------------------------
|
||||
|
||||
align 4
|
||||
public _R_DrawSurfaceBlock8_mip3
|
||||
_R_DrawSurfaceBlock8_mip3:
|
||||
push ebp ; preserve caller's stack frame
|
||||
push edi
|
||||
push esi ; preserve register variables
|
||||
push ebx
|
||||
|
||||
; for (v=0 ; v<numvblocks ; v++)
|
||||
; {
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
mov eax,ds:dword ptr[_r_numvblocks]
|
||||
|
||||
mov ds:dword ptr[sb_v],eax
|
||||
mov edi,ds:dword ptr[_prowdestbase]
|
||||
|
||||
mov esi,ds:dword ptr[_pbasesource]
|
||||
|
||||
Lv_loop_mip3:
|
||||
|
||||
; lightleft = lightptr[0];
|
||||
; lightright = lightptr[1];
|
||||
; lightdelta = (lightleft - lightright) & 0xFFFFF;
|
||||
mov eax,ds:dword ptr[ebx] ; lightleft
|
||||
mov edx,ds:dword ptr[4+ebx] ; lightright
|
||||
|
||||
mov ebp,eax
|
||||
mov ecx,ds:dword ptr[_r_lightwidth]
|
||||
|
||||
mov ds:dword ptr[_lightright],edx
|
||||
sub ebp,edx
|
||||
|
||||
and ebp,0FFFFFh
|
||||
lea ebx,ds:dword ptr[ebx+ecx*4]
|
||||
|
||||
mov ds:dword ptr[_lightdelta],ebp
|
||||
; lightptr += lightwidth;
|
||||
mov ds:dword ptr[_r_lightptr],ebx
|
||||
|
||||
; lightleftstep = (lightptr[0] - lightleft) >> blockdivshift;
|
||||
; lightrightstep = (lightptr[1] - lightright) >> blockdivshift;
|
||||
; lightdeltastep = ((lightleftstep - lightrightstep) & 0xFFFFF) |
|
||||
; 0xF0000000;
|
||||
mov ecx,ds:dword ptr[4+ebx] ; lightptr[1]
|
||||
mov ebx,ds:dword ptr[ebx] ; lightptr[0]
|
||||
|
||||
sub ebx,eax
|
||||
sub ecx,edx
|
||||
|
||||
sar ecx,1
|
||||
|
||||
sar ebx,1
|
||||
mov ds:dword ptr[_lightrightstep],ecx
|
||||
|
||||
sub ebx,ecx
|
||||
and ebx,0FFFFFh
|
||||
|
||||
sar ebp,1
|
||||
or ebx,0F0000000h
|
||||
|
||||
mov ds:dword ptr[_lightdeltastep],ebx
|
||||
sub ebx,ebx ; high word must be 0 in loop for addressing
|
||||
|
||||
mov bl,ds:byte ptr[1+esi]
|
||||
sub ecx,ecx ; high word must be 0 in loop for addressing
|
||||
|
||||
mov bh,dh
|
||||
mov cl,ds:byte ptr[esi]
|
||||
|
||||
add edx,ebp
|
||||
mov ch,dh
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch16:
|
||||
mov edx,ds:dword ptr[_lightright]
|
||||
|
||||
mov ds:byte ptr[1+edi],al
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch17:
|
||||
|
||||
mov ds:byte ptr[edi],al
|
||||
mov eax,ds:dword ptr[_sourcetstep]
|
||||
|
||||
add esi,eax
|
||||
mov eax,ds:dword ptr[_surfrowbytes]
|
||||
|
||||
add edi,eax
|
||||
mov eax,ds:dword ptr[_lightdeltastep]
|
||||
|
||||
mov ebp,ds:dword ptr[_lightdelta]
|
||||
mov cl,ds:byte ptr[esi]
|
||||
|
||||
add ebp,eax
|
||||
mov eax,ds:dword ptr[_lightrightstep]
|
||||
|
||||
sar ebp,1
|
||||
add edx,eax
|
||||
|
||||
mov bh,dh
|
||||
mov bl,ds:byte ptr[1+esi]
|
||||
|
||||
add edx,ebp
|
||||
mov ch,dh
|
||||
|
||||
mov al,ds:byte ptr[12345678h+ebx]
|
||||
LBPatch30:
|
||||
mov edx,ds:dword ptr[_sourcetstep]
|
||||
|
||||
mov ds:byte ptr[1+edi],al
|
||||
mov al,ds:byte ptr[12345678h+ecx]
|
||||
LBPatch31:
|
||||
|
||||
mov ds:byte ptr[edi],al
|
||||
mov ebp,ds:dword ptr[_surfrowbytes]
|
||||
|
||||
add esi,edx
|
||||
add edi,ebp
|
||||
|
||||
; if (pbasesource >= r_sourcemax)
|
||||
; pbasesource -= stepback;
|
||||
|
||||
cmp esi,ds:dword ptr[_r_sourcemax]
|
||||
jb LSkip_mip3
|
||||
sub esi,ds:dword ptr[_r_stepback]
|
||||
LSkip_mip3:
|
||||
|
||||
mov ebx,ds:dword ptr[_r_lightptr]
|
||||
dec ds:dword ptr[sb_v]
|
||||
|
||||
jnz Lv_loop_mip3
|
||||
|
||||
pop ebx ; restore register variables
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebp ; restore the caller's stack frame
|
||||
ret
|
||||
|
||||
|
||||
public _R_Surf8End
|
||||
_R_Surf8End:
|
||||
|
||||
;----------------------------------------------------------------------
|
||||
; Code patching routines
|
||||
;----------------------------------------------------------------------
|
||||
_TEXT ENDS
|
||||
_DATA SEGMENT
|
||||
|
||||
align 4
|
||||
LPatchTable8:
|
||||
dd LBPatch0-4
|
||||
dd LBPatch1-4
|
||||
dd LBPatch2-4
|
||||
dd LBPatch3-4
|
||||
dd LBPatch4-4
|
||||
dd LBPatch5-4
|
||||
dd LBPatch6-4
|
||||
dd LBPatch7-4
|
||||
dd LBPatch8-4
|
||||
dd LBPatch9-4
|
||||
dd LBPatch10-4
|
||||
dd LBPatch11-4
|
||||
dd LBPatch12-4
|
||||
dd LBPatch13-4
|
||||
dd LBPatch14-4
|
||||
dd LBPatch15-4
|
||||
dd LBPatch16-4
|
||||
dd LBPatch17-4
|
||||
dd LBPatch18-4
|
||||
dd LBPatch19-4
|
||||
dd LBPatch20-4
|
||||
dd LBPatch21-4
|
||||
dd LBPatch22-4
|
||||
dd LBPatch23-4
|
||||
dd LBPatch24-4
|
||||
dd LBPatch25-4
|
||||
dd LBPatch26-4
|
||||
dd LBPatch27-4
|
||||
dd LBPatch28-4
|
||||
dd LBPatch29-4
|
||||
dd LBPatch30-4
|
||||
dd LBPatch31-4
|
||||
|
||||
_DATA ENDS
|
||||
_TEXT SEGMENT
|
||||
|
||||
align 4
|
||||
public _R_Surf8Patch
|
||||
_R_Surf8Patch:
|
||||
push ebx
|
||||
|
||||
mov eax,ds:dword ptr[_colormap]
|
||||
mov ebx,offset LPatchTable8
|
||||
mov ecx,32
|
||||
LPatchLoop8:
|
||||
mov edx,ds:dword ptr[ebx]
|
||||
add ebx,4
|
||||
mov ds:dword ptr[edx],eax
|
||||
dec ecx
|
||||
jnz LPatchLoop8
|
||||
|
||||
pop ebx
|
||||
|
||||
ret
|
||||
|
||||
_TEXT ENDS
|
||||
endif ;id386
|
||||
|
||||
END
|
||||
|
||||
220
ref_soft/r_varsa.asm
Normal file
220
ref_soft/r_varsa.asm
Normal file
@@ -0,0 +1,220 @@
|
||||
.386P
|
||||
.model FLAT
|
||||
;
|
||||
; d_varsa.s
|
||||
;
|
||||
|
||||
include qasm.inc
|
||||
include d_if.inc
|
||||
|
||||
if id386
|
||||
|
||||
_DATA SEGMENT
|
||||
|
||||
;-------------------------------------------------------
|
||||
; ASM-only variables
|
||||
;-------------------------------------------------------
|
||||
public float_1, float_particle_z_clip, float_point5
|
||||
public float_minus_1, float_0
|
||||
float_0 dd 0.0
|
||||
float_1 dd 1.0
|
||||
float_minus_1 dd -1.0
|
||||
float_particle_z_clip dd PARTICLE_Z_CLIP
|
||||
float_point5 dd 0.5
|
||||
|
||||
public fp_16, fp_64k, fp_1m, fp_64kx64k
|
||||
public fp_1m_minus_1
|
||||
public fp_8
|
||||
fp_1m dd 1048576.0
|
||||
fp_1m_minus_1 dd 1048575.0
|
||||
fp_64k dd 65536.0
|
||||
fp_8 dd 8.0
|
||||
fp_16 dd 16.0
|
||||
fp_64kx64k dd 04f000000h ; (float)0x8000*0x10000
|
||||
|
||||
|
||||
public FloatZero, Float2ToThe31nd, FloatMinus2ToThe31nd
|
||||
FloatZero dd 0
|
||||
Float2ToThe31nd dd 04f000000h
|
||||
FloatMinus2ToThe31nd dd 0cf000000h
|
||||
|
||||
public _r_bmodelactive
|
||||
_r_bmodelactive dd 0
|
||||
|
||||
|
||||
;-------------------------------------------------------
|
||||
; global refresh variables
|
||||
;-------------------------------------------------------
|
||||
|
||||
; FIXME: put all refresh variables into one contiguous block. Make into one
|
||||
; big structure, like cl or sv?
|
||||
|
||||
align 4
|
||||
public _d_sdivzstepu
|
||||
public _d_tdivzstepu
|
||||
public _d_zistepu
|
||||
public _d_sdivzstepv
|
||||
public _d_tdivzstepv
|
||||
public _d_zistepv
|
||||
public _d_sdivzorigin
|
||||
public _d_tdivzorigin
|
||||
public _d_ziorigin
|
||||
_d_sdivzstepu dd 0
|
||||
_d_tdivzstepu dd 0
|
||||
_d_zistepu dd 0
|
||||
_d_sdivzstepv dd 0
|
||||
_d_tdivzstepv dd 0
|
||||
_d_zistepv dd 0
|
||||
_d_sdivzorigin dd 0
|
||||
_d_tdivzorigin dd 0
|
||||
_d_ziorigin dd 0
|
||||
|
||||
public _sadjust
|
||||
public _tadjust
|
||||
public _bbextents
|
||||
public _bbextentt
|
||||
_sadjust dd 0
|
||||
_tadjust dd 0
|
||||
_bbextents dd 0
|
||||
_bbextentt dd 0
|
||||
|
||||
public _cacheblock
|
||||
public _d_viewbuffer
|
||||
public _cachewidth
|
||||
public _d_pzbuffer
|
||||
public _d_zrowbytes
|
||||
public _d_zwidth
|
||||
_cacheblock dd 0
|
||||
_cachewidth dd 0
|
||||
_d_viewbuffer dd 0
|
||||
_d_pzbuffer dd 0
|
||||
_d_zrowbytes dd 0
|
||||
_d_zwidth dd 0
|
||||
|
||||
|
||||
;-------------------------------------------------------
|
||||
; ASM-only variables
|
||||
;-------------------------------------------------------
|
||||
public izi
|
||||
izi dd 0
|
||||
|
||||
public pbase, s, t, sfracf, tfracf, snext, tnext
|
||||
public spancountminus1, zi16stepu, sdivz16stepu, tdivz16stepu
|
||||
public zi8stepu, sdivz8stepu, tdivz8stepu, pz
|
||||
s dd 0
|
||||
t dd 0
|
||||
snext dd 0
|
||||
tnext dd 0
|
||||
sfracf dd 0
|
||||
tfracf dd 0
|
||||
pbase dd 0
|
||||
zi8stepu dd 0
|
||||
sdivz8stepu dd 0
|
||||
tdivz8stepu dd 0
|
||||
zi16stepu dd 0
|
||||
sdivz16stepu dd 0
|
||||
tdivz16stepu dd 0
|
||||
spancountminus1 dd 0
|
||||
pz dd 0
|
||||
|
||||
public izistep
|
||||
izistep dd 0
|
||||
|
||||
;-------------------------------------------------------
|
||||
; local variables for d_draw16.s
|
||||
;-------------------------------------------------------
|
||||
|
||||
public reciprocal_table_16, entryvec_table_16
|
||||
; 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13,
|
||||
; 1/14, and 1/15 in 0.32 form
|
||||
reciprocal_table_16 dd 040000000h, 02aaaaaaah, 020000000h
|
||||
dd 019999999h, 015555555h, 012492492h
|
||||
dd 010000000h, 0e38e38eh, 0ccccccch, 0ba2e8bah
|
||||
dd 0aaaaaaah, 09d89d89h, 09249249h, 08888888h
|
||||
|
||||
externdef Entry2_16:dword
|
||||
externdef Entry3_16:dword
|
||||
externdef Entry4_16:dword
|
||||
externdef Entry5_16:dword
|
||||
externdef Entry6_16:dword
|
||||
externdef Entry7_16:dword
|
||||
externdef Entry8_16:dword
|
||||
externdef Entry9_16:dword
|
||||
externdef Entry10_16:dword
|
||||
externdef Entry11_16:dword
|
||||
externdef Entry12_16:dword
|
||||
externdef Entry13_16:dword
|
||||
externdef Entry14_16:dword
|
||||
externdef Entry15_16:dword
|
||||
externdef Entry16_16:dword
|
||||
|
||||
entryvec_table_16 dd 0, Entry2_16, Entry3_16, Entry4_16
|
||||
dd Entry5_16, Entry6_16, Entry7_16, Entry8_16
|
||||
dd Entry9_16, Entry10_16, Entry11_16, Entry12_16
|
||||
dd Entry13_16, Entry14_16, Entry15_16, Entry16_16
|
||||
|
||||
;-------------------------------------------------------
|
||||
; local variables for d_parta.s
|
||||
;-------------------------------------------------------
|
||||
public DP_Count, DP_u, DP_v, DP_32768, DP_Color, DP_Pix
|
||||
DP_Count dd 0
|
||||
DP_u dd 0
|
||||
DP_v dd 0
|
||||
DP_32768 dd 32768.0
|
||||
DP_Color dd 0
|
||||
DP_Pix dd 0
|
||||
|
||||
|
||||
;externdef DP_1x1:dword
|
||||
;externdef DP_2x2:dword
|
||||
;externdef DP_3x3:dword
|
||||
;externdef DP_4x4:dword
|
||||
|
||||
;DP_EntryTable dd DP_1x1, DP_2x2, DP_3x3, DP_4x4
|
||||
|
||||
;
|
||||
; advancetable is 8 bytes, but points to the middle of that range so negative
|
||||
; offsets will work
|
||||
;
|
||||
public advancetable, sstep, tstep, pspantemp, counttemp, jumptemp
|
||||
advancetable dd 0, 0
|
||||
sstep dd 0
|
||||
tstep dd 0
|
||||
|
||||
pspantemp dd 0
|
||||
counttemp dd 0
|
||||
jumptemp dd 0
|
||||
|
||||
; 1/2, 1/3, 1/4, 1/5, 1/6, and 1/7 in 0.32 form
|
||||
; public reciprocal_table, entryvec_table
|
||||
reciprocal_table dd 040000000h, 02aaaaaaah, 020000000h
|
||||
dd 019999999h, 015555555h, 012492492h
|
||||
|
||||
|
||||
; externdef Entry2_8:dword
|
||||
; externdef Entry3_8:dword
|
||||
; externdef Entry4_8:dword
|
||||
; externdef Entry5_8:dword
|
||||
; externdef Entry6_8:dword
|
||||
; externdef Entry7_8:dword
|
||||
; externdef Entry8_8:dword
|
||||
|
||||
;entryvec_table dd 0, Entry2_8, Entry3_8, Entry4_8
|
||||
; dd Entry5_8, Entry6_8, Entry7_8, Entry8_8
|
||||
|
||||
externdef Spr8Entry2_8:dword
|
||||
externdef Spr8Entry3_8:dword
|
||||
externdef Spr8Entry4_8:dword
|
||||
externdef Spr8Entry5_8:dword
|
||||
externdef Spr8Entry6_8:dword
|
||||
externdef Spr8Entry7_8:dword
|
||||
externdef Spr8Entry8_8:dword
|
||||
|
||||
public spr8entryvec_table
|
||||
spr8entryvec_table dd 0, Spr8Entry2_8, Spr8Entry3_8, Spr8Entry4_8
|
||||
dd Spr8Entry5_8, Spr8Entry6_8, Spr8Entry7_8, Spr8Entry8_8
|
||||
|
||||
|
||||
_DATA ENDS
|
||||
endif ; id386
|
||||
END
|
||||
123
ref_soft/rand1k.h
Normal file
123
ref_soft/rand1k.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// 1K random numbers in the range 0-255
|
||||
0, 144, 49, 207, 149, 122, 89, 229, 210, 191,
|
||||
44, 219, 181, 131, 77, 3, 23, 93, 37, 42,
|
||||
253, 114, 30, 1, 2, 96, 136, 146, 154, 155,
|
||||
42, 169, 115, 90, 14, 155, 200, 205, 133, 77,
|
||||
224, 186, 244, 236, 138, 36, 118, 60, 220, 53,
|
||||
199, 215, 255, 255, 156, 100, 68, 76, 215, 6,
|
||||
96, 23, 173, 14, 2, 235, 70, 69, 150, 176,
|
||||
214, 185, 124, 52, 190, 119, 117, 242, 190, 27,
|
||||
153, 98, 188, 155, 146, 92, 38, 57, 108, 205,
|
||||
132, 253, 192, 88, 43, 168, 125, 16, 179, 129,
|
||||
37, 243, 36, 231, 177, 77, 109, 18, 247, 174,
|
||||
39, 224, 210, 149, 48, 45, 209, 121, 39, 129,
|
||||
187, 103, 71, 145, 174, 193, 184, 121, 31, 94,
|
||||
213, 8, 132, 169, 109, 26, 243, 235, 140, 88,
|
||||
120, 95, 216, 81, 116, 69, 251, 76, 189, 145,
|
||||
50, 194, 214, 101, 128, 227, 7, 254, 146, 12,
|
||||
136, 49, 215, 160, 168, 50, 215, 31, 28, 190,
|
||||
80, 240, 73, 86, 35, 187, 213, 181, 153, 191,
|
||||
64, 36, 0, 15, 206, 218, 53, 29, 141, 3,
|
||||
29, 116, 192, 175, 139, 18, 111, 51, 178, 74,
|
||||
111, 59, 147, 136, 160, 41, 129, 246, 178, 236,
|
||||
48, 86, 45, 254, 117, 255, 24, 160, 24, 112,
|
||||
238, 12, 229, 74, 58, 196, 105, 51, 160, 154,
|
||||
115, 119, 153, 162, 218, 212, 159, 184, 144, 96,
|
||||
47, 188, 142, 231, 62, 48, 154, 178, 149, 89,
|
||||
126, 20, 189, 156, 158, 176, 205, 38, 147, 222,
|
||||
233, 157, 186, 11, 170, 249, 80, 145, 78, 44,
|
||||
27, 222, 217, 190, 39, 83, 20, 19, 164, 209,
|
||||
139, 114, 104, 76, 119, 128, 39, 82, 188, 80,
|
||||
211, 245, 223, 185, 76, 241, 32, 16, 200, 134,
|
||||
156, 244, 18, 224, 167, 82, 26, 129, 58, 74,
|
||||
235, 141, 169, 29, 126, 97, 127, 203, 130, 97,
|
||||
176, 136, 155, 101, 1, 181, 25, 159, 220, 125,
|
||||
191, 127, 97, 201, 141, 91, 244, 161, 45, 95,
|
||||
33, 190, 243, 156, 7, 84, 14, 163, 33, 216,
|
||||
221, 152, 184, 218, 3, 32, 181, 157, 55, 16,
|
||||
43, 159, 87, 81, 94, 169, 205, 206, 134, 156,
|
||||
204, 230, 37, 161, 103, 64, 34, 218, 16, 109,
|
||||
146, 77, 140, 57, 79, 28, 206, 34, 72, 201,
|
||||
229, 202, 190, 157, 92, 219, 58, 221, 58, 63,
|
||||
138, 252, 13, 20, 134, 109, 24, 66, 228, 59,
|
||||
37, 32, 238, 20, 12, 15, 86, 234, 102, 110,
|
||||
242, 214, 136, 215, 177, 101, 66, 1, 134, 244,
|
||||
102, 61, 149, 65, 175, 241, 111, 227, 1, 240,
|
||||
153, 201, 147, 36, 56, 98, 1, 106, 21, 168,
|
||||
218, 16, 207, 169, 177, 205, 135, 175, 36, 176,
|
||||
186, 199, 7, 222, 164, 180, 21, 141, 242, 15,
|
||||
70, 37, 251, 158, 74, 236, 94, 177, 55, 39,
|
||||
61, 133, 230, 27, 231, 113, 20, 200, 43, 249,
|
||||
198, 222, 53, 116, 0, 192, 29, 103, 79, 254,
|
||||
9, 64, 48, 63, 39, 158, 226, 240, 50, 199,
|
||||
165, 168, 232, 116, 235, 170, 38, 162, 145, 108,
|
||||
241, 138, 148, 137, 65, 101, 89, 9, 203, 50,
|
||||
17, 99, 151, 18, 50, 39, 164, 116, 154, 178,
|
||||
112, 175, 101, 213, 151, 51, 243, 224, 100, 252,
|
||||
47, 229, 147, 113, 160, 181, 12, 73, 66, 104,
|
||||
229, 181, 186, 229, 100, 101, 231, 79, 99, 146,
|
||||
90, 187, 190, 188, 189, 35, 51, 69, 174, 233,
|
||||
94, 132, 28, 232, 51, 132, 167, 112, 176, 23,
|
||||
20, 19, 7, 90, 78, 178, 36, 101, 17, 172,
|
||||
185, 50, 177, 157, 167, 139, 25, 139, 12, 249,
|
||||
118, 248, 186, 135, 174, 177, 95, 99, 12, 207,
|
||||
43, 15, 79, 200, 54, 82, 124, 2, 112, 130,
|
||||
155, 194, 102, 89, 215, 241, 159, 255, 13, 144,
|
||||
221, 99, 78, 72, 6, 156, 100, 4, 7, 116,
|
||||
219, 239, 102, 186, 156, 206, 224, 149, 152, 20,
|
||||
203, 118, 151, 150, 145, 208, 172, 87, 2, 68,
|
||||
87, 59, 197, 95, 222, 29, 185, 161, 228, 46,
|
||||
137, 230, 199, 247, 50, 230, 204, 244, 217, 227,
|
||||
160, 47, 157, 67, 64, 187, 201, 43, 182, 123,
|
||||
20, 206, 218, 31, 78, 146, 121, 195, 49, 186,
|
||||
254, 3, 165, 177, 44, 18, 70, 173, 214, 142,
|
||||
95, 199, 59, 163, 59, 52, 248, 72, 5, 196,
|
||||
38, 12, 2, 89, 164, 87, 106, 106, 23, 139,
|
||||
179, 86, 168, 224, 137, 145, 13, 119, 66, 109,
|
||||
221, 124, 22, 144, 181, 199, 221, 217, 75, 221,
|
||||
165, 191, 212, 195, 223, 232, 233, 133, 112, 27,
|
||||
90, 210, 109, 43, 0, 168, 198, 16, 22, 98,
|
||||
175, 206, 39, 36, 12, 88, 4, 250, 165, 13,
|
||||
234, 163, 110, 5, 62, 100, 167, 200, 5, 211,
|
||||
35, 162, 140, 251, 118, 54, 76, 200, 87, 123,
|
||||
155, 26, 252, 193, 38, 116, 182, 255, 198, 164,
|
||||
159, 242, 176, 74, 145, 74, 140, 182, 63, 139,
|
||||
126, 243, 171, 195, 159, 114, 204, 190, 253, 52,
|
||||
161, 232, 151, 235, 129, 125, 115, 227, 240, 46,
|
||||
64, 51, 187, 240, 160, 10, 164, 8, 142, 139,
|
||||
114, 15, 254, 32, 153, 12, 44, 169, 85, 80,
|
||||
167, 105, 109, 56, 173, 42, 127, 129, 205, 111,
|
||||
1, 86, 96, 32, 211, 187, 228, 164, 166, 131,
|
||||
187, 188, 245, 119, 92, 28, 231, 210, 116, 27,
|
||||
222, 194, 10, 106, 239, 17, 42, 54, 29, 151,
|
||||
30, 158, 148, 176, 187, 234, 171, 76, 207, 96,
|
||||
255, 197, 52, 43, 99, 46, 148, 50, 245, 48,
|
||||
97, 77, 30, 50, 11, 197, 194, 225, 0, 114,
|
||||
109, 205, 118, 126, 191, 61, 143, 23, 236, 228,
|
||||
219, 15, 125, 161, 191, 193, 65, 232, 202, 51,
|
||||
141, 13, 133, 202, 180, 6, 187, 141, 234, 224,
|
||||
204, 78, 101, 123, 13, 166, 0, 196, 193, 56,
|
||||
39, 14, 171, 8, 88, 178, 204, 111, 251, 162,
|
||||
75, 122, 223, 20, 25, 36, 36, 235, 79, 95,
|
||||
208, 11, 208, 61, 229, 65, 68, 53, 58, 216,
|
||||
223, 227, 216, 155, 10, 44, 47, 91, 115, 47,
|
||||
228, 159, 139, 233
|
||||
1498
ref_soft/ref_soft.001
Normal file
1498
ref_soft/ref_soft.001
Normal file
File diff suppressed because it is too large
Load Diff
2
ref_soft/ref_soft.def
Normal file
2
ref_soft/ref_soft.def
Normal file
@@ -0,0 +1,2 @@
|
||||
EXPORTS
|
||||
GetRefAPI
|
||||
1496
ref_soft/ref_soft.dsp
Normal file
1496
ref_soft/ref_soft.dsp
Normal file
File diff suppressed because it is too large
Load Diff
17
ref_soft/ref_soft.plg
Normal file
17
ref_soft/ref_soft.plg
Normal file
@@ -0,0 +1,17 @@
|
||||
--------------------Configuration: ref_soft - Win32 Release Alpha--------------------
|
||||
Begining build with project "G:\quake2\code\ref_soft\ref_soft.dsp", at root.
|
||||
Active configuration is Win32 (ALPHA) Dynamic-Link Library (based on Win32 (ALPHA) Dynamic-Link Library)
|
||||
|
||||
Project's tools are:
|
||||
"OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
|
||||
"C/C++ Compiler for Alpha" with flags "/nologo /QA21164 /MT /Gt0 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "C_ONLY" /Fp".\ReleaseAXP/ref_soft.pch" /YX /Fo".\ReleaseAXP/" /Fd".\ReleaseAXP/" /FD /QAieee1 /c "
|
||||
"Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" "
|
||||
"Browser Database Maker" with flags "/nologo /o"..\ReleaseAXP/ref_soft.bsc" "
|
||||
"COFF Linker for Alpha" with flags "kernel32.lib user32.lib gdi32.lib winmm.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"..\ReleaseAXP/ref_soft.pdb" /debug /machine:ALPHA /def:".\ref_soft.def" /out:"..\ReleaseAXP/ref_soft.dll" /implib:"..\ReleaseAXP/ref_soft.lib" "
|
||||
"Custom Build" with flags ""
|
||||
"<Component 0xa>" with flags ""
|
||||
|
||||
|
||||
|
||||
|
||||
ref_soft.dll - 0 error(s), 0 warning(s)
|
||||
332
rhapsody/in_next.m
Normal file
332
rhapsody/in_next.m
Normal file
@@ -0,0 +1,332 @@
|
||||
// in_next.m
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <drivers/event_status_driver.h>
|
||||
#include "../client/client.h"
|
||||
|
||||
float mousex, mousey;
|
||||
|
||||
float mouse_center_x = 160;
|
||||
float mouse_center_y = 100;
|
||||
|
||||
void PSsetmouse (float x, float y);
|
||||
void PSshowcursor (void);
|
||||
void PShidecursor (void);
|
||||
void PScurrentmouse (int win, float *x, float *y);
|
||||
|
||||
extern NSView *vid_view_i;
|
||||
extern NSWindow *vid_window_i;
|
||||
|
||||
qboolean mlooking;
|
||||
qboolean mouseinitialized;
|
||||
int mouse_buttons;
|
||||
int mouse_oldbuttonstate;
|
||||
int mouseactive;
|
||||
int mousereset;
|
||||
int mx_accum, my_accum;
|
||||
int window_center_x, window_center_y;
|
||||
int old_mouse_x, old_mouse_y;
|
||||
|
||||
cvar_t in_mouse = {"in_mouse", "0", CVAR_ARCHIVE};
|
||||
cvar_t m_filter = {"m_filter", "0", CVAR_ARCHIVE};
|
||||
cvar_t freelook = {"in_freelook", "0", CVAR_ARCHIVE};
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_ActivateMouse
|
||||
|
||||
Called when the window gains focus or changes in some way
|
||||
===========
|
||||
*/
|
||||
void IN_ActivateMouse (void)
|
||||
{
|
||||
NSRect r;
|
||||
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
if (!in_mouse.value)
|
||||
return;
|
||||
|
||||
r = [vid_window_i frame];
|
||||
window_center_x = r.size.width / 2;
|
||||
window_center_y = r.size.height / 2;
|
||||
|
||||
if (!mouseactive)
|
||||
PShidecursor ();
|
||||
|
||||
mouseactive = true;
|
||||
mousereset = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_DeactivateMouse
|
||||
|
||||
Called when the window loses focus
|
||||
===========
|
||||
*/
|
||||
void IN_DeactivateMouse (void)
|
||||
{
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
|
||||
if (mouseactive)
|
||||
PSshowcursor ();
|
||||
|
||||
mouseactive = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_StartupMouse
|
||||
===========
|
||||
*/
|
||||
void IN_StartupMouse (void)
|
||||
{
|
||||
if ( COM_CheckParm ("-nomouse") )
|
||||
return;
|
||||
|
||||
mouseinitialized = true;
|
||||
|
||||
mouse_buttons = 3;
|
||||
|
||||
IN_ActivateMouse ();
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_MouseEvent
|
||||
===========
|
||||
*/
|
||||
void IN_MouseEvent (int mstate)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mouseactive)
|
||||
return;
|
||||
|
||||
// perform button actions
|
||||
for (i=0 ; i<mouse_buttons ; i++)
|
||||
{
|
||||
if ( (mstate & (1<<i)) &&
|
||||
!(mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_MOUSE1 + i, true);
|
||||
}
|
||||
|
||||
if ( !(mstate & (1<<i)) &&
|
||||
(mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_MOUSE1 + i, false);
|
||||
}
|
||||
}
|
||||
|
||||
mouse_oldbuttonstate = mstate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Accumulate
|
||||
===========
|
||||
*/
|
||||
void IN_Accumulate (void)
|
||||
{
|
||||
int dx, dy;
|
||||
static int old_x, old_y;
|
||||
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
|
||||
if (in_mouse.modified)
|
||||
{
|
||||
in_mouse.modified = false;
|
||||
IN_DeactivateMouse ();
|
||||
IN_ActivateMouse ();
|
||||
}
|
||||
|
||||
if (!mouseactive)
|
||||
return;
|
||||
|
||||
// [vid_view_i lockFocus];
|
||||
|
||||
if (mousereset)
|
||||
{ // we haven't centered cursor yet
|
||||
mousereset = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSPoint p;
|
||||
|
||||
PScurrentmouse ([vid_window_i windowNumber], &mousex, &mousey);
|
||||
|
||||
p.x = mousex;
|
||||
p.y = mousey;
|
||||
p = [vid_view_i convertPoint:p fromView: nil];
|
||||
|
||||
mousex = p.x;
|
||||
mousey = p.y;
|
||||
|
||||
dx = mousex - old_x;
|
||||
dy = old_y - mousey;
|
||||
|
||||
if (!dx && !dy)
|
||||
return;
|
||||
mx_accum += dx;
|
||||
my_accum += dy;
|
||||
}
|
||||
|
||||
// force the mouse to the center, so there's room to move
|
||||
PSsetmouse (window_center_x, window_center_y);
|
||||
PScurrentmouse ([vid_window_i windowNumber], &mousex, &mousey);
|
||||
// PSsetmouse (window_center_x, window_center_y);
|
||||
old_x = window_center_x;
|
||||
old_y = window_center_y;
|
||||
|
||||
// [vid_view_i unlockFocus];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_MouseMove
|
||||
===========
|
||||
*/
|
||||
void IN_MouseMove (usercmd_t *cmd)
|
||||
{
|
||||
int mx, my;
|
||||
int mouse_x, mouse_y;
|
||||
|
||||
IN_Accumulate ();
|
||||
|
||||
mx = mx_accum;
|
||||
my = my_accum;
|
||||
|
||||
mx_accum = 0;
|
||||
my_accum = 0;
|
||||
|
||||
if (m_filter.value)
|
||||
{
|
||||
mouse_x = (mx + old_mouse_x) * 0.5;
|
||||
mouse_y = (my + old_mouse_y) * 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse_x = mx;
|
||||
mouse_y = my;
|
||||
}
|
||||
|
||||
old_mouse_x = mx;
|
||||
old_mouse_y = my;
|
||||
|
||||
if (!mx && !my)
|
||||
return;
|
||||
|
||||
if (!mouseactive)
|
||||
return;
|
||||
|
||||
mouse_x *= sensitivity.value;
|
||||
mouse_y *= sensitivity.value;
|
||||
|
||||
// add mouse X/Y movement to cmd
|
||||
if ( (in_strafe.state & 1) || (lookstrafe.value && mlooking ))
|
||||
cmd->sidemove += m_side.value * mouse_x;
|
||||
else
|
||||
cl.viewangles[YAW] -= m_yaw.value * mouse_x;
|
||||
|
||||
if ( (mlooking || freelook.value) && !(in_strafe.state & 1))
|
||||
{
|
||||
cl.viewangles[PITCH] += m_pitch.value * mouse_y;
|
||||
if (cl.viewangles[PITCH] > 80)
|
||||
cl.viewangles[PITCH] = 80;
|
||||
if (cl.viewangles[PITCH] < -70)
|
||||
cl.viewangles[PITCH] = -70;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->forwardmove -= m_forward.value * mouse_y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IN_ShowMouse (void)
|
||||
{
|
||||
PSshowcursor ();
|
||||
}
|
||||
|
||||
void IN_HideMouse (void)
|
||||
{
|
||||
PShidecursor ();
|
||||
}
|
||||
|
||||
NXEventHandle eventhandle;
|
||||
NXMouseScaling oldscaling, newscaling;
|
||||
NXMouseButton oldbutton;
|
||||
|
||||
/*
|
||||
=============
|
||||
IN_Init
|
||||
=============
|
||||
*/
|
||||
void IN_Init (void)
|
||||
{
|
||||
Cvar_RegisterVariable (&in_mouse);
|
||||
Cvar_RegisterVariable (&m_filter);
|
||||
Cvar_RegisterVariable (&freelook);
|
||||
|
||||
Cmd_AddCommand ("showmouse", IN_ShowMouse);
|
||||
Cmd_AddCommand ("hidemouse", IN_HideMouse);
|
||||
|
||||
IN_StartupMouse ();
|
||||
|
||||
// open the event status driver
|
||||
eventhandle = NXOpenEventStatus();
|
||||
NXGetMouseScaling (eventhandle, &oldscaling);
|
||||
NXSetMouseScaling (eventhandle, &newscaling);
|
||||
oldbutton = NXMouseButtonEnabled (eventhandle);
|
||||
NXEnableMouseButton (eventhandle, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
IN_Shutdown
|
||||
=============
|
||||
*/
|
||||
void IN_Shutdown (void)
|
||||
{
|
||||
IN_DeactivateMouse ();
|
||||
|
||||
// put mouse scaling back the way it was
|
||||
NXSetMouseScaling (eventhandle, &oldscaling);
|
||||
NXEnableMouseButton (eventhandle, oldbutton);
|
||||
NXCloseEventStatus (eventhandle);
|
||||
}
|
||||
|
||||
void IN_Move (usercmd_t *cmd)
|
||||
{
|
||||
IN_MouseMove (cmd);
|
||||
}
|
||||
|
||||
void IN_Commands (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================================================================
|
||||
|
||||
VIEW CENTERING
|
||||
|
||||
=========================================================================
|
||||
*/
|
||||
|
||||
void V_StopPitchDrift (void)
|
||||
{
|
||||
cl.laststop = cl.time;
|
||||
cl.nodrift = true;
|
||||
cl.pitchvel = 0;
|
||||
}
|
||||
63
rhapsody/makefile.bak
Normal file
63
rhapsody/makefile.bak
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
CFLAGS = -O -g -DGAME_HARD_LINKED -DREF_HARD_LINKED
|
||||
LDFLAGS = -sectcreate __ICON __header quake2.iconheader -segprot __ICON r r -sectcreate __ICON app quake2.tiff -framework AppKit -framework Foundation
|
||||
EXE = quake2
|
||||
TARGETS = $(EXE)
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
SERVERFILES = sv_ccmds.o sv_ents.o sv_game.o sv_init.o sv_main.o sv_send.o sv_user.o sv_world.o
|
||||
|
||||
GAMEFILES = g_ai.o g_cmds.o g_combat.o g_func.o g_items.o g_main.o g_misc.o g_monster.o g_phys.o g_save.o g_spawn.o g_target.o g_trigger.o g_utils.o g_weapon.o g_turret.o m_actor.o m_berserk.o m_boss2.o m_boss3.o m_boss31.o m_boss32.o m_brain.o m_chick.o m_flipper.o m_float.o m_flyer.o m_gladiator.o m_gunner.o m_hover.o m_infantry.o m_insane.o m_medic.o m_move.o m_mutant.o m_parasite.o m_soldier.o m_supertank.o m_tank.o p_client.o p_hud.o p_trail.o p_view.o p_weapon.o
|
||||
|
||||
CLIENTFILES = cl_ents.o cl_fx.o cl_input.o cl_inv.o cl_main.o cl_parse.o cl_pred.o cl_scrn.o cl_cin.o cl_tent.o cl_view.o console.o keys.o menu.o qmenu.o snd_dma.o snd_mem.o snd_mix.o
|
||||
|
||||
# commonfiles are used by both client and server
|
||||
COMMONFILES = m_flash.o cmd.o cmodel.o common.o cvar.o files.o md4.o net_chan.o net_udp.o pmove.o
|
||||
|
||||
REFGLFILES = gl_draw.o gl_light.o gl_mesh.o gl_model.o gl_rmain.o gl_rmisc.o gl_rsurf.o gl_warp.o gl_image.o
|
||||
|
||||
REFSOFTFILES = r_aclip.o r_alias.o r_bsp.o r_draw.o r_edge.o r_image.o r_light.o r_main.o r_misc.o r_model.o r_part.o r_polyse.o r_poly.o r_rast.o r_scan.o r_sprite.o r_surf.o
|
||||
|
||||
# sharedfiles are included in EVERY dll
|
||||
SHAREDFILES = q_shared.o
|
||||
|
||||
IRIXFILES = cd_sgi.o glx_imp.o qgl_sgi.o sys_sgi.o vid_sgi.o in_sgi.o snddma_null.o
|
||||
|
||||
RHAPFILES = cd_null.o in_null.o snddma_null.o sys_rhap.o vid_null.o swimp_rhap.o
|
||||
|
||||
NULLFILES = cd_null.o in_null.o snddma_null.o sys_null.o vid_null.o swimp_null.o
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
FILES = $(SERVERFILES) $(GAMEFILES) $(COMMONFILES) $(CLIENTFILES) $(REFSOFTFILES) $(SHAREDFILES) $(RHAPFILES)
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(FILES) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(EXE) $(FILES)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
# gnumake pattern rules are so cool!
|
||||
|
||||
%.o : ../game/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../qcommon/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../client/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../server/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../ref_soft/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../ref_gl/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../null/%.c
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
%.o : ../rhapsody/%.m
|
||||
cc $(CFLAGS) -c -o $@ $?
|
||||
|
||||
34
rhapsody/notes.txt
Normal file
34
rhapsody/notes.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
f1
|
||||
|
||||
not calling back to set vid size after sw_mode change?
|
||||
|
||||
do vid_xpos / ypos creep because of frames?
|
||||
|
||||
fix fullscreen fallback bug
|
||||
|
||||
nsping
|
||||
|
||||
icon
|
||||
|
||||
don't make sys_error varargs
|
||||
|
||||
cvar_stvalue in ref????
|
||||
|
||||
subframe event timing information
|
||||
|
||||
swimp init / swimp_initgraphics?
|
||||
|
||||
SWimp_SetMode shouldn't call
|
||||
R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
|
||||
|
||||
subclass window instead of view?
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
|
||||
do we ever pass a NULL palette?
|
||||
17
rhapsody/pb.project
Normal file
17
rhapsody/pb.project
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
DYNAMIC_CODE_GEN = YES;
|
||||
FILESTABLE = {
|
||||
FRAMEWORKS = (Foundation.framework);
|
||||
OTHER_LINKED = (QuakeWorld_main.m);
|
||||
OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, m.template, h.template);
|
||||
};
|
||||
LANGUAGE = English;
|
||||
LOCALIZABLE_FILES = {};
|
||||
MAKEFILEDIR = "$(NEXT_ROOT)/NextDeveloper/Makefiles/pb_makefiles";
|
||||
NEXTSTEP_BUILDTOOL = /bin/gnumake;
|
||||
PDO_UNIX_BUILDTOOL = $NEXT_ROOT/NextDeveloper/bin/make;
|
||||
PROJECTNAME = QuakeWorld;
|
||||
PROJECTTYPE = Tool;
|
||||
PROJECTVERSION = 2.6;
|
||||
WINDOWS_BUILDTOOL = $NEXT_ROOT/NextDeveloper/Executables/make;
|
||||
}
|
||||
2
rhapsody/quake2.iconheader
Normal file
2
rhapsody/quake2.iconheader
Normal file
@@ -0,0 +1,2 @@
|
||||
F test.app test app
|
||||
F test test app
|
||||
BIN
rhapsody/quake2.tiff
Normal file
BIN
rhapsody/quake2.tiff
Normal file
Binary file not shown.
735
rhapsody/r_next.m
Normal file
735
rhapsody/r_next.m
Normal file
@@ -0,0 +1,735 @@
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#include "../ref_soft/r_local.h"
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
OPENSTEP specific stuff
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
|
||||
@interface QuakeView : NSView
|
||||
@end
|
||||
|
||||
NSWindow *vid_window_i;
|
||||
QuakeView *vid_view_i;
|
||||
|
||||
unsigned *buffernative;
|
||||
|
||||
//===========================================================
|
||||
|
||||
|
||||
int Draw_SetResolution (void);
|
||||
|
||||
#define TYPE_FULLSCREEN 0
|
||||
#define TYPE_WINDOWED 1
|
||||
#define TYPE_STRETCHED 2
|
||||
|
||||
#define NUM_RESOLUTIONS 7
|
||||
int resolutions[NUM_RESOLUTIONS][2] = {
|
||||
{320,200}, {320,240}, {400,300}, {512,384}, {640,480}, {800,600}, {1024,768} };
|
||||
|
||||
qboolean available[NUM_RESOLUTIONS][3];
|
||||
int mode_res = 0, mode_type = TYPE_WINDOWED;
|
||||
|
||||
byte gammatable[256]; // palette is sent through this
|
||||
unsigned current_palette[256];
|
||||
unsigned gamma_palette[256];
|
||||
|
||||
int cursor_res, cursor_type;
|
||||
|
||||
cvar_t *vid_x;
|
||||
cvar_t *vid_y;
|
||||
cvar_t *vid_mode;
|
||||
cvar_t *vid_stretched;
|
||||
cvar_t *vid_fullscreen;
|
||||
cvar_t *draw_gamma;
|
||||
|
||||
void Draw_BuildGammaTable (void);
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
MENU INTERACTION
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
|
||||
void FindModes (void)
|
||||
{
|
||||
if (mode_res < 0 || mode_res >= NUM_RESOLUTIONS)
|
||||
mode_res = 0;
|
||||
if (mode_type < 0 || mode_type > 3)
|
||||
mode_type = 1;
|
||||
|
||||
}
|
||||
|
||||
void RM_Print (int x, int y, char *s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
Draw_Char (x, y, (*s)+128);
|
||||
s++;
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_MenuDraw
|
||||
================
|
||||
*/
|
||||
void Draw_MenuDraw (void)
|
||||
{
|
||||
int i, j;
|
||||
int y;
|
||||
char string[32];
|
||||
|
||||
Draw_Pic ( 4, 4, "vidmodes");
|
||||
|
||||
RM_Print (80, 32, "fullscreen windowed stretched");
|
||||
RM_Print (80, 40, "---------- -------- ---------");
|
||||
y = 50;
|
||||
|
||||
// draw background behind selected mode
|
||||
Draw_Fill ( (mode_type+1)*80, y+(mode_res)*10, 40,10, 8);
|
||||
|
||||
// draw available grid
|
||||
for (i=0 ; i<NUM_RESOLUTIONS ; i++, y+= 10)
|
||||
{
|
||||
sprintf (string, "%ix%i", resolutions[i][0], resolutions[i][1]);
|
||||
RM_Print (0, y, string);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (available[i][j])
|
||||
RM_Print ( 80 + j*80, y, "*");
|
||||
}
|
||||
|
||||
// draw the cursor
|
||||
Draw_Char (80 + cursor_type*80, 50 + cursor_res*10, 128 + 12+((int)(r_newrefdef.time*4)&1));
|
||||
}
|
||||
|
||||
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
|
||||
// normal keys should be passed as lowercased ascii
|
||||
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_MenuKey
|
||||
================
|
||||
*/
|
||||
void Draw_MenuKey (int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case K_LEFTARROW:
|
||||
cursor_type--;
|
||||
if (cursor_type < 0)
|
||||
cursor_type = 2;
|
||||
break;
|
||||
|
||||
case K_RIGHTARROW:
|
||||
cursor_type++;
|
||||
if (cursor_type > 2)
|
||||
cursor_type = 0;
|
||||
break;
|
||||
|
||||
case K_UPARROW:
|
||||
cursor_res--;
|
||||
if (cursor_res < 0)
|
||||
cursor_res = NUM_RESOLUTIONS-1;
|
||||
break;
|
||||
|
||||
case K_DOWNARROW:
|
||||
cursor_res++;
|
||||
if (cursor_res >= NUM_RESOLUTIONS)
|
||||
cursor_res = 0;
|
||||
break;
|
||||
|
||||
case K_ENTER:
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_mode %i", cursor_res));
|
||||
switch (cursor_type)
|
||||
{
|
||||
case TYPE_FULLSCREEN:
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 1");
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 0");
|
||||
break;
|
||||
case TYPE_WINDOWED:
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 0");
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 0");
|
||||
break;
|
||||
case TYPE_STRETCHED:
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_fullscreen 0");
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_stretched 1");
|
||||
break;
|
||||
}
|
||||
|
||||
mode_res = cursor_res;
|
||||
mode_type = cursor_type;
|
||||
Draw_SetResolution ();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Draw_SetResolution
|
||||
|
||||
The vid structure will be filled in on return
|
||||
Also allocates the z buffer and surface cache
|
||||
================
|
||||
*/
|
||||
int Draw_SetResolution (void)
|
||||
{
|
||||
NSRect content;
|
||||
|
||||
if (vid_mode->value < 0)
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, "vid_mode 0");
|
||||
if (vid_mode->value >= NUM_RESOLUTIONS)
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_mode %i", NUM_RESOLUTIONS-1));
|
||||
|
||||
vid_mode->modified = false;
|
||||
vid_fullscreen->modified = false;
|
||||
vid_stretched->modified = false;
|
||||
|
||||
// free nativebuffer
|
||||
if (buffernative)
|
||||
{
|
||||
free (buffernative);
|
||||
buffernative = NULL;
|
||||
}
|
||||
|
||||
// free z buffer
|
||||
if (d_pzbuffer)
|
||||
{
|
||||
free (d_pzbuffer);
|
||||
d_pzbuffer = NULL;
|
||||
}
|
||||
// free surface cache
|
||||
if (sc_base)
|
||||
{
|
||||
D_FlushCaches ();
|
||||
free (sc_base);
|
||||
sc_base = NULL;
|
||||
}
|
||||
|
||||
vid.width = resolutions[(int)(vid_mode->value)][0];
|
||||
vid.height = resolutions[(int)(vid_mode->value)][1];
|
||||
|
||||
vid.win_width = vid.width;
|
||||
vid.win_height = vid.height;
|
||||
if (vid_stretched->value)
|
||||
{
|
||||
vid.win_width <<= 1;
|
||||
vid.win_height <<= 1;
|
||||
}
|
||||
|
||||
vid.aspect = 1;
|
||||
vid.buffer = malloc (vid.width*vid.height);
|
||||
vid.rowbytes = vid.width;
|
||||
d_pzbuffer = malloc(vid.width*vid.height*2);
|
||||
buffernative = malloc(vid.width*vid.height*4);
|
||||
|
||||
D_InitCaches ();
|
||||
|
||||
Sys_SetPalette ((byte *)d_8to24table);
|
||||
|
||||
if (vid_view_i)
|
||||
[vid_view_i unlockFocus];
|
||||
if (vid_window_i)
|
||||
[vid_window_i close];
|
||||
//
|
||||
// open a window
|
||||
//
|
||||
content = NSMakeRect (vid_x->value,vid_y->value,vid.win_width, vid.win_height);
|
||||
vid_window_i = [[NSWindow alloc]
|
||||
initWithContentRect: content
|
||||
styleMask: NSTitledWindowMask
|
||||
backing: NSBackingStoreRetained
|
||||
defer: NO
|
||||
];
|
||||
|
||||
[vid_window_i setDelegate: vid_window_i];
|
||||
[vid_window_i display];
|
||||
[NSApp activateIgnoringOtherApps: YES];
|
||||
[vid_window_i makeKeyAndOrderFront: nil];
|
||||
|
||||
// NSPing ();
|
||||
|
||||
content.origin.x = content.origin.y = 0;
|
||||
vid_view_i = [[QuakeView alloc] initWithFrame: content];
|
||||
[vid_window_i setContentView: vid_view_i];
|
||||
[vid_window_i makeFirstResponder: vid_view_i];
|
||||
[vid_window_i setDelegate: vid_view_i];
|
||||
|
||||
// [vid_window_i addToEventMask: NS_FLAGSCHANGEDMASK];
|
||||
[vid_window_i setTitle: @"Bitmap Quake Console"];
|
||||
[vid_window_i makeKeyAndOrderFront: nil];
|
||||
|
||||
// leave focus locked forever
|
||||
[vid_view_i lockFocus];
|
||||
|
||||
ri.VID_SetSize (vid.width, vid.height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
Draw_Init
|
||||
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
*/
|
||||
int Draw_Init (void *window)
|
||||
{
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp finishLaunching];
|
||||
|
||||
ri.Con_Printf (PRINT_ALL, "refresh version: "REF_VERSION"\n");
|
||||
|
||||
vid_x = ri.Cvar_Get ("vid_x", "0", CVAR_ARCHIVE);
|
||||
vid_y = ri.Cvar_Get ("vid_y", "0", CVAR_ARCHIVE);
|
||||
vid_mode = ri.Cvar_Get ("vid_mode", "0", CVAR_ARCHIVE);
|
||||
vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
|
||||
vid_stretched = ri.Cvar_Get ("vid_stretched", "0", CVAR_ARCHIVE);
|
||||
draw_gamma = ri.Cvar_Get ("gamma", "1", CVAR_ARCHIVE);
|
||||
|
||||
Draw_GetPalette ();
|
||||
|
||||
Draw_BuildGammaTable ();
|
||||
|
||||
// get the lighting colormap
|
||||
ri.FS_LoadFile ("gfx/colormap.lmp", (void **)&vid.colormap);
|
||||
if (!vid.colormap)
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "ERROR: Couldn't load gfx/colormap.lmp");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Draw_SetResolution ();
|
||||
|
||||
R_Init ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
Draw_Shutdown
|
||||
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
*/
|
||||
void Draw_Shutdown (void)
|
||||
{
|
||||
R_Shutdown ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
Draw_BuildGammaTable
|
||||
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
*/
|
||||
void Draw_BuildGammaTable (void)
|
||||
{
|
||||
int i, inf;
|
||||
float g;
|
||||
|
||||
draw_gamma->modified = false;
|
||||
g = draw_gamma->value;
|
||||
|
||||
if (g == 1.0)
|
||||
{
|
||||
for (i=0 ; i<256 ; i++)
|
||||
gammatable[i] = i;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0 ; i<256 ; i++)
|
||||
{
|
||||
inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
|
||||
if (inf < 0)
|
||||
inf = 0;
|
||||
if (inf > 255)
|
||||
inf = 255;
|
||||
gammatable[i] = inf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
Draw_BeginFram
|
||||
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
*/
|
||||
void Draw_BeginFrame (void)
|
||||
{
|
||||
if (vid_mode->modified || vid_fullscreen->modified
|
||||
|| vid_stretched->modified)
|
||||
Draw_SetResolution ();
|
||||
|
||||
if (draw_gamma->modified)
|
||||
{
|
||||
Draw_BuildGammaTable ();
|
||||
Sys_SetPalette ((byte *)current_palette);
|
||||
}
|
||||
|
||||
// MGL_beginDirectAccess();
|
||||
// vid.buffer = mgldc->surface;
|
||||
// vid.rowbytes = mgldc->mi.bytesPerLine;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
Draw_EndFrame
|
||||
|
||||
@@@@@@@@@@@@@@@@@@@@@
|
||||
*/
|
||||
void Draw_EndFrame (void)
|
||||
{
|
||||
int i, c;
|
||||
int bps, spp, bpp, bpr;
|
||||
unsigned char *planes[5];
|
||||
NSRect bounds;
|
||||
|
||||
// translate to 24 bit color
|
||||
c = vid.width*vid.height;
|
||||
for (i=0 ; i<c ; i++)
|
||||
buffernative[i] = gamma_palette[vid.buffer[i]];
|
||||
|
||||
bps = 8;
|
||||
spp = 3;
|
||||
bpp = 32;
|
||||
bpr = vid.width * 4;
|
||||
planes[0] = (unsigned char *)buffernative;
|
||||
|
||||
bounds = [vid_view_i bounds];
|
||||
|
||||
NSDrawBitmap(
|
||||
bounds,
|
||||
vid.width,
|
||||
vid.height,
|
||||
bps,
|
||||
spp,
|
||||
bpp,
|
||||
bpr,
|
||||
NO,
|
||||
NO,
|
||||
@"NSDeviceRGBColorSpace",
|
||||
planes
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//===============================================================================
|
||||
|
||||
#define HUNK_MAGIC 0xffaffaff
|
||||
typedef struct
|
||||
{
|
||||
int magic;
|
||||
int length;
|
||||
int pad[6];
|
||||
} hunkheader_t;
|
||||
|
||||
hunkheader_t *membase;
|
||||
int maxsize;
|
||||
int cursize;
|
||||
|
||||
void *Hunk_Begin (void)
|
||||
{
|
||||
kern_return_t r;
|
||||
|
||||
// reserve a huge chunk of memory, but don't commit any yet
|
||||
maxsize = 16*1024*1024;
|
||||
cursize = 0;
|
||||
membase = NULL;
|
||||
r = vm_allocate(task_self(), (vm_address_t *)&membase, maxsize, 1);
|
||||
if (!membase || r != KERN_SUCCESS)
|
||||
ri.Sys_Error (ERR_FATAL,"vm_allocate failed");
|
||||
membase->magic = HUNK_MAGIC;
|
||||
membase->length = maxsize;
|
||||
cursize = 32;
|
||||
return (void *)((byte *)membase + cursize);
|
||||
}
|
||||
|
||||
void *Hunk_Alloc (int size)
|
||||
{
|
||||
// round to cacheline
|
||||
size = (size+31)&~31;
|
||||
|
||||
cursize += size;
|
||||
|
||||
if (cursize > maxsize)
|
||||
ri.Sys_Error (ERR_DROP, "Hunk_Alloc overflow");
|
||||
|
||||
memset ((byte *)membase+cursize-size,0,size);
|
||||
|
||||
return (void *)((byte *)membase+cursize-size);
|
||||
}
|
||||
|
||||
int Hunk_End (void)
|
||||
{
|
||||
kern_return_t r;
|
||||
|
||||
// round to pagesize
|
||||
cursize = (cursize+vm_page_size)&~(vm_page_size-1);
|
||||
membase->length = cursize;
|
||||
r = vm_deallocate(task_self(),
|
||||
(vm_address_t)((byte *)membase + cursize),
|
||||
maxsize - cursize);
|
||||
if ( r != KERN_SUCCESS )
|
||||
ri.Sys_Error (ERR_DROP, "vm_deallocate failed");
|
||||
return cursize;
|
||||
}
|
||||
|
||||
void Hunk_Free (void *base)
|
||||
{
|
||||
hunkheader_t *h;
|
||||
kern_return_t r;
|
||||
|
||||
h = ((hunkheader_t *)base) - 1;
|
||||
if (h->magic != HUNK_MAGIC)
|
||||
ri.Sys_Error (ERR_FATAL, "Hunk_Free: bad magic");
|
||||
|
||||
r = vm_deallocate(task_self(), (vm_address_t)h, h->length);
|
||||
if ( r != KERN_SUCCESS )
|
||||
ri.Sys_Error (ERR_DROP, "vm_deallocate failed");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_SetPalette
|
||||
================
|
||||
*/
|
||||
void Sys_SetPalette (byte *palette)
|
||||
{
|
||||
byte *p;
|
||||
int i;
|
||||
|
||||
memcpy (current_palette, palette, sizeof(current_palette));
|
||||
p = (byte *)gamma_palette;
|
||||
// gamma correct and byte swap
|
||||
for (i=0 ; i<256 ; i++, p+=4, palette+=4)
|
||||
{
|
||||
p[0] = gammatable[palette[0]];
|
||||
p[1] = gammatable[palette[1]];
|
||||
p[2] = gammatable[palette[2]];
|
||||
p[3] = 0xff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==========================================================================
|
||||
|
||||
NEXTSTEP VIEW CLASS
|
||||
|
||||
==========================================================================
|
||||
*/
|
||||
#include "../client/keys.h"
|
||||
|
||||
void IN_ActivateMouse (void);
|
||||
void IN_DeactivateMouse (void);
|
||||
|
||||
@implementation QuakeView
|
||||
|
||||
-(BOOL) acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)windowDidMove: (NSNotification *)note
|
||||
{
|
||||
NSRect r;
|
||||
|
||||
r = [vid_window_i frame];
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_x %i", (int)r.origin.x+1));
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_y %i", (int)r.origin.y+1));
|
||||
}
|
||||
|
||||
- (void)becomeKeyWindow
|
||||
{
|
||||
IN_ActivateMouse ();
|
||||
}
|
||||
|
||||
- (void)resignKeyWindow
|
||||
{
|
||||
IN_DeactivateMouse ();
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int source, dest;
|
||||
} keymap_t;
|
||||
|
||||
keymap_t keymaps[] =
|
||||
{
|
||||
{103, K_RIGHTARROW},
|
||||
{102, K_LEFTARROW},
|
||||
{100, K_UPARROW},
|
||||
{101, K_DOWNARROW},
|
||||
|
||||
{59, K_F1},
|
||||
{60, K_F2},
|
||||
{61, K_F3},
|
||||
{62, K_F4},
|
||||
{63, K_F5},
|
||||
{64, K_F6},
|
||||
{65, K_F7},
|
||||
{66, K_F8},
|
||||
{67, K_F9},
|
||||
{68, K_F10},
|
||||
{87, K_F11},
|
||||
{88, K_F12},
|
||||
|
||||
{-1,-1}
|
||||
};
|
||||
|
||||
keymap_t flagmaps[] =
|
||||
{
|
||||
{NSShiftKeyMask, K_SHIFT},
|
||||
{NSControlKeyMask, K_CTRL},
|
||||
{NSAlternateKeyMask, K_ALT},
|
||||
{NSCommandKeyMask, K_ALT},
|
||||
|
||||
{-1,-1}
|
||||
};
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE1, true);
|
||||
}
|
||||
- (void)mouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE1, false);
|
||||
}
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE2, true);
|
||||
}
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE2, false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
keyboard methods
|
||||
===================
|
||||
*/
|
||||
- (void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
int ch;
|
||||
keymap_t *km;
|
||||
|
||||
// PSobscurecursor ();
|
||||
|
||||
// check for non-ascii first
|
||||
ch = [theEvent keyCode];
|
||||
for (km=keymaps;km->source!=-1;km++)
|
||||
if (ch == km->source)
|
||||
{
|
||||
Key_Event (km->dest, true);
|
||||
return;
|
||||
}
|
||||
|
||||
ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
ch += 'a' - 'A';
|
||||
if (ch>=256)
|
||||
return;
|
||||
|
||||
Key_Event (ch, true);
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)theEvent
|
||||
{
|
||||
static int oldflags;
|
||||
int newflags;
|
||||
int delta;
|
||||
keymap_t *km;
|
||||
int i;
|
||||
|
||||
// PSobscurecursor ();
|
||||
newflags = [theEvent modifierFlags];
|
||||
delta = newflags ^ oldflags;
|
||||
for (i=0 ; i<32 ; i++)
|
||||
{
|
||||
if ( !(delta & (1<<i)))
|
||||
continue;
|
||||
// changed
|
||||
for (km=flagmaps;km->source!=-1;km++)
|
||||
if ( (1<<i) == km->source)
|
||||
{
|
||||
if (newflags & (1<<i))
|
||||
Key_Event (km->dest, true);
|
||||
else
|
||||
Key_Event (km->dest, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
oldflags = newflags;
|
||||
}
|
||||
|
||||
|
||||
- (void)keyUp:(NSEvent *)theEvent
|
||||
{
|
||||
int ch;
|
||||
keymap_t *km;
|
||||
|
||||
// check for non-ascii first
|
||||
ch = [theEvent keyCode];
|
||||
for (km=keymaps;km->source!=-1;km++)
|
||||
if (ch == km->source)
|
||||
{
|
||||
Key_Event (km->dest, false);
|
||||
return;
|
||||
}
|
||||
|
||||
ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
ch += 'a' - 'A';
|
||||
if (ch>=256)
|
||||
return;
|
||||
Key_Event (ch, false);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
36
rhapsody/rhapqw.txt
Normal file
36
rhapsody/rhapqw.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
Put this QuakeWorld executable in a directory with the registered quake and QuakeWorld files. You should be able to launch it from the workspace or the command line.
|
||||
|
||||
The sound is a bit lagged and will likely drift on longer games, because I am using the system timer to calculate sample position. This will need to be fixed at some point.
|
||||
|
||||
There is no assembly language in yet, and it is still just using DPS to draw, so it isn't real fast yet. Run it on a ppro with a write combining video driver.
|
||||
|
||||
If you ever lose your mouse cursor inapropriately due to the game messing up, if you can restart QuakeWorld, you can type "showmouse" to bump the visibility counter by one.
|
||||
|
||||
You should eb able to connect to any QuakeWorld server, but you will have to do it with manual connect commands at the console, because we don't have either qspy or a browser plugin (yet) for openstep to find servers.
|
||||
|
||||
Because the configuration ranges are different than windows, things like sensitivity and volume will need to be specified at the console.
|
||||
|
||||
Some typical values (all of these should be saved automatically in the config file):
|
||||
|
||||
vid_mode 1
|
||||
Sets 320*240 resolution. 320*200 (vid_mode 0) is somewhat faster, but looks scrunched at some desktop resolutions.
|
||||
|
||||
vid_stretched 1
|
||||
Sets pixel doubling. Slower, of cource.
|
||||
|
||||
snd_mixahead 0.2
|
||||
Because this isn't very fast yet, you probably want to increase the mixahead from 0.1 so the sound doesn't break up.
|
||||
|
||||
volume 0.15
|
||||
The default 0.7 is VERY loud on my system. I don't know what it will be like on other systems.
|
||||
|
||||
gamma 1.4
|
||||
Because openstep desktops are typically gamma corrected, the game will look washed out with default settings. Geater than 1.0 gets darker, less than gets brighter.
|
||||
|
||||
sensitivity 20
|
||||
The normal slider range probably doesn't give enough speed for most people.
|
||||
|
||||
in_mouse 0
|
||||
The mouse is normally grabbed for controlling the game. Setting this to 0 will give the mouse back to the desktop.
|
||||
|
||||
|
||||
2151
rhapsody/snd_next.m
Normal file
2151
rhapsody/snd_next.m
Normal file
File diff suppressed because it is too large
Load Diff
580
rhapsody/swimp_rhap.m
Normal file
580
rhapsody/swimp_rhap.m
Normal file
@@ -0,0 +1,580 @@
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Interceptor/NSDirectScreen.h>
|
||||
#import <AppKit/NSColor.h>
|
||||
#include "../ref_soft/r_local.h"
|
||||
|
||||
@interface QuakeView : NSView
|
||||
@end
|
||||
|
||||
NSWindow *vid_window_i;
|
||||
QuakeView *vid_view_i;
|
||||
NSDirectScreen *vid_screen;
|
||||
byte *vid_buffer; // real framebuffer
|
||||
int vid_rowbytes; // framebuffer rowbytes
|
||||
|
||||
unsigned *buffernative; // 24 bit off-screen back buffer for window
|
||||
unsigned swimp_palette[256];
|
||||
|
||||
typedef enum {
|
||||
rhap_shutdown,
|
||||
rhap_windowed,
|
||||
rhap_fullscreen
|
||||
} rhapMode_t;
|
||||
|
||||
rhapMode_t rhap_mode;
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
FULLSCREEN
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** InitFullscreen
|
||||
*/
|
||||
rserr_t InitFullscreen (int width, int height)
|
||||
{
|
||||
NSDictionary *mode, *bestMode;
|
||||
int modeWidth, bestWidth;
|
||||
int modeHeight, bestHeight;
|
||||
NSArray *modes;
|
||||
int i;
|
||||
NSString *string;
|
||||
|
||||
|
||||
vid_screen = [[NSDirectScreen alloc] initWithScreen:[NSScreen mainScreen]];
|
||||
|
||||
// search for an apropriate mode
|
||||
modes = [vid_screen availableDisplayModes];
|
||||
bestMode = NULL;
|
||||
bestWidth = 99999;
|
||||
bestHeight = 99999;
|
||||
for (i=0 ; i<[modes count] ; i++) {
|
||||
mode = [modes objectAtIndex: i];
|
||||
string = [mode objectForKey: @"NSDirectScreenPixelEncoding"];
|
||||
if ( ![string isEqualToString: @"PPPPPPPP"] )
|
||||
continue; // only look at paletted modes
|
||||
modeWidth = [[mode objectForKey: @"NSDirectScreenWidth"] intValue];
|
||||
modeHeight = [[mode objectForKey: @"NSDirectScreenHeight"] intValue];
|
||||
if (modeWidth < width || modeHeight < height)
|
||||
continue;
|
||||
if (modeWidth < bestWidth) {
|
||||
bestWidth = modeWidth;
|
||||
bestHeight = modeHeight;
|
||||
bestMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
// if there wasn't any paletted mode of that res or greater, fail
|
||||
if (!bestMode)
|
||||
return rserr_invalid_fullscreen;
|
||||
|
||||
ri.Con_Printf (PRINT_ALL, "SheildDisplay\n");
|
||||
[vid_screen shieldDisplay];
|
||||
|
||||
// hide the cursor in all fullscreen modes
|
||||
[NSCursor hide];
|
||||
|
||||
vid_window_i = [vid_screen shieldingWindow];
|
||||
|
||||
ri.Con_Printf (PRINT_ALL, "switchToDisplayMode\n");
|
||||
[vid_screen switchToDisplayMode:bestMode];
|
||||
// [vid_screen fadeDisplayOutToColor:[NSColor blackColor]];
|
||||
// [vid_screen fadeDisplayInFromColor:[NSColor blackColor]];
|
||||
|
||||
vid_buffer = [vid_screen data];
|
||||
vid_rowbytes = [vid_screen bytesPerRow];
|
||||
|
||||
return rserr_ok;
|
||||
}
|
||||
|
||||
void ShutdownFullscreen (void)
|
||||
{
|
||||
[vid_screen dealloc];
|
||||
[NSCursor unhide];
|
||||
}
|
||||
|
||||
void SetPaletteFullscreen (const unsigned char *palette) {
|
||||
#if 0
|
||||
byte *p;
|
||||
int i;
|
||||
NSDirectPalette *pal;
|
||||
|
||||
pal = [NSDirectPalette init];
|
||||
for (i=0 ; i<256 ; i++)
|
||||
[pal setRed: palette[0]*(1.0/255)
|
||||
green: palette[1]*(1.0/255)
|
||||
blue: palette[2]*(1.0/255)
|
||||
atIndex: i];
|
||||
[vid_screen setPalette: pal];
|
||||
[pal release];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BlitFullscreen (void)
|
||||
{
|
||||
int i, j;
|
||||
int w;
|
||||
int *dest, *source;
|
||||
|
||||
w = vid.width>>2;
|
||||
|
||||
source = (int *)vid.buffer; // off-screen buffer
|
||||
dest = (int *)vid_buffer; // directly on screen
|
||||
for (j=0 ; j<vid.height ; j++
|
||||
, source += (vid.rowbytes>>2), dest += (vid_rowbytes>>2) ) {
|
||||
for (i=0 ; i<w ; i++ ) {
|
||||
dest[i] = source[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
WINDOWED
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** InitWindowed
|
||||
*/
|
||||
rserr_t InitWindowed (int width, int height)
|
||||
{
|
||||
rserr_t retval = rserr_ok;
|
||||
NSRect content;
|
||||
cvar_t *vid_xpos;
|
||||
cvar_t *vid_ypos;
|
||||
|
||||
//
|
||||
// open a window
|
||||
//
|
||||
vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
|
||||
vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
|
||||
|
||||
content = NSMakeRect (vid_xpos->value,vid_ypos->value, width, height);
|
||||
vid_window_i = [[NSWindow alloc]
|
||||
initWithContentRect: content
|
||||
styleMask: NSTitledWindowMask
|
||||
backing: NSBackingStoreRetained
|
||||
defer: NO
|
||||
];
|
||||
|
||||
// [vid_window_i addToEventMask: NS_FLAGSCHANGEDMASK];
|
||||
[vid_window_i setTitle: @"Quake2"];
|
||||
|
||||
buffernative = malloc(width * height * 4);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ShutdownWindowed (void)
|
||||
{
|
||||
if (vid_window_i)
|
||||
{
|
||||
[vid_window_i release];
|
||||
vid_window_i = NULL;
|
||||
}
|
||||
if (buffernative)
|
||||
{
|
||||
free (buffernative);
|
||||
buffernative = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPaletteWindowed (const unsigned char *palette) {
|
||||
byte *p;
|
||||
int i;
|
||||
|
||||
p = (byte *)swimp_palette;
|
||||
for (i=0 ; i<256 ; i++, p+=4, palette+=4)
|
||||
{
|
||||
p[0] = palette[0];
|
||||
p[1] = palette[1];
|
||||
p[2] = palette[2];
|
||||
p[3] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BlitWindowed (void)
|
||||
{
|
||||
int i, c;
|
||||
int bps, spp, bpp, bpr;
|
||||
unsigned char *planes[5];
|
||||
NSRect bounds;
|
||||
|
||||
if (!vid_view_i)
|
||||
return;
|
||||
|
||||
// translate to 24 bit color
|
||||
c = vid.width*vid.height;
|
||||
for (i=0 ; i<c ; i++)
|
||||
buffernative[i] = swimp_palette[vid.buffer[i]];
|
||||
|
||||
bps = 8;
|
||||
spp = 3;
|
||||
bpp = 32;
|
||||
bpr = vid.width * 4;
|
||||
planes[0] = (unsigned char *)buffernative;
|
||||
|
||||
bounds = [vid_view_i bounds];
|
||||
|
||||
[vid_view_i lockFocus];
|
||||
|
||||
NSDrawBitmap(
|
||||
bounds,
|
||||
vid.width,
|
||||
vid.height,
|
||||
bps,
|
||||
spp,
|
||||
bpp,
|
||||
bpr,
|
||||
NO,
|
||||
NO,
|
||||
@"NSDeviceRGBColorSpace",
|
||||
planes
|
||||
);
|
||||
|
||||
[vid_view_i unlockFocus];
|
||||
PSWait ();
|
||||
}
|
||||
|
||||
|
||||
//======================================================================
|
||||
|
||||
/*
|
||||
** 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** SWimp_Init
|
||||
**
|
||||
** This routine is responsible for initializing the implementation
|
||||
** specific stuff in a software rendering subsystem.
|
||||
*/
|
||||
int SWimp_Init( void *hInstance, void *wndProc )
|
||||
{
|
||||
if (!NSApp)
|
||||
{
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp finishLaunching];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** SWimp_SetMode
|
||||
*/
|
||||
rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen)
|
||||
{
|
||||
const char *win_fs[] = { "W", "FS" };
|
||||
NSRect content;
|
||||
rserr_t ret;
|
||||
|
||||
// free resources in use
|
||||
SWimp_Shutdown ();
|
||||
|
||||
ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
|
||||
|
||||
if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
|
||||
return rserr_invalid_mode;
|
||||
}
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] );
|
||||
|
||||
vid.buffer = malloc(*pwidth * *pheight);
|
||||
vid.rowbytes = *pwidth;
|
||||
|
||||
if (fullscreen) {
|
||||
rhap_mode = rhap_fullscreen;
|
||||
ret = InitFullscreen (*pwidth, *pheight);
|
||||
} else {
|
||||
rhap_mode = rhap_windowed;
|
||||
ret = InitWindowed (*pwidth, *pheight);
|
||||
}
|
||||
|
||||
if (ret != rserr_ok) {
|
||||
SWimp_Shutdown ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** the view is identical in windowed and fullscreen modes
|
||||
*/
|
||||
content.origin.x = content.origin.y = 0;
|
||||
content.size.width = *pwidth;
|
||||
content.size.height = *pheight;
|
||||
vid_view_i = [[QuakeView alloc] initWithFrame: content];
|
||||
[vid_window_i setContentView: vid_view_i];
|
||||
[vid_window_i makeFirstResponder: vid_view_i];
|
||||
[vid_window_i setDelegate: vid_view_i];
|
||||
|
||||
[NSApp activateIgnoringOtherApps: YES];
|
||||
[vid_window_i makeKeyAndOrderFront: nil];
|
||||
[vid_window_i display];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** SWimp_Shutdown
|
||||
**
|
||||
** System specific graphics subsystem shutdown routine
|
||||
*/
|
||||
void SWimp_Shutdown( void )
|
||||
{
|
||||
if (rhap_mode == rhap_windowed)
|
||||
ShutdownWindowed ();
|
||||
else if (rhap_mode == rhap_fullscreen)
|
||||
ShutdownFullscreen ();
|
||||
|
||||
rhap_mode = rhap_shutdown;
|
||||
|
||||
if (vid.buffer)
|
||||
{
|
||||
free (vid.buffer);
|
||||
vid.buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
void SWimp_SetPalette( const unsigned char *palette )
|
||||
{
|
||||
if (rhap_mode == rhap_windowed)
|
||||
SetPaletteWindowed (palette);
|
||||
else if (rhap_mode == rhap_fullscreen)
|
||||
SetPaletteFullscreen (palette);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
void SWimp_EndFrame (void)
|
||||
{
|
||||
if (rhap_mode == rhap_windowed)
|
||||
BlitWindowed ();
|
||||
else if (rhap_mode == rhap_fullscreen)
|
||||
BlitFullscreen ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** SWimp_AppActivate
|
||||
*/
|
||||
void SWimp_AppActivate( qboolean active )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==========================================================================
|
||||
|
||||
NEXTSTEP VIEW CLASS
|
||||
|
||||
==========================================================================
|
||||
*/
|
||||
#include "../client/keys.h"
|
||||
|
||||
void IN_ActivateMouse (void);
|
||||
void IN_DeactivateMouse (void);
|
||||
|
||||
@implementation QuakeView
|
||||
|
||||
-(BOOL) acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)windowDidMove: (NSNotification *)note
|
||||
{
|
||||
NSRect r;
|
||||
|
||||
r = [vid_window_i frame];
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_xpos %i", (int)r.origin.x+1));
|
||||
ri.Cmd_ExecuteText (EXEC_NOW, va("vid_ypos %i", (int)r.origin.y+1));
|
||||
}
|
||||
|
||||
- (void)becomeKeyWindow
|
||||
{
|
||||
IN_ActivateMouse ();
|
||||
}
|
||||
|
||||
- (void)resignKeyWindow
|
||||
{
|
||||
IN_DeactivateMouse ();
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int source, dest;
|
||||
} keymap_t;
|
||||
|
||||
keymap_t keymaps[] =
|
||||
{
|
||||
{0xf703, K_RIGHTARROW},
|
||||
{0xf702, K_LEFTARROW},
|
||||
{0xf700, K_UPARROW},
|
||||
{0xf701, K_DOWNARROW},
|
||||
|
||||
{0xf704, K_F1},
|
||||
{0xf705, K_F2},
|
||||
{0xf706, K_F3},
|
||||
{0xf707, K_F4},
|
||||
{0xf708, K_F5},
|
||||
{0xf709, K_F6},
|
||||
{0xf70a, K_F7},
|
||||
{0xf70b, K_F8},
|
||||
{0xf70c, K_F9},
|
||||
{0xf70d, K_F10},
|
||||
{0xf70e, K_F11},
|
||||
{0xf70f, K_F12},
|
||||
|
||||
{-1,-1}
|
||||
};
|
||||
|
||||
keymap_t flagmaps[] =
|
||||
{
|
||||
{NSShiftKeyMask, K_SHIFT},
|
||||
{NSControlKeyMask, K_CTRL},
|
||||
{NSAlternateKeyMask, K_ALT},
|
||||
{NSCommandKeyMask, K_ALT},
|
||||
|
||||
{-1,-1}
|
||||
};
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE1, true, 0);
|
||||
}
|
||||
- (void)mouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE1, false, 0);
|
||||
}
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE2, true, 0);
|
||||
}
|
||||
- (void)rightMouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
Key_Event (K_MOUSE2, false, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
keyboard methods
|
||||
===================
|
||||
*/
|
||||
- (void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
int ch;
|
||||
keymap_t *km;
|
||||
|
||||
// PSobscurecursor ();
|
||||
|
||||
ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
// check for non-ascii first
|
||||
for (km=keymaps;km->source!=-1;km++)
|
||||
if (ch == km->source)
|
||||
{
|
||||
Key_Event (km->dest, true, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
ch += 'a' - 'A';
|
||||
if (ch>=256)
|
||||
return;
|
||||
|
||||
Key_Event (ch, true, 0);
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)theEvent
|
||||
{
|
||||
static int oldflags;
|
||||
int newflags;
|
||||
int delta;
|
||||
keymap_t *km;
|
||||
int i;
|
||||
|
||||
// PSobscurecursor ();
|
||||
newflags = [theEvent modifierFlags];
|
||||
delta = newflags ^ oldflags;
|
||||
for (i=0 ; i<32 ; i++)
|
||||
{
|
||||
if ( !(delta & (1<<i)))
|
||||
continue;
|
||||
// changed
|
||||
for (km=flagmaps;km->source!=-1;km++)
|
||||
if ( (1<<i) == km->source)
|
||||
{
|
||||
if (newflags & (1<<i))
|
||||
Key_Event (km->dest, true, 0);
|
||||
else
|
||||
Key_Event (km->dest, false, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
oldflags = newflags;
|
||||
}
|
||||
|
||||
|
||||
- (void)keyUp:(NSEvent *)theEvent
|
||||
{
|
||||
int ch;
|
||||
keymap_t *km;
|
||||
|
||||
ch = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
|
||||
// check for non-ascii first
|
||||
for (km=keymaps;km->source!=-1;km++)
|
||||
if (ch == km->source)
|
||||
{
|
||||
Key_Event (km->dest, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
ch += 'a' - 'A';
|
||||
if (ch>=256)
|
||||
return;
|
||||
Key_Event (ch, false, 0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
338
rhapsody/sys_rhap.m
Normal file
338
rhapsody/sys_rhap.m
Normal file
@@ -0,0 +1,338 @@
|
||||
#include <libc.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
int curtime;
|
||||
int sys_frame_time;
|
||||
|
||||
void Sys_UnloadGame (void)
|
||||
{
|
||||
}
|
||||
|
||||
void *GetGameAPI (void *import);
|
||||
|
||||
void *Sys_GetGameAPI (void *parms)
|
||||
{
|
||||
// we are hard-linked in, so no need to load anything
|
||||
return GetGameAPI (parms);
|
||||
}
|
||||
|
||||
void Sys_CopyProtect (void)
|
||||
{
|
||||
}
|
||||
|
||||
char *Sys_GetClipboardData( void )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
int hunkcount;
|
||||
|
||||
byte *membase;
|
||||
int hunkmaxsize;
|
||||
int cursize;
|
||||
|
||||
//#define VIRTUAL_ALLOC
|
||||
|
||||
void *Hunk_Begin (int maxsize)
|
||||
{
|
||||
// reserve a huge chunk of memory, but don't commit any yet
|
||||
cursize = 0;
|
||||
hunkmaxsize = maxsize;
|
||||
#ifdef VIRTUAL_ALLOC
|
||||
membase = VirtualAlloc (NULL, maxsize, MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
membase = malloc (maxsize);
|
||||
memset (membase, 0, maxsize);
|
||||
#endif
|
||||
if (!membase)
|
||||
Sys_Error ("VirtualAlloc reserve failed");
|
||||
return (void *)membase;
|
||||
}
|
||||
|
||||
void *Hunk_Alloc (int size)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
// round to cacheline
|
||||
size = (size+31)&~31;
|
||||
|
||||
#ifdef VIRTUAL_ALLOC
|
||||
// commit pages as needed
|
||||
// buf = VirtualAlloc (membase+cursize, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
buf = VirtualAlloc (membase, cursize+size, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (!buf)
|
||||
{
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
|
||||
Sys_Error ("VirtualAlloc commit failed.\n%s", buf);
|
||||
}
|
||||
#endif
|
||||
cursize += size;
|
||||
if (cursize > hunkmaxsize)
|
||||
Sys_Error ("Hunk_Alloc overflow");
|
||||
|
||||
return (void *)(membase+cursize-size);
|
||||
}
|
||||
|
||||
int Hunk_End (void)
|
||||
{
|
||||
|
||||
// free the remaining unused virtual memory
|
||||
#if 0
|
||||
void *buf;
|
||||
|
||||
// write protect it
|
||||
buf = VirtualAlloc (membase, cursize, MEM_COMMIT, PAGE_READONLY);
|
||||
if (!buf)
|
||||
Sys_Error ("VirtualAlloc commit failed");
|
||||
#endif
|
||||
|
||||
hunkcount++;
|
||||
//Com_Printf ("hunkcount: %i\n", hunkcount);
|
||||
return cursize;
|
||||
}
|
||||
|
||||
void Hunk_Free (void *base)
|
||||
{
|
||||
if ( base )
|
||||
#ifdef VIRTUAL_ALLOC
|
||||
VirtualFree (base, 0, MEM_RELEASE);
|
||||
#else
|
||||
free (base);
|
||||
#endif
|
||||
|
||||
hunkcount--;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
|
||||
void Sys_Mkdir (char *path)
|
||||
{
|
||||
if (mkdir (path, 0777) != -1)
|
||||
return;
|
||||
if (errno != EEXIST)
|
||||
Com_Error (ERR_FATAL, "mkdir %s: %s",path, strerror(errno));
|
||||
}
|
||||
|
||||
char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *Sys_FindNext (unsigned musthave, unsigned canthave)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Sys_FindClose (void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Milliseconds
|
||||
================
|
||||
*/
|
||||
int Sys_Milliseconds (void)
|
||||
{
|
||||
struct timeval tp;
|
||||
struct timezone tzp;
|
||||
static int secbase;
|
||||
|
||||
gettimeofday(&tp, &tzp);
|
||||
|
||||
if (!secbase)
|
||||
{
|
||||
secbase = tp.tv_sec;
|
||||
return tp.tv_usec/1000;
|
||||
}
|
||||
|
||||
curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Error
|
||||
================
|
||||
*/
|
||||
void Sys_Error (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
// change stdin to non blocking
|
||||
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
|
||||
|
||||
va_start (argptr,error);
|
||||
vsprintf (string,error,argptr);
|
||||
va_end (argptr);
|
||||
printf ("Fatal error: %s\n",string);
|
||||
|
||||
if (!NSApp)
|
||||
{ // appkit isn't running, so don't try to pop up a panel
|
||||
exit (1);
|
||||
}
|
||||
NSRunAlertPanel (@"Fatal error",[NSString stringWithCString: string]
|
||||
,@"exit",NULL,NULL);
|
||||
[NSApp terminate: NULL];
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Printf
|
||||
================
|
||||
*/
|
||||
void Sys_ConsoleOutput (char *text)
|
||||
{
|
||||
char *t_p;
|
||||
int l, r;
|
||||
|
||||
l = strlen(text);
|
||||
t_p = text;
|
||||
|
||||
// make sure everything goes through, even though we are non-blocking
|
||||
while (l)
|
||||
{
|
||||
r = write (1, text, l);
|
||||
if (r != l)
|
||||
sleep (0);
|
||||
if (r > 0)
|
||||
{
|
||||
t_p += r;
|
||||
l -= r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Quit
|
||||
================
|
||||
*/
|
||||
void Sys_Quit (void)
|
||||
{
|
||||
// change stdin to blocking
|
||||
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
|
||||
|
||||
if (!NSApp)
|
||||
exit (0); // appkit isn't running
|
||||
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Init
|
||||
================
|
||||
*/
|
||||
void Sys_Init(void)
|
||||
{
|
||||
moncontrol(0); // turn off profiling except during real Quake work
|
||||
|
||||
// change stdin to non blocking
|
||||
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
|
||||
}
|
||||
|
||||
|
||||
extern NSWindow *vid_window_i;
|
||||
|
||||
void Sys_AppActivate (void)
|
||||
{
|
||||
[vid_window_i makeKeyAndOrderFront: nil];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_SendKeyEvents
|
||||
|
||||
service any pending appkit events
|
||||
================
|
||||
*/
|
||||
void Sys_SendKeyEvents (void)
|
||||
{
|
||||
NSEvent *event;
|
||||
NSDate *date;
|
||||
|
||||
date = [NSDate date];
|
||||
do
|
||||
{
|
||||
event = [NSApp
|
||||
nextEventMatchingMask: 0xffffffff
|
||||
untilDate: date
|
||||
inMode: @"NSDefaultRunLoopMode"
|
||||
dequeue: YES];
|
||||
if (event)
|
||||
[NSApp sendEvent: event];
|
||||
} while (event);
|
||||
|
||||
// grab frame time
|
||||
sys_frame_time = Sys_Milliseconds();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_ConsoleInput
|
||||
|
||||
Checks for a complete line of text typed in at the console, then forwards
|
||||
it to the host command processor
|
||||
================
|
||||
*/
|
||||
char *Sys_ConsoleInput (void)
|
||||
{
|
||||
static char text[256];
|
||||
int len;
|
||||
|
||||
len = read (0, text, sizeof(text));
|
||||
if (len < 1)
|
||||
return NULL;
|
||||
text[len-1] = 0; // rip off the /n and terminate
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
main
|
||||
=============
|
||||
*/
|
||||
void main (int argc, char **argv)
|
||||
{
|
||||
int frame;
|
||||
NSAutoreleasePool *pool;
|
||||
int oldtime, t;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
Qcommon_Init (argc, argv);
|
||||
|
||||
[pool release];
|
||||
|
||||
oldtime = Sys_Milliseconds ();
|
||||
while (1)
|
||||
{
|
||||
pool =[[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (++frame > 10)
|
||||
moncontrol(1);// profile only while we do each Quake frame
|
||||
|
||||
t = Sys_Milliseconds ();
|
||||
Qcommon_Frame (t - oldtime);
|
||||
oldtime = t;
|
||||
moncontrol(0);
|
||||
|
||||
[pool release];
|
||||
}
|
||||
}
|
||||
|
||||
1789
rhapsody/vid_next.m
Normal file
1789
rhapsody/vid_next.m
Normal file
File diff suppressed because it is too large
Load Diff
341
server/server.h
Normal file
341
server/server.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// server.h
|
||||
|
||||
|
||||
//define PARANOID // speed sapping error checking
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "../game/game.h"
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#define MAX_MASTERS 8 // max recipients for heartbeat packets
|
||||
|
||||
typedef enum {
|
||||
ss_dead, // no map loaded
|
||||
ss_loading, // spawning level edicts
|
||||
ss_game, // actively running
|
||||
ss_cinematic,
|
||||
ss_demo,
|
||||
ss_pic
|
||||
} server_state_t;
|
||||
// some qc commands are only valid before the server has finished
|
||||
// initializing (precache commands, static sounds / objects, etc)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
server_state_t state; // precache commands are only valid during load
|
||||
|
||||
qboolean attractloop; // running cinematics and demos for the local system only
|
||||
qboolean loadgame; // client begins should reuse existing entity
|
||||
|
||||
unsigned time; // always sv.framenum * 100 msec
|
||||
int framenum;
|
||||
|
||||
char name[MAX_QPATH]; // map name, or cinematic name
|
||||
struct cmodel_s *models[MAX_MODELS];
|
||||
|
||||
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
|
||||
entity_state_t baselines[MAX_EDICTS];
|
||||
|
||||
// the multicast buffer is used to send a message to a set of clients
|
||||
// it is only used to marshall data until SV_Multicast is called
|
||||
sizebuf_t multicast;
|
||||
byte multicast_buf[MAX_MSGLEN];
|
||||
|
||||
// demo server information
|
||||
FILE *demofile;
|
||||
qboolean timedemo; // don't time sync
|
||||
} server_t;
|
||||
|
||||
#define EDICT_NUM(n) ((edict_t *)((byte *)ge->edicts + ge->edict_size*(n)))
|
||||
#define NUM_FOR_EDICT(e) ( ((byte *)(e)-(byte *)ge->edicts ) / ge->edict_size)
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
cs_free, // can be reused for a new connection
|
||||
cs_zombie, // client has been disconnected, but don't reuse
|
||||
// connection for a couple seconds
|
||||
cs_connected, // has been assigned to a client_t, but not in game yet
|
||||
cs_spawned // client is fully in game
|
||||
} client_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int areabytes;
|
||||
byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits
|
||||
player_state_t ps;
|
||||
int num_entities;
|
||||
int first_entity; // into the circular sv_packet_entities[]
|
||||
int senttime; // for ping calculations
|
||||
} client_frame_t;
|
||||
|
||||
#define LATENCY_COUNTS 16
|
||||
#define RATE_MESSAGES 10
|
||||
|
||||
typedef struct client_s
|
||||
{
|
||||
client_state_t state;
|
||||
|
||||
char userinfo[MAX_INFO_STRING]; // name, etc
|
||||
|
||||
int lastframe; // for delta compression
|
||||
usercmd_t lastcmd; // for filling in big drops
|
||||
|
||||
int commandMsec; // every seconds this is reset, if user
|
||||
// commands exhaust it, assume time cheating
|
||||
|
||||
int frame_latency[LATENCY_COUNTS];
|
||||
int ping;
|
||||
|
||||
int message_size[RATE_MESSAGES]; // used to rate drop packets
|
||||
int rate;
|
||||
int surpressCount; // number of messages rate supressed
|
||||
|
||||
edict_t *edict; // EDICT_NUM(clientnum+1)
|
||||
char name[32]; // extracted from userinfo, high bits masked
|
||||
int messagelevel; // for filtering printed messages
|
||||
|
||||
// The datagram is written to by sound calls, prints, temp ents, etc.
|
||||
// It can be harmlessly overflowed.
|
||||
sizebuf_t datagram;
|
||||
byte datagram_buf[MAX_MSGLEN];
|
||||
|
||||
client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here
|
||||
|
||||
byte *download; // file being downloaded
|
||||
int downloadsize; // total bytes (can't use EOF because of paks)
|
||||
int downloadcount; // bytes sent
|
||||
|
||||
int lastmessage; // sv.framenum when packet was last received
|
||||
int lastconnect;
|
||||
|
||||
int challenge; // challenge of this user, randomly generated
|
||||
|
||||
netchan_t netchan;
|
||||
} client_t;
|
||||
|
||||
// a client can leave the server in one of four ways:
|
||||
// dropping properly by quiting or disconnecting
|
||||
// timing out if no valid messages are received for timeout.value seconds
|
||||
// getting kicked off by the server operator
|
||||
// a program error, like an overflowed reliable buffer
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// MAX_CHALLENGES is made large to prevent a denial
|
||||
// of service attack that could cycle all of them
|
||||
// out before legitimate users connected
|
||||
#define MAX_CHALLENGES 1024
|
||||
|
||||
typedef struct
|
||||
{
|
||||
netadr_t adr;
|
||||
int challenge;
|
||||
int time;
|
||||
} challenge_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean initialized; // sv_init has completed
|
||||
int realtime; // always increasing, no clamping, etc
|
||||
|
||||
char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base
|
||||
|
||||
int spawncount; // incremented each server start
|
||||
// used to check late spawns
|
||||
|
||||
client_t *clients; // [maxclients->value];
|
||||
int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES
|
||||
int next_client_entities; // next client_entity to use
|
||||
entity_state_t *client_entities; // [num_client_entities]
|
||||
|
||||
int last_heartbeat;
|
||||
|
||||
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
|
||||
|
||||
// serverrecord values
|
||||
FILE *demofile;
|
||||
sizebuf_t demo_multicast;
|
||||
byte demo_multicast_buf[MAX_MSGLEN];
|
||||
} server_static_t;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
extern netadr_t net_from;
|
||||
extern sizebuf_t net_message;
|
||||
|
||||
extern netadr_t master_adr[MAX_MASTERS]; // address of the master server
|
||||
|
||||
extern server_static_t svs; // persistant server info
|
||||
extern server_t sv; // local server
|
||||
|
||||
extern cvar_t *sv_paused;
|
||||
extern cvar_t *maxclients;
|
||||
extern cvar_t *sv_noreload; // don't reload level state when reentering
|
||||
extern cvar_t *sv_airaccelerate; // don't reload level state when reentering
|
||||
// development tool
|
||||
extern cvar_t *sv_enforcetime;
|
||||
|
||||
extern client_t *sv_client;
|
||||
extern edict_t *sv_player;
|
||||
|
||||
//===========================================================
|
||||
|
||||
//
|
||||
// sv_main.c
|
||||
//
|
||||
void SV_FinalMessage (char *message, qboolean reconnect);
|
||||
void SV_DropClient (client_t *drop);
|
||||
|
||||
int SV_ModelIndex (char *name);
|
||||
int SV_SoundIndex (char *name);
|
||||
int SV_ImageIndex (char *name);
|
||||
|
||||
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);
|
||||
|
||||
void SV_ExecuteUserCommand (char *s);
|
||||
void SV_InitOperatorCommands (void);
|
||||
|
||||
void SV_SendServerinfo (client_t *client);
|
||||
void SV_UserinfoChanged (client_t *cl);
|
||||
|
||||
|
||||
void Master_Heartbeat (void);
|
||||
void Master_Packet (void);
|
||||
|
||||
//
|
||||
// sv_init.c
|
||||
//
|
||||
void SV_InitGame (void);
|
||||
void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame);
|
||||
|
||||
|
||||
//
|
||||
// sv_phys.c
|
||||
//
|
||||
void SV_PrepWorldFrame (void);
|
||||
|
||||
//
|
||||
// sv_send.c
|
||||
//
|
||||
typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t;
|
||||
#define SV_OUTPUTBUF_LENGTH (MAX_MSGLEN - 16)
|
||||
|
||||
extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
|
||||
|
||||
void SV_FlushRedirect (int sv_redirected, char *outputbuf);
|
||||
|
||||
void SV_DemoCompleted (void);
|
||||
void SV_SendClientMessages (void);
|
||||
|
||||
void SV_Multicast (vec3_t origin, multicast_t to);
|
||||
void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
|
||||
int soundindex, float volume,
|
||||
float attenuation, float timeofs);
|
||||
void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...);
|
||||
void SV_BroadcastPrintf (int level, char *fmt, ...);
|
||||
void SV_BroadcastCommand (char *fmt, ...);
|
||||
|
||||
//
|
||||
// sv_user.c
|
||||
//
|
||||
void SV_Nextserver (void);
|
||||
void SV_ExecuteClientMessage (client_t *cl);
|
||||
|
||||
//
|
||||
// sv_ccmds.c
|
||||
//
|
||||
void SV_ReadLevelFile (void);
|
||||
void SV_Status_f (void);
|
||||
|
||||
//
|
||||
// sv_ents.c
|
||||
//
|
||||
void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg);
|
||||
void SV_RecordDemoMessage (void);
|
||||
void SV_BuildClientFrame (client_t *client);
|
||||
|
||||
|
||||
void SV_Error (char *error, ...);
|
||||
|
||||
//
|
||||
// sv_game.c
|
||||
//
|
||||
extern game_export_t *ge;
|
||||
|
||||
void SV_InitGameProgs (void);
|
||||
void SV_ShutdownGameProgs (void);
|
||||
void SV_InitEdict (edict_t *e);
|
||||
|
||||
|
||||
|
||||
//============================================================
|
||||
|
||||
//
|
||||
// high level object sorting to reduce interaction tests
|
||||
//
|
||||
|
||||
void SV_ClearWorld (void);
|
||||
// called after the world model has been loaded, before linking any entities
|
||||
|
||||
void SV_UnlinkEdict (edict_t *ent);
|
||||
// call before removing an entity, and before trying to move one,
|
||||
// so it doesn't clip against itself
|
||||
|
||||
void SV_LinkEdict (edict_t *ent);
|
||||
// Needs to be called any time an entity changes origin, mins, maxs,
|
||||
// or solid. Automatically unlinks if needed.
|
||||
// sets ent->v.absmin and ent->v.absmax
|
||||
// sets ent->leafnums[] for pvs determination even if the entity
|
||||
// is not solid
|
||||
|
||||
int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
|
||||
// fills in a table of edict pointers with edicts that have bounding boxes
|
||||
// that intersect the given area. It is possible for a non-axial bmodel
|
||||
// to be returned that doesn't actually intersect the area on an exact
|
||||
// test.
|
||||
// returns the number of pointers filled in
|
||||
// ??? does this always return the world?
|
||||
|
||||
//===================================================================
|
||||
|
||||
//
|
||||
// functions that interact with everything apropriate
|
||||
//
|
||||
int SV_PointContents (vec3_t p);
|
||||
// returns the CONTENTS_* value from the world at the given point.
|
||||
// Quake 2 extends this to also check entities, to allow moving liquids
|
||||
|
||||
|
||||
trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask);
|
||||
// mins and maxs are relative
|
||||
|
||||
// if the entire move stays in a solid volume, trace.allsolid will be set,
|
||||
// trace.startsolid will be set, and trace.fraction will be 0
|
||||
|
||||
// if the starting point is in a solid, it will be allowed to move out
|
||||
// to an open area
|
||||
|
||||
// passedict is explicitly excluded from clipping checks (normally NULL)
|
||||
|
||||
1050
server/sv_ccmds.c
Normal file
1050
server/sv_ccmds.c
Normal file
File diff suppressed because it is too large
Load Diff
727
server/sv_ents.c
Normal file
727
server/sv_ents.c
Normal file
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
Encode a client frame onto the network channel
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
// because there can be a lot of projectiles, there is a special
|
||||
// network protocol for them
|
||||
#define MAX_PROJECTILES 64
|
||||
edict_t *projectiles[MAX_PROJECTILES];
|
||||
int numprojs;
|
||||
cvar_t *sv_projectiles;
|
||||
|
||||
qboolean SV_AddProjectileUpdate (edict_t *ent)
|
||||
{
|
||||
if (!sv_projectiles)
|
||||
sv_projectiles = Cvar_Get("sv_projectiles", "1", 0);
|
||||
|
||||
if (!sv_projectiles->value)
|
||||
return false;
|
||||
|
||||
if (!(ent->svflags & SVF_PROJECTILE))
|
||||
return false;
|
||||
if (numprojs == MAX_PROJECTILES)
|
||||
return true;
|
||||
|
||||
projectiles[numprojs++] = ent;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SV_EmitProjectileUpdate (sizebuf_t *msg)
|
||||
{
|
||||
byte bits[16]; // [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2]
|
||||
int n, i;
|
||||
edict_t *ent;
|
||||
int x, y, z, p, yaw;
|
||||
int len;
|
||||
|
||||
if (!numprojs)
|
||||
return;
|
||||
|
||||
MSG_WriteByte (msg, numprojs);
|
||||
|
||||
for (n=0 ; n<numprojs ; n++)
|
||||
{
|
||||
ent = projectiles[n];
|
||||
x = (int)(ent->s.origin[0]+4096)>>1;
|
||||
y = (int)(ent->s.origin[1]+4096)>>1;
|
||||
z = (int)(ent->s.origin[2]+4096)>>1;
|
||||
p = (int)(256*ent->s.angles[0]/360)&255;
|
||||
yaw = (int)(256*ent->s.angles[1]/360)&255;
|
||||
|
||||
len = 0;
|
||||
bits[len++] = x;
|
||||
bits[len++] = (x>>8) | (y<<4);
|
||||
bits[len++] = (y>>4);
|
||||
bits[len++] = z;
|
||||
bits[len++] = (z>>8);
|
||||
if (ent->s.effects & EF_BLASTER)
|
||||
bits[len-1] |= 64;
|
||||
|
||||
if (ent->s.old_origin[0] != ent->s.origin[0] ||
|
||||
ent->s.old_origin[1] != ent->s.origin[1] ||
|
||||
ent->s.old_origin[2] != ent->s.origin[2]) {
|
||||
bits[len-1] |= 128;
|
||||
x = (int)(ent->s.old_origin[0]+4096)>>1;
|
||||
y = (int)(ent->s.old_origin[1]+4096)>>1;
|
||||
z = (int)(ent->s.old_origin[2]+4096)>>1;
|
||||
bits[len++] = x;
|
||||
bits[len++] = (x>>8) | (y<<4);
|
||||
bits[len++] = (y>>4);
|
||||
bits[len++] = z;
|
||||
bits[len++] = (z>>8);
|
||||
}
|
||||
|
||||
bits[len++] = p;
|
||||
bits[len++] = yaw;
|
||||
bits[len++] = ent->s.modelindex;
|
||||
|
||||
bits[len++] = (ent->s.number & 0x7f);
|
||||
if (ent->s.number > 255) {
|
||||
bits[len-1] |= 128;
|
||||
bits[len++] = (ent->s.number >> 7);
|
||||
}
|
||||
|
||||
for (i=0 ; i<len ; i++)
|
||||
MSG_WriteByte (msg, bits[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_EmitPacketEntities
|
||||
|
||||
Writes a delta update of an entity_state_t list to the message.
|
||||
=============
|
||||
*/
|
||||
void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
|
||||
{
|
||||
entity_state_t *oldent, *newent;
|
||||
int oldindex, newindex;
|
||||
int oldnum, newnum;
|
||||
int from_num_entities;
|
||||
int bits;
|
||||
|
||||
#if 0
|
||||
if (numprojs)
|
||||
MSG_WriteByte (msg, svc_packetentities2);
|
||||
else
|
||||
#endif
|
||||
MSG_WriteByte (msg, svc_packetentities);
|
||||
|
||||
if (!from)
|
||||
from_num_entities = 0;
|
||||
else
|
||||
from_num_entities = from->num_entities;
|
||||
|
||||
newindex = 0;
|
||||
oldindex = 0;
|
||||
while (newindex < to->num_entities || oldindex < from_num_entities)
|
||||
{
|
||||
if (newindex >= to->num_entities)
|
||||
newnum = 9999;
|
||||
else
|
||||
{
|
||||
newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
|
||||
newnum = newent->number;
|
||||
}
|
||||
|
||||
if (oldindex >= from_num_entities)
|
||||
oldnum = 9999;
|
||||
else
|
||||
{
|
||||
oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
|
||||
oldnum = oldent->number;
|
||||
}
|
||||
|
||||
if (newnum == oldnum)
|
||||
{ // delta update from old position
|
||||
// because the force parm is false, this will not result
|
||||
// in any bytes being emited if the entity has not changed at all
|
||||
// note that players are always 'newentities', this updates their oldorigin always
|
||||
// and prevents warping
|
||||
MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
|
||||
oldindex++;
|
||||
newindex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newnum < oldnum)
|
||||
{ // this is a new entity, send it from the baseline
|
||||
MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
|
||||
newindex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newnum > oldnum)
|
||||
{ // the old entity isn't present in the new message
|
||||
bits = U_REMOVE;
|
||||
if (oldnum >= 256)
|
||||
bits |= U_NUMBER16 | U_MOREBITS1;
|
||||
|
||||
MSG_WriteByte (msg, bits&255 );
|
||||
if (bits & 0x0000ff00)
|
||||
MSG_WriteByte (msg, (bits>>8)&255 );
|
||||
|
||||
if (bits & U_NUMBER16)
|
||||
MSG_WriteShort (msg, oldnum);
|
||||
else
|
||||
MSG_WriteByte (msg, oldnum);
|
||||
|
||||
oldindex++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
MSG_WriteShort (msg, 0); // end of packetentities
|
||||
|
||||
#if 0
|
||||
if (numprojs)
|
||||
SV_EmitProjectileUpdate(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_WritePlayerstateToClient
|
||||
|
||||
=============
|
||||
*/
|
||||
void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
|
||||
{
|
||||
int i;
|
||||
int pflags;
|
||||
player_state_t *ps, *ops;
|
||||
player_state_t dummy;
|
||||
int statbits;
|
||||
|
||||
ps = &to->ps;
|
||||
if (!from)
|
||||
{
|
||||
memset (&dummy, 0, sizeof(dummy));
|
||||
ops = &dummy;
|
||||
}
|
||||
else
|
||||
ops = &from->ps;
|
||||
|
||||
//
|
||||
// determine what needs to be sent
|
||||
//
|
||||
pflags = 0;
|
||||
|
||||
if (ps->pmove.pm_type != ops->pmove.pm_type)
|
||||
pflags |= PS_M_TYPE;
|
||||
|
||||
if (ps->pmove.origin[0] != ops->pmove.origin[0]
|
||||
|| ps->pmove.origin[1] != ops->pmove.origin[1]
|
||||
|| ps->pmove.origin[2] != ops->pmove.origin[2] )
|
||||
pflags |= PS_M_ORIGIN;
|
||||
|
||||
if (ps->pmove.velocity[0] != ops->pmove.velocity[0]
|
||||
|| ps->pmove.velocity[1] != ops->pmove.velocity[1]
|
||||
|| ps->pmove.velocity[2] != ops->pmove.velocity[2] )
|
||||
pflags |= PS_M_VELOCITY;
|
||||
|
||||
if (ps->pmove.pm_time != ops->pmove.pm_time)
|
||||
pflags |= PS_M_TIME;
|
||||
|
||||
if (ps->pmove.pm_flags != ops->pmove.pm_flags)
|
||||
pflags |= PS_M_FLAGS;
|
||||
|
||||
if (ps->pmove.gravity != ops->pmove.gravity)
|
||||
pflags |= PS_M_GRAVITY;
|
||||
|
||||
if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0]
|
||||
|| ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1]
|
||||
|| ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] )
|
||||
pflags |= PS_M_DELTA_ANGLES;
|
||||
|
||||
|
||||
if (ps->viewoffset[0] != ops->viewoffset[0]
|
||||
|| ps->viewoffset[1] != ops->viewoffset[1]
|
||||
|| ps->viewoffset[2] != ops->viewoffset[2] )
|
||||
pflags |= PS_VIEWOFFSET;
|
||||
|
||||
if (ps->viewangles[0] != ops->viewangles[0]
|
||||
|| ps->viewangles[1] != ops->viewangles[1]
|
||||
|| ps->viewangles[2] != ops->viewangles[2] )
|
||||
pflags |= PS_VIEWANGLES;
|
||||
|
||||
if (ps->kick_angles[0] != ops->kick_angles[0]
|
||||
|| ps->kick_angles[1] != ops->kick_angles[1]
|
||||
|| ps->kick_angles[2] != ops->kick_angles[2] )
|
||||
pflags |= PS_KICKANGLES;
|
||||
|
||||
if (ps->blend[0] != ops->blend[0]
|
||||
|| ps->blend[1] != ops->blend[1]
|
||||
|| ps->blend[2] != ops->blend[2]
|
||||
|| ps->blend[3] != ops->blend[3] )
|
||||
pflags |= PS_BLEND;
|
||||
|
||||
if (ps->fov != ops->fov)
|
||||
pflags |= PS_FOV;
|
||||
|
||||
if (ps->rdflags != ops->rdflags)
|
||||
pflags |= PS_RDFLAGS;
|
||||
|
||||
if (ps->gunframe != ops->gunframe)
|
||||
pflags |= PS_WEAPONFRAME;
|
||||
|
||||
pflags |= PS_WEAPONINDEX;
|
||||
|
||||
//
|
||||
// write it
|
||||
//
|
||||
MSG_WriteByte (msg, svc_playerinfo);
|
||||
MSG_WriteShort (msg, pflags);
|
||||
|
||||
//
|
||||
// write the pmove_state_t
|
||||
//
|
||||
if (pflags & PS_M_TYPE)
|
||||
MSG_WriteByte (msg, ps->pmove.pm_type);
|
||||
|
||||
if (pflags & PS_M_ORIGIN)
|
||||
{
|
||||
MSG_WriteShort (msg, ps->pmove.origin[0]);
|
||||
MSG_WriteShort (msg, ps->pmove.origin[1]);
|
||||
MSG_WriteShort (msg, ps->pmove.origin[2]);
|
||||
}
|
||||
|
||||
if (pflags & PS_M_VELOCITY)
|
||||
{
|
||||
MSG_WriteShort (msg, ps->pmove.velocity[0]);
|
||||
MSG_WriteShort (msg, ps->pmove.velocity[1]);
|
||||
MSG_WriteShort (msg, ps->pmove.velocity[2]);
|
||||
}
|
||||
|
||||
if (pflags & PS_M_TIME)
|
||||
MSG_WriteByte (msg, ps->pmove.pm_time);
|
||||
|
||||
if (pflags & PS_M_FLAGS)
|
||||
MSG_WriteByte (msg, ps->pmove.pm_flags);
|
||||
|
||||
if (pflags & PS_M_GRAVITY)
|
||||
MSG_WriteShort (msg, ps->pmove.gravity);
|
||||
|
||||
if (pflags & PS_M_DELTA_ANGLES)
|
||||
{
|
||||
MSG_WriteShort (msg, ps->pmove.delta_angles[0]);
|
||||
MSG_WriteShort (msg, ps->pmove.delta_angles[1]);
|
||||
MSG_WriteShort (msg, ps->pmove.delta_angles[2]);
|
||||
}
|
||||
|
||||
//
|
||||
// write the rest of the player_state_t
|
||||
//
|
||||
if (pflags & PS_VIEWOFFSET)
|
||||
{
|
||||
MSG_WriteChar (msg, ps->viewoffset[0]*4);
|
||||
MSG_WriteChar (msg, ps->viewoffset[1]*4);
|
||||
MSG_WriteChar (msg, ps->viewoffset[2]*4);
|
||||
}
|
||||
|
||||
if (pflags & PS_VIEWANGLES)
|
||||
{
|
||||
MSG_WriteAngle16 (msg, ps->viewangles[0]);
|
||||
MSG_WriteAngle16 (msg, ps->viewangles[1]);
|
||||
MSG_WriteAngle16 (msg, ps->viewangles[2]);
|
||||
}
|
||||
|
||||
if (pflags & PS_KICKANGLES)
|
||||
{
|
||||
MSG_WriteChar (msg, ps->kick_angles[0]*4);
|
||||
MSG_WriteChar (msg, ps->kick_angles[1]*4);
|
||||
MSG_WriteChar (msg, ps->kick_angles[2]*4);
|
||||
}
|
||||
|
||||
if (pflags & PS_WEAPONINDEX)
|
||||
{
|
||||
MSG_WriteByte (msg, ps->gunindex);
|
||||
}
|
||||
|
||||
if (pflags & PS_WEAPONFRAME)
|
||||
{
|
||||
MSG_WriteByte (msg, ps->gunframe);
|
||||
MSG_WriteChar (msg, ps->gunoffset[0]*4);
|
||||
MSG_WriteChar (msg, ps->gunoffset[1]*4);
|
||||
MSG_WriteChar (msg, ps->gunoffset[2]*4);
|
||||
MSG_WriteChar (msg, ps->gunangles[0]*4);
|
||||
MSG_WriteChar (msg, ps->gunangles[1]*4);
|
||||
MSG_WriteChar (msg, ps->gunangles[2]*4);
|
||||
}
|
||||
|
||||
if (pflags & PS_BLEND)
|
||||
{
|
||||
MSG_WriteByte (msg, ps->blend[0]*255);
|
||||
MSG_WriteByte (msg, ps->blend[1]*255);
|
||||
MSG_WriteByte (msg, ps->blend[2]*255);
|
||||
MSG_WriteByte (msg, ps->blend[3]*255);
|
||||
}
|
||||
if (pflags & PS_FOV)
|
||||
MSG_WriteByte (msg, ps->fov);
|
||||
if (pflags & PS_RDFLAGS)
|
||||
MSG_WriteByte (msg, ps->rdflags);
|
||||
|
||||
// send stats
|
||||
statbits = 0;
|
||||
for (i=0 ; i<MAX_STATS ; i++)
|
||||
if (ps->stats[i] != ops->stats[i])
|
||||
statbits |= 1<<i;
|
||||
MSG_WriteLong (msg, statbits);
|
||||
for (i=0 ; i<MAX_STATS ; i++)
|
||||
if (statbits & (1<<i) )
|
||||
MSG_WriteShort (msg, ps->stats[i]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_WriteFrameToClient
|
||||
==================
|
||||
*/
|
||||
void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg)
|
||||
{
|
||||
client_frame_t *frame, *oldframe;
|
||||
int lastframe;
|
||||
|
||||
//Com_Printf ("%i -> %i\n", client->lastframe, sv.framenum);
|
||||
// this is the frame we are creating
|
||||
frame = &client->frames[sv.framenum & UPDATE_MASK];
|
||||
|
||||
if (client->lastframe <= 0)
|
||||
{ // client is asking for a retransmit
|
||||
oldframe = NULL;
|
||||
lastframe = -1;
|
||||
}
|
||||
else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
|
||||
{ // client hasn't gotten a good message through in a long time
|
||||
// Com_Printf ("%s: Delta request from out-of-date packet.\n", client->name);
|
||||
oldframe = NULL;
|
||||
lastframe = -1;
|
||||
}
|
||||
else
|
||||
{ // we have a valid message to delta from
|
||||
oldframe = &client->frames[client->lastframe & UPDATE_MASK];
|
||||
lastframe = client->lastframe;
|
||||
}
|
||||
|
||||
MSG_WriteByte (msg, svc_frame);
|
||||
MSG_WriteLong (msg, sv.framenum);
|
||||
MSG_WriteLong (msg, lastframe); // what we are delta'ing from
|
||||
MSG_WriteByte (msg, client->surpressCount); // rate dropped packets
|
||||
client->surpressCount = 0;
|
||||
|
||||
// send over the areabits
|
||||
MSG_WriteByte (msg, frame->areabytes);
|
||||
SZ_Write (msg, frame->areabits, frame->areabytes);
|
||||
|
||||
// delta encode the playerstate
|
||||
SV_WritePlayerstateToClient (oldframe, frame, msg);
|
||||
|
||||
// delta encode the entities
|
||||
SV_EmitPacketEntities (oldframe, frame, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
Build a client frame structure
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
byte fatpvs[65536/8]; // 32767 is MAX_MAP_LEAFS
|
||||
|
||||
/*
|
||||
============
|
||||
SV_FatPVS
|
||||
|
||||
The client will interpolate the view position,
|
||||
so we can't use a single PVS point
|
||||
===========
|
||||
*/
|
||||
void SV_FatPVS (vec3_t org)
|
||||
{
|
||||
int leafs[64];
|
||||
int i, j, count;
|
||||
int longs;
|
||||
byte *src;
|
||||
vec3_t mins, maxs;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
mins[i] = org[i] - 8;
|
||||
maxs[i] = org[i] + 8;
|
||||
}
|
||||
|
||||
count = CM_BoxLeafnums (mins, maxs, leafs, 64, NULL);
|
||||
if (count < 1)
|
||||
Com_Error (ERR_FATAL, "SV_FatPVS: count < 1");
|
||||
longs = (CM_NumClusters()+31)>>5;
|
||||
|
||||
// convert leafs to clusters
|
||||
for (i=0 ; i<count ; i++)
|
||||
leafs[i] = CM_LeafCluster(leafs[i]);
|
||||
|
||||
memcpy (fatpvs, CM_ClusterPVS(leafs[0]), longs<<2);
|
||||
// or in all the other leaf bits
|
||||
for (i=1 ; i<count ; i++)
|
||||
{
|
||||
for (j=0 ; j<i ; j++)
|
||||
if (leafs[i] == leafs[j])
|
||||
break;
|
||||
if (j != i)
|
||||
continue; // already have the cluster we want
|
||||
src = CM_ClusterPVS(leafs[i]);
|
||||
for (j=0 ; j<longs ; j++)
|
||||
((long *)fatpvs)[j] |= ((long *)src)[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_BuildClientFrame
|
||||
|
||||
Decides which entities are going to be visible to the client, and
|
||||
copies off the playerstat and areabits.
|
||||
=============
|
||||
*/
|
||||
void SV_BuildClientFrame (client_t *client)
|
||||
{
|
||||
int e, i;
|
||||
vec3_t org;
|
||||
edict_t *ent;
|
||||
edict_t *clent;
|
||||
client_frame_t *frame;
|
||||
entity_state_t *state;
|
||||
int l;
|
||||
int clientarea, clientcluster;
|
||||
int leafnum;
|
||||
int c_fullsend;
|
||||
byte *clientphs;
|
||||
byte *bitvector;
|
||||
|
||||
clent = client->edict;
|
||||
if (!clent->client)
|
||||
return; // not in game yet
|
||||
|
||||
#if 0
|
||||
numprojs = 0; // no projectiles yet
|
||||
#endif
|
||||
|
||||
// this is the frame we are creating
|
||||
frame = &client->frames[sv.framenum & UPDATE_MASK];
|
||||
|
||||
frame->senttime = svs.realtime; // save it for ping calc later
|
||||
|
||||
// find the client's PVS
|
||||
for (i=0 ; i<3 ; i++)
|
||||
org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];
|
||||
|
||||
leafnum = CM_PointLeafnum (org);
|
||||
clientarea = CM_LeafArea (leafnum);
|
||||
clientcluster = CM_LeafCluster (leafnum);
|
||||
|
||||
// calculate the visible areas
|
||||
frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea);
|
||||
|
||||
// grab the current player_state_t
|
||||
frame->ps = clent->client->ps;
|
||||
|
||||
|
||||
SV_FatPVS (org);
|
||||
clientphs = CM_ClusterPHS (clientcluster);
|
||||
|
||||
// build up the list of visible entities
|
||||
frame->num_entities = 0;
|
||||
frame->first_entity = svs.next_client_entities;
|
||||
|
||||
c_fullsend = 0;
|
||||
|
||||
for (e=1 ; e<ge->num_edicts ; e++)
|
||||
{
|
||||
ent = EDICT_NUM(e);
|
||||
|
||||
// ignore ents without visible models
|
||||
if (ent->svflags & SVF_NOCLIENT)
|
||||
continue;
|
||||
|
||||
// ignore ents without visible models unless they have an effect
|
||||
if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound
|
||||
&& !ent->s.event)
|
||||
continue;
|
||||
|
||||
// ignore if not touching a PV leaf
|
||||
if (ent != clent)
|
||||
{
|
||||
// check area
|
||||
if (!CM_AreasConnected (clientarea, ent->areanum))
|
||||
{ // doors can legally straddle two areas, so
|
||||
// we may need to check another one
|
||||
if (!ent->areanum2
|
||||
|| !CM_AreasConnected (clientarea, ent->areanum2))
|
||||
continue; // blocked by a door
|
||||
}
|
||||
|
||||
// beams just check one point for PHS
|
||||
if (ent->s.renderfx & RF_BEAM)
|
||||
{
|
||||
l = ent->clusternums[0];
|
||||
if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: if an ent has a model and a sound, but isn't
|
||||
// in the PVS, only the PHS, clear the model
|
||||
if (ent->s.sound)
|
||||
{
|
||||
bitvector = fatpvs; //clientphs;
|
||||
}
|
||||
else
|
||||
bitvector = fatpvs;
|
||||
|
||||
if (ent->num_clusters == -1)
|
||||
{ // too many leafs for individual check, go by headnode
|
||||
if (!CM_HeadnodeVisible (ent->headnode, bitvector))
|
||||
continue;
|
||||
c_fullsend++;
|
||||
}
|
||||
else
|
||||
{ // check individual leafs
|
||||
for (i=0 ; i < ent->num_clusters ; i++)
|
||||
{
|
||||
l = ent->clusternums[i];
|
||||
if (bitvector[l >> 3] & (1 << (l&7) ))
|
||||
break;
|
||||
}
|
||||
if (i == ent->num_clusters)
|
||||
continue; // not visible
|
||||
}
|
||||
|
||||
if (!ent->s.modelindex)
|
||||
{ // don't send sounds if they will be attenuated away
|
||||
vec3_t delta;
|
||||
float len;
|
||||
|
||||
VectorSubtract (org, ent->s.origin, delta);
|
||||
len = VectorLength (delta);
|
||||
if (len > 400)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (SV_AddProjectileUpdate(ent))
|
||||
continue; // added as a special projectile
|
||||
#endif
|
||||
|
||||
// add it to the circular client_entities array
|
||||
state = &svs.client_entities[svs.next_client_entities%svs.num_client_entities];
|
||||
if (ent->s.number != e)
|
||||
{
|
||||
Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
|
||||
ent->s.number = e;
|
||||
}
|
||||
*state = ent->s;
|
||||
|
||||
// don't mark players missiles as solid
|
||||
if (ent->owner == client->edict)
|
||||
state->solid = 0;
|
||||
|
||||
svs.next_client_entities++;
|
||||
frame->num_entities++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_RecordDemoMessage
|
||||
|
||||
Save everything in the world out without deltas.
|
||||
Used for recording footage for merged or assembled demos
|
||||
==================
|
||||
*/
|
||||
void SV_RecordDemoMessage (void)
|
||||
{
|
||||
int e;
|
||||
edict_t *ent;
|
||||
entity_state_t nostate;
|
||||
sizebuf_t buf;
|
||||
byte buf_data[32768];
|
||||
int len;
|
||||
|
||||
if (!svs.demofile)
|
||||
return;
|
||||
|
||||
memset (&nostate, 0, sizeof(nostate));
|
||||
SZ_Init (&buf, buf_data, sizeof(buf_data));
|
||||
|
||||
// write a frame message that doesn't contain a player_state_t
|
||||
MSG_WriteByte (&buf, svc_frame);
|
||||
MSG_WriteLong (&buf, sv.framenum);
|
||||
|
||||
MSG_WriteByte (&buf, svc_packetentities);
|
||||
|
||||
e = 1;
|
||||
ent = EDICT_NUM(e);
|
||||
while (e < ge->num_edicts)
|
||||
{
|
||||
// ignore ents without visible models unless they have an effect
|
||||
if (ent->inuse &&
|
||||
ent->s.number &&
|
||||
(ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) &&
|
||||
!(ent->svflags & SVF_NOCLIENT))
|
||||
MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true);
|
||||
|
||||
e++;
|
||||
ent = EDICT_NUM(e);
|
||||
}
|
||||
|
||||
MSG_WriteShort (&buf, 0); // end of packetentities
|
||||
|
||||
// now add the accumulated multicast information
|
||||
SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
|
||||
SZ_Clear (&svs.demo_multicast);
|
||||
|
||||
// now write the entire message to the file, prefixed by the length
|
||||
len = LittleLong (buf.cursize);
|
||||
fwrite (&len, 4, 1, svs.demofile);
|
||||
fwrite (buf.data, buf.cursize, 1, svs.demofile);
|
||||
}
|
||||
|
||||
396
server/sv_game.c
Normal file
396
server/sv_game.c
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sv_game.c -- interface to the game dll
|
||||
|
||||
#include "server.h"
|
||||
|
||||
game_export_t *ge;
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_Unicast
|
||||
|
||||
Sends the contents of the mutlicast buffer to a single client
|
||||
===============
|
||||
*/
|
||||
void PF_Unicast (edict_t *ent, qboolean reliable)
|
||||
{
|
||||
int p;
|
||||
client_t *client;
|
||||
|
||||
if (!ent)
|
||||
return;
|
||||
|
||||
p = NUM_FOR_EDICT(ent);
|
||||
if (p < 1 || p > maxclients->value)
|
||||
return;
|
||||
|
||||
client = svs.clients + (p-1);
|
||||
|
||||
if (reliable)
|
||||
SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
|
||||
else
|
||||
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
|
||||
|
||||
SZ_Clear (&sv.multicast);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_dprintf
|
||||
|
||||
Debug print to server console
|
||||
===============
|
||||
*/
|
||||
void PF_dprintf (char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list argptr;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg, fmt, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Com_Printf ("%s", msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_cprintf
|
||||
|
||||
Print to a single client
|
||||
===============
|
||||
*/
|
||||
void PF_cprintf (edict_t *ent, int level, char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list argptr;
|
||||
int n;
|
||||
|
||||
if (ent)
|
||||
{
|
||||
n = NUM_FOR_EDICT(ent);
|
||||
if (n < 1 || n > maxclients->value)
|
||||
Com_Error (ERR_DROP, "cprintf to a non-client");
|
||||
}
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg, fmt, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
if (ent)
|
||||
SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg);
|
||||
else
|
||||
Com_Printf ("%s", msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_centerprintf
|
||||
|
||||
centerprint to a single client
|
||||
===============
|
||||
*/
|
||||
void PF_centerprintf (edict_t *ent, char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list argptr;
|
||||
int n;
|
||||
|
||||
n = NUM_FOR_EDICT(ent);
|
||||
if (n < 1 || n > maxclients->value)
|
||||
return; // Com_Error (ERR_DROP, "centerprintf to a non-client");
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg, fmt, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
MSG_WriteByte (&sv.multicast,svc_centerprint);
|
||||
MSG_WriteString (&sv.multicast,msg);
|
||||
PF_Unicast (ent, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_error
|
||||
|
||||
Abort the server with a game error
|
||||
===============
|
||||
*/
|
||||
void PF_error (char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list argptr;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg, fmt, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Com_Error (ERR_DROP, "Game Error: %s", msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
PF_setmodel
|
||||
|
||||
Also sets mins and maxs for inline bmodels
|
||||
=================
|
||||
*/
|
||||
void PF_setmodel (edict_t *ent, char *name)
|
||||
{
|
||||
int i;
|
||||
cmodel_t *mod;
|
||||
|
||||
if (!name)
|
||||
Com_Error (ERR_DROP, "PF_setmodel: NULL");
|
||||
|
||||
i = SV_ModelIndex (name);
|
||||
|
||||
// ent->model = name;
|
||||
ent->s.modelindex = i;
|
||||
|
||||
// if it is an inline model, get the size information for it
|
||||
if (name[0] == '*')
|
||||
{
|
||||
mod = CM_InlineModel (name);
|
||||
VectorCopy (mod->mins, ent->mins);
|
||||
VectorCopy (mod->maxs, ent->maxs);
|
||||
SV_LinkEdict (ent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
PF_Configstring
|
||||
|
||||
===============
|
||||
*/
|
||||
void PF_Configstring (int index, char *val)
|
||||
{
|
||||
if (index < 0 || index >= MAX_CONFIGSTRINGS)
|
||||
Com_Error (ERR_DROP, "configstring: bad index %i\n", index);
|
||||
|
||||
if (!val)
|
||||
val = "";
|
||||
|
||||
// change the string in sv
|
||||
strcpy (sv.configstrings[index], val);
|
||||
|
||||
if (sv.state != ss_loading)
|
||||
{ // send the update to everyone
|
||||
SZ_Clear (&sv.multicast);
|
||||
MSG_WriteChar (&sv.multicast, svc_configstring);
|
||||
MSG_WriteShort (&sv.multicast, index);
|
||||
MSG_WriteString (&sv.multicast, val);
|
||||
|
||||
SV_Multicast (vec3_origin, MULTICAST_ALL_R);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PF_WriteChar (int c) {MSG_WriteChar (&sv.multicast, c);}
|
||||
void PF_WriteByte (int c) {MSG_WriteByte (&sv.multicast, c);}
|
||||
void PF_WriteShort (int c) {MSG_WriteShort (&sv.multicast, c);}
|
||||
void PF_WriteLong (int c) {MSG_WriteLong (&sv.multicast, c);}
|
||||
void PF_WriteFloat (float f) {MSG_WriteFloat (&sv.multicast, f);}
|
||||
void PF_WriteString (char *s) {MSG_WriteString (&sv.multicast, s);}
|
||||
void PF_WritePos (vec3_t pos) {MSG_WritePos (&sv.multicast, pos);}
|
||||
void PF_WriteDir (vec3_t dir) {MSG_WriteDir (&sv.multicast, dir);}
|
||||
void PF_WriteAngle (float f) {MSG_WriteAngle (&sv.multicast, f);}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
PF_inPVS
|
||||
|
||||
Also checks portalareas so that doors block sight
|
||||
=================
|
||||
*/
|
||||
qboolean PF_inPVS (vec3_t p1, vec3_t p2)
|
||||
{
|
||||
int leafnum;
|
||||
int cluster;
|
||||
int area1, area2;
|
||||
byte *mask;
|
||||
|
||||
leafnum = CM_PointLeafnum (p1);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
area1 = CM_LeafArea (leafnum);
|
||||
mask = CM_ClusterPVS (cluster);
|
||||
|
||||
leafnum = CM_PointLeafnum (p2);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
area2 = CM_LeafArea (leafnum);
|
||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||
return false;
|
||||
if (!CM_AreasConnected (area1, area2))
|
||||
return false; // a door blocks sight
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
PF_inPHS
|
||||
|
||||
Also checks portalareas so that doors block sound
|
||||
=================
|
||||
*/
|
||||
qboolean PF_inPHS (vec3_t p1, vec3_t p2)
|
||||
{
|
||||
int leafnum;
|
||||
int cluster;
|
||||
int area1, area2;
|
||||
byte *mask;
|
||||
|
||||
leafnum = CM_PointLeafnum (p1);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
area1 = CM_LeafArea (leafnum);
|
||||
mask = CM_ClusterPHS (cluster);
|
||||
|
||||
leafnum = CM_PointLeafnum (p2);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
area2 = CM_LeafArea (leafnum);
|
||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||
return false; // more than one bounce away
|
||||
if (!CM_AreasConnected (area1, area2))
|
||||
return false; // a door blocks hearing
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume,
|
||||
float attenuation, float timeofs)
|
||||
{
|
||||
if (!entity)
|
||||
return;
|
||||
SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs);
|
||||
}
|
||||
|
||||
//==============================================
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_ShutdownGameProgs
|
||||
|
||||
Called when either the entire server is being killed, or
|
||||
it is changing to a different game directory.
|
||||
===============
|
||||
*/
|
||||
void SV_ShutdownGameProgs (void)
|
||||
{
|
||||
if (!ge)
|
||||
return;
|
||||
ge->Shutdown ();
|
||||
Sys_UnloadGame ();
|
||||
ge = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_InitGameProgs
|
||||
|
||||
Init the game subsystem for a new map
|
||||
===============
|
||||
*/
|
||||
void SCR_DebugGraph (float value, int color);
|
||||
|
||||
void SV_InitGameProgs (void)
|
||||
{
|
||||
game_import_t import;
|
||||
|
||||
// unload anything we have now
|
||||
if (ge)
|
||||
SV_ShutdownGameProgs ();
|
||||
|
||||
|
||||
// load a new game dll
|
||||
import.multicast = SV_Multicast;
|
||||
import.unicast = PF_Unicast;
|
||||
import.bprintf = SV_BroadcastPrintf;
|
||||
import.dprintf = PF_dprintf;
|
||||
import.cprintf = PF_cprintf;
|
||||
import.centerprintf = PF_centerprintf;
|
||||
import.error = PF_error;
|
||||
|
||||
import.linkentity = SV_LinkEdict;
|
||||
import.unlinkentity = SV_UnlinkEdict;
|
||||
import.BoxEdicts = SV_AreaEdicts;
|
||||
import.trace = SV_Trace;
|
||||
import.pointcontents = SV_PointContents;
|
||||
import.setmodel = PF_setmodel;
|
||||
import.inPVS = PF_inPVS;
|
||||
import.inPHS = PF_inPHS;
|
||||
import.Pmove = Pmove;
|
||||
|
||||
import.modelindex = SV_ModelIndex;
|
||||
import.soundindex = SV_SoundIndex;
|
||||
import.imageindex = SV_ImageIndex;
|
||||
|
||||
import.configstring = PF_Configstring;
|
||||
import.sound = PF_StartSound;
|
||||
import.positioned_sound = SV_StartSound;
|
||||
|
||||
import.WriteChar = PF_WriteChar;
|
||||
import.WriteByte = PF_WriteByte;
|
||||
import.WriteShort = PF_WriteShort;
|
||||
import.WriteLong = PF_WriteLong;
|
||||
import.WriteFloat = PF_WriteFloat;
|
||||
import.WriteString = PF_WriteString;
|
||||
import.WritePosition = PF_WritePos;
|
||||
import.WriteDir = PF_WriteDir;
|
||||
import.WriteAngle = PF_WriteAngle;
|
||||
|
||||
import.TagMalloc = Z_TagMalloc;
|
||||
import.TagFree = Z_Free;
|
||||
import.FreeTags = Z_FreeTags;
|
||||
|
||||
import.cvar = Cvar_Get;
|
||||
import.cvar_set = Cvar_Set;
|
||||
import.cvar_forceset = Cvar_ForceSet;
|
||||
|
||||
import.argc = Cmd_Argc;
|
||||
import.argv = Cmd_Argv;
|
||||
import.args = Cmd_Args;
|
||||
import.AddCommandString = Cbuf_AddText;
|
||||
|
||||
import.DebugGraph = SCR_DebugGraph;
|
||||
import.SetAreaPortalState = CM_SetAreaPortalState;
|
||||
import.AreasConnected = CM_AreasConnected;
|
||||
|
||||
ge = (game_export_t *)Sys_GetGameAPI (&import);
|
||||
|
||||
if (!ge)
|
||||
Com_Error (ERR_DROP, "failed to load game DLL");
|
||||
if (ge->apiversion != GAME_API_VERSION)
|
||||
Com_Error (ERR_DROP, "game is version %i, not %i", ge->apiversion,
|
||||
GAME_API_VERSION);
|
||||
|
||||
ge->Init ();
|
||||
}
|
||||
|
||||
465
server/sv_init.c
Normal file
465
server/sv_init.c
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
|
||||
server_static_t svs; // persistant server info
|
||||
server_t sv; // local server
|
||||
|
||||
/*
|
||||
================
|
||||
SV_FindIndex
|
||||
|
||||
================
|
||||
*/
|
||||
int SV_FindIndex (char *name, int start, int max, qboolean create)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name || !name[0])
|
||||
return 0;
|
||||
|
||||
for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
|
||||
if (!strcmp(sv.configstrings[start+i], name))
|
||||
return i;
|
||||
|
||||
if (!create)
|
||||
return 0;
|
||||
|
||||
if (i == max)
|
||||
Com_Error (ERR_DROP, "*Index: overflow");
|
||||
|
||||
strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
|
||||
|
||||
if (sv.state != ss_loading)
|
||||
{ // send the update to everyone
|
||||
SZ_Clear (&sv.multicast);
|
||||
MSG_WriteChar (&sv.multicast, svc_configstring);
|
||||
MSG_WriteShort (&sv.multicast, start+i);
|
||||
MSG_WriteString (&sv.multicast, name);
|
||||
SV_Multicast (vec3_origin, MULTICAST_ALL_R);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int SV_ModelIndex (char *name)
|
||||
{
|
||||
return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
|
||||
}
|
||||
|
||||
int SV_SoundIndex (char *name)
|
||||
{
|
||||
return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
|
||||
}
|
||||
|
||||
int SV_ImageIndex (char *name)
|
||||
{
|
||||
return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SV_CreateBaseline
|
||||
|
||||
Entity baselines are used to compress the update messages
|
||||
to the clients -- only the fields that differ from the
|
||||
baseline will be transmitted
|
||||
================
|
||||
*/
|
||||
void SV_CreateBaseline (void)
|
||||
{
|
||||
edict_t *svent;
|
||||
int entnum;
|
||||
|
||||
for (entnum = 1; entnum < ge->num_edicts ; entnum++)
|
||||
{
|
||||
svent = EDICT_NUM(entnum);
|
||||
if (!svent->inuse)
|
||||
continue;
|
||||
if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
|
||||
continue;
|
||||
svent->s.number = entnum;
|
||||
|
||||
//
|
||||
// take current state as baseline
|
||||
//
|
||||
VectorCopy (svent->s.origin, svent->s.old_origin);
|
||||
sv.baselines[entnum] = svent->s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_CheckForSavegame
|
||||
=================
|
||||
*/
|
||||
void SV_CheckForSavegame (void)
|
||||
{
|
||||
char name[MAX_OSPATH];
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
if (sv_noreload->value)
|
||||
return;
|
||||
|
||||
if (Cvar_VariableValue ("deathmatch"))
|
||||
return;
|
||||
|
||||
Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
|
||||
f = fopen (name, "rb");
|
||||
if (!f)
|
||||
return; // no savegame
|
||||
|
||||
fclose (f);
|
||||
|
||||
SV_ClearWorld ();
|
||||
|
||||
// get configstrings and areaportals
|
||||
SV_ReadLevelFile ();
|
||||
|
||||
if (!sv.loadgame)
|
||||
{ // coming back to a level after being in a different
|
||||
// level, so run it for ten seconds
|
||||
|
||||
// rlava2 was sending too many lightstyles, and overflowing the
|
||||
// reliable data. temporarily changing the server state to loading
|
||||
// prevents these from being passed down.
|
||||
server_state_t previousState; // PGM
|
||||
|
||||
previousState = sv.state; // PGM
|
||||
sv.state = ss_loading; // PGM
|
||||
for (i=0 ; i<100 ; i++)
|
||||
ge->RunFrame ();
|
||||
|
||||
sv.state = previousState; // PGM
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SV_SpawnServer
|
||||
|
||||
Change the server to a new map, taking all connected
|
||||
clients along with it.
|
||||
|
||||
================
|
||||
*/
|
||||
void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
|
||||
{
|
||||
int i;
|
||||
unsigned checksum;
|
||||
|
||||
if (attractloop)
|
||||
Cvar_Set ("paused", "0");
|
||||
|
||||
Com_Printf ("------- Server Initialization -------\n");
|
||||
|
||||
Com_DPrintf ("SpawnServer: %s\n",server);
|
||||
if (sv.demofile)
|
||||
fclose (sv.demofile);
|
||||
|
||||
svs.spawncount++; // any partially connected client will be
|
||||
// restarted
|
||||
sv.state = ss_dead;
|
||||
Com_SetServerState (sv.state);
|
||||
|
||||
// wipe the entire per-level structure
|
||||
memset (&sv, 0, sizeof(sv));
|
||||
svs.realtime = 0;
|
||||
sv.loadgame = loadgame;
|
||||
sv.attractloop = attractloop;
|
||||
|
||||
// save name for levels that don't set message
|
||||
strcpy (sv.configstrings[CS_NAME], server);
|
||||
if (Cvar_VariableValue ("deathmatch"))
|
||||
{
|
||||
sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
|
||||
pm_airaccelerate = sv_airaccelerate->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(sv.configstrings[CS_AIRACCEL], "0");
|
||||
pm_airaccelerate = 0;
|
||||
}
|
||||
|
||||
SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
|
||||
|
||||
strcpy (sv.name, server);
|
||||
|
||||
// leave slots at start for clients only
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
// needs to reconnect
|
||||
if (svs.clients[i].state > cs_connected)
|
||||
svs.clients[i].state = cs_connected;
|
||||
svs.clients[i].lastframe = -1;
|
||||
}
|
||||
|
||||
sv.time = 1000;
|
||||
|
||||
strcpy (sv.name, server);
|
||||
strcpy (sv.configstrings[CS_NAME], server);
|
||||
|
||||
if (serverstate != ss_game)
|
||||
{
|
||||
sv.models[1] = CM_LoadMap ("", false, &checksum); // no real map
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
|
||||
"maps/%s.bsp", server);
|
||||
sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
|
||||
}
|
||||
Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
|
||||
"%i", checksum);
|
||||
|
||||
//
|
||||
// clear physics interaction links
|
||||
//
|
||||
SV_ClearWorld ();
|
||||
|
||||
for (i=1 ; i< CM_NumInlineModels() ; i++)
|
||||
{
|
||||
Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
|
||||
"*%i", i);
|
||||
sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
|
||||
}
|
||||
|
||||
//
|
||||
// spawn the rest of the entities on the map
|
||||
//
|
||||
|
||||
// precache and static commands can be issued during
|
||||
// map initialization
|
||||
sv.state = ss_loading;
|
||||
Com_SetServerState (sv.state);
|
||||
|
||||
// load and spawn all other entities
|
||||
ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
|
||||
|
||||
// run two frames to allow everything to settle
|
||||
ge->RunFrame ();
|
||||
ge->RunFrame ();
|
||||
|
||||
// all precaches are complete
|
||||
sv.state = serverstate;
|
||||
Com_SetServerState (sv.state);
|
||||
|
||||
// create a baseline for more efficient communications
|
||||
SV_CreateBaseline ();
|
||||
|
||||
// check for a savegame
|
||||
SV_CheckForSavegame ();
|
||||
|
||||
// set serverinfo variable
|
||||
Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
|
||||
|
||||
Com_Printf ("-------------------------------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SV_InitGame
|
||||
|
||||
A brand new game has been started
|
||||
==============
|
||||
*/
|
||||
void SV_InitGame (void)
|
||||
{
|
||||
int i;
|
||||
edict_t *ent;
|
||||
char idmaster[32];
|
||||
|
||||
if (svs.initialized)
|
||||
{
|
||||
// cause any connected clients to reconnect
|
||||
SV_Shutdown ("Server restarted\n", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure the client is down
|
||||
CL_Drop ();
|
||||
SCR_BeginLoadingPlaque ();
|
||||
}
|
||||
|
||||
// get any latched variable changes (maxclients, etc)
|
||||
Cvar_GetLatchedVars ();
|
||||
|
||||
svs.initialized = true;
|
||||
|
||||
if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
|
||||
{
|
||||
Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
|
||||
Cvar_FullSet ("coop", "0", CVAR_SERVERINFO | CVAR_LATCH);
|
||||
}
|
||||
|
||||
// dedicated servers are can't be single player and are usually DM
|
||||
// so unless they explicity set coop, force it to deathmatch
|
||||
if (dedicated->value)
|
||||
{
|
||||
if (!Cvar_VariableValue ("coop"))
|
||||
Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
|
||||
}
|
||||
|
||||
// init clients
|
||||
if (Cvar_VariableValue ("deathmatch"))
|
||||
{
|
||||
if (maxclients->value <= 1)
|
||||
Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
|
||||
else if (maxclients->value > MAX_CLIENTS)
|
||||
Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
|
||||
}
|
||||
else if (Cvar_VariableValue ("coop"))
|
||||
{
|
||||
if (maxclients->value <= 1 || maxclients->value > 4)
|
||||
Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
|
||||
#ifdef COPYPROTECT
|
||||
if (!sv.attractloop && !dedicated->value)
|
||||
Sys_CopyProtect ();
|
||||
#endif
|
||||
}
|
||||
else // non-deathmatch, non-coop is one player
|
||||
{
|
||||
Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
|
||||
#ifdef COPYPROTECT
|
||||
if (!sv.attractloop)
|
||||
Sys_CopyProtect ();
|
||||
#endif
|
||||
}
|
||||
|
||||
svs.spawncount = rand();
|
||||
svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
|
||||
svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
|
||||
svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
|
||||
|
||||
// init network stuff
|
||||
NET_Config ( (maxclients->value > 1) );
|
||||
|
||||
// heartbeats will always be sent to the id master
|
||||
svs.last_heartbeat = -99999; // send immediately
|
||||
Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
|
||||
NET_StringToAdr (idmaster, &master_adr[0]);
|
||||
|
||||
// init game
|
||||
SV_InitGameProgs ();
|
||||
for (i=0 ; i<maxclients->value ; i++)
|
||||
{
|
||||
ent = EDICT_NUM(i+1);
|
||||
ent->s.number = i+1;
|
||||
svs.clients[i].edict = ent;
|
||||
memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
======================
|
||||
SV_Map
|
||||
|
||||
the full syntax is:
|
||||
|
||||
map [*]<map>$<startspot>+<nextserver>
|
||||
|
||||
command from the console or progs.
|
||||
Map can also be a.cin, .pcx, or .dm2 file
|
||||
Nextserver is used to allow a cinematic to play, then proceed to
|
||||
another level:
|
||||
|
||||
map tram.cin+jail_e3
|
||||
======================
|
||||
*/
|
||||
void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
|
||||
{
|
||||
char level[MAX_QPATH];
|
||||
char *ch;
|
||||
int l;
|
||||
char spawnpoint[MAX_QPATH];
|
||||
|
||||
sv.loadgame = loadgame;
|
||||
sv.attractloop = attractloop;
|
||||
|
||||
if (sv.state == ss_dead && !sv.loadgame)
|
||||
SV_InitGame (); // the game is just starting
|
||||
|
||||
strcpy (level, levelstring);
|
||||
|
||||
// if there is a + in the map, set nextserver to the remainder
|
||||
ch = strstr(level, "+");
|
||||
if (ch)
|
||||
{
|
||||
*ch = 0;
|
||||
Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
|
||||
}
|
||||
else
|
||||
Cvar_Set ("nextserver", "");
|
||||
|
||||
//ZOID special hack for end game screen in coop mode
|
||||
if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx"))
|
||||
Cvar_Set ("nextserver", "gamemap \"*base1\"");
|
||||
|
||||
// if there is a $, use the remainder as a spawnpoint
|
||||
ch = strstr(level, "$");
|
||||
if (ch)
|
||||
{
|
||||
*ch = 0;
|
||||
strcpy (spawnpoint, ch+1);
|
||||
}
|
||||
else
|
||||
spawnpoint[0] = 0;
|
||||
|
||||
// skip the end-of-unit flag if necessary
|
||||
if (level[0] == '*')
|
||||
strcpy (level, level+1);
|
||||
|
||||
l = strlen(level);
|
||||
if (l > 4 && !strcmp (level+l-4, ".cin") )
|
||||
{
|
||||
SCR_BeginLoadingPlaque (); // for local system
|
||||
SV_BroadcastCommand ("changing\n");
|
||||
SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
|
||||
}
|
||||
else if (l > 4 && !strcmp (level+l-4, ".dm2") )
|
||||
{
|
||||
SCR_BeginLoadingPlaque (); // for local system
|
||||
SV_BroadcastCommand ("changing\n");
|
||||
SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
|
||||
}
|
||||
else if (l > 4 && !strcmp (level+l-4, ".pcx") )
|
||||
{
|
||||
SCR_BeginLoadingPlaque (); // for local system
|
||||
SV_BroadcastCommand ("changing\n");
|
||||
SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
|
||||
}
|
||||
else
|
||||
{
|
||||
SCR_BeginLoadingPlaque (); // for local system
|
||||
SV_BroadcastCommand ("changing\n");
|
||||
SV_SendClientMessages ();
|
||||
SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
|
||||
Cbuf_CopyToDefer ();
|
||||
}
|
||||
|
||||
SV_BroadcastCommand ("reconnect\n");
|
||||
}
|
||||
1055
server/sv_main.c
Normal file
1055
server/sv_main.c
Normal file
File diff suppressed because it is too large
Load Diff
15
server/sv_null.c
Normal file
15
server/sv_null.c
Normal file
@@ -0,0 +1,15 @@
|
||||
// sv_null.c -- this file can stub out the entire server system
|
||||
// for pure net-only clients
|
||||
|
||||
void SV_Init (void)
|
||||
{
|
||||
}
|
||||
|
||||
void SV_Shutdown (char *finalmsg, qboolean reconnect)
|
||||
{
|
||||
}
|
||||
|
||||
void SV_Frame (float time)
|
||||
{
|
||||
}
|
||||
|
||||
567
server/sv_send.c
Normal file
567
server/sv_send.c
Normal file
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sv_main.c -- server main program
|
||||
|
||||
#include "server.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
Com_Printf redirection
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
|
||||
|
||||
void SV_FlushRedirect (int sv_redirected, char *outputbuf)
|
||||
{
|
||||
if (sv_redirected == RD_PACKET)
|
||||
{
|
||||
Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", outputbuf);
|
||||
}
|
||||
else if (sv_redirected == RD_CLIENT)
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_print);
|
||||
MSG_WriteByte (&sv_client->netchan.message, PRINT_HIGH);
|
||||
MSG_WriteString (&sv_client->netchan.message, outputbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
EVENT MESSAGES
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_ClientPrintf
|
||||
|
||||
Sends text across to be displayed if the level passes
|
||||
=================
|
||||
*/
|
||||
void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
if (level < cl->messagelevel)
|
||||
return;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (string, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
MSG_WriteByte (&cl->netchan.message, svc_print);
|
||||
MSG_WriteByte (&cl->netchan.message, level);
|
||||
MSG_WriteString (&cl->netchan.message, string);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_BroadcastPrintf
|
||||
|
||||
Sends text to all active clients
|
||||
=================
|
||||
*/
|
||||
void SV_BroadcastPrintf (int level, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[2048];
|
||||
client_t *cl;
|
||||
int i;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (string, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
// echo to console
|
||||
if (dedicated->value)
|
||||
{
|
||||
char copy[1024];
|
||||
int i;
|
||||
|
||||
// mask off high bits
|
||||
for (i=0 ; i<1023 && string[i] ; i++)
|
||||
copy[i] = string[i]&127;
|
||||
copy[i] = 0;
|
||||
Com_Printf ("%s", copy);
|
||||
}
|
||||
|
||||
for (i=0, cl = svs.clients ; i<maxclients->value; i++, cl++)
|
||||
{
|
||||
if (level < cl->messagelevel)
|
||||
continue;
|
||||
if (cl->state != cs_spawned)
|
||||
continue;
|
||||
MSG_WriteByte (&cl->netchan.message, svc_print);
|
||||
MSG_WriteByte (&cl->netchan.message, level);
|
||||
MSG_WriteString (&cl->netchan.message, string);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_BroadcastCommand
|
||||
|
||||
Sends text to all active clients
|
||||
=================
|
||||
*/
|
||||
void SV_BroadcastCommand (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
if (!sv.state)
|
||||
return;
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (string, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
MSG_WriteByte (&sv.multicast, svc_stufftext);
|
||||
MSG_WriteString (&sv.multicast, string);
|
||||
SV_Multicast (NULL, MULTICAST_ALL_R);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_Multicast
|
||||
|
||||
Sends the contents of sv.multicast to a subset of the clients,
|
||||
then clears sv.multicast.
|
||||
|
||||
MULTICAST_ALL same as broadcast (origin can be NULL)
|
||||
MULTICAST_PVS send to clients potentially visible from org
|
||||
MULTICAST_PHS send to clients potentially hearable from org
|
||||
=================
|
||||
*/
|
||||
void SV_Multicast (vec3_t origin, multicast_t to)
|
||||
{
|
||||
client_t *client;
|
||||
byte *mask;
|
||||
int leafnum, cluster;
|
||||
int j;
|
||||
qboolean reliable;
|
||||
int area1, area2;
|
||||
|
||||
reliable = false;
|
||||
|
||||
if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
|
||||
{
|
||||
leafnum = CM_PointLeafnum (origin);
|
||||
area1 = CM_LeafArea (leafnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
leafnum = 0; // just to avoid compiler warnings
|
||||
area1 = 0;
|
||||
}
|
||||
|
||||
// if doing a serverrecord, store everything
|
||||
if (svs.demofile)
|
||||
SZ_Write (&svs.demo_multicast, sv.multicast.data, sv.multicast.cursize);
|
||||
|
||||
switch (to)
|
||||
{
|
||||
case MULTICAST_ALL_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_ALL:
|
||||
leafnum = 0;
|
||||
mask = NULL;
|
||||
break;
|
||||
|
||||
case MULTICAST_PHS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PHS:
|
||||
leafnum = CM_PointLeafnum (origin);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
mask = CM_ClusterPHS (cluster);
|
||||
break;
|
||||
|
||||
case MULTICAST_PVS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PVS:
|
||||
leafnum = CM_PointLeafnum (origin);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
mask = CM_ClusterPVS (cluster);
|
||||
break;
|
||||
|
||||
default:
|
||||
mask = NULL;
|
||||
Com_Error (ERR_FATAL, "SV_Multicast: bad to:%i", to);
|
||||
}
|
||||
|
||||
// send the data to all relevent clients
|
||||
for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
|
||||
{
|
||||
if (client->state == cs_free || client->state == cs_zombie)
|
||||
continue;
|
||||
if (client->state != cs_spawned && !reliable)
|
||||
continue;
|
||||
|
||||
if (mask)
|
||||
{
|
||||
leafnum = CM_PointLeafnum (client->edict->s.origin);
|
||||
cluster = CM_LeafCluster (leafnum);
|
||||
area2 = CM_LeafArea (leafnum);
|
||||
if (!CM_AreasConnected (area1, area2))
|
||||
continue;
|
||||
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reliable)
|
||||
SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize);
|
||||
else
|
||||
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
|
||||
}
|
||||
|
||||
SZ_Clear (&sv.multicast);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_StartSound
|
||||
|
||||
Each entity can have eight independant sound sources, like voice,
|
||||
weapon, feet, etc.
|
||||
|
||||
If cahnnel & 8, the sound will be sent to everyone, not just
|
||||
things in the PHS.
|
||||
|
||||
FIXME: if entity isn't in PHS, they must be forced to be sent or
|
||||
have the origin explicitly sent.
|
||||
|
||||
Channel 0 is an auto-allocate channel, the others override anything
|
||||
already running on that entity/channel pair.
|
||||
|
||||
An attenuation of 0 will play full volume everywhere in the level.
|
||||
Larger attenuations will drop off. (max 4 attenuation)
|
||||
|
||||
Timeofs can range from 0.0 to 0.1 to cause sounds to be started
|
||||
later in the frame than they normally would.
|
||||
|
||||
If origin is NULL, the origin is determined from the entity origin
|
||||
or the midpoint of the entity box for bmodels.
|
||||
==================
|
||||
*/
|
||||
void SV_StartSound (vec3_t origin, edict_t *entity, int channel,
|
||||
int soundindex, float volume,
|
||||
float attenuation, float timeofs)
|
||||
{
|
||||
int sendchan;
|
||||
int flags;
|
||||
int i;
|
||||
int ent;
|
||||
vec3_t origin_v;
|
||||
qboolean use_phs;
|
||||
|
||||
if (volume < 0 || volume > 1.0)
|
||||
Com_Error (ERR_FATAL, "SV_StartSound: volume = %f", volume);
|
||||
|
||||
if (attenuation < 0 || attenuation > 4)
|
||||
Com_Error (ERR_FATAL, "SV_StartSound: attenuation = %f", attenuation);
|
||||
|
||||
// if (channel < 0 || channel > 15)
|
||||
// Com_Error (ERR_FATAL, "SV_StartSound: channel = %i", channel);
|
||||
|
||||
if (timeofs < 0 || timeofs > 0.255)
|
||||
Com_Error (ERR_FATAL, "SV_StartSound: timeofs = %f", timeofs);
|
||||
|
||||
ent = NUM_FOR_EDICT(entity);
|
||||
|
||||
if (channel & 8) // no PHS flag
|
||||
{
|
||||
use_phs = false;
|
||||
channel &= 7;
|
||||
}
|
||||
else
|
||||
use_phs = true;
|
||||
|
||||
sendchan = (ent<<3) | (channel&7);
|
||||
|
||||
flags = 0;
|
||||
if (volume != DEFAULT_SOUND_PACKET_VOLUME)
|
||||
flags |= SND_VOLUME;
|
||||
if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
|
||||
flags |= SND_ATTENUATION;
|
||||
|
||||
// the client doesn't know that bmodels have weird origins
|
||||
// the origin can also be explicitly set
|
||||
if ( (entity->svflags & SVF_NOCLIENT)
|
||||
|| (entity->solid == SOLID_BSP)
|
||||
|| origin )
|
||||
flags |= SND_POS;
|
||||
|
||||
// always send the entity number for channel overrides
|
||||
flags |= SND_ENT;
|
||||
|
||||
if (timeofs)
|
||||
flags |= SND_OFFSET;
|
||||
|
||||
// use the entity origin unless it is a bmodel or explicitly specified
|
||||
if (!origin)
|
||||
{
|
||||
origin = origin_v;
|
||||
if (entity->solid == SOLID_BSP)
|
||||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy (entity->s.origin, origin_v);
|
||||
}
|
||||
}
|
||||
|
||||
MSG_WriteByte (&sv.multicast, svc_sound);
|
||||
MSG_WriteByte (&sv.multicast, flags);
|
||||
MSG_WriteByte (&sv.multicast, soundindex);
|
||||
|
||||
if (flags & SND_VOLUME)
|
||||
MSG_WriteByte (&sv.multicast, volume*255);
|
||||
if (flags & SND_ATTENUATION)
|
||||
MSG_WriteByte (&sv.multicast, attenuation*64);
|
||||
if (flags & SND_OFFSET)
|
||||
MSG_WriteByte (&sv.multicast, timeofs*1000);
|
||||
|
||||
if (flags & SND_ENT)
|
||||
MSG_WriteShort (&sv.multicast, sendchan);
|
||||
|
||||
if (flags & SND_POS)
|
||||
MSG_WritePos (&sv.multicast, origin);
|
||||
|
||||
// if the sound doesn't attenuate,send it to everyone
|
||||
// (global radio chatter, voiceovers, etc)
|
||||
if (attenuation == ATTN_NONE)
|
||||
use_phs = false;
|
||||
|
||||
if (channel & CHAN_RELIABLE)
|
||||
{
|
||||
if (use_phs)
|
||||
SV_Multicast (origin, MULTICAST_PHS_R);
|
||||
else
|
||||
SV_Multicast (origin, MULTICAST_ALL_R);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_phs)
|
||||
SV_Multicast (origin, MULTICAST_PHS);
|
||||
else
|
||||
SV_Multicast (origin, MULTICAST_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FRAME UPDATES
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_SendClientDatagram
|
||||
=======================
|
||||
*/
|
||||
qboolean SV_SendClientDatagram (client_t *client)
|
||||
{
|
||||
byte msg_buf[MAX_MSGLEN];
|
||||
sizebuf_t msg;
|
||||
|
||||
SV_BuildClientFrame (client);
|
||||
|
||||
SZ_Init (&msg, msg_buf, sizeof(msg_buf));
|
||||
msg.allowoverflow = true;
|
||||
|
||||
// send over all the relevant entity_state_t
|
||||
// and the player_state_t
|
||||
SV_WriteFrameToClient (client, &msg);
|
||||
|
||||
// copy the accumulated multicast datagram
|
||||
// for this client out to the message
|
||||
// it is necessary for this to be after the WriteEntities
|
||||
// so that entity references will be current
|
||||
if (client->datagram.overflowed)
|
||||
Com_Printf ("WARNING: datagram overflowed for %s\n", client->name);
|
||||
else
|
||||
SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
|
||||
SZ_Clear (&client->datagram);
|
||||
|
||||
if (msg.overflowed)
|
||||
{ // must have room left for the packet header
|
||||
Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
|
||||
SZ_Clear (&msg);
|
||||
}
|
||||
|
||||
// send the datagram
|
||||
Netchan_Transmit (&client->netchan, msg.cursize, msg.data);
|
||||
|
||||
// record the size for rate estimation
|
||||
client->message_size[sv.framenum % RATE_MESSAGES] = msg.cursize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_DemoCompleted
|
||||
==================
|
||||
*/
|
||||
void SV_DemoCompleted (void)
|
||||
{
|
||||
if (sv.demofile)
|
||||
{
|
||||
fclose (sv.demofile);
|
||||
sv.demofile = NULL;
|
||||
}
|
||||
SV_Nextserver ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_RateDrop
|
||||
|
||||
Returns true if the client is over its current
|
||||
bandwidth estimation and should not be sent another packet
|
||||
=======================
|
||||
*/
|
||||
qboolean SV_RateDrop (client_t *c)
|
||||
{
|
||||
int total;
|
||||
int i;
|
||||
|
||||
// never drop over the loopback
|
||||
if (c->netchan.remote_address.type == NA_LOOPBACK)
|
||||
return false;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i = 0 ; i < RATE_MESSAGES ; i++)
|
||||
{
|
||||
total += c->message_size[i];
|
||||
}
|
||||
|
||||
if (total > c->rate)
|
||||
{
|
||||
c->surpressCount++;
|
||||
c->message_size[sv.framenum % RATE_MESSAGES] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_SendClientMessages
|
||||
=======================
|
||||
*/
|
||||
void SV_SendClientMessages (void)
|
||||
{
|
||||
int i;
|
||||
client_t *c;
|
||||
int msglen;
|
||||
byte msgbuf[MAX_MSGLEN];
|
||||
int r;
|
||||
|
||||
msglen = 0;
|
||||
|
||||
// read the next demo message if needed
|
||||
if (sv.state == ss_demo && sv.demofile)
|
||||
{
|
||||
if (sv_paused->value)
|
||||
msglen = 0;
|
||||
else
|
||||
{
|
||||
// get the next message
|
||||
r = fread (&msglen, 4, 1, sv.demofile);
|
||||
if (r != 1)
|
||||
{
|
||||
SV_DemoCompleted ();
|
||||
return;
|
||||
}
|
||||
msglen = LittleLong (msglen);
|
||||
if (msglen == -1)
|
||||
{
|
||||
SV_DemoCompleted ();
|
||||
return;
|
||||
}
|
||||
if (msglen > MAX_MSGLEN)
|
||||
Com_Error (ERR_DROP, "SV_SendClientMessages: msglen > MAX_MSGLEN");
|
||||
r = fread (msgbuf, msglen, 1, sv.demofile);
|
||||
if (r != 1)
|
||||
{
|
||||
SV_DemoCompleted ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send a message to each connected client
|
||||
for (i=0, c = svs.clients ; i<maxclients->value; i++, c++)
|
||||
{
|
||||
if (!c->state)
|
||||
continue;
|
||||
// if the reliable message overflowed,
|
||||
// drop the client
|
||||
if (c->netchan.message.overflowed)
|
||||
{
|
||||
SZ_Clear (&c->netchan.message);
|
||||
SZ_Clear (&c->datagram);
|
||||
SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
|
||||
SV_DropClient (c);
|
||||
}
|
||||
|
||||
if (sv.state == ss_cinematic
|
||||
|| sv.state == ss_demo
|
||||
|| sv.state == ss_pic
|
||||
)
|
||||
Netchan_Transmit (&c->netchan, msglen, msgbuf);
|
||||
else if (c->state == cs_spawned)
|
||||
{
|
||||
// don't overrun bandwidth
|
||||
if (SV_RateDrop (c))
|
||||
continue;
|
||||
|
||||
SV_SendClientDatagram (c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// just update reliable if needed
|
||||
if (c->netchan.message.cursize || curtime - c->netchan.last_sent > 1000 )
|
||||
Netchan_Transmit (&c->netchan, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
664
server/sv_user.c
Normal file
664
server/sv_user.c
Normal file
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sv_user.c -- server code for moving users
|
||||
|
||||
#include "server.h"
|
||||
|
||||
edict_t *sv_player;
|
||||
|
||||
/*
|
||||
============================================================
|
||||
|
||||
USER STRINGCMD EXECUTION
|
||||
|
||||
sv_client and sv_player will be valid.
|
||||
============================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_BeginDemoServer
|
||||
==================
|
||||
*/
|
||||
void SV_BeginDemoserver (void)
|
||||
{
|
||||
char name[MAX_OSPATH];
|
||||
|
||||
Com_sprintf (name, sizeof(name), "demos/%s", sv.name);
|
||||
FS_FOpenFile (name, &sv.demofile);
|
||||
if (!sv.demofile)
|
||||
Com_Error (ERR_DROP, "Couldn't open %s\n", name);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_New_f
|
||||
|
||||
Sends the first message from the server to a connected client.
|
||||
This will be sent on the initial connection and upon each server load.
|
||||
================
|
||||
*/
|
||||
void SV_New_f (void)
|
||||
{
|
||||
char *gamedir;
|
||||
int playernum;
|
||||
edict_t *ent;
|
||||
|
||||
Com_DPrintf ("New() from %s\n", sv_client->name);
|
||||
|
||||
if (sv_client->state != cs_connected)
|
||||
{
|
||||
Com_Printf ("New not valid -- already spawned\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// demo servers just dump the file message
|
||||
if (sv.state == ss_demo)
|
||||
{
|
||||
SV_BeginDemoserver ();
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// serverdata needs to go over for all types of servers
|
||||
// to make sure the protocol is right, and to set the gamedir
|
||||
//
|
||||
gamedir = Cvar_VariableString ("gamedir");
|
||||
|
||||
// send the serverdata
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_serverdata);
|
||||
MSG_WriteLong (&sv_client->netchan.message, PROTOCOL_VERSION);
|
||||
MSG_WriteLong (&sv_client->netchan.message, svs.spawncount);
|
||||
MSG_WriteByte (&sv_client->netchan.message, sv.attractloop);
|
||||
MSG_WriteString (&sv_client->netchan.message, gamedir);
|
||||
|
||||
if (sv.state == ss_cinematic || sv.state == ss_pic)
|
||||
playernum = -1;
|
||||
else
|
||||
playernum = sv_client - svs.clients;
|
||||
MSG_WriteShort (&sv_client->netchan.message, playernum);
|
||||
|
||||
// send full levelname
|
||||
MSG_WriteString (&sv_client->netchan.message, sv.configstrings[CS_NAME]);
|
||||
|
||||
//
|
||||
// game server
|
||||
//
|
||||
if (sv.state == ss_game)
|
||||
{
|
||||
// set up the entity for the client
|
||||
ent = EDICT_NUM(playernum+1);
|
||||
ent->s.number = playernum+1;
|
||||
sv_client->edict = ent;
|
||||
memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
|
||||
|
||||
// begin fetching configstrings
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i 0\n",svs.spawncount) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Configstrings_f
|
||||
==================
|
||||
*/
|
||||
void SV_Configstrings_f (void)
|
||||
{
|
||||
int start;
|
||||
|
||||
Com_DPrintf ("Configstrings() from %s\n", sv_client->name);
|
||||
|
||||
if (sv_client->state != cs_connected)
|
||||
{
|
||||
Com_Printf ("configstrings not valid -- already spawned\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// handle the case of a level changing while a client was connecting
|
||||
if ( atoi(Cmd_Argv(1)) != svs.spawncount )
|
||||
{
|
||||
Com_Printf ("SV_Configstrings_f from different level\n");
|
||||
SV_New_f ();
|
||||
return;
|
||||
}
|
||||
|
||||
start = atoi(Cmd_Argv(2));
|
||||
|
||||
// write a packet full of data
|
||||
|
||||
while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
|
||||
&& start < MAX_CONFIGSTRINGS)
|
||||
{
|
||||
if (sv.configstrings[start][0])
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_configstring);
|
||||
MSG_WriteShort (&sv_client->netchan.message, start);
|
||||
MSG_WriteString (&sv_client->netchan.message, sv.configstrings[start]);
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
// send next command
|
||||
|
||||
if (start == MAX_CONFIGSTRINGS)
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i 0\n",svs.spawncount) );
|
||||
}
|
||||
else
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&sv_client->netchan.message, va("cmd configstrings %i %i\n",svs.spawncount, start) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Baselines_f
|
||||
==================
|
||||
*/
|
||||
void SV_Baselines_f (void)
|
||||
{
|
||||
int start;
|
||||
entity_state_t nullstate;
|
||||
entity_state_t *base;
|
||||
|
||||
Com_DPrintf ("Baselines() from %s\n", sv_client->name);
|
||||
|
||||
if (sv_client->state != cs_connected)
|
||||
{
|
||||
Com_Printf ("baselines not valid -- already spawned\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// handle the case of a level changing while a client was connecting
|
||||
if ( atoi(Cmd_Argv(1)) != svs.spawncount )
|
||||
{
|
||||
Com_Printf ("SV_Baselines_f from different level\n");
|
||||
SV_New_f ();
|
||||
return;
|
||||
}
|
||||
|
||||
start = atoi(Cmd_Argv(2));
|
||||
|
||||
memset (&nullstate, 0, sizeof(nullstate));
|
||||
|
||||
// write a packet full of data
|
||||
|
||||
while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2
|
||||
&& start < MAX_EDICTS)
|
||||
{
|
||||
base = &sv.baselines[start];
|
||||
if (base->modelindex || base->sound || base->effects)
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_spawnbaseline);
|
||||
MSG_WriteDeltaEntity (&nullstate, base, &sv_client->netchan.message, true, true);
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
// send next command
|
||||
|
||||
if (start == MAX_EDICTS)
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&sv_client->netchan.message, va("precache %i\n", svs.spawncount) );
|
||||
}
|
||||
else
|
||||
{
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_stufftext);
|
||||
MSG_WriteString (&sv_client->netchan.message, va("cmd baselines %i %i\n",svs.spawncount, start) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Begin_f
|
||||
==================
|
||||
*/
|
||||
void SV_Begin_f (void)
|
||||
{
|
||||
Com_DPrintf ("Begin() from %s\n", sv_client->name);
|
||||
|
||||
// handle the case of a level changing while a client was connecting
|
||||
if ( atoi(Cmd_Argv(1)) != svs.spawncount )
|
||||
{
|
||||
Com_Printf ("SV_Begin_f from different level\n");
|
||||
SV_New_f ();
|
||||
return;
|
||||
}
|
||||
|
||||
sv_client->state = cs_spawned;
|
||||
|
||||
// call the game begin function
|
||||
ge->ClientBegin (sv_player);
|
||||
|
||||
Cbuf_InsertFromDefer ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_NextDownload_f
|
||||
==================
|
||||
*/
|
||||
void SV_NextDownload_f (void)
|
||||
{
|
||||
int r;
|
||||
int percent;
|
||||
int size;
|
||||
|
||||
if (!sv_client->download)
|
||||
return;
|
||||
|
||||
r = sv_client->downloadsize - sv_client->downloadcount;
|
||||
if (r > 1024)
|
||||
r = 1024;
|
||||
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_download);
|
||||
MSG_WriteShort (&sv_client->netchan.message, r);
|
||||
|
||||
sv_client->downloadcount += r;
|
||||
size = sv_client->downloadsize;
|
||||
if (!size)
|
||||
size = 1;
|
||||
percent = sv_client->downloadcount*100/size;
|
||||
MSG_WriteByte (&sv_client->netchan.message, percent);
|
||||
SZ_Write (&sv_client->netchan.message,
|
||||
sv_client->download + sv_client->downloadcount - r, r);
|
||||
|
||||
if (sv_client->downloadcount != sv_client->downloadsize)
|
||||
return;
|
||||
|
||||
FS_FreeFile (sv_client->download);
|
||||
sv_client->download = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_BeginDownload_f
|
||||
==================
|
||||
*/
|
||||
void SV_BeginDownload_f(void)
|
||||
{
|
||||
char *name;
|
||||
extern cvar_t *allow_download;
|
||||
extern cvar_t *allow_download_players;
|
||||
extern cvar_t *allow_download_models;
|
||||
extern cvar_t *allow_download_sounds;
|
||||
extern cvar_t *allow_download_maps;
|
||||
extern int file_from_pak; // ZOID did file come from pak?
|
||||
int offset = 0;
|
||||
|
||||
name = Cmd_Argv(1);
|
||||
|
||||
if (Cmd_Argc() > 2)
|
||||
offset = atoi(Cmd_Argv(2)); // downloaded offset
|
||||
|
||||
// hacked by zoid to allow more conrol over download
|
||||
// first off, no .. or global allow check
|
||||
if (strstr (name, "..") || !allow_download->value
|
||||
// leading dot is no good
|
||||
|| *name == '.'
|
||||
// leading slash bad as well, must be in subdir
|
||||
|| *name == '/'
|
||||
// next up, skin check
|
||||
|| (strncmp(name, "players/", 6) == 0 && !allow_download_players->value)
|
||||
// now models
|
||||
|| (strncmp(name, "models/", 6) == 0 && !allow_download_models->value)
|
||||
// now sounds
|
||||
|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds->value)
|
||||
// now maps (note special case for maps, must not be in pak)
|
||||
|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps->value)
|
||||
// MUST be in a subdirectory
|
||||
|| !strstr (name, "/") )
|
||||
{ // don't allow anything with .. path
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_download);
|
||||
MSG_WriteShort (&sv_client->netchan.message, -1);
|
||||
MSG_WriteByte (&sv_client->netchan.message, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (sv_client->download)
|
||||
FS_FreeFile (sv_client->download);
|
||||
|
||||
sv_client->downloadsize = FS_LoadFile (name, (void **)&sv_client->download);
|
||||
sv_client->downloadcount = offset;
|
||||
|
||||
if (offset > sv_client->downloadsize)
|
||||
sv_client->downloadcount = sv_client->downloadsize;
|
||||
|
||||
if (!sv_client->download
|
||||
// special check for maps, if it came from a pak file, don't allow
|
||||
// download ZOID
|
||||
|| (strncmp(name, "maps/", 5) == 0 && file_from_pak))
|
||||
{
|
||||
Com_DPrintf ("Couldn't download %s to %s\n", name, sv_client->name);
|
||||
if (sv_client->download) {
|
||||
FS_FreeFile (sv_client->download);
|
||||
sv_client->download = NULL;
|
||||
}
|
||||
|
||||
MSG_WriteByte (&sv_client->netchan.message, svc_download);
|
||||
MSG_WriteShort (&sv_client->netchan.message, -1);
|
||||
MSG_WriteByte (&sv_client->netchan.message, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
SV_NextDownload_f ();
|
||||
Com_DPrintf ("Downloading %s to %s\n", name, sv_client->name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_Disconnect_f
|
||||
|
||||
The client is going to disconnect, so remove the connection immediately
|
||||
=================
|
||||
*/
|
||||
void SV_Disconnect_f (void)
|
||||
{
|
||||
// SV_EndRedirect ();
|
||||
SV_DropClient (sv_client);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_ShowServerinfo_f
|
||||
|
||||
Dumps the serverinfo info string
|
||||
==================
|
||||
*/
|
||||
void SV_ShowServerinfo_f (void)
|
||||
{
|
||||
Info_Print (Cvar_Serverinfo());
|
||||
}
|
||||
|
||||
|
||||
void SV_Nextserver (void)
|
||||
{
|
||||
char *v;
|
||||
|
||||
//ZOID, ss_pic can be nextserver'd in coop mode
|
||||
if (sv.state == ss_game || (sv.state == ss_pic && !Cvar_VariableValue("coop")))
|
||||
return; // can't nextserver while playing a normal game
|
||||
|
||||
svs.spawncount++; // make sure another doesn't sneak in
|
||||
v = Cvar_VariableString ("nextserver");
|
||||
if (!v[0])
|
||||
Cbuf_AddText ("killserver\n");
|
||||
else
|
||||
{
|
||||
Cbuf_AddText (v);
|
||||
Cbuf_AddText ("\n");
|
||||
}
|
||||
Cvar_Set ("nextserver","");
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Nextserver_f
|
||||
|
||||
A cinematic has completed or been aborted by a client, so move
|
||||
to the next server,
|
||||
==================
|
||||
*/
|
||||
void SV_Nextserver_f (void)
|
||||
{
|
||||
if ( atoi(Cmd_Argv(1)) != svs.spawncount ) {
|
||||
Com_DPrintf ("Nextserver() from wrong level, from %s\n", sv_client->name);
|
||||
return; // leftover from last server
|
||||
}
|
||||
|
||||
Com_DPrintf ("Nextserver() from %s\n", sv_client->name);
|
||||
|
||||
SV_Nextserver ();
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
void (*func) (void);
|
||||
} ucmd_t;
|
||||
|
||||
ucmd_t ucmds[] =
|
||||
{
|
||||
// auto issued
|
||||
{"new", SV_New_f},
|
||||
{"configstrings", SV_Configstrings_f},
|
||||
{"baselines", SV_Baselines_f},
|
||||
{"begin", SV_Begin_f},
|
||||
|
||||
{"nextserver", SV_Nextserver_f},
|
||||
|
||||
{"disconnect", SV_Disconnect_f},
|
||||
|
||||
// issued by hand at client consoles
|
||||
{"info", SV_ShowServerinfo_f},
|
||||
|
||||
{"download", SV_BeginDownload_f},
|
||||
{"nextdl", SV_NextDownload_f},
|
||||
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_ExecuteUserCommand
|
||||
==================
|
||||
*/
|
||||
void SV_ExecuteUserCommand (char *s)
|
||||
{
|
||||
ucmd_t *u;
|
||||
|
||||
Cmd_TokenizeString (s, true);
|
||||
sv_player = sv_client->edict;
|
||||
|
||||
// SV_BeginRedirect (RD_CLIENT);
|
||||
|
||||
for (u=ucmds ; u->name ; u++)
|
||||
if (!strcmp (Cmd_Argv(0), u->name) )
|
||||
{
|
||||
u->func ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!u->name && sv.state == ss_game)
|
||||
ge->ClientCommand (sv_player);
|
||||
|
||||
// SV_EndRedirect ();
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
USER CMD EXECUTION
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void SV_ClientThink (client_t *cl, usercmd_t *cmd)
|
||||
|
||||
{
|
||||
cl->commandMsec -= cmd->msec;
|
||||
|
||||
if (cl->commandMsec < 0 && sv_enforcetime->value )
|
||||
{
|
||||
Com_DPrintf ("commandMsec underflow from %s\n", cl->name);
|
||||
return;
|
||||
}
|
||||
|
||||
ge->ClientThink (cl->edict, cmd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define MAX_STRINGCMDS 8
|
||||
/*
|
||||
===================
|
||||
SV_ExecuteClientMessage
|
||||
|
||||
The current net_message is parsed for the given client
|
||||
===================
|
||||
*/
|
||||
void SV_ExecuteClientMessage (client_t *cl)
|
||||
{
|
||||
int c;
|
||||
char *s;
|
||||
|
||||
usercmd_t nullcmd;
|
||||
usercmd_t oldest, oldcmd, newcmd;
|
||||
int net_drop;
|
||||
int stringCmdCount;
|
||||
int checksum, calculatedChecksum;
|
||||
int checksumIndex;
|
||||
qboolean move_issued;
|
||||
int lastframe;
|
||||
|
||||
sv_client = cl;
|
||||
sv_player = sv_client->edict;
|
||||
|
||||
// only allow one move command
|
||||
move_issued = false;
|
||||
stringCmdCount = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (net_message.readcount > net_message.cursize)
|
||||
{
|
||||
Com_Printf ("SV_ReadClientMessage: badread\n");
|
||||
SV_DropClient (cl);
|
||||
return;
|
||||
}
|
||||
|
||||
c = MSG_ReadByte (&net_message);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
default:
|
||||
Com_Printf ("SV_ReadClientMessage: unknown command char\n");
|
||||
SV_DropClient (cl);
|
||||
return;
|
||||
|
||||
case clc_nop:
|
||||
break;
|
||||
|
||||
case clc_userinfo:
|
||||
strncpy (cl->userinfo, MSG_ReadString (&net_message), sizeof(cl->userinfo)-1);
|
||||
SV_UserinfoChanged (cl);
|
||||
break;
|
||||
|
||||
case clc_move:
|
||||
if (move_issued)
|
||||
return; // someone is trying to cheat...
|
||||
|
||||
move_issued = true;
|
||||
checksumIndex = net_message.readcount;
|
||||
checksum = MSG_ReadByte (&net_message);
|
||||
lastframe = MSG_ReadLong (&net_message);
|
||||
if (lastframe != cl->lastframe) {
|
||||
cl->lastframe = lastframe;
|
||||
if (cl->lastframe > 0) {
|
||||
cl->frame_latency[cl->lastframe&(LATENCY_COUNTS-1)] =
|
||||
svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime;
|
||||
}
|
||||
}
|
||||
|
||||
memset (&nullcmd, 0, sizeof(nullcmd));
|
||||
MSG_ReadDeltaUsercmd (&net_message, &nullcmd, &oldest);
|
||||
MSG_ReadDeltaUsercmd (&net_message, &oldest, &oldcmd);
|
||||
MSG_ReadDeltaUsercmd (&net_message, &oldcmd, &newcmd);
|
||||
|
||||
if ( cl->state != cs_spawned )
|
||||
{
|
||||
cl->lastframe = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// if the checksum fails, ignore the rest of the packet
|
||||
calculatedChecksum = COM_BlockSequenceCRCByte (
|
||||
net_message.data + checksumIndex + 1,
|
||||
net_message.readcount - checksumIndex - 1,
|
||||
cl->netchan.incoming_sequence);
|
||||
|
||||
if (calculatedChecksum != checksum)
|
||||
{
|
||||
Com_DPrintf ("Failed command checksum for %s (%d != %d)/%d\n",
|
||||
cl->name, calculatedChecksum, checksum,
|
||||
cl->netchan.incoming_sequence);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sv_paused->value)
|
||||
{
|
||||
net_drop = cl->netchan.dropped;
|
||||
if (net_drop < 20)
|
||||
{
|
||||
|
||||
//if (net_drop > 2)
|
||||
|
||||
// Com_Printf ("drop %i\n", net_drop);
|
||||
while (net_drop > 2)
|
||||
{
|
||||
SV_ClientThink (cl, &cl->lastcmd);
|
||||
|
||||
net_drop--;
|
||||
}
|
||||
if (net_drop > 1)
|
||||
SV_ClientThink (cl, &oldest);
|
||||
|
||||
if (net_drop > 0)
|
||||
SV_ClientThink (cl, &oldcmd);
|
||||
|
||||
}
|
||||
SV_ClientThink (cl, &newcmd);
|
||||
}
|
||||
|
||||
cl->lastcmd = newcmd;
|
||||
break;
|
||||
|
||||
case clc_stringcmd:
|
||||
s = MSG_ReadString (&net_message);
|
||||
|
||||
// malicious users may try using too many string commands
|
||||
if (++stringCmdCount < MAX_STRINGCMDS)
|
||||
SV_ExecuteUserCommand (s);
|
||||
|
||||
if (cl->state == cs_zombie)
|
||||
return; // disconnect command
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
659
server/sv_world.c
Normal file
659
server/sv_world.c
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// world.c -- world query functions
|
||||
|
||||
#include "server.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
ENTITY AREA CHECKING
|
||||
|
||||
FIXME: this use of "area" is different from the bsp file use
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
// (type *)STRUCT_FROM_LINK(link_t *link, type, member)
|
||||
// ent = STRUCT_FROM_LINK(link,entity_t,order)
|
||||
// FIXME: remove this mess!
|
||||
#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))
|
||||
|
||||
#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)
|
||||
|
||||
typedef struct areanode_s
|
||||
{
|
||||
int axis; // -1 = leaf node
|
||||
float dist;
|
||||
struct areanode_s *children[2];
|
||||
link_t trigger_edicts;
|
||||
link_t solid_edicts;
|
||||
} areanode_t;
|
||||
|
||||
#define AREA_DEPTH 4
|
||||
#define AREA_NODES 32
|
||||
|
||||
areanode_t sv_areanodes[AREA_NODES];
|
||||
int sv_numareanodes;
|
||||
|
||||
float *area_mins, *area_maxs;
|
||||
edict_t **area_list;
|
||||
int area_count, area_maxcount;
|
||||
int area_type;
|
||||
|
||||
int SV_HullForEntity (edict_t *ent);
|
||||
|
||||
|
||||
// ClearLink is used for new headnodes
|
||||
void ClearLink (link_t *l)
|
||||
{
|
||||
l->prev = l->next = l;
|
||||
}
|
||||
|
||||
void RemoveLink (link_t *l)
|
||||
{
|
||||
l->next->prev = l->prev;
|
||||
l->prev->next = l->next;
|
||||
}
|
||||
|
||||
void InsertLinkBefore (link_t *l, link_t *before)
|
||||
{
|
||||
l->next = before;
|
||||
l->prev = before->prev;
|
||||
l->prev->next = l;
|
||||
l->next->prev = l;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_CreateAreaNode
|
||||
|
||||
Builds a uniformly subdivided tree for the given world size
|
||||
===============
|
||||
*/
|
||||
areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
|
||||
{
|
||||
areanode_t *anode;
|
||||
vec3_t size;
|
||||
vec3_t mins1, maxs1, mins2, maxs2;
|
||||
|
||||
anode = &sv_areanodes[sv_numareanodes];
|
||||
sv_numareanodes++;
|
||||
|
||||
ClearLink (&anode->trigger_edicts);
|
||||
ClearLink (&anode->solid_edicts);
|
||||
|
||||
if (depth == AREA_DEPTH)
|
||||
{
|
||||
anode->axis = -1;
|
||||
anode->children[0] = anode->children[1] = NULL;
|
||||
return anode;
|
||||
}
|
||||
|
||||
VectorSubtract (maxs, mins, size);
|
||||
if (size[0] > size[1])
|
||||
anode->axis = 0;
|
||||
else
|
||||
anode->axis = 1;
|
||||
|
||||
anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
|
||||
VectorCopy (mins, mins1);
|
||||
VectorCopy (mins, mins2);
|
||||
VectorCopy (maxs, maxs1);
|
||||
VectorCopy (maxs, maxs2);
|
||||
|
||||
maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
|
||||
|
||||
anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
|
||||
anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
|
||||
|
||||
return anode;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_ClearWorld
|
||||
|
||||
===============
|
||||
*/
|
||||
void SV_ClearWorld (void)
|
||||
{
|
||||
memset (sv_areanodes, 0, sizeof(sv_areanodes));
|
||||
sv_numareanodes = 0;
|
||||
SV_CreateAreaNode (0, sv.models[1]->mins, sv.models[1]->maxs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_UnlinkEdict
|
||||
|
||||
===============
|
||||
*/
|
||||
void SV_UnlinkEdict (edict_t *ent)
|
||||
{
|
||||
if (!ent->area.prev)
|
||||
return; // not linked in anywhere
|
||||
RemoveLink (&ent->area);
|
||||
ent->area.prev = ent->area.next = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
SV_LinkEdict
|
||||
|
||||
===============
|
||||
*/
|
||||
#define MAX_TOTAL_ENT_LEAFS 128
|
||||
void SV_LinkEdict (edict_t *ent)
|
||||
{
|
||||
areanode_t *node;
|
||||
int leafs[MAX_TOTAL_ENT_LEAFS];
|
||||
int clusters[MAX_TOTAL_ENT_LEAFS];
|
||||
int num_leafs;
|
||||
int i, j, k;
|
||||
int area;
|
||||
int topnode;
|
||||
|
||||
if (ent->area.prev)
|
||||
SV_UnlinkEdict (ent); // unlink from old position
|
||||
|
||||
if (ent == ge->edicts)
|
||||
return; // don't add the world
|
||||
|
||||
if (!ent->inuse)
|
||||
return;
|
||||
|
||||
// set the size
|
||||
VectorSubtract (ent->maxs, ent->mins, ent->size);
|
||||
|
||||
// encode the size into the entity_state for client prediction
|
||||
if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
|
||||
{ // assume that x/y are equal and symetric
|
||||
i = ent->maxs[0]/8;
|
||||
if (i<1)
|
||||
i = 1;
|
||||
if (i>31)
|
||||
i = 31;
|
||||
|
||||
// z is not symetric
|
||||
j = (-ent->mins[2])/8;
|
||||
if (j<1)
|
||||
j = 1;
|
||||
if (j>31)
|
||||
j = 31;
|
||||
|
||||
// and z maxs can be negative...
|
||||
k = (ent->maxs[2]+32)/8;
|
||||
if (k<1)
|
||||
k = 1;
|
||||
if (k>63)
|
||||
k = 63;
|
||||
|
||||
ent->s.solid = (k<<10) | (j<<5) | i;
|
||||
}
|
||||
else if (ent->solid == SOLID_BSP)
|
||||
{
|
||||
ent->s.solid = 31; // a solid_bbox will never create this value
|
||||
}
|
||||
else
|
||||
ent->s.solid = 0;
|
||||
|
||||
// set the abs box
|
||||
if (ent->solid == SOLID_BSP &&
|
||||
(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
|
||||
{ // expand for rotation
|
||||
float max, v;
|
||||
int i;
|
||||
|
||||
max = 0;
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
v =fabs( ent->mins[i]);
|
||||
if (v > max)
|
||||
max = v;
|
||||
v =fabs( ent->maxs[i]);
|
||||
if (v > max)
|
||||
max = v;
|
||||
}
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
ent->absmin[i] = ent->s.origin[i] - max;
|
||||
ent->absmax[i] = ent->s.origin[i] + max;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // normal
|
||||
VectorAdd (ent->s.origin, ent->mins, ent->absmin);
|
||||
VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
|
||||
}
|
||||
|
||||
// because movement is clipped an epsilon away from an actual edge,
|
||||
// we must fully check even when bounding boxes don't quite touch
|
||||
ent->absmin[0] -= 1;
|
||||
ent->absmin[1] -= 1;
|
||||
ent->absmin[2] -= 1;
|
||||
ent->absmax[0] += 1;
|
||||
ent->absmax[1] += 1;
|
||||
ent->absmax[2] += 1;
|
||||
|
||||
// link to PVS leafs
|
||||
ent->num_clusters = 0;
|
||||
ent->areanum = 0;
|
||||
ent->areanum2 = 0;
|
||||
|
||||
//get all leafs, including solids
|
||||
num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
|
||||
leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
|
||||
|
||||
// set areas
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
{
|
||||
clusters[i] = CM_LeafCluster (leafs[i]);
|
||||
area = CM_LeafArea (leafs[i]);
|
||||
if (area)
|
||||
{ // doors may legally straggle two areas,
|
||||
// but nothing should evern need more than that
|
||||
if (ent->areanum && ent->areanum != area)
|
||||
{
|
||||
if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
|
||||
Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
|
||||
ent->absmin[0], ent->absmin[1], ent->absmin[2]);
|
||||
ent->areanum2 = area;
|
||||
}
|
||||
else
|
||||
ent->areanum = area;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_clusters = -1;
|
||||
ent->headnode = topnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->num_clusters = 0;
|
||||
for (i=0 ; i<num_leafs ; i++)
|
||||
{
|
||||
if (clusters[i] == -1)
|
||||
continue; // not a visible leaf
|
||||
for (j=0 ; j<i ; j++)
|
||||
if (clusters[j] == clusters[i])
|
||||
break;
|
||||
if (j == i)
|
||||
{
|
||||
if (ent->num_clusters == MAX_ENT_CLUSTERS)
|
||||
{ // assume we missed some leafs, and mark by headnode
|
||||
ent->num_clusters = -1;
|
||||
ent->headnode = topnode;
|
||||
break;
|
||||
}
|
||||
|
||||
ent->clusternums[ent->num_clusters++] = clusters[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if first time, make sure old_origin is valid
|
||||
if (!ent->linkcount)
|
||||
{
|
||||
VectorCopy (ent->s.origin, ent->s.old_origin);
|
||||
}
|
||||
ent->linkcount++;
|
||||
|
||||
if (ent->solid == SOLID_NOT)
|
||||
return;
|
||||
|
||||
// find the first node that the ent's box crosses
|
||||
node = sv_areanodes;
|
||||
while (1)
|
||||
{
|
||||
if (node->axis == -1)
|
||||
break;
|
||||
if (ent->absmin[node->axis] > node->dist)
|
||||
node = node->children[0];
|
||||
else if (ent->absmax[node->axis] < node->dist)
|
||||
node = node->children[1];
|
||||
else
|
||||
break; // crosses the node
|
||||
}
|
||||
|
||||
// link it in
|
||||
if (ent->solid == SOLID_TRIGGER)
|
||||
InsertLinkBefore (&ent->area, &node->trigger_edicts);
|
||||
else
|
||||
InsertLinkBefore (&ent->area, &node->solid_edicts);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_AreaEdicts_r
|
||||
|
||||
====================
|
||||
*/
|
||||
void SV_AreaEdicts_r (areanode_t *node)
|
||||
{
|
||||
link_t *l, *next, *start;
|
||||
edict_t *check;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
// touch linked edicts
|
||||
if (area_type == AREA_SOLID)
|
||||
start = &node->solid_edicts;
|
||||
else
|
||||
start = &node->trigger_edicts;
|
||||
|
||||
for (l=start->next ; l != start ; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
check = EDICT_FROM_AREA(l);
|
||||
|
||||
if (check->solid == SOLID_NOT)
|
||||
continue; // deactivated
|
||||
if (check->absmin[0] > area_maxs[0]
|
||||
|| check->absmin[1] > area_maxs[1]
|
||||
|| check->absmin[2] > area_maxs[2]
|
||||
|| check->absmax[0] < area_mins[0]
|
||||
|| check->absmax[1] < area_mins[1]
|
||||
|| check->absmax[2] < area_mins[2])
|
||||
continue; // not touching
|
||||
|
||||
if (area_count == area_maxcount)
|
||||
{
|
||||
Com_Printf ("SV_AreaEdicts: MAXCOUNT\n");
|
||||
return;
|
||||
}
|
||||
|
||||
area_list[area_count] = check;
|
||||
area_count++;
|
||||
}
|
||||
|
||||
if (node->axis == -1)
|
||||
return; // terminal node
|
||||
|
||||
// recurse down both sides
|
||||
if ( area_maxs[node->axis] > node->dist )
|
||||
SV_AreaEdicts_r ( node->children[0] );
|
||||
if ( area_mins[node->axis] < node->dist )
|
||||
SV_AreaEdicts_r ( node->children[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
SV_AreaEdicts
|
||||
================
|
||||
*/
|
||||
int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list,
|
||||
int maxcount, int areatype)
|
||||
{
|
||||
area_mins = mins;
|
||||
area_maxs = maxs;
|
||||
area_list = list;
|
||||
area_count = 0;
|
||||
area_maxcount = maxcount;
|
||||
area_type = areatype;
|
||||
|
||||
SV_AreaEdicts_r (sv_areanodes);
|
||||
|
||||
return area_count;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_PointContents
|
||||
=============
|
||||
*/
|
||||
int SV_PointContents (vec3_t p)
|
||||
{
|
||||
edict_t *touch[MAX_EDICTS], *hit;
|
||||
int i, num;
|
||||
int contents, c2;
|
||||
int headnode;
|
||||
float *angles;
|
||||
|
||||
// get base contents from world
|
||||
contents = CM_PointContents (p, sv.models[1]->headnode);
|
||||
|
||||
// or in contents from all the other entities
|
||||
num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID);
|
||||
|
||||
for (i=0 ; i<num ; i++)
|
||||
{
|
||||
hit = touch[i];
|
||||
|
||||
// might intersect, so do an exact clip
|
||||
headnode = SV_HullForEntity (hit);
|
||||
angles = hit->s.angles;
|
||||
if (hit->solid != SOLID_BSP)
|
||||
angles = vec3_origin; // boxes don't rotate
|
||||
|
||||
c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles);
|
||||
|
||||
contents |= c2;
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t boxmins, boxmaxs;// enclose the test object along entire move
|
||||
float *mins, *maxs; // size of the moving object
|
||||
vec3_t mins2, maxs2; // size when clipping against mosnters
|
||||
float *start, *end;
|
||||
trace_t trace;
|
||||
edict_t *passedict;
|
||||
int contentmask;
|
||||
} moveclip_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
SV_HullForEntity
|
||||
|
||||
Returns a headnode that can be used for testing or clipping an
|
||||
object of mins/maxs size.
|
||||
Offset is filled in to contain the adjustment that must be added to the
|
||||
testing object's origin to get a point to use with the returned hull.
|
||||
================
|
||||
*/
|
||||
int SV_HullForEntity (edict_t *ent)
|
||||
{
|
||||
cmodel_t *model;
|
||||
|
||||
// decide which clipping hull to use, based on the size
|
||||
if (ent->solid == SOLID_BSP)
|
||||
{ // explicit hulls in the BSP model
|
||||
model = sv.models[ ent->s.modelindex ];
|
||||
|
||||
if (!model)
|
||||
Com_Error (ERR_FATAL, "MOVETYPE_PUSH with a non bsp model");
|
||||
|
||||
return model->headnode;
|
||||
}
|
||||
|
||||
// create a temp hull from bounding box sizes
|
||||
|
||||
return CM_HeadnodeForBox (ent->mins, ent->maxs);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_ClipMoveToEntities
|
||||
|
||||
====================
|
||||
*/
|
||||
void SV_ClipMoveToEntities ( moveclip_t *clip )
|
||||
{
|
||||
int i, num;
|
||||
edict_t *touchlist[MAX_EDICTS], *touch;
|
||||
trace_t trace;
|
||||
int headnode;
|
||||
float *angles;
|
||||
|
||||
num = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist
|
||||
, MAX_EDICTS, AREA_SOLID);
|
||||
|
||||
// be careful, it is possible to have an entity in this
|
||||
// list removed before we get to it (killtriggered)
|
||||
for (i=0 ; i<num ; i++)
|
||||
{
|
||||
touch = touchlist[i];
|
||||
if (touch->solid == SOLID_NOT)
|
||||
continue;
|
||||
if (touch == clip->passedict)
|
||||
continue;
|
||||
if (clip->trace.allsolid)
|
||||
return;
|
||||
if (clip->passedict)
|
||||
{
|
||||
if (touch->owner == clip->passedict)
|
||||
continue; // don't clip against own missiles
|
||||
if (clip->passedict->owner == touch)
|
||||
continue; // don't clip against owner
|
||||
}
|
||||
|
||||
if ( !(clip->contentmask & CONTENTS_DEADMONSTER)
|
||||
&& (touch->svflags & SVF_DEADMONSTER) )
|
||||
continue;
|
||||
|
||||
// might intersect, so do an exact clip
|
||||
headnode = SV_HullForEntity (touch);
|
||||
angles = touch->s.angles;
|
||||
if (touch->solid != SOLID_BSP)
|
||||
angles = vec3_origin; // boxes don't rotate
|
||||
|
||||
if (touch->svflags & SVF_MONSTER)
|
||||
trace = CM_TransformedBoxTrace (clip->start, clip->end,
|
||||
clip->mins2, clip->maxs2, headnode, clip->contentmask,
|
||||
touch->s.origin, angles);
|
||||
else
|
||||
trace = CM_TransformedBoxTrace (clip->start, clip->end,
|
||||
clip->mins, clip->maxs, headnode, clip->contentmask,
|
||||
touch->s.origin, angles);
|
||||
|
||||
if (trace.allsolid || trace.startsolid ||
|
||||
trace.fraction < clip->trace.fraction)
|
||||
{
|
||||
trace.ent = touch;
|
||||
if (clip->trace.startsolid)
|
||||
{
|
||||
clip->trace = trace;
|
||||
clip->trace.startsolid = true;
|
||||
}
|
||||
else
|
||||
clip->trace = trace;
|
||||
}
|
||||
else if (trace.startsolid)
|
||||
clip->trace.startsolid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_TraceBounds
|
||||
==================
|
||||
*/
|
||||
void SV_TraceBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
|
||||
{
|
||||
#if 0
|
||||
// debug to test against everything
|
||||
boxmins[0] = boxmins[1] = boxmins[2] = -9999;
|
||||
boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
|
||||
#else
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (end[i] > start[i])
|
||||
{
|
||||
boxmins[i] = start[i] + mins[i] - 1;
|
||||
boxmaxs[i] = end[i] + maxs[i] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
boxmins[i] = end[i] + mins[i] - 1;
|
||||
boxmaxs[i] = start[i] + maxs[i] + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_Trace
|
||||
|
||||
Moves the given mins/maxs volume through the world from start to end.
|
||||
|
||||
Passedict and edicts owned by passedict are explicitly not checked.
|
||||
|
||||
==================
|
||||
*/
|
||||
trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
|
||||
{
|
||||
moveclip_t clip;
|
||||
|
||||
if (!mins)
|
||||
mins = vec3_origin;
|
||||
if (!maxs)
|
||||
maxs = vec3_origin;
|
||||
|
||||
memset ( &clip, 0, sizeof ( moveclip_t ) );
|
||||
|
||||
// clip to world
|
||||
clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask);
|
||||
clip.trace.ent = ge->edicts;
|
||||
if (clip.trace.fraction == 0)
|
||||
return clip.trace; // blocked by the world
|
||||
|
||||
clip.contentmask = contentmask;
|
||||
clip.start = start;
|
||||
clip.end = end;
|
||||
clip.mins = mins;
|
||||
clip.maxs = maxs;
|
||||
clip.passedict = passedict;
|
||||
|
||||
VectorCopy (mins, clip.mins2);
|
||||
VectorCopy (maxs, clip.maxs2);
|
||||
|
||||
// create the bounding box of the entire move
|
||||
SV_TraceBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
|
||||
|
||||
// clip to other solid entities
|
||||
SV_ClipMoveToEntities ( &clip );
|
||||
|
||||
return clip.trace;
|
||||
}
|
||||
|
||||
478
solaris/Makefile.OLD
Normal file
478
solaris/Makefile.OLD
Normal file
@@ -0,0 +1,478 @@
|
||||
#
|
||||
# Quake2 Makefile for Solaris
|
||||
#
|
||||
# Jan '98 by Zoid <zoid@idsoftware.com>
|
||||
#
|
||||
|
||||
ifneq (,$(findstring i86pc,$(shell uname -m)))
|
||||
ARCH=i386
|
||||
else
|
||||
ARCH=sparc
|
||||
endif
|
||||
|
||||
MOUNT_DIR=/chest/Quake2/code
|
||||
|
||||
BUILD_DEBUG_DIR=debug$(ARCH)
|
||||
BUILD_RELEASE_DIR=release$(ARCH)
|
||||
CLIENT_DIR=$(MOUNT_DIR)/client
|
||||
SERVER_DIR=$(MOUNT_DIR)/server
|
||||
COMMON_DIR=$(MOUNT_DIR)/qcommon
|
||||
SOLARIS_DIR=$(MOUNT_DIR)/solaris
|
||||
GAME_DIR=$(MOUNT_DIR)/game
|
||||
XATRIX_DIR=$(MOUNT_DIR)/xatrix
|
||||
CTF_DIR=$(MOUNT_DIR)/game
|
||||
NULL_DIR=$(MOUNT_DIR)/null
|
||||
|
||||
ARCH=i386
|
||||
|
||||
CC=gcc
|
||||
BASE_CFLAGS=-Dstricmp=strcasecmp
|
||||
RELEASE_CFLAGS=$(BASE_CFLAGS) -O6 -fomit-frame-pointer -fno-strength-reduce -funroll-loops -fexpensive-optimizations
|
||||
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
|
||||
LDFLAGS=-ldl -lm -lnsl -lsocket
|
||||
|
||||
SHLIBEXT=so
|
||||
|
||||
SHLIBCFLAGS=-fPIC
|
||||
SHLIBLDFLAGS=-G
|
||||
|
||||
DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
|
||||
DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
|
||||
|
||||
#############################################################################
|
||||
# SETUP AND BUILD
|
||||
#############################################################################
|
||||
|
||||
TARGETS=$(BUILDDIR)/quake2 $(BUILDDIR)/game$(ARCH).$(SHLIBEXT)
|
||||
|
||||
build_debug:
|
||||
@-mkdir $(BUILD_DEBUG_DIR) \
|
||||
$(BUILD_DEBUG_DIR)/client \
|
||||
$(BUILD_DEBUG_DIR)/game
|
||||
$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
build_release:
|
||||
@-mkdir $(BUILD_RELEASE_DIR) \
|
||||
$(BUILD_RELEASE_DIR)/client \
|
||||
$(BUILD_RELEASE_DIR)/game
|
||||
$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
|
||||
|
||||
all: build_debug build_release
|
||||
|
||||
targets: $(TARGETS)
|
||||
|
||||
#############################################################################
|
||||
# CLIENT/SERVER
|
||||
#############################################################################
|
||||
|
||||
QUAKE2_OBJS = \
|
||||
$(BUILDDIR)/client/cl_cin.o \
|
||||
$(BUILDDIR)/client/cl_ents.o \
|
||||
$(BUILDDIR)/client/cl_fx.o \
|
||||
$(BUILDDIR)/client/cl_input.o \
|
||||
$(BUILDDIR)/client/cl_inv.o \
|
||||
$(BUILDDIR)/client/cl_main.o \
|
||||
$(BUILDDIR)/client/cl_parse.o \
|
||||
$(BUILDDIR)/client/cl_pred.o \
|
||||
$(BUILDDIR)/client/cl_tent.o \
|
||||
$(BUILDDIR)/client/cl_scrn.o \
|
||||
$(BUILDDIR)/client/cl_view.o \
|
||||
$(BUILDDIR)/client/console.o \
|
||||
$(BUILDDIR)/client/keys.o \
|
||||
$(BUILDDIR)/client/menu.o \
|
||||
$(BUILDDIR)/client/qmenu.o \
|
||||
$(BUILDDIR)/client/m_flash.o \
|
||||
\
|
||||
$(BUILDDIR)/client/cmd.o \
|
||||
$(BUILDDIR)/client/cmodel.o \
|
||||
$(BUILDDIR)/client/common.o \
|
||||
$(BUILDDIR)/client/cvar.o \
|
||||
$(BUILDDIR)/client/files.o \
|
||||
$(BUILDDIR)/client/md4.o \
|
||||
$(BUILDDIR)/client/net_chan.o \
|
||||
\
|
||||
$(BUILDDIR)/client/sv_ccmds.o \
|
||||
$(BUILDDIR)/client/sv_ents.o \
|
||||
$(BUILDDIR)/client/sv_game.o \
|
||||
$(BUILDDIR)/client/sv_init.o \
|
||||
$(BUILDDIR)/client/sv_main.o \
|
||||
$(BUILDDIR)/client/sv_send.o \
|
||||
$(BUILDDIR)/client/sv_user.o \
|
||||
$(BUILDDIR)/client/sv_world.o \
|
||||
\
|
||||
$(BUILDDIR)/client/snd_dma.o \
|
||||
$(BUILDDIR)/client/snd_mem.o \
|
||||
$(BUILDDIR)/client/snd_mix.o \
|
||||
\
|
||||
$(BUILDDIR)/client/cd_null.o \
|
||||
$(BUILDDIR)/client/q_shsolaris.o \
|
||||
$(BUILDDIR)/client/vid_null.o \
|
||||
$(BUILDDIR)/client/ref_null.o \
|
||||
$(BUILDDIR)/client/in_null.o \
|
||||
$(BUILDDIR)/client/snddma_null.o \
|
||||
$(BUILDDIR)/client/sys_solaris.o \
|
||||
$(BUILDDIR)/client/glob.o \
|
||||
$(BUILDDIR)/client/net_udp.o \
|
||||
\
|
||||
$(BUILDDIR)/client/q_shared.o \
|
||||
$(BUILDDIR)/client/pmove.o
|
||||
|
||||
$(BUILDDIR)/quake2 : $(QUAKE2_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(LDFLAGS)
|
||||
|
||||
$(BUILDDIR)/client/cl_cin.o : $(CLIENT_DIR)/cl_cin.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_ents.o : $(CLIENT_DIR)/cl_ents.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_fx.o : $(CLIENT_DIR)/cl_fx.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_input.o : $(CLIENT_DIR)/cl_input.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_inv.o : $(CLIENT_DIR)/cl_inv.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_main.o : $(CLIENT_DIR)/cl_main.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_parse.o : $(CLIENT_DIR)/cl_parse.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_pred.o : $(CLIENT_DIR)/cl_pred.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_tent.o : $(CLIENT_DIR)/cl_tent.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_scrn.o : $(CLIENT_DIR)/cl_scrn.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_view.o : $(CLIENT_DIR)/cl_view.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/console.o : $(CLIENT_DIR)/console.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/keys.o : $(CLIENT_DIR)/keys.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/menu.o : $(CLIENT_DIR)/menu.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/qmenu.o : $(CLIENT_DIR)/qmenu.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/m_flash.o : $(GAME_DIR)/m_flash.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cmd.o : $(COMMON_DIR)/cmd.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cmodel.o : $(COMMON_DIR)/cmodel.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/common.o : $(COMMON_DIR)/common.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cvar.o : $(COMMON_DIR)/cvar.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/files.o : $(COMMON_DIR)/files.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/md4.o : $(COMMON_DIR)/md4.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/net_chan.o : $(COMMON_DIR)/net_chan.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/q_shared.o : $(GAME_DIR)/q_shared.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/pmove.o : $(COMMON_DIR)/pmove.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_ccmds.o : $(SERVER_DIR)/sv_ccmds.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_ents.o : $(SERVER_DIR)/sv_ents.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_game.o : $(SERVER_DIR)/sv_game.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_init.o : $(SERVER_DIR)/sv_init.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_main.o : $(SERVER_DIR)/sv_main.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_send.o : $(SERVER_DIR)/sv_send.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_user.o : $(SERVER_DIR)/sv_user.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_world.o : $(SERVER_DIR)/sv_world.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cd_null.o : $(NULL_DIR)/cd_null.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/q_shsolaris.o : $(SOLARIS_DIR)/q_shsolaris.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/vid_null.o : $(NULL_DIR)/vid_null.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/ref_null.o : $(NULL_DIR)/ref_null.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/snddma_null.o : $(NULL_DIR)/snddma_null.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/snd_dma.o : $(CLIENT_DIR)/snd_dma.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/snd_mem.o : $(CLIENT_DIR)/snd_mem.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/snd_mix.o : $(CLIENT_DIR)/snd_mix.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/in_null.o : $(NULL_DIR)/in_null.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sys_solaris.o : $(SOLARIS_DIR)/sys_solaris.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/glob.o : $(SOLARIS_DIR)/glob.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/net_udp.o : $(SOLARIS_DIR)/net_udp.c
|
||||
$(DO_CC)
|
||||
|
||||
#############################################################################
|
||||
# GAME
|
||||
#############################################################################
|
||||
|
||||
GAME_OBJS = \
|
||||
$(BUILDDIR)/game/g_ai.o \
|
||||
$(BUILDDIR)/game/p_client.o \
|
||||
$(BUILDDIR)/game/g_cmds.o \
|
||||
$(BUILDDIR)/game/g_svcmds.o \
|
||||
$(BUILDDIR)/game/g_combat.o \
|
||||
$(BUILDDIR)/game/g_func.o \
|
||||
$(BUILDDIR)/game/g_items.o \
|
||||
$(BUILDDIR)/game/g_main.o \
|
||||
$(BUILDDIR)/game/g_misc.o \
|
||||
$(BUILDDIR)/game/g_monster.o \
|
||||
$(BUILDDIR)/game/g_phys.o \
|
||||
$(BUILDDIR)/game/g_save.o \
|
||||
$(BUILDDIR)/game/g_spawn.o \
|
||||
$(BUILDDIR)/game/g_target.o \
|
||||
$(BUILDDIR)/game/g_trigger.o \
|
||||
$(BUILDDIR)/game/g_turret.o \
|
||||
$(BUILDDIR)/game/g_utils.o \
|
||||
$(BUILDDIR)/game/g_weapon.o \
|
||||
$(BUILDDIR)/game/m_actor.o \
|
||||
$(BUILDDIR)/game/m_berserk.o \
|
||||
$(BUILDDIR)/game/m_boss2.o \
|
||||
$(BUILDDIR)/game/m_boss3.o \
|
||||
$(BUILDDIR)/game/m_boss31.o \
|
||||
$(BUILDDIR)/game/m_boss32.o \
|
||||
$(BUILDDIR)/game/m_brain.o \
|
||||
$(BUILDDIR)/game/m_chick.o \
|
||||
$(BUILDDIR)/game/m_flipper.o \
|
||||
$(BUILDDIR)/game/m_float.o \
|
||||
$(BUILDDIR)/game/m_flyer.o \
|
||||
$(BUILDDIR)/game/m_gladiator.o \
|
||||
$(BUILDDIR)/game/m_gunner.o \
|
||||
$(BUILDDIR)/game/m_hover.o \
|
||||
$(BUILDDIR)/game/m_infantry.o \
|
||||
$(BUILDDIR)/game/m_insane.o \
|
||||
$(BUILDDIR)/game/m_medic.o \
|
||||
$(BUILDDIR)/game/m_move.o \
|
||||
$(BUILDDIR)/game/m_mutant.o \
|
||||
$(BUILDDIR)/game/m_parasite.o \
|
||||
$(BUILDDIR)/game/m_soldier.o \
|
||||
$(BUILDDIR)/game/m_supertank.o \
|
||||
$(BUILDDIR)/game/m_tank.o \
|
||||
$(BUILDDIR)/game/p_hud.o \
|
||||
$(BUILDDIR)/game/p_trail.o \
|
||||
$(BUILDDIR)/game/p_view.o \
|
||||
$(BUILDDIR)/game/p_weapon.o \
|
||||
$(BUILDDIR)/game/q_shared.o \
|
||||
$(BUILDDIR)/game/m_flash.o \
|
||||
$(BUILDDIR)/game/g_so.o
|
||||
|
||||
$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
|
||||
$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
|
||||
|
||||
$(BUILDDIR)/game/g_ai.o : $(GAME_DIR)/g_ai.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_client.o : $(GAME_DIR)/p_client.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_cmds.o : $(GAME_DIR)/g_cmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_svcmds.o : $(GAME_DIR)/g_svcmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_combat.o : $(GAME_DIR)/g_combat.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_func.o : $(GAME_DIR)/g_func.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_items.o : $(GAME_DIR)/g_items.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_main.o : $(GAME_DIR)/g_main.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_misc.o : $(GAME_DIR)/g_misc.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_monster.o : $(GAME_DIR)/g_monster.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_phys.o : $(GAME_DIR)/g_phys.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_save.o : $(GAME_DIR)/g_save.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_spawn.o : $(GAME_DIR)/g_spawn.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_target.o : $(GAME_DIR)/g_target.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_trigger.o : $(GAME_DIR)/g_trigger.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_turret.o : $(GAME_DIR)/g_turret.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_utils.o : $(GAME_DIR)/g_utils.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_weapon.o : $(GAME_DIR)/g_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_actor.o : $(GAME_DIR)/m_actor.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_berserk.o : $(GAME_DIR)/m_berserk.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss2.o : $(GAME_DIR)/m_boss2.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss3.o : $(GAME_DIR)/m_boss3.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss31.o : $(GAME_DIR)/m_boss31.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss32.o : $(GAME_DIR)/m_boss32.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_brain.o : $(GAME_DIR)/m_brain.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_chick.o : $(GAME_DIR)/m_chick.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_flipper.o : $(GAME_DIR)/m_flipper.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_float.o : $(GAME_DIR)/m_float.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_flyer.o : $(GAME_DIR)/m_flyer.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_gladiator.o : $(GAME_DIR)/m_gladiator.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_gunner.o : $(GAME_DIR)/m_gunner.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_hover.o : $(GAME_DIR)/m_hover.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_infantry.o : $(GAME_DIR)/m_infantry.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_insane.o : $(GAME_DIR)/m_insane.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_medic.o : $(GAME_DIR)/m_medic.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_move.o : $(GAME_DIR)/m_move.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_mutant.o : $(GAME_DIR)/m_mutant.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_parasite.o : $(GAME_DIR)/m_parasite.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_soldier.o : $(GAME_DIR)/m_soldier.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_supertank.o : $(GAME_DIR)/m_supertank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_tank.o : $(GAME_DIR)/m_tank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_hud.o : $(GAME_DIR)/p_hud.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_trail.o : $(GAME_DIR)/p_trail.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_view.o : $(GAME_DIR)/p_view.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_weapon.o : $(GAME_DIR)/p_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/q_shared.o : $(GAME_DIR)/q_shared.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_flash.o : $(GAME_DIR)/m_flash.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_so.o : $(SOLARIS_DIR)/g_so.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
#############################################################################
|
||||
# MISC
|
||||
#############################################################################
|
||||
|
||||
clean: clean-debug clean-release
|
||||
|
||||
clean-debug:
|
||||
$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
clean-release:
|
||||
$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
clean2:
|
||||
-rm -f $(QUAKE2_OBJS) \
|
||||
$(GAME_OBJS) \
|
||||
$(REF_SOFT_OBJS) \
|
||||
$(REF_SOFT_SVGA_OBJS) \
|
||||
$(REF_SOFT_X11_OBJS) \
|
||||
$(REF_GL_OBJS)
|
||||
|
||||
719
solaris/Makefile.Solaris
Normal file
719
solaris/Makefile.Solaris
Normal file
@@ -0,0 +1,719 @@
|
||||
#
|
||||
# Quake2 Makefile for Solaris
|
||||
#
|
||||
# Nov '97 by Zoid <zoid@idsoftware.com>
|
||||
#
|
||||
# ELF only
|
||||
#
|
||||
|
||||
ifneq (,$(findstring i86pc,$(shell uname -m)))
|
||||
ARCH=i386
|
||||
else
|
||||
ARCH=sparc
|
||||
endif
|
||||
|
||||
MOUNT_DIR=/chest/Quake2/code
|
||||
|
||||
BUILD_DEBUG_DIR=debug$(ARCH)
|
||||
BUILD_RELEASE_DIR=release$(ARCH)
|
||||
CLIENT_DIR=$(MOUNT_DIR)/client
|
||||
SERVER_DIR=$(MOUNT_DIR)/server
|
||||
COMMON_DIR=$(MOUNT_DIR)/qcommon
|
||||
SOLARIS_DIR=$(MOUNT_DIR)/solaris
|
||||
GAME_DIR=$(MOUNT_DIR)/game
|
||||
CTF_DIR=$(MOUNT_DIR)/ctf
|
||||
XATRIX_DIR=$(MOUNT_DIR)/xatrix
|
||||
NULL_DIR=$(MOUNT_DIR)/null
|
||||
|
||||
CC=gcc
|
||||
BASE_CFLAGS=-Dstricmp=strcasecmp -DC_ONLY -DDEDICATED_ONLY
|
||||
RELEASE_CFLAGS=$(BASE_CFLAGS) -ffast-math -funroll-loops \
|
||||
-fomit-frame-pointer -fexpensive-optimizations
|
||||
|
||||
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
|
||||
LDFLAGS=-ldl -lm -lsocket -lnsl
|
||||
|
||||
SHLIBEXT=so
|
||||
|
||||
SHLIBCFLAGS=-fPIC
|
||||
SHLIBLDFLAGS=-shared
|
||||
|
||||
DO_CC=$(CC) $(CFLAGS) -o $@ -c $<
|
||||
DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $<
|
||||
|
||||
#############################################################################
|
||||
# SETUP AND BUILD
|
||||
#############################################################################
|
||||
|
||||
TARGETS=$(BUILDDIR)/q2ded \
|
||||
$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) \
|
||||
$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) \
|
||||
$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT)
|
||||
|
||||
build_debug:
|
||||
@-mkdir $(BUILD_DEBUG_DIR) \
|
||||
$(BUILD_DEBUG_DIR)/client \
|
||||
$(BUILD_DEBUG_DIR)/game \
|
||||
$(BUILD_DEBUG_DIR)/ctf \
|
||||
$(BUILD_DEBUG_DIR)/xatrix
|
||||
$(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
build_release:
|
||||
@-mkdir $(BUILD_RELEASE_DIR) \
|
||||
$(BUILD_RELEASE_DIR)/client \
|
||||
$(BUILD_RELEASE_DIR)/game \
|
||||
$(BUILD_RELEASE_DIR)/ctf \
|
||||
$(BUILD_RELEASE_DIR)/xatrix
|
||||
$(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)"
|
||||
|
||||
all: build_debug build_release
|
||||
|
||||
targets: $(TARGETS)
|
||||
|
||||
#############################################################################
|
||||
# CLIENT/SERVER
|
||||
#############################################################################
|
||||
|
||||
QUAKE2_OBJS = \
|
||||
\
|
||||
$(BUILDDIR)/client/cmd.o \
|
||||
$(BUILDDIR)/client/cmodel.o \
|
||||
$(BUILDDIR)/client/common.o \
|
||||
$(BUILDDIR)/client/crc.o \
|
||||
$(BUILDDIR)/client/cvar.o \
|
||||
$(BUILDDIR)/client/files.o \
|
||||
$(BUILDDIR)/client/md4.o \
|
||||
$(BUILDDIR)/client/net_chan.o \
|
||||
\
|
||||
$(BUILDDIR)/client/sv_ccmds.o \
|
||||
$(BUILDDIR)/client/sv_ents.o \
|
||||
$(BUILDDIR)/client/sv_game.o \
|
||||
$(BUILDDIR)/client/sv_init.o \
|
||||
$(BUILDDIR)/client/sv_main.o \
|
||||
$(BUILDDIR)/client/sv_send.o \
|
||||
$(BUILDDIR)/client/sv_user.o \
|
||||
$(BUILDDIR)/client/sv_world.o \
|
||||
\
|
||||
$(BUILDDIR)/client/q_shsolaris.o \
|
||||
$(BUILDDIR)/client/sys_solaris.o \
|
||||
$(BUILDDIR)/client/glob.o \
|
||||
$(BUILDDIR)/client/net_udp.o \
|
||||
\
|
||||
$(BUILDDIR)/client/q_shared.o \
|
||||
$(BUILDDIR)/client/pmove.o \
|
||||
\
|
||||
$(BUILDDIR)/client/cl_null.o \
|
||||
$(BUILDDIR)/client/cd_null.o
|
||||
|
||||
$(BUILDDIR)/q2ded : $(QUAKE2_OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(QUAKE2_OBJS) $(LDFLAGS)
|
||||
|
||||
$(BUILDDIR)/client/cmd.o : $(COMMON_DIR)/cmd.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cmodel.o : $(COMMON_DIR)/cmodel.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/common.o : $(COMMON_DIR)/common.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/crc.o : $(COMMON_DIR)/crc.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cvar.o : $(COMMON_DIR)/cvar.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/files.o : $(COMMON_DIR)/files.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/md4.o : $(COMMON_DIR)/md4.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/net_chan.o : $(COMMON_DIR)/net_chan.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/q_shared.o : $(GAME_DIR)/q_shared.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/pmove.o : $(COMMON_DIR)/pmove.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_ccmds.o : $(SERVER_DIR)/sv_ccmds.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_ents.o : $(SERVER_DIR)/sv_ents.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_game.o : $(SERVER_DIR)/sv_game.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_init.o : $(SERVER_DIR)/sv_init.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_main.o : $(SERVER_DIR)/sv_main.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_send.o : $(SERVER_DIR)/sv_send.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_user.o : $(SERVER_DIR)/sv_user.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sv_world.o : $(SERVER_DIR)/sv_world.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/q_shsolaris.o : $(SOLARIS_DIR)/q_shsolaris.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/sys_solaris.o : $(SOLARIS_DIR)/sys_solaris.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/glob.o : $(SOLARIS_DIR)/glob.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/net_udp.o : $(SOLARIS_DIR)/net_udp.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cd_null.o : $(NULL_DIR)/cd_null.c
|
||||
$(DO_CC)
|
||||
|
||||
$(BUILDDIR)/client/cl_null.o : $(NULL_DIR)/cl_null.c
|
||||
$(DO_CC)
|
||||
|
||||
#############################################################################
|
||||
# GAME
|
||||
#############################################################################
|
||||
|
||||
GAME_OBJS = \
|
||||
$(BUILDDIR)/game/g_ai.o \
|
||||
$(BUILDDIR)/game/p_client.o \
|
||||
$(BUILDDIR)/game/g_cmds.o \
|
||||
$(BUILDDIR)/game/g_svcmds.o \
|
||||
$(BUILDDIR)/game/g_combat.o \
|
||||
$(BUILDDIR)/game/g_func.o \
|
||||
$(BUILDDIR)/game/g_items.o \
|
||||
$(BUILDDIR)/game/g_main.o \
|
||||
$(BUILDDIR)/game/g_misc.o \
|
||||
$(BUILDDIR)/game/g_monster.o \
|
||||
$(BUILDDIR)/game/g_phys.o \
|
||||
$(BUILDDIR)/game/g_save.o \
|
||||
$(BUILDDIR)/game/g_spawn.o \
|
||||
$(BUILDDIR)/game/g_target.o \
|
||||
$(BUILDDIR)/game/g_trigger.o \
|
||||
$(BUILDDIR)/game/g_turret.o \
|
||||
$(BUILDDIR)/game/g_utils.o \
|
||||
$(BUILDDIR)/game/g_weapon.o \
|
||||
$(BUILDDIR)/game/m_actor.o \
|
||||
$(BUILDDIR)/game/m_berserk.o \
|
||||
$(BUILDDIR)/game/m_boss2.o \
|
||||
$(BUILDDIR)/game/m_boss3.o \
|
||||
$(BUILDDIR)/game/m_boss31.o \
|
||||
$(BUILDDIR)/game/m_boss32.o \
|
||||
$(BUILDDIR)/game/m_brain.o \
|
||||
$(BUILDDIR)/game/m_chick.o \
|
||||
$(BUILDDIR)/game/m_flipper.o \
|
||||
$(BUILDDIR)/game/m_float.o \
|
||||
$(BUILDDIR)/game/m_flyer.o \
|
||||
$(BUILDDIR)/game/m_gladiator.o \
|
||||
$(BUILDDIR)/game/m_gunner.o \
|
||||
$(BUILDDIR)/game/m_hover.o \
|
||||
$(BUILDDIR)/game/m_infantry.o \
|
||||
$(BUILDDIR)/game/m_insane.o \
|
||||
$(BUILDDIR)/game/m_medic.o \
|
||||
$(BUILDDIR)/game/m_move.o \
|
||||
$(BUILDDIR)/game/m_mutant.o \
|
||||
$(BUILDDIR)/game/m_parasite.o \
|
||||
$(BUILDDIR)/game/m_soldier.o \
|
||||
$(BUILDDIR)/game/m_supertank.o \
|
||||
$(BUILDDIR)/game/m_tank.o \
|
||||
$(BUILDDIR)/game/p_hud.o \
|
||||
$(BUILDDIR)/game/p_trail.o \
|
||||
$(BUILDDIR)/game/p_view.o \
|
||||
$(BUILDDIR)/game/p_weapon.o \
|
||||
$(BUILDDIR)/game/q_shared.o \
|
||||
$(BUILDDIR)/game/m_flash.o
|
||||
|
||||
$(BUILDDIR)/game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
|
||||
$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
|
||||
|
||||
$(BUILDDIR)/game/g_ai.o : $(GAME_DIR)/g_ai.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_client.o : $(GAME_DIR)/p_client.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_cmds.o : $(GAME_DIR)/g_cmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_svcmds.o : $(GAME_DIR)/g_svcmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_combat.o : $(GAME_DIR)/g_combat.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_func.o : $(GAME_DIR)/g_func.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_items.o : $(GAME_DIR)/g_items.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_main.o : $(GAME_DIR)/g_main.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_misc.o : $(GAME_DIR)/g_misc.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_monster.o : $(GAME_DIR)/g_monster.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_phys.o : $(GAME_DIR)/g_phys.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_save.o : $(GAME_DIR)/g_save.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_spawn.o : $(GAME_DIR)/g_spawn.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_target.o : $(GAME_DIR)/g_target.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_trigger.o : $(GAME_DIR)/g_trigger.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_turret.o : $(GAME_DIR)/g_turret.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_utils.o : $(GAME_DIR)/g_utils.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/g_weapon.o : $(GAME_DIR)/g_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_actor.o : $(GAME_DIR)/m_actor.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_berserk.o : $(GAME_DIR)/m_berserk.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss2.o : $(GAME_DIR)/m_boss2.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss3.o : $(GAME_DIR)/m_boss3.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss31.o : $(GAME_DIR)/m_boss31.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_boss32.o : $(GAME_DIR)/m_boss32.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_brain.o : $(GAME_DIR)/m_brain.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_chick.o : $(GAME_DIR)/m_chick.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_flipper.o : $(GAME_DIR)/m_flipper.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_float.o : $(GAME_DIR)/m_float.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_flyer.o : $(GAME_DIR)/m_flyer.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_gladiator.o : $(GAME_DIR)/m_gladiator.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_gunner.o : $(GAME_DIR)/m_gunner.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_hover.o : $(GAME_DIR)/m_hover.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_infantry.o : $(GAME_DIR)/m_infantry.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_insane.o : $(GAME_DIR)/m_insane.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_medic.o : $(GAME_DIR)/m_medic.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_move.o : $(GAME_DIR)/m_move.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_mutant.o : $(GAME_DIR)/m_mutant.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_parasite.o : $(GAME_DIR)/m_parasite.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_soldier.o : $(GAME_DIR)/m_soldier.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_supertank.o : $(GAME_DIR)/m_supertank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_tank.o : $(GAME_DIR)/m_tank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_hud.o : $(GAME_DIR)/p_hud.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_trail.o : $(GAME_DIR)/p_trail.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_view.o : $(GAME_DIR)/p_view.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/p_weapon.o : $(GAME_DIR)/p_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/q_shared.o : $(GAME_DIR)/q_shared.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/game/m_flash.o : $(GAME_DIR)/m_flash.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
#############################################################################
|
||||
# CTF
|
||||
#############################################################################
|
||||
|
||||
CTF_OBJS = \
|
||||
$(BUILDDIR)/ctf/g_ai.o \
|
||||
$(BUILDDIR)/ctf/g_chase.o \
|
||||
$(BUILDDIR)/ctf/g_cmds.o \
|
||||
$(BUILDDIR)/ctf/g_combat.o \
|
||||
$(BUILDDIR)/ctf/g_ctf.o \
|
||||
$(BUILDDIR)/ctf/g_func.o \
|
||||
$(BUILDDIR)/ctf/g_items.o \
|
||||
$(BUILDDIR)/ctf/g_main.o \
|
||||
$(BUILDDIR)/ctf/g_misc.o \
|
||||
$(BUILDDIR)/ctf/g_monster.o \
|
||||
$(BUILDDIR)/ctf/g_phys.o \
|
||||
$(BUILDDIR)/ctf/g_save.o \
|
||||
$(BUILDDIR)/ctf/g_spawn.o \
|
||||
$(BUILDDIR)/ctf/g_svcmds.o \
|
||||
$(BUILDDIR)/ctf/g_target.o \
|
||||
$(BUILDDIR)/ctf/g_trigger.o \
|
||||
$(BUILDDIR)/ctf/g_utils.o \
|
||||
$(BUILDDIR)/ctf/g_weapon.o \
|
||||
$(BUILDDIR)/ctf/m_move.o \
|
||||
$(BUILDDIR)/ctf/p_client.o \
|
||||
$(BUILDDIR)/ctf/p_hud.o \
|
||||
$(BUILDDIR)/ctf/p_menu.o \
|
||||
$(BUILDDIR)/ctf/p_trail.o \
|
||||
$(BUILDDIR)/ctf/p_view.o \
|
||||
$(BUILDDIR)/ctf/p_weapon.o \
|
||||
$(BUILDDIR)/ctf/q_shared.o
|
||||
|
||||
$(BUILDDIR)/ctf/game$(ARCH).$(SHLIBEXT) : $(CTF_OBJS)
|
||||
$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CTF_OBJS)
|
||||
|
||||
$(BUILDDIR)/ctf/g_ai.o : $(CTF_DIR)/g_ai.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_chase.o : $(CTF_DIR)/g_chase.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_cmds.o : $(CTF_DIR)/g_cmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_combat.o : $(CTF_DIR)/g_combat.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_ctf.o : $(CTF_DIR)/g_ctf.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_func.o : $(CTF_DIR)/g_func.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_items.o : $(CTF_DIR)/g_items.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_main.o : $(CTF_DIR)/g_main.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_misc.o : $(CTF_DIR)/g_misc.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_monster.o : $(CTF_DIR)/g_monster.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_phys.o : $(CTF_DIR)/g_phys.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_save.o : $(CTF_DIR)/g_save.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_spawn.o : $(CTF_DIR)/g_spawn.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_svcmds.o : $(CTF_DIR)/g_svcmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_target.o : $(CTF_DIR)/g_target.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_trigger.o : $(CTF_DIR)/g_trigger.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_utils.o : $(CTF_DIR)/g_utils.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/g_weapon.o : $(CTF_DIR)/g_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/m_move.o : $(CTF_DIR)/m_move.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/p_client.o : $(CTF_DIR)/p_client.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/p_hud.o : $(CTF_DIR)/p_hud.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/p_menu.o : $(CTF_DIR)/p_menu.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/p_trail.o : $(CTF_DIR)/p_trail.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/p_view.o : $(CTF_DIR)/p_view.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/p_weapon.o : $(CTF_DIR)/p_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/ctf/q_shared.o : $(CTF_DIR)/q_shared.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
#############################################################################
|
||||
# XATRIX
|
||||
#############################################################################
|
||||
|
||||
XATRIX_OBJS = \
|
||||
$(BUILDDIR)/xatrix/g_ai.o \
|
||||
$(BUILDDIR)/xatrix/g_cmds.o \
|
||||
$(BUILDDIR)/xatrix/g_combat.o \
|
||||
$(BUILDDIR)/xatrix/g_func.o \
|
||||
$(BUILDDIR)/xatrix/g_items.o \
|
||||
$(BUILDDIR)/xatrix/g_main.o \
|
||||
$(BUILDDIR)/xatrix/g_misc.o \
|
||||
$(BUILDDIR)/xatrix/g_monster.o \
|
||||
$(BUILDDIR)/xatrix/g_phys.o \
|
||||
$(BUILDDIR)/xatrix/g_save.o \
|
||||
$(BUILDDIR)/xatrix/g_spawn.o \
|
||||
$(BUILDDIR)/xatrix/g_svcmds.o \
|
||||
$(BUILDDIR)/xatrix/g_target.o \
|
||||
$(BUILDDIR)/xatrix/g_trigger.o \
|
||||
$(BUILDDIR)/xatrix/g_turret.o \
|
||||
$(BUILDDIR)/xatrix/g_utils.o \
|
||||
$(BUILDDIR)/xatrix/g_weapon.o \
|
||||
$(BUILDDIR)/xatrix/m_actor.o \
|
||||
$(BUILDDIR)/xatrix/m_berserk.o \
|
||||
$(BUILDDIR)/xatrix/m_boss2.o \
|
||||
$(BUILDDIR)/xatrix/m_boss3.o \
|
||||
$(BUILDDIR)/xatrix/m_boss31.o \
|
||||
$(BUILDDIR)/xatrix/m_boss32.o \
|
||||
$(BUILDDIR)/xatrix/m_boss5.o \
|
||||
$(BUILDDIR)/xatrix/m_brain.o \
|
||||
$(BUILDDIR)/xatrix/m_chick.o \
|
||||
$(BUILDDIR)/xatrix/m_fixbot.o \
|
||||
$(BUILDDIR)/xatrix/m_flash.o \
|
||||
$(BUILDDIR)/xatrix/m_flipper.o \
|
||||
$(BUILDDIR)/xatrix/m_float.o \
|
||||
$(BUILDDIR)/xatrix/m_flyer.o \
|
||||
$(BUILDDIR)/xatrix/m_gekk.o \
|
||||
$(BUILDDIR)/xatrix/m_gladb.o \
|
||||
$(BUILDDIR)/xatrix/m_gladiator.o \
|
||||
$(BUILDDIR)/xatrix/m_gunner.o \
|
||||
$(BUILDDIR)/xatrix/m_hover.o \
|
||||
$(BUILDDIR)/xatrix/m_infantry.o \
|
||||
$(BUILDDIR)/xatrix/m_insane.o \
|
||||
$(BUILDDIR)/xatrix/m_medic.o \
|
||||
$(BUILDDIR)/xatrix/m_move.o \
|
||||
$(BUILDDIR)/xatrix/m_mutant.o \
|
||||
$(BUILDDIR)/xatrix/m_parasite.o \
|
||||
$(BUILDDIR)/xatrix/m_soldier.o \
|
||||
$(BUILDDIR)/xatrix/m_supertank.o \
|
||||
$(BUILDDIR)/xatrix/m_tank.o \
|
||||
$(BUILDDIR)/xatrix/p_client.o \
|
||||
$(BUILDDIR)/xatrix/p_hud.o \
|
||||
$(BUILDDIR)/xatrix/p_trail.o \
|
||||
$(BUILDDIR)/xatrix/p_view.o \
|
||||
$(BUILDDIR)/xatrix/p_weapon.o \
|
||||
$(BUILDDIR)/xatrix/q_shared.o
|
||||
|
||||
$(BUILDDIR)/xatrix/game$(ARCH).$(SHLIBEXT) : $(XATRIX_OBJS)
|
||||
$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(XATRIX_OBJS)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_ai.o : $(XATRIX_DIR)/g_ai.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_cmds.o : $(XATRIX_DIR)/g_cmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_combat.o : $(XATRIX_DIR)/g_combat.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_func.o : $(XATRIX_DIR)/g_func.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_items.o : $(XATRIX_DIR)/g_items.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_main.o : $(XATRIX_DIR)/g_main.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_misc.o : $(XATRIX_DIR)/g_misc.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_monster.o : $(XATRIX_DIR)/g_monster.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_phys.o : $(XATRIX_DIR)/g_phys.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_save.o : $(XATRIX_DIR)/g_save.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_spawn.o : $(XATRIX_DIR)/g_spawn.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_svcmds.o : $(XATRIX_DIR)/g_svcmds.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_target.o : $(XATRIX_DIR)/g_target.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_trigger.o : $(XATRIX_DIR)/g_trigger.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_turret.o : $(XATRIX_DIR)/g_turret.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_utils.o : $(XATRIX_DIR)/g_utils.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/g_weapon.o : $(XATRIX_DIR)/g_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_actor.o : $(XATRIX_DIR)/m_actor.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_berserk.o : $(XATRIX_DIR)/m_berserk.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_boss2.o : $(XATRIX_DIR)/m_boss2.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_boss3.o : $(XATRIX_DIR)/m_boss3.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_boss31.o : $(XATRIX_DIR)/m_boss31.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_boss32.o : $(XATRIX_DIR)/m_boss32.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_boss5.o : $(XATRIX_DIR)/m_boss5.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_brain.o : $(XATRIX_DIR)/m_brain.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_chick.o : $(XATRIX_DIR)/m_chick.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_fixbot.o : $(XATRIX_DIR)/m_fixbot.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_flash.o : $(XATRIX_DIR)/m_flash.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_flipper.o : $(XATRIX_DIR)/m_flipper.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_float.o : $(XATRIX_DIR)/m_float.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_flyer.o : $(XATRIX_DIR)/m_flyer.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_gekk.o : $(XATRIX_DIR)/m_gekk.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_gladb.o : $(XATRIX_DIR)/m_gladb.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_gladiator.o : $(XATRIX_DIR)/m_gladiator.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_gunner.o : $(XATRIX_DIR)/m_gunner.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_hover.o : $(XATRIX_DIR)/m_hover.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_infantry.o : $(XATRIX_DIR)/m_infantry.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_insane.o : $(XATRIX_DIR)/m_insane.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_medic.o : $(XATRIX_DIR)/m_medic.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_move.o : $(XATRIX_DIR)/m_move.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_mutant.o : $(XATRIX_DIR)/m_mutant.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_parasite.o : $(XATRIX_DIR)/m_parasite.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_soldier.o : $(XATRIX_DIR)/m_soldier.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_supertank.o : $(XATRIX_DIR)/m_supertank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/m_tank.o : $(XATRIX_DIR)/m_tank.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/p_client.o : $(XATRIX_DIR)/p_client.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/p_hud.o : $(XATRIX_DIR)/p_hud.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/p_trail.o : $(XATRIX_DIR)/p_trail.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/p_view.o : $(XATRIX_DIR)/p_view.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/p_weapon.o : $(XATRIX_DIR)/p_weapon.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
$(BUILDDIR)/xatrix/q_shared.o : $(XATRIX_DIR)/q_shared.c
|
||||
$(DO_SHLIB_CC)
|
||||
|
||||
#############################################################################
|
||||
# MISC
|
||||
#############################################################################
|
||||
|
||||
clean: clean-debug clean-release
|
||||
|
||||
clean-debug:
|
||||
$(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
clean-release:
|
||||
$(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)"
|
||||
|
||||
clean2:
|
||||
-rm -f $(QUAKE2_OBJS) $(GAME_OBJS) $(CTF_OBJS) $(XATRIX_OBJS)
|
||||
3
solaris/g_so.c
Normal file
3
solaris/g_so.c
Normal file
@@ -0,0 +1,3 @@
|
||||
int main(int argc, char *argv)
|
||||
{
|
||||
}
|
||||
164
solaris/glob.c
Normal file
164
solaris/glob.c
Normal file
@@ -0,0 +1,164 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../linux/glob.h"
|
||||
|
||||
/* Like glob_match, but match PATTERN against any final segment of TEXT. */
|
||||
static int glob_match_after_star(char *pattern, char *text)
|
||||
{
|
||||
register char *p = pattern, *t = text;
|
||||
register char c, c1;
|
||||
|
||||
while ((c = *p++) == '?' || c == '*')
|
||||
if (c == '?' && *t++ == '\0')
|
||||
return 0;
|
||||
|
||||
if (c == '\0')
|
||||
return 1;
|
||||
|
||||
if (c == '\\')
|
||||
c1 = *p;
|
||||
else
|
||||
c1 = c;
|
||||
|
||||
while (1) {
|
||||
if ((c == '[' || *t == c1) && glob_match(p - 1, t))
|
||||
return 1;
|
||||
if (*t++ == '\0')
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if PATTERN has any special globbing chars in it. */
|
||||
static int glob_pattern_p(char *pattern)
|
||||
{
|
||||
register char *p = pattern;
|
||||
register char c;
|
||||
int open = 0;
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
switch (c) {
|
||||
case '?':
|
||||
case '*':
|
||||
return 1;
|
||||
|
||||
case '[': /* Only accept an open brace if there is a close */
|
||||
open++; /* brace to match it. Bracket expressions must be */
|
||||
continue; /* complete, according to Posix.2 */
|
||||
case ']':
|
||||
if (open)
|
||||
return 1;
|
||||
continue;
|
||||
|
||||
case '\\':
|
||||
if (*p++ == '\0')
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match the pattern PATTERN against the string TEXT;
|
||||
return 1 if it matches, 0 otherwise.
|
||||
|
||||
A match means the entire string TEXT is used up in matching.
|
||||
|
||||
In the pattern string, `*' matches any sequence of characters,
|
||||
`?' matches any character, [SET] matches any character in the specified set,
|
||||
[!SET] matches any character not in the specified set.
|
||||
|
||||
A set is composed of characters or ranges; a range looks like
|
||||
character hyphen character (as in 0-9 or A-Z).
|
||||
[0-9a-zA-Z_] is the set of characters allowed in C identifiers.
|
||||
Any other character in the pattern must be matched exactly.
|
||||
|
||||
To suppress the special syntactic significance of any of `[]*?!-\',
|
||||
and match the character exactly, precede it with a `\'.
|
||||
*/
|
||||
|
||||
int glob_match(char *pattern, char *text)
|
||||
{
|
||||
register char *p = pattern, *t = text;
|
||||
register char c;
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
switch (c) {
|
||||
case '?':
|
||||
if (*t == '\0')
|
||||
return 0;
|
||||
else
|
||||
++t;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (*p++ != *t++)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
return glob_match_after_star(p, t);
|
||||
|
||||
case '[':
|
||||
{
|
||||
register char c1 = *t++;
|
||||
int invert;
|
||||
|
||||
if (!c1)
|
||||
return (0);
|
||||
|
||||
invert = ((*p == '!') || (*p == '^'));
|
||||
if (invert)
|
||||
p++;
|
||||
|
||||
c = *p++;
|
||||
while (1) {
|
||||
register char cstart = c, cend = c;
|
||||
|
||||
if (c == '\\') {
|
||||
cstart = *p++;
|
||||
cend = cstart;
|
||||
}
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
|
||||
c = *p++;
|
||||
if (c == '-' && *p != ']') {
|
||||
cend = *p++;
|
||||
if (cend == '\\')
|
||||
cend = *p++;
|
||||
if (cend == '\0')
|
||||
return 0;
|
||||
c = *p++;
|
||||
}
|
||||
if (c1 >= cstart && c1 <= cend)
|
||||
goto match;
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
if (!invert)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
match:
|
||||
/* Skip the rest of the [...] construct that already matched. */
|
||||
while (c != ']') {
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
else if (c == '\\')
|
||||
++p;
|
||||
}
|
||||
if (invert)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (c != *t++)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return *t == '\0';
|
||||
}
|
||||
|
||||
1
solaris/glob.h
Normal file
1
solaris/glob.h
Normal file
@@ -0,0 +1 @@
|
||||
int glob_match(char *pattern, char *text);
|
||||
537
solaris/net_udp.c
Normal file
537
solaris/net_udp.c
Normal file
@@ -0,0 +1,537 @@
|
||||
// net_wins.c
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/filio.h>
|
||||
|
||||
#ifdef NeXT
|
||||
#include <libc.h>
|
||||
#endif
|
||||
|
||||
netadr_t net_local_adr;
|
||||
|
||||
#define LOOPBACK 0x7f000001
|
||||
|
||||
#define MAX_LOOPBACK 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte data[MAX_MSGLEN];
|
||||
int datalen;
|
||||
} loopmsg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
loopmsg_t msgs[MAX_LOOPBACK];
|
||||
int get, send;
|
||||
} loopback_t;
|
||||
|
||||
loopback_t loopbacks[2];
|
||||
int ip_sockets[2];
|
||||
int ipx_sockets[2];
|
||||
|
||||
int NET_Socket (char *net_interface, int port);
|
||||
char *NET_ErrorString (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
|
||||
{
|
||||
memset (s, 0, sizeof(*s));
|
||||
|
||||
if (a->type == NA_BROADCAST)
|
||||
{
|
||||
s->sin_family = AF_INET;
|
||||
|
||||
s->sin_port = a->port;
|
||||
*(int *)&s->sin_addr = -1;
|
||||
}
|
||||
else if (a->type == NA_IP)
|
||||
{
|
||||
s->sin_family = AF_INET;
|
||||
|
||||
*(int *)&s->sin_addr = *(int *)&a->ip;
|
||||
s->sin_port = a->port;
|
||||
}
|
||||
}
|
||||
|
||||
void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
|
||||
{
|
||||
*(int *)&a->ip = *(int *)&s->sin_addr;
|
||||
a->port = s->sin_port;
|
||||
a->type = NA_IP;
|
||||
}
|
||||
|
||||
|
||||
qboolean NET_CompareAdr (netadr_t a, netadr_t b)
|
||||
{
|
||||
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
NET_CompareBaseAdr
|
||||
|
||||
Compares without the port
|
||||
===================
|
||||
*/
|
||||
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
|
||||
{
|
||||
if (a.type != b.type)
|
||||
return false;
|
||||
|
||||
if (a.type == NA_LOOPBACK)
|
||||
return true;
|
||||
|
||||
if (a.type == NA_IP)
|
||||
{
|
||||
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type == NA_IPX)
|
||||
{
|
||||
if ((memcmp(a.ipx, b.ipx, 10) == 0))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char *NET_AdrToString (netadr_t a)
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
char *NET_BaseAdrToString (netadr_t a)
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
localhost
|
||||
idnewt
|
||||
idnewt:28000
|
||||
192.246.40.70
|
||||
192.246.40.70:28000
|
||||
=============
|
||||
*/
|
||||
qboolean NET_StringToSockaddr (char *s, struct sockaddr *sadr)
|
||||
{
|
||||
struct hostent *h;
|
||||
char *colon;
|
||||
char copy[128];
|
||||
|
||||
memset (sadr, 0, sizeof(*sadr));
|
||||
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)sadr)->sin_port = 0;
|
||||
|
||||
strcpy (copy, s);
|
||||
// strip off a trailing :port if present
|
||||
for (colon = copy ; *colon ; colon++)
|
||||
if (*colon == ':')
|
||||
{
|
||||
*colon = 0;
|
||||
((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));
|
||||
}
|
||||
|
||||
if (copy[0] >= '0' && copy[0] <= '9')
|
||||
{
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! (h = gethostbyname(copy)) )
|
||||
return 0;
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
localhost
|
||||
idnewt
|
||||
idnewt:28000
|
||||
192.246.40.70
|
||||
192.246.40.70:28000
|
||||
=============
|
||||
*/
|
||||
qboolean NET_StringToAdr (char *s, netadr_t *a)
|
||||
{
|
||||
struct sockaddr_in sadr;
|
||||
|
||||
if (!strcmp (s, "localhost"))
|
||||
{
|
||||
memset (a, 0, sizeof(*a));
|
||||
a->type = NA_LOOPBACK;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!NET_StringToSockaddr (s, (struct sockaddr *)&sadr))
|
||||
return false;
|
||||
|
||||
SockadrToNetadr (&sadr, a);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
qboolean NET_IsLocalAddress (netadr_t adr)
|
||||
{
|
||||
return NET_CompareAdr (adr, net_local_adr);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
LOOPBACK BUFFERS FOR LOCAL PLAYER
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock];
|
||||
|
||||
if (loop->send - loop->get > MAX_LOOPBACK)
|
||||
loop->get = loop->send - MAX_LOOPBACK;
|
||||
|
||||
if (loop->get >= loop->send)
|
||||
return false;
|
||||
|
||||
i = loop->get & (MAX_LOOPBACK-1);
|
||||
loop->get++;
|
||||
|
||||
memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
|
||||
net_message->cursize = loop->msgs[i].datalen;
|
||||
*net_from = net_local_adr;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock^1];
|
||||
|
||||
i = loop->send & (MAX_LOOPBACK-1);
|
||||
loop->send++;
|
||||
|
||||
memcpy (loop->msgs[i].data, data, length);
|
||||
loop->msgs[i].datalen = length;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_in from;
|
||||
int fromlen;
|
||||
int net_socket;
|
||||
int protocol;
|
||||
int err;
|
||||
|
||||
if (NET_GetLoopPacket (sock, net_from, net_message))
|
||||
return true;
|
||||
|
||||
for (protocol = 0 ; protocol < 2 ; protocol++)
|
||||
{
|
||||
if (protocol == 0)
|
||||
net_socket = ip_sockets[sock];
|
||||
else
|
||||
net_socket = ipx_sockets[sock];
|
||||
|
||||
if (!net_socket)
|
||||
continue;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
ret = recvfrom (net_socket, net_message->data, net_message->maxsize
|
||||
, 0, (struct sockaddr *)&from, &fromlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
err = errno;
|
||||
|
||||
if (err == EWOULDBLOCK || err == ECONNREFUSED)
|
||||
continue;
|
||||
Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret == net_message->maxsize)
|
||||
{
|
||||
Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
|
||||
continue;
|
||||
}
|
||||
|
||||
net_message->cursize = ret;
|
||||
SockadrToNetadr (&from, net_from);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_in addr;
|
||||
int net_socket;
|
||||
|
||||
if ( to.type == NA_LOOPBACK )
|
||||
{
|
||||
NET_SendLoopPacket (sock, length, data, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (to.type == NA_BROADCAST)
|
||||
{
|
||||
net_socket = ip_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else if (to.type == NA_IP)
|
||||
{
|
||||
net_socket = ip_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else if (to.type == NA_IPX)
|
||||
{
|
||||
net_socket = ipx_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else if (to.type == NA_BROADCAST_IPX)
|
||||
{
|
||||
net_socket = ipx_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else
|
||||
Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
|
||||
|
||||
NetadrToSockadr (&to, &addr);
|
||||
|
||||
ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
|
||||
if (ret == -1)
|
||||
{
|
||||
Com_Printf ("NET_SendPacket ERROR: %i\n", NET_ErrorString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIP
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIP (void)
|
||||
{
|
||||
cvar_t *port, *ip;
|
||||
|
||||
port = Cvar_Get ("port", va("%i", PORT_SERVER), CVAR_NOSET);
|
||||
ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
|
||||
|
||||
if (!ip_sockets[NS_SERVER])
|
||||
ip_sockets[NS_SERVER] = NET_Socket (ip->string, port->value);
|
||||
if (!ip_sockets[NS_CLIENT])
|
||||
ip_sockets[NS_CLIENT] = NET_Socket (ip->string, PORT_ANY);
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIPX
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIPX (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Config
|
||||
|
||||
A single player game will only use the loopback code
|
||||
====================
|
||||
*/
|
||||
void NET_Config (qboolean multiplayer)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!multiplayer)
|
||||
{ // shut down any existing sockets
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (ip_sockets[i])
|
||||
{
|
||||
close (ip_sockets[i]);
|
||||
ip_sockets[i] = 0;
|
||||
}
|
||||
if (ipx_sockets[i])
|
||||
{
|
||||
close (ipx_sockets[i]);
|
||||
ipx_sockets[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // open sockets
|
||||
NET_OpenIP ();
|
||||
NET_OpenIPX ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Init
|
||||
====================
|
||||
*/
|
||||
void NET_Init (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Socket
|
||||
====================
|
||||
*/
|
||||
int NET_Socket (char *net_interface, int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_in address;
|
||||
qboolean _true = true;
|
||||
int i = 1;
|
||||
|
||||
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
Com_Printf ("ERROR: UDP_OpenSocket: socket:", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it non-blocking
|
||||
if (ioctl (newsocket, FIONBIO, &_true) == -1)
|
||||
{
|
||||
Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it broadcast capable
|
||||
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
|
||||
{
|
||||
Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
else
|
||||
NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
|
||||
|
||||
if (port == PORT_ANY)
|
||||
address.sin_port = 0;
|
||||
else
|
||||
address.sin_port = htons((short)port);
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
{
|
||||
Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
|
||||
close (newsocket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Shutdown
|
||||
====================
|
||||
*/
|
||||
void NET_Shutdown (void)
|
||||
{
|
||||
NET_Config (false); // close sockets
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_ErrorString
|
||||
====================
|
||||
*/
|
||||
char *NET_ErrorString (void)
|
||||
{
|
||||
int code;
|
||||
|
||||
code = errno;
|
||||
return strerror (code);
|
||||
}
|
||||
|
||||
// sleeps msec or until net socket is ready
|
||||
void NET_Sleep(int msec)
|
||||
{
|
||||
struct timeval timeout;
|
||||
fd_set fdset;
|
||||
extern cvar_t *dedicated;
|
||||
extern qboolean stdin_active;
|
||||
|
||||
if (!ip_sockets[NS_SERVER] || (dedicated && !dedicated->value))
|
||||
return; // we're not a server, just run full speed
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
if (stdin_active)
|
||||
FD_SET(0, &fdset); // stdin is processed too
|
||||
FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
|
||||
timeout.tv_sec = msec/1000;
|
||||
timeout.tv_usec = (msec%1000)*1000;
|
||||
select(ip_sockets[NS_SERVER]+1, &fdset, NULL, NULL, &timeout);
|
||||
}
|
||||
|
||||
196
solaris/q_shsolaris.c
Normal file
196
solaris/q_shsolaris.c
Normal file
@@ -0,0 +1,196 @@
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "../linux/glob.h"
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
//===============================================================================
|
||||
|
||||
byte *membase;
|
||||
int maxhunksize;
|
||||
int curhunksize;
|
||||
|
||||
void *Hunk_Begin (int maxsize)
|
||||
{
|
||||
// reserve a huge chunk of memory, but don't commit any yet
|
||||
maxhunksize = maxsize;
|
||||
curhunksize = 0;
|
||||
membase = malloc(maxhunksize);
|
||||
if (membase == NULL)
|
||||
Sys_Error(ERR_FATAL, "unable to allocate %d bytes", maxsize);
|
||||
|
||||
return membase;
|
||||
}
|
||||
|
||||
void *Hunk_Alloc (int size)
|
||||
{
|
||||
byte *buf;
|
||||
|
||||
// round to cacheline
|
||||
size = (size+31)&~31;
|
||||
if (curhunksize + size > maxhunksize)
|
||||
Sys_Error(ERR_FATAL, "Hunk_Alloc overflow");
|
||||
buf = membase + curhunksize;
|
||||
curhunksize += size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int Hunk_End (void)
|
||||
{
|
||||
byte *n;
|
||||
|
||||
n = realloc(membase, curhunksize);
|
||||
if (n != membase)
|
||||
Sys_Error(ERR_FATAL, "Hunk_End: Could not remap virtual block (%d)", errno);
|
||||
|
||||
return curhunksize;
|
||||
}
|
||||
|
||||
void Hunk_Free (void *base)
|
||||
{
|
||||
if (base)
|
||||
free(base);
|
||||
}
|
||||
|
||||
//===============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Milliseconds
|
||||
================
|
||||
*/
|
||||
int curtime;
|
||||
int Sys_Milliseconds (void)
|
||||
{
|
||||
struct timeval tp;
|
||||
struct timezone tzp;
|
||||
static int secbase;
|
||||
|
||||
gettimeofday(&tp, &tzp);
|
||||
|
||||
if (!secbase)
|
||||
{
|
||||
secbase = tp.tv_sec;
|
||||
return tp.tv_usec/1000;
|
||||
}
|
||||
|
||||
curtime = (tp.tv_sec - secbase)*1000 + tp.tv_usec/1000;
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
void Sys_Mkdir (char *path)
|
||||
{
|
||||
mkdir (path, 0777);
|
||||
}
|
||||
|
||||
char *strlwr (char *s)
|
||||
{
|
||||
while (*s) {
|
||||
*s = tolower(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================
|
||||
|
||||
static char findbase[MAX_OSPATH];
|
||||
static char findpath[MAX_OSPATH];
|
||||
static char findpattern[MAX_OSPATH];
|
||||
static DIR *fdir;
|
||||
|
||||
static qboolean CompareAttributes(char *path, char *name,
|
||||
unsigned musthave, unsigned canthave )
|
||||
{
|
||||
struct stat st;
|
||||
char fn[MAX_OSPATH];
|
||||
|
||||
// . and .. never match
|
||||
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
|
||||
return false;
|
||||
|
||||
sprintf(fn, "%s/%s", path, name);
|
||||
if (stat(fn, &st) == -1)
|
||||
return false; // shouldn't happen
|
||||
|
||||
if ( ( st.st_mode & S_IFDIR ) && ( canthave & SFF_SUBDIR ) )
|
||||
return false;
|
||||
|
||||
if ( ( musthave & SFF_SUBDIR ) && !( st.st_mode & S_IFDIR ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *Sys_FindFirst (char *path, unsigned musthave, unsigned canhave)
|
||||
{
|
||||
struct dirent *d;
|
||||
char *p;
|
||||
|
||||
if (fdir)
|
||||
Sys_Error ("Sys_BeginFind without close");
|
||||
|
||||
// COM_FilePath (path, findbase);
|
||||
strcpy(findbase, path);
|
||||
|
||||
if ((p = strrchr(findbase, '/')) != NULL) {
|
||||
*p = 0;
|
||||
strcpy(findpattern, p + 1);
|
||||
} else
|
||||
strcpy(findpattern, "*");
|
||||
|
||||
if (strcmp(findpattern, "*.*") == 0)
|
||||
strcpy(findpattern, "*");
|
||||
|
||||
if ((fdir = opendir(path)) == NULL)
|
||||
return NULL;
|
||||
while ((d = readdir(fdir)) != NULL) {
|
||||
if (!*findpattern || glob_match(findpattern, d->d_name)) {
|
||||
// if (*findpattern)
|
||||
// printf("%s matched %s\n", findpattern, d->d_name);
|
||||
if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
|
||||
sprintf (findpath, "%s/%s", findbase, d->d_name);
|
||||
return findpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *Sys_FindNext (unsigned musthave, unsigned canhave)
|
||||
{
|
||||
struct dirent *d;
|
||||
|
||||
if (fdir == NULL)
|
||||
return NULL;
|
||||
while ((d = readdir(fdir)) != NULL) {
|
||||
if (!*findpattern || glob_match(findpattern, d->d_name)) {
|
||||
// if (*findpattern)
|
||||
// printf("%s matched %s\n", findpattern, d->d_name);
|
||||
if (CompareAttributes(findbase, d->d_name, musthave, canhave)) {
|
||||
sprintf (findpath, "%s/%s", findbase, d->d_name);
|
||||
return findpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Sys_FindClose (void)
|
||||
{
|
||||
if (fdir != NULL)
|
||||
closedir(fdir);
|
||||
fdir = NULL;
|
||||
}
|
||||
|
||||
|
||||
//============================================
|
||||
|
||||
337
solaris/sys_solaris.c
Normal file
337
solaris/sys_solaris.c
Normal file
@@ -0,0 +1,337 @@
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
cvar_t *nostdout;
|
||||
|
||||
unsigned sys_frame_time;
|
||||
|
||||
qboolean stdin_active = true;
|
||||
|
||||
// =======================================================================
|
||||
// General routines
|
||||
// =======================================================================
|
||||
|
||||
void Sys_ConsoleOutput (char *string)
|
||||
{
|
||||
if (nostdout && nostdout->value)
|
||||
return;
|
||||
|
||||
fputs(string, stdout);
|
||||
}
|
||||
|
||||
void Sys_Printf (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
unsigned char *p;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (text,fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
if (strlen(text) > sizeof(text))
|
||||
Sys_Error("memory overwrite in Sys_Printf");
|
||||
|
||||
if (nostdout && nostdout->value)
|
||||
return;
|
||||
|
||||
for (p = (unsigned char *)text; *p; p++) {
|
||||
*p &= 0x7f;
|
||||
if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
|
||||
printf("[%02x]", *p);
|
||||
else
|
||||
putc(*p, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void Sys_Quit (void)
|
||||
{
|
||||
CL_Shutdown ();
|
||||
Qcommon_Shutdown ();
|
||||
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void Sys_Init(void)
|
||||
{
|
||||
#if id386
|
||||
// Sys_SetFPCW();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Sys_Error (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
// change stdin to non blocking
|
||||
fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
|
||||
|
||||
va_start (argptr,error);
|
||||
vsprintf (string,error,argptr);
|
||||
va_end (argptr);
|
||||
fprintf(stderr, "Error: %s\n", string);
|
||||
|
||||
CL_Shutdown ();
|
||||
Qcommon_Shutdown ();
|
||||
_exit (1);
|
||||
|
||||
}
|
||||
|
||||
void Sys_Warn (char *warning, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
va_start (argptr,warning);
|
||||
vsprintf (string,warning,argptr);
|
||||
va_end (argptr);
|
||||
fprintf(stderr, "Warning: %s", string);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Sys_FileTime
|
||||
|
||||
returns -1 if not present
|
||||
============
|
||||
*/
|
||||
int Sys_FileTime (char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (stat (path,&buf) == -1)
|
||||
return -1;
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
void floating_point_exception_handler(int whatever)
|
||||
{
|
||||
// Sys_Warn("floating point exception\n");
|
||||
signal(SIGFPE, floating_point_exception_handler);
|
||||
}
|
||||
|
||||
char *Sys_ConsoleInput(void)
|
||||
{
|
||||
static char text[256];
|
||||
int len;
|
||||
fd_set fdset;
|
||||
struct timeval timeout;
|
||||
|
||||
if (!dedicated || !dedicated->value)
|
||||
return NULL;
|
||||
|
||||
if (!stdin_active)
|
||||
return NULL;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(0, &fdset); // stdin
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
|
||||
return NULL;
|
||||
|
||||
len = read (0, text, sizeof(text));
|
||||
if (len == 0) { // eof!
|
||||
stdin_active = false;
|
||||
return NULL;
|
||||
}
|
||||
if (len < 1)
|
||||
return NULL;
|
||||
text[len-1] = 0; // rip off the /n and terminate
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void *game_library;
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_UnloadGame
|
||||
=================
|
||||
*/
|
||||
void Sys_UnloadGame (void)
|
||||
{
|
||||
if (game_library)
|
||||
dlclose (game_library);
|
||||
game_library = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_GetGameAPI
|
||||
|
||||
Loads the game dll
|
||||
=================
|
||||
*/
|
||||
void *Sys_GetGameAPI (void *parms)
|
||||
{
|
||||
void *(*GetGameAPI) (void *);
|
||||
|
||||
char name[MAX_OSPATH];
|
||||
char curpath[MAX_OSPATH];
|
||||
char *path;
|
||||
#ifdef __i386__
|
||||
const char *gamename = "gamei386.so";
|
||||
#elif defined __sun__
|
||||
const char *gamename = "gamesparc.so";
|
||||
#else
|
||||
#error Unknown arch
|
||||
#endif
|
||||
|
||||
if (game_library)
|
||||
Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
|
||||
|
||||
getcwd(curpath, sizeof(curpath));
|
||||
|
||||
Com_Printf("------- Loading %s -------", gamename);
|
||||
|
||||
// now run through the search paths
|
||||
path = NULL;
|
||||
while (1)
|
||||
{
|
||||
path = FS_NextPath (path);
|
||||
if (!path)
|
||||
return NULL; // couldn't find one anywhere
|
||||
sprintf (name, "%s/%s/%s", curpath, path, gamename);
|
||||
game_library = dlopen (name, RTLD_NOW );
|
||||
if (game_library)
|
||||
{
|
||||
Com_DPrintf ("LoadLibrary (%s)\n",name);
|
||||
break;
|
||||
} else
|
||||
Com_Printf("error: %s\n", dlerror());
|
||||
}
|
||||
|
||||
GetGameAPI = (void *)dlsym (game_library, "GetGameAPI");
|
||||
if (!GetGameAPI)
|
||||
{
|
||||
Sys_UnloadGame ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return GetGameAPI (parms);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void Sys_AppActivate (void)
|
||||
{
|
||||
}
|
||||
|
||||
void Sys_SendKeyEvents (void)
|
||||
{
|
||||
// grab frame time
|
||||
sys_frame_time = Sys_Milliseconds();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
char *Sys_GetClipboardData(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int time, oldtime, newtime;
|
||||
|
||||
#if 0
|
||||
int newargc;
|
||||
char **newargv;
|
||||
int i;
|
||||
|
||||
// force dedicated
|
||||
newargc = argc;
|
||||
newargv = malloc((argc + 3) * sizeof(char *));
|
||||
newargv[0] = argv[0];
|
||||
newargv[1] = "+set";
|
||||
newargv[2] = "dedicated";
|
||||
newargv[3] = "1";
|
||||
for (i = 1; i < argc; i++)
|
||||
newargv[i + 3] = argv[i];
|
||||
newargc += 3;
|
||||
|
||||
Qcommon_Init(newargc, newargv);
|
||||
#else
|
||||
Qcommon_Init(argc, argv);
|
||||
#endif
|
||||
|
||||
fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
|
||||
|
||||
nostdout = Cvar_Get("nostdout", "0", 0);
|
||||
|
||||
if (!nostdout->value) {
|
||||
fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
|
||||
// printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
|
||||
}
|
||||
|
||||
oldtime = Sys_Milliseconds ();
|
||||
while (1)
|
||||
{
|
||||
// find time spent rendering last frame
|
||||
do {
|
||||
newtime = Sys_Milliseconds ();
|
||||
time = newtime - oldtime;
|
||||
} while (time < 1);
|
||||
Qcommon_Frame (time);
|
||||
oldtime = newtime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Sys_CopyProtect(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
|
||||
int r;
|
||||
unsigned long addr;
|
||||
int psize = getpagesize();
|
||||
|
||||
addr = (startaddr & ~(psize-1)) - psize;
|
||||
|
||||
// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
|
||||
// addr, startaddr+length, length);
|
||||
|
||||
r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
|
||||
|
||||
if (r < 0)
|
||||
Sys_Error("Protection change failed\n");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
308
unix/makefile
Normal file
308
unix/makefile
Normal file
@@ -0,0 +1,308 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = quake2
|
||||
EXE = $(ODIR)/quake2
|
||||
all: $(EXE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
SERVERFILES = $(ODIR)/sv_ccmds.o $(ODIR)/sv_ents.o $(ODIR)/sv_game.o $(ODIR)/sv_init.o $(ODIR)/sv_main.o $(ODIR)/sv_send.o $(ODIR)/sv_user.o $(ODIR)/sv_world.o
|
||||
|
||||
CLIENTFILES = $(ODIR)/cl_demo.o $(ODIR)/cl_ents.o $(ODIR)/cl_fx.o $(ODIR)/cl_input.o $(ODIR)/cl_inv.o $(ODIR)/cl_main.o $(ODIR)/cl_parse.o $(ODIR)/cl_tent.o $(ODIR)/console.o $(ODIR)/keys.o $(ODIR)/menu.o $(ODIR)/qmenu.o $(ODIR)/screen.o $(ODIR)/scr_cin.o $(ODIR)/snd_dma.o $(ODIR)/snd_mem.o $(ODIR)/snd_mix.o $(ODIR)/view.o
|
||||
|
||||
# commonfiles are used by both client and server
|
||||
COMMONFILES = $(ODIR)/cmd.o $(ODIR)/cmodel.o $(ODIR)/cvar.o $(ODIR)/files.o $(ODIR)/md4.o $(ODIR)/net_chan.o $(ODIR)/net_udp.o
|
||||
|
||||
REFGLFILES = $(ODIR)/gl_draw.o $(ODIR)/gl_inter.o $(ODIR)/gl_light.o $(ODIR)/gl_math.o $(ODIR)/gl_mesh.o $(ODIR)/gl_model.o $(ODIR)/gl_rmain.o $(ODIR)/gl_rmisc.o $(ODIR)/gl_rsurf.o $(ODIR)/gl_textr.o $(ODIR)/gl_warp.
|
||||
|
||||
REFSOFTFILES = $(ODIR)/r_aclip.o $(ODIR)/r_alias.o $(ODIR)/r_bsp.o $(ODIR)/r_draw.o $(ODIR)/r_edge.o $(ODIR)/r_image.o $(ODIR)/r_light.o $(ODIR)/r_main.o $(ODIR)/r_misc.o $(ODIR)/r_model.o $(ODIR)/r_part.o $(ODIR)/r_polyse.o $(ODIR)/r_poly.o $(ODIR)/r_rast.o $(ODIR)/r_scan.o $(ODIR)/r_sprite.o $(ODIR)/r_surf.o
|
||||
|
||||
# sharedfiles are included in EVERY dll
|
||||
SHAREDFILES = $(ODIR)/q_shared
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -Wall -g -O" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -O2 -Xcpluscomm -woff 513 -woff 594 -woff 596" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -Xcpluscomm" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
clean:
|
||||
rm -f next/*.o next/$(EXEBASE)
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
FILES = $(SERVERFILES) $(COMMONFILES) $(CLIENTFILES) $(REFSOFTFILES) $(SHAREDFILES)
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/q_shared.o : ../qcommon/q_shared.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/sv_ccmds.o : ../server/sv_ccmds.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_ents.o : ../server/sv_ents.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_game.o : ../server/sv_game.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_init.o : ../server/sv_init.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_main.o : ../server/sv_main.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_send.o : ../server/sv_send.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_user.o : ../server/sv_user.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
$(ODIR)/sv_world.o : ../server/sv_world.c
|
||||
cc $(CFLAGS) -o $@ $?
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/cl_demo.o : ../client/cl_demo.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_ents.o : ../client/cl_ents.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_fx.o : ../client/cl_fx.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_input.o : ../client/cl_input.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_inv.o : ../client/cl_inv.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_main.o : ../client/cl_main.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_parse.o : ../client/cl_parse.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_tent.o : ../client/cl_tent.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/console.o : ../client/console.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/keys.o : ../client/keys.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/menu.o : ../client/menu.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/qmenu.o : ../client/qmenu.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sbar2.o : ../client/sbar2.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/screen.o : ../client/screen.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/scr_cin.o : ../client/scr_cin.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/snd_dma.o : ../client/snd_dma.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/snd_mem.o : ../client/snd_mem.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/snd_mix.o : ../client/snd_mix.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/view.o : ../client/view.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/cmd.o : ../qcommon/cmd.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmodel.o : ../qcommon/cmodel.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cvar.o : ../qcommon/cvar.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/files.o : ../qcommon/files.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/md4.o : ../qcommon/md4.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/net_chan.o : ../qcommon/net_chan.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/net_udp.o : ../qcommon/net_udp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sys_null.o : ../qcommon/sys_null.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/gl_draw.o : ../ref_gl/gl_draw.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_inter.o : ../ref_gl/gl_inter.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_light.o : ../ref_gl/gl_light.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_math.o : ../ref_gl/gl_math.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_mesh.o : ../ref_gl/gl_mesh.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_model.o : ../ref_gl/gl_model.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_rmain.o : ../ref_gl/gl_rmain.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_rmisc.o : ../ref_gl/gl_rmisc.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_rsurf.o : ../ref_gl/gl_rsurf.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_textr.o : ../ref_gl/gl_textr.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_warp.o : ../ref_gl/gl_warp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/r_aclip.o : ../ref_soft/r_aclip.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_alias.o : ../ref_soft/r_alias.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_bsp.o : ../ref_soft/r_bsp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_draw.o : ../ref_soft/r_draw.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_edge.o : ../ref_soft/r_edge.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_image.o : ../ref_soft/r_image.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_light.o : ../ref_soft/r_light.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_main.o : ../ref_soft/r_main.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_misc.o : ../ref_soft/r_misc.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_model.o : ../ref_soft/r_model.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_part.o : ../ref_soft/r_part.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_polyse.o : ../ref_soft/r_polyse.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_poly.o : ../ref_soft/r_poly.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_rast.o : ../ref_soft/r_rast.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_scan.o : ../ref_soft/r_scan.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_sprite.o : ../ref_soft/r_sprite.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_surf.o : ../ref_soft/r_surf.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
317
unix/makefile_old
Normal file
317
unix/makefile_old
Normal file
@@ -0,0 +1,317 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = quake2
|
||||
EXE = $(ODIR)/quake2
|
||||
all: $(EXE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
SERVERFILES = $(ODIR)/sv_ccmds.o $(ODIR)/sv_ents.o $(ODIR)/sv_game.o $(ODIR)/sv_init.o $(ODIR)/sv_main.o $(ODIR)/sv_send.o $(ODIR)/sv_user.o $(ODIR)/sv_world.o
|
||||
|
||||
CLIENTFILES = $(ODIR)/cl_demo.o $(ODIR)/cl_ents.o $(ODIR)/cl_fx.o $(ODIR)/cl_input.o $(ODIR)/cl_inv.o $(ODIR)/cl_main.o $(ODIR)/cl_parse.o $(ODIR)/cl_tent.o $(ODIR)/console.o $(ODIR)/keys.o $(ODIR)/menu.o $(ODIR)/qmenu.o $(ODIR)/screen.o $(ODIR)/scr_cin.o $(ODIR)/snd_dma.o $(ODIR)/snd_mem.o $(ODIR)/snd_mix.o $(ODIR)/view.o
|
||||
|
||||
# commonfiles are used by both client and server
|
||||
COMMONFILES = $(ODIR)/cmd.o $(ODIR)/cmodel.o $(ODIR)/cvar.o $(ODIR)/files.o $(ODIR)/md4.o $(ODIR)/net_chan.o $(ODIR)/net_udp.o
|
||||
|
||||
REFGLFILES = $(ODIR)/gl_draw.o $(ODIR)/gl_inter.o $(ODIR)/gl_light.o $(ODIR)/gl_math.o $(ODIR)/gl_mesh.o $(ODIR)/gl_model.o $(ODIR)/gl_rmain.o $(ODIR)/gl_rmisc.o $(ODIR)/gl_rsurf.o $(ODIR)/gl_textr.o $(ODIR)/gl_warp.
|
||||
|
||||
REFSOFTFILES = $(ODIR)/r_aclip.o $(ODIR)/r_alias.o $(ODIR)/r_bsp.o $(ODIR)/r_draw.o $(ODIR)/r_edge.o $(ODIR)/r_image.o $(ODIR)/r_light.o $(ODIR)/r_main.o $(ODIR)/r_misc.o $(ODIR)/r_model.o $(ODIR)/r_part.o $(ODIR)/r_polyse.o $(ODIR)/r_poly.o $(ODIR)/r_rast.o $(ODIR)/r_scan.o $(ODIR)/r_sprite.o $(ODIR)/r_surf.o
|
||||
|
||||
# sharedfiles are included in EVERY dll
|
||||
SHAREDFILES = $(ODIR)/q_shared
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -Wall -g -O" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -woff 513 -Ofast=ip32_10k -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -Xcpluscomm" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
clean:
|
||||
rm -f next/*.o next/$(EXEBASE)
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
FILES = $(SERVERFILES) $(COMMONFILES) $(CLIENTFILES) $(REFSOFTFILES) $(SHAREDFILES)
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/q_shared.o : ../qcommon/q_shared.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/sv_ccmds.o : ../server/sv_ccmds.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_ents.o : ../server/sv_ents.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_game.o : ../server/sv_game.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_init.o : ../server/sv_init.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_main.o : ../server/sv_main.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_send.o : ../server/sv_send.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_user.o : ../server/sv_user.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sv_world.o : ../server/sv_world.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/cl_demo.o : ../client/cl_demo.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_ents.o : ../client/cl_ents.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_fx.o : ../client/cl_fx.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_input.o : ../client/cl_input.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_inv.o : ../client/cl_inv.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_main.o : ../client/cl_main.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_parse.o : ../client/cl_parse.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cl_tent.o : ../client/cl_tent.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/console.o : ../client/console.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/keys.o : ../client/keys.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/menu.o : ../client/menu.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/qmenu.o : ../client/qmenu.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sbar2.o : ../client/sbar2.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/screen.o : ../client/screen.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/scr_cin.o : ../client/scr_cin.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/snd_dma.o : ../client/snd_dma.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/snd_mem.o : ../client/snd_mem.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/snd_mix.o : ../client/snd_mix.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/view.o : ../client/view.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/cmd.o : ../qcommon/cmd.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cmodel.o : ../qcommon/cmodel.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/cvar.o : ../qcommon/cvar.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/files.o : ../qcommon/files.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/md4.o : ../qcommon/md4.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/net_chan.o : ../qcommon/net_chan.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/net_udp.o : ../qcommon/net_udp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/sys_null.o : ../qcommon/sys_null.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/gl_draw.o : ../ref_gl/gl_draw.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_inter.o : ../ref_gl/gl_inter.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_light.o : ../ref_gl/gl_light.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_math.o : ../ref_gl/gl_math.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_mesh.o : ../ref_gl/gl_mesh.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_model.o : ../ref_gl/gl_model.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_rmain.o : ../ref_gl/gl_rmain.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_rmisc.o : ../ref_gl/gl_rmisc.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_rsurf.o : ../ref_gl/gl_rsurf.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_textr.o : ../ref_gl/gl_textr.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/gl_warp.o : ../ref_gl/gl_warp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
$(ODIR)/r_aclip.o : ../ref_soft/r_aclip.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_alias.o : ../ref_soft/r_alias.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_bsp.o : ../ref_soft/r_bsp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_draw.o : ../ref_soft/r_draw.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_edge.o : ../ref_soft/r_edge.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_image.o : ../ref_soft/r_image.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_light.o : ../ref_soft/r_light.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_main.o : ../ref_soft/r_main.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_misc.o : ../ref_soft/r_misc.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_model.o : ../ref_soft/r_model.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_part.o : ../ref_soft/r_part.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_polyse.o : ../ref_soft/r_polyse.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_poly.o : ../ref_soft/r_poly.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_rast.o : ../ref_soft/r_rast.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_scan.o : ../ref_soft/r_scan.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_sprite.o : ../ref_soft/r_sprite.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
$(ODIR)/r_surf.o : ../ref_soft/r_surf.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
BIN
unix/next/sv_ccmds.o
Normal file
BIN
unix/next/sv_ccmds.o
Normal file
Binary file not shown.
510
win32/cd_win.c
Normal file
510
win32/cd_win.c
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
|
||||
// rights reserved.
|
||||
|
||||
#include <windows.h>
|
||||
#include "../client/client.h"
|
||||
|
||||
extern HWND cl_hwnd;
|
||||
|
||||
static qboolean cdValid = false;
|
||||
static qboolean playing = false;
|
||||
static qboolean wasPlaying = false;
|
||||
static qboolean initialized = false;
|
||||
static qboolean enabled = false;
|
||||
static qboolean playLooping = false;
|
||||
static byte remap[100];
|
||||
static byte cdrom;
|
||||
static byte playTrack;
|
||||
static byte maxTrack;
|
||||
|
||||
cvar_t *cd_nocd;
|
||||
cvar_t *cd_loopcount;
|
||||
cvar_t *cd_looptrack;
|
||||
|
||||
UINT wDeviceID;
|
||||
int loopcounter;
|
||||
|
||||
|
||||
void CDAudio_Pause(void);
|
||||
|
||||
static void CDAudio_Eject(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL))
|
||||
Com_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn);
|
||||
}
|
||||
|
||||
|
||||
static void CDAudio_CloseDoor(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL))
|
||||
Com_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn);
|
||||
}
|
||||
|
||||
|
||||
static int CDAudio_GetAudioDiskInfo(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_STATUS_PARMS mciStatusParms;
|
||||
|
||||
|
||||
cdValid = false;
|
||||
|
||||
mciStatusParms.dwItem = MCI_STATUS_READY;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Com_DPrintf("CDAudio: drive ready test - get status failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!mciStatusParms.dwReturn)
|
||||
{
|
||||
Com_DPrintf("CDAudio: drive not ready\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Com_DPrintf("CDAudio: get tracks - status failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (mciStatusParms.dwReturn < 1)
|
||||
{
|
||||
Com_DPrintf("CDAudio: no music tracks\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cdValid = true;
|
||||
maxTrack = mciStatusParms.dwReturn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CDAudio_Play2(int track, qboolean looping)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_PLAY_PARMS mciPlayParms;
|
||||
MCI_STATUS_PARMS mciStatusParms;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!cdValid)
|
||||
{
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
if (!cdValid)
|
||||
return;
|
||||
}
|
||||
|
||||
track = remap[track];
|
||||
|
||||
if (track < 1 || track > maxTrack)
|
||||
{
|
||||
CDAudio_Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// don't try to play a non-audio track
|
||||
mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
|
||||
mciStatusParms.dwTrack = track;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
|
||||
{
|
||||
Com_Printf("CDAudio: track %i is not audio\n", track);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the length of the track to be played
|
||||
mciStatusParms.dwItem = MCI_STATUS_LENGTH;
|
||||
mciStatusParms.dwTrack = track;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (playing)
|
||||
{
|
||||
if (playTrack == track)
|
||||
return;
|
||||
CDAudio_Stop();
|
||||
}
|
||||
|
||||
mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
|
||||
mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
|
||||
mciPlayParms.dwCallback = (DWORD)cl_hwnd;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
|
||||
playLooping = looping;
|
||||
playTrack = track;
|
||||
playing = true;
|
||||
|
||||
if ( Cvar_VariableValue( "cd_nocd" ) )
|
||||
CDAudio_Pause ();
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Play(int track, qboolean looping)
|
||||
{
|
||||
// set a loop counter so that this track will change to the
|
||||
// looptrack later
|
||||
loopcounter = 0;
|
||||
CDAudio_Play2(track, looping);
|
||||
}
|
||||
|
||||
void CDAudio_Stop(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!playing)
|
||||
return;
|
||||
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL))
|
||||
Com_DPrintf("MCI_STOP failed (%i)", dwReturn);
|
||||
|
||||
wasPlaying = false;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Pause(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_GENERIC_PARMS mciGenericParms;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!playing)
|
||||
return;
|
||||
|
||||
mciGenericParms.dwCallback = (DWORD)cl_hwnd;
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms))
|
||||
Com_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
|
||||
|
||||
wasPlaying = playing;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Resume(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_PLAY_PARMS mciPlayParms;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!cdValid)
|
||||
return;
|
||||
|
||||
if (!wasPlaying)
|
||||
return;
|
||||
|
||||
mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
|
||||
mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
|
||||
mciPlayParms.dwCallback = (DWORD)cl_hwnd;
|
||||
dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
|
||||
if (dwReturn)
|
||||
{
|
||||
Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
|
||||
return;
|
||||
}
|
||||
playing = true;
|
||||
}
|
||||
|
||||
|
||||
static void CD_f (void)
|
||||
{
|
||||
char *command;
|
||||
int ret;
|
||||
int n;
|
||||
|
||||
if (Cmd_Argc() < 2)
|
||||
return;
|
||||
|
||||
command = Cmd_Argv (1);
|
||||
|
||||
if (Q_strcasecmp(command, "on") == 0)
|
||||
{
|
||||
enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "off") == 0)
|
||||
{
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "reset") == 0)
|
||||
{
|
||||
enabled = true;
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
for (n = 0; n < 100; n++)
|
||||
remap[n] = n;
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "remap") == 0)
|
||||
{
|
||||
ret = Cmd_Argc() - 2;
|
||||
if (ret <= 0)
|
||||
{
|
||||
for (n = 1; n < 100; n++)
|
||||
if (remap[n] != n)
|
||||
Com_Printf(" %u -> %u\n", n, remap[n]);
|
||||
return;
|
||||
}
|
||||
for (n = 1; n <= ret; n++)
|
||||
remap[n] = atoi(Cmd_Argv (n+1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "close") == 0)
|
||||
{
|
||||
CDAudio_CloseDoor();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cdValid)
|
||||
{
|
||||
CDAudio_GetAudioDiskInfo();
|
||||
if (!cdValid)
|
||||
{
|
||||
Com_Printf("No CD in player.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "play") == 0)
|
||||
{
|
||||
CDAudio_Play(atoi(Cmd_Argv (2)), false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "loop") == 0)
|
||||
{
|
||||
CDAudio_Play(atoi(Cmd_Argv (2)), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "stop") == 0)
|
||||
{
|
||||
CDAudio_Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "pause") == 0)
|
||||
{
|
||||
CDAudio_Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "resume") == 0)
|
||||
{
|
||||
CDAudio_Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "eject") == 0)
|
||||
{
|
||||
if (playing)
|
||||
CDAudio_Stop();
|
||||
CDAudio_Eject();
|
||||
cdValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Q_strcasecmp(command, "info") == 0)
|
||||
{
|
||||
Com_Printf("%u tracks\n", maxTrack);
|
||||
if (playing)
|
||||
Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
|
||||
else if (wasPlaying)
|
||||
Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (lParam != wDeviceID)
|
||||
return 1;
|
||||
|
||||
switch (wParam)
|
||||
{
|
||||
case MCI_NOTIFY_SUCCESSFUL:
|
||||
if (playing)
|
||||
{
|
||||
playing = false;
|
||||
if (playLooping)
|
||||
{
|
||||
// if the track has played the given number of times,
|
||||
// go to the ambient track
|
||||
if (++loopcounter >= cd_loopcount->value)
|
||||
CDAudio_Play2(cd_looptrack->value, true);
|
||||
else
|
||||
CDAudio_Play2(playTrack, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MCI_NOTIFY_ABORTED:
|
||||
case MCI_NOTIFY_SUPERSEDED:
|
||||
break;
|
||||
|
||||
case MCI_NOTIFY_FAILURE:
|
||||
Com_DPrintf("MCI_NOTIFY_FAILURE\n");
|
||||
CDAudio_Stop ();
|
||||
cdValid = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
Com_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Update(void)
|
||||
{
|
||||
if ( cd_nocd->value != !enabled )
|
||||
{
|
||||
if ( cd_nocd->value )
|
||||
{
|
||||
CDAudio_Stop();
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
enabled = true;
|
||||
CDAudio_Resume ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CDAudio_Init(void)
|
||||
{
|
||||
DWORD dwReturn;
|
||||
MCI_OPEN_PARMS mciOpenParms;
|
||||
MCI_SET_PARMS mciSetParms;
|
||||
int n;
|
||||
|
||||
cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
|
||||
cd_loopcount = Cvar_Get ("cd_loopcount", "4", 0);
|
||||
cd_looptrack = Cvar_Get ("cd_looptrack", "11", 0);
|
||||
if ( cd_nocd->value)
|
||||
return -1;
|
||||
|
||||
mciOpenParms.lpstrDeviceType = "cdaudio";
|
||||
if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms))
|
||||
{
|
||||
Com_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
|
||||
return -1;
|
||||
}
|
||||
wDeviceID = mciOpenParms.wDeviceID;
|
||||
|
||||
// Set the time format to track/minute/second/frame (TMSF).
|
||||
mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
|
||||
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
|
||||
{
|
||||
Com_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
|
||||
mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < 100; n++)
|
||||
remap[n] = n;
|
||||
initialized = true;
|
||||
enabled = true;
|
||||
|
||||
if (CDAudio_GetAudioDiskInfo())
|
||||
{
|
||||
// Com_Printf("CDAudio_Init: No CD in player.\n");
|
||||
cdValid = false;
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
Cmd_AddCommand ("cd", CD_f);
|
||||
|
||||
Com_Printf("CD Audio Initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CDAudio_Shutdown(void)
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
CDAudio_Stop();
|
||||
if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
|
||||
Com_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
CDAudio_Activate
|
||||
|
||||
Called when the main window gains or loses focus.
|
||||
The window have been destroyed and recreated
|
||||
between a deactivate and an activate.
|
||||
===========
|
||||
*/
|
||||
void CDAudio_Activate (qboolean active)
|
||||
{
|
||||
if (active)
|
||||
CDAudio_Resume ();
|
||||
else
|
||||
CDAudio_Pause ();
|
||||
}
|
||||
431
win32/conproc.c
Normal file
431
win32/conproc.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// conproc.c -- support for qhost
|
||||
#include <stdio.h>
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
#include "conproc.h"
|
||||
|
||||
#define CCOM_WRITE_TEXT 0x2
|
||||
// Param1 : Text
|
||||
|
||||
#define CCOM_GET_TEXT 0x3
|
||||
// Param1 : Begin line
|
||||
// Param2 : End line
|
||||
|
||||
#define CCOM_GET_SCR_LINES 0x4
|
||||
// No params
|
||||
|
||||
#define CCOM_SET_SCR_LINES 0x5
|
||||
// Param1 : Number of lines
|
||||
|
||||
|
||||
HANDLE heventDone;
|
||||
HANDLE hfileBuffer;
|
||||
HANDLE heventChildSend;
|
||||
HANDLE heventParentSend;
|
||||
HANDLE hStdout;
|
||||
HANDLE hStdin;
|
||||
|
||||
unsigned _stdcall RequestProc (void *arg);
|
||||
LPVOID GetMappedBuffer (HANDLE hfileBuffer);
|
||||
void ReleaseMappedBuffer (LPVOID pBuffer);
|
||||
BOOL GetScreenBufferLines (int *piLines);
|
||||
BOOL SetScreenBufferLines (int iLines);
|
||||
BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine);
|
||||
BOOL WriteText (LPCTSTR szText);
|
||||
int CharToCode (char c);
|
||||
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy);
|
||||
|
||||
int ccom_argc;
|
||||
char **ccom_argv;
|
||||
|
||||
/*
|
||||
================
|
||||
CCheckParm
|
||||
|
||||
Returns the position (1 to argc-1) in the program's argument list
|
||||
where the given parameter apears, or 0 if not present
|
||||
================
|
||||
*/
|
||||
int CCheckParm (char *parm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=1 ; i<ccom_argc ; i++)
|
||||
{
|
||||
if (!ccom_argv[i])
|
||||
continue;
|
||||
if (!strcmp (parm,ccom_argv[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void InitConProc (int argc, char **argv)
|
||||
{
|
||||
unsigned threadAddr;
|
||||
HANDLE hFile;
|
||||
HANDLE heventParent;
|
||||
HANDLE heventChild;
|
||||
int t;
|
||||
|
||||
ccom_argc = argc;
|
||||
ccom_argv = argv;
|
||||
|
||||
// give QHOST a chance to hook into the console
|
||||
if ((t = CCheckParm ("-HFILE")) > 0)
|
||||
{
|
||||
if (t < argc)
|
||||
hFile = (HANDLE)atoi (ccom_argv[t+1]);
|
||||
}
|
||||
|
||||
if ((t = CCheckParm ("-HPARENT")) > 0)
|
||||
{
|
||||
if (t < argc)
|
||||
heventParent = (HANDLE)atoi (ccom_argv[t+1]);
|
||||
}
|
||||
|
||||
if ((t = CCheckParm ("-HCHILD")) > 0)
|
||||
{
|
||||
if (t < argc)
|
||||
heventChild = (HANDLE)atoi (ccom_argv[t+1]);
|
||||
}
|
||||
|
||||
|
||||
// ignore if we don't have all the events.
|
||||
if (!hFile || !heventParent || !heventChild)
|
||||
{
|
||||
printf ("Qhost not present.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf ("Initializing for qhost.\n");
|
||||
|
||||
hfileBuffer = hFile;
|
||||
heventParentSend = heventParent;
|
||||
heventChildSend = heventChild;
|
||||
|
||||
// so we'll know when to go away.
|
||||
heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if (!heventDone)
|
||||
{
|
||||
printf ("Couldn't create heventDone\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr))
|
||||
{
|
||||
CloseHandle (heventDone);
|
||||
printf ("Couldn't create QHOST thread\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// save off the input/output handles.
|
||||
hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
hStdin = GetStdHandle (STD_INPUT_HANDLE);
|
||||
|
||||
// force 80 character width, at least 25 character height
|
||||
SetConsoleCXCY (hStdout, 80, 25);
|
||||
}
|
||||
|
||||
|
||||
void DeinitConProc (void)
|
||||
{
|
||||
if (heventDone)
|
||||
SetEvent (heventDone);
|
||||
}
|
||||
|
||||
|
||||
unsigned _stdcall RequestProc (void *arg)
|
||||
{
|
||||
int *pBuffer;
|
||||
DWORD dwRet;
|
||||
HANDLE heventWait[2];
|
||||
int iBeginLine, iEndLine;
|
||||
|
||||
heventWait[0] = heventParentSend;
|
||||
heventWait[1] = heventDone;
|
||||
|
||||
while (1)
|
||||
{
|
||||
dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE);
|
||||
|
||||
// heventDone fired, so we're exiting.
|
||||
if (dwRet == WAIT_OBJECT_0 + 1)
|
||||
break;
|
||||
|
||||
pBuffer = (int *) GetMappedBuffer (hfileBuffer);
|
||||
|
||||
// hfileBuffer is invalid. Just leave.
|
||||
if (!pBuffer)
|
||||
{
|
||||
printf ("Invalid hfileBuffer\n");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pBuffer[0])
|
||||
{
|
||||
case CCOM_WRITE_TEXT:
|
||||
// Param1 : Text
|
||||
pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
|
||||
break;
|
||||
|
||||
case CCOM_GET_TEXT:
|
||||
// Param1 : Begin line
|
||||
// Param2 : End line
|
||||
iBeginLine = pBuffer[1];
|
||||
iEndLine = pBuffer[2];
|
||||
pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine,
|
||||
iEndLine);
|
||||
break;
|
||||
|
||||
case CCOM_GET_SCR_LINES:
|
||||
// No params
|
||||
pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
|
||||
break;
|
||||
|
||||
case CCOM_SET_SCR_LINES:
|
||||
// Param1 : Number of lines
|
||||
pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseMappedBuffer (pBuffer);
|
||||
SetEvent (heventChildSend);
|
||||
}
|
||||
|
||||
_endthreadex (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LPVOID GetMappedBuffer (HANDLE hfileBuffer)
|
||||
{
|
||||
LPVOID pBuffer;
|
||||
|
||||
pBuffer = MapViewOfFile (hfileBuffer,
|
||||
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
|
||||
void ReleaseMappedBuffer (LPVOID pBuffer)
|
||||
{
|
||||
UnmapViewOfFile (pBuffer);
|
||||
}
|
||||
|
||||
|
||||
BOOL GetScreenBufferLines (int *piLines)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
BOOL bRet;
|
||||
|
||||
bRet = GetConsoleScreenBufferInfo (hStdout, &info);
|
||||
|
||||
if (bRet)
|
||||
*piLines = info.dwSize.Y;
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
BOOL SetScreenBufferLines (int iLines)
|
||||
{
|
||||
|
||||
return SetConsoleCXCY (hStdout, 80, iLines);
|
||||
}
|
||||
|
||||
|
||||
BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
|
||||
{
|
||||
COORD coord;
|
||||
DWORD dwRead;
|
||||
BOOL bRet;
|
||||
|
||||
coord.X = 0;
|
||||
coord.Y = iBeginLine;
|
||||
|
||||
bRet = ReadConsoleOutputCharacter(
|
||||
hStdout,
|
||||
pszText,
|
||||
80 * (iEndLine - iBeginLine + 1),
|
||||
coord,
|
||||
&dwRead);
|
||||
|
||||
// Make sure it's null terminated.
|
||||
if (bRet)
|
||||
pszText[dwRead] = '\0';
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
||||
BOOL WriteText (LPCTSTR szText)
|
||||
{
|
||||
DWORD dwWritten;
|
||||
INPUT_RECORD rec;
|
||||
char upper, *sz;
|
||||
|
||||
sz = (LPTSTR) szText;
|
||||
|
||||
while (*sz)
|
||||
{
|
||||
// 13 is the code for a carriage return (\n) instead of 10.
|
||||
if (*sz == 10)
|
||||
*sz = 13;
|
||||
|
||||
upper = toupper(*sz);
|
||||
|
||||
rec.EventType = KEY_EVENT;
|
||||
rec.Event.KeyEvent.bKeyDown = TRUE;
|
||||
rec.Event.KeyEvent.wRepeatCount = 1;
|
||||
rec.Event.KeyEvent.wVirtualKeyCode = upper;
|
||||
rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
|
||||
rec.Event.KeyEvent.uChar.AsciiChar = *sz;
|
||||
rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
|
||||
rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0;
|
||||
|
||||
WriteConsoleInput(
|
||||
hStdin,
|
||||
&rec,
|
||||
1,
|
||||
&dwWritten);
|
||||
|
||||
rec.Event.KeyEvent.bKeyDown = FALSE;
|
||||
|
||||
WriteConsoleInput(
|
||||
hStdin,
|
||||
&rec,
|
||||
1,
|
||||
&dwWritten);
|
||||
|
||||
sz++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int CharToCode (char c)
|
||||
{
|
||||
char upper;
|
||||
|
||||
upper = toupper(c);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 13:
|
||||
return 28;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (isalpha(c))
|
||||
return (30 + upper - 65);
|
||||
|
||||
if (isdigit(c))
|
||||
return (1 + upper - 47);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
COORD coordMax;
|
||||
|
||||
coordMax = GetLargestConsoleWindowSize(hStdout);
|
||||
|
||||
if (cy > coordMax.Y)
|
||||
cy = coordMax.Y;
|
||||
|
||||
if (cx > coordMax.X)
|
||||
cx = coordMax.X;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
||||
return FALSE;
|
||||
|
||||
// height
|
||||
info.srWindow.Left = 0;
|
||||
info.srWindow.Right = info.dwSize.X - 1;
|
||||
info.srWindow.Top = 0;
|
||||
info.srWindow.Bottom = cy - 1;
|
||||
|
||||
if (cy < info.dwSize.Y)
|
||||
{
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
|
||||
info.dwSize.Y = cy;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
}
|
||||
else if (cy > info.dwSize.Y)
|
||||
{
|
||||
info.dwSize.Y = cy;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
||||
return FALSE;
|
||||
|
||||
// width
|
||||
info.srWindow.Left = 0;
|
||||
info.srWindow.Right = cx - 1;
|
||||
info.srWindow.Top = 0;
|
||||
info.srWindow.Bottom = info.dwSize.Y - 1;
|
||||
|
||||
if (cx < info.dwSize.X)
|
||||
{
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
|
||||
info.dwSize.X = cx;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
}
|
||||
else if (cx > info.dwSize.X)
|
||||
{
|
||||
info.dwSize.X = cx;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
24
win32/conproc.h
Normal file
24
win32/conproc.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// conproc.h -- support for qhost
|
||||
|
||||
void InitConProc (int argc, char **argv);
|
||||
void DeinitConProc (void);
|
||||
|
||||
616
win32/glw_imp.c
Normal file
616
win32/glw_imp.c
Normal file
@@ -0,0 +1,616 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
/*
|
||||
** GLW_IMP.C
|
||||
**
|
||||
** This file contains ALL Win32 specific stuff having to do with the
|
||||
** OpenGL refresh. When a port is being made the following functions
|
||||
** must be implemented by the port:
|
||||
**
|
||||
** GLimp_EndFrame
|
||||
** GLimp_Init
|
||||
** GLimp_Shutdown
|
||||
** GLimp_SwitchFullscreen
|
||||
**
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
#include "../ref_gl/gl_local.h"
|
||||
#include "glw_win.h"
|
||||
#include "winquake.h"
|
||||
|
||||
static qboolean GLimp_SwitchFullscreen( int width, int height );
|
||||
qboolean GLimp_InitGL (void);
|
||||
|
||||
glwstate_t glw_state;
|
||||
|
||||
extern cvar_t *vid_fullscreen;
|
||||
extern cvar_t *vid_ref;
|
||||
|
||||
static qboolean VerifyDriver( void )
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
strcpy( buffer, qglGetString( GL_RENDERER ) );
|
||||
strlwr( buffer );
|
||||
if ( strcmp( buffer, "gdi generic" ) == 0 )
|
||||
if ( !glw_state.mcd_accelerated )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_CreateWindow
|
||||
*/
|
||||
#define WINDOW_CLASS_NAME "Quake 2"
|
||||
|
||||
qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
|
||||
{
|
||||
WNDCLASS wc;
|
||||
RECT r;
|
||||
cvar_t *vid_xpos, *vid_ypos;
|
||||
int stylebits;
|
||||
int x, y, w, h;
|
||||
int exstyle;
|
||||
|
||||
/* Register the frame class */
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = (WNDPROC)glw_state.wndproc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = glw_state.hInstance;
|
||||
wc.hIcon = 0;
|
||||
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
|
||||
wc.hbrBackground = (void *)COLOR_GRAYTEXT;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.lpszClassName = WINDOW_CLASS_NAME;
|
||||
|
||||
if (!RegisterClass (&wc) )
|
||||
ri.Sys_Error (ERR_FATAL, "Couldn't register window class");
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
exstyle = WS_EX_TOPMOST;
|
||||
stylebits = WS_POPUP|WS_VISIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
exstyle = 0;
|
||||
stylebits = WINDOW_STYLE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
|
||||
vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
|
||||
x = vid_xpos->value;
|
||||
y = vid_ypos->value;
|
||||
}
|
||||
|
||||
glw_state.hWnd = CreateWindowEx (
|
||||
exstyle,
|
||||
WINDOW_CLASS_NAME,
|
||||
"Quake 2",
|
||||
stylebits,
|
||||
x, y, w, h,
|
||||
NULL,
|
||||
NULL,
|
||||
glw_state.hInstance,
|
||||
NULL);
|
||||
|
||||
if (!glw_state.hWnd)
|
||||
ri.Sys_Error (ERR_FATAL, "Couldn't create window");
|
||||
|
||||
ShowWindow( glw_state.hWnd, SW_SHOW );
|
||||
UpdateWindow( glw_state.hWnd );
|
||||
|
||||
// init all the gl stuff for the window
|
||||
if (!GLimp_InitGL ())
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetForegroundWindow( glw_state.hWnd );
|
||||
SetFocus( glw_state.hWnd );
|
||||
|
||||
// let the sound and input subsystems know about the new window
|
||||
ri.Vid_NewWindow (width, height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** GLimp_SetMode
|
||||
*/
|
||||
rserr_t GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
|
||||
{
|
||||
int width, height;
|
||||
const char *win_fs[] = { "W", "FS" };
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
|
||||
|
||||
ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
|
||||
|
||||
if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
|
||||
return rserr_invalid_mode;
|
||||
}
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, " %d %d %s\n", width, height, win_fs[fullscreen] );
|
||||
|
||||
// destroy the existing window
|
||||
if (glw_state.hWnd)
|
||||
{
|
||||
GLimp_Shutdown ();
|
||||
}
|
||||
|
||||
// do a CDS if needed
|
||||
if ( fullscreen )
|
||||
{
|
||||
DEVMODE dm;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...attempting fullscreen\n" );
|
||||
|
||||
memset( &dm, 0, sizeof( dm ) );
|
||||
|
||||
dm.dmSize = sizeof( dm );
|
||||
|
||||
dm.dmPelsWidth = width;
|
||||
dm.dmPelsHeight = height;
|
||||
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
||||
|
||||
if ( gl_bitdepth->value != 0 )
|
||||
{
|
||||
dm.dmBitsPerPel = gl_bitdepth->value;
|
||||
dm.dmFields |= DM_BITSPERPEL;
|
||||
ri.Con_Printf( PRINT_ALL, "...using gl_bitdepth of %d\n", ( int ) gl_bitdepth->value );
|
||||
}
|
||||
else
|
||||
{
|
||||
HDC hdc = GetDC( NULL );
|
||||
int bitspixel = GetDeviceCaps( hdc, BITSPIXEL );
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel );
|
||||
|
||||
ReleaseDC( 0, hdc );
|
||||
}
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...calling CDS: " );
|
||||
if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
|
||||
{
|
||||
*pwidth = width;
|
||||
*pheight = height;
|
||||
|
||||
gl_state.fullscreen = true;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
if ( !VID_CreateWindow (width, height, true) )
|
||||
return rserr_invalid_mode;
|
||||
|
||||
return rserr_ok;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pwidth = width;
|
||||
*pheight = height;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "failed\n" );
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" );
|
||||
|
||||
dm.dmPelsWidth = width * 2;
|
||||
dm.dmPelsHeight = height;
|
||||
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
||||
|
||||
if ( gl_bitdepth->value != 0 )
|
||||
{
|
||||
dm.dmBitsPerPel = gl_bitdepth->value;
|
||||
dm.dmFields |= DM_BITSPERPEL;
|
||||
}
|
||||
|
||||
/*
|
||||
** our first CDS failed, so maybe we're running on some weird dual monitor
|
||||
** system
|
||||
*/
|
||||
if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, " failed\n" );
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
|
||||
|
||||
ChangeDisplaySettings( 0, 0 );
|
||||
|
||||
*pwidth = width;
|
||||
*pheight = height;
|
||||
gl_state.fullscreen = false;
|
||||
if ( !VID_CreateWindow (width, height, false) )
|
||||
return rserr_invalid_mode;
|
||||
return rserr_invalid_fullscreen;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, " ok\n" );
|
||||
if ( !VID_CreateWindow (width, height, true) )
|
||||
return rserr_invalid_mode;
|
||||
|
||||
gl_state.fullscreen = true;
|
||||
return rserr_ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
|
||||
|
||||
ChangeDisplaySettings( 0, 0 );
|
||||
|
||||
*pwidth = width;
|
||||
*pheight = height;
|
||||
gl_state.fullscreen = false;
|
||||
if ( !VID_CreateWindow (width, height, false) )
|
||||
return rserr_invalid_mode;
|
||||
}
|
||||
|
||||
return rserr_ok;
|
||||
}
|
||||
|
||||
/*
|
||||
** GLimp_Shutdown
|
||||
**
|
||||
** This routine does all OS specific shutdown procedures for the OpenGL
|
||||
** subsystem. Under OpenGL this means NULLing out the current DC and
|
||||
** HGLRC, deleting the rendering context, and releasing the DC acquired
|
||||
** for the window. The state structure is also nulled out.
|
||||
**
|
||||
*/
|
||||
void GLimp_Shutdown( void )
|
||||
{
|
||||
if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) )
|
||||
ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n");
|
||||
if ( glw_state.hGLRC )
|
||||
{
|
||||
if ( qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) )
|
||||
ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n");
|
||||
glw_state.hGLRC = NULL;
|
||||
}
|
||||
if (glw_state.hDC)
|
||||
{
|
||||
if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) )
|
||||
ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" );
|
||||
glw_state.hDC = NULL;
|
||||
}
|
||||
if (glw_state.hWnd)
|
||||
{
|
||||
DestroyWindow ( glw_state.hWnd );
|
||||
glw_state.hWnd = NULL;
|
||||
}
|
||||
|
||||
if ( glw_state.log_fp )
|
||||
{
|
||||
fclose( glw_state.log_fp );
|
||||
glw_state.log_fp = 0;
|
||||
}
|
||||
|
||||
UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance);
|
||||
|
||||
if ( gl_state.fullscreen )
|
||||
{
|
||||
ChangeDisplaySettings( 0, 0 );
|
||||
gl_state.fullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** GLimp_Init
|
||||
**
|
||||
** This routine is responsible for initializing the OS specific portions
|
||||
** of OpenGL. Under Win32 this means dealing with the pixelformats and
|
||||
** doing the wgl interface stuff.
|
||||
*/
|
||||
qboolean GLimp_Init( void *hinstance, void *wndproc )
|
||||
{
|
||||
#define OSR2_BUILD_NUMBER 1111
|
||||
|
||||
OSVERSIONINFO vinfo;
|
||||
|
||||
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
|
||||
|
||||
glw_state.allowdisplaydepthchange = false;
|
||||
|
||||
if ( GetVersionEx( &vinfo) )
|
||||
{
|
||||
if ( vinfo.dwMajorVersion > 4 )
|
||||
{
|
||||
glw_state.allowdisplaydepthchange = true;
|
||||
}
|
||||
else if ( vinfo.dwMajorVersion == 4 )
|
||||
{
|
||||
if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
|
||||
{
|
||||
glw_state.allowdisplaydepthchange = true;
|
||||
}
|
||||
else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
|
||||
{
|
||||
if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
|
||||
{
|
||||
glw_state.allowdisplaydepthchange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
glw_state.hInstance = ( HINSTANCE ) hinstance;
|
||||
glw_state.wndproc = wndproc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean GLimp_InitGL (void)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd =
|
||||
{
|
||||
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
|
||||
1, // version number
|
||||
PFD_DRAW_TO_WINDOW | // support window
|
||||
PFD_SUPPORT_OPENGL | // support OpenGL
|
||||
PFD_DOUBLEBUFFER, // double buffered
|
||||
PFD_TYPE_RGBA, // RGBA type
|
||||
24, // 24-bit color depth
|
||||
0, 0, 0, 0, 0, 0, // color bits ignored
|
||||
0, // no alpha buffer
|
||||
0, // shift bit ignored
|
||||
0, // no accumulation buffer
|
||||
0, 0, 0, 0, // accum bits ignored
|
||||
32, // 32-bit z-buffer
|
||||
0, // no stencil buffer
|
||||
0, // no auxiliary buffer
|
||||
PFD_MAIN_PLANE, // main layer
|
||||
0, // reserved
|
||||
0, 0, 0 // layer masks ignored
|
||||
};
|
||||
int pixelformat;
|
||||
cvar_t *stereo;
|
||||
|
||||
stereo = ri.Cvar_Get( "cl_stereo", "0", 0 );
|
||||
|
||||
/*
|
||||
** set PFD_STEREO if necessary
|
||||
*/
|
||||
if ( stereo->value != 0 )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" );
|
||||
pfd.dwFlags |= PFD_STEREO;
|
||||
gl_state.stereo_enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_state.stereo_enabled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
** figure out if we're running on a minidriver or not
|
||||
*/
|
||||
if ( strstr( gl_driver->string, "opengl32" ) != 0 )
|
||||
glw_state.minidriver = false;
|
||||
else
|
||||
glw_state.minidriver = true;
|
||||
|
||||
/*
|
||||
** Get a DC for the specified window
|
||||
*/
|
||||
if ( glw_state.hDC != NULL )
|
||||
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" );
|
||||
|
||||
if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( glw_state.minidriver )
|
||||
{
|
||||
if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n");
|
||||
return false;
|
||||
}
|
||||
if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n");
|
||||
return false;
|
||||
}
|
||||
qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n");
|
||||
return false;
|
||||
}
|
||||
if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n");
|
||||
return false;
|
||||
}
|
||||
DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
|
||||
|
||||
if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
|
||||
{
|
||||
extern cvar_t *gl_allow_software;
|
||||
|
||||
if ( gl_allow_software->value )
|
||||
glw_state.mcd_accelerated = true;
|
||||
else
|
||||
glw_state.mcd_accelerated = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
glw_state.mcd_accelerated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** report if stereo is desired but unavailable
|
||||
*/
|
||||
if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
|
||||
ri.Cvar_SetValue( "cl_stereo", 0 );
|
||||
gl_state.stereo_enabled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
** startup the OpenGL subsystem by creating a context and making
|
||||
** it current
|
||||
*/
|
||||
if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
|
||||
{
|
||||
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n");
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( !VerifyDriver() )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
** print out PFD specifics
|
||||
*/
|
||||
ri.Con_Printf( PRINT_ALL, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
if ( glw_state.hGLRC )
|
||||
{
|
||||
qwglDeleteContext( glw_state.hGLRC );
|
||||
glw_state.hGLRC = NULL;
|
||||
}
|
||||
|
||||
if ( glw_state.hDC )
|
||||
{
|
||||
ReleaseDC( glw_state.hWnd, glw_state.hDC );
|
||||
glw_state.hDC = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** GLimp_BeginFrame
|
||||
*/
|
||||
void GLimp_BeginFrame( float camera_separation )
|
||||
{
|
||||
if ( gl_bitdepth->modified )
|
||||
{
|
||||
if ( gl_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange )
|
||||
{
|
||||
ri.Cvar_SetValue( "gl_bitdepth", 0 );
|
||||
ri.Con_Printf( PRINT_ALL, "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
|
||||
}
|
||||
gl_bitdepth->modified = false;
|
||||
}
|
||||
|
||||
if ( camera_separation < 0 && gl_state.stereo_enabled )
|
||||
{
|
||||
qglDrawBuffer( GL_BACK_LEFT );
|
||||
}
|
||||
else if ( camera_separation > 0 && gl_state.stereo_enabled )
|
||||
{
|
||||
qglDrawBuffer( GL_BACK_RIGHT );
|
||||
}
|
||||
else
|
||||
{
|
||||
qglDrawBuffer( GL_BACK );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** GLimp_EndFrame
|
||||
**
|
||||
** Responsible for doing a swapbuffers and possibly for other stuff
|
||||
** as yet to be determined. Probably better not to make this a GLimp
|
||||
** function and instead do a call to GLimp_SwapBuffers.
|
||||
*/
|
||||
void GLimp_EndFrame (void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = qglGetError();
|
||||
assert( err == GL_NO_ERROR );
|
||||
|
||||
if ( stricmp( gl_drawbuffer->string, "GL_BACK" ) == 0 )
|
||||
{
|
||||
if ( !qwglSwapBuffers( glw_state.hDC ) )
|
||||
ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** GLimp_AppActivate
|
||||
*/
|
||||
void GLimp_AppActivate( qboolean active )
|
||||
{
|
||||
if ( active )
|
||||
{
|
||||
SetForegroundWindow( glw_state.hWnd );
|
||||
ShowWindow( glw_state.hWnd, SW_RESTORE );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( vid_fullscreen->value )
|
||||
ShowWindow( glw_state.hWnd, SW_MINIMIZE );
|
||||
}
|
||||
}
|
||||
47
win32/glw_win.h
Normal file
47
win32/glw_win.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
# error You should not be including this file on this platform
|
||||
#endif
|
||||
|
||||
#ifndef __GLW_WIN_H__
|
||||
#define __GLW_WIN_H__
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HINSTANCE hInstance;
|
||||
void *wndproc;
|
||||
|
||||
HDC hDC; // handle to device context
|
||||
HWND hWnd; // handle to window
|
||||
HGLRC hGLRC; // handle to GL rendering context
|
||||
|
||||
HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library
|
||||
|
||||
qboolean minidriver;
|
||||
qboolean allowdisplaydepthchange;
|
||||
qboolean mcd_accelerated;
|
||||
|
||||
FILE *log_fp;
|
||||
} glwstate_t;
|
||||
|
||||
extern glwstate_t glw_state;
|
||||
|
||||
#endif
|
||||
889
win32/in_win.c
Normal file
889
win32/in_win.c
Normal file
@@ -0,0 +1,889 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// in_win.c -- windows 95 mouse and joystick code
|
||||
// 02/21/97 JCB Added extended DirectInput code to support external controllers.
|
||||
|
||||
#include "../client/client.h"
|
||||
#include "winquake.h"
|
||||
|
||||
extern unsigned sys_msg_time;
|
||||
|
||||
// joystick defines and variables
|
||||
// where should defines be moved?
|
||||
#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick
|
||||
#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball
|
||||
#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
|
||||
#define JOY_AXIS_X 0
|
||||
#define JOY_AXIS_Y 1
|
||||
#define JOY_AXIS_Z 2
|
||||
#define JOY_AXIS_R 3
|
||||
#define JOY_AXIS_U 4
|
||||
#define JOY_AXIS_V 5
|
||||
|
||||
enum _ControlList
|
||||
{
|
||||
AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn, AxisUp
|
||||
};
|
||||
|
||||
DWORD dwAxisFlags[JOY_MAX_AXES] =
|
||||
{
|
||||
JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
|
||||
};
|
||||
|
||||
DWORD dwAxisMap[JOY_MAX_AXES];
|
||||
DWORD dwControlMap[JOY_MAX_AXES];
|
||||
PDWORD pdwRawValue[JOY_MAX_AXES];
|
||||
|
||||
cvar_t *in_mouse;
|
||||
cvar_t *in_joystick;
|
||||
|
||||
|
||||
// none of these cvars are saved over a session
|
||||
// this means that advanced controller configuration needs to be executed
|
||||
// each time. this avoids any problems with getting back to a default usage
|
||||
// or when changing from one controller to another. this way at least something
|
||||
// works.
|
||||
cvar_t *joy_name;
|
||||
cvar_t *joy_advanced;
|
||||
cvar_t *joy_advaxisx;
|
||||
cvar_t *joy_advaxisy;
|
||||
cvar_t *joy_advaxisz;
|
||||
cvar_t *joy_advaxisr;
|
||||
cvar_t *joy_advaxisu;
|
||||
cvar_t *joy_advaxisv;
|
||||
cvar_t *joy_forwardthreshold;
|
||||
cvar_t *joy_sidethreshold;
|
||||
cvar_t *joy_pitchthreshold;
|
||||
cvar_t *joy_yawthreshold;
|
||||
cvar_t *joy_forwardsensitivity;
|
||||
cvar_t *joy_sidesensitivity;
|
||||
cvar_t *joy_pitchsensitivity;
|
||||
cvar_t *joy_yawsensitivity;
|
||||
cvar_t *joy_upthreshold;
|
||||
cvar_t *joy_upsensitivity;
|
||||
|
||||
qboolean joy_avail, joy_advancedinit, joy_haspov;
|
||||
DWORD joy_oldbuttonstate, joy_oldpovstate;
|
||||
|
||||
int joy_id;
|
||||
DWORD joy_flags;
|
||||
DWORD joy_numbuttons;
|
||||
|
||||
static JOYINFOEX ji;
|
||||
|
||||
qboolean in_appactive;
|
||||
|
||||
// forward-referenced functions
|
||||
void IN_StartupJoystick (void);
|
||||
void Joy_AdvancedUpdate_f (void);
|
||||
void IN_JoyMove (usercmd_t *cmd);
|
||||
|
||||
/*
|
||||
============================================================
|
||||
|
||||
MOUSE CONTROL
|
||||
|
||||
============================================================
|
||||
*/
|
||||
|
||||
// mouse variables
|
||||
cvar_t *m_filter;
|
||||
|
||||
qboolean mlooking;
|
||||
|
||||
void IN_MLookDown (void) { mlooking = true; }
|
||||
void IN_MLookUp (void) {
|
||||
mlooking = false;
|
||||
if (!freelook->value && lookspring->value)
|
||||
IN_CenterView ();
|
||||
}
|
||||
|
||||
int mouse_buttons;
|
||||
int mouse_oldbuttonstate;
|
||||
POINT current_pos;
|
||||
int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
|
||||
|
||||
int old_x, old_y;
|
||||
|
||||
qboolean mouseactive; // false when not focus app
|
||||
|
||||
qboolean restore_spi;
|
||||
qboolean mouseinitialized;
|
||||
int originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
|
||||
qboolean mouseparmsvalid;
|
||||
|
||||
int window_center_x, window_center_y;
|
||||
RECT window_rect;
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_ActivateMouse
|
||||
|
||||
Called when the window gains focus or changes in some way
|
||||
===========
|
||||
*/
|
||||
void IN_ActivateMouse (void)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
if (!in_mouse->value)
|
||||
{
|
||||
mouseactive = false;
|
||||
return;
|
||||
}
|
||||
if (mouseactive)
|
||||
return;
|
||||
|
||||
mouseactive = true;
|
||||
|
||||
if (mouseparmsvalid)
|
||||
restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
|
||||
|
||||
width = GetSystemMetrics (SM_CXSCREEN);
|
||||
height = GetSystemMetrics (SM_CYSCREEN);
|
||||
|
||||
GetWindowRect ( cl_hwnd, &window_rect);
|
||||
if (window_rect.left < 0)
|
||||
window_rect.left = 0;
|
||||
if (window_rect.top < 0)
|
||||
window_rect.top = 0;
|
||||
if (window_rect.right >= width)
|
||||
window_rect.right = width-1;
|
||||
if (window_rect.bottom >= height-1)
|
||||
window_rect.bottom = height-1;
|
||||
|
||||
window_center_x = (window_rect.right + window_rect.left)/2;
|
||||
window_center_y = (window_rect.top + window_rect.bottom)/2;
|
||||
|
||||
SetCursorPos (window_center_x, window_center_y);
|
||||
|
||||
old_x = window_center_x;
|
||||
old_y = window_center_y;
|
||||
|
||||
SetCapture ( cl_hwnd );
|
||||
ClipCursor (&window_rect);
|
||||
while (ShowCursor (FALSE) >= 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_DeactivateMouse
|
||||
|
||||
Called when the window loses focus
|
||||
===========
|
||||
*/
|
||||
void IN_DeactivateMouse (void)
|
||||
{
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
if (!mouseactive)
|
||||
return;
|
||||
|
||||
if (restore_spi)
|
||||
SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
|
||||
|
||||
mouseactive = false;
|
||||
|
||||
ClipCursor (NULL);
|
||||
ReleaseCapture ();
|
||||
while (ShowCursor (TRUE) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_StartupMouse
|
||||
===========
|
||||
*/
|
||||
void IN_StartupMouse (void)
|
||||
{
|
||||
cvar_t *cv;
|
||||
|
||||
cv = Cvar_Get ("in_initmouse", "1", CVAR_NOSET);
|
||||
if ( !cv->value )
|
||||
return;
|
||||
|
||||
mouseinitialized = true;
|
||||
mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
|
||||
mouse_buttons = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_MouseEvent
|
||||
===========
|
||||
*/
|
||||
void IN_MouseEvent (int mstate)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
|
||||
// perform button actions
|
||||
for (i=0 ; i<mouse_buttons ; i++)
|
||||
{
|
||||
if ( (mstate & (1<<i)) &&
|
||||
!(mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_MOUSE1 + i, true, sys_msg_time);
|
||||
}
|
||||
|
||||
if ( !(mstate & (1<<i)) &&
|
||||
(mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_MOUSE1 + i, false, sys_msg_time);
|
||||
}
|
||||
}
|
||||
|
||||
mouse_oldbuttonstate = mstate;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_MouseMove
|
||||
===========
|
||||
*/
|
||||
void IN_MouseMove (usercmd_t *cmd)
|
||||
{
|
||||
int mx, my;
|
||||
|
||||
if (!mouseactive)
|
||||
return;
|
||||
|
||||
// find mouse movement
|
||||
if (!GetCursorPos (¤t_pos))
|
||||
return;
|
||||
|
||||
mx = current_pos.x - window_center_x;
|
||||
my = current_pos.y - window_center_y;
|
||||
|
||||
#if 0
|
||||
if (!mx && !my)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (m_filter->value)
|
||||
{
|
||||
mouse_x = (mx + old_mouse_x) * 0.5;
|
||||
mouse_y = (my + old_mouse_y) * 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse_x = mx;
|
||||
mouse_y = my;
|
||||
}
|
||||
|
||||
old_mouse_x = mx;
|
||||
old_mouse_y = my;
|
||||
|
||||
mouse_x *= sensitivity->value;
|
||||
mouse_y *= sensitivity->value;
|
||||
|
||||
// add mouse X/Y movement to cmd
|
||||
if ( (in_strafe.state & 1) || (lookstrafe->value && mlooking ))
|
||||
cmd->sidemove += m_side->value * mouse_x;
|
||||
else
|
||||
cl.viewangles[YAW] -= m_yaw->value * mouse_x;
|
||||
|
||||
if ( (mlooking || freelook->value) && !(in_strafe.state & 1))
|
||||
{
|
||||
cl.viewangles[PITCH] += m_pitch->value * mouse_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->forwardmove -= m_forward->value * mouse_y;
|
||||
}
|
||||
|
||||
// force the mouse to the center, so there's room to move
|
||||
if (mx || my)
|
||||
SetCursorPos (window_center_x, window_center_y);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================================================================
|
||||
|
||||
VIEW CENTERING
|
||||
|
||||
=========================================================================
|
||||
*/
|
||||
|
||||
cvar_t *v_centermove;
|
||||
cvar_t *v_centerspeed;
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Init
|
||||
===========
|
||||
*/
|
||||
void IN_Init (void)
|
||||
{
|
||||
// mouse variables
|
||||
m_filter = Cvar_Get ("m_filter", "0", 0);
|
||||
in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
|
||||
|
||||
// joystick variables
|
||||
in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
|
||||
joy_name = Cvar_Get ("joy_name", "joystick", 0);
|
||||
joy_advanced = Cvar_Get ("joy_advanced", "0", 0);
|
||||
joy_advaxisx = Cvar_Get ("joy_advaxisx", "0", 0);
|
||||
joy_advaxisy = Cvar_Get ("joy_advaxisy", "0", 0);
|
||||
joy_advaxisz = Cvar_Get ("joy_advaxisz", "0", 0);
|
||||
joy_advaxisr = Cvar_Get ("joy_advaxisr", "0", 0);
|
||||
joy_advaxisu = Cvar_Get ("joy_advaxisu", "0", 0);
|
||||
joy_advaxisv = Cvar_Get ("joy_advaxisv", "0", 0);
|
||||
joy_forwardthreshold = Cvar_Get ("joy_forwardthreshold", "0.15", 0);
|
||||
joy_sidethreshold = Cvar_Get ("joy_sidethreshold", "0.15", 0);
|
||||
joy_upthreshold = Cvar_Get ("joy_upthreshold", "0.15", 0);
|
||||
joy_pitchthreshold = Cvar_Get ("joy_pitchthreshold", "0.15", 0);
|
||||
joy_yawthreshold = Cvar_Get ("joy_yawthreshold", "0.15", 0);
|
||||
joy_forwardsensitivity = Cvar_Get ("joy_forwardsensitivity", "-1", 0);
|
||||
joy_sidesensitivity = Cvar_Get ("joy_sidesensitivity", "-1", 0);
|
||||
joy_upsensitivity = Cvar_Get ("joy_upsensitivity", "-1", 0);
|
||||
joy_pitchsensitivity = Cvar_Get ("joy_pitchsensitivity", "1", 0);
|
||||
joy_yawsensitivity = Cvar_Get ("joy_yawsensitivity", "-1", 0);
|
||||
|
||||
// centering
|
||||
v_centermove = Cvar_Get ("v_centermove", "0.15", 0);
|
||||
v_centerspeed = Cvar_Get ("v_centerspeed", "500", 0);
|
||||
|
||||
Cmd_AddCommand ("+mlook", IN_MLookDown);
|
||||
Cmd_AddCommand ("-mlook", IN_MLookUp);
|
||||
|
||||
Cmd_AddCommand ("joy_advancedupdate", Joy_AdvancedUpdate_f);
|
||||
|
||||
IN_StartupMouse ();
|
||||
IN_StartupJoystick ();
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Shutdown
|
||||
===========
|
||||
*/
|
||||
void IN_Shutdown (void)
|
||||
{
|
||||
IN_DeactivateMouse ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Activate
|
||||
|
||||
Called when the main window gains or loses focus.
|
||||
The window may have been destroyed and recreated
|
||||
between a deactivate and an activate.
|
||||
===========
|
||||
*/
|
||||
void IN_Activate (qboolean active)
|
||||
{
|
||||
in_appactive = active;
|
||||
mouseactive = !active; // force a new window check or turn off
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
IN_Frame
|
||||
|
||||
Called every frame, even if not generating commands
|
||||
==================
|
||||
*/
|
||||
void IN_Frame (void)
|
||||
{
|
||||
if (!mouseinitialized)
|
||||
return;
|
||||
|
||||
if (!in_mouse || !in_appactive)
|
||||
{
|
||||
IN_DeactivateMouse ();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !cl.refresh_prepped
|
||||
|| cls.key_dest == key_console
|
||||
|| cls.key_dest == key_menu)
|
||||
{
|
||||
// temporarily deactivate if in fullscreen
|
||||
if (Cvar_VariableValue ("vid_fullscreen") == 0)
|
||||
{
|
||||
IN_DeactivateMouse ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IN_ActivateMouse ();
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Move
|
||||
===========
|
||||
*/
|
||||
void IN_Move (usercmd_t *cmd)
|
||||
{
|
||||
IN_MouseMove (cmd);
|
||||
|
||||
if (ActiveApp)
|
||||
IN_JoyMove (cmd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
IN_ClearStates
|
||||
===================
|
||||
*/
|
||||
void IN_ClearStates (void)
|
||||
{
|
||||
mx_accum = 0;
|
||||
my_accum = 0;
|
||||
mouse_oldbuttonstate = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================================================================
|
||||
|
||||
JOYSTICK
|
||||
|
||||
=========================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_StartupJoystick
|
||||
===============
|
||||
*/
|
||||
void IN_StartupJoystick (void)
|
||||
{
|
||||
int numdevs;
|
||||
JOYCAPS jc;
|
||||
MMRESULT mmr;
|
||||
cvar_t *cv;
|
||||
|
||||
// assume no joystick
|
||||
joy_avail = false;
|
||||
|
||||
// abort startup if user requests no joystick
|
||||
cv = Cvar_Get ("in_initjoy", "1", CVAR_NOSET);
|
||||
if ( !cv->value )
|
||||
return;
|
||||
|
||||
// verify joystick driver is present
|
||||
if ((numdevs = joyGetNumDevs ()) == 0)
|
||||
{
|
||||
// Com_Printf ("\njoystick not found -- driver not present\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// cycle through the joystick ids for the first valid one
|
||||
for (joy_id=0 ; joy_id<numdevs ; joy_id++)
|
||||
{
|
||||
memset (&ji, 0, sizeof(ji));
|
||||
ji.dwSize = sizeof(ji);
|
||||
ji.dwFlags = JOY_RETURNCENTERED;
|
||||
|
||||
if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
// abort startup if we didn't find a valid joystick
|
||||
if (mmr != JOYERR_NOERROR)
|
||||
{
|
||||
Com_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the capabilities of the selected joystick
|
||||
// abort startup if command fails
|
||||
memset (&jc, 0, sizeof(jc));
|
||||
if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
|
||||
{
|
||||
Com_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
|
||||
return;
|
||||
}
|
||||
|
||||
// save the joystick's number of buttons and POV status
|
||||
joy_numbuttons = jc.wNumButtons;
|
||||
joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
|
||||
|
||||
// old button and POV states default to no buttons pressed
|
||||
joy_oldbuttonstate = joy_oldpovstate = 0;
|
||||
|
||||
// mark the joystick as available and advanced initialization not completed
|
||||
// this is needed as cvars are not available during initialization
|
||||
|
||||
joy_avail = true;
|
||||
joy_advancedinit = false;
|
||||
|
||||
Com_Printf ("\njoystick detected\n\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
RawValuePointer
|
||||
===========
|
||||
*/
|
||||
PDWORD RawValuePointer (int axis)
|
||||
{
|
||||
switch (axis)
|
||||
{
|
||||
case JOY_AXIS_X:
|
||||
return &ji.dwXpos;
|
||||
case JOY_AXIS_Y:
|
||||
return &ji.dwYpos;
|
||||
case JOY_AXIS_Z:
|
||||
return &ji.dwZpos;
|
||||
case JOY_AXIS_R:
|
||||
return &ji.dwRpos;
|
||||
case JOY_AXIS_U:
|
||||
return &ji.dwUpos;
|
||||
case JOY_AXIS_V:
|
||||
return &ji.dwVpos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
Joy_AdvancedUpdate_f
|
||||
===========
|
||||
*/
|
||||
void Joy_AdvancedUpdate_f (void)
|
||||
{
|
||||
|
||||
// called once by IN_ReadJoystick and by user whenever an update is needed
|
||||
// cvars are now available
|
||||
int i;
|
||||
DWORD dwTemp;
|
||||
|
||||
// initialize all the maps
|
||||
for (i = 0; i < JOY_MAX_AXES; i++)
|
||||
{
|
||||
dwAxisMap[i] = AxisNada;
|
||||
dwControlMap[i] = JOY_ABSOLUTE_AXIS;
|
||||
pdwRawValue[i] = RawValuePointer(i);
|
||||
}
|
||||
|
||||
if( joy_advanced->value == 0.0)
|
||||
{
|
||||
// default joystick initialization
|
||||
// 2 axes only with joystick control
|
||||
dwAxisMap[JOY_AXIS_X] = AxisTurn;
|
||||
// dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
|
||||
dwAxisMap[JOY_AXIS_Y] = AxisForward;
|
||||
// dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp (joy_name->string, "joystick") != 0)
|
||||
{
|
||||
// notify user of advanced controller
|
||||
Com_Printf ("\n%s configured\n\n", joy_name->string);
|
||||
}
|
||||
|
||||
// advanced initialization here
|
||||
// data supplied by user via joy_axisn cvars
|
||||
dwTemp = (DWORD) joy_advaxisx->value;
|
||||
dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
|
||||
dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
|
||||
dwTemp = (DWORD) joy_advaxisy->value;
|
||||
dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
|
||||
dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
|
||||
dwTemp = (DWORD) joy_advaxisz->value;
|
||||
dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
|
||||
dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
|
||||
dwTemp = (DWORD) joy_advaxisr->value;
|
||||
dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
|
||||
dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
|
||||
dwTemp = (DWORD) joy_advaxisu->value;
|
||||
dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
|
||||
dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
|
||||
dwTemp = (DWORD) joy_advaxisv->value;
|
||||
dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
|
||||
dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
|
||||
}
|
||||
|
||||
// compute the axes to collect from DirectInput
|
||||
joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
|
||||
for (i = 0; i < JOY_MAX_AXES; i++)
|
||||
{
|
||||
if (dwAxisMap[i] != AxisNada)
|
||||
{
|
||||
joy_flags |= dwAxisFlags[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Commands
|
||||
===========
|
||||
*/
|
||||
void IN_Commands (void)
|
||||
{
|
||||
int i, key_index;
|
||||
DWORD buttonstate, povstate;
|
||||
|
||||
if (!joy_avail)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// loop through the joystick buttons
|
||||
// key a joystick event or auxillary event for higher number buttons for each state change
|
||||
buttonstate = ji.dwButtons;
|
||||
for (i=0 ; i < joy_numbuttons ; i++)
|
||||
{
|
||||
if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
key_index = (i < 4) ? K_JOY1 : K_AUX1;
|
||||
Key_Event (key_index + i, true, 0);
|
||||
}
|
||||
|
||||
if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
key_index = (i < 4) ? K_JOY1 : K_AUX1;
|
||||
Key_Event (key_index + i, false, 0);
|
||||
}
|
||||
}
|
||||
joy_oldbuttonstate = buttonstate;
|
||||
|
||||
if (joy_haspov)
|
||||
{
|
||||
// convert POV information into 4 bits of state information
|
||||
// this avoids any potential problems related to moving from one
|
||||
// direction to another without going through the center position
|
||||
povstate = 0;
|
||||
if(ji.dwPOV != JOY_POVCENTERED)
|
||||
{
|
||||
if (ji.dwPOV == JOY_POVFORWARD)
|
||||
povstate |= 0x01;
|
||||
if (ji.dwPOV == JOY_POVRIGHT)
|
||||
povstate |= 0x02;
|
||||
if (ji.dwPOV == JOY_POVBACKWARD)
|
||||
povstate |= 0x04;
|
||||
if (ji.dwPOV == JOY_POVLEFT)
|
||||
povstate |= 0x08;
|
||||
}
|
||||
// determine which bits have changed and key an auxillary event for each change
|
||||
for (i=0 ; i < 4 ; i++)
|
||||
{
|
||||
if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_AUX29 + i, true, 0);
|
||||
}
|
||||
|
||||
if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
|
||||
{
|
||||
Key_Event (K_AUX29 + i, false, 0);
|
||||
}
|
||||
}
|
||||
joy_oldpovstate = povstate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
IN_ReadJoystick
|
||||
===============
|
||||
*/
|
||||
qboolean IN_ReadJoystick (void)
|
||||
{
|
||||
|
||||
memset (&ji, 0, sizeof(ji));
|
||||
ji.dwSize = sizeof(ji);
|
||||
ji.dwFlags = joy_flags;
|
||||
|
||||
if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// read error occurred
|
||||
// turning off the joystick seems too harsh for 1 read error,\
|
||||
// but what should be done?
|
||||
// Com_Printf ("IN_ReadJoystick: no response\n");
|
||||
// joy_avail = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_JoyMove
|
||||
===========
|
||||
*/
|
||||
void IN_JoyMove (usercmd_t *cmd)
|
||||
{
|
||||
float speed, aspeed;
|
||||
float fAxisValue;
|
||||
int i;
|
||||
|
||||
// complete initialization if first time in
|
||||
// this is needed as cvars are not available at initialization time
|
||||
if( joy_advancedinit != true )
|
||||
{
|
||||
Joy_AdvancedUpdate_f();
|
||||
joy_advancedinit = true;
|
||||
}
|
||||
|
||||
// verify joystick is available and that the user wants to use it
|
||||
if (!joy_avail || !in_joystick->value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// collect the joystick data, if possible
|
||||
if (IN_ReadJoystick () != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (in_speed.state & 1) ^ (int)cl_run->value)
|
||||
speed = 2;
|
||||
else
|
||||
speed = 1;
|
||||
aspeed = speed * cls.frametime;
|
||||
|
||||
// loop through the axes
|
||||
for (i = 0; i < JOY_MAX_AXES; i++)
|
||||
{
|
||||
// get the floating point zero-centered, potentially-inverted data for the current axis
|
||||
fAxisValue = (float) *pdwRawValue[i];
|
||||
// move centerpoint to zero
|
||||
fAxisValue -= 32768.0;
|
||||
|
||||
// convert range from -32768..32767 to -1..1
|
||||
fAxisValue /= 32768.0;
|
||||
|
||||
switch (dwAxisMap[i])
|
||||
{
|
||||
case AxisForward:
|
||||
if ((joy_advanced->value == 0.0) && mlooking)
|
||||
{
|
||||
// user wants forward control to become look control
|
||||
if (fabs(fAxisValue) > joy_pitchthreshold->value)
|
||||
{
|
||||
// if mouse invert is on, invert the joystick pitch value
|
||||
// only absolute control support here (joy_advanced is false)
|
||||
if (m_pitch->value < 0.0)
|
||||
{
|
||||
cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// user wants forward control to be forward control
|
||||
if (fabs(fAxisValue) > joy_forwardthreshold->value)
|
||||
{
|
||||
cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AxisSide:
|
||||
if (fabs(fAxisValue) > joy_sidethreshold->value)
|
||||
{
|
||||
cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case AxisUp:
|
||||
if (fabs(fAxisValue) > joy_upthreshold->value)
|
||||
{
|
||||
cmd->upmove += (fAxisValue * joy_upsensitivity->value) * speed * cl_upspeed->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case AxisTurn:
|
||||
if ((in_strafe.state & 1) || (lookstrafe->value && mlooking))
|
||||
{
|
||||
// user wants turn control to become side control
|
||||
if (fabs(fAxisValue) > joy_sidethreshold->value)
|
||||
{
|
||||
cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// user wants turn control to be turn control
|
||||
if (fabs(fAxisValue) > joy_yawthreshold->value)
|
||||
{
|
||||
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
|
||||
{
|
||||
cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AxisLook:
|
||||
if (mlooking)
|
||||
{
|
||||
if (fabs(fAxisValue) > joy_pitchthreshold->value)
|
||||
{
|
||||
// pitch movement detected and pitch movement desired by user
|
||||
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
|
||||
{
|
||||
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
842
win32/net_wins.c
Normal file
842
win32/net_wins.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_wins.c
|
||||
|
||||
#include "winsock.h"
|
||||
#include "wsipx.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
#define MAX_LOOPBACK 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte data[MAX_MSGLEN];
|
||||
int datalen;
|
||||
} loopmsg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
loopmsg_t msgs[MAX_LOOPBACK];
|
||||
int get, send;
|
||||
} loopback_t;
|
||||
|
||||
|
||||
cvar_t *net_shownet;
|
||||
static cvar_t *noudp;
|
||||
static cvar_t *noipx;
|
||||
|
||||
loopback_t loopbacks[2];
|
||||
int ip_sockets[2];
|
||||
int ipx_sockets[2];
|
||||
|
||||
char *NET_ErrorString (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void NetadrToSockadr (netadr_t *a, struct sockaddr *s)
|
||||
{
|
||||
memset (s, 0, sizeof(*s));
|
||||
|
||||
if (a->type == NA_BROADCAST)
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else if (a->type == NA_IP)
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
}
|
||||
else if (a->type == NA_IPX)
|
||||
{
|
||||
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
|
||||
memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
|
||||
memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
|
||||
((struct sockaddr_ipx *)s)->sa_socket = a->port;
|
||||
}
|
||||
else if (a->type == NA_BROADCAST_IPX)
|
||||
{
|
||||
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
|
||||
memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4);
|
||||
memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6);
|
||||
((struct sockaddr_ipx *)s)->sa_socket = a->port;
|
||||
}
|
||||
}
|
||||
|
||||
void SockadrToNetadr (struct sockaddr *s, netadr_t *a)
|
||||
{
|
||||
if (s->sa_family == AF_INET)
|
||||
{
|
||||
a->type = NA_IP;
|
||||
*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
|
||||
a->port = ((struct sockaddr_in *)s)->sin_port;
|
||||
}
|
||||
else if (s->sa_family == AF_IPX)
|
||||
{
|
||||
a->type = NA_IPX;
|
||||
memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
|
||||
memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
|
||||
a->port = ((struct sockaddr_ipx *)s)->sa_socket;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qboolean NET_CompareAdr (netadr_t a, netadr_t b)
|
||||
{
|
||||
if (a.type != b.type)
|
||||
return false;
|
||||
|
||||
if (a.type == NA_LOOPBACK)
|
||||
return TRUE;
|
||||
|
||||
if (a.type == NA_IP)
|
||||
{
|
||||
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type == NA_IPX)
|
||||
{
|
||||
if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
NET_CompareBaseAdr
|
||||
|
||||
Compares without the port
|
||||
===================
|
||||
*/
|
||||
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
|
||||
{
|
||||
if (a.type != b.type)
|
||||
return false;
|
||||
|
||||
if (a.type == NA_LOOPBACK)
|
||||
return TRUE;
|
||||
|
||||
if (a.type == NA_IP)
|
||||
{
|
||||
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type == NA_IPX)
|
||||
{
|
||||
if ((memcmp(a.ipx, b.ipx, 10) == 0))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char *NET_AdrToString (netadr_t a)
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
if (a.type == NA_LOOPBACK)
|
||||
Com_sprintf (s, sizeof(s), "loopback");
|
||||
else if (a.type == NA_IP)
|
||||
Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
|
||||
else
|
||||
Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
localhost
|
||||
idnewt
|
||||
idnewt:28000
|
||||
192.246.40.70
|
||||
192.246.40.70:28000
|
||||
=============
|
||||
*/
|
||||
#define DO(src,dest) \
|
||||
copy[0] = s[src]; \
|
||||
copy[1] = s[src + 1]; \
|
||||
sscanf (copy, "%x", &val); \
|
||||
((struct sockaddr_ipx *)sadr)->dest = val
|
||||
|
||||
qboolean NET_StringToSockaddr (char *s, struct sockaddr *sadr)
|
||||
{
|
||||
struct hostent *h;
|
||||
char *colon;
|
||||
int val;
|
||||
char copy[128];
|
||||
|
||||
memset (sadr, 0, sizeof(*sadr));
|
||||
|
||||
if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':')) // check for an IPX address
|
||||
{
|
||||
((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
|
||||
copy[2] = 0;
|
||||
DO(0, sa_netnum[0]);
|
||||
DO(2, sa_netnum[1]);
|
||||
DO(4, sa_netnum[2]);
|
||||
DO(6, sa_netnum[3]);
|
||||
DO(9, sa_nodenum[0]);
|
||||
DO(11, sa_nodenum[1]);
|
||||
DO(13, sa_nodenum[2]);
|
||||
DO(15, sa_nodenum[3]);
|
||||
DO(17, sa_nodenum[4]);
|
||||
DO(19, sa_nodenum[5]);
|
||||
sscanf (&s[22], "%u", &val);
|
||||
((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val);
|
||||
}
|
||||
else
|
||||
{
|
||||
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)sadr)->sin_port = 0;
|
||||
|
||||
strcpy (copy, s);
|
||||
// strip off a trailing :port if present
|
||||
for (colon = copy ; *colon ; colon++)
|
||||
if (*colon == ':')
|
||||
{
|
||||
*colon = 0;
|
||||
((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));
|
||||
}
|
||||
|
||||
if (copy[0] >= '0' && copy[0] <= '9')
|
||||
{
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! (h = gethostbyname(copy)) )
|
||||
return 0;
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef DO
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
localhost
|
||||
idnewt
|
||||
idnewt:28000
|
||||
192.246.40.70
|
||||
192.246.40.70:28000
|
||||
=============
|
||||
*/
|
||||
qboolean NET_StringToAdr (char *s, netadr_t *a)
|
||||
{
|
||||
struct sockaddr sadr;
|
||||
|
||||
if (!strcmp (s, "localhost"))
|
||||
{
|
||||
memset (a, 0, sizeof(*a));
|
||||
a->type = NA_LOOPBACK;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!NET_StringToSockaddr (s, &sadr))
|
||||
return false;
|
||||
|
||||
SockadrToNetadr (&sadr, a);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
qboolean NET_IsLocalAddress (netadr_t adr)
|
||||
{
|
||||
return adr.type == NA_LOOPBACK;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
LOOPBACK BUFFERS FOR LOCAL PLAYER
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock];
|
||||
|
||||
if (loop->send - loop->get > MAX_LOOPBACK)
|
||||
loop->get = loop->send - MAX_LOOPBACK;
|
||||
|
||||
if (loop->get >= loop->send)
|
||||
return false;
|
||||
|
||||
i = loop->get & (MAX_LOOPBACK-1);
|
||||
loop->get++;
|
||||
|
||||
memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
|
||||
net_message->cursize = loop->msgs[i].datalen;
|
||||
memset (net_from, 0, sizeof(*net_from));
|
||||
net_from->type = NA_LOOPBACK;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock^1];
|
||||
|
||||
i = loop->send & (MAX_LOOPBACK-1);
|
||||
loop->send++;
|
||||
|
||||
memcpy (loop->msgs[i].data, data, length);
|
||||
loop->msgs[i].datalen = length;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr from;
|
||||
int fromlen;
|
||||
int net_socket;
|
||||
int protocol;
|
||||
int err;
|
||||
|
||||
if (NET_GetLoopPacket (sock, net_from, net_message))
|
||||
return true;
|
||||
|
||||
for (protocol = 0 ; protocol < 2 ; protocol++)
|
||||
{
|
||||
if (protocol == 0)
|
||||
net_socket = ip_sockets[sock];
|
||||
else
|
||||
net_socket = ipx_sockets[sock];
|
||||
|
||||
if (!net_socket)
|
||||
continue;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
ret = recvfrom (net_socket, net_message->data, net_message->maxsize
|
||||
, 0, (struct sockaddr *)&from, &fromlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
err = WSAGetLastError();
|
||||
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
continue;
|
||||
if (dedicated->value) // let dedicated servers continue after errors
|
||||
Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
|
||||
else
|
||||
Com_Error (ERR_DROP, "NET_GetPacket: %s", NET_ErrorString());
|
||||
continue;
|
||||
}
|
||||
|
||||
SockadrToNetadr (&from, net_from);
|
||||
|
||||
if (ret == net_message->maxsize)
|
||||
{
|
||||
Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
|
||||
continue;
|
||||
}
|
||||
|
||||
net_message->cursize = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr addr;
|
||||
int net_socket;
|
||||
|
||||
if ( to.type == NA_LOOPBACK )
|
||||
{
|
||||
NET_SendLoopPacket (sock, length, data, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (to.type == NA_BROADCAST)
|
||||
{
|
||||
net_socket = ip_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else if (to.type == NA_IP)
|
||||
{
|
||||
net_socket = ip_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else if (to.type == NA_IPX)
|
||||
{
|
||||
net_socket = ipx_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else if (to.type == NA_BROADCAST_IPX)
|
||||
{
|
||||
net_socket = ipx_sockets[sock];
|
||||
if (!net_socket)
|
||||
return;
|
||||
}
|
||||
else
|
||||
Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
|
||||
|
||||
NetadrToSockadr (&to, &addr);
|
||||
|
||||
ret = sendto (net_socket, data, length, 0, &addr, sizeof(addr) );
|
||||
if (ret == -1)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
|
||||
// wouldblock is silent
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
return;
|
||||
|
||||
// some PPP links dont allow broadcasts
|
||||
if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
|
||||
return;
|
||||
|
||||
if (dedicated->value) // let dedicated servers continue after errors
|
||||
{
|
||||
Com_Printf ("NET_SendPacket ERROR: %s\n", NET_ErrorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (err == WSAEADDRNOTAVAIL)
|
||||
{
|
||||
Com_DPrintf ("NET_SendPacket Warning: %s : %s\n", NET_ErrorString(), NET_AdrToString (to));
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_Error (ERR_DROP, "NET_SendPacket ERROR: %s\n", NET_ErrorString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Socket
|
||||
====================
|
||||
*/
|
||||
int NET_IPSocket (char *net_interface, int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_in address;
|
||||
qboolean _true = true;
|
||||
int i = 1;
|
||||
int err;
|
||||
|
||||
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEAFNOSUPPORT)
|
||||
Com_Printf ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it non-blocking
|
||||
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
|
||||
{
|
||||
Com_Printf ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it broadcast capable
|
||||
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
|
||||
{
|
||||
Com_Printf ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
else
|
||||
NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
|
||||
|
||||
if (port == PORT_ANY)
|
||||
address.sin_port = 0;
|
||||
else
|
||||
address.sin_port = htons((short)port);
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
{
|
||||
Com_Printf ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
|
||||
closesocket (newsocket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIP
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIP (void)
|
||||
{
|
||||
cvar_t *ip;
|
||||
int port;
|
||||
int dedicated;
|
||||
|
||||
ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
|
||||
|
||||
dedicated = Cvar_VariableValue ("dedicated");
|
||||
|
||||
if (!ip_sockets[NS_SERVER])
|
||||
{
|
||||
port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
|
||||
}
|
||||
}
|
||||
ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
|
||||
if (!ip_sockets[NS_SERVER] && dedicated)
|
||||
Com_Error (ERR_FATAL, "Couldn't allocate dedicated server IP port");
|
||||
}
|
||||
|
||||
|
||||
// dedicated servers don't need client ports
|
||||
if (dedicated)
|
||||
return;
|
||||
|
||||
if (!ip_sockets[NS_CLIENT])
|
||||
{
|
||||
port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
port = PORT_ANY;
|
||||
}
|
||||
ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
|
||||
if (!ip_sockets[NS_CLIENT])
|
||||
ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
IPX_Socket
|
||||
====================
|
||||
*/
|
||||
int NET_IPXSocket (int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_ipx address;
|
||||
int _true = 1;
|
||||
int err;
|
||||
|
||||
if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
|
||||
{
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEAFNOSUPPORT)
|
||||
Com_Printf ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it non-blocking
|
||||
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
|
||||
{
|
||||
Com_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it broadcast capable
|
||||
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
|
||||
{
|
||||
Com_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
address.sa_family = AF_IPX;
|
||||
memset (address.sa_netnum, 0, 4);
|
||||
memset (address.sa_nodenum, 0, 6);
|
||||
if (port == PORT_ANY)
|
||||
address.sa_socket = 0;
|
||||
else
|
||||
address.sa_socket = htons((short)port);
|
||||
|
||||
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
{
|
||||
Com_Printf ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
|
||||
closesocket (newsocket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIPX
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIPX (void)
|
||||
{
|
||||
int port;
|
||||
int dedicated;
|
||||
|
||||
dedicated = Cvar_VariableValue ("dedicated");
|
||||
|
||||
if (!ipx_sockets[NS_SERVER])
|
||||
{
|
||||
port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
|
||||
}
|
||||
}
|
||||
ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
|
||||
}
|
||||
|
||||
// dedicated servers don't need client ports
|
||||
if (dedicated)
|
||||
return;
|
||||
|
||||
if (!ipx_sockets[NS_CLIENT])
|
||||
{
|
||||
port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
|
||||
if (!port)
|
||||
port = PORT_ANY;
|
||||
}
|
||||
ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
|
||||
if (!ipx_sockets[NS_CLIENT])
|
||||
ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Config
|
||||
|
||||
A single player game will only use the loopback code
|
||||
====================
|
||||
*/
|
||||
void NET_Config (qboolean multiplayer)
|
||||
{
|
||||
int i;
|
||||
static qboolean old_config;
|
||||
|
||||
if (old_config == multiplayer)
|
||||
return;
|
||||
|
||||
old_config = multiplayer;
|
||||
|
||||
if (!multiplayer)
|
||||
{ // shut down any existing sockets
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (ip_sockets[i])
|
||||
{
|
||||
closesocket (ip_sockets[i]);
|
||||
ip_sockets[i] = 0;
|
||||
}
|
||||
if (ipx_sockets[i])
|
||||
{
|
||||
closesocket (ipx_sockets[i]);
|
||||
ipx_sockets[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // open sockets
|
||||
if (! noudp->value)
|
||||
NET_OpenIP ();
|
||||
if (! noipx->value)
|
||||
NET_OpenIPX ();
|
||||
}
|
||||
}
|
||||
|
||||
// sleeps msec or until net socket is ready
|
||||
void NET_Sleep(int msec)
|
||||
{
|
||||
struct timeval timeout;
|
||||
fd_set fdset;
|
||||
extern cvar_t *dedicated;
|
||||
int i;
|
||||
|
||||
if (!dedicated || !dedicated->value)
|
||||
return; // we're not a server, just run full speed
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
i = 0;
|
||||
if (ip_sockets[NS_SERVER]) {
|
||||
FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
|
||||
i = ip_sockets[NS_SERVER];
|
||||
}
|
||||
if (ipx_sockets[NS_SERVER]) {
|
||||
FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
|
||||
if (ipx_sockets[NS_SERVER] > i)
|
||||
i = ipx_sockets[NS_SERVER];
|
||||
}
|
||||
timeout.tv_sec = msec/1000;
|
||||
timeout.tv_usec = (msec%1000)*1000;
|
||||
select(i+1, &fdset, NULL, NULL, &timeout);
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
static WSADATA winsockdata;
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Init
|
||||
====================
|
||||
*/
|
||||
void NET_Init (void)
|
||||
{
|
||||
WORD wVersionRequested;
|
||||
int r;
|
||||
|
||||
wVersionRequested = MAKEWORD(1, 1);
|
||||
|
||||
r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
|
||||
|
||||
if (r)
|
||||
Com_Error (ERR_FATAL,"Winsock initialization failed.");
|
||||
|
||||
Com_Printf("Winsock Initialized\n");
|
||||
|
||||
noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
|
||||
noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
|
||||
|
||||
net_shownet = Cvar_Get ("net_shownet", "0", 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Shutdown
|
||||
====================
|
||||
*/
|
||||
void NET_Shutdown (void)
|
||||
{
|
||||
NET_Config (false); // close sockets
|
||||
|
||||
WSACleanup ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_ErrorString
|
||||
====================
|
||||
*/
|
||||
char *NET_ErrorString (void)
|
||||
{
|
||||
int code;
|
||||
|
||||
code = WSAGetLastError ();
|
||||
switch (code)
|
||||
{
|
||||
case WSAEINTR: return "WSAEINTR";
|
||||
case WSAEBADF: return "WSAEBADF";
|
||||
case WSAEACCES: return "WSAEACCES";
|
||||
case WSAEDISCON: return "WSAEDISCON";
|
||||
case WSAEFAULT: return "WSAEFAULT";
|
||||
case WSAEINVAL: return "WSAEINVAL";
|
||||
case WSAEMFILE: return "WSAEMFILE";
|
||||
case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
|
||||
case WSAEINPROGRESS: return "WSAEINPROGRESS";
|
||||
case WSAEALREADY: return "WSAEALREADY";
|
||||
case WSAENOTSOCK: return "WSAENOTSOCK";
|
||||
case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
|
||||
case WSAEMSGSIZE: return "WSAEMSGSIZE";
|
||||
case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
|
||||
case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
|
||||
case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
|
||||
case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
|
||||
case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
|
||||
case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
|
||||
case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
|
||||
case WSAEADDRINUSE: return "WSAEADDRINUSE";
|
||||
case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
|
||||
case WSAENETDOWN: return "WSAENETDOWN";
|
||||
case WSAENETUNREACH: return "WSAENETUNREACH";
|
||||
case WSAENETRESET: return "WSAENETRESET";
|
||||
case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
|
||||
case WSAECONNRESET: return "WSAECONNRESET";
|
||||
case WSAENOBUFS: return "WSAENOBUFS";
|
||||
case WSAEISCONN: return "WSAEISCONN";
|
||||
case WSAENOTCONN: return "WSAENOTCONN";
|
||||
case WSAESHUTDOWN: return "WSAESHUTDOWN";
|
||||
case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
|
||||
case WSAETIMEDOUT: return "WSAETIMEDOUT";
|
||||
case WSAECONNREFUSED: return "WSAECONNREFUSED";
|
||||
case WSAELOOP: return "WSAELOOP";
|
||||
case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
|
||||
case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
|
||||
case WSASYSNOTREADY: return "WSASYSNOTREADY";
|
||||
case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
|
||||
case WSANOTINITIALISED: return "WSANOTINITIALISED";
|
||||
case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
|
||||
case WSATRY_AGAIN: return "WSATRY_AGAIN";
|
||||
case WSANO_RECOVERY: return "WSANO_RECOVERY";
|
||||
case WSANO_DATA: return "WSANO_DATA";
|
||||
default: return "NO ERROR";
|
||||
}
|
||||
}
|
||||
BIN
win32/q2.aps
Normal file
BIN
win32/q2.aps
Normal file
Binary file not shown.
BIN
win32/q2.ico
Normal file
BIN
win32/q2.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 766 B |
72
win32/q2.rc
Normal file
72
win32/q2.rc
Normal file
@@ -0,0 +1,72 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON DISCARDABLE "q2.ico"
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
215
win32/q_shwin.c
Normal file
215
win32/q_shwin.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "winquake.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <conio.h>
|
||||
|
||||
//===============================================================================
|
||||
|
||||
int hunkcount;
|
||||
|
||||
|
||||
byte *membase;
|
||||
int hunkmaxsize;
|
||||
int cursize;
|
||||
|
||||
#define VIRTUAL_ALLOC
|
||||
|
||||
void *Hunk_Begin (int maxsize)
|
||||
{
|
||||
// reserve a huge chunk of memory, but don't commit any yet
|
||||
cursize = 0;
|
||||
hunkmaxsize = maxsize;
|
||||
#ifdef VIRTUAL_ALLOC
|
||||
membase = VirtualAlloc (NULL, maxsize, MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
membase = malloc (maxsize);
|
||||
memset (membase, 0, maxsize);
|
||||
#endif
|
||||
if (!membase)
|
||||
Sys_Error ("VirtualAlloc reserve failed");
|
||||
return (void *)membase;
|
||||
}
|
||||
|
||||
void *Hunk_Alloc (int size)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
// round to cacheline
|
||||
size = (size+31)&~31;
|
||||
|
||||
#ifdef VIRTUAL_ALLOC
|
||||
// commit pages as needed
|
||||
// buf = VirtualAlloc (membase+cursize, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
buf = VirtualAlloc (membase, cursize+size, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (!buf)
|
||||
{
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
|
||||
Sys_Error ("VirtualAlloc commit failed.\n%s", buf);
|
||||
}
|
||||
#endif
|
||||
cursize += size;
|
||||
if (cursize > hunkmaxsize)
|
||||
Sys_Error ("Hunk_Alloc overflow");
|
||||
|
||||
return (void *)(membase+cursize-size);
|
||||
}
|
||||
|
||||
int Hunk_End (void)
|
||||
{
|
||||
|
||||
// free the remaining unused virtual memory
|
||||
#if 0
|
||||
void *buf;
|
||||
|
||||
// write protect it
|
||||
buf = VirtualAlloc (membase, cursize, MEM_COMMIT, PAGE_READONLY);
|
||||
if (!buf)
|
||||
Sys_Error ("VirtualAlloc commit failed");
|
||||
#endif
|
||||
|
||||
hunkcount++;
|
||||
//Com_Printf ("hunkcount: %i\n", hunkcount);
|
||||
return cursize;
|
||||
}
|
||||
|
||||
void Hunk_Free (void *base)
|
||||
{
|
||||
if ( base )
|
||||
#ifdef VIRTUAL_ALLOC
|
||||
VirtualFree (base, 0, MEM_RELEASE);
|
||||
#else
|
||||
free (base);
|
||||
#endif
|
||||
|
||||
hunkcount--;
|
||||
}
|
||||
|
||||
//===============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Milliseconds
|
||||
================
|
||||
*/
|
||||
int curtime;
|
||||
int Sys_Milliseconds (void)
|
||||
{
|
||||
static int base;
|
||||
static qboolean initialized = false;
|
||||
|
||||
if (!initialized)
|
||||
{ // let base retain 16 bits of effectively random data
|
||||
base = timeGetTime() & 0xffff0000;
|
||||
initialized = true;
|
||||
}
|
||||
curtime = timeGetTime() - base;
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
void Sys_Mkdir (char *path)
|
||||
{
|
||||
_mkdir (path);
|
||||
}
|
||||
|
||||
//============================================
|
||||
|
||||
char findbase[MAX_OSPATH];
|
||||
char findpath[MAX_OSPATH];
|
||||
int findhandle;
|
||||
|
||||
static qboolean CompareAttributes( unsigned found, unsigned musthave, unsigned canthave )
|
||||
{
|
||||
if ( ( found & _A_RDONLY ) && ( canthave & SFF_RDONLY ) )
|
||||
return false;
|
||||
if ( ( found & _A_HIDDEN ) && ( canthave & SFF_HIDDEN ) )
|
||||
return false;
|
||||
if ( ( found & _A_SYSTEM ) && ( canthave & SFF_SYSTEM ) )
|
||||
return false;
|
||||
if ( ( found & _A_SUBDIR ) && ( canthave & SFF_SUBDIR ) )
|
||||
return false;
|
||||
if ( ( found & _A_ARCH ) && ( canthave & SFF_ARCH ) )
|
||||
return false;
|
||||
|
||||
if ( ( musthave & SFF_RDONLY ) && !( found & _A_RDONLY ) )
|
||||
return false;
|
||||
if ( ( musthave & SFF_HIDDEN ) && !( found & _A_HIDDEN ) )
|
||||
return false;
|
||||
if ( ( musthave & SFF_SYSTEM ) && !( found & _A_SYSTEM ) )
|
||||
return false;
|
||||
if ( ( musthave & SFF_SUBDIR ) && !( found & _A_SUBDIR ) )
|
||||
return false;
|
||||
if ( ( musthave & SFF_ARCH ) && !( found & _A_ARCH ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave )
|
||||
{
|
||||
struct _finddata_t findinfo;
|
||||
|
||||
if (findhandle)
|
||||
Sys_Error ("Sys_BeginFind without close");
|
||||
findhandle = 0;
|
||||
|
||||
COM_FilePath (path, findbase);
|
||||
findhandle = _findfirst (path, &findinfo);
|
||||
if (findhandle == -1)
|
||||
return NULL;
|
||||
if ( !CompareAttributes( findinfo.attrib, musthave, canthave ) )
|
||||
return NULL;
|
||||
Com_sprintf (findpath, sizeof(findpath), "%s/%s", findbase, findinfo.name);
|
||||
return findpath;
|
||||
}
|
||||
|
||||
char *Sys_FindNext ( unsigned musthave, unsigned canthave )
|
||||
{
|
||||
struct _finddata_t findinfo;
|
||||
|
||||
if (findhandle == -1)
|
||||
return NULL;
|
||||
if (_findnext (findhandle, &findinfo) == -1)
|
||||
return NULL;
|
||||
if ( !CompareAttributes( findinfo.attrib, musthave, canthave ) )
|
||||
return NULL;
|
||||
|
||||
Com_sprintf (findpath, sizeof(findpath), "%s/%s", findbase, findinfo.name);
|
||||
return findpath;
|
||||
}
|
||||
|
||||
void Sys_FindClose (void)
|
||||
{
|
||||
if (findhandle != -1)
|
||||
_findclose (findhandle);
|
||||
findhandle = 0;
|
||||
}
|
||||
|
||||
|
||||
//============================================
|
||||
|
||||
BIN
win32/qe3.ico
Normal file
BIN
win32/qe3.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 766 B |
4133
win32/qgl_win.c
Normal file
4133
win32/qgl_win.c
Normal file
File diff suppressed because it is too large
Load Diff
16
win32/resource.h
Normal file
16
win32/resource.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by q2.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
556
win32/rw_ddraw.c
Normal file
556
win32/rw_ddraw.c
Normal file
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
/*
|
||||
** RW_DDRAW.C
|
||||
**
|
||||
** This handles DirecTDraw management under Windows.
|
||||
*/
|
||||
#ifndef _WIN32
|
||||
# error You should not be compiling this file on this platform
|
||||
#endif
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "..\ref_soft\r_local.h"
|
||||
#define INITGUID
|
||||
#include "rw_win.h"
|
||||
|
||||
static const char *DDrawError( int code );
|
||||
|
||||
/*
|
||||
** DDRAW_Init
|
||||
**
|
||||
** Builds our DDRAW stuff
|
||||
*/
|
||||
qboolean DDRAW_Init( unsigned char **ppbuffer, int *ppitch )
|
||||
{
|
||||
HRESULT ddrval;
|
||||
DDSURFACEDESC ddsd;
|
||||
DDSCAPS ddscaps;
|
||||
PALETTEENTRY palentries[256];
|
||||
int i;
|
||||
extern cvar_t *sw_allow_modex;
|
||||
|
||||
HRESULT (WINAPI *QDirectDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR * lplpDDRAW, IUnknown FAR * pUnkOuter );
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "Initializing DirectDraw\n");
|
||||
|
||||
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
palentries[i].peRed = ( d_8to24table[i] >> 0 ) & 0xff;
|
||||
palentries[i].peGreen = ( d_8to24table[i] >> 8 ) & 0xff;
|
||||
palentries[i].peBlue = ( d_8to24table[i] >> 16 ) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
** load DLL and fetch pointer to entry point
|
||||
*/
|
||||
if ( !sww_state.hinstDDRAW )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...loading DDRAW.DLL: ");
|
||||
if ( ( sww_state.hinstDDRAW = LoadLibrary( "ddraw.dll" ) ) == NULL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
}
|
||||
|
||||
if ( ( QDirectDrawCreate = ( HRESULT (WINAPI *)( GUID FAR *, LPDIRECTDRAW FAR *, IUnknown FAR * ) ) GetProcAddress( sww_state.hinstDDRAW, "DirectDrawCreate" ) ) == NULL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "*** DirectDrawCreate == NULL ***\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
** create the direct draw object
|
||||
*/
|
||||
ri.Con_Printf( PRINT_ALL, "...creating DirectDraw object: ");
|
||||
if ( ( ddrval = QDirectDrawCreate( NULL, &sww_state.lpDirectDraw, NULL ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
/*
|
||||
** see if linear modes exist first
|
||||
*/
|
||||
sww_state.modex = false;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...setting exclusive mode: ");
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw,
|
||||
sww_state.hWnd,
|
||||
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n",DDrawError (ddrval) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
/*
|
||||
** try changing the display mode normally
|
||||
*/
|
||||
ri.Con_Printf( PRINT_ALL, "...finding display mode\n" );
|
||||
ri.Con_Printf( PRINT_ALL, "...setting linear mode: " );
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetDisplayMode( sww_state.lpDirectDraw, vid.width, vid.height, 8 ) ) == DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
}
|
||||
/*
|
||||
** if no linear mode found, go for modex if we're trying 320x240
|
||||
*/
|
||||
else if ( ( sw_mode->value == 0 ) && sw_allow_modex->value )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed\n" );
|
||||
ri.Con_Printf( PRINT_ALL, "...attempting ModeX 320x240: ");
|
||||
|
||||
/*
|
||||
** reset to normal cooperative level
|
||||
*/
|
||||
sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw,
|
||||
sww_state.hWnd,
|
||||
DDSCL_NORMAL );
|
||||
|
||||
/*
|
||||
** set exclusive mode
|
||||
*/
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw,
|
||||
sww_state.hWnd,
|
||||
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES | DDSCL_ALLOWMODEX ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed SCL - %s\n",DDrawError (ddrval) );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
** change our display mode
|
||||
*/
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetDisplayMode( sww_state.lpDirectDraw, vid.width, vid.height, 8 ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed SDM - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
sww_state.modex = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
** create our front buffer
|
||||
*/
|
||||
memset( &ddsd, 0, sizeof( ddsd ) );
|
||||
ddsd.dwSize = sizeof( ddsd );
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
|
||||
ddsd.dwBackBufferCount = 1;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...creating front buffer: ");
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreateSurface( sww_state.lpDirectDraw, &ddsd, &sww_state.lpddsFrontBuffer, NULL ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
/*
|
||||
** see if we're a ModeX mode
|
||||
*/
|
||||
sww_state.lpddsFrontBuffer->lpVtbl->GetCaps( sww_state.lpddsFrontBuffer, &ddscaps );
|
||||
if ( ddscaps.dwCaps & DDSCAPS_MODEX )
|
||||
ri.Con_Printf( PRINT_ALL, "...using ModeX\n" );
|
||||
|
||||
/*
|
||||
** create our back buffer
|
||||
*/
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...creating back buffer: " );
|
||||
if ( ( ddrval = sww_state.lpddsFrontBuffer->lpVtbl->GetAttachedSurface( sww_state.lpddsFrontBuffer, &ddsd.ddsCaps, &sww_state.lpddsBackBuffer ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
/*
|
||||
** create our rendering buffer
|
||||
*/
|
||||
memset( &ddsd, 0, sizeof( ddsd ) );
|
||||
ddsd.dwSize = sizeof( ddsd );
|
||||
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
||||
ddsd.dwHeight = vid.height;
|
||||
ddsd.dwWidth = vid.width;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...creating offscreen buffer: " );
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreateSurface( sww_state.lpDirectDraw, &ddsd, &sww_state.lpddsOffScreenBuffer, NULL ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
/*
|
||||
** create our DIRECTDRAWPALETTE
|
||||
*/
|
||||
ri.Con_Printf( PRINT_ALL, "...creating palette: " );
|
||||
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreatePalette( sww_state.lpDirectDraw,
|
||||
DDPCAPS_8BIT | DDPCAPS_ALLOW256,
|
||||
palentries,
|
||||
&sww_state.lpddpPalette,
|
||||
NULL ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...setting palette: " );
|
||||
if ( ( ddrval = sww_state.lpddsFrontBuffer->lpVtbl->SetPalette( sww_state.lpddsFrontBuffer,
|
||||
sww_state.lpddpPalette ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
DDRAW_SetPalette( ( const unsigned char * ) sw_state.currentpalette );
|
||||
|
||||
/*
|
||||
** lock the back buffer
|
||||
*/
|
||||
memset( &ddsd, 0, sizeof( ddsd ) );
|
||||
ddsd.dwSize = sizeof( ddsd );
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, "...locking backbuffer: " );
|
||||
if ( ( ddrval = sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ) ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
|
||||
goto fail;
|
||||
}
|
||||
ri.Con_Printf( PRINT_ALL, "ok\n" );
|
||||
|
||||
*ppbuffer = ddsd.lpSurface;
|
||||
*ppitch = ddsd.lPitch;
|
||||
|
||||
for ( i = 0; i < vid.height; i++ )
|
||||
{
|
||||
memset( *ppbuffer + i * *ppitch, 0, *ppitch );
|
||||
}
|
||||
|
||||
sww_state.palettized = true;
|
||||
|
||||
return true;
|
||||
fail:
|
||||
ri.Con_Printf( PRINT_ALL, "*** DDraw init failure ***\n" );
|
||||
|
||||
DDRAW_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** DDRAW_SetPalette
|
||||
**
|
||||
** Sets the color table in our DIB section, and also sets the system palette
|
||||
** into an identity mode if we're running in an 8-bit palettized display mode.
|
||||
**
|
||||
** The palette is expected to be 1024 bytes, in the format:
|
||||
**
|
||||
** R = offset 0
|
||||
** G = offset 1
|
||||
** B = offset 2
|
||||
** A = offset 3
|
||||
*/
|
||||
void DDRAW_SetPalette( const unsigned char *pal )
|
||||
{
|
||||
PALETTEENTRY palentries[256];
|
||||
int i;
|
||||
|
||||
if (!sww_state.lpddpPalette)
|
||||
return;
|
||||
|
||||
for ( i = 0; i < 256; i++, pal += 4 )
|
||||
{
|
||||
palentries[i].peRed = pal[0];
|
||||
palentries[i].peGreen = pal[1];
|
||||
palentries[i].peBlue = pal[2];
|
||||
palentries[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
|
||||
}
|
||||
|
||||
if ( sww_state.lpddpPalette->lpVtbl->SetEntries( sww_state.lpddpPalette,
|
||||
0,
|
||||
0,
|
||||
256,
|
||||
palentries ) != DD_OK )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "DDRAW_SetPalette() - SetEntries failed\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** DDRAW_Shutdown
|
||||
*/
|
||||
void DDRAW_Shutdown( void )
|
||||
{
|
||||
if ( sww_state.lpddsOffScreenBuffer )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...releasing offscreen buffer\n");
|
||||
sww_state.lpddsOffScreenBuffer->lpVtbl->Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer );
|
||||
sww_state.lpddsOffScreenBuffer->lpVtbl->Release( sww_state.lpddsOffScreenBuffer );
|
||||
sww_state.lpddsOffScreenBuffer = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.lpddsBackBuffer )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...releasing back buffer\n");
|
||||
sww_state.lpddsBackBuffer->lpVtbl->Release( sww_state.lpddsBackBuffer );
|
||||
sww_state.lpddsBackBuffer = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.lpddsFrontBuffer )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...releasing front buffer\n");
|
||||
sww_state.lpddsFrontBuffer->lpVtbl->Release( sww_state.lpddsFrontBuffer );
|
||||
sww_state.lpddsFrontBuffer = NULL;
|
||||
}
|
||||
|
||||
if (sww_state.lpddpPalette)
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...releasing palette\n");
|
||||
sww_state.lpddpPalette->lpVtbl->Release ( sww_state.lpddpPalette );
|
||||
sww_state.lpddpPalette = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.lpDirectDraw )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...restoring display mode\n");
|
||||
sww_state.lpDirectDraw->lpVtbl->RestoreDisplayMode( sww_state.lpDirectDraw );
|
||||
ri.Con_Printf( PRINT_ALL, "...restoring normal coop mode\n");
|
||||
sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw, sww_state.hWnd, DDSCL_NORMAL );
|
||||
ri.Con_Printf( PRINT_ALL, "...releasing lpDirectDraw\n");
|
||||
sww_state.lpDirectDraw->lpVtbl->Release( sww_state.lpDirectDraw );
|
||||
sww_state.lpDirectDraw = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.hinstDDRAW )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "...freeing library\n");
|
||||
FreeLibrary( sww_state.hinstDDRAW );
|
||||
sww_state.hinstDDRAW = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *DDrawError (int code)
|
||||
{
|
||||
switch(code) {
|
||||
case DD_OK:
|
||||
return "DD_OK";
|
||||
case DDERR_ALREADYINITIALIZED:
|
||||
return "DDERR_ALREADYINITIALIZED";
|
||||
case DDERR_BLTFASTCANTCLIP:
|
||||
return "DDERR_BLTFASTCANTCLIP";
|
||||
case DDERR_CANNOTATTACHSURFACE:
|
||||
return "DDER_CANNOTATTACHSURFACE";
|
||||
case DDERR_CANNOTDETACHSURFACE:
|
||||
return "DDERR_CANNOTDETACHSURFACE";
|
||||
case DDERR_CANTCREATEDC:
|
||||
return "DDERR_CANTCREATEDC";
|
||||
case DDERR_CANTDUPLICATE:
|
||||
return "DDER_CANTDUPLICATE";
|
||||
case DDERR_CLIPPERISUSINGHWND:
|
||||
return "DDER_CLIPPERUSINGHWND";
|
||||
case DDERR_COLORKEYNOTSET:
|
||||
return "DDERR_COLORKEYNOTSET";
|
||||
case DDERR_CURRENTLYNOTAVAIL:
|
||||
return "DDERR_CURRENTLYNOTAVAIL";
|
||||
case DDERR_DIRECTDRAWALREADYCREATED:
|
||||
return "DDERR_DIRECTDRAWALREADYCREATED";
|
||||
case DDERR_EXCEPTION:
|
||||
return "DDERR_EXCEPTION";
|
||||
case DDERR_EXCLUSIVEMODEALREADYSET:
|
||||
return "DDERR_EXCLUSIVEMODEALREADYSET";
|
||||
case DDERR_GENERIC:
|
||||
return "DDERR_GENERIC";
|
||||
case DDERR_HEIGHTALIGN:
|
||||
return "DDERR_HEIGHTALIGN";
|
||||
case DDERR_HWNDALREADYSET:
|
||||
return "DDERR_HWNDALREADYSET";
|
||||
case DDERR_HWNDSUBCLASSED:
|
||||
return "DDERR_HWNDSUBCLASSED";
|
||||
case DDERR_IMPLICITLYCREATED:
|
||||
return "DDERR_IMPLICITLYCREATED";
|
||||
case DDERR_INCOMPATIBLEPRIMARY:
|
||||
return "DDERR_INCOMPATIBLEPRIMARY";
|
||||
case DDERR_INVALIDCAPS:
|
||||
return "DDERR_INVALIDCAPS";
|
||||
case DDERR_INVALIDCLIPLIST:
|
||||
return "DDERR_INVALIDCLIPLIST";
|
||||
case DDERR_INVALIDDIRECTDRAWGUID:
|
||||
return "DDERR_INVALIDDIRECTDRAWGUID";
|
||||
case DDERR_INVALIDMODE:
|
||||
return "DDERR_INVALIDMODE";
|
||||
case DDERR_INVALIDOBJECT:
|
||||
return "DDERR_INVALIDOBJECT";
|
||||
case DDERR_INVALIDPARAMS:
|
||||
return "DDERR_INVALIDPARAMS";
|
||||
case DDERR_INVALIDPIXELFORMAT:
|
||||
return "DDERR_INVALIDPIXELFORMAT";
|
||||
case DDERR_INVALIDPOSITION:
|
||||
return "DDERR_INVALIDPOSITION";
|
||||
case DDERR_INVALIDRECT:
|
||||
return "DDERR_INVALIDRECT";
|
||||
case DDERR_LOCKEDSURFACES:
|
||||
return "DDERR_LOCKEDSURFACES";
|
||||
case DDERR_NO3D:
|
||||
return "DDERR_NO3D";
|
||||
case DDERR_NOALPHAHW:
|
||||
return "DDERR_NOALPHAHW";
|
||||
case DDERR_NOBLTHW:
|
||||
return "DDERR_NOBLTHW";
|
||||
case DDERR_NOCLIPLIST:
|
||||
return "DDERR_NOCLIPLIST";
|
||||
case DDERR_NOCLIPPERATTACHED:
|
||||
return "DDERR_NOCLIPPERATTACHED";
|
||||
case DDERR_NOCOLORCONVHW:
|
||||
return "DDERR_NOCOLORCONVHW";
|
||||
case DDERR_NOCOLORKEY:
|
||||
return "DDERR_NOCOLORKEY";
|
||||
case DDERR_NOCOLORKEYHW:
|
||||
return "DDERR_NOCOLORKEYHW";
|
||||
case DDERR_NOCOOPERATIVELEVELSET:
|
||||
return "DDERR_NOCOOPERATIVELEVELSET";
|
||||
case DDERR_NODC:
|
||||
return "DDERR_NODC";
|
||||
case DDERR_NODDROPSHW:
|
||||
return "DDERR_NODDROPSHW";
|
||||
case DDERR_NODIRECTDRAWHW:
|
||||
return "DDERR_NODIRECTDRAWHW";
|
||||
case DDERR_NOEMULATION:
|
||||
return "DDERR_NOEMULATION";
|
||||
case DDERR_NOEXCLUSIVEMODE:
|
||||
return "DDERR_NOEXCLUSIVEMODE";
|
||||
case DDERR_NOFLIPHW:
|
||||
return "DDERR_NOFLIPHW";
|
||||
case DDERR_NOGDI:
|
||||
return "DDERR_NOGDI";
|
||||
case DDERR_NOHWND:
|
||||
return "DDERR_NOHWND";
|
||||
case DDERR_NOMIRRORHW:
|
||||
return "DDERR_NOMIRRORHW";
|
||||
case DDERR_NOOVERLAYDEST:
|
||||
return "DDERR_NOOVERLAYDEST";
|
||||
case DDERR_NOOVERLAYHW:
|
||||
return "DDERR_NOOVERLAYHW";
|
||||
case DDERR_NOPALETTEATTACHED:
|
||||
return "DDERR_NOPALETTEATTACHED";
|
||||
case DDERR_NOPALETTEHW:
|
||||
return "DDERR_NOPALETTEHW";
|
||||
case DDERR_NORASTEROPHW:
|
||||
return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0";
|
||||
case DDERR_NOROTATIONHW:
|
||||
return "Operation could not be carried out because there is no rotation hardware present or available.\0";
|
||||
case DDERR_NOSTRETCHHW:
|
||||
return "Operation could not be carried out because there is no hardware support for stretching.\0";
|
||||
case DDERR_NOT4BITCOLOR:
|
||||
return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0";
|
||||
case DDERR_NOT4BITCOLORINDEX:
|
||||
return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0";
|
||||
case DDERR_NOT8BITCOLOR:
|
||||
return "DDERR_NOT8BITCOLOR";
|
||||
case DDERR_NOTAOVERLAYSURFACE:
|
||||
return "Returned when an overlay member is called for a non-overlay surface.\0";
|
||||
case DDERR_NOTEXTUREHW:
|
||||
return "Operation could not be carried out because there is no texture mapping hardware present or available.\0";
|
||||
case DDERR_NOTFLIPPABLE:
|
||||
return "DDERR_NOTFLIPPABLE";
|
||||
case DDERR_NOTFOUND:
|
||||
return "DDERR_NOTFOUND";
|
||||
case DDERR_NOTLOCKED:
|
||||
return "DDERR_NOTLOCKED";
|
||||
case DDERR_NOTPALETTIZED:
|
||||
return "DDERR_NOTPALETTIZED";
|
||||
case DDERR_NOVSYNCHW:
|
||||
return "DDERR_NOVSYNCHW";
|
||||
case DDERR_NOZBUFFERHW:
|
||||
return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0";
|
||||
case DDERR_NOZOVERLAYHW:
|
||||
return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0";
|
||||
case DDERR_OUTOFCAPS:
|
||||
return "The hardware needed for the requested operation has already been allocated.\0";
|
||||
case DDERR_OUTOFMEMORY:
|
||||
return "DDERR_OUTOFMEMORY";
|
||||
case DDERR_OUTOFVIDEOMEMORY:
|
||||
return "DDERR_OUTOFVIDEOMEMORY";
|
||||
case DDERR_OVERLAYCANTCLIP:
|
||||
return "The hardware does not support clipped overlays.\0";
|
||||
case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
|
||||
return "Can only have ony color key active at one time for overlays.\0";
|
||||
case DDERR_OVERLAYNOTVISIBLE:
|
||||
return "Returned when GetOverlayPosition is called on a hidden overlay.\0";
|
||||
case DDERR_PALETTEBUSY:
|
||||
return "DDERR_PALETTEBUSY";
|
||||
case DDERR_PRIMARYSURFACEALREADYEXISTS:
|
||||
return "DDERR_PRIMARYSURFACEALREADYEXISTS";
|
||||
case DDERR_REGIONTOOSMALL:
|
||||
return "Region passed to Clipper::GetClipList is too small.\0";
|
||||
case DDERR_SURFACEALREADYATTACHED:
|
||||
return "DDERR_SURFACEALREADYATTACHED";
|
||||
case DDERR_SURFACEALREADYDEPENDENT:
|
||||
return "DDERR_SURFACEALREADYDEPENDENT";
|
||||
case DDERR_SURFACEBUSY:
|
||||
return "DDERR_SURFACEBUSY";
|
||||
case DDERR_SURFACEISOBSCURED:
|
||||
return "Access to surface refused because the surface is obscured.\0";
|
||||
case DDERR_SURFACELOST:
|
||||
return "DDERR_SURFACELOST";
|
||||
case DDERR_SURFACENOTATTACHED:
|
||||
return "DDERR_SURFACENOTATTACHED";
|
||||
case DDERR_TOOBIGHEIGHT:
|
||||
return "Height requested by DirectDraw is too large.\0";
|
||||
case DDERR_TOOBIGSIZE:
|
||||
return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0";
|
||||
case DDERR_TOOBIGWIDTH:
|
||||
return "Width requested by DirectDraw is too large.\0";
|
||||
case DDERR_UNSUPPORTED:
|
||||
return "DDERR_UNSUPPORTED";
|
||||
case DDERR_UNSUPPORTEDFORMAT:
|
||||
return "FOURCC format requested is unsupported by DirectDraw.\0";
|
||||
case DDERR_UNSUPPORTEDMASK:
|
||||
return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0";
|
||||
case DDERR_VERTICALBLANKINPROGRESS:
|
||||
return "Vertical blank is in progress.\0";
|
||||
case DDERR_WASSTILLDRAWING:
|
||||
return "DDERR_WASSTILLDRAWING";
|
||||
case DDERR_WRONGMODE:
|
||||
return "This surface can not be restored because it was created in a different mode.\0";
|
||||
case DDERR_XALIGN:
|
||||
return "Rectangle provided was not horizontally aligned on required boundary.\0";
|
||||
default:
|
||||
return "UNKNOWN\0";
|
||||
}
|
||||
}
|
||||
|
||||
375
win32/rw_dib.c
Normal file
375
win32/rw_dib.c
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
/*
|
||||
** RW_DIB.C
|
||||
**
|
||||
** This handles DIB section management under Windows.
|
||||
**
|
||||
*/
|
||||
#include "..\ref_soft\r_local.h"
|
||||
#include "rw_win.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# error You should not be trying to compile this file on this platform
|
||||
#endif
|
||||
|
||||
static qboolean s_systemcolors_saved;
|
||||
|
||||
static HGDIOBJ previously_selected_GDI_obj;
|
||||
|
||||
static int s_syspalindices[] =
|
||||
{
|
||||
COLOR_ACTIVEBORDER,
|
||||
COLOR_ACTIVECAPTION,
|
||||
COLOR_APPWORKSPACE,
|
||||
COLOR_BACKGROUND,
|
||||
COLOR_BTNFACE,
|
||||
COLOR_BTNSHADOW,
|
||||
COLOR_BTNTEXT,
|
||||
COLOR_CAPTIONTEXT,
|
||||
COLOR_GRAYTEXT,
|
||||
COLOR_HIGHLIGHT,
|
||||
COLOR_HIGHLIGHTTEXT,
|
||||
COLOR_INACTIVEBORDER,
|
||||
|
||||
COLOR_INACTIVECAPTION,
|
||||
COLOR_MENU,
|
||||
COLOR_MENUTEXT,
|
||||
COLOR_SCROLLBAR,
|
||||
COLOR_WINDOW,
|
||||
COLOR_WINDOWFRAME,
|
||||
COLOR_WINDOWTEXT
|
||||
};
|
||||
|
||||
#define NUM_SYS_COLORS ( sizeof( s_syspalindices ) / sizeof( int ) )
|
||||
|
||||
static int s_oldsyscolors[NUM_SYS_COLORS];
|
||||
|
||||
typedef struct dibinfo
|
||||
{
|
||||
BITMAPINFOHEADER header;
|
||||
RGBQUAD acolors[256];
|
||||
} dibinfo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD palVersion;
|
||||
WORD palNumEntries;
|
||||
PALETTEENTRY palEntries[256];
|
||||
} identitypalette_t;
|
||||
|
||||
static identitypalette_t s_ipal;
|
||||
|
||||
static void DIB_SaveSystemColors( void );
|
||||
static void DIB_RestoreSystemColors( void );
|
||||
|
||||
/*
|
||||
** DIB_Init
|
||||
**
|
||||
** Builds our DIB section
|
||||
*/
|
||||
qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch )
|
||||
{
|
||||
dibinfo_t dibheader;
|
||||
BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader;
|
||||
int i;
|
||||
|
||||
memset( &dibheader, 0, sizeof( dibheader ) );
|
||||
|
||||
/*
|
||||
** grab a DC
|
||||
*/
|
||||
if ( !sww_state.hDC )
|
||||
{
|
||||
if ( ( sww_state.hDC = GetDC( sww_state.hWnd ) ) == NULL )
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** figure out if we're running in an 8-bit display mode
|
||||
*/
|
||||
if ( GetDeviceCaps( sww_state.hDC, RASTERCAPS ) & RC_PALETTE )
|
||||
{
|
||||
sww_state.palettized = true;
|
||||
|
||||
// save system colors
|
||||
if ( !s_systemcolors_saved )
|
||||
{
|
||||
DIB_SaveSystemColors();
|
||||
s_systemcolors_saved = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sww_state.palettized = false;
|
||||
}
|
||||
|
||||
/*
|
||||
** fill in the BITMAPINFO struct
|
||||
*/
|
||||
pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
pbmiDIB->bmiHeader.biWidth = vid.width;
|
||||
pbmiDIB->bmiHeader.biHeight = vid.height;
|
||||
pbmiDIB->bmiHeader.biPlanes = 1;
|
||||
pbmiDIB->bmiHeader.biBitCount = 8;
|
||||
pbmiDIB->bmiHeader.biCompression = BI_RGB;
|
||||
pbmiDIB->bmiHeader.biSizeImage = 0;
|
||||
pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
|
||||
pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
|
||||
pbmiDIB->bmiHeader.biClrUsed = 256;
|
||||
pbmiDIB->bmiHeader.biClrImportant = 256;
|
||||
|
||||
/*
|
||||
** fill in the palette
|
||||
*/
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{
|
||||
dibheader.acolors[i].rgbRed = ( d_8to24table[i] >> 0 ) & 0xff;
|
||||
dibheader.acolors[i].rgbGreen = ( d_8to24table[i] >> 8 ) & 0xff;
|
||||
dibheader.acolors[i].rgbBlue = ( d_8to24table[i] >> 16 ) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
** create the DIB section
|
||||
*/
|
||||
sww_state.hDIBSection = CreateDIBSection( sww_state.hDC,
|
||||
pbmiDIB,
|
||||
DIB_RGB_COLORS,
|
||||
&sww_state.pDIBBase,
|
||||
NULL,
|
||||
0 );
|
||||
|
||||
if ( sww_state.hDIBSection == NULL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateDIBSection failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ( pbmiDIB->bmiHeader.biHeight > 0 )
|
||||
{
|
||||
// bottom up
|
||||
*ppbuffer = sww_state.pDIBBase + ( vid.height - 1 ) * vid.width;
|
||||
*ppitch = -vid.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
// top down
|
||||
*ppbuffer = sww_state.pDIBBase;
|
||||
*ppitch = vid.width;
|
||||
}
|
||||
|
||||
/*
|
||||
** clear the DIB memory buffer
|
||||
*/
|
||||
memset( sww_state.pDIBBase, 0xff, vid.width * vid.height );
|
||||
|
||||
if ( ( sww_state.hdcDIBSection = CreateCompatibleDC( sww_state.hDC ) ) == NULL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateCompatibleDC failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
if ( ( previously_selected_GDI_obj = SelectObject( sww_state.hdcDIBSection, sww_state.hDIBSection ) ) == NULL )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "DIB_Init() - SelectObject failed\n" );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
DIB_Shutdown();
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** DIB_SetPalette
|
||||
**
|
||||
** Sets the color table in our DIB section, and also sets the system palette
|
||||
** into an identity mode if we're running in an 8-bit palettized display mode.
|
||||
**
|
||||
** The palette is expected to be 1024 bytes, in the format:
|
||||
**
|
||||
** R = offset 0
|
||||
** G = offset 1
|
||||
** B = offset 2
|
||||
** A = offset 3
|
||||
*/
|
||||
void DIB_SetPalette( const unsigned char *_pal )
|
||||
{
|
||||
const unsigned char *pal = _pal;
|
||||
LOGPALETTE *pLogPal = ( LOGPALETTE * ) &s_ipal;
|
||||
RGBQUAD colors[256];
|
||||
int i;
|
||||
int ret;
|
||||
HDC hDC = sww_state.hDC;
|
||||
|
||||
/*
|
||||
** set the DIB color table
|
||||
*/
|
||||
if ( sww_state.hdcDIBSection )
|
||||
{
|
||||
for ( i = 0; i < 256; i++, pal += 4 )
|
||||
{
|
||||
colors[i].rgbRed = pal[0];
|
||||
colors[i].rgbGreen = pal[1];
|
||||
colors[i].rgbBlue = pal[2];
|
||||
colors[i].rgbReserved = 0;
|
||||
}
|
||||
|
||||
colors[0].rgbRed = 0;
|
||||
colors[0].rgbGreen = 0;
|
||||
colors[0].rgbBlue = 0;
|
||||
|
||||
colors[255].rgbRed = 0xff;
|
||||
colors[255].rgbGreen = 0xff;
|
||||
colors[255].rgbBlue = 0xff;
|
||||
|
||||
if ( SetDIBColorTable( sww_state.hdcDIBSection, 0, 256, colors ) == 0 )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "DIB_SetPalette() - SetDIBColorTable failed\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** for 8-bit color desktop modes we set up the palette for maximum
|
||||
** speed by going into an identity palette mode.
|
||||
*/
|
||||
if ( sww_state.palettized )
|
||||
{
|
||||
int i;
|
||||
HPALETTE hpalOld;
|
||||
|
||||
if ( SetSystemPaletteUse( hDC, SYSPAL_NOSTATIC ) == SYSPAL_ERROR )
|
||||
{
|
||||
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SetSystemPaletteUse() failed\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
** destroy our old palette
|
||||
*/
|
||||
if ( sww_state.hPal )
|
||||
{
|
||||
DeleteObject( sww_state.hPal );
|
||||
sww_state.hPal = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** take up all physical palette entries to flush out anything that's currently
|
||||
** in the palette
|
||||
*/
|
||||
pLogPal->palVersion = 0x300;
|
||||
pLogPal->palNumEntries = 256;
|
||||
|
||||
for ( i = 0, pal = _pal; i < 256; i++, pal += 4 )
|
||||
{
|
||||
pLogPal->palPalEntry[i].peRed = pal[0];
|
||||
pLogPal->palPalEntry[i].peGreen = pal[1];
|
||||
pLogPal->palPalEntry[i].peBlue = pal[2];
|
||||
pLogPal->palPalEntry[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
|
||||
}
|
||||
pLogPal->palPalEntry[0].peRed = 0;
|
||||
pLogPal->palPalEntry[0].peGreen = 0;
|
||||
pLogPal->palPalEntry[0].peBlue = 0;
|
||||
pLogPal->palPalEntry[0].peFlags = 0;
|
||||
pLogPal->palPalEntry[255].peRed = 0xff;
|
||||
pLogPal->palPalEntry[255].peGreen = 0xff;
|
||||
pLogPal->palPalEntry[255].peBlue = 0xff;
|
||||
pLogPal->palPalEntry[255].peFlags = 0;
|
||||
|
||||
if ( ( sww_state.hPal = CreatePalette( pLogPal ) ) == NULL )
|
||||
{
|
||||
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - CreatePalette failed(%x)\n", GetLastError() );
|
||||
}
|
||||
|
||||
if ( ( hpalOld = SelectPalette( hDC, sww_state.hPal, FALSE ) ) == NULL )
|
||||
{
|
||||
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SelectPalette failed(%x)\n",GetLastError() );
|
||||
}
|
||||
|
||||
if ( sww_state.hpalOld == NULL )
|
||||
sww_state.hpalOld = hpalOld;
|
||||
|
||||
if ( ( ret = RealizePalette( hDC ) ) != pLogPal->palNumEntries )
|
||||
{
|
||||
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - RealizePalette set %d entries\n", ret );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** DIB_Shutdown
|
||||
*/
|
||||
void DIB_Shutdown( void )
|
||||
{
|
||||
if ( sww_state.palettized && s_systemcolors_saved )
|
||||
DIB_RestoreSystemColors();
|
||||
|
||||
if ( sww_state.hPal )
|
||||
{
|
||||
DeleteObject( sww_state.hPal );
|
||||
sww_state.hPal = 0;
|
||||
}
|
||||
|
||||
if ( sww_state.hpalOld )
|
||||
{
|
||||
SelectPalette( sww_state.hDC, sww_state.hpalOld, FALSE );
|
||||
RealizePalette( sww_state.hDC );
|
||||
sww_state.hpalOld = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.hdcDIBSection )
|
||||
{
|
||||
SelectObject( sww_state.hdcDIBSection, previously_selected_GDI_obj );
|
||||
DeleteDC( sww_state.hdcDIBSection );
|
||||
sww_state.hdcDIBSection = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.hDIBSection )
|
||||
{
|
||||
DeleteObject( sww_state.hDIBSection );
|
||||
sww_state.hDIBSection = NULL;
|
||||
sww_state.pDIBBase = NULL;
|
||||
}
|
||||
|
||||
if ( sww_state.hDC )
|
||||
{
|
||||
ReleaseDC( sww_state.hWnd, sww_state.hDC );
|
||||
sww_state.hDC = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** DIB_Save/RestoreSystemColors
|
||||
*/
|
||||
static void DIB_RestoreSystemColors( void )
|
||||
{
|
||||
SetSystemPaletteUse( sww_state.hDC, SYSPAL_STATIC );
|
||||
SetSysColors( NUM_SYS_COLORS, s_syspalindices, s_oldsyscolors );
|
||||
}
|
||||
|
||||
static void DIB_SaveSystemColors( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < NUM_SYS_COLORS; i++ )
|
||||
s_oldsyscolors[i] = GetSysColor( s_syspalindices[i] );
|
||||
}
|
||||
471
win32/rw_imp.c
Normal file
471
win32/rw_imp.c
Normal file
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
/*
|
||||
** 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
|
||||
*/
|
||||
#include "..\ref_soft\r_local.h"
|
||||
#include "rw_win.h"
|
||||
#include "winquake.h"
|
||||
|
||||
// Console variables that we need to access from this module
|
||||
|
||||
swwstate_t sww_state;
|
||||
|
||||
/*
|
||||
** VID_CreateWindow
|
||||
*/
|
||||
#define WINDOW_CLASS_NAME "Quake 2"
|
||||
|
||||
void VID_CreateWindow( int width, int height, int stylebits )
|
||||
{
|
||||
WNDCLASS wc;
|
||||
RECT r;
|
||||
cvar_t *vid_xpos, *vid_ypos, *vid_fullscreen;
|
||||
int x, y, w, h;
|
||||
int exstyle;
|
||||
|
||||
vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
|
||||
vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
|
||||
vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE );
|
||||
|
||||
if ( vid_fullscreen->value )
|
||||
exstyle = WS_EX_TOPMOST;
|
||||
else
|
||||
exstyle = 0;
|
||||
|
||||
/* Register the frame class */
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = (WNDPROC)sww_state.wndproc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = sww_state.hInstance;
|
||||
wc.hIcon = 0;
|
||||
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
|
||||
wc.hbrBackground = (void *)COLOR_GRAYTEXT;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.lpszClassName = WINDOW_CLASS_NAME;
|
||||
|
||||
if (!RegisterClass (&wc) )
|
||||
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,
|
||||
"Quake 2",
|
||||
stylebits,
|
||||
x, y, w, h,
|
||||
NULL,
|
||||
NULL,
|
||||
sww_state.hInstance,
|
||||
NULL);
|
||||
|
||||
if (!sww_state.hWnd)
|
||||
ri.Sys_Error (ERR_FATAL, "Couldn't create 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);
|
||||
}
|
||||
|
||||
/*
|
||||
** SWimp_Init
|
||||
**
|
||||
** This routine is responsible for initializing the implementation
|
||||
** specific stuff in a software rendering subsystem.
|
||||
*/
|
||||
int SWimp_Init( void *hInstance, void *wndProc )
|
||||
{
|
||||
sww_state.hInstance = ( HINSTANCE ) hInstance;
|
||||
sww_state.wndproc = wndProc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
static qboolean SWimp_InitGraphics( qboolean fullscreen )
|
||||
{
|
||||
// free resources in use
|
||||
SWimp_Shutdown ();
|
||||
|
||||
// create a new window
|
||||
VID_CreateWindow (vid.width, vid.height, WINDOW_STYLE);
|
||||
|
||||
// initialize the appropriate subsystem
|
||||
if ( !fullscreen )
|
||||
{
|
||||
if ( !DIB_Init( &vid.buffer, &vid.rowbytes ) )
|
||||
{
|
||||
vid.buffer = 0;
|
||||
vid.rowbytes = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !DDRAW_Init( &vid.buffer, &vid.rowbytes ) )
|
||||
{
|
||||
vid.buffer = 0;
|
||||
vid.rowbytes = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
void SWimp_EndFrame (void)
|
||||
{
|
||||
if ( !sw_state.fullscreen )
|
||||
{
|
||||
if ( sww_state.palettized )
|
||||
{
|
||||
// holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE);
|
||||
// RealizePalette(hdcScreen);
|
||||
}
|
||||
|
||||
|
||||
BitBlt( sww_state.hDC,
|
||||
0, 0,
|
||||
vid.width,
|
||||
vid.height,
|
||||
sww_state.hdcDIBSection,
|
||||
0, 0,
|
||||
SRCCOPY );
|
||||
|
||||
if ( sww_state.palettized )
|
||||
{
|
||||
// SelectPalette(hdcScreen, holdpal, FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RECT r;
|
||||
HRESULT rval;
|
||||
DDSURFACEDESC ddsd;
|
||||
|
||||
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 )
|
||||
{
|
||||
if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer,
|
||||
0, 0,
|
||||
sww_state.lpddsOffScreenBuffer,
|
||||
&r,
|
||||
DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
|
||||
{
|
||||
sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsBackBuffer );
|
||||
sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer,
|
||||
0, 0,
|
||||
sww_state.lpddsOffScreenBuffer,
|
||||
&r,
|
||||
DDBLTFAST_WAIT );
|
||||
}
|
||||
|
||||
if ( ( rval = sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer,
|
||||
NULL, DDFLIP_WAIT ) ) == DDERR_SURFACELOST )
|
||||
{
|
||||
sww_state.lpddsFrontBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer );
|
||||
sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer, NULL, DDFLIP_WAIT );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer,
|
||||
0, 0,
|
||||
sww_state.lpddsOffScreenBuffer,
|
||||
&r,
|
||||
DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
|
||||
{
|
||||
sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer );
|
||||
sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer,
|
||||
0, 0,
|
||||
sww_state.lpddsOffScreenBuffer,
|
||||
&r,
|
||||
DDBLTFAST_WAIT );
|
||||
}
|
||||
}
|
||||
|
||||
memset( &ddsd, 0, sizeof( ddsd ) );
|
||||
ddsd.dwSize = sizeof( ddsd );
|
||||
|
||||
sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL );
|
||||
|
||||
vid.buffer = ddsd.lpSurface;
|
||||
vid.rowbytes = ddsd.lPitch;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** SWimp_SetMode
|
||||
*/
|
||||
rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
|
||||
{
|
||||
const char *win_fs[] = { "W", "FS" };
|
||||
rserr_t retval = rserr_ok;
|
||||
|
||||
ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
|
||||
|
||||
if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
|
||||
return rserr_invalid_mode;
|
||||
}
|
||||
|
||||
ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] );
|
||||
|
||||
sww_state.initializing = true;
|
||||
if ( fullscreen )
|
||||
{
|
||||
if ( !SWimp_InitGraphics( 1 ) )
|
||||
{
|
||||
if ( SWimp_InitGraphics( 0 ) )
|
||||
{
|
||||
// mode is legal but not as fullscreen
|
||||
fullscreen = 0;
|
||||
retval = rserr_invalid_fullscreen;
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to set a valid mode in windowed mode
|
||||
retval = rserr_unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// failure to set a valid mode in windowed mode
|
||||
if ( !SWimp_InitGraphics( fullscreen ) )
|
||||
{
|
||||
sww_state.initializing = true;
|
||||
return rserr_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
sw_state.fullscreen = fullscreen;
|
||||
#if 0
|
||||
if ( retval != rserr_unknown )
|
||||
{
|
||||
if ( retval == rserr_invalid_fullscreen ||
|
||||
( retval == rserr_ok && !fullscreen ) )
|
||||
{
|
||||
SetWindowLong( sww_state.hWnd, GWL_STYLE, WINDOW_STYLE );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
|
||||
sww_state.initializing = true;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
*/
|
||||
void SWimp_SetPalette( const unsigned char *palette )
|
||||
{
|
||||
// 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 ( !palette )
|
||||
palette = ( const unsigned char * ) sw_state.currentpalette;
|
||||
|
||||
if ( !sw_state.fullscreen )
|
||||
{
|
||||
DIB_SetPalette( ( const unsigned char * ) palette );
|
||||
}
|
||||
else
|
||||
{
|
||||
DDRAW_SetPalette( ( const unsigned char * ) palette );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** SWimp_Shutdown
|
||||
**
|
||||
** System specific graphics subsystem shutdown routine. Destroys
|
||||
** DIBs or DDRAW surfaces as appropriate.
|
||||
*/
|
||||
void SWimp_Shutdown( void )
|
||||
{
|
||||
ri.Con_Printf( PRINT_ALL, "Shutting down SW imp\n" );
|
||||
DIB_Shutdown();
|
||||
DDRAW_Shutdown();
|
||||
|
||||
if ( sww_state.hWnd )
|
||||
{
|
||||
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 = NULL;
|
||||
UnregisterClass (WINDOW_CLASS_NAME, sww_state.hInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** SWimp_AppActivate
|
||||
*/
|
||||
void SWimp_AppActivate( qboolean active )
|
||||
{
|
||||
if ( active )
|
||||
{
|
||||
if ( sww_state.hWnd )
|
||||
{
|
||||
SetForegroundWindow( sww_state.hWnd );
|
||||
ShowWindow( sww_state.hWnd, SW_RESTORE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( sww_state.hWnd )
|
||||
{
|
||||
if ( sww_state.initializing )
|
||||
return;
|
||||
if ( vid_fullscreen->value )
|
||||
ShowWindow( sww_state.hWnd, SW_MINIMIZE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_MakeCodeWriteable
|
||||
================
|
||||
*/
|
||||
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
|
||||
{
|
||||
DWORD flOldProtect;
|
||||
|
||||
if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
|
||||
ri.Sys_Error(ERR_FATAL, "Protection change failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
** 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)
|
||||
**
|
||||
*/
|
||||
#if !id386
|
||||
void Sys_SetFPCW (void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
unsigned fpu_ceil_cw, fpu_chop_cw, fpu_full_cw, fpu_cw, fpu_pushed_cw;
|
||||
unsigned fpu_sp24_cw, fpu_sp24_ceil_cw;
|
||||
|
||||
void Sys_SetFPCW( void )
|
||||
{
|
||||
__asm xor eax, eax
|
||||
|
||||
__asm fnstcw word ptr fpu_cw
|
||||
__asm mov ax, word ptr fpu_cw
|
||||
|
||||
__asm and ah, 0f0h
|
||||
__asm or ah, 003h ; round to nearest mode, extended precision
|
||||
__asm mov fpu_full_cw, eax
|
||||
|
||||
__asm and ah, 0f0h
|
||||
__asm or ah, 00fh ; RTZ/truncate/chop mode, extended precision
|
||||
__asm mov fpu_chop_cw, eax
|
||||
|
||||
__asm and ah, 0f0h
|
||||
__asm or ah, 00bh ; ceil mode, extended precision
|
||||
__asm mov fpu_ceil_cw, eax
|
||||
|
||||
__asm and ah, 0f0h ; round to nearest, 24-bit single precision
|
||||
__asm mov fpu_sp24_cw, eax
|
||||
|
||||
__asm and ah, 0f0h ; ceil mode, 24-bit single precision
|
||||
__asm or ah, 008h ;
|
||||
__asm mov fpu_sp24_ceil_cw, eax
|
||||
}
|
||||
#endif
|
||||
|
||||
68
win32/rw_win.h
Normal file
68
win32/rw_win.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#ifndef __RW_WIN_H__
|
||||
#define __RW_WIN_H__
|
||||
|
||||
#include <windows.h>
|
||||
#include <ddraw.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HINSTANCE hInstance;
|
||||
void *wndproc;
|
||||
HDC hDC; // global DC we're using
|
||||
HWND hWnd; // HWND of parent window
|
||||
|
||||
HDC hdcDIBSection; // DC compatible with DIB section
|
||||
HBITMAP hDIBSection; // DIB section
|
||||
unsigned char *pDIBBase; // DIB base pointer, NOT used directly for rendering!
|
||||
|
||||
HPALETTE hPal; // palette we're using
|
||||
HPALETTE hpalOld; // original system palette
|
||||
COLORREF oldsyscolors[20]; // original system colors
|
||||
|
||||
HINSTANCE hinstDDRAW; // library instance for DDRAW.DLL
|
||||
LPDIRECTDRAW lpDirectDraw; // pointer to DirectDraw object
|
||||
|
||||
LPDIRECTDRAWSURFACE lpddsFrontBuffer; // video card display memory front buffer
|
||||
LPDIRECTDRAWSURFACE lpddsBackBuffer; // system memory backbuffer
|
||||
LPDIRECTDRAWSURFACE lpddsOffScreenBuffer; // system memory backbuffer
|
||||
LPDIRECTDRAWPALETTE lpddpPalette; // DirectDraw palette
|
||||
|
||||
qboolean palettized; // true if desktop is paletted
|
||||
qboolean modex;
|
||||
|
||||
qboolean initializing;
|
||||
} swwstate_t;
|
||||
|
||||
extern swwstate_t sww_state;
|
||||
|
||||
/*
|
||||
** DIB code
|
||||
*/
|
||||
qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch );
|
||||
void DIB_Shutdown( void );
|
||||
void DIB_SetPalette( const unsigned char *palette );
|
||||
|
||||
qboolean DDRAW_Init( unsigned char **ppbuffer, int *ppitch );
|
||||
void DDRAW_Shutdown( void );
|
||||
void DDRAW_SetPalette( const unsigned char *palette );
|
||||
|
||||
#endif
|
||||
861
win32/snd_win.c
Normal file
861
win32/snd_win.c
Normal file
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include <float.h>
|
||||
|
||||
#include "../client/client.h"
|
||||
#include "../client/snd_loc.h"
|
||||
#include "winquake.h"
|
||||
|
||||
#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c)
|
||||
|
||||
HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
|
||||
|
||||
// 64K is > 1 second at 16-bit, 22050 Hz
|
||||
#define WAV_BUFFERS 64
|
||||
#define WAV_MASK 0x3F
|
||||
#define WAV_BUFFER_SIZE 0x0400
|
||||
#define SECONDARY_BUFFER_SIZE 0x10000
|
||||
|
||||
typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
|
||||
|
||||
cvar_t *s_wavonly;
|
||||
|
||||
static qboolean dsound_init;
|
||||
static qboolean wav_init;
|
||||
static qboolean snd_firsttime = true, snd_isdirect, snd_iswave;
|
||||
static qboolean primary_format_set;
|
||||
|
||||
// starts at 0 for disabled
|
||||
static int snd_buffer_count = 0;
|
||||
static int sample16;
|
||||
static int snd_sent, snd_completed;
|
||||
|
||||
/*
|
||||
* Global variables. Must be visible to window-procedure function
|
||||
* so it can unlock and free the data block after it has been played.
|
||||
*/
|
||||
|
||||
|
||||
HANDLE hData;
|
||||
HPSTR lpData, lpData2;
|
||||
|
||||
HGLOBAL hWaveHdr;
|
||||
LPWAVEHDR lpWaveHdr;
|
||||
|
||||
HWAVEOUT hWaveOut;
|
||||
|
||||
WAVEOUTCAPS wavecaps;
|
||||
|
||||
DWORD gSndBufSize;
|
||||
|
||||
MMTIME mmstarttime;
|
||||
|
||||
LPDIRECTSOUND pDS;
|
||||
LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
|
||||
|
||||
HINSTANCE hInstDS;
|
||||
|
||||
qboolean SNDDMA_InitDirect (void);
|
||||
qboolean SNDDMA_InitWav (void);
|
||||
|
||||
void FreeSound( void );
|
||||
|
||||
static const char *DSoundError( int error )
|
||||
{
|
||||
switch ( error )
|
||||
{
|
||||
case DSERR_BUFFERLOST:
|
||||
return "DSERR_BUFFERLOST";
|
||||
case DSERR_INVALIDCALL:
|
||||
return "DSERR_INVALIDCALLS";
|
||||
case DSERR_INVALIDPARAM:
|
||||
return "DSERR_INVALIDPARAM";
|
||||
case DSERR_PRIOLEVELNEEDED:
|
||||
return "DSERR_PRIOLEVELNEEDED";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/*
|
||||
** DS_CreateBuffers
|
||||
*/
|
||||
static qboolean DS_CreateBuffers( void )
|
||||
{
|
||||
DSBUFFERDESC dsbuf;
|
||||
DSBCAPS dsbcaps;
|
||||
WAVEFORMATEX pformat, format;
|
||||
DWORD dwWrite;
|
||||
|
||||
memset (&format, 0, sizeof(format));
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
format.nChannels = dma.channels;
|
||||
format.wBitsPerSample = dma.samplebits;
|
||||
format.nSamplesPerSec = dma.speed;
|
||||
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
|
||||
format.cbSize = 0;
|
||||
format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign;
|
||||
|
||||
Com_Printf( "Creating DS buffers\n" );
|
||||
|
||||
Com_DPrintf("...setting EXCLUSIVE coop level: " );
|
||||
if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_EXCLUSIVE ) )
|
||||
{
|
||||
Com_Printf ("failed\n");
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
Com_DPrintf("ok\n" );
|
||||
|
||||
// get access to the primary buffer, if possible, so we can set the
|
||||
// sound hardware format
|
||||
memset (&dsbuf, 0, sizeof(dsbuf));
|
||||
dsbuf.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||||
dsbuf.dwBufferBytes = 0;
|
||||
dsbuf.lpwfxFormat = NULL;
|
||||
|
||||
memset(&dsbcaps, 0, sizeof(dsbcaps));
|
||||
dsbcaps.dwSize = sizeof(dsbcaps);
|
||||
primary_format_set = false;
|
||||
|
||||
Com_DPrintf( "...creating primary buffer: " );
|
||||
if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
|
||||
{
|
||||
pformat = format;
|
||||
|
||||
Com_DPrintf( "ok\n" );
|
||||
if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
|
||||
{
|
||||
if (snd_firsttime)
|
||||
Com_DPrintf ("...setting primary sound format: failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (snd_firsttime)
|
||||
Com_DPrintf ("...setting primary sound format: ok\n");
|
||||
|
||||
primary_format_set = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
Com_Printf( "failed\n" );
|
||||
|
||||
if ( !primary_format_set || !s_primary->value)
|
||||
{
|
||||
// create the secondary buffer we'll actually work with
|
||||
memset (&dsbuf, 0, sizeof(dsbuf));
|
||||
dsbuf.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
|
||||
dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
|
||||
dsbuf.lpwfxFormat = &format;
|
||||
|
||||
memset(&dsbcaps, 0, sizeof(dsbcaps));
|
||||
dsbcaps.dwSize = sizeof(dsbcaps);
|
||||
|
||||
Com_DPrintf( "...creating secondary buffer: " );
|
||||
if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
|
||||
{
|
||||
Com_Printf( "failed\n" );
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
dma.channels = format.nChannels;
|
||||
dma.samplebits = format.wBitsPerSample;
|
||||
dma.speed = format.nSamplesPerSec;
|
||||
|
||||
if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
|
||||
{
|
||||
Com_Printf ("*** GetCaps failed ***\n");
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
|
||||
Com_Printf ("...using secondary sound buffer\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_Printf( "...using primary buffer\n" );
|
||||
|
||||
Com_DPrintf( "...setting WRITEPRIMARY coop level: " );
|
||||
if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, cl_hwnd, DSSCL_WRITEPRIMARY))
|
||||
{
|
||||
Com_Printf( "failed\n" );
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
|
||||
{
|
||||
Com_Printf ("*** GetCaps failed ***\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pDSBuf = pDSPBuf;
|
||||
}
|
||||
|
||||
// Make sure mixer is active
|
||||
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
if (snd_firsttime)
|
||||
Com_Printf(" %d channel(s)\n"
|
||||
" %d bits/sample\n"
|
||||
" %d bytes/sec\n",
|
||||
dma.channels, dma.samplebits, dma.speed);
|
||||
|
||||
gSndBufSize = dsbcaps.dwBufferBytes;
|
||||
|
||||
/* we don't want anyone to access the buffer directly w/o locking it first. */
|
||||
lpData = NULL;
|
||||
|
||||
pDSBuf->lpVtbl->Stop(pDSBuf);
|
||||
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
|
||||
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
dma.samples = gSndBufSize/(dma.samplebits/8);
|
||||
dma.samplepos = 0;
|
||||
dma.submission_chunk = 1;
|
||||
dma.buffer = (unsigned char *) lpData;
|
||||
sample16 = (dma.samplebits/8) - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** DS_DestroyBuffers
|
||||
*/
|
||||
static void DS_DestroyBuffers( void )
|
||||
{
|
||||
Com_DPrintf( "Destroying DS buffers\n" );
|
||||
if ( pDS )
|
||||
{
|
||||
Com_DPrintf( "...setting NORMAL coop level\n" );
|
||||
pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_NORMAL );
|
||||
}
|
||||
|
||||
if ( pDSBuf )
|
||||
{
|
||||
Com_DPrintf( "...stopping and releasing sound buffer\n" );
|
||||
pDSBuf->lpVtbl->Stop( pDSBuf );
|
||||
pDSBuf->lpVtbl->Release( pDSBuf );
|
||||
}
|
||||
|
||||
// only release primary buffer if it's not also the mixing buffer we just released
|
||||
if ( pDSPBuf && ( pDSBuf != pDSPBuf ) )
|
||||
{
|
||||
Com_DPrintf( "...releasing primary buffer\n" );
|
||||
pDSPBuf->lpVtbl->Release( pDSPBuf );
|
||||
}
|
||||
pDSBuf = NULL;
|
||||
pDSPBuf = NULL;
|
||||
|
||||
dma.buffer = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
FreeSound
|
||||
==================
|
||||
*/
|
||||
void FreeSound (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
Com_DPrintf( "Shutting down sound system\n" );
|
||||
|
||||
if ( pDS )
|
||||
DS_DestroyBuffers();
|
||||
|
||||
if ( hWaveOut )
|
||||
{
|
||||
Com_DPrintf( "...resetting waveOut\n" );
|
||||
waveOutReset (hWaveOut);
|
||||
|
||||
if (lpWaveHdr)
|
||||
{
|
||||
Com_DPrintf( "...unpreparing headers\n" );
|
||||
for (i=0 ; i< WAV_BUFFERS ; i++)
|
||||
waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
|
||||
}
|
||||
|
||||
Com_DPrintf( "...closing waveOut\n" );
|
||||
waveOutClose (hWaveOut);
|
||||
|
||||
if (hWaveHdr)
|
||||
{
|
||||
Com_DPrintf( "...freeing WAV header\n" );
|
||||
GlobalUnlock(hWaveHdr);
|
||||
GlobalFree(hWaveHdr);
|
||||
}
|
||||
|
||||
if (hData)
|
||||
{
|
||||
Com_DPrintf( "...freeing WAV buffer\n" );
|
||||
GlobalUnlock(hData);
|
||||
GlobalFree(hData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( pDS )
|
||||
{
|
||||
Com_DPrintf( "...releasing DS object\n" );
|
||||
pDS->lpVtbl->Release( pDS );
|
||||
}
|
||||
|
||||
if ( hInstDS )
|
||||
{
|
||||
Com_DPrintf( "...freeing DSOUND.DLL\n" );
|
||||
FreeLibrary( hInstDS );
|
||||
hInstDS = NULL;
|
||||
}
|
||||
|
||||
pDS = NULL;
|
||||
pDSBuf = NULL;
|
||||
pDSPBuf = NULL;
|
||||
hWaveOut = 0;
|
||||
hData = 0;
|
||||
hWaveHdr = 0;
|
||||
lpData = NULL;
|
||||
lpWaveHdr = NULL;
|
||||
dsound_init = false;
|
||||
wav_init = false;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SNDDMA_InitDirect
|
||||
|
||||
Direct-Sound support
|
||||
==================
|
||||
*/
|
||||
sndinitstat SNDDMA_InitDirect (void)
|
||||
{
|
||||
DSCAPS dscaps;
|
||||
HRESULT hresult;
|
||||
|
||||
dma.channels = 2;
|
||||
dma.samplebits = 16;
|
||||
|
||||
if (s_khz->value == 44)
|
||||
dma.speed = 44100;
|
||||
if (s_khz->value == 22)
|
||||
dma.speed = 22050;
|
||||
else
|
||||
dma.speed = 11025;
|
||||
|
||||
Com_Printf( "Initializing DirectSound\n");
|
||||
|
||||
if ( !hInstDS )
|
||||
{
|
||||
Com_DPrintf( "...loading dsound.dll: " );
|
||||
|
||||
hInstDS = LoadLibrary("dsound.dll");
|
||||
|
||||
if (hInstDS == NULL)
|
||||
{
|
||||
Com_Printf ("failed\n");
|
||||
return SIS_FAILURE;
|
||||
}
|
||||
|
||||
Com_DPrintf ("ok\n");
|
||||
pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
|
||||
|
||||
if (!pDirectSoundCreate)
|
||||
{
|
||||
Com_Printf ("*** couldn't get DS proc addr ***\n");
|
||||
return SIS_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
Com_DPrintf( "...creating DS object: " );
|
||||
while ( ( hresult = iDirectSoundCreate( NULL, &pDS, NULL ) ) != DS_OK )
|
||||
{
|
||||
if (hresult != DSERR_ALLOCATED)
|
||||
{
|
||||
Com_Printf( "failed\n" );
|
||||
return SIS_FAILURE;
|
||||
}
|
||||
|
||||
if (MessageBox (NULL,
|
||||
"The sound hardware is in use by another app.\n\n"
|
||||
"Select Retry to try to start sound again or Cancel to run Quake with no sound.",
|
||||
"Sound not available",
|
||||
MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
|
||||
{
|
||||
Com_Printf ("failed, hardware already in use\n" );
|
||||
return SIS_NOTAVAIL;
|
||||
}
|
||||
}
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
dscaps.dwSize = sizeof(dscaps);
|
||||
|
||||
if ( DS_OK != pDS->lpVtbl->GetCaps( pDS, &dscaps ) )
|
||||
{
|
||||
Com_Printf ("*** couldn't get DS caps ***\n");
|
||||
}
|
||||
|
||||
if ( dscaps.dwFlags & DSCAPS_EMULDRIVER )
|
||||
{
|
||||
Com_DPrintf ("...no DSound driver found\n" );
|
||||
FreeSound();
|
||||
return SIS_FAILURE;
|
||||
}
|
||||
|
||||
if ( !DS_CreateBuffers() )
|
||||
return SIS_FAILURE;
|
||||
|
||||
dsound_init = true;
|
||||
|
||||
Com_DPrintf("...completed successfully\n" );
|
||||
|
||||
return SIS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SNDDM_InitWav
|
||||
|
||||
Crappy windows multimedia base
|
||||
==================
|
||||
*/
|
||||
qboolean SNDDMA_InitWav (void)
|
||||
{
|
||||
WAVEFORMATEX format;
|
||||
int i;
|
||||
HRESULT hr;
|
||||
|
||||
Com_Printf( "Initializing wave sound\n" );
|
||||
|
||||
snd_sent = 0;
|
||||
snd_completed = 0;
|
||||
|
||||
dma.channels = 2;
|
||||
dma.samplebits = 16;
|
||||
|
||||
if (s_khz->value == 44)
|
||||
dma.speed = 44100;
|
||||
if (s_khz->value == 22)
|
||||
dma.speed = 22050;
|
||||
else
|
||||
dma.speed = 11025;
|
||||
|
||||
memset (&format, 0, sizeof(format));
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
format.nChannels = dma.channels;
|
||||
format.wBitsPerSample = dma.samplebits;
|
||||
format.nSamplesPerSec = dma.speed;
|
||||
format.nBlockAlign = format.nChannels
|
||||
*format.wBitsPerSample / 8;
|
||||
format.cbSize = 0;
|
||||
format.nAvgBytesPerSec = format.nSamplesPerSec
|
||||
*format.nBlockAlign;
|
||||
|
||||
/* Open a waveform device for output using window callback. */
|
||||
Com_DPrintf ("...opening waveform device: ");
|
||||
while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
|
||||
&format,
|
||||
0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
|
||||
{
|
||||
if (hr != MMSYSERR_ALLOCATED)
|
||||
{
|
||||
Com_Printf ("failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MessageBox (NULL,
|
||||
"The sound hardware is in use by another app.\n\n"
|
||||
"Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.",
|
||||
"Sound not available",
|
||||
MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
|
||||
{
|
||||
Com_Printf ("hw in use\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
/*
|
||||
* Allocate and lock memory for the waveform data. The memory
|
||||
* for waveform data must be globally allocated with
|
||||
* GMEM_MOVEABLE and GMEM_SHARE flags.
|
||||
|
||||
*/
|
||||
Com_DPrintf ("...allocating waveform buffer: ");
|
||||
gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
|
||||
hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize);
|
||||
if (!hData)
|
||||
{
|
||||
Com_Printf( " failed\n" );
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
Com_DPrintf ("...locking waveform buffer: ");
|
||||
lpData = GlobalLock(hData);
|
||||
if (!lpData)
|
||||
{
|
||||
Com_Printf( " failed\n" );
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
memset (lpData, 0, gSndBufSize);
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
/*
|
||||
* Allocate and lock memory for the header. This memory must
|
||||
* also be globally allocated with GMEM_MOVEABLE and
|
||||
* GMEM_SHARE flags.
|
||||
*/
|
||||
Com_DPrintf ("...allocating waveform header: ");
|
||||
hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
|
||||
(DWORD) sizeof(WAVEHDR) * WAV_BUFFERS);
|
||||
|
||||
if (hWaveHdr == NULL)
|
||||
{
|
||||
Com_Printf( "failed\n" );
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
Com_DPrintf ("...locking waveform header: ");
|
||||
lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
|
||||
|
||||
if (lpWaveHdr == NULL)
|
||||
{
|
||||
Com_Printf( "failed\n" );
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
|
||||
Com_DPrintf( "ok\n" );
|
||||
|
||||
/* After allocation, set up and prepare headers. */
|
||||
Com_DPrintf ("...preparing headers: ");
|
||||
for (i=0 ; i<WAV_BUFFERS ; i++)
|
||||
{
|
||||
lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
|
||||
lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
|
||||
|
||||
if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
|
||||
MMSYSERR_NOERROR)
|
||||
{
|
||||
Com_Printf ("failed\n");
|
||||
FreeSound ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Com_DPrintf ("ok\n");
|
||||
|
||||
dma.samples = gSndBufSize/(dma.samplebits/8);
|
||||
dma.samplepos = 0;
|
||||
dma.submission_chunk = 512;
|
||||
dma.buffer = (unsigned char *) lpData;
|
||||
sample16 = (dma.samplebits/8) - 1;
|
||||
|
||||
wav_init = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SNDDMA_Init
|
||||
|
||||
Try to find a sound device to mix for.
|
||||
Returns false if nothing is found.
|
||||
==================
|
||||
*/
|
||||
int SNDDMA_Init(void)
|
||||
{
|
||||
sndinitstat stat;
|
||||
|
||||
memset ((void *)&dma, 0, sizeof (dma));
|
||||
|
||||
s_wavonly = Cvar_Get ("s_wavonly", "0", 0);
|
||||
|
||||
dsound_init = wav_init = 0;
|
||||
|
||||
stat = SIS_FAILURE; // assume DirectSound won't initialize
|
||||
|
||||
/* Init DirectSound */
|
||||
if (!s_wavonly->value)
|
||||
{
|
||||
if (snd_firsttime || snd_isdirect)
|
||||
{
|
||||
stat = SNDDMA_InitDirect ();
|
||||
|
||||
if (stat == SIS_SUCCESS)
|
||||
{
|
||||
snd_isdirect = true;
|
||||
|
||||
if (snd_firsttime)
|
||||
Com_Printf ("dsound init succeeded\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
snd_isdirect = false;
|
||||
Com_Printf ("*** dsound init failed ***\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if DirectSound didn't succeed in initializing, try to initialize
|
||||
// waveOut sound, unless DirectSound failed because the hardware is
|
||||
// already allocated (in which case the user has already chosen not
|
||||
// to have sound)
|
||||
if (!dsound_init && (stat != SIS_NOTAVAIL))
|
||||
{
|
||||
if (snd_firsttime || snd_iswave)
|
||||
{
|
||||
|
||||
snd_iswave = SNDDMA_InitWav ();
|
||||
|
||||
if (snd_iswave)
|
||||
{
|
||||
if (snd_firsttime)
|
||||
Com_Printf ("Wave sound init succeeded\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_Printf ("Wave sound init failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snd_firsttime = false;
|
||||
|
||||
snd_buffer_count = 1;
|
||||
|
||||
if (!dsound_init && !wav_init)
|
||||
{
|
||||
if (snd_firsttime)
|
||||
Com_Printf ("*** No sound device initialized ***\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_GetDMAPos
|
||||
|
||||
return the current sample position (in mono samples read)
|
||||
inside the recirculating dma buffer, so the mixing code will know
|
||||
how many sample are required to fill it up.
|
||||
===============
|
||||
*/
|
||||
int SNDDMA_GetDMAPos(void)
|
||||
{
|
||||
MMTIME mmtime;
|
||||
int s;
|
||||
DWORD dwWrite;
|
||||
|
||||
if (dsound_init)
|
||||
{
|
||||
mmtime.wType = TIME_SAMPLES;
|
||||
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
|
||||
s = mmtime.u.sample - mmstarttime.u.sample;
|
||||
}
|
||||
else if (wav_init)
|
||||
{
|
||||
s = snd_sent * WAV_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
|
||||
s >>= sample16;
|
||||
|
||||
s &= (dma.samples-1);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_BeginPainting
|
||||
|
||||
Makes sure dma.buffer is valid
|
||||
===============
|
||||
*/
|
||||
DWORD locksize;
|
||||
void SNDDMA_BeginPainting (void)
|
||||
{
|
||||
int reps;
|
||||
DWORD dwSize2;
|
||||
DWORD *pbuf, *pbuf2;
|
||||
HRESULT hresult;
|
||||
DWORD dwStatus;
|
||||
|
||||
if (!pDSBuf)
|
||||
return;
|
||||
|
||||
// if the buffer was lost or stopped, restore it and/or restart it
|
||||
if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK)
|
||||
Com_Printf ("Couldn't get sound buffer status\n");
|
||||
|
||||
if (dwStatus & DSBSTATUS_BUFFERLOST)
|
||||
pDSBuf->lpVtbl->Restore (pDSBuf);
|
||||
|
||||
if (!(dwStatus & DSBSTATUS_PLAYING))
|
||||
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
// lock the dsound buffer
|
||||
|
||||
reps = 0;
|
||||
dma.buffer = NULL;
|
||||
|
||||
while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &locksize,
|
||||
&pbuf2, &dwSize2, 0)) != DS_OK)
|
||||
{
|
||||
if (hresult != DSERR_BUFFERLOST)
|
||||
{
|
||||
Com_Printf( "S_TransferStereo16: Lock failed with error '%s'\n", DSoundError( hresult ) );
|
||||
S_Shutdown ();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDSBuf->lpVtbl->Restore( pDSBuf );
|
||||
}
|
||||
|
||||
if (++reps > 2)
|
||||
return;
|
||||
}
|
||||
dma.buffer = (unsigned char *)pbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_Submit
|
||||
|
||||
Send sound to device if buffer isn't really the dma buffer
|
||||
Also unlocks the dsound buffer
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_Submit(void)
|
||||
{
|
||||
LPWAVEHDR h;
|
||||
int wResult;
|
||||
|
||||
if (!dma.buffer)
|
||||
return;
|
||||
|
||||
// unlock the dsound buffer
|
||||
if (pDSBuf)
|
||||
pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
|
||||
|
||||
if (!wav_init)
|
||||
return;
|
||||
|
||||
//
|
||||
// find which sound blocks have completed
|
||||
//
|
||||
while (1)
|
||||
{
|
||||
if ( snd_completed == snd_sent )
|
||||
{
|
||||
Com_DPrintf ("Sound overrun\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
snd_completed++; // this buffer has been played
|
||||
}
|
||||
|
||||
//Com_Printf ("completed %i\n", snd_completed);
|
||||
//
|
||||
// submit a few new sound blocks
|
||||
//
|
||||
while (((snd_sent - snd_completed) >> sample16) < 8)
|
||||
{
|
||||
h = lpWaveHdr + ( snd_sent&WAV_MASK );
|
||||
if (paintedtime/256 <= snd_sent)
|
||||
break; // Com_Printf ("submit overrun\n");
|
||||
//Com_Printf ("send %i\n", snd_sent);
|
||||
snd_sent++;
|
||||
/*
|
||||
* Now the data block can be sent to the output device. The
|
||||
* waveOutWrite function returns immediately and waveform
|
||||
* data is sent to the output device in the background.
|
||||
*/
|
||||
wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR));
|
||||
|
||||
if (wResult != MMSYSERR_NOERROR)
|
||||
{
|
||||
Com_Printf ("Failed to write block to device\n");
|
||||
FreeSound ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SNDDMA_Shutdown
|
||||
|
||||
Reset the sound device for exiting
|
||||
===============
|
||||
*/
|
||||
void SNDDMA_Shutdown(void)
|
||||
{
|
||||
FreeSound ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
S_Activate
|
||||
|
||||
Called when the main window gains or loses focus.
|
||||
The window have been destroyed and recreated
|
||||
between a deactivate and an activate.
|
||||
===========
|
||||
*/
|
||||
void S_Activate (qboolean active)
|
||||
{
|
||||
if ( active )
|
||||
{
|
||||
if ( pDS && cl_hwnd && snd_isdirect )
|
||||
{
|
||||
DS_CreateBuffers();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pDS && cl_hwnd && snd_isdirect )
|
||||
{
|
||||
DS_DestroyBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
663
win32/sys_win.c
Normal file
663
win32/sys_win.c
Normal file
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// sys_win.h
|
||||
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "winquake.h"
|
||||
#include "resource.h"
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <conio.h>
|
||||
#include "../win32/conproc.h"
|
||||
|
||||
#define MINIMUM_WIN_MEMORY 0x0a00000
|
||||
#define MAXIMUM_WIN_MEMORY 0x1000000
|
||||
|
||||
//#define DEMO
|
||||
|
||||
qboolean s_win95;
|
||||
|
||||
int starttime;
|
||||
int ActiveApp;
|
||||
qboolean Minimized;
|
||||
|
||||
static HANDLE hinput, houtput;
|
||||
|
||||
unsigned sys_msg_time;
|
||||
unsigned sys_frame_time;
|
||||
|
||||
|
||||
static HANDLE qwclsemaphore;
|
||||
|
||||
#define MAX_NUM_ARGVS 128
|
||||
int argc;
|
||||
char *argv[MAX_NUM_ARGVS];
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
SYSTEM IO
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
|
||||
void Sys_Error (char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char text[1024];
|
||||
|
||||
CL_Shutdown ();
|
||||
Qcommon_Shutdown ();
|
||||
|
||||
va_start (argptr, error);
|
||||
vsprintf (text, error, argptr);
|
||||
va_end (argptr);
|
||||
|
||||
MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
|
||||
|
||||
if (qwclsemaphore)
|
||||
CloseHandle (qwclsemaphore);
|
||||
|
||||
// shut down QHOST hooks if necessary
|
||||
DeinitConProc ();
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void Sys_Quit (void)
|
||||
{
|
||||
timeEndPeriod( 1 );
|
||||
|
||||
CL_Shutdown();
|
||||
Qcommon_Shutdown ();
|
||||
CloseHandle (qwclsemaphore);
|
||||
if (dedicated && dedicated->value)
|
||||
FreeConsole ();
|
||||
|
||||
// shut down QHOST hooks if necessary
|
||||
DeinitConProc ();
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
||||
void WinError (void)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
// Display the string.
|
||||
MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
|
||||
|
||||
// Free the buffer.
|
||||
LocalFree( lpMsgBuf );
|
||||
}
|
||||
|
||||
//================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_ScanForCD
|
||||
|
||||
================
|
||||
*/
|
||||
char *Sys_ScanForCD (void)
|
||||
{
|
||||
static char cddir[MAX_OSPATH];
|
||||
static qboolean done;
|
||||
#ifndef DEMO
|
||||
char drive[4];
|
||||
FILE *f;
|
||||
char test[MAX_QPATH];
|
||||
|
||||
if (done) // don't re-check
|
||||
return cddir;
|
||||
|
||||
// no abort/retry/fail errors
|
||||
SetErrorMode (SEM_FAILCRITICALERRORS);
|
||||
|
||||
drive[0] = 'c';
|
||||
drive[1] = ':';
|
||||
drive[2] = '\\';
|
||||
drive[3] = 0;
|
||||
|
||||
done = true;
|
||||
|
||||
// scan the drives
|
||||
for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++)
|
||||
{
|
||||
// where activision put the stuff...
|
||||
sprintf (cddir, "%sinstall\\data", drive);
|
||||
sprintf (test, "%sinstall\\data\\quake2.exe", drive);
|
||||
f = fopen(test, "r");
|
||||
if (f)
|
||||
{
|
||||
fclose (f);
|
||||
if (GetDriveType (drive) == DRIVE_CDROM)
|
||||
return cddir;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
cddir[0] = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_CopyProtect
|
||||
|
||||
================
|
||||
*/
|
||||
void Sys_CopyProtect (void)
|
||||
{
|
||||
#ifndef DEMO
|
||||
char *cddir;
|
||||
|
||||
cddir = Sys_ScanForCD();
|
||||
if (!cddir[0])
|
||||
Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Init
|
||||
================
|
||||
*/
|
||||
void Sys_Init (void)
|
||||
{
|
||||
OSVERSIONINFO vinfo;
|
||||
|
||||
#if 0
|
||||
// allocate a named semaphore on the client so the
|
||||
// front end can tell if it is alive
|
||||
|
||||
// mutex will fail if semephore already exists
|
||||
qwclsemaphore = CreateMutex(
|
||||
NULL, /* Security attributes */
|
||||
0, /* owner */
|
||||
"qwcl"); /* Semaphore name */
|
||||
if (!qwclsemaphore)
|
||||
Sys_Error ("QWCL is already running on this system");
|
||||
CloseHandle (qwclsemaphore);
|
||||
|
||||
qwclsemaphore = CreateSemaphore(
|
||||
NULL, /* Security attributes */
|
||||
0, /* Initial count */
|
||||
1, /* Maximum count */
|
||||
"qwcl"); /* Semaphore name */
|
||||
#endif
|
||||
|
||||
timeBeginPeriod( 1 );
|
||||
|
||||
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
|
||||
|
||||
if (!GetVersionEx (&vinfo))
|
||||
Sys_Error ("Couldn't get OS info");
|
||||
|
||||
if (vinfo.dwMajorVersion < 4)
|
||||
Sys_Error ("Quake2 requires windows version 4 or greater");
|
||||
if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
|
||||
Sys_Error ("Quake2 doesn't run on Win32s");
|
||||
else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
|
||||
s_win95 = true;
|
||||
|
||||
if (dedicated->value)
|
||||
{
|
||||
if (!AllocConsole ())
|
||||
Sys_Error ("Couldn't create dedicated server console");
|
||||
hinput = GetStdHandle (STD_INPUT_HANDLE);
|
||||
houtput = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
|
||||
// let QHOST hook in
|
||||
InitConProc (argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static char console_text[256];
|
||||
static int console_textlen;
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_ConsoleInput
|
||||
================
|
||||
*/
|
||||
char *Sys_ConsoleInput (void)
|
||||
{
|
||||
INPUT_RECORD recs[1024];
|
||||
int dummy;
|
||||
int ch, numread, numevents;
|
||||
|
||||
if (!dedicated || !dedicated->value)
|
||||
return NULL;
|
||||
|
||||
|
||||
for ( ;; )
|
||||
{
|
||||
if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
|
||||
Sys_Error ("Error getting # of console events");
|
||||
|
||||
if (numevents <= 0)
|
||||
break;
|
||||
|
||||
if (!ReadConsoleInput(hinput, recs, 1, &numread))
|
||||
Sys_Error ("Error reading console input");
|
||||
|
||||
if (numread != 1)
|
||||
Sys_Error ("Couldn't read console input");
|
||||
|
||||
if (recs[0].EventType == KEY_EVENT)
|
||||
{
|
||||
if (!recs[0].Event.KeyEvent.bKeyDown)
|
||||
{
|
||||
ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '\r':
|
||||
WriteFile(houtput, "\r\n", 2, &dummy, NULL);
|
||||
|
||||
if (console_textlen)
|
||||
{
|
||||
console_text[console_textlen] = 0;
|
||||
console_textlen = 0;
|
||||
return console_text;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
if (console_textlen)
|
||||
{
|
||||
console_textlen--;
|
||||
WriteFile(houtput, "\b \b", 3, &dummy, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ch >= ' ')
|
||||
{
|
||||
if (console_textlen < sizeof(console_text)-2)
|
||||
{
|
||||
WriteFile(houtput, &ch, 1, &dummy, NULL);
|
||||
console_text[console_textlen] = ch;
|
||||
console_textlen++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_ConsoleOutput
|
||||
|
||||
Print text to the dedicated console
|
||||
================
|
||||
*/
|
||||
void Sys_ConsoleOutput (char *string)
|
||||
{
|
||||
int dummy;
|
||||
char text[256];
|
||||
|
||||
if (!dedicated || !dedicated->value)
|
||||
return;
|
||||
|
||||
if (console_textlen)
|
||||
{
|
||||
text[0] = '\r';
|
||||
memset(&text[1], ' ', console_textlen);
|
||||
text[console_textlen+1] = '\r';
|
||||
text[console_textlen+2] = 0;
|
||||
WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
|
||||
}
|
||||
|
||||
WriteFile(houtput, string, strlen(string), &dummy, NULL);
|
||||
|
||||
if (console_textlen)
|
||||
WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_SendKeyEvents
|
||||
|
||||
Send Key_Event calls
|
||||
================
|
||||
*/
|
||||
void Sys_SendKeyEvents (void)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
|
||||
{
|
||||
if (!GetMessage (&msg, NULL, 0, 0))
|
||||
Sys_Quit ();
|
||||
sys_msg_time = msg.time;
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
|
||||
// grab frame time
|
||||
sys_frame_time = timeGetTime(); // FIXME: should this be at start?
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetClipboardData
|
||||
|
||||
================
|
||||
*/
|
||||
char *Sys_GetClipboardData( void )
|
||||
{
|
||||
char *data = NULL;
|
||||
char *cliptext;
|
||||
|
||||
if ( OpenClipboard( NULL ) != 0 )
|
||||
{
|
||||
HANDLE hClipboardData;
|
||||
|
||||
if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
|
||||
{
|
||||
if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 )
|
||||
{
|
||||
data = malloc( GlobalSize( hClipboardData ) + 1 );
|
||||
strcpy( data, cliptext );
|
||||
GlobalUnlock( hClipboardData );
|
||||
}
|
||||
}
|
||||
CloseClipboard();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
WINDOWS CRAP
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_AppActivate
|
||||
=================
|
||||
*/
|
||||
void Sys_AppActivate (void)
|
||||
{
|
||||
ShowWindow ( cl_hwnd, SW_RESTORE);
|
||||
SetForegroundWindow ( cl_hwnd );
|
||||
}
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
GAME DLL
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
static HINSTANCE game_library;
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_UnloadGame
|
||||
=================
|
||||
*/
|
||||
void Sys_UnloadGame (void)
|
||||
{
|
||||
if (!FreeLibrary (game_library))
|
||||
Com_Error (ERR_FATAL, "FreeLibrary failed for game library");
|
||||
game_library = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Sys_GetGameAPI
|
||||
|
||||
Loads the game dll
|
||||
=================
|
||||
*/
|
||||
void *Sys_GetGameAPI (void *parms)
|
||||
{
|
||||
void *(*GetGameAPI) (void *);
|
||||
char name[MAX_OSPATH];
|
||||
char *path;
|
||||
char cwd[MAX_OSPATH];
|
||||
#if defined _M_IX86
|
||||
const char *gamename = "gamex86.dll";
|
||||
|
||||
#ifdef NDEBUG
|
||||
const char *debugdir = "release";
|
||||
#else
|
||||
const char *debugdir = "debug";
|
||||
#endif
|
||||
|
||||
#elif defined _M_ALPHA
|
||||
const char *gamename = "gameaxp.dll";
|
||||
|
||||
#ifdef NDEBUG
|
||||
const char *debugdir = "releaseaxp";
|
||||
#else
|
||||
const char *debugdir = "debugaxp";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
if (game_library)
|
||||
Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
|
||||
|
||||
// check the current debug directory first for development purposes
|
||||
_getcwd (cwd, sizeof(cwd));
|
||||
Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
|
||||
game_library = LoadLibrary ( name );
|
||||
if (game_library)
|
||||
{
|
||||
Com_DPrintf ("LoadLibrary (%s)\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check the current directory for other development purposes
|
||||
Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
|
||||
game_library = LoadLibrary ( name );
|
||||
if (game_library)
|
||||
{
|
||||
Com_DPrintf ("LoadLibrary (%s)\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// now run through the search paths
|
||||
path = NULL;
|
||||
while (1)
|
||||
{
|
||||
path = FS_NextPath (path);
|
||||
if (!path)
|
||||
return NULL; // couldn't find one anywhere
|
||||
Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
|
||||
game_library = LoadLibrary (name);
|
||||
if (game_library)
|
||||
{
|
||||
Com_DPrintf ("LoadLibrary (%s)\n",name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI");
|
||||
if (!GetGameAPI)
|
||||
{
|
||||
Sys_UnloadGame ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return GetGameAPI (parms);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
ParseCommandLine
|
||||
|
||||
==================
|
||||
*/
|
||||
void ParseCommandLine (LPSTR lpCmdLine)
|
||||
{
|
||||
argc = 1;
|
||||
argv[0] = "exe";
|
||||
|
||||
while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
|
||||
{
|
||||
while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine)
|
||||
{
|
||||
argv[argc] = lpCmdLine;
|
||||
argc++;
|
||||
|
||||
while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
|
||||
lpCmdLine++;
|
||||
|
||||
if (*lpCmdLine)
|
||||
{
|
||||
*lpCmdLine = 0;
|
||||
lpCmdLine++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
WinMain
|
||||
|
||||
==================
|
||||
*/
|
||||
HINSTANCE global_hInstance;
|
||||
|
||||
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
MSG msg;
|
||||
int time, oldtime, newtime;
|
||||
char *cddir;
|
||||
|
||||
/* previous instances do not exist in Win32 */
|
||||
if (hPrevInstance)
|
||||
return 0;
|
||||
|
||||
global_hInstance = hInstance;
|
||||
|
||||
ParseCommandLine (lpCmdLine);
|
||||
|
||||
// if we find the CD, add a +set cddir xxx command line
|
||||
cddir = Sys_ScanForCD ();
|
||||
if (cddir && argc < MAX_NUM_ARGVS - 3)
|
||||
{
|
||||
int i;
|
||||
|
||||
// don't override a cddir on the command line
|
||||
for (i=0 ; i<argc ; i++)
|
||||
if (!strcmp(argv[i], "cddir"))
|
||||
break;
|
||||
if (i == argc)
|
||||
{
|
||||
argv[argc++] = "+set";
|
||||
argv[argc++] = "cddir";
|
||||
argv[argc++] = cddir;
|
||||
}
|
||||
}
|
||||
|
||||
Qcommon_Init (argc, argv);
|
||||
oldtime = Sys_Milliseconds ();
|
||||
|
||||
/* main window message loop */
|
||||
while (1)
|
||||
{
|
||||
// if at a full screen console, don't update unless needed
|
||||
if (Minimized || (dedicated && dedicated->value) )
|
||||
{
|
||||
Sleep (1);
|
||||
}
|
||||
|
||||
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
|
||||
{
|
||||
if (!GetMessage (&msg, NULL, 0, 0))
|
||||
Com_Quit ();
|
||||
sys_msg_time = msg.time;
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
newtime = Sys_Milliseconds ();
|
||||
time = newtime - oldtime;
|
||||
} while (time < 1);
|
||||
// Con_Printf ("time:%5.2f - %5.2f = %5.2f\n", newtime, oldtime, time);
|
||||
|
||||
// _controlfp( ~( _EM_ZERODIVIDE /*| _EM_INVALID*/ ), _MCW_EM );
|
||||
_controlfp( _PC_24, _MCW_PC );
|
||||
Qcommon_Frame (time);
|
||||
|
||||
oldtime = newtime;
|
||||
}
|
||||
|
||||
// never gets here
|
||||
return TRUE;
|
||||
}
|
||||
760
win32/vid_dll.c
Normal file
760
win32/vid_dll.c
Normal file
@@ -0,0 +1,760 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// Main windowed and fullscreen graphics interface module. This module
|
||||
// is used for both the software and OpenGL rendering versions of the
|
||||
// Quake refresh engine.
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "..\client\client.h"
|
||||
#include "winquake.h"
|
||||
//#include "zmouse.h"
|
||||
|
||||
// Structure containing functions exported from refresh DLL
|
||||
refexport_t re;
|
||||
|
||||
cvar_t *win_noalttab;
|
||||
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
#define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported by the OS
|
||||
#endif
|
||||
|
||||
static UINT MSH_MOUSEWHEEL;
|
||||
|
||||
// Console variables that we need to access from this module
|
||||
cvar_t *vid_gamma;
|
||||
cvar_t *vid_ref; // Name of Refresh DLL loaded
|
||||
cvar_t *vid_xpos; // X coordinate of window position
|
||||
cvar_t *vid_ypos; // Y coordinate of window position
|
||||
cvar_t *vid_fullscreen;
|
||||
|
||||
// Global variables used internally by this module
|
||||
viddef_t viddef; // global video state; used by other modules
|
||||
HINSTANCE reflib_library; // Handle to refresh DLL
|
||||
qboolean reflib_active = 0;
|
||||
|
||||
HWND cl_hwnd; // Main window handle for life of program
|
||||
|
||||
#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
|
||||
|
||||
LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
||||
|
||||
static qboolean s_alttab_disabled;
|
||||
|
||||
extern unsigned sys_msg_time;
|
||||
|
||||
/*
|
||||
** WIN32 helper functions
|
||||
*/
|
||||
extern qboolean s_win95;
|
||||
|
||||
static void WIN_DisableAltTab( void )
|
||||
{
|
||||
if ( s_alttab_disabled )
|
||||
return;
|
||||
|
||||
if ( s_win95 )
|
||||
{
|
||||
BOOL old;
|
||||
|
||||
SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
|
||||
RegisterHotKey( 0, 1, MOD_ALT, VK_RETURN );
|
||||
}
|
||||
s_alttab_disabled = true;
|
||||
}
|
||||
|
||||
static void WIN_EnableAltTab( void )
|
||||
{
|
||||
if ( s_alttab_disabled )
|
||||
{
|
||||
if ( s_win95 )
|
||||
{
|
||||
BOOL old;
|
||||
|
||||
SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
UnregisterHotKey( 0, 0 );
|
||||
UnregisterHotKey( 0, 1 );
|
||||
}
|
||||
|
||||
s_alttab_disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==========================================================================
|
||||
|
||||
DLL GLUE
|
||||
|
||||
==========================================================================
|
||||
*/
|
||||
|
||||
#define MAXPRINTMSG 4096
|
||||
void VID_Printf (int print_level, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char msg[MAXPRINTMSG];
|
||||
static qboolean inupdate;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg,fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
if (print_level == PRINT_ALL)
|
||||
{
|
||||
Com_Printf ("%s", msg);
|
||||
}
|
||||
else if ( print_level == PRINT_DEVELOPER )
|
||||
{
|
||||
Com_DPrintf ("%s", msg);
|
||||
}
|
||||
else if ( print_level == PRINT_ALERT )
|
||||
{
|
||||
MessageBox( 0, msg, "PRINT_ALERT", MB_ICONWARNING );
|
||||
OutputDebugString( msg );
|
||||
}
|
||||
}
|
||||
|
||||
void VID_Error (int err_level, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char msg[MAXPRINTMSG];
|
||||
static qboolean inupdate;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg,fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Com_Error (err_level,"%s", msg);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
||||
byte scantokey[128] =
|
||||
{
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// 8 9 A B C D E F
|
||||
0 , 27, '1', '2', '3', '4', '5', '6',
|
||||
'7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
|
||||
'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
|
||||
'\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2
|
||||
'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',
|
||||
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
|
||||
K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME,
|
||||
K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4
|
||||
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
|
||||
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
|
||||
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
|
||||
};
|
||||
|
||||
/*
|
||||
=======
|
||||
MapKey
|
||||
|
||||
Map from windows to quake keynums
|
||||
=======
|
||||
*/
|
||||
int MapKey (int key)
|
||||
{
|
||||
int result;
|
||||
int modified = ( key >> 16 ) & 255;
|
||||
qboolean is_extended = false;
|
||||
|
||||
if ( modified > 127)
|
||||
return 0;
|
||||
|
||||
if ( key & ( 1 << 24 ) )
|
||||
is_extended = true;
|
||||
|
||||
result = scantokey[modified];
|
||||
|
||||
if ( !is_extended )
|
||||
{
|
||||
switch ( result )
|
||||
{
|
||||
case K_HOME:
|
||||
return K_KP_HOME;
|
||||
case K_UPARROW:
|
||||
return K_KP_UPARROW;
|
||||
case K_PGUP:
|
||||
return K_KP_PGUP;
|
||||
case K_LEFTARROW:
|
||||
return K_KP_LEFTARROW;
|
||||
case K_RIGHTARROW:
|
||||
return K_KP_RIGHTARROW;
|
||||
case K_END:
|
||||
return K_KP_END;
|
||||
case K_DOWNARROW:
|
||||
return K_KP_DOWNARROW;
|
||||
case K_PGDN:
|
||||
return K_KP_PGDN;
|
||||
case K_INS:
|
||||
return K_KP_INS;
|
||||
case K_DEL:
|
||||
return K_KP_DEL;
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( result )
|
||||
{
|
||||
case 0x0D:
|
||||
return K_KP_ENTER;
|
||||
case 0x2F:
|
||||
return K_KP_SLASH;
|
||||
case 0xAF:
|
||||
return K_KP_PLUS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void AppActivate(BOOL fActive, BOOL minimize)
|
||||
{
|
||||
Minimized = minimize;
|
||||
|
||||
Key_ClearStates();
|
||||
|
||||
// we don't want to act like we're active if we're minimized
|
||||
if (fActive && !Minimized)
|
||||
ActiveApp = true;
|
||||
else
|
||||
ActiveApp = false;
|
||||
|
||||
// minimize/restore mouse-capture on demand
|
||||
if (!ActiveApp)
|
||||
{
|
||||
IN_Activate (false);
|
||||
CDAudio_Activate (false);
|
||||
S_Activate (false);
|
||||
|
||||
if ( win_noalttab->value )
|
||||
{
|
||||
WIN_EnableAltTab();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IN_Activate (true);
|
||||
CDAudio_Activate (true);
|
||||
S_Activate (true);
|
||||
if ( win_noalttab->value )
|
||||
{
|
||||
WIN_DisableAltTab();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
MainWndProc
|
||||
|
||||
main window procedure
|
||||
====================
|
||||
*/
|
||||
LONG WINAPI MainWndProc (
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
LONG lRet = 0;
|
||||
|
||||
if ( uMsg == MSH_MOUSEWHEEL )
|
||||
{
|
||||
if ( ( ( int ) wParam ) > 0 )
|
||||
{
|
||||
Key_Event( K_MWHEELUP, true, sys_msg_time );
|
||||
Key_Event( K_MWHEELUP, false, sys_msg_time );
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_Event( K_MWHEELDOWN, true, sys_msg_time );
|
||||
Key_Event( K_MWHEELDOWN, false, sys_msg_time );
|
||||
}
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_MOUSEWHEEL:
|
||||
/*
|
||||
** this chunk of code theoretically only works under NT4 and Win98
|
||||
** since this message doesn't exist under Win95
|
||||
*/
|
||||
if ( ( short ) HIWORD( wParam ) > 0 )
|
||||
{
|
||||
Key_Event( K_MWHEELUP, true, sys_msg_time );
|
||||
Key_Event( K_MWHEELUP, false, sys_msg_time );
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_Event( K_MWHEELDOWN, true, sys_msg_time );
|
||||
Key_Event( K_MWHEELDOWN, false, sys_msg_time );
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_HOTKEY:
|
||||
return 0;
|
||||
|
||||
case WM_CREATE:
|
||||
cl_hwnd = hWnd;
|
||||
|
||||
MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG");
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
|
||||
case WM_PAINT:
|
||||
SCR_DirtyScreen (); // force entire screen to update next frame
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
|
||||
case WM_DESTROY:
|
||||
// let sound and input know about this?
|
||||
cl_hwnd = NULL;
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
|
||||
case WM_ACTIVATE:
|
||||
{
|
||||
int fActive, fMinimized;
|
||||
|
||||
// KJB: Watch this for problems in fullscreen modes with Alt-tabbing.
|
||||
fActive = LOWORD(wParam);
|
||||
fMinimized = (BOOL) HIWORD(wParam);
|
||||
|
||||
AppActivate( fActive != WA_INACTIVE, fMinimized);
|
||||
|
||||
if ( reflib_active )
|
||||
re.AppActivate( !( fActive == WA_INACTIVE ) );
|
||||
}
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
|
||||
case WM_MOVE:
|
||||
{
|
||||
int xPos, yPos;
|
||||
RECT r;
|
||||
int style;
|
||||
|
||||
if (!vid_fullscreen->value)
|
||||
{
|
||||
xPos = (short) LOWORD(lParam); // horizontal position
|
||||
yPos = (short) HIWORD(lParam); // vertical position
|
||||
|
||||
r.left = 0;
|
||||
r.top = 0;
|
||||
r.right = 1;
|
||||
r.bottom = 1;
|
||||
|
||||
style = GetWindowLong( hWnd, GWL_STYLE );
|
||||
AdjustWindowRect( &r, style, FALSE );
|
||||
|
||||
Cvar_SetValue( "vid_xpos", xPos + r.left);
|
||||
Cvar_SetValue( "vid_ypos", yPos + r.top);
|
||||
vid_xpos->modified = false;
|
||||
vid_ypos->modified = false;
|
||||
if (ActiveApp)
|
||||
IN_Activate (true);
|
||||
}
|
||||
}
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
|
||||
// this is complicated because Win32 seems to pack multiple mouse events into
|
||||
// one update sometimes, so we always check all states and look for events
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = 0;
|
||||
|
||||
if (wParam & MK_LBUTTON)
|
||||
temp |= 1;
|
||||
|
||||
if (wParam & MK_RBUTTON)
|
||||
temp |= 2;
|
||||
|
||||
if (wParam & MK_MBUTTON)
|
||||
temp |= 4;
|
||||
|
||||
IN_MouseEvent (temp);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
if ( wParam == SC_SCREENSAVE )
|
||||
return 0;
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
case WM_SYSKEYDOWN:
|
||||
if ( wParam == 13 )
|
||||
{
|
||||
if ( vid_fullscreen )
|
||||
{
|
||||
Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// fall through
|
||||
case WM_KEYDOWN:
|
||||
Key_Event( MapKey( lParam ), true, sys_msg_time);
|
||||
break;
|
||||
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYUP:
|
||||
Key_Event( MapKey( lParam ), false, sys_msg_time);
|
||||
break;
|
||||
|
||||
case MM_MCINOTIFY:
|
||||
{
|
||||
LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
|
||||
default: // pass all unhandled messages to DefWindowProc
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
/* return 0 if handled message, 1 if not */
|
||||
return DefWindowProc( hWnd, uMsg, wParam, lParam );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_Restart_f
|
||||
|
||||
Console command to re-start the video mode and refresh DLL. We do this
|
||||
simply by setting the modified flag for the vid_ref variable, which will
|
||||
cause the entire video mode and refresh DLL to be reset on the next frame.
|
||||
============
|
||||
*/
|
||||
void VID_Restart_f (void)
|
||||
{
|
||||
vid_ref->modified = true;
|
||||
}
|
||||
|
||||
void VID_Front_f( void )
|
||||
{
|
||||
SetWindowLong( cl_hwnd, GWL_EXSTYLE, WS_EX_TOPMOST );
|
||||
SetForegroundWindow( cl_hwnd );
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_GetModeInfo
|
||||
*/
|
||||
typedef struct vidmode_s
|
||||
{
|
||||
const char *description;
|
||||
int width, height;
|
||||
int mode;
|
||||
} vidmode_t;
|
||||
|
||||
vidmode_t vid_modes[] =
|
||||
{
|
||||
{ "Mode 0: 320x240", 320, 240, 0 },
|
||||
{ "Mode 1: 400x300", 400, 300, 1 },
|
||||
{ "Mode 2: 512x384", 512, 384, 2 },
|
||||
{ "Mode 3: 640x480", 640, 480, 3 },
|
||||
{ "Mode 4: 800x600", 800, 600, 4 },
|
||||
{ "Mode 5: 960x720", 960, 720, 5 },
|
||||
{ "Mode 6: 1024x768", 1024, 768, 6 },
|
||||
{ "Mode 7: 1152x864", 1152, 864, 7 },
|
||||
{ "Mode 8: 1280x960", 1280, 960, 8 },
|
||||
{ "Mode 9: 1600x1200", 1600, 1200, 9 }
|
||||
};
|
||||
|
||||
qboolean VID_GetModeInfo( int *width, int *height, int mode )
|
||||
{
|
||||
if ( mode < 0 || mode >= VID_NUM_MODES )
|
||||
return false;
|
||||
|
||||
*width = vid_modes[mode].width;
|
||||
*height = vid_modes[mode].height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_UpdateWindowPosAndSize
|
||||
*/
|
||||
void VID_UpdateWindowPosAndSize( int x, int y )
|
||||
{
|
||||
RECT r;
|
||||
int style;
|
||||
int w, h;
|
||||
|
||||
r.left = 0;
|
||||
r.top = 0;
|
||||
r.right = viddef.width;
|
||||
r.bottom = viddef.height;
|
||||
|
||||
style = GetWindowLong( cl_hwnd, GWL_STYLE );
|
||||
AdjustWindowRect( &r, style, FALSE );
|
||||
|
||||
w = r.right - r.left;
|
||||
h = r.bottom - r.top;
|
||||
|
||||
MoveWindow( cl_hwnd, vid_xpos->value, vid_ypos->value, w, h, TRUE );
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_NewWindow
|
||||
*/
|
||||
void VID_NewWindow ( int width, int height)
|
||||
{
|
||||
viddef.width = width;
|
||||
viddef.height = height;
|
||||
|
||||
cl.force_refdef = true; // can't use a paused refdef
|
||||
}
|
||||
|
||||
void VID_FreeReflib (void)
|
||||
{
|
||||
if ( !FreeLibrary( reflib_library ) )
|
||||
Com_Error( ERR_FATAL, "Reflib FreeLibrary failed" );
|
||||
memset (&re, 0, sizeof(re));
|
||||
reflib_library = NULL;
|
||||
reflib_active = false;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
VID_LoadRefresh
|
||||
==============
|
||||
*/
|
||||
qboolean VID_LoadRefresh( char *name )
|
||||
{
|
||||
refimport_t ri;
|
||||
GetRefAPI_t GetRefAPI;
|
||||
|
||||
if ( reflib_active )
|
||||
{
|
||||
re.Shutdown();
|
||||
VID_FreeReflib ();
|
||||
}
|
||||
|
||||
Com_Printf( "------- Loading %s -------\n", name );
|
||||
|
||||
if ( ( reflib_library = LoadLibrary( name ) ) == 0 )
|
||||
{
|
||||
Com_Printf( "LoadLibrary(\"%s\") failed\n", name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ri.Cmd_AddCommand = Cmd_AddCommand;
|
||||
ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
|
||||
ri.Cmd_Argc = Cmd_Argc;
|
||||
ri.Cmd_Argv = Cmd_Argv;
|
||||
ri.Cmd_ExecuteText = Cbuf_ExecuteText;
|
||||
ri.Con_Printf = VID_Printf;
|
||||
ri.Sys_Error = VID_Error;
|
||||
ri.FS_LoadFile = FS_LoadFile;
|
||||
ri.FS_FreeFile = FS_FreeFile;
|
||||
ri.FS_Gamedir = FS_Gamedir;
|
||||
ri.Cvar_Get = Cvar_Get;
|
||||
ri.Cvar_Set = Cvar_Set;
|
||||
ri.Cvar_SetValue = Cvar_SetValue;
|
||||
ri.Vid_GetModeInfo = VID_GetModeInfo;
|
||||
ri.Vid_MenuInit = VID_MenuInit;
|
||||
ri.Vid_NewWindow = VID_NewWindow;
|
||||
|
||||
if ( ( GetRefAPI = (void *) GetProcAddress( reflib_library, "GetRefAPI" ) ) == 0 )
|
||||
Com_Error( ERR_FATAL, "GetProcAddress failed on %s", name );
|
||||
|
||||
re = GetRefAPI( ri );
|
||||
|
||||
if (re.api_version != API_VERSION)
|
||||
{
|
||||
VID_FreeReflib ();
|
||||
Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
|
||||
}
|
||||
|
||||
if ( re.Init( global_hInstance, MainWndProc ) == -1 )
|
||||
{
|
||||
re.Shutdown();
|
||||
VID_FreeReflib ();
|
||||
return false;
|
||||
}
|
||||
|
||||
Com_Printf( "------------------------------------\n");
|
||||
reflib_active = true;
|
||||
|
||||
//======
|
||||
//PGM
|
||||
vidref_val = VIDREF_OTHER;
|
||||
if(vid_ref)
|
||||
{
|
||||
if(!strcmp (vid_ref->string, "gl"))
|
||||
vidref_val = VIDREF_GL;
|
||||
else if(!strcmp(vid_ref->string, "soft"))
|
||||
vidref_val = VIDREF_SOFT;
|
||||
}
|
||||
//PGM
|
||||
//======
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_CheckChanges
|
||||
|
||||
This function gets called once just before drawing each frame, and it's sole purpose in life
|
||||
is to check to see if any of the video mode parameters have changed, and if they have to
|
||||
update the rendering DLL and/or video mode to match.
|
||||
============
|
||||
*/
|
||||
void VID_CheckChanges (void)
|
||||
{
|
||||
char name[100];
|
||||
|
||||
if ( win_noalttab->modified )
|
||||
{
|
||||
if ( win_noalttab->value )
|
||||
{
|
||||
WIN_DisableAltTab();
|
||||
}
|
||||
else
|
||||
{
|
||||
WIN_EnableAltTab();
|
||||
}
|
||||
win_noalttab->modified = false;
|
||||
}
|
||||
|
||||
if ( vid_ref->modified )
|
||||
{
|
||||
cl.force_refdef = true; // can't use a paused refdef
|
||||
S_StopAllSounds();
|
||||
}
|
||||
while (vid_ref->modified)
|
||||
{
|
||||
/*
|
||||
** refresh has changed
|
||||
*/
|
||||
vid_ref->modified = false;
|
||||
vid_fullscreen->modified = true;
|
||||
cl.refresh_prepped = false;
|
||||
cls.disable_screen = true;
|
||||
|
||||
Com_sprintf( name, sizeof(name), "ref_%s.dll", vid_ref->string );
|
||||
if ( !VID_LoadRefresh( name ) )
|
||||
{
|
||||
if ( strcmp (vid_ref->string, "soft") == 0 )
|
||||
Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
|
||||
Cvar_Set( "vid_ref", "soft" );
|
||||
|
||||
/*
|
||||
** drop the console if we fail to load a refresh
|
||||
*/
|
||||
if ( cls.key_dest != key_console )
|
||||
{
|
||||
Con_ToggleConsole_f();
|
||||
}
|
||||
}
|
||||
cls.disable_screen = false;
|
||||
}
|
||||
|
||||
/*
|
||||
** update our window position
|
||||
*/
|
||||
if ( vid_xpos->modified || vid_ypos->modified )
|
||||
{
|
||||
if (!vid_fullscreen->value)
|
||||
VID_UpdateWindowPosAndSize( vid_xpos->value, vid_ypos->value );
|
||||
|
||||
vid_xpos->modified = false;
|
||||
vid_ypos->modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_Init
|
||||
============
|
||||
*/
|
||||
void VID_Init (void)
|
||||
{
|
||||
/* Create the video variables so we know how to start the graphics drivers */
|
||||
vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
|
||||
vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
|
||||
vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
|
||||
vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
|
||||
vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
|
||||
win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
|
||||
|
||||
/* Add some console commands that we want to handle */
|
||||
Cmd_AddCommand ("vid_restart", VID_Restart_f);
|
||||
Cmd_AddCommand ("vid_front", VID_Front_f);
|
||||
|
||||
/*
|
||||
** this is a gross hack but necessary to clamp the mode for 3Dfx
|
||||
*/
|
||||
#if 0
|
||||
{
|
||||
cvar_t *gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
|
||||
cvar_t *gl_mode = Cvar_Get( "gl_mode", "3", 0 );
|
||||
|
||||
if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
|
||||
{
|
||||
Cvar_SetValue( "gl_mode", 3 );
|
||||
viddef.width = 640;
|
||||
viddef.height = 480;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Disable the 3Dfx splash screen */
|
||||
putenv("FX_GLIDE_NO_SPLASH=0");
|
||||
|
||||
/* Start the graphics mode and load refresh DLL */
|
||||
VID_CheckChanges();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
VID_Shutdown
|
||||
============
|
||||
*/
|
||||
void VID_Shutdown (void)
|
||||
{
|
||||
if ( reflib_active )
|
||||
{
|
||||
re.Shutdown ();
|
||||
VID_FreeReflib ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
473
win32/vid_menu.c
Normal file
473
win32/vid_menu.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
#include "../client/client.h"
|
||||
#include "../client/qmenu.h"
|
||||
|
||||
#define REF_SOFT 0
|
||||
#define REF_OPENGL 1
|
||||
#define REF_3DFX 2
|
||||
#define REF_POWERVR 3
|
||||
#define REF_VERITE 4
|
||||
|
||||
extern cvar_t *vid_ref;
|
||||
extern cvar_t *vid_fullscreen;
|
||||
extern cvar_t *vid_gamma;
|
||||
extern cvar_t *scr_viewsize;
|
||||
|
||||
static cvar_t *gl_mode;
|
||||
static cvar_t *gl_driver;
|
||||
static cvar_t *gl_picmip;
|
||||
static cvar_t *gl_ext_palettedtexture;
|
||||
static cvar_t *gl_finish;
|
||||
|
||||
static cvar_t *sw_mode;
|
||||
static cvar_t *sw_stipplealpha;
|
||||
|
||||
extern void M_ForceMenuOff( void );
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
|
||||
MENU INTERACTION
|
||||
|
||||
====================================================================
|
||||
*/
|
||||
#define SOFTWARE_MENU 0
|
||||
#define OPENGL_MENU 1
|
||||
|
||||
static menuframework_s s_software_menu;
|
||||
static menuframework_s s_opengl_menu;
|
||||
static menuframework_s *s_current_menu;
|
||||
static int s_current_menu_index;
|
||||
|
||||
static menulist_s s_mode_list[2];
|
||||
static menulist_s s_ref_list[2];
|
||||
static menuslider_s s_tq_slider;
|
||||
static menuslider_s s_screensize_slider[2];
|
||||
static menuslider_s s_brightness_slider[2];
|
||||
static menulist_s s_fs_box[2];
|
||||
static menulist_s s_stipple_box;
|
||||
static menulist_s s_paletted_texture_box;
|
||||
static menulist_s s_finish_box;
|
||||
static menuaction_s s_cancel_action[2];
|
||||
static menuaction_s s_defaults_action[2];
|
||||
|
||||
static void DriverCallback( void *unused )
|
||||
{
|
||||
s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
|
||||
|
||||
if ( s_ref_list[s_current_menu_index].curvalue == 0 )
|
||||
{
|
||||
s_current_menu = &s_software_menu;
|
||||
s_current_menu_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_current_menu = &s_opengl_menu;
|
||||
s_current_menu_index = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void ScreenSizeCallback( void *s )
|
||||
{
|
||||
menuslider_s *slider = ( menuslider_s * ) s;
|
||||
|
||||
Cvar_SetValue( "viewsize", slider->curvalue * 10 );
|
||||
}
|
||||
|
||||
static void BrightnessCallback( void *s )
|
||||
{
|
||||
menuslider_s *slider = ( menuslider_s * ) s;
|
||||
|
||||
if ( s_current_menu_index == SOFTWARE_MENU )
|
||||
s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
|
||||
else
|
||||
s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
|
||||
|
||||
if ( stricmp( vid_ref->string, "soft" ) == 0 )
|
||||
{
|
||||
float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5;
|
||||
|
||||
Cvar_SetValue( "vid_gamma", gamma );
|
||||
}
|
||||
}
|
||||
|
||||
static void ResetDefaults( void *unused )
|
||||
{
|
||||
VID_MenuInit();
|
||||
}
|
||||
|
||||
static void ApplyChanges( void *unused )
|
||||
{
|
||||
float gamma;
|
||||
|
||||
/*
|
||||
** make values consistent
|
||||
*/
|
||||
s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
|
||||
s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
|
||||
s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
|
||||
|
||||
/*
|
||||
** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
|
||||
*/
|
||||
gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5;
|
||||
|
||||
Cvar_SetValue( "vid_gamma", gamma );
|
||||
Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
|
||||
Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
|
||||
Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
|
||||
Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
|
||||
Cvar_SetValue( "gl_finish", s_finish_box.curvalue );
|
||||
Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
|
||||
Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
|
||||
|
||||
switch ( s_ref_list[s_current_menu_index].curvalue )
|
||||
{
|
||||
case REF_SOFT:
|
||||
Cvar_Set( "vid_ref", "soft" );
|
||||
break;
|
||||
case REF_OPENGL:
|
||||
Cvar_Set( "vid_ref", "gl" );
|
||||
Cvar_Set( "gl_driver", "opengl32" );
|
||||
break;
|
||||
case REF_3DFX:
|
||||
Cvar_Set( "vid_ref", "gl" );
|
||||
Cvar_Set( "gl_driver", "3dfxgl" );
|
||||
break;
|
||||
case REF_POWERVR:
|
||||
Cvar_Set( "vid_ref", "gl" );
|
||||
Cvar_Set( "gl_driver", "pvrgl" );
|
||||
break;
|
||||
case REF_VERITE:
|
||||
Cvar_Set( "vid_ref", "gl" );
|
||||
Cvar_Set( "gl_driver", "veritegl" );
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** update appropriate stuff if we're running OpenGL and gamma
|
||||
** has been modified
|
||||
*/
|
||||
if ( stricmp( vid_ref->string, "gl" ) == 0 )
|
||||
{
|
||||
if ( vid_gamma->modified )
|
||||
{
|
||||
vid_ref->modified = true;
|
||||
if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
|
||||
{
|
||||
char envbuffer[1024];
|
||||
float g;
|
||||
|
||||
vid_ref->modified = true;
|
||||
|
||||
g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
|
||||
Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g );
|
||||
putenv( envbuffer );
|
||||
Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
|
||||
putenv( envbuffer );
|
||||
|
||||
vid_gamma->modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( gl_driver->modified )
|
||||
vid_ref->modified = true;
|
||||
}
|
||||
|
||||
M_ForceMenuOff();
|
||||
}
|
||||
|
||||
static void CancelChanges( void *unused )
|
||||
{
|
||||
extern void M_PopMenu( void );
|
||||
|
||||
M_PopMenu();
|
||||
}
|
||||
|
||||
/*
|
||||
** VID_MenuInit
|
||||
*/
|
||||
void VID_MenuInit( void )
|
||||
{
|
||||
static const char *resolutions[] =
|
||||
{
|
||||
"[320 240 ]",
|
||||
"[400 300 ]",
|
||||
"[512 384 ]",
|
||||
"[640 480 ]",
|
||||
"[800 600 ]",
|
||||
"[960 720 ]",
|
||||
"[1024 768 ]",
|
||||
"[1152 864 ]",
|
||||
"[1280 960 ]",
|
||||
"[1600 1200]",
|
||||
0
|
||||
};
|
||||
static const char *refs[] =
|
||||
{
|
||||
"[software ]",
|
||||
"[default OpenGL]",
|
||||
"[3Dfx OpenGL ]",
|
||||
"[PowerVR OpenGL]",
|
||||
// "[Rendition OpenGL]",
|
||||
0
|
||||
};
|
||||
static const char *yesno_names[] =
|
||||
{
|
||||
"no",
|
||||
"yes",
|
||||
0
|
||||
};
|
||||
int i;
|
||||
|
||||
if ( !gl_driver )
|
||||
gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
|
||||
if ( !gl_picmip )
|
||||
gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
|
||||
if ( !gl_mode )
|
||||
gl_mode = Cvar_Get( "gl_mode", "3", 0 );
|
||||
if ( !sw_mode )
|
||||
sw_mode = Cvar_Get( "sw_mode", "0", 0 );
|
||||
if ( !gl_ext_palettedtexture )
|
||||
gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
|
||||
if ( !gl_finish )
|
||||
gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE );
|
||||
|
||||
if ( !sw_stipplealpha )
|
||||
sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
|
||||
|
||||
s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value;
|
||||
s_mode_list[OPENGL_MENU].curvalue = gl_mode->value;
|
||||
|
||||
if ( !scr_viewsize )
|
||||
scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
|
||||
|
||||
s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10;
|
||||
s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10;
|
||||
|
||||
if ( strcmp( vid_ref->string, "soft" ) == 0 )
|
||||
{
|
||||
s_current_menu_index = SOFTWARE_MENU;
|
||||
s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
|
||||
}
|
||||
else if ( strcmp( vid_ref->string, "gl" ) == 0 )
|
||||
{
|
||||
s_current_menu_index = OPENGL_MENU;
|
||||
if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 )
|
||||
s_ref_list[s_current_menu_index].curvalue = REF_3DFX;
|
||||
else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 )
|
||||
s_ref_list[s_current_menu_index].curvalue = REF_POWERVR;
|
||||
else if ( strcmp( gl_driver->string, "opengl32" ) == 0 )
|
||||
s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
|
||||
else
|
||||
// s_ref_list[s_current_menu_index].curvalue = REF_VERITE;
|
||||
s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
|
||||
}
|
||||
|
||||
s_software_menu.x = viddef.width * 0.50;
|
||||
s_software_menu.nitems = 0;
|
||||
s_opengl_menu.x = viddef.width * 0.50;
|
||||
s_opengl_menu.nitems = 0;
|
||||
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
|
||||
s_ref_list[i].generic.name = "driver";
|
||||
s_ref_list[i].generic.x = 0;
|
||||
s_ref_list[i].generic.y = 0;
|
||||
s_ref_list[i].generic.callback = DriverCallback;
|
||||
s_ref_list[i].itemnames = refs;
|
||||
|
||||
s_mode_list[i].generic.type = MTYPE_SPINCONTROL;
|
||||
s_mode_list[i].generic.name = "video mode";
|
||||
s_mode_list[i].generic.x = 0;
|
||||
s_mode_list[i].generic.y = 10;
|
||||
s_mode_list[i].itemnames = resolutions;
|
||||
|
||||
s_screensize_slider[i].generic.type = MTYPE_SLIDER;
|
||||
s_screensize_slider[i].generic.x = 0;
|
||||
s_screensize_slider[i].generic.y = 20;
|
||||
s_screensize_slider[i].generic.name = "screen size";
|
||||
s_screensize_slider[i].minvalue = 3;
|
||||
s_screensize_slider[i].maxvalue = 12;
|
||||
s_screensize_slider[i].generic.callback = ScreenSizeCallback;
|
||||
|
||||
s_brightness_slider[i].generic.type = MTYPE_SLIDER;
|
||||
s_brightness_slider[i].generic.x = 0;
|
||||
s_brightness_slider[i].generic.y = 30;
|
||||
s_brightness_slider[i].generic.name = "brightness";
|
||||
s_brightness_slider[i].generic.callback = BrightnessCallback;
|
||||
s_brightness_slider[i].minvalue = 5;
|
||||
s_brightness_slider[i].maxvalue = 13;
|
||||
s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10;
|
||||
|
||||
s_fs_box[i].generic.type = MTYPE_SPINCONTROL;
|
||||
s_fs_box[i].generic.x = 0;
|
||||
s_fs_box[i].generic.y = 40;
|
||||
s_fs_box[i].generic.name = "fullscreen";
|
||||
s_fs_box[i].itemnames = yesno_names;
|
||||
s_fs_box[i].curvalue = vid_fullscreen->value;
|
||||
|
||||
s_defaults_action[i].generic.type = MTYPE_ACTION;
|
||||
s_defaults_action[i].generic.name = "reset to defaults";
|
||||
s_defaults_action[i].generic.x = 0;
|
||||
s_defaults_action[i].generic.y = 90;
|
||||
s_defaults_action[i].generic.callback = ResetDefaults;
|
||||
|
||||
s_cancel_action[i].generic.type = MTYPE_ACTION;
|
||||
s_cancel_action[i].generic.name = "cancel";
|
||||
s_cancel_action[i].generic.x = 0;
|
||||
s_cancel_action[i].generic.y = 100;
|
||||
s_cancel_action[i].generic.callback = CancelChanges;
|
||||
}
|
||||
|
||||
s_stipple_box.generic.type = MTYPE_SPINCONTROL;
|
||||
s_stipple_box.generic.x = 0;
|
||||
s_stipple_box.generic.y = 60;
|
||||
s_stipple_box.generic.name = "stipple alpha";
|
||||
s_stipple_box.curvalue = sw_stipplealpha->value;
|
||||
s_stipple_box.itemnames = yesno_names;
|
||||
|
||||
s_tq_slider.generic.type = MTYPE_SLIDER;
|
||||
s_tq_slider.generic.x = 0;
|
||||
s_tq_slider.generic.y = 60;
|
||||
s_tq_slider.generic.name = "texture quality";
|
||||
s_tq_slider.minvalue = 0;
|
||||
s_tq_slider.maxvalue = 3;
|
||||
s_tq_slider.curvalue = 3-gl_picmip->value;
|
||||
|
||||
s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL;
|
||||
s_paletted_texture_box.generic.x = 0;
|
||||
s_paletted_texture_box.generic.y = 70;
|
||||
s_paletted_texture_box.generic.name = "8-bit textures";
|
||||
s_paletted_texture_box.itemnames = yesno_names;
|
||||
s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value;
|
||||
|
||||
s_finish_box.generic.type = MTYPE_SPINCONTROL;
|
||||
s_finish_box.generic.x = 0;
|
||||
s_finish_box.generic.y = 80;
|
||||
s_finish_box.generic.name = "sync every frame";
|
||||
s_finish_box.curvalue = gl_finish->value;
|
||||
s_finish_box.itemnames = yesno_names;
|
||||
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box );
|
||||
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_finish_box );
|
||||
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_software_menu, ( void * ) &s_cancel_action[SOFTWARE_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] );
|
||||
Menu_AddItem( &s_opengl_menu, ( void * ) &s_cancel_action[OPENGL_MENU] );
|
||||
|
||||
Menu_Center( &s_software_menu );
|
||||
Menu_Center( &s_opengl_menu );
|
||||
s_opengl_menu.x -= 8;
|
||||
s_software_menu.x -= 8;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VID_MenuDraw
|
||||
================
|
||||
*/
|
||||
void VID_MenuDraw (void)
|
||||
{
|
||||
int w, h;
|
||||
|
||||
if ( s_current_menu_index == 0 )
|
||||
s_current_menu = &s_software_menu;
|
||||
else
|
||||
s_current_menu = &s_opengl_menu;
|
||||
|
||||
/*
|
||||
** draw the banner
|
||||
*/
|
||||
re.DrawGetPicSize( &w, &h, "m_banner_video" );
|
||||
re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
|
||||
|
||||
/*
|
||||
** move cursor to a reasonable starting position
|
||||
*/
|
||||
Menu_AdjustCursor( s_current_menu, 1 );
|
||||
|
||||
/*
|
||||
** draw the menu
|
||||
*/
|
||||
Menu_Draw( s_current_menu );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
VID_MenuKey
|
||||
================
|
||||
*/
|
||||
const char *VID_MenuKey( int key )
|
||||
{
|
||||
menuframework_s *m = s_current_menu;
|
||||
static const char *sound = "misc/menu1.wav";
|
||||
|
||||
switch ( key )
|
||||
{
|
||||
case K_ESCAPE:
|
||||
ApplyChanges( 0 );
|
||||
return NULL;
|
||||
case K_KP_UPARROW:
|
||||
case K_UPARROW:
|
||||
m->cursor--;
|
||||
Menu_AdjustCursor( m, -1 );
|
||||
break;
|
||||
case K_KP_DOWNARROW:
|
||||
case K_DOWNARROW:
|
||||
m->cursor++;
|
||||
Menu_AdjustCursor( m, 1 );
|
||||
break;
|
||||
case K_KP_LEFTARROW:
|
||||
case K_LEFTARROW:
|
||||
Menu_SlideItem( m, -1 );
|
||||
break;
|
||||
case K_KP_RIGHTARROW:
|
||||
case K_RIGHTARROW:
|
||||
Menu_SlideItem( m, 1 );
|
||||
break;
|
||||
case K_KP_ENTER:
|
||||
case K_ENTER:
|
||||
if ( !Menu_SelectItem( m ) )
|
||||
ApplyChanges( NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
|
||||
BIN
win32/winquake.aps
Normal file
BIN
win32/winquake.aps
Normal file
Binary file not shown.
44
win32/winquake.h
Normal file
44
win32/winquake.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// winquake.h: Win32-specific Quake header file
|
||||
|
||||
#pragma warning( disable : 4229 ) // mgraph gets this
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <dsound.h>
|
||||
|
||||
#define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE)
|
||||
|
||||
extern HINSTANCE global_hInstance;
|
||||
|
||||
extern LPDIRECTSOUND pDS;
|
||||
extern LPDIRECTSOUNDBUFFER pDSBuf;
|
||||
|
||||
extern DWORD gSndBufSize;
|
||||
|
||||
extern HWND cl_hwnd;
|
||||
extern qboolean ActiveApp, Minimized;
|
||||
|
||||
void IN_Activate (qboolean active);
|
||||
void IN_MouseEvent (int mstate);
|
||||
|
||||
extern int window_center_x, window_center_y;
|
||||
extern RECT window_rect;
|
||||
98
win32/winquake.rc
Normal file
98
win32/winquake.rc
Normal file
@@ -0,0 +1,98 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON1 ICON DISCARDABLE "q2.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_DIALOG1 DIALOGEX 0, 0, 62, 21
|
||||
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP |
|
||||
WS_VISIBLE
|
||||
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
|
||||
FONT 16, "Times New Roman", 0, 0, 0x1
|
||||
BEGIN
|
||||
CTEXT "Starting QW...",IDC_STATIC,4,6,54,8
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
BEGIN
|
||||
IDS_STRING1 "WinQuake"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
Reference in New Issue
Block a user