Quack 3: Arena

This commit is contained in:
Literally A Penguin
2024-09-25 15:40:36 -05:00
committed by GitHub
parent 0bf99969fd
commit 40035fa235
74 changed files with 36999 additions and 0 deletions

107
3.15_Changes.txt Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

852
ref_soft/r_rast.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

2
ref_soft/ref_soft.def Normal file
View File

@ -0,0 +1,2 @@
EXPORTS
GetRefAPI

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
View 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
View 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
View 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
View 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
View 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;
}

View File

@ -0,0 +1,2 @@
F test.app test app
F test test app

BIN
rhapsody/quake2.tiff Normal file

Binary file not shown.

735
rhapsody/r_next.m Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

580
rhapsody/swimp_rhap.m Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

341
server/server.h Normal file
View 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

File diff suppressed because it is too large Load Diff

727
server/sv_ents.c Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

15
server/sv_null.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
int main(int argc, char *argv)
{
}

164
solaris/glob.c Normal file
View 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
View File

@ -0,0 +1 @@
int glob_match(char *pattern, char *text);

537
solaris/net_udp.c Normal file
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

510
win32/cd_win.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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 (&current_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
View 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

Binary file not shown.

BIN
win32/q2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

72
win32/q2.rc Normal file
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

4133
win32/qgl_win.c Normal file

File diff suppressed because it is too large Load Diff

16
win32/resource.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

44
win32/winquake.h Normal file
View 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
View 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