summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile131
-rw-r--r--src/asm/matha.s370
-rw-r--r--src/asm/qasm.h9
-rw-r--r--src/client/cl_avi.c2
-rw-r--r--src/client/cl_cgame.c2
-rw-r--r--src/client/cl_main.c114
-rw-r--r--src/client/cl_ui.c2
-rw-r--r--src/client/snd_dma.c11
-rw-r--r--src/client/snd_main.c5
-rw-r--r--src/client/snd_openal.c53
-rw-r--r--src/libspeex/config.h3
-rw-r--r--src/qcommon/cmd.c10
-rw-r--r--src/qcommon/common.c46
-rw-r--r--src/qcommon/cvar.c69
-rw-r--r--src/qcommon/files.c29
-rw-r--r--src/qcommon/net_ip.c259
-rw-r--r--src/qcommon/q_math.c330
-rw-r--r--src/qcommon/q_platform.h9
-rw-r--r--src/qcommon/q_shared.h14
-rw-r--r--src/qcommon/qcommon.h14
-rw-r--r--src/qcommon/vm.c11
-rw-r--r--src/qcommon/vm_sparc.c1648
-rw-r--r--src/qcommon/vm_sparc.h78
-rw-r--r--src/qcommon/vm_x86.c26
-rw-r--r--src/qcommon/vm_x86_64.c2
-rw-r--r--src/renderer/tr_init.c13
-rw-r--r--src/renderer/tr_local.h1
-rw-r--r--src/renderer/tr_main.c6
-rw-r--r--src/renderer/tr_noise.c2
-rw-r--r--src/renderer/tr_scene.c8
-rw-r--r--src/renderer/tr_surface.c30
-rw-r--r--src/sdl/sdl_glimp.c67
-rw-r--r--src/sdl/sdl_input.c23
-rw-r--r--src/server/server.h3
-rw-r--r--src/server/sv_client.c33
-rw-r--r--src/server/sv_game.c3
-rw-r--r--src/server/sv_init.c15
-rw-r--r--src/server/sv_main.c107
-rw-r--r--src/server/sv_net_chan.c60
-rw-r--r--src/server/sv_snapshot.c3
-rw-r--r--src/server/sv_world.c6
-rw-r--r--src/sys/con_tty.c18
-rw-r--r--src/sys/sys_cocoa.m40
-rw-r--r--src/sys/sys_local.h1
-rw-r--r--src/sys/sys_main.c13
-rw-r--r--src/sys/sys_unix.c58
-rw-r--r--src/sys/sys_win32.c19
-rw-r--r--src/tools/asm/cmdlib.c8
-rw-r--r--src/tools/asm/q3asm.c17
49 files changed, 2656 insertions, 1145 deletions
diff --git a/Makefile b/Makefile
index ee4105e5..fab90efc 100644
--- a/Makefile
+++ b/Makefile
@@ -85,6 +85,10 @@ ifndef COPYDIR
COPYDIR="/usr/local/games/tremulous"
endif
+ifndef COPYBINDIR
+COPYBINDIR=$(COPYDIR)
+endif
+
ifndef MOUNT_DIR
MOUNT_DIR=src
endif
@@ -183,6 +187,13 @@ ifeq ($(shell which pkg-config > /dev/null; echo $$?),0)
SDL_CFLAGS=$(shell pkg-config --cflags sdl|sed 's/-Dmain=SDL_main//')
SDL_LIBS=$(shell pkg-config --libs sdl)
endif
+# Use sdl-config if all else fails
+ifeq ($(SDL_CFLAGS),)
+ ifeq ($(shell which sdl-config > /dev/null; echo $$?),0)
+ SDL_CFLAGS=$(shell sdl-config --cflags)
+ SDL_LIBS=$(shell sdl-config --libs)
+ endif
+endif
# version info
VERSION=1.1.0
@@ -226,7 +237,7 @@ ifeq ($(PLATFORM),linux)
endif
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON $(shell sdl-config --cflags)
+ -pipe -DUSE_ICON $(SDL_CFLAGS)
ifeq ($(USE_OPENAL),1)
BASE_CFLAGS += -DUSE_OPENAL
@@ -269,6 +280,10 @@ ifeq ($(PLATFORM),linux)
BASE_CFLAGS += -maltivec
HAVE_VM_COMPILED=true
endif
+ ifeq ($(ARCH),sparc)
+ OPTIMIZE += -mtune=ultrasparc3 -mv8plus
+ HAVE_VM_COMPILED=true
+ endif
endif
endif
@@ -277,13 +292,13 @@ ifeq ($(PLATFORM),linux)
endif
SHLIBEXT=so
- SHLIBCFLAGS=-fPIC
+ SHLIBCFLAGS=-fPIC -fvisibility=hidden
SHLIBLDFLAGS=-shared $(LDFLAGS)
THREAD_LIBS=-lpthread
LIBS=-ldl -lm
- CLIENT_LIBS=$(shell sdl-config --libs) -lGL
+ CLIENT_LIBS=$(SDL_LIBS) -lGL
ifeq ($(USE_OPENAL),1)
ifneq ($(USE_OPENAL_DLOPEN),1)
@@ -513,7 +528,7 @@ ifeq ($(PLATFORM),freebsd)
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON $(shell sdl-config --cflags)
+ -DUSE_ICON $(SDL_CFLAGS)
ifeq ($(USE_OPENAL),1)
BASE_CFLAGS += -DUSE_OPENAL
@@ -554,7 +569,7 @@ ifeq ($(PLATFORM),freebsd)
CLIENT_LIBS =
- CLIENT_LIBS += $(shell sdl-config --libs) -lGL
+ CLIENT_LIBS += $(SDL_LIBS) -lGL
ifeq ($(USE_OPENAL),1)
ifneq ($(USE_OPENAL_DLOPEN),1)
@@ -579,7 +594,7 @@ ifeq ($(PLATFORM),openbsd)
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -DUSE_ICON $(shell sdl-config --cflags)
+ -DUSE_ICON $(SDL_CFLAGS)
ifeq ($(USE_OPENAL),1)
BASE_CFLAGS += -DUSE_OPENAL
@@ -592,25 +607,28 @@ ifeq ($(PLATFORM),openbsd)
BASE_CFLAGS += -DUSE_CODEC_VORBIS
endif
- BASE_CFLAGS += -DNO_VM_COMPILED -I/usr/X11R6/include -I/usr/local/include
- RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 \
- -march=pentium -fomit-frame-pointer -pipe -ffast-math \
- -falign-loops=2 -falign-jumps=2 -falign-functions=2 \
- -funroll-loops -fstrength-reduce
+ ifeq ($(USE_CURL),1)
+ BASE_CFLAGS += -DUSE_CURL $(CURL_CFLAGS)
+ USE_CURL_DLOPEN=0
+ endif
+
+ BASE_CFLAGS += -DNO_VM_COMPILED
+ RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG
HAVE_VM_COMPILED=false
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
SHLIBEXT=so
+ SHLIBNAME=.$(SHLIBEXT)
SHLIBCFLAGS=-fPIC
SHLIBLDFLAGS=-shared $(LDFLAGS)
- THREAD_LIBS=-lpthread
+ THREAD_LIBS=-pthread
LIBS=-lm
CLIENT_LIBS =
- CLIENT_LIBS += $(shell sdl-config --libs) -lGL
+ CLIENT_LIBS += $(SDL_LIBS) -lGL
ifeq ($(USE_OPENAL),1)
ifneq ($(USE_OPENAL_DLOPEN),1)
@@ -622,6 +640,12 @@ ifeq ($(PLATFORM),openbsd)
CLIENT_LIBS += -lvorbisfile -lvorbis -logg
endif
+ ifeq ($(USE_CURL),1)
+ ifneq ($(USE_CURL_DLOPEN),1)
+ CLIENT_LIBS += -lcurl
+ endif
+ endif
+
else # ifeq openbsd
#############################################################################
@@ -665,7 +689,7 @@ ifeq ($(PLATFORM),irix64)
MKDIR = mkdir -p
BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \
- -I. $(shell sdl-config --cflags) -I$(ROOT)/usr/include -DNO_VM_COMPILED
+ -I. $(SDL_CFLAGS) -I$(ROOT)/usr/include -DNO_VM_COMPILED
RELEASE_CFLAGS=$(BASE_CFLAGS) -O3
DEBUG_CFLAGS=$(BASE_CFLAGS) -g
@@ -675,7 +699,7 @@ ifeq ($(PLATFORM),irix64)
LIBS=-ldl -lm -lgen
# FIXME: The X libraries probably aren't necessary?
- CLIENT_LIBS=-L/usr/X11/$(LIB) $(shell sdl-config --libs) -lGL \
+ CLIENT_LIBS=-L/usr/X11/$(LIB) $(SDL_LIBS) -lGL \
-lX11 -lXext -lm
else # ifeq IRIX
@@ -703,9 +727,8 @@ ifeq ($(PLATFORM),sunos)
endif
endif
-
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON $(shell sdl-config --cflags)
+ -pipe -DUSE_ICON $(SDL_CFLAGS)
OPTIMIZE = -O3 -ffast-math -funroll-loops
@@ -714,6 +737,7 @@ ifeq ($(PLATFORM),sunos)
-fstrength-reduce -falign-functions=2 \
-mtune=ultrasparc3 -mv8plus -mno-faster-structs \
-funroll-loops #-mv8plus
+ HAVE_VM_COMPILED=true
else
ifeq ($(ARCH),x86)
OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \
@@ -743,7 +767,7 @@ ifeq ($(PLATFORM),sunos)
BOTCFLAGS=-O0
- CLIENT_LIBS +=$(shell sdl-config --libs) -lGL
+ CLIENT_LIBS +=$(SDL_LIBS) -lGL -lX11 -lXext -liconv -lm
else # ifeq sunos
@@ -769,22 +793,30 @@ endif #SunOS
TARGETS =
+ifndef FULLBINEXT
+ FULLBINEXT=.$(ARCH)$(BINEXT)
+endif
+
+ifndef SHLIBNAME
+ SHLIBNAME=$(ARCH).$(SHLIBEXT)
+endif
+
ifneq ($(BUILD_SERVER),0)
- TARGETS += $(B)/tremded.$(ARCH)$(BINEXT)
+ TARGETS += $(B)/tremded$(FULLBINEXT)
endif
ifneq ($(BUILD_CLIENT),0)
- TARGETS += $(B)/tremulous.$(ARCH)$(BINEXT)
+ TARGETS += $(B)/tremulous$(FULLBINEXT)
ifneq ($(BUILD_CLIENT_SMP),0)
- TARGETS += $(B)/tremulous-smp.$(ARCH)$(BINEXT)
+ TARGETS += $(B)/tremulous-smp$(FULLBINEXT)
endif
endif
ifneq ($(BUILD_GAME_SO),0)
TARGETS += \
- $(B)/base/cgame$(ARCH).$(SHLIBEXT) \
- $(B)/base/game$(ARCH).$(SHLIBEXT) \
- $(B)/base/ui$(ARCH).$(SHLIBEXT)
+ $(B)/base/cgame$(SHLIBNAME) \
+ $(B)/base/game$(SHLIBNAME) \
+ $(B)/base/ui$(SHLIBNAME)
endif
ifneq ($(BUILD_GAME_QVM),0)
@@ -805,7 +837,7 @@ ifeq ($(USE_VOIP),1)
ifeq ($(USE_INTERNAL_SPEEX),1)
BASE_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include
else
- CLIENT_LIBS += -lspeex
+ CLIENT_LIBS += -lspeex -lspeexdsp
endif
endif
@@ -827,6 +859,12 @@ else
DEPEND_CFLAGS =
endif
+ifeq ($(NO_STRIP),1)
+ STRIP_FLAG =
+else
+ STRIP_FLAG = -s
+endif
+
BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\"
ifeq ($(V),1)
@@ -942,6 +980,12 @@ targets: makedirs
echo " $$i"; \
done
@echo ""
+ @echo " CLIENT_LIBS:"
+ -@for i in $(CLIENT_LIBS); \
+ do \
+ echo " $$i"; \
+ done
+ @echo ""
@echo " Output:"
-@for i in $(TARGETS); \
do \
@@ -976,10 +1020,10 @@ makedirs:
#############################################################################
TOOLS_OPTIMIZE = -g -O2 -Wall -fno-strict-aliasing
-TOOLS_CFLAGS = $(TOOLS_OPTIMIZE) \
- -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
- -I$(Q3LCCSRCDIR) \
- -I$(LBURGDIR)
+TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \
+ -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \
+ -I$(Q3LCCSRCDIR) \
+ -I$(LBURGDIR)
TOOLS_LIBS =
TOOLS_LDFLAGS =
@@ -1332,6 +1376,9 @@ ifeq ($(HAVE_VM_COMPILED),true)
ifeq ($(ARCH),ppc64)
Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o
endif
+ ifeq ($(ARCH),sparc)
+ Q3OBJ += $(B)/client/vm_sparc.o
+ endif
endif
ifeq ($(PLATFORM),mingw32)
@@ -1343,6 +1390,11 @@ else
$(B)/client/sys_unix.o
endif
+ifeq ($(PLATFORM),darwin)
+ Q3OBJ += \
+ $(B)/client/sys_cocoa.o
+endif
+
ifeq ($(USE_MUMBLE),1)
Q3OBJ += \
$(B)/client/libmumblelink.o
@@ -1354,13 +1406,13 @@ Q3POBJ += \
Q3POBJ_SMP += \
$(B)/clientsmp/sdl_glimp.o
-$(B)/tremulous.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
+$(B)/tremulous$(FULLBINEXT): $(Q3OBJ) $(Q3POBJ) $(LIBSDLMAIN)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \
-o $@ $(Q3OBJ) $(Q3POBJ) \
$(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS)
-$(B)/tremulous-smp.$(ARCH)$(BINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
+$(B)/tremulous-smp$(FULLBINEXT): $(Q3OBJ) $(Q3POBJ_SMP) $(LIBSDLMAIN)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \
-o $@ $(Q3OBJ) $(Q3POBJ_SMP) \
@@ -1440,6 +1492,9 @@ ifeq ($(HAVE_VM_COMPILED),true)
ifeq ($(ARCH),ppc64)
Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o
endif
+ ifeq ($(ARCH),sparc)
+ Q3DOBJ += $(B)/ded/vm_sparc.o
+ endif
endif
ifeq ($(PLATFORM),mingw32)
@@ -1453,7 +1508,7 @@ else
$(B)/ded/con_tty.o
endif
-$(B)/tremded.$(ARCH)$(BINEXT): $(Q3DOBJ)
+$(B)/tremded$(FULLBINEXT): $(Q3DOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS)
@@ -1501,7 +1556,7 @@ CGOBJ_ = \
CGOBJ = $(CGOBJ_) $(B)/base/cgame/cg_syscalls.o
CGVMOBJ = $(CGOBJ_:%.o=%.asm)
-$(B)/base/cgame$(ARCH).$(SHLIBEXT): $(CGOBJ)
+$(B)/base/cgame$(SHLIBNAME): $(CGOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CGOBJ)
@@ -1550,7 +1605,7 @@ GOBJ_ = \
GOBJ = $(GOBJ_) $(B)/base/game/g_syscalls.o
GVMOBJ = $(GOBJ_:%.o=%.asm)
-$(B)/base/game$(ARCH).$(SHLIBEXT): $(GOBJ)
+$(B)/base/game$(SHLIBNAME): $(GOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GOBJ)
@@ -1578,7 +1633,7 @@ UIOBJ_ = \
UIOBJ = $(UIOBJ_) $(B)/base/ui/ui_syscalls.o
UIVMOBJ = $(UIOBJ_:%.o=%.asm)
-$(B)/base/ui$(ARCH).$(SHLIBEXT): $(UIOBJ)
+$(B)/base/ui$(SHLIBNAME): $(UIOBJ)
$(echo_cmd) "LD $@"
$(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(UIOBJ)
@@ -1622,6 +1677,9 @@ $(B)/clientsmp/%.o: $(SDLDIR)/%.c
$(B)/client/%.o: $(SYSDIR)/%.c
$(DO_CC)
+$(B)/client/%.o: $(SYSDIR)/%.m
+ $(DO_CC)
+
$(B)/client/%.o: $(SYSDIR)/%.rc
$(DO_WINDRES)
@@ -1638,6 +1696,9 @@ $(B)/ded/%.o: $(CMDIR)/%.c
$(B)/ded/%.o: $(SYSDIR)/%.c
$(DO_DED_CC)
+$(B)/ded/%.o: $(SYSDIR)/%.m
+ $(DO_DED_CC)
+
$(B)/ded/%.o: $(SYSDIR)/%.rc
$(DO_WINDRES)
diff --git a/src/asm/matha.s b/src/asm/matha.s
index 3bc22204..e4770d37 100644
--- a/src/asm/matha.s
+++ b/src/asm/matha.s
@@ -28,12 +28,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#if id386
- .data
-
- .align 4
-Ljmptab: .long Lcase0, Lcase1, Lcase2, Lcase3
- .long Lcase4, Lcase5, Lcase6, Lcase7
-
.text
// TODO: rounding needed?
@@ -57,368 +51,4 @@ LOutOfRange:
movl $0xFFFFFFFF,%eax
ret
-#if 0
-
-#define in 4
-#define out 8
-
- .align 2
-.globl C(TransformVector)
-C(TransformVector):
- movl in(%esp),%eax
- movl out(%esp),%edx
-
- flds (%eax) // in[0]
- fmuls C(vright) // in[0]*vright[0]
- flds (%eax) // in[0] | in[0]*vright[0]
- fmuls C(vup) // in[0]*vup[0] | in[0]*vright[0]
- flds (%eax) // in[0] | in[0]*vup[0] | in[0]*vright[0]
- fmuls C(vpn) // in[0]*vpn[0] | in[0]*vup[0] | in[0]*vright[0]
-
- flds 4(%eax) // in[1] | ...
- fmuls C(vright)+4 // in[1]*vright[1] | ...
- flds 4(%eax) // in[1] | in[1]*vright[1] | ...
- fmuls C(vup)+4 // in[1]*vup[1] | in[1]*vright[1] | ...
- flds 4(%eax) // in[1] | in[1]*vup[1] | in[1]*vright[1] | ...
- fmuls C(vpn)+4 // in[1]*vpn[1] | in[1]*vup[1] | in[1]*vright[1] | ...
- fxch %st(2) // in[1]*vright[1] | in[1]*vup[1] | in[1]*vpn[1] | ...
-
- faddp %st(0),%st(5) // in[1]*vup[1] | in[1]*vpn[1] | ...
- faddp %st(0),%st(3) // in[1]*vpn[1] | ...
- faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum
-
- flds 8(%eax) // in[2] | ...
- fmuls C(vright)+8 // in[2]*vright[2] | ...
- flds 8(%eax) // in[2] | in[2]*vright[2] | ...
- fmuls C(vup)+8 // in[2]*vup[2] | in[2]*vright[2] | ...
- flds 8(%eax) // in[2] | in[2]*vup[2] | in[2]*vright[2] | ...
- fmuls C(vpn)+8 // in[2]*vpn[2] | in[2]*vup[2] | in[2]*vright[2] | ...
- fxch %st(2) // in[2]*vright[2] | in[2]*vup[2] | in[2]*vpn[2] | ...
-
- faddp %st(0),%st(5) // in[2]*vup[2] | in[2]*vpn[2] | ...
- faddp %st(0),%st(3) // in[2]*vpn[2] | ...
- faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum
-
- fstps 8(%edx) // out[2]
- fstps 4(%edx) // out[1]
- fstps (%edx) // out[0]
-
- ret
-
-#endif
-
-#define EMINS 4+4
-#define EMAXS 4+8
-#define P 4+12
-
- .align 2
-.globl C(BoxOnPlaneSide)
-C(BoxOnPlaneSide):
- pushl %ebx
-
- movl P(%esp),%edx
- movl EMINS(%esp),%ecx
- xorl %eax,%eax
- movl EMAXS(%esp),%ebx
- movb pl_signbits(%edx),%al
- cmpb $8,%al
- jge Lerror
- flds pl_normal(%edx) // p->normal[0]
- fld %st(0) // p->normal[0] | p->normal[0]
- // bk000422 - warning: missing prefix `*' in absolute indirect address, maybe misassembled!
- // bk001129 - fix from Andrew Henderson, was: Ljmptab(,%eax,4)
- jmp *Ljmptab(,%eax,4)
-
-
-//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
-//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
-Lcase0:
- fmuls (%ebx) // p->normal[0]*emaxs[0] | p->normal[0]
- flds pl_normal+4(%edx) // p->normal[1] | p->normal[0]*emaxs[0] |
- // p->normal[0]
- fxch %st(2) // p->normal[0] | p->normal[0]*emaxs[0] |
- // p->normal[1]
- fmuls (%ecx) // p->normal[0]*emins[0] |
- // p->normal[0]*emaxs[0] | p->normal[1]
- fxch %st(2) // p->normal[1] | p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fld %st(0) // p->normal[1] | p->normal[1] |
- // p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fmuls 4(%ebx) // p->normal[1]*emaxs[1] | p->normal[1] |
- // p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- flds pl_normal+8(%edx) // p->normal[2] | p->normal[1]*emaxs[1] |
- // p->normal[1] | p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fxch %st(2) // p->normal[1] | p->normal[1]*emaxs[1] |
- // p->normal[2] | p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fmuls 4(%ecx) // p->normal[1]*emins[1] |
- // p->normal[1]*emaxs[1] |
- // p->normal[2] | p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fxch %st(2) // p->normal[2] | p->normal[1]*emaxs[1] |
- // p->normal[1]*emins[1] |
- // p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fld %st(0) // p->normal[2] | p->normal[2] |
- // p->normal[1]*emaxs[1] |
- // p->normal[1]*emins[1] |
- // p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fmuls 8(%ebx) // p->normal[2]*emaxs[2] |
- // p->normal[2] |
- // p->normal[1]*emaxs[1] |
- // p->normal[1]*emins[1] |
- // p->normal[0]*emaxs[0] |
- // p->normal[0]*emins[0]
- fxch %st(5) // p->normal[0]*emins[0] |
- // p->normal[2] |
- // p->normal[1]*emaxs[1] |
- // p->normal[1]*emins[1] |
- // p->normal[0]*emaxs[0] |
- // p->normal[2]*emaxs[2]
- faddp %st(0),%st(3) //p->normal[2] |
- // p->normal[1]*emaxs[1] |
- // p->normal[1]*emins[1]+p->normal[0]*emins[0]|
- // p->normal[0]*emaxs[0] |
- // p->normal[2]*emaxs[2]
- fmuls 8(%ecx) //p->normal[2]*emins[2] |
- // p->normal[1]*emaxs[1] |
- // p->normal[1]*emins[1]+p->normal[0]*emins[0]|
- // p->normal[0]*emaxs[0] |
- // p->normal[2]*emaxs[2]
- fxch %st(1) //p->normal[1]*emaxs[1] |
- // p->normal[2]*emins[2] |
- // p->normal[1]*emins[1]+p->normal[0]*emins[0]|
- // p->normal[0]*emaxs[0] |
- // p->normal[2]*emaxs[2]
- faddp %st(0),%st(3) //p->normal[2]*emins[2] |
- // p->normal[1]*emins[1]+p->normal[0]*emins[0]|
- // p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]|
- // p->normal[2]*emaxs[2]
- fxch %st(3) //p->normal[2]*emaxs[2] +
- // p->normal[1]*emins[1]+p->normal[0]*emins[0]|
- // p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]|
- // p->normal[2]*emins[2]
- faddp %st(0),%st(2) //p->normal[1]*emins[1]+p->normal[0]*emins[0]|
- // dist1 | p->normal[2]*emins[2]
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
-//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
-Lcase1:
- fmuls (%ecx) // emins[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ebx) // emaxs[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ebx) // emaxs[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ecx) // emins[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ecx) // emins[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
-//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
-Lcase2:
- fmuls (%ebx) // emaxs[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ecx) // emins[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ecx) // emins[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ebx) // emaxs[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ecx) // emins[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
-//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
-Lcase3:
- fmuls (%ecx) // emins[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ebx) // emaxs[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ecx) // emins[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ebx) // emaxs[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ecx) // emins[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
-//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
-Lcase4:
- fmuls (%ebx) // emaxs[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ecx) // emins[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ebx) // emaxs[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ecx) // emins[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ecx) // emins[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
-//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
-Lcase5:
- fmuls (%ecx) // emins[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ebx) // emaxs[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ebx) // emaxs[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ecx) // emins[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ecx) // emins[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
-//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
-Lcase6:
- fmuls (%ebx) // emaxs[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ecx) // emins[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ecx) // emins[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ebx) // emaxs[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ecx) // emins[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
- jmp LSetSides
-
-//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
-//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
-Lcase7:
- fmuls (%ecx) // emins[0]
- flds pl_normal+4(%edx)
- fxch %st(2)
- fmuls (%ebx) // emaxs[0]
- fxch %st(2)
- fld %st(0)
- fmuls 4(%ecx) // emins[1]
- flds pl_normal+8(%edx)
- fxch %st(2)
- fmuls 4(%ebx) // emaxs[1]
- fxch %st(2)
- fld %st(0)
- fmuls 8(%ecx) // emins[2]
- fxch %st(5)
- faddp %st(0),%st(3)
- fmuls 8(%ebx) // emaxs[2]
- fxch %st(1)
- faddp %st(0),%st(3)
- fxch %st(3)
- faddp %st(0),%st(2)
-
-LSetSides:
-
-// sides = 0;
-// if (dist1 >= p->dist)
-// sides = 1;
-// if (dist2 < p->dist)
-// sides |= 2;
-
- faddp %st(0),%st(2) // dist1 | dist2
- fcomps pl_dist(%edx)
- xorl %ecx,%ecx
- fnstsw %ax
- fcomps pl_dist(%edx)
- andb $1,%ah
- xorb $1,%ah
- addb %ah,%cl
-
- fnstsw %ax
- andb $1,%ah
- addb %ah,%ah
- addb %ah,%cl
-
-// return sides;
-
- popl %ebx
- movl %ecx,%eax // return status
-
- ret
-
-
-Lerror:
- movl 1, %eax
- ret
-
#endif // id386
diff --git a/src/asm/qasm.h b/src/asm/qasm.h
index b26e9524..e12e2adb 100644
--- a/src/asm/qasm.h
+++ b/src/asm/qasm.h
@@ -34,13 +34,4 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define C(label) _##label
#endif
-// plane_t structure
-// !!! if this is changed, it must be changed in q_shared.h too !!!
-#define pl_normal 0
-#define pl_dist 12
-#define pl_type 16
-#define pl_signbits 17
-#define pl_pad 18
-#define pl_size 20
-
#endif
diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c
index df7bc7b9..fee1340e 100644
--- a/src/client/cl_avi.c
+++ b/src/client/cl_avi.c
@@ -555,7 +555,7 @@ void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size )
afd.numAudioFrames++;
afd.moviSize += ( chunkSize + paddingSize );
- afd.a.totalBytes =+ bytesInBuffer;
+ afd.a.totalBytes += bytesInBuffer;
// Index
bufIndex = 0;
diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c
index 9a16d3bf..d30d4ac0 100644
--- a/src/client/cl_cgame.c
+++ b/src/client/cl_cgame.c
@@ -336,6 +336,8 @@ rescan:
// clear notify lines and outgoing commands before passing
// the restart to the cgame
Con_ClearNotify();
+ // reparse the string, because Con_ClearNotify() may have done another Cmd_TokenizeString()
+ Cmd_TokenizeString( s );
Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) );
return qtrue;
}
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 47cf0196..16fbe56b 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -194,8 +194,10 @@ void CL_UpdateVoipIgnore(const char *idstr, qboolean ignore)
ignore ? "ignore" : "unignore", id));
Com_Printf("VoIP: %s ignoring player #%d\n",
ignore ? "Now" : "No longer", id);
+ return;
}
}
+ Com_Printf("VoIP: invalid player ID#\n");
}
static
@@ -234,7 +236,19 @@ void CL_Voip_f( void )
} else if (strcmp(cmd, "unignore") == 0) {
CL_UpdateVoipIgnore(Cmd_Argv(2), qfalse);
} else if (strcmp(cmd, "gain") == 0) {
- CL_UpdateVoipGain(Cmd_Argv(2), atof(Cmd_Argv(3)));
+ if (Cmd_Argc() > 3) {
+ CL_UpdateVoipGain(Cmd_Argv(2), atof(Cmd_Argv(3)));
+ } else if (Q_isanumber(Cmd_Argv(2))) {
+ int id = atoi(Cmd_Argv(2));
+ if (id >= 0 && id < MAX_CLIENTS) {
+ Com_Printf("VoIP: current gain for player #%d "
+ "is %f\n", id, clc.voipGain[id]);
+ } else {
+ Com_Printf("VoIP: invalid player ID#\n");
+ }
+ } else {
+ Com_Printf("usage: voip gain <playerID#> [value]\n");
+ }
} else if (strcmp(cmd, "muteall") == 0) {
Com_Printf("VoIP: muting incoming voice\n");
CL_AddReliableCommand("voip muteall");
@@ -243,6 +257,10 @@ void CL_Voip_f( void )
Com_Printf("VoIP: unmuting incoming voice\n");
CL_AddReliableCommand("voip unmuteall");
clc.voipMuteAll = qfalse;
+ } else {
+ Com_Printf("usage: voip [un]ignore <playerID#>\n"
+ " voip [un]muteall\n"
+ " voip gain <playerID#> [value]\n");
}
}
@@ -1354,11 +1372,7 @@ void CL_RequestMotd( void ) {
NET_AdrToStringwPort( cls.updateServer ) );
info[0] = 0;
- // NOTE TTimo xoring against Com_Milliseconds, otherwise we may not have a true randomization
- // only srand I could catch before here is tr_noise.c l:26 srand(1001)
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=382
- // NOTE: the Com_Milliseconds xoring only affects the lower 16-bit word,
- // but I decided it was enough randomization
+
Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ),
"%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());
@@ -1531,10 +1545,14 @@ void CL_Connect_f( void ) {
// if we aren't playing on a lan, we need to authenticate
// with the cd key
- if ( NET_IsLocalAddress( clc.serverAddress ) ) {
+ if(NET_IsLocalAddress(clc.serverAddress))
cls.state = CA_CHALLENGING;
- } else {
+ else
+ {
cls.state = CA_CONNECTING;
+
+ // Set a client challenge number that ideally is mirrored back by the server.
+ clc.challenge = ((rand() << 16) ^ rand()) ^ Com_Milliseconds();
}
Key_SetCatcher( 0 );
@@ -2129,7 +2147,11 @@ void CL_CheckForResend( void ) {
switch ( cls.state ) {
case CA_CONNECTING:
// requesting a challenge
- NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "getchallenge");
+
+ // The challenge request shall be followed by a client challenge so no malicious server can hijack this connection.
+ Com_sprintf(data, sizeof(data), "getchallenge %d", clc.challenge);
+
+ NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "%s", data);
break;
case CA_CHALLENGING:
@@ -2505,8 +2527,7 @@ Responses to broadcasts, etc
*/
void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
char *s;
- char c[ BIG_INFO_STRING ];
- char arg1[ BIG_INFO_STRING ];
+ char *c;
MSG_BeginReadingOOB( msg );
MSG_ReadLong( msg ); // skip the -1
@@ -2515,27 +2536,44 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
Cmd_TokenizeString( s );
- Q_strncpyz( c, Cmd_Argv( 0 ), BIG_INFO_STRING );
- Q_strncpyz( arg1, Cmd_Argv( 1 ), BIG_INFO_STRING );
+ c = Cmd_Argv(0);
Com_DPrintf ("CL packet %s: %s\n", NET_AdrToStringwPort(from), c);
// challenge from the server we are connecting to
- if ( !Q_stricmp(c, "challengeResponse") ) {
- if ( cls.state != CA_CONNECTING ) {
- Com_DPrintf( "Unwanted challenge response received. Ignored.\n" );
- } else {
- // start sending challenge repsonse instead of challenge request packets
- clc.challenge = atoi(arg1);
- cls.state = CA_CHALLENGING;
- clc.connectPacketCount = 0;
- clc.connectTime = -99999;
-
- // take this address as the new server address. This allows
- // a server proxy to hand off connections to multiple servers
- clc.serverAddress = from;
- Com_DPrintf ("challengeResponse: %d\n", clc.challenge);
+ if (!Q_stricmp(c, "challengeResponse"))
+ {
+ if (cls.state != CA_CONNECTING)
+ {
+ Com_DPrintf("Unwanted challenge response received. Ignored.\n");
+ return;
+ }
+
+ if(!NET_CompareAdr(from, clc.serverAddress))
+ {
+ // This challenge response is not coming from the expected address.
+ // Check whether we have a matching client challenge to prevent
+ // connection hi-jacking.
+
+ c = Cmd_Argv(2);
+
+ if(!*c || atoi(c) != clc.challenge)
+ {
+ Com_DPrintf("Challenge response received from unexpected source. Ignored.\n");
+ return;
+ }
}
+
+ // start sending challenge response instead of challenge request packets
+ clc.challenge = atoi(Cmd_Argv(1));
+ cls.state = CA_CHALLENGING;
+ clc.connectPacketCount = 0;
+ clc.connectTime = -99999;
+
+ // take this address as the new server address. This allows
+ // a server proxy to hand off connections to multiple servers
+ clc.serverAddress = from;
+ Com_DPrintf ("challengeResponse: %d\n", clc.challenge);
return;
}
@@ -2546,13 +2584,11 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
return;
}
if ( cls.state != CA_CHALLENGING ) {
- Com_Printf ("connectResponse packet while not connecting. Ignored.\n");
+ Com_Printf ("connectResponse packet while not connecting. Ignored.\n");
return;
}
- if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) {
- Com_Printf( "connectResponse from a different address. Ignored.\n" );
- Com_Printf( "%s should have been %s\n", NET_AdrToStringwPort( from ),
- NET_AdrToStringwPort( clc.serverAddress ) );
+ if ( !NET_CompareAdr( from, clc.serverAddress ) ) {
+ Com_Printf( "connectResponse from wrong address. Ignored.\n" );
return;
}
Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) );
@@ -2582,7 +2618,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
// echo request from server
if ( !Q_stricmp(c, "echo") ) {
- NET_OutOfBandPrint( NS_CLIENT, from, "%s", arg1 );
+ NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
return;
}
@@ -3544,7 +3580,7 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
if ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) )
{
// calc ping time
- cl_pinglist[i].time = cls.realtime - cl_pinglist[i].start + 1;
+ cl_pinglist[i].time = Sys_Milliseconds() - cl_pinglist[i].start;
Com_DPrintf( "ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString( from ) );
// save of info
@@ -3936,7 +3972,7 @@ void CL_GetPing( int n, char *buf, int buflen, int *pingtime )
if (!time)
{
// check for timeout
- time = cls.realtime - cl_pinglist[n].start;
+ time = Sys_Milliseconds() - cl_pinglist[n].start;
maxPing = Cvar_VariableIntegerValue( "cl_maxPing" );
if( maxPing < 100 ) {
maxPing = 100;
@@ -4043,7 +4079,7 @@ ping_t* CL_GetFreePing( void )
{
if (!pingptr->time)
{
- if (cls.realtime - pingptr->start < 500)
+ if (Sys_Milliseconds() - pingptr->start < 500)
{
// still waiting for response
continue;
@@ -4068,7 +4104,7 @@ ping_t* CL_GetFreePing( void )
for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )
{
// scan for oldest
- time = cls.realtime - pingptr->start;
+ time = Sys_Milliseconds() - pingptr->start;
if (time > oldest)
{
oldest = time;
@@ -4121,7 +4157,7 @@ void CL_Ping_f( void ) {
pingptr = CL_GetFreePing();
memcpy( &pingptr->adr, &to, sizeof (netadr_t) );
- pingptr->start = cls.realtime;
+ pingptr->start = Sys_Milliseconds();
pingptr->time = 0;
CL_SetServerInfoByAddress(pingptr->adr, NULL, 0);
@@ -4193,7 +4229,7 @@ qboolean CL_UpdateVisiblePings_f(int source) {
}
}
memcpy(&cl_pinglist[j].adr, &server[i].adr, sizeof(netadr_t));
- cl_pinglist[j].start = cls.realtime;
+ cl_pinglist[j].start = Sys_Milliseconds();
cl_pinglist[j].time = 0;
NET_OutOfBandPrint( NS_CLIENT, cl_pinglist[j].adr, "getinfo xxx" );
slots++;
diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c
index 34ae04ea..6c00a353 100644
--- a/src/client/cl_ui.c
+++ b/src/client/cl_ui.c
@@ -295,7 +295,7 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) {
Info_SetValueForKey( info, "game", server->game);
Info_SetValueForKey( info, "gametype", va("%i",server->gameType));
Info_SetValueForKey( info, "nettype", va("%i",server->netType));
- Info_SetValueForKey( info, "addr", NET_AdrToString(server->adr));
+ Info_SetValueForKey( info, "addr", NET_AdrToStringwPort(server->adr));
Q_strncpyz(buf, info, buflen);
} else {
if (buf) {
diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c
index a418733a..c8df2daf 100644
--- a/src/client/snd_dma.c
+++ b/src/client/snd_dma.c
@@ -1369,17 +1369,13 @@ void S_UpdateBackgroundTrack( void ) {
byte raw[30000]; // just enough to fit in a mac stack frame
int fileBytes;
int r;
- static float musicVolume = 0.5f;
if(!s_backgroundStream) {
return;
}
- // graeme see if this is OK
- musicVolume = (musicVolume + (s_musicVolume->value * 2))/4.0f;
-
// don't bother playing anything if musicvolume is 0
- if ( musicVolume <= 0 ) {
+ if ( s_musicVolume->value <= 0 ) {
return;
}
@@ -1394,6 +1390,9 @@ void S_UpdateBackgroundTrack( void ) {
// decide how much data needs to be read from the file
fileSamples = bufferSamples * s_backgroundStream->info.rate / dma.speed;
+ if (!fileSamples)
+ return;
+
// our max buffer size
fileBytes = fileSamples * (s_backgroundStream->info.width * s_backgroundStream->info.channels);
if ( fileBytes > sizeof(raw) ) {
@@ -1413,7 +1412,7 @@ void S_UpdateBackgroundTrack( void ) {
{
// add to raw buffer
S_Base_RawSamples( 0, fileSamples, s_backgroundStream->info.rate,
- s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, musicVolume );
+ s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value );
}
else
{
diff --git a/src/client/snd_main.c b/src/client/snd_main.c
index d3391b23..c386cd75 100644
--- a/src/client/snd_main.c
+++ b/src/client/snd_main.c
@@ -32,6 +32,7 @@ cvar_t *s_musicVolume;
cvar_t *s_doppler;
cvar_t *s_backend;
cvar_t *s_muteWhenMinimized;
+cvar_t *s_muteWhenUnfocused;
static soundInterface_t si;
@@ -230,7 +231,8 @@ S_Update
*/
void S_Update( void )
{
- if( s_muteWhenMinimized->integer && com_minimized->integer ) {
+ if( ( s_muteWhenMinimized->integer && com_minimized->integer ) ||
+ ( s_muteWhenUnfocused->integer && com_unfocused->integer ) ) {
S_StopAllSounds( );
return;
}
@@ -466,6 +468,7 @@ void S_Init( void )
s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE );
s_backend = Cvar_Get( "s_backend", "", CVAR_ROM );
s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE );
+ s_muteWhenUnfocused = Cvar_Get( "s_muteWhenUnfocused", "0", CVAR_ARCHIVE );
cv = Cvar_Get( "s_initsound", "1", 0 );
if( !cv->integer ) {
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c
index 912006d8..1f91ae95 100644
--- a/src/client/snd_openal.c
+++ b/src/client/snd_openal.c
@@ -1419,6 +1419,8 @@ S_AL_StreamDie
static
void S_AL_StreamDie( int stream )
{
+ int numBuffers;
+
if ((stream < 0) || (stream >= MAX_RAW_STREAMS))
return;
@@ -1427,6 +1429,16 @@ void S_AL_StreamDie( int stream )
streamPlaying[stream] = qfalse;
qalSourceStop(streamSources[stream]);
+
+ // Un-queue any buffers, and delete them
+ qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers );
+ while( numBuffers-- )
+ {
+ ALuint buffer;
+ qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer);
+ qalDeleteBuffers(1, &buffer);
+ }
+
S_AL_FreeStreamChannel(stream);
}
@@ -1726,7 +1738,6 @@ static cvar_t *s_alCapture;
#ifdef _WIN32
#define ALDRIVER_DEFAULT "OpenAL32.dll"
-#define ALDEVICE_DEFAULT "Generic Software"
#elif defined(MACOS_X)
#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL"
#else
@@ -1976,8 +1987,7 @@ S_AL_Init
qboolean S_AL_Init( soundInterface_t *si )
{
#ifdef USE_OPENAL
-
- qboolean enumsupport, founddev = qfalse;
+ const char* device = NULL;
int i;
if( !si ) {
@@ -2001,7 +2011,9 @@ qboolean S_AL_Init( soundInterface_t *si )
s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT);
s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT);
- s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE );
+ s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH );
+
+ s_alDevice = Cvar_Get("s_alDevice", "", CVAR_ARCHIVE | CVAR_LATCH);
// Load QAL
if( !QAL_Init( s_alDriver->string ) )
@@ -2010,8 +2022,12 @@ qboolean S_AL_Init( soundInterface_t *si )
return qfalse;
}
+ device = s_alDevice->string;
+ if(device && !*device)
+ device = NULL;
+
// Device enumeration support (extension is implemented reasonably only on Windows right now).
- if((enumsupport = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")))
+ if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
{
char devicenames[1024] = "";
const char *devicelist;
@@ -2027,11 +2043,9 @@ qboolean S_AL_Init( soundInterface_t *si )
// Generic Software as that one works more reliably with various sound systems.
// If it's not, use OpenAL's default selection as we don't want to ignore
// native hardware acceleration.
- if(!strcmp(defaultdevice, "Generic Hardware"))
- s_alDevice = Cvar_Get("s_alDevice", ALDEVICE_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH);
- else
+ if(!device && !strcmp(defaultdevice, "Generic Hardware"))
+ device = "Generic Software";
#endif
- s_alDevice = Cvar_Get("s_alDevice", defaultdevice, CVAR_ARCHIVE | CVAR_LATCH);
// dump a list of available devices to a cvar for the user to see.
while((curlen = strlen(devicelist)))
@@ -2039,26 +2053,18 @@ qboolean S_AL_Init( soundInterface_t *si )
Q_strcat(devicenames, sizeof(devicenames), devicelist);
Q_strcat(devicenames, sizeof(devicenames), "\n");
- // check whether the device we want to load is available at all.
- if(!strcmp(s_alDevice->string, devicelist))
- founddev = qtrue;
-
devicelist += curlen + 1;
}
s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART);
-
- if(!founddev)
- {
- Cvar_ForceReset("s_alDevice");
- founddev = 1;
- }
}
- if(founddev)
- alDevice = qalcOpenDevice(s_alDevice->string);
- else
+ alDevice = qalcOpenDevice(device);
+ if( !alDevice && device )
+ {
+ Com_Printf( "Failed to open OpenAL device '%s', trying default.\n", device );
alDevice = qalcOpenDevice(NULL);
+ }
if( !alDevice )
{
@@ -2067,9 +2073,6 @@ qboolean S_AL_Init( soundInterface_t *si )
return qfalse;
}
- if(enumsupport)
- Cvar_Set("s_alDevice", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER));
-
// Create OpenAL context
alContext = qalcCreateContext( alDevice, NULL );
if( !alContext )
diff --git a/src/libspeex/config.h b/src/libspeex/config.h
index abd35f09..e6657fc0 100644
--- a/src/libspeex/config.h
+++ b/src/libspeex/config.h
@@ -6,6 +6,9 @@
// SSE is enabled.
#ifndef _USE_SSE
# define USE_ALLOCA
+# if defined(__sun) /* Solaris needs this for alloca(). */
+# define HAVE_ALLOCA_H
+# endif
#endif
/* Default to floating point */
diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c
index e04f314c..ecf747d8 100644
--- a/src/qcommon/cmd.c
+++ b/src/qcommon/cmd.c
@@ -53,6 +53,8 @@ bind g "cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster"
void Cmd_Wait_f( void ) {
if ( Cmd_Argc() == 2 ) {
cmd_wait = atoi( Cmd_Argv( 1 ) );
+ if ( cmd_wait < 0 )
+ cmd_wait = 1; // ignore the argument
} else {
cmd_wait = 1;
}
@@ -177,7 +179,7 @@ void Cbuf_Execute (void)
while (cmd_text.cursize)
{
- if ( cmd_wait ) {
+ if ( cmd_wait > 0 ) {
// skip out while text still remains in buffer, leaving it
// for next frame
cmd_wait--;
@@ -296,11 +298,7 @@ Just prints the rest of the line to the console
*/
void Cmd_Echo_f (void)
{
- int i;
-
- for (i=1 ; i<Cmd_Argc() ; i++)
- Com_Printf ("%s ",Cmd_Argv(i));
- Com_Printf ("\n");
+ Com_Printf ("%s\n", Cmd_Args());
}
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index ef9ee76a..b97626ed 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -41,8 +41,6 @@ int demo_protocols[] =
#define MIN_COMHUNKMEGS 128
#define DEF_COMHUNKMEGS 128
#define DEF_COMZONEMEGS 24
-#define XSTRING(x) STRING(x)
-#define STRING(x) #x
#define DEF_COMHUNKMEGS_S XSTRING(DEF_COMHUNKMEGS)
#define DEF_COMZONEMEGS_S XSTRING(DEF_COMZONEMEGS)
@@ -1398,9 +1396,11 @@ void Com_InitSmallZoneMemory( void ) {
void Com_InitZoneMemory( void ) {
cvar_t *cv;
- //FIXME: 05/01/06 com_zoneMegs is useless right now as neither q3config.cfg nor
- // Com_StartupVariable have been executed by this point. The net result is that
- // s_zoneTotal will always be set to the default value.
+ // Please note: com_zoneMegs can only be set on the command line, and
+ // not in q3config.cfg or Com_StartupVariable, as they haven't been
+ // executed by this point. It's a chicken and egg problem. We need the
+ // memory manager configured to handle those places where you would
+ // configure the memory manager.
// allocate the random block zone
cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS_S, CVAR_LATCH | CVAR_ARCHIVE );
@@ -2378,6 +2378,21 @@ static void Com_DetectAltivec(void)
}
}
+/*
+=================
+Com_InitRand
+Seed the random number generator, if possible with an OS supplied random seed.
+=================
+*/
+static void Com_InitRand(void)
+{
+ unsigned int seed;
+
+ if(Sys_RandomBytes((byte *) &seed, sizeof(seed)))
+ srand(seed);
+ else
+ srand(time(NULL));
+}
/*
=================
@@ -2386,6 +2401,7 @@ Com_Init
*/
void Com_Init( char *commandLine ) {
char *s;
+ int qport;
Com_Printf( "%s %s %s\n", Q3_VERSION, PLATFORM_STRING, __DATE__ );
@@ -2397,8 +2413,11 @@ void Com_Init( char *commandLine ) {
Com_Memset( &eventQueue[ 0 ], 0, MAX_QUEUED_EVENTS * sizeof( sysEvent_t ) );
Com_Memset( &sys_packetReceived[ 0 ], 0, MAX_MSGLEN * sizeof( byte ) );
- // do this before anything else decides to push events
- Com_InitPushEvent();
+ // initialize the weak pseudo-random number generator for use later.
+ Com_InitRand();
+
+ // do this before anything else decides to push events
+ Com_InitPushEvent();
Com_InitSmallZoneMemory();
Cvar_Init ();
@@ -2410,12 +2429,12 @@ void Com_Init( char *commandLine ) {
// Swap_Init ();
Cbuf_Init ();
- Com_InitZoneMemory();
- Cmd_Init ();
-
// override anything from the config files with command line args
Com_StartupVariable( NULL );
+ Com_InitZoneMemory();
+ Cmd_Init ();
+
// get the developer cvar set as early as possible
Com_StartupVariable( "developer" );
@@ -2501,7 +2520,11 @@ void Com_Init( char *commandLine ) {
com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );
Sys_Init();
- Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random
+
+ // Pick a random port value
+ Com_RandomBytes( (byte*)&qport, sizeof(int) );
+ Netchan_Init( qport & 0xffff );
+
VM_Init();
SV_Init();
@@ -3171,7 +3194,6 @@ void Com_RandomBytes( byte *string, int len )
return;
Com_Printf( "Com_RandomBytes: using weak randomization\n" );
- srand( time( 0 ) );
for( i = 0; i < len; i++ )
string[i] = (unsigned char)( rand() % 255 );
}
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index c26ba543..0af10587 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -306,9 +306,9 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
cvar_t *var;
long hash;
- if ( !var_name || ! var_value ) {
+ if ( !var_name || ! var_value ) {
Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
- }
+ }
if ( !Cvar_ValidateString( var_name ) ) {
Com_Printf("invalid cvar name string: %s\n", var_name );
@@ -616,15 +616,15 @@ void Cvar_SetCheatState( void ) {
// set all default vars to the safe value
for ( var = cvar_vars ; var ; var = var->next ) {
if ( var->flags & CVAR_CHEAT ) {
- // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
- // because of a different var->latchedString
- if (var->latchedString)
- {
- Z_Free(var->latchedString);
- var->latchedString = NULL;
- }
+ // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
+ // because of a different var->latchedString
+ if (var->latchedString)
+ {
+ Z_Free(var->latchedString);
+ var->latchedString = NULL;
+ }
if (strcmp(var->resetString,var->string)) {
- Cvar_Set( var->name, var->resetString );
+ Cvar_Set( var->name, var->resetString );
}
}
}
@@ -653,7 +653,7 @@ qboolean Cvar_Command( void ) {
}
// set the value if forcing isn't required
- Cvar_Set2 (v->name, Cmd_Argv(1), qfalse);
+ Cvar_Set2 (v->name, Cmd_Args(), qfalse);
return qtrue;
}
@@ -691,21 +691,44 @@ void Cvar_Print_f(void)
============
Cvar_Toggle_f
-Toggles a cvar for easy single key binding
+Toggles a cvar for easy single key binding, optionally through a list of
+given values
============
*/
void Cvar_Toggle_f( void ) {
- int v;
+ int i, c = Cmd_Argc();
+ char *curval;
- if ( Cmd_Argc() != 2 ) {
- Com_Printf ("usage: toggle <variable>\n");
+ if(c < 2) {
+ Com_Printf("usage: toggle <variable> [value1, value2, ...]\n");
+ return;
+ }
+
+ if(c == 2) {
+ Cvar_Set2(Cmd_Argv(1), va("%d",
+ !Cvar_VariableValue(Cmd_Argv(1))),
+ qfalse);
+ return;
+ }
+
+ if(c == 3) {
+ Com_Printf("toggle: nothing to toggle to\n");
return;
}
- v = Cvar_VariableValue( Cmd_Argv( 1 ) );
- v = !v;
+ curval = Cvar_VariableString(Cmd_Argv(1));
- Cvar_Set2 (Cmd_Argv(1), va("%i", v), qfalse);
+ // don't bother checking the last arg for a match since the desired
+ // behaviour is the same as no match (set to the first argument)
+ for(i = 2; i + 1 < c; i++) {
+ if(strcmp(curval, Cmd_Argv(i)) == 0) {
+ Cvar_Set2(Cmd_Argv(1), Cmd_Argv(i + 1), qfalse);
+ return;
+ }
+ }
+
+ // fallback
+ Cvar_Set2(Cmd_Argv(1), Cmd_Argv(2), qfalse);
}
/*
@@ -840,6 +863,11 @@ void Cvar_List_f( void ) {
} else {
Com_Printf(" ");
}
+ if (var->flags & CVAR_SYSTEMINFO) {
+ Com_Printf("s");
+ } else {
+ Com_Printf(" ");
+ }
if (var->flags & CVAR_USERINFO) {
Com_Printf("U");
} else {
@@ -870,6 +898,11 @@ void Cvar_List_f( void ) {
} else {
Com_Printf(" ");
}
+ if (var->flags & CVAR_USER_CREATED) {
+ Com_Printf("?");
+ } else {
+ Com_Printf(" ");
+ }
Com_Printf (" %s \"%s\"\n", var->name, var->string);
}
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 6b407c20..db7e79d4 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -479,7 +479,7 @@ FS_CreatePath
Creates any directories needed to store the given filename
============
*/
-static qboolean FS_CreatePath (char *OSPath) {
+qboolean FS_CreatePath (char *OSPath) {
char *ofs;
// make absolutely sure that it can't back up the path
@@ -502,18 +502,19 @@ static qboolean FS_CreatePath (char *OSPath) {
/*
=================
-FS_FilenameIsExecutable
+FS_CheckFilenameIsNotExecutable
ERR_FATAL if trying to maniuplate a file with the platform library extension
=================
*/
-static void FS_FilenameIsExecutable( const char *filename, const char *function )
+static void FS_CheckFilenameIsNotExecutable( const char *filename,
+ const char *function )
{
// Check if the filename ends with the library extension
- if( !Q_stricmp( filename + strlen( filename ) - strlen( DLL_EXT ), DLL_EXT ) )
+ if( !Q_stricmp( COM_GetExtension( filename ), DLL_EXT ) )
{
- Com_Error( ERR_FATAL, "%s: Not allowed to write '%s' due to %s extension\n",
- function, filename, DLL_EXT );
+ Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due "
+ "to %s extension\n", function, filename, DLL_EXT );
}
}
@@ -532,7 +533,7 @@ static void FS_CopyFile( char *fromOSPath, char *toOSPath ) {
Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath );
- FS_FilenameIsExecutable( toOSPath, __func__ );
+ FS_CheckFilenameIsNotExecutable( toOSPath, __func__ );
if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) {
Com_Printf( "Ignoring journal files\n");
@@ -575,7 +576,7 @@ FS_Remove
===========
*/
void FS_Remove( const char *osPath ) {
- FS_FilenameIsExecutable( osPath, __func__ );
+ FS_CheckFilenameIsNotExecutable( osPath, __func__ );
remove( osPath );
}
@@ -587,7 +588,7 @@ FS_HomeRemove
===========
*/
void FS_HomeRemove( const char *homePath ) {
- FS_FilenameIsExecutable( homePath, __func__ );
+ FS_CheckFilenameIsNotExecutable( homePath, __func__ );
remove( FS_BuildOSPath( fs_homepath->string,
fs_gamedir, homePath ) );
@@ -666,7 +667,7 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) {
Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath );
}
- FS_FilenameIsExecutable( ospath, __func__ );
+ FS_CheckFilenameIsNotExecutable( ospath, __func__ );
if( FS_CreatePath( ospath ) ) {
return 0;
@@ -777,7 +778,7 @@ void FS_SV_Rename( const char *from, const char *to ) {
Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath );
}
- FS_FilenameIsExecutable( to_ospath, __func__ );
+ FS_CheckFilenameIsNotExecutable( to_ospath, __func__ );
if (rename( from_ospath, to_ospath )) {
// Failed, try copying it and deleting the original
@@ -811,7 +812,7 @@ void FS_Rename( const char *from, const char *to ) {
Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath );
}
- FS_FilenameIsExecutable( to_ospath, __func__ );
+ FS_CheckFilenameIsNotExecutable( to_ospath, __func__ );
if (rename( from_ospath, to_ospath )) {
// Failed, try copying it and deleting the original
@@ -874,7 +875,7 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) {
Com_Printf( "FS_FOpenFileWrite: %s\n", ospath );
}
- FS_FilenameIsExecutable( ospath, __func__ );
+ FS_CheckFilenameIsNotExecutable( ospath, __func__ );
if( FS_CreatePath( ospath ) ) {
return 0;
@@ -922,7 +923,7 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) {
Com_Printf( "FS_FOpenFileAppend: %s\n", ospath );
}
- FS_FilenameIsExecutable( ospath, __func__ );
+ FS_CheckFilenameIsNotExecutable( ospath, __func__ );
if( FS_CreatePath( ospath ) ) {
return 0;
diff --git a/src/qcommon/net_ip.c b/src/qcommon/net_ip.c
index e7a52996..9ad4a821 100644
--- a/src/qcommon/net_ip.c
+++ b/src/qcommon/net_ip.c
@@ -92,13 +92,6 @@ typedef int SOCKET;
static qboolean usingSocks = qfalse;
static int networkingEnabled = 0;
-#define NET_ENABLEV4 0x01
-#define NET_ENABLEV6 0x02
-// if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found.
-#define NET_PRIOV6 0x04
-// disables ipv6 multicast support if set.
-#define NET_DISABLEMCAST 0x08
-
static cvar_t *net_enabled;
static cvar_t *net_socksEnabled;
@@ -274,7 +267,9 @@ Sys_StringToSockaddr
*/
static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int sadr_len, sa_family_t family)
{
- struct addrinfo hints, *res = NULL, *search;
+ struct addrinfo hints;
+ struct addrinfo *res = NULL;
+ struct addrinfo *search = NULL;
struct addrinfo *hintsp;
int retval;
@@ -284,8 +279,6 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s
hintsp = &hints;
hintsp->ai_family = family;
hintsp->ai_socktype = SOCK_DGRAM;
- // FIXME: we should set "->ai_flags" to AI_PASSIVE if we intend
- // to use this structure for a bind() - instead of a sendto()
retval = getaddrinfo(s, NULL, hintsp, &res);
@@ -294,18 +287,20 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s
if(family == AF_UNSPEC)
{
// Decide here and now which protocol family to use
- if((net_enabled->integer & NET_ENABLEV6) && (net_enabled->integer & NET_PRIOV6))
- search = SearchAddrInfo(res, AF_INET6);
+ if(net_enabled->integer & NET_PRIOV6)
+ {
+ if(net_enabled->integer & NET_ENABLEV6)
+ search = SearchAddrInfo(res, AF_INET6);
+
+ if(!search && (net_enabled->integer & NET_ENABLEV4))
+ search = SearchAddrInfo(res, AF_INET);
+ }
else
- search = SearchAddrInfo(res, AF_INET);
-
- if(!search)
{
- if((net_enabled->integer & NET_ENABLEV6) &&
- (net_enabled->integer & NET_PRIOV6) &&
- (net_enabled->integer & NET_ENABLEV4))
+ if(net_enabled->integer & NET_ENABLEV4)
search = SearchAddrInfo(res, AF_INET);
- else if(net_enabled->integer & NET_ENABLEV6)
+
+ if(!search && (net_enabled->integer & NET_ENABLEV6))
search = SearchAddrInfo(res, AF_INET6);
}
}
@@ -348,7 +343,8 @@ static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input
else
inputlen = sizeof(struct sockaddr_in);
- getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST);
+ if(getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST) && destlen > 0)
+ *dest = '\0';
}
/*
@@ -382,47 +378,96 @@ qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) {
/*
===================
-NET_CompareBaseAdr
+NET_CompareBaseAdrMask
-Compares without the port
+Compare without port, and up to the bit number given in netmask.
===================
*/
-qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
+qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask)
{
+ qboolean differed;
+ byte cmpmask, *addra, *addrb;
+ int curbyte;
+
if (a.type != b.type)
return qfalse;
if (a.type == NA_LOOPBACK)
return qtrue;
- if (a.type == NA_IP)
+ if(a.type == NA_IP)
{
- if(!memcmp(a.ip, b.ip, sizeof(a.ip)))
- return qtrue;
+ addra = (byte *) &a.ip;
+ addrb = (byte *) &b.ip;
- return qfalse;
+ if(netmask < 0 || netmask > 32)
+ netmask = 32;
}
-
- if (a.type == NA_IP6)
+ else if(a.type == NA_IP6)
{
- if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6)) && a.scope_id == b.scope_id)
- return qtrue;
+ addra = (byte *) &a.ip6;
+ addrb = (byte *) &b.ip6;
+ if(netmask < 0 || netmask > 128)
+ netmask = 128;
+ }
+ else
+ {
+ Com_Printf ("NET_CompareBaseAdr: bad address type\n");
return qfalse;
}
- Com_Printf ("NET_CompareBaseAdr: bad address type\n");
+ differed = qfalse;
+ curbyte = 0;
+
+ while(netmask > 7)
+ {
+ if(addra[curbyte] != addrb[curbyte])
+ {
+ differed = qtrue;
+ break;
+ }
+
+ curbyte++;
+ netmask -= 8;
+ }
+
+ if(differed)
+ return qfalse;
+
+ if(netmask)
+ {
+ cmpmask = (1 << netmask) - 1;
+ cmpmask <<= 8 - netmask;
+
+ if((addra[curbyte] & cmpmask) == (addrb[curbyte] & cmpmask))
+ return qtrue;
+ }
+ else
+ return qtrue;
+
return qfalse;
}
+
+/*
+===================
+NET_CompareBaseAdr
+
+Compares without the port
+===================
+*/
+qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
+{
+ return NET_CompareBaseAdrMask(a, b, -1);
+}
+
const char *NET_AdrToString (netadr_t a)
{
static char s[NET_ADDRSTRMAXLEN];
if (a.type == NA_LOOPBACK)
- {
Com_sprintf (s, sizeof(s), "loopback");
- }
else if (a.type == NA_IP || a.type == NA_IP6)
{
struct sockaddr_storage sadr;
@@ -440,16 +485,11 @@ const char *NET_AdrToStringwPort (netadr_t a)
static char s[NET_ADDRSTRMAXLEN];
if (a.type == NA_LOOPBACK)
- {
Com_sprintf (s, sizeof(s), "loopback");
- }
- else if (a.type == NA_IP || a.type == NA_IP6)
- {
- if(a.type == NA_IP)
- Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port));
- else if(a.type == NA_IP6)
- Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port));
- }
+ else if(a.type == NA_IP)
+ Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port));
+ else if(a.type == NA_IP6)
+ Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port));
return s;
}
@@ -886,7 +926,7 @@ int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, i
#ifdef IPV6_V6ONLY
{
- int i;
+ int i = 1;
// ipv4 addresses should not be allowed to connect via this socket.
if(setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &i, sizeof(i)) == SOCKET_ERROR)
@@ -1278,9 +1318,6 @@ void NET_GetLocalAddress( void ) {
char hostname[256];
struct addrinfo hint;
struct addrinfo *res = NULL;
- struct addrinfo *search;
- struct sockaddr_in mask4;
- struct sockaddr_in6 mask6;
if(gethostname( hostname, 256 ) == SOCKET_ERROR)
return;
@@ -1292,29 +1329,36 @@ void NET_GetLocalAddress( void ) {
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_DGRAM;
- if(getaddrinfo(hostname, NULL, &hint, &res))
- return;
-
- /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a
- * netmask with all bits set. */
-
- memset(&mask4, 0, sizeof(mask4));
- memset(&mask6, 0, sizeof(mask6));
- mask4.sin_family = AF_INET;
- memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr));
- mask6.sin6_family = AF_INET6;
- memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr));
-
- // add all IPs from returned list.
- for(search = res; search; search = search->ai_next)
+ if(!getaddrinfo(hostname, NULL, &hint, &res))
{
- if(search->ai_family == AF_INET)
- NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4);
- else if(search->ai_family == AF_INET6)
- NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6);
+ struct sockaddr_in mask4;
+ struct sockaddr_in6 mask6;
+ struct addrinfo *search;
+
+ /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a
+ * netmask with all bits set. */
+
+ memset(&mask4, 0, sizeof(mask4));
+ memset(&mask6, 0, sizeof(mask6));
+ mask4.sin_family = AF_INET;
+ memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr));
+ mask6.sin6_family = AF_INET6;
+ memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr));
+
+ // add all IPs from returned list.
+ for(search = res; search; search = search->ai_next)
+ {
+ if(search->ai_family == AF_INET)
+ NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4);
+ else if(search->ai_family == AF_INET6)
+ NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6);
+ }
+
+ Sys_ShowIP();
}
- Sys_ShowIP();
+ if(res)
+ freeaddrinfo(res);
}
#endif
@@ -1329,11 +1373,6 @@ void NET_OpenIP( void ) {
int port;
int port6;
- net_ip = Cvar_Get( "net_ip", "0.0.0.0", CVAR_LATCH );
- net_ip6 = Cvar_Get( "net_ip6", "::", CVAR_LATCH );
- net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH );
- net_port6 = Cvar_Get( "net_port6", va( "%i", PORT_SERVER ), CVAR_LATCH );
-
port = net_port->integer;
port6 = net_port6->integer;
@@ -1397,14 +1436,8 @@ NET_GetCvars
====================
*/
static qboolean NET_GetCvars( void ) {
- qboolean modified;
-
- modified = qfalse;
+ int modified;
- if( net_enabled && net_enabled->modified ) {
- modified = qtrue;
- }
-
#ifdef DEDICATED
// I want server owners to explicitly turn on ipv6 support.
net_enabled = Cvar_Get( "net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE );
@@ -1413,45 +1446,55 @@ static qboolean NET_GetCvars( void ) {
* used if available due to ping */
net_enabled = Cvar_Get( "net_enabled", "3", CVAR_LATCH | CVAR_ARCHIVE );
#endif
+ modified = net_enabled->modified;
+ net_enabled->modified = qfalse;
+
+ net_ip = Cvar_Get( "net_ip", "0.0.0.0", CVAR_LATCH );
+ modified += net_ip->modified;
+ net_ip->modified = qfalse;
+
+ net_ip6 = Cvar_Get( "net_ip6", "::", CVAR_LATCH );
+ modified += net_ip6->modified;
+ net_ip6->modified = qfalse;
+
+ net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH );
+ modified += net_port->modified;
+ net_port->modified = qfalse;
+
+ net_port6 = Cvar_Get( "net_port6", va( "%i", PORT_SERVER ), CVAR_LATCH );
+ modified += net_port6->modified;
+ net_port6->modified = qfalse;
// Some cvars for configuring multicast options which facilitates scanning for servers on local subnets.
- if( net_mcast6addr && net_mcast6addr->modified ) {
- modified = qtrue;
- }
net_mcast6addr = Cvar_Get( "net_mcast6addr", NET_MULTICAST_IP6, CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_mcast6addr->modified;
+ net_mcast6addr->modified = qfalse;
- if( net_mcast6iface && net_mcast6iface->modified ) {
- modified = qtrue;
- }
net_mcast6iface = Cvar_Get( "net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_mcast6iface->modified;
+ net_mcast6iface->modified = qfalse;
- if( net_socksEnabled && net_socksEnabled->modified ) {
- modified = qtrue;
- }
net_socksEnabled = Cvar_Get( "net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_socksEnabled->modified;
+ net_socksEnabled->modified = qfalse;
- if( net_socksServer && net_socksServer->modified ) {
- modified = qtrue;
- }
net_socksServer = Cvar_Get( "net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_socksServer->modified;
+ net_socksServer->modified = qfalse;
- if( net_socksPort && net_socksPort->modified ) {
- modified = qtrue;
- }
net_socksPort = Cvar_Get( "net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_socksPort->modified;
+ net_socksPort->modified = qfalse;
- if( net_socksUsername && net_socksUsername->modified ) {
- modified = qtrue;
- }
net_socksUsername = Cvar_Get( "net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_socksUsername->modified;
+ net_socksUsername->modified = qfalse;
- if( net_socksPassword && net_socksPassword->modified ) {
- modified = qtrue;
- }
net_socksPassword = Cvar_Get( "net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE );
+ modified += net_socksPassword->modified;
+ net_socksPassword->modified = qfalse;
-
- return modified;
+ return modified ? qtrue : qfalse;
}
@@ -1555,10 +1598,9 @@ void NET_Init( void ) {
Com_Printf( "Winsock Initialized\n" );
#endif
- // this is really just to get the cvars registered
- NET_GetCvars();
-
NET_Config( qtrue );
+
+ Cmd_AddCommand ("net_restart", NET_Restart_f);
}
@@ -1608,8 +1650,7 @@ void NET_Sleep( int msec ) {
{
FD_SET(ip_socket, &fdset);
- if(ip_socket > highestfd)
- highestfd = ip_socket;
+ highestfd = ip_socket;
}
if(ip6_socket != INVALID_SOCKET)
{
@@ -1621,7 +1662,7 @@ void NET_Sleep( int msec ) {
timeout.tv_sec = msec/1000;
timeout.tv_usec = (msec%1000)*1000;
- select(ip_socket+1, &fdset, NULL, NULL, &timeout);
+ select(highestfd + 1, &fdset, NULL, NULL, &timeout);
}
@@ -1630,6 +1671,6 @@ void NET_Sleep( int msec ) {
NET_Restart_f
====================
*/
-void NET_Restart( void ) {
+void NET_Restart_f( void ) {
NET_Config( networkingEnabled );
}
diff --git a/src/qcommon/q_math.c b/src/qcommon/q_math.c
index e7924073..ba910a37 100644
--- a/src/qcommon/q_math.c
+++ b/src/qcommon/q_math.c
@@ -696,50 +696,14 @@ void SetPlaneSignbits (cplane_t *out) {
BoxOnPlaneSide
Returns 1, 2, or 1 + 2
-
-// this is the slow, general version
-int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
-{
- int i;
- float dist1, dist2;
- int sides;
- vec3_t corners[2];
-
- for (i=0 ; i<3 ; i++)
- {
- if (p->normal[i] < 0)
- {
- corners[0][i] = emins[i];
- corners[1][i] = emaxs[i];
- }
- else
- {
- corners[1][i] = emins[i];
- corners[0][i] = emaxs[i];
- }
- }
- dist1 = DotProduct (p->normal, corners[0]) - p->dist;
- dist2 = DotProduct (p->normal, corners[1]) - p->dist;
- sides = 0;
- if (dist1 >= 0)
- sides = 1;
- if (dist2 < 0)
- sides |= 2;
-
- return sides;
-}
-
==================
*/
-
-#if !id386
-
-int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
+int BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p)
{
- float dist1, dist2;
- int sides;
+ float dist[2];
+ int sides, b, i;
-// fast axial cases
+ // fast axial cases
if (p->type < 3)
{
if (p->dist <= emins[p->type])
@@ -749,291 +713,27 @@ int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
return 3;
}
-// general case
- switch (p->signbits)
+ // general case
+ dist[0] = dist[1] = 0;
+ if (p->signbits < 8) // >= 8: default case is original code (dist[0]=dist[1]=0)
{
- case 0:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 1:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- break;
- case 2:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 3:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- break;
- case 4:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 5:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
- break;
- case 6:
- dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- case 7:
- dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
- dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
- break;
- default:
- dist1 = dist2 = 0; // shut up compiler
- break;
+ for (i=0 ; i<3 ; i++)
+ {
+ b = (p->signbits >> i) & 1;
+ dist[ b] += p->normal[i]*emaxs[i];
+ dist[!b] += p->normal[i]*emins[i];
+ }
}
sides = 0;
- if (dist1 >= p->dist)
+ if (dist[0] >= p->dist)
sides = 1;
- if (dist2 < p->dist)
+ if (dist[1] < p->dist)
sides |= 2;
return sides;
}
-#elif __GNUC__
-// use matha.s
-#else
-#pragma warning( disable: 4035 )
-
-__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
-{
- static int bops_initialized;
- static int Ljmptab[8];
-
- __asm {
-
- push ebx
-
- cmp bops_initialized, 1
- je initialized
- mov bops_initialized, 1
-
- mov Ljmptab[0*4], offset Lcase0
- mov Ljmptab[1*4], offset Lcase1
- mov Ljmptab[2*4], offset Lcase2
- mov Ljmptab[3*4], offset Lcase3
- mov Ljmptab[4*4], offset Lcase4
- mov Ljmptab[5*4], offset Lcase5
- mov Ljmptab[6*4], offset Lcase6
- mov Ljmptab[7*4], offset Lcase7
-
-initialized:
-
- mov edx,dword ptr[4+12+esp]
- mov ecx,dword ptr[4+4+esp]
- xor eax,eax
- mov ebx,dword ptr[4+8+esp]
- mov al,byte ptr[17+edx]
- cmp al,8
- jge Lerror
- fld dword ptr[0+edx]
- fld st(0)
- jmp dword ptr[Ljmptab+eax*4]
-Lcase0:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase1:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase2:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase3:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ebx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ecx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase4:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase5:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ebx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase6:
- fmul dword ptr[ebx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ecx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
- jmp LSetSides
-Lcase7:
- fmul dword ptr[ecx]
- fld dword ptr[0+4+edx]
- fxch st(2)
- fmul dword ptr[ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[4+ecx]
- fld dword ptr[0+8+edx]
- fxch st(2)
- fmul dword ptr[4+ebx]
- fxch st(2)
- fld st(0)
- fmul dword ptr[8+ecx]
- fxch st(5)
- faddp st(3),st(0)
- fmul dword ptr[8+ebx]
- fxch st(1)
- faddp st(3),st(0)
- fxch st(3)
- faddp st(2),st(0)
-LSetSides:
- faddp st(2),st(0)
- fcomp dword ptr[12+edx]
- xor ecx,ecx
- fnstsw ax
- fcomp dword ptr[12+edx]
- and ah,1
- xor ah,1
- add cl,ah
- fnstsw ax
- and ah,1
- add ah,ah
- add cl,ah
- pop ebx
- mov eax,ecx
- ret
-Lerror:
- int 3
- }
-}
-#pragma warning( default: 4035 )
-#endif
/*
=================
diff --git a/src/qcommon/q_platform.h b/src/qcommon/q_platform.h
index 4ce1fb56..5da62b38 100644
--- a/src/qcommon/q_platform.h
+++ b/src/qcommon/q_platform.h
@@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define id386 0
#define idppc 0
#define idppc_altivec 0
+#define idsparc 0
#else
@@ -59,6 +60,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#define idppc_altivec 0
#endif
+#if defined(__sparc__) && !defined(C_ONLY)
+#define idsparc 1
+#else
+#define idsparc 0
+#endif
+
#endif
#ifndef __ASM_I386__ // don't include the C bits if included from qasm.h
@@ -193,6 +200,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifdef __i386__
#define ARCH_STRING "x86"
+#elif defined __amd64__
+#define ARCH_STRING "x86_64"
#elif defined __axp__
#define ARCH_STRING "alpha"
#endif
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 622d71fe..a346bf5e 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -74,6 +74,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#endif
+#if (defined _MSC_VER)
+#define Q_EXPORT __declspec(dllexport)
+#elif (defined __SUNPRO_C)
+#define Q_EXPORT __global
+#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun))
+#define Q_EXPORT __attribute__((visibility("default")))
+#else
+#define Q_EXPORT
+#endif
+
/**********************************************************************
VM Considerations
@@ -167,6 +177,10 @@ typedef int clipHandle_t;
#define NULL ((void *)0)
#endif
+#define STRING(s) #s
+// expand constants before stringifying them
+#define XSTRING(s) STRING(s)
+
#define MAX_QINT 0x7fffffff
#define MIN_QINT (-MAX_QINT-1)
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index e4234f54..bcfd60b9 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -120,6 +120,14 @@ NET
==============================================================
*/
+#define NET_ENABLEV4 0x01
+#define NET_ENABLEV6 0x02
+// if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found.
+#define NET_PRIOV6 0x04
+// disables ipv6 multicast support if set.
+#define NET_DISABLEMCAST 0x08
+
+
#define PACKET_BACKUP 32 // number of old messages that must be kept on client and
// server for delta comrpession and ping estimation
#define PACKET_MASK (PACKET_BACKUP-1)
@@ -131,7 +139,7 @@ NET
#define MAX_RELIABLE_COMMANDS 128 // max string commands buffered for restransmit
typedef enum {
- NA_BAD, // an address lookup failed
+ NA_BAD = 0, // an address lookup failed
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
@@ -158,7 +166,7 @@ typedef struct {
void NET_Init( void );
void NET_Shutdown( void );
-void NET_Restart( void );
+void NET_Restart_f( void );
void NET_Config( qboolean enableNetworking );
void NET_FlushPacketQueue(void);
void NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t to);
@@ -166,6 +174,7 @@ void QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *f
void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len );
qboolean NET_CompareAdr (netadr_t a, netadr_t b);
+qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask);
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
qboolean NET_IsLocalAddress (netadr_t adr);
const char *NET_AdrToString (netadr_t a);
@@ -584,6 +593,7 @@ void FS_FreeFileList( char **list );
qboolean FS_FileExists( const char *file );
+qboolean FS_CreatePath (char *OSPath);
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
int FS_LoadStack( void );
diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c
index c1a829a6..713256a7 100644
--- a/src/qcommon/vm.c
+++ b/src/qcommon/vm.c
@@ -357,6 +357,9 @@ intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) {
#endif
}
+
+#define STACK_SIZE 0x20000
+
/*
=================
VM_LoadQVM
@@ -424,7 +427,8 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
// round up to next power of 2 so all data operations can
// be mask protected
- dataLength = header.h->dataLength + header.h->litLength + header.h->bssLength;
+ dataLength = header.h->dataLength + header.h->litLength +
+ header.h->bssLength + STACK_SIZE;
for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) {
}
dataLength = 1 << i;
@@ -516,9 +520,6 @@ If image ends in .qvm it will be interpreted, otherwise
it will attempt to load as a system dll
================
*/
-
-#define STACK_SIZE 0x20000
-
vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
vmInterpret_t interpret ) {
vm_t *vm;
@@ -766,7 +767,7 @@ intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) {
args[4], args[5], args[6], args[7],
args[8], args[9]);
} else {
-#if id386 // i386 calling convention doesn't need conversion
+#if id386 || idsparc // i386/sparc calling convention doesn't need conversion
#ifndef NO_VM_COMPILED
if ( vm->compiled )
r = VM_CallCompiled( vm, (int*)&callnum );
diff --git a/src/qcommon/vm_sparc.c b/src/qcommon/vm_sparc.c
new file mode 100644
index 00000000..39f2202a
--- /dev/null
+++ b/src/qcommon/vm_sparc.c
@@ -0,0 +1,1648 @@
+/*
+===========================================================================
+Copyright (C) 2009 David S. Miller <davem@davemloft.net>
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+/* This code is based almost entirely upon the vm_powerpc.c code by
+ * Przemyslaw Iskra. All I did was make it work on Sparc :-) -DaveM
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stddef.h>
+
+#include "vm_local.h"
+#include "vm_sparc.h"
+
+/* exit() won't be called but use it because it is marked with noreturn */
+#define DIE( reason ) \
+ do { \
+ Com_Error(ERR_DROP, "vm_sparc compiler error: " reason "\n"); \
+ exit(1); \
+ } while(0)
+
+/* Select Length - first value on 32 bits, second on 64 */
+#ifdef __arch64__
+#define SL(a, b) (b)
+#else
+#define SL(a, b) (a)
+#endif
+
+#define rTMP G1
+#define rVMDATA G2
+#define rPSTACK G3
+#define rDATABASE G4
+#define rDATAMASK G5
+
+struct sparc_opcode {
+ const char *name;
+ unsigned int opcode;
+ unsigned int mask;
+ unsigned char args[4];
+#define ARG_NONE 0
+#define ARG_RS1 1
+#define ARG_RS2 2
+#define ARG_RD 3
+#define ARG_SIMM13 4
+#define ARG_DISP30 5
+#define ARG_IMM22 6
+#define ARG_DISP22 7
+#define ARG_SWTRAP 8
+};
+
+#define ARG_RS1_RS2_RD { ARG_RS1, ARG_RS2, ARG_RD }
+#define ARG_RS1_SIMM13_RD { ARG_RS1, ARG_SIMM13, ARG_RD }
+#define ARG_RS1_RS2 { ARG_RS1, ARG_RS2 }
+#define ARG_RS2_RD { ARG_RS2, ARG_RD }
+
+#define OP_MASK 0xc0000000
+#define OP2_MASK 0x01c00000
+#define OP3_MASK 0x01f80000
+#define OPF_MASK 0x00003fe0
+
+#define IMM 0x00002000
+
+#define FMT1(op) ((op) << 30), OP_MASK
+#define FMT2(op,op2) ((op) << 30)|((op2)<<22), (OP_MASK | OP2_MASK)
+#define FMT3(op,op3) ((op) << 30)|((op3)<<19), (OP_MASK | OP3_MASK | IMM)
+#define FMT3I(op,op3) ((op) << 30)|((op3)<<19)|IMM, (OP_MASK | OP3_MASK | IMM)
+#define FMT3F(op,op3,opf) ((op) << 30)|((op3)<<19)|((opf)<<5), \
+ (OP_MASK | OP3_MASK | OPF_MASK)
+
+#define BICC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x2))
+#define BFCC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x6))
+#define TICC(COND) FMT3I(0,((COND<<6)|0x3a))
+
+enum sparc_iname {
+ CALL, NOP, SETHI,
+
+ BA, BN, BNE, BE, BG, BLE, BGE, BL, BGU, BLEU, BCC, BCS,
+ BPOS, BNEG, BVC, BVS,
+
+ ADDI, ADD,
+ ANDI, AND,
+ ORI, OR,
+ XORI, XOR,
+ SUBI, SUB,
+ ANDNI, ANDN,
+ ORNI, ORN,
+ XNORI, XNOR,
+
+ UMULI, UMUL,
+ SMULI, SMUL,
+ UDIVI, UDIV,
+ SDIVI, SDIV,
+
+ SUBCCI, SUBCC,
+
+ SLLI, SLL,
+ SRLI, SRL,
+ SRAI, SRA,
+
+ WRI, WR,
+
+ SAVEI, SAVE,
+ RESTOREI, RESTORE,
+
+ TA,
+
+ JMPLI, JMPL,
+
+ LDXI, LDX,
+ LDUWI, LDUW,
+ LDUHI, LDUH,
+ LDUBI, LDUB,
+
+ STXI, STX,
+ STWI, STW,
+ STHI, STH,
+ STBI, STB,
+
+ LDFI, LDF,
+ STFI, STF,
+
+ FADD, FSUB, FCMP, FSTOI, FITOS, FNEG, FDIV, FMUL,
+ FBE, FBNE, FBL, FBGE, FBG, FBLE,
+};
+
+#define LDLI SL(LDUWI, LDXI)
+#define LDL SL(LDUW, LDX)
+#define STLI SL(STWI, STXI)
+#define STL SL(STW, STX)
+
+#define SPARC_NOP 0x01000000
+
+static const struct sparc_opcode sparc_opcodes[] = {
+ { "call", FMT1(1), { ARG_DISP30 }, },
+ { "nop", SPARC_NOP, 0xffffffff, { ARG_NONE }, }, /* sethi %hi(0), %g0 */
+ { "sethi", FMT2(0,4), { ARG_IMM22, ARG_RD }, },
+ { "ba", BICC(0,8), { ARG_DISP22 }, },
+ { "bn", BICC(0,0), { ARG_DISP22 }, },
+ { "bne", BICC(0,9), { ARG_DISP22 }, },
+ { "be", BICC(0,1), { ARG_DISP22 }, },
+ { "bg", BICC(0,10), { ARG_DISP22 }, },
+ { "ble", BICC(0,2), { ARG_DISP22 }, },
+ { "bge", BICC(0,11), { ARG_DISP22 }, },
+ { "bl", BICC(0,3), { ARG_DISP22 }, },
+ { "bgu", BICC(0,12), { ARG_DISP22 }, },
+ { "bleu", BICC(0,4), { ARG_DISP22 }, },
+ { "bcc", BICC(0,13), { ARG_DISP22 }, },
+ { "bcs", BICC(0,5), { ARG_DISP22 }, },
+ { "bpos", BICC(0,14), { ARG_DISP22 }, },
+ { "bneg", BICC(0,6), { ARG_DISP22 }, },
+ { "bvc", BICC(0,15), { ARG_DISP22 }, },
+ { "bvs", BICC(0,7), { ARG_DISP22 }, },
+
+ { "add", FMT3I(2, 0x00), ARG_RS1_SIMM13_RD, },
+ { "add", FMT3 (2, 0x00), ARG_RS1_RS2_RD, },
+ { "and", FMT3I(2, 0x01), ARG_RS1_SIMM13_RD, },
+ { "and", FMT3 (2, 0x01), ARG_RS1_RS2_RD, },
+ { "or", FMT3I(2, 0x02), ARG_RS1_SIMM13_RD, },
+ { "or", FMT3 (2, 0x02), ARG_RS1_RS2_RD, },
+ { "xor", FMT3I(2, 0x03), ARG_RS1_SIMM13_RD, },
+ { "xor", FMT3 (2, 0x03), ARG_RS1_RS2_RD, },
+ { "sub", FMT3I(2, 0x04), ARG_RS1_SIMM13_RD, },
+ { "sub", FMT3 (2, 0x04), ARG_RS1_RS2_RD, },
+ { "andn", FMT3I(2, 0x05), ARG_RS1_SIMM13_RD, },
+ { "andn", FMT3 (2, 0x05), ARG_RS1_RS2_RD, },
+ { "orn", FMT3I(2, 0x06), ARG_RS1_SIMM13_RD, },
+ { "orn", FMT3 (2, 0x06), ARG_RS1_RS2_RD, },
+ { "xnor", FMT3I(2, 0x07), ARG_RS1_SIMM13_RD, },
+ { "xnor", FMT3 (2, 0x07), ARG_RS1_RS2_RD, },
+
+ { "umul", FMT3I(2, 0x0a), ARG_RS1_SIMM13_RD, },
+ { "umul", FMT3 (2, 0x0a), ARG_RS1_RS2_RD, },
+ { "smul", FMT3I(2, 0x0b), ARG_RS1_SIMM13_RD, },
+ { "smul", FMT3 (2, 0x0b), ARG_RS1_RS2_RD, },
+ { "udiv", FMT3I(2, 0x0e), ARG_RS1_SIMM13_RD, },
+ { "udiv", FMT3 (2, 0x0e), ARG_RS1_RS2_RD, },
+ { "sdiv", FMT3I(2, 0x0f), ARG_RS1_SIMM13_RD, },
+ { "sdiv", FMT3 (2, 0x0f), ARG_RS1_RS2_RD, },
+
+ { "subcc", FMT3I(2, 0x14), ARG_RS1_SIMM13_RD, },
+ { "subcc", FMT3 (2, 0x14), ARG_RS1_RS2_RD, },
+
+ { "sll", FMT3I(2, 0x25), ARG_RS1_SIMM13_RD, },
+ { "sll", FMT3 (2, 0x25), ARG_RS1_RS2_RD, },
+ { "srl", FMT3I(2, 0x26), ARG_RS1_SIMM13_RD, },
+ { "srl", FMT3 (2, 0x26), ARG_RS1_RS2_RD, },
+ { "sra", FMT3I(2, 0x27), ARG_RS1_SIMM13_RD, },
+ { "sra", FMT3 (2, 0x27), ARG_RS1_RS2_RD, },
+
+ { "wr", FMT3I(2, 0x30), ARG_RS1_SIMM13_RD, },
+ { "wr", FMT3 (2, 0x30), ARG_RS1_SIMM13_RD, },
+
+ { "save", FMT3I(2,0x3c), ARG_RS1_SIMM13_RD, },
+ { "save", FMT3 (2,0x3c), ARG_RS1_RS2_RD, },
+ { "restore", FMT3I(2,0x3d), ARG_RS1_SIMM13_RD, },
+ { "restore", FMT3 (2,0x3d), ARG_RS1_RS2_RD, },
+ { "ta", TICC(8), { ARG_SWTRAP, ARG_NONE }, },
+ { "jmpl", FMT3I(2,0x38), ARG_RS1_SIMM13_RD, },
+ { "jmpl", FMT3 (2,0x38), ARG_RS1_RS2_RD, },
+
+ { "ldx", FMT3I(3,0x0b), ARG_RS1_SIMM13_RD, },
+ { "ldx", FMT3 (3,0x0b), ARG_RS1_RS2_RD, },
+ { "lduw", FMT3I(3,0x00), ARG_RS1_SIMM13_RD, },
+ { "lduw", FMT3 (3,0x00), ARG_RS1_RS2_RD, },
+ { "lduh", FMT3I(3,0x02), ARG_RS1_SIMM13_RD, },
+ { "lduh", FMT3 (3,0x02), ARG_RS1_RS2_RD, },
+ { "ldub", FMT3I(3,0x01), ARG_RS1_SIMM13_RD, },
+ { "ldub", FMT3 (3,0x01), ARG_RS1_RS2_RD, },
+
+ { "stx", FMT3I(3,0x0e), ARG_RS1_SIMM13_RD, },
+ { "stx", FMT3 (3,0x0e), ARG_RS1_RS2_RD, },
+ { "stw", FMT3I(3,0x04), ARG_RS1_SIMM13_RD, },
+ { "stw", FMT3 (3,0x04), ARG_RS1_RS2_RD, },
+ { "sth", FMT3I(3,0x06), ARG_RS1_SIMM13_RD, },
+ { "sth", FMT3 (3,0x06), ARG_RS1_RS2_RD, },
+ { "stb", FMT3I(3,0x05), ARG_RS1_SIMM13_RD, },
+ { "stb", FMT3 (3,0x05), ARG_RS1_RS2_RD, },
+
+ { "ldf", FMT3I(3,0x20), ARG_RS1_SIMM13_RD, },
+ { "ldf", FMT3 (3,0x20), ARG_RS1_RS2_RD, },
+ { "stf", FMT3I(3,0x24), ARG_RS1_SIMM13_RD, },
+ { "stf", FMT3 (3,0x24), ARG_RS1_RS2_RD, },
+
+ { "fadd", FMT3F(2,0x34,0x041), ARG_RS1_RS2_RD, },
+ { "fsub", FMT3F(2,0x34,0x045), ARG_RS1_RS2_RD, },
+ { "fcmp", FMT3F(2,0x35,0x051), ARG_RS1_RS2, },
+ { "fstoi", FMT3F(2,0x34,0x0d1), ARG_RS2_RD, },
+ { "fitos", FMT3F(2,0x34,0x0c4), ARG_RS2_RD, },
+
+ { "fneg", FMT3F(2,0x34,0x005), ARG_RS2_RD, },
+ { "fdiv", FMT3F(2,0x34,0x04d), ARG_RS1_RS2_RD, },
+ { "fmul", FMT3F(2,0x34,0x049), ARG_RS1_RS2_RD, },
+
+ { "fbe", BFCC(0,9), { ARG_DISP22 }, },
+ { "fbne", BFCC(0,1), { ARG_DISP22 }, },
+ { "fbl", BFCC(0,4), { ARG_DISP22 }, },
+ { "fbge", BFCC(0,11), { ARG_DISP22 }, },
+ { "fbg", BFCC(0,6), { ARG_DISP22 }, },
+ { "fble", BFCC(0,13), { ARG_DISP22 }, },
+};
+#define SPARC_NUM_OPCODES (sizeof(sparc_opcodes) / sizeof(sparc_opcodes[0]))
+
+#define RS1(X) (((X) & 0x1f) << 14)
+#define RS2(X) (((X) & 0x1f) << 0)
+#define RD(X) (((X) & 0x1f) << 25)
+#define SIMM13(X) (((X) & 0x1fff) << 0)
+#define IMM22(X) (((X) & 0x3fffff) << 0)
+#define DISP30(X) ((((X) >> 2) & 0x3fffffff) << 0)
+#define DISP22(X) ((((X) >> 2) & 0x3fffff) << 0)
+#define SWTRAP(X) (((X) & 0x7f) << 0)
+
+#define SIMM13_P(X) ((unsigned int) (X) + 0x1000 < 0x2000)
+
+static void vimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
+{
+ unsigned int orig_val = val;
+ int orig_bits = bits;
+
+ if (sgned) {
+ int x = (int) val;
+ if (x < 0)
+ x = -x;
+ val = (unsigned int) x;
+ bits--;
+ }
+ if (val & ~((1U << bits) - 1U)) {
+ Com_Printf("VM ERROR: immediate value 0x%08x out of %d bit range\n",
+ orig_val, orig_bits);
+ DIE("sparc VM bug");
+ }
+}
+
+static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const int *argv)
+{
+ const struct sparc_opcode *op = &sparc_opcodes[iname];
+ unsigned int insn = op->opcode;
+ int i, flt, rd_flt;
+
+ flt = (op->name[0] == 'f');
+ rd_flt = flt || (op->name[2] == 'f');
+
+ for (i = 0; op->args[i] != ARG_NONE; i++) {
+ int val = argv[i];
+
+ switch (op->args[i]) {
+ case ARG_RS1: insn |= RS1(val); break;
+ case ARG_RS2: insn |= RS2(val); break;
+ case ARG_RD: insn |= RD(val); break;
+ case ARG_SIMM13: insn |= SIMM13(val); vimm(val,13,0,1,i); break;
+ case ARG_DISP30: insn |= DISP30(val); vimm(val,30,0,1,i); break;
+ case ARG_IMM22: insn |= IMM22(val); vimm(val,22,0,0,i); break;
+ case ARG_DISP22: insn |= DISP22(val); vimm(val,22,0,1,i); break;
+ case ARG_SWTRAP: insn |= SWTRAP(val); vimm(val,7,0,0,i); break;
+ }
+ }
+
+ return insn;
+}
+
+#define IN(inst, args...) \
+({ const int argv[] = { args }; \
+ const int argc = sizeof(argv) / sizeof(argv[0]); \
+ sparc_assemble(inst, argc, argv); \
+})
+
+#if 0
+static void pgreg(int reg_num, int arg_index, int flt)
+{
+ if (!flt) {
+ const char *fmt[] = { "%g", "%o", "%l", "%i" };
+
+ Com_Printf("%s%s%d",
+ (arg_index ? ", " : ""),
+ fmt[reg_num >> 3], reg_num & 7);
+ } else
+ Com_Printf("%s%%f%d", (arg_index ? ", " : ""), reg_num);
+}
+
+static void pimm(unsigned int val, int bits, int shift, int sgned, int arg_index)
+
+{
+ val >>= shift;
+ val &= ((1 << bits) - 1);
+ if (sgned) {
+ int sval = val << (32 - bits);
+ sval >>= (32 - bits);
+ Com_Printf("%s%d",
+ (arg_index ? ", " : ""), sval);
+ } else
+ Com_Printf("%s0x%08x",
+ (arg_index ? ", " : ""), val);
+}
+
+static void sparc_disassemble(unsigned int insn)
+{
+ int op_idx;
+
+ for (op_idx = 0; op_idx < SPARC_NUM_OPCODES; op_idx++) {
+ const struct sparc_opcode *op = &sparc_opcodes[op_idx];
+ int i, flt, rd_flt;
+
+ if ((insn & op->mask) != op->opcode)
+ continue;
+
+ flt = (op->name[0] == 'f');
+ rd_flt = flt || (op->name[2] == 'f');
+
+ Com_Printf("ASM: %7s\t", op->name);
+ for (i = 0; op->args[i] != ARG_NONE; i++) {
+ switch (op->args[i]) {
+ case ARG_RS1: pgreg((insn >> 14) & 0x1f, i, flt); break;
+ case ARG_RS2: pgreg((insn >> 0) & 0x1f, i, flt); break;
+ case ARG_RD: pgreg((insn >> 25) & 0x1f, i, rd_flt); break;
+ case ARG_SIMM13: pimm(insn, 13, 0, 1, i); break;
+ case ARG_DISP30: pimm(insn, 30, 0, 0, i); break;
+ case ARG_IMM22: pimm(insn, 22, 0, 0, i); break;
+ case ARG_DISP22: pimm(insn, 22, 0, 0, i); break;
+ case ARG_SWTRAP: pimm(insn, 7, 0, 0, i); break;
+ }
+ }
+ Com_Printf("\n");
+ return;
+ }
+}
+#endif
+
+/*
+ * opcode information table:
+ * - length of immediate value
+ * - returned register type
+ * - required register(s) type
+ */
+#define opImm0 0x0000 /* no immediate */
+#define opImm1 0x0001 /* 1 byte immadiate value after opcode */
+#define opImm4 0x0002 /* 4 bytes immediate value after opcode */
+
+#define opRet0 0x0000 /* returns nothing */
+#define opRetI 0x0004 /* returns integer */
+#define opRetF 0x0008 /* returns float */
+#define opRetIF (opRetI | opRetF) /* returns integer or float */
+
+#define opArg0 0x0000 /* requires nothing */
+#define opArgI 0x0010 /* requires integer(s) */
+#define opArgF 0x0020 /* requires float(s) */
+#define opArgIF (opArgI | opArgF) /* requires integer or float */
+
+#define opArg2I 0x0040 /* requires second argument, integer */
+#define opArg2F 0x0080 /* requires second argument, float */
+#define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */
+
+static const unsigned char vm_opInfo[256] =
+{
+ [OP_UNDEF] = opImm0,
+ [OP_IGNORE] = opImm0,
+ [OP_BREAK] = opImm0,
+ [OP_ENTER] = opImm4,
+ /* OP_LEAVE has to accept floats, they will be converted to ints */
+ [OP_LEAVE] = opImm4 | opRet0 | opArgIF,
+ /* only STORE4 and POP use values from OP_CALL,
+ * no need to convert floats back */
+ [OP_CALL] = opImm0 | opRetI | opArgI,
+ [OP_PUSH] = opImm0 | opRetIF,
+ [OP_POP] = opImm0 | opRet0 | opArgIF,
+ [OP_CONST] = opImm4 | opRetIF,
+ [OP_LOCAL] = opImm4 | opRetI,
+ [OP_JUMP] = opImm0 | opRet0 | opArgI,
+
+ [OP_EQ] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_NE] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LTI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LEI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GTI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GEI] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LTU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_LEU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GTU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_GEU] = opImm4 | opRet0 | opArgI | opArg2I,
+ [OP_EQF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_NEF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_LTF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_LEF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_GTF] = opImm4 | opRet0 | opArgF | opArg2F,
+ [OP_GEF] = opImm4 | opRet0 | opArgF | opArg2F,
+
+ [OP_LOAD1] = opImm0 | opRetI | opArgI,
+ [OP_LOAD2] = opImm0 | opRetI | opArgI,
+ [OP_LOAD4] = opImm0 | opRetIF| opArgI,
+ [OP_STORE1] = opImm0 | opRet0 | opArgI | opArg2I,
+ [OP_STORE2] = opImm0 | opRet0 | opArgI | opArg2I,
+ [OP_STORE4] = opImm0 | opRet0 | opArgIF| opArg2I,
+ [OP_ARG] = opImm1 | opRet0 | opArgIF,
+ [OP_BLOCK_COPY] = opImm4 | opRet0 | opArgI | opArg2I,
+
+ [OP_SEX8] = opImm0 | opRetI | opArgI,
+ [OP_SEX16] = opImm0 | opRetI | opArgI,
+ [OP_NEGI] = opImm0 | opRetI | opArgI,
+ [OP_ADD] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_SUB] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_DIVI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_DIVU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MODI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MODU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MULI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_MULU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BAND] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BOR] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BXOR] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_BCOM] = opImm0 | opRetI | opArgI,
+ [OP_LSH] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_RSHI] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_RSHU] = opImm0 | opRetI | opArgI | opArg2I,
+ [OP_NEGF] = opImm0 | opRetF | opArgF,
+ [OP_ADDF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_SUBF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_DIVF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_MULF] = opImm0 | opRetF | opArgF | opArg2F,
+ [OP_CVIF] = opImm0 | opRetF | opArgI,
+ [OP_CVFI] = opImm0 | opRetI | opArgF,
+};
+
+static const char *opnames[256] = {
+ "OP_UNDEF", "OP_IGNORE", "OP_BREAK", "OP_ENTER", "OP_LEAVE", "OP_CALL",
+ "OP_PUSH", "OP_POP", "OP_CONST", "OP_LOCAL", "OP_JUMP",
+ "OP_EQ", "OP_NE", "OP_LTI", "OP_LEI", "OP_GTI", "OP_GEI",
+ "OP_LTU", "OP_LEU", "OP_GTU", "OP_GEU", "OP_EQF", "OP_NEF",
+ "OP_LTF", "OP_LEF", "OP_GTF", "OP_GEF",
+ "OP_LOAD1", "OP_LOAD2", "OP_LOAD4", "OP_STORE1", "OP_STORE2",
+ "OP_STORE4", "OP_ARG", "OP_BLOCK_COPY",
+ "OP_SEX8", "OP_SEX16",
+ "OP_NEGI", "OP_ADD", "OP_SUB", "OP_DIVI", "OP_DIVU",
+ "OP_MODI", "OP_MODU", "OP_MULI", "OP_MULU", "OP_BAND",
+ "OP_BOR", "OP_BXOR", "OP_BCOM", "OP_LSH", "OP_RSHI", "OP_RSHU",
+ "OP_NEGF", "OP_ADDF", "OP_SUBF", "OP_DIVF", "OP_MULF",
+ "OP_CVIF", "OP_CVFI",
+};
+
+static void VM_Destroy_Compiled(vm_t *vm)
+{
+ if (vm->codeBase) {
+ if (munmap(vm->codeBase, vm->codeLength))
+ Com_Printf(S_COLOR_RED "Memory unmap failed, possible memory leak\n");
+ }
+ vm->codeBase = NULL;
+}
+
+typedef struct VM_Data {
+ unsigned int dataLength;
+ unsigned int codeLength;
+ unsigned int *CallThunk;
+ int (*AsmCall)(int, int);
+ void (*BlockCopy)(unsigned int, unsigned int, unsigned int);
+ unsigned int *iPointers;
+ unsigned int data[0];
+} vm_data_t;
+
+#ifdef offsetof
+# define VM_Data_Offset(field) offsetof(vm_data_t, field)
+#else
+# define OFFSET(structName, field) \
+ ((void *)&(((structName *)NULL)->field) - NULL)
+# define VM_Data_Offset(field) OFFSET(vm_data_t, field)
+#endif
+
+struct src_insn {
+ unsigned char op;
+ unsigned int i_count;
+
+ union {
+ unsigned int i;
+ signed int si;
+ signed short ss[2];
+ unsigned short us[2];
+ unsigned char b;
+ } arg;
+
+ unsigned char dst_reg_flags;
+ unsigned char src1_reg_flags;
+ unsigned char src2_reg_flags;
+#define REG_FLAGS_FLOAT 0x1
+
+ struct src_insn *next;
+};
+
+struct dst_insn;
+struct jump_insn {
+ enum sparc_iname jump_iname;
+ int jump_dest_insn;
+ struct dst_insn *parent;
+ struct jump_insn *next;
+};
+
+struct dst_insn {
+ struct dst_insn *next;
+
+ unsigned int count;
+ unsigned int i_count;
+
+ struct jump_insn *jump;
+ unsigned int length;
+ unsigned int code[0];
+};
+
+#define HUNK_SIZE 29
+struct data_hunk {
+ struct data_hunk *next;
+ int count;
+ unsigned int data[HUNK_SIZE];
+};
+
+struct func_info {
+ struct src_insn *first;
+ struct src_insn *last;
+ int has_call;
+ int need_float_tmp;
+
+ struct src_insn *cached_const;
+
+ int stack_space;
+ int gpr_pos;
+#define rFIRST(fp) ((fp)->gpr_pos - 1)
+#define rSECOND(fp) ((fp)->gpr_pos - 2)
+#define POP_GPR(fp) ((fp)->gpr_pos--)
+#define PUSH_GPR(fp) ((fp)->gpr_pos++)
+
+ int fpr_pos;
+#define fFIRST(fp) ((fp)->fpr_pos - 1)
+#define fSECOND(fp) ((fp)->fpr_pos - 2)
+#define POP_FPR(fp) ((fp)->fpr_pos--)
+#define PUSH_FPR(fp) ((fp)->fpr_pos++)
+
+#define INSN_BUF_SIZE 50
+ unsigned int insn_buf[INSN_BUF_SIZE];
+ int insn_index;
+
+ int saved_icount;
+ int force_emit;
+
+ struct jump_insn *jump_first;
+ struct jump_insn *jump_last;
+
+ struct dst_insn *dst_first;
+ struct dst_insn *dst_last;
+ int dst_count;
+
+ struct dst_insn **dst_by_i_count;
+
+ struct data_hunk *data_first;
+ int data_num;
+};
+
+#define THUNK_ICOUNT -1
+
+static unsigned int sparc_push_data(struct func_info * const fp, unsigned int val)
+{
+ struct data_hunk *last, *dp = fp->data_first;
+ int off = 0;
+
+ last = NULL;
+ while (dp) {
+ int i;
+
+ for (i = 0; i < dp->count; i++) {
+ if (dp->data[i] == val) {
+ off += i;
+ return VM_Data_Offset(data[off]);
+ }
+ }
+ off += dp->count;
+ last = dp;
+ dp = dp->next;
+ }
+
+ dp = last;
+ if (!dp || dp->count >= HUNK_SIZE) {
+ struct data_hunk *new = Z_Malloc(sizeof(*new));
+ if (!dp)
+ fp->data_first = new;
+ else
+ dp->next = new;
+ dp = new;
+ dp->count = 0;
+ dp->next = NULL;
+ }
+ dp->data[dp->count++] = val;
+ fp->data_num = off + 1;
+ return VM_Data_Offset(data[off]);
+}
+
+static void dst_insn_insert_tail(struct func_info * const fp,
+ struct dst_insn *dp)
+{
+ if (!fp->dst_first) {
+ fp->dst_first = fp->dst_last = dp;
+ } else {
+ fp->dst_last->next = dp;
+ fp->dst_last = dp;
+ }
+}
+
+static void jump_insn_insert_tail(struct func_info * const fp,
+ struct jump_insn *jp)
+{
+ if (!fp->jump_first) {
+ fp->jump_first = fp->jump_last = jp;
+ } else {
+ fp->jump_last->next = jp;
+ fp->jump_last = jp;
+ }
+}
+
+static struct dst_insn *dst_new(struct func_info * const fp, unsigned int length,
+ struct jump_insn *jp, int insns_size)
+{
+ struct dst_insn *dp = Z_Malloc(sizeof(struct dst_insn) + insns_size);
+
+ dp->length = length;
+ dp->jump = jp;
+ dp->count = fp->dst_count++;
+ dp->i_count = fp->saved_icount;
+ dp->next = NULL;
+ if (fp->saved_icount != THUNK_ICOUNT)
+ fp->dst_by_i_count[fp->saved_icount] = dp;
+
+ return dp;
+}
+
+static void dst_insn_append(struct func_info * const fp)
+{
+ int insns_size = (sizeof(unsigned int) * fp->insn_index);
+ struct dst_insn *dp;
+
+ dp = dst_new(fp, fp->insn_index, NULL, insns_size);
+ if (insns_size)
+ memcpy(&dp->code[0], fp->insn_buf, insns_size);
+ dst_insn_insert_tail(fp, dp);
+
+ fp->insn_index = 0;
+}
+
+static void jump_insn_append(struct func_info * const fp, enum sparc_iname iname, int dest)
+{
+ struct jump_insn *jp = Z_Malloc(sizeof(*jp));
+ struct dst_insn *dp;
+
+ dp = dst_new(fp, 2, jp, 0);
+
+ jp->jump_iname = iname;
+ jp->jump_dest_insn = dest;
+ jp->parent = dp;
+ jp->next = NULL;
+
+ jump_insn_insert_tail(fp, jp);
+ dst_insn_insert_tail(fp, dp);
+}
+
+static void start_emit(struct func_info * const fp, int i_count)
+{
+ fp->saved_icount = i_count;
+ fp->insn_index = 0;
+ fp->force_emit = 0;
+}
+
+static void __do_emit_one(struct func_info * const fp, unsigned int insn)
+{
+ fp->insn_buf[fp->insn_index++] = insn;
+}
+
+#define in(inst, args...) __do_emit_one(fp, IN(inst, args))
+
+static void end_emit(struct func_info * const fp)
+{
+ if (fp->insn_index || fp->force_emit)
+ dst_insn_append(fp);
+}
+
+static void emit_jump(struct func_info * const fp, enum sparc_iname iname, int dest)
+{
+ end_emit(fp);
+ jump_insn_append(fp, iname, dest);
+}
+
+static void analyze_function(struct func_info * const fp)
+{
+ struct src_insn *value_provider[20] = { NULL };
+ struct src_insn *sp = fp->first;
+ int opstack_depth = 0;
+
+ while ((sp = sp->next) != NULL) {
+ unsigned char opi, op = sp->op;
+
+ opi = vm_opInfo[op];
+ if (opi & opArgIF) {
+ struct src_insn *vp = value_provider[--opstack_depth];
+ unsigned char vpopi = vm_opInfo[vp->op];
+
+ if ((opi & opArgI) && (vpopi & opRetI)) {
+ /* src1 and dst are integers */
+ } else if ((opi & opArgF) && (vpopi & opRetF)) {
+ /* src1 and dst are floats */
+ vp->dst_reg_flags |= REG_FLAGS_FLOAT;
+ sp->src1_reg_flags = REG_FLAGS_FLOAT;
+ } else {
+ /* illegal combination */
+ DIE("unrecognized instruction combination");
+ }
+ }
+ if (opi & opArg2IF) {
+ struct src_insn *vp = value_provider[--opstack_depth];
+ unsigned char vpopi = vm_opInfo[vp->op];
+
+ if ((opi & opArg2I) && (vpopi & opRetI)) {
+ /* src2 and dst are integers */
+ } else if ( (opi & opArg2F) && (vpopi & opRetF) ) {
+ /* src2 and dst are floats */
+ vp->dst_reg_flags |= REG_FLAGS_FLOAT;
+ sp->src2_reg_flags = REG_FLAGS_FLOAT;
+ } else {
+ /* illegal combination */
+ DIE("unrecognized instruction combination");
+ }
+ }
+ if (opi & opRetIF) {
+ value_provider[opstack_depth] = sp;
+ opstack_depth++;
+ }
+ }
+}
+
+static int asmcall(int call, int pstack)
+{
+ vm_t *savedVM = currentVM;
+ int i, ret;
+
+ currentVM->programStack = pstack - 4;
+ if (sizeof(intptr_t) == sizeof(int)) {
+ intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4);
+ argPosition[0] = -1 - call;
+ ret = currentVM->systemCall(argPosition);
+ } else {
+ intptr_t args[11];
+
+ args[0] = -1 - call;
+ int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4);
+ for( i = 1; i < 11; i++ )
+ args[i] = argPosition[i];
+
+ ret = currentVM->systemCall(args);
+ }
+
+ currentVM = savedVM;
+
+ return ret;
+}
+
+static void blockcopy(unsigned int dest, unsigned int src, unsigned int count)
+{
+ unsigned int dataMask = currentVM->dataMask;
+
+ if ((dest & dataMask) != dest ||
+ (src & dataMask) != src ||
+ ((dest+count) & dataMask) != dest + count ||
+ ((src+count) & dataMask) != src + count) {
+ DIE("OP_BLOCK_COPY out of range!");
+ }
+
+ memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count);
+}
+
+static void do_emit_const(struct func_info * const fp, struct src_insn *sp)
+{
+ start_emit(fp, sp->i_count);
+ if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
+ in(LDFI, rVMDATA, sparc_push_data(fp, sp->arg.i), fFIRST(fp));
+ } else {
+ if ((sp->arg.i & ~0x3ff) == 0) {
+ in(ORI, G0, sp->arg.i & 0x3ff, rFIRST(fp));
+ } else if ((sp->arg.i & 0x3ff) == 0) {
+ in(SETHI, sp->arg.i >> 10, rFIRST(fp));
+ } else {
+ in(SETHI, sp->arg.i >> 10, rFIRST(fp));
+ in(ORI, rFIRST(fp), sp->arg.i & 0x3ff, rFIRST(fp));
+ }
+ }
+ end_emit(fp);
+}
+
+#define MAYBE_EMIT_CONST(fp) \
+do { if ((fp)->cached_const) { \
+ int saved_i_count = (fp)->saved_icount; \
+ do_emit_const(fp, (fp)->cached_const); \
+ (fp)->saved_icount = saved_i_count; \
+ } \
+} while (0)
+
+#define EMIT_FALSE_CONST(fp) \
+do { int saved_i_count = (fp)->saved_icount; \
+ (fp)->saved_icount = (fp)->cached_const->i_count; \
+ dst_insn_append(fp); \
+ (fp)->saved_icount = saved_i_count; \
+} while (0)
+
+static void compile_one_insn(struct func_info * const fp, struct src_insn *sp)
+{
+ start_emit(fp, sp->i_count);
+
+ switch (sp->op) {
+ default:
+ Com_Printf("VM: Unhandled opcode 0x%02x[%s]\n",
+ sp->op,
+ opnames[sp->op] ? opnames[sp->op] : "UNKNOWN");
+ DIE("Unsupported opcode");
+ break;
+
+ case OP_ENTER: {
+ int stack = SL(64, 128);
+
+ if (fp->need_float_tmp)
+ stack += 16;
+
+ in(SAVEI, O6, -stack, O6);
+ if (!SIMM13_P(sp->arg.si)) {
+ in(SETHI, sp->arg.i >> 10, rTMP);
+ in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
+ in(SUB, rPSTACK, rTMP, rPSTACK);
+ } else
+ in(SUBI, rPSTACK, sp->arg.si, rPSTACK);
+ break;
+ }
+ case OP_LEAVE:
+ if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
+ EMIT_FALSE_CONST(fp);
+ if (fp->cached_const->src1_reg_flags & REG_FLAGS_FLOAT)
+ DIE("constant float in OP_LEAVE");
+
+ if (!SIMM13_P(sp->arg.si)) {
+ in(SETHI, sp->arg.i >> 10, rTMP);
+ in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
+ in(ADD, rPSTACK, rTMP, rPSTACK);
+ } else
+ in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
+ in(JMPLI, I7, 8, G0);
+ in(RESTOREI, G0, fp->cached_const->arg.si, O0);
+ POP_GPR(fp);
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ if (!SIMM13_P(sp->arg.si)) {
+ in(SETHI, sp->arg.i >> 10, rTMP);
+ in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
+ in(ADD, rPSTACK, rTMP, rPSTACK);
+ } else
+ in(ADDI, rPSTACK, sp->arg.si, rPSTACK);
+ if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
+ in(STFI, O6, SL(64, 128), fFIRST(fp));
+ in(LDUWI, O6, SL(64, 128), O0);
+ in(JMPLI, I7, 8, G0);
+ in(RESTORE, O0, G0, O0);
+ POP_FPR(fp);
+ } else {
+ in(JMPLI, I7, 8, G0);
+ in(RESTORE, rFIRST(fp), G0, O0);
+ POP_GPR(fp);
+ }
+ }
+ assert(fp->gpr_pos == L0);
+ assert(fp->fpr_pos == F0);
+ break;
+ case OP_JUMP:
+ if (fp->cached_const) {
+ EMIT_FALSE_CONST(fp);
+ emit_jump(fp, BA, fp->cached_const->arg.i);
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP);
+ in(SLLI, rFIRST(fp), 2, rFIRST(fp));
+ in(LDL, rTMP, rFIRST(fp), rTMP);
+ in(JMPL, rTMP, G0, G0);
+ in(NOP);
+ }
+ POP_GPR(fp);
+ break;
+ case OP_CALL:
+ if (fp->cached_const) {
+ EMIT_FALSE_CONST(fp);
+ if (fp->cached_const->arg.si >= 0) {
+ emit_jump(fp, CALL, fp->cached_const->arg.i);
+ } else {
+ in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
+ in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
+ in(ORI, G0, fp->cached_const->arg.si, O0);
+ in(JMPL, rTMP, G0, O7);
+ in(OR, G0, rPSTACK, O1);
+ }
+ in(OR, G0, O0, rFIRST(fp));
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(SUBCCI, rFIRST(fp), 0, G0);
+ in(BL, +4*7);
+ in(NOP);
+
+ /* normal call */
+ in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5);
+ in(SLLI, rFIRST(fp), 2, rFIRST(fp));
+ in(LDL, O5, rFIRST(fp), rTMP);
+ in(BA, +4*4);
+ in(NOP);
+
+ /* syscall */
+ in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
+ in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3);
+
+ in(OR, G0, rFIRST(fp), O0);
+ in(JMPL, rTMP, G0, O7);
+ in(OR, G0, rPSTACK, O1);
+
+ /* return value */
+ in(OR, G0, O0, rFIRST(fp));
+ }
+ break;
+ case OP_BLOCK_COPY:
+ MAYBE_EMIT_CONST(fp);
+ in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP);
+ in(LDLI, rVMDATA, VM_Data_Offset(BlockCopy), O3);
+ in(OR, G0, rSECOND(fp), O0);
+ in(OR, G0, rFIRST(fp), O1);
+ if ((sp->arg.i & ~0x3ff) == 0) {
+ in(ORI, G0, sp->arg.i & 0x3ff, O2);
+ } else if ((sp->arg.i & 0x3ff) == 0) {
+ in(SETHI, sp->arg.i >> 10, O2);
+ } else {
+ in(SETHI, sp->arg.i >> 10, O2);
+ in(ORI, O2, sp->arg.i & 0x3ff, O2);
+ }
+ in(JMPL, rTMP, G0, O7);
+ in(NOP);
+ POP_GPR(fp);
+ POP_GPR(fp);
+ break;
+
+ case OP_PUSH:
+ MAYBE_EMIT_CONST(fp);
+ if (sp->dst_reg_flags & REG_FLAGS_FLOAT)
+ PUSH_FPR(fp);
+ else
+ PUSH_GPR(fp);
+ fp->force_emit = 1;
+ break;
+ case OP_POP:
+ MAYBE_EMIT_CONST(fp);
+ if (sp->src1_reg_flags & REG_FLAGS_FLOAT)
+ POP_FPR(fp);
+ else
+ POP_GPR(fp);
+ fp->force_emit = 1;
+ break;
+ case OP_ARG:
+ MAYBE_EMIT_CONST(fp);
+ in(ADDI, rPSTACK, sp->arg.b, rTMP);
+ if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
+ in(STF, rDATABASE, rTMP, fFIRST(fp));
+ POP_FPR(fp);
+ } else {
+ in(STW, rDATABASE, rTMP, rFIRST(fp));
+ POP_GPR(fp);
+ }
+ break;
+ case OP_IGNORE:
+ MAYBE_EMIT_CONST(fp);
+ in(NOP);
+ break;
+ case OP_BREAK:
+ MAYBE_EMIT_CONST(fp);
+ in(TA, 0x5);
+ break;
+ case OP_LOCAL:
+ MAYBE_EMIT_CONST(fp);
+ PUSH_GPR(fp);
+ if (!SIMM13_P(sp->arg.i)) {
+ in(SETHI, sp->arg.i >> 10, rTMP);
+ in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP);
+ in(ADD, rPSTACK, rTMP, rFIRST(fp));
+ } else
+ in(ADDI, rPSTACK, sp->arg.i, rFIRST(fp));
+ break;
+ case OP_CONST:
+ MAYBE_EMIT_CONST(fp);
+ break;
+ case OP_LOAD4:
+ MAYBE_EMIT_CONST(fp);
+ in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
+ if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
+ PUSH_FPR(fp);
+ in(LDF, rFIRST(fp), rDATABASE, fFIRST(fp));
+ POP_GPR(fp);
+ } else {
+ in(LDUW, rFIRST(fp), rDATABASE, rFIRST(fp));
+ }
+ break;
+ case OP_LOAD2:
+ MAYBE_EMIT_CONST(fp);
+ in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
+ in(LDUH, rFIRST(fp), rDATABASE, rFIRST(fp));
+ break;
+ case OP_LOAD1:
+ MAYBE_EMIT_CONST(fp);
+ in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
+ in(LDUB, rFIRST(fp), rDATABASE, rFIRST(fp));
+ break;
+ case OP_STORE4:
+ MAYBE_EMIT_CONST(fp);
+ if (sp->src1_reg_flags & REG_FLAGS_FLOAT) {
+ in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp));
+ in(STF, rFIRST(fp), rDATABASE, fFIRST(fp));
+ POP_FPR(fp);
+ } else {
+ in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
+ in(STW, rSECOND(fp), rDATABASE, rFIRST(fp));
+ POP_GPR(fp);
+ }
+ POP_GPR(fp);
+ break;
+ case OP_STORE2:
+ MAYBE_EMIT_CONST(fp);
+ in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
+ in(STH, rSECOND(fp), rDATABASE, rFIRST(fp));
+ POP_GPR(fp);
+ POP_GPR(fp);
+ break;
+ case OP_STORE1:
+ MAYBE_EMIT_CONST(fp);
+ in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp));
+ in(STB, rSECOND(fp), rDATABASE, rFIRST(fp));
+ POP_GPR(fp);
+ POP_GPR(fp);
+ break;
+ case OP_EQ:
+ case OP_NE:
+ case OP_LTI:
+ case OP_GEI:
+ case OP_GTI:
+ case OP_LEI:
+ case OP_LTU:
+ case OP_GEU:
+ case OP_GTU:
+ case OP_LEU: {
+ enum sparc_iname iname = BA;
+
+ if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
+ EMIT_FALSE_CONST(fp);
+ in(SUBCCI, rSECOND(fp), fp->cached_const->arg.si, G0);
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(SUBCC, rSECOND(fp), rFIRST(fp), G0);
+ }
+ switch(sp->op) {
+ case OP_EQ: iname = BE; break;
+ case OP_NE: iname = BNE; break;
+ case OP_LTI: iname = BL; break;
+ case OP_GEI: iname = BGE; break;
+ case OP_GTI: iname = BG; break;
+ case OP_LEI: iname = BLE; break;
+ case OP_LTU: iname = BCS; break;
+ case OP_GEU: iname = BCC; break;
+ case OP_GTU: iname = BGU; break;
+ case OP_LEU: iname = BLEU; break;
+ }
+ emit_jump(fp, iname, sp->arg.i);
+ POP_GPR(fp);
+ POP_GPR(fp);
+ break;
+ }
+
+ case OP_SEX8:
+ MAYBE_EMIT_CONST(fp);
+ in(SLLI, rFIRST(fp), 24, rFIRST(fp));
+ in(SRAI, rFIRST(fp), 24, rFIRST(fp));
+ break;
+ case OP_SEX16:
+ MAYBE_EMIT_CONST(fp);
+ in(SLLI, rFIRST(fp), 16, rFIRST(fp));
+ in(SRAI, rFIRST(fp), 16, rFIRST(fp));
+ break;
+ case OP_NEGI:
+ MAYBE_EMIT_CONST(fp);
+ in(SUB, G0, rFIRST(fp), rFIRST(fp));
+ break;
+ case OP_ADD:
+ if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
+ EMIT_FALSE_CONST(fp);
+ in(ADDI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(ADD, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ }
+ POP_GPR(fp);
+ break;
+ case OP_SUB:
+ if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) {
+ EMIT_FALSE_CONST(fp);
+ in(SUBI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(SUB, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ }
+ POP_GPR(fp);
+ break;
+ case OP_DIVI:
+ MAYBE_EMIT_CONST(fp);
+ in(SRAI, rSECOND(fp), 31, rTMP);
+ in(WRI, rTMP, 0, Y_REG);
+ in(SDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_DIVU:
+ MAYBE_EMIT_CONST(fp);
+ in(WRI, G0, 0, Y_REG);
+ in(UDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_MODI:
+ MAYBE_EMIT_CONST(fp);
+ in(SRAI, rSECOND(fp), 31, rTMP);
+ in(WRI, rTMP, 0, Y_REG);
+ in(SDIV, rSECOND(fp), rFIRST(fp), rTMP);
+ in(SMUL, rTMP, rFIRST(fp), rTMP);
+ in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_MODU:
+ MAYBE_EMIT_CONST(fp);
+ in(WRI, G0, 0, Y_REG);
+ in(UDIV, rSECOND(fp), rFIRST(fp), rTMP);
+ in(SMUL, rTMP, rFIRST(fp), rTMP);
+ in(SUB, rSECOND(fp), rTMP, rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_MULI:
+ MAYBE_EMIT_CONST(fp);
+ in(SMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_MULU:
+ MAYBE_EMIT_CONST(fp);
+ in(UMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_BAND:
+ MAYBE_EMIT_CONST(fp);
+ in(AND, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_BOR:
+ MAYBE_EMIT_CONST(fp);
+ in(OR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_BXOR:
+ MAYBE_EMIT_CONST(fp);
+ in(XOR, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ POP_GPR(fp);
+ break;
+ case OP_BCOM:
+ MAYBE_EMIT_CONST(fp);
+ in(XNOR, rFIRST(fp), G0, rFIRST(fp));
+ break;
+ case OP_LSH:
+ if (fp->cached_const) {
+ EMIT_FALSE_CONST(fp);
+ in(SLLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(SLL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ }
+ POP_GPR(fp);
+ break;
+ case OP_RSHI:
+ if (fp->cached_const) {
+ EMIT_FALSE_CONST(fp);
+ in(SRAI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(SRA, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ }
+ POP_GPR(fp);
+ break;
+ case OP_RSHU:
+ if (fp->cached_const) {
+ EMIT_FALSE_CONST(fp);
+ in(SRLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp));
+ } else {
+ MAYBE_EMIT_CONST(fp);
+ in(SRL, rSECOND(fp), rFIRST(fp), rSECOND(fp));
+ }
+ POP_GPR(fp);
+ break;
+
+ case OP_NEGF:
+ MAYBE_EMIT_CONST(fp);
+ in(FNEG, fFIRST(fp), fFIRST(fp));
+ break;
+ case OP_ADDF:
+ MAYBE_EMIT_CONST(fp);
+ in(FADD, fSECOND(fp), fFIRST(fp), fSECOND(fp));
+ POP_FPR(fp);
+ break;
+ case OP_SUBF:
+ MAYBE_EMIT_CONST(fp);
+ in(FSUB, fSECOND(fp), fFIRST(fp), fSECOND(fp));
+ POP_FPR(fp);
+ break;
+ case OP_DIVF:
+ MAYBE_EMIT_CONST(fp);
+ in(FDIV, fSECOND(fp), fFIRST(fp), fSECOND(fp));
+ POP_FPR(fp);
+ break;
+ case OP_MULF:
+ MAYBE_EMIT_CONST(fp);
+ in(FMUL, fSECOND(fp), fFIRST(fp), fSECOND(fp));
+ POP_FPR(fp);
+ break;
+
+ case OP_EQF:
+ case OP_NEF:
+ case OP_LTF:
+ case OP_GEF:
+ case OP_GTF:
+ case OP_LEF: {
+ enum sparc_iname iname = FBE;
+
+ MAYBE_EMIT_CONST(fp);
+ in(FCMP, fSECOND(fp), fFIRST(fp));
+ switch(sp->op) {
+ case OP_EQF: iname = FBE; break;
+ case OP_NEF: iname = FBNE; break;
+ case OP_LTF: iname = FBL; break;
+ case OP_GEF: iname = FBGE; break;
+ case OP_GTF: iname = FBG; break;
+ case OP_LEF: iname = FBLE; break;
+ }
+ emit_jump(fp, iname, sp->arg.i);
+ POP_FPR(fp);
+ POP_FPR(fp);
+ break;
+ }
+ case OP_CVIF:
+ MAYBE_EMIT_CONST(fp);
+ PUSH_FPR(fp);
+ in(STWI, O6, SL(64, 128), rFIRST(fp));
+ in(LDFI, O6, SL(64, 128), fFIRST(fp));
+ in(FITOS, fFIRST(fp), fFIRST(fp));
+ POP_GPR(fp);
+ break;
+ case OP_CVFI:
+ MAYBE_EMIT_CONST(fp);
+ PUSH_GPR(fp);
+ in(FSTOI, fFIRST(fp), fFIRST(fp));
+ in(STFI, O6, SL(64, 128), fFIRST(fp));
+ in(LDUWI, O6, SL(64, 128), rFIRST(fp));
+ POP_FPR(fp);
+ break;
+ }
+ if (sp->op != OP_CONST) {
+ fp->cached_const = NULL;
+ end_emit(fp);
+ } else {
+ fp->cached_const = sp;
+ if (sp->dst_reg_flags & REG_FLAGS_FLOAT) {
+ PUSH_FPR(fp);
+ } else {
+ PUSH_GPR(fp);
+ }
+ }
+ end_emit(fp);
+}
+
+static void free_source_insns(struct func_info * const fp)
+{
+ struct src_insn *sp = fp->first->next;
+
+ while (sp) {
+ struct src_insn *next = sp->next;
+ Z_Free(sp);
+ sp = next;
+ }
+}
+
+static void compile_function(struct func_info * const fp)
+{
+ struct src_insn *sp;
+
+ analyze_function(fp);
+
+ fp->gpr_pos = L0;
+ fp->fpr_pos = F0;
+ fp->insn_index = 0;
+
+ fp->stack_space = SL(64, 128);
+ fp->cached_const = NULL;
+
+ sp = fp->first;
+ while ((sp = sp->next) != NULL)
+ compile_one_insn(fp, sp);
+
+ free_source_insns(fp);
+}
+
+/* We have two thunks for sparc. The first is for the entry into
+ * the VM, where setup the fixed global registers. The second is
+ * for calling out to C code from the VM, where we need to preserve
+ * those fixed globals across the call.
+ */
+static void emit_vm_thunk(struct func_info * const fp)
+{
+ /* int vm_thunk(void *vmdata, int programstack, void *database, int datamask) */
+ start_emit(fp, THUNK_ICOUNT);
+
+ in(OR, G0, O0, rVMDATA);
+ in(OR, G0, O1, rPSTACK);
+ in(OR, G0, O2, rDATABASE);
+ in(BA, +4*17);
+ in(OR, G0, O3, rDATAMASK);
+
+ /* int call_thunk(int arg0, int arg1, int arg2, int (*func)(int int int)) */
+#define CALL_THUNK_INSN_OFFSET 5
+ in(SAVEI, O6, -SL(64, 128), O6);
+
+ in(OR, G0, rVMDATA, L0);
+ in(OR, G0, rPSTACK, L1);
+ in(OR, G0, rDATABASE, L2);
+ in(OR, G0, rDATAMASK, L3);
+
+ in(OR, G0, I0, O0);
+ in(OR, G0, I1, O1);
+ in(JMPL, I3, G0, O7);
+ in(OR, G0, I2, O2);
+
+ in(OR, G0, L0, rVMDATA);
+ in(OR, G0, L1, rPSTACK);
+ in(OR, G0, L2, rDATABASE);
+ in(OR, G0, L3, rDATAMASK);
+
+ in(JMPLI, I7, 8, G0);
+ in(RESTORE, O0, G0, O0);
+
+ end_emit(fp);
+}
+
+static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
+{
+ struct dst_insn *dp = fp->dst_first;
+ unsigned int *code_now, *code_begin;
+ unsigned char *data_and_code;
+ unsigned int code_length;
+ int code_insns = 0, off;
+ struct data_hunk *dhp;
+ struct jump_insn *jp;
+ vm_data_t *data;
+
+ while (dp) {
+ code_insns += dp->length;
+ dp = dp->next;
+ }
+
+ code_length = (sizeof(vm_data_t) +
+ (fp->data_num * sizeof(unsigned int)) +
+ (code_insns * sizeof(unsigned int)));
+
+ data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (!data_and_code)
+ DIE("Not enough memory");
+
+ code_now = code_begin = (unsigned int *)
+ (data_and_code + VM_Data_Offset(data[fp->data_num]));
+
+ dp = fp->dst_first;
+ while (dp) {
+ int i_count = dp->i_count;
+
+ if (i_count != THUNK_ICOUNT) {
+ if (!fp->dst_by_i_count[i_count])
+ fp->dst_by_i_count[i_count] = (void *) code_now;
+ }
+ if (!dp->jump) {
+ memcpy(code_now, &dp->code[0], dp->length * sizeof(unsigned int));
+ code_now += dp->length;
+ } else {
+ int i;
+
+ dp->jump->parent = (void *) code_now;
+
+ for (i = 0; i < dp->length; i++)
+ code_now[i] = SPARC_NOP;
+ code_now += dp->length;
+ }
+
+ dp = dp->next;
+ }
+
+ jp = fp->jump_first;
+ while (jp) {
+ unsigned int *from = (void *) jp->parent;
+ unsigned int *to = (void *) fp->dst_by_i_count[jp->jump_dest_insn];
+ signed int disp = (to - from);
+
+ *from = IN(jp->jump_iname, disp << 2);
+
+ jp = jp->next;
+ }
+
+ vm->codeBase = data_and_code;
+ vm->codeLength = code_length;
+
+ data = (vm_data_t *) data_and_code;
+ data->CallThunk = code_begin + CALL_THUNK_INSN_OFFSET;
+ data->AsmCall = asmcall;
+ data->BlockCopy = blockcopy;
+ data->iPointers = (unsigned int *) vm->instructionPointers;
+ data->dataLength = VM_Data_Offset(data[fp->data_num]);
+ data->codeLength = (code_now - code_begin) * sizeof(unsigned int);
+
+#if 0
+ {
+ unsigned int *insn = code_begin;
+ int i;
+
+ Com_Printf("INSN DUMP\n");
+ for (i = 0; i < data->codeLength / 4; i+= 8) {
+ Com_Printf("\t.word\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ insn[i + 0], insn[i + 1],
+ insn[i + 2], insn[i + 3],
+ insn[i + 4], insn[i + 5],
+ insn[i + 6], insn[i + 7]);
+ }
+ }
+#endif
+
+ dhp = fp->data_first;
+ off = 0;
+ while (dhp) {
+ struct data_hunk *next = dhp->next;
+ int i;
+
+ for (i = 0; i < dhp->count; i++)
+ data->data[off + i] = dhp->data[i];
+
+ off += dhp->count;
+
+ Z_Free(dhp);
+
+ dhp = next;
+ }
+ fp->data_first = NULL;
+ fp->data_num = 0;
+
+ dp = fp->dst_first;
+ while (dp) {
+ struct dst_insn *next = dp->next;
+ if (dp->jump)
+ Z_Free(dp->jump);
+ Z_Free(dp);
+ dp = next;
+ }
+ fp->dst_first = fp->dst_last = NULL;
+}
+
+void VM_Compile(vm_t *vm, vmHeader_t *header)
+{
+ struct func_info fi;
+ unsigned char *code;
+ int i_count, pc, i;
+
+ memset(&fi, 0, sizeof(fi));
+
+ fi.first = Z_Malloc(sizeof(struct src_insn));
+ fi.first->next = NULL;
+
+#ifdef __arch64__
+ Z_Free(vm->instructionPointers);
+ vm->instructionPointers = Z_Malloc(header->instructionCount *
+ sizeof(void *));
+#endif
+
+ fi.dst_by_i_count = (struct dst_insn **) vm->instructionPointers;
+ memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
+
+ vm->compiled = qfalse;
+
+ emit_vm_thunk(&fi);
+
+ code = (unsigned char *) header + header->codeOffset;
+ pc = 0;
+
+ for (i_count = 0; i_count < header->instructionCount; i_count++) {
+ unsigned char opi, op = code[pc++];
+ struct src_insn *sp;
+
+ if (op == OP_CALL || op == OP_BLOCK_COPY)
+ fi.has_call = 1;
+ opi = vm_opInfo[op];
+ if (op == OP_CVIF || op == OP_CVFI ||
+ (op == OP_LEAVE && (opi & opArgF)))
+ fi.need_float_tmp = 1;
+
+ if (op == OP_ENTER) {
+ if (fi.first->next)
+ compile_function(&fi);
+ fi.first->next = NULL;
+ fi.last = fi.first;
+ fi.has_call = fi.need_float_tmp = 0;
+ }
+
+ sp = Z_Malloc(sizeof(*sp));
+ sp->op = op;
+ sp->i_count = i_count;
+ sp->arg.i = 0;
+ sp->next = NULL;
+
+ if (vm_opInfo[op] & opImm4) {
+ union {
+ unsigned char b[4];
+ unsigned int i;
+ } c = { { code[ pc + 3 ], code[ pc + 2 ],
+ code[ pc + 1 ], code[ pc + 0 ] }, };
+
+ sp->arg.i = c.i;
+ pc += 4;
+ } else if (vm_opInfo[op] & opImm1) {
+ sp->arg.b = code[pc++];
+ }
+
+ fi.last->next = sp;
+ fi.last = sp;
+ }
+ compile_function(&fi);
+
+ Z_Free(fi.first);
+
+ memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *));
+ sparc_compute_code(vm, &fi);
+
+ for (i = 0; i < header->instructionCount; i++) {
+ if (!fi.dst_by_i_count[i]) {
+ Com_Printf(S_COLOR_RED "Pointer %d not initialized !\n", i);
+ DIE("sparc JIT bug");
+ }
+ }
+
+ if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC)) {
+ VM_Destroy_Compiled(vm);
+ DIE("mprotect failed");
+ }
+
+ vm->destroy = VM_Destroy_Compiled;
+ vm->compiled = qtrue;
+}
+
+int VM_CallCompiled(vm_t *vm, int *args)
+{
+ vm_data_t *vm_dataAndCode = (void *) vm->codeBase;
+ int programStack = vm->programStack;
+ int stackOnEntry = programStack;
+ byte *image = vm->dataBase;
+ int *argPointer;
+ int retVal;
+
+ currentVM = vm;
+
+ vm->currentlyInterpreting = qtrue;
+
+ programStack -= 48;
+ argPointer = (int *)&image[ programStack + 8 ];
+ memcpy( argPointer, args, 4 * 9 );
+ argPointer[-1] = 0;
+ argPointer[-2] = -1;
+
+ /* call generated code */
+ {
+ int (*entry)(void *, int, void *, int);
+ entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength);
+ retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask);
+ }
+
+ vm->programStack = stackOnEntry;
+ vm->currentlyInterpreting = qfalse;
+
+ return retVal;
+}
diff --git a/src/qcommon/vm_sparc.h b/src/qcommon/vm_sparc.h
new file mode 100644
index 00000000..dbed6278
--- /dev/null
+++ b/src/qcommon/vm_sparc.h
@@ -0,0 +1,78 @@
+#ifndef VM_SPARC_H
+#define VM_SPARC_H
+
+/* integer regs */
+#define G0 0
+#define G1 1
+#define G2 2
+#define G3 3
+#define G4 4
+#define G5 5
+#define G6 6
+#define G7 7
+#define O0 8
+#define O1 9
+#define O2 10
+#define O3 11
+#define O4 12
+#define O5 13
+#define O6 14
+#define O7 15
+#define L0 16
+#define L1 17
+#define L2 18
+#define L3 19
+#define L4 20
+#define L5 21
+#define L6 22
+#define L7 23
+#define I0 24
+#define I1 25
+#define I2 26
+#define I3 27
+#define I4 28
+#define I5 29
+#define I6 30
+#define I7 31
+
+/* float regs */
+#define F0 0
+#define F1 1
+#define F2 2
+#define F3 3
+#define F4 4
+#define F5 5
+#define F6 6
+#define F7 7
+#define F8 8
+#define F9 9
+#define F10 10
+#define F11 11
+#define F12 12
+#define F13 13
+#define F14 14
+#define F15 15
+#define F16 16
+#define F17 17
+#define F18 18
+#define F19 19
+#define F20 20
+#define F21 21
+#define F22 22
+#define F23 23
+#define F24 24
+#define F25 25
+#define F26 26
+#define F27 27
+#define F28 28
+#define F29 29
+#define F30 30
+#define F31 31
+
+/* state registers */
+#define Y_REG 0
+#define CCR_REG 2
+#define ASI_REG 3
+#define FPRS_REG 6
+
+#endif
diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c
index 64af7d11..0f558ef7 100644
--- a/src/qcommon/vm_x86.c
+++ b/src/qcommon/vm_x86.c
@@ -177,9 +177,14 @@ _asm {
#else //!_MSC_VER
#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols
-# define CMANG(sym) "_"#sym
+#define CMANGVAR(sym) "_"#sym
+#define CMANGFUNC(sym) "_"#sym
+#elif defined(__ICC) && (__ICC >= 1000)
+#define CMANGVAR(sym) #sym".0"
+#define CMANGFUNC(sym) #sym
#else
-# define CMANG(sym) #sym
+#define CMANGVAR(sym) #sym
+#define CMANGFUNC(sym) #sym
#endif
static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum,
@@ -200,32 +205,37 @@ __asm__(
".text\n\t"
".p2align 4,,15\n\t"
#if defined __ELF__
- ".type " CMANG(AsmCall) ", @function\n"
+ ".type " CMANGFUNC(AsmCall) ", @function\n"
#endif
- CMANG(AsmCall) ":\n\t"
+ CMANGFUNC(AsmCall) ":\n\t"
"movl (%edi), %eax\n\t"
"subl $4, %edi\n\t"
"testl %eax, %eax\n\t"
"jl 0f\n\t"
"shll $2, %eax\n\t"
- "addl " CMANG(instructionPointers) ", %eax\n\t"
+ "addl " CMANGVAR(instructionPointers) ", %eax\n\t"
"call *(%eax)\n\t"
"movl (%edi), %eax\n\t"
- "andl " CMANG(callMask) ", %eax\n\t"
+ "andl " CMANGVAR(callMask) ", %eax\n\t"
"ret\n"
"0:\n\t" // system call
"notl %eax\n\t"
+ "pushl %ebp\n\t"
+ "movl %esp, %ebp\n\t"
+ "andl $-16, %esp\n\t" // align the stack so engine can use sse
"pushl %ecx\n\t"
"pushl %edi\n\t" // opStack
"pushl %esi\n\t" // programStack
"pushl %eax\n\t" // syscallNum
- "call " CMANG(CallAsmCall) "\n\t"
+ "call " CMANGFUNC(CallAsmCall) "\n\t"
"addl $12, %esp\n\t"
"popl %ecx\n\t"
+ "movl %ebp, %esp\n\t"
+ "popl %ebp\n\t"
"addl $4, %edi\n\t"
"ret\n\t"
#if defined __ELF__
- ".size " CMANG(AsmCall)", .-" CMANG(AsmCall)
+ ".size " CMANGFUNC(AsmCall)", .-" CMANGFUNC(AsmCall)
#endif
);
diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c
index 09a9c6d1..b424baf8 100644
--- a/src/qcommon/vm_x86_64.c
+++ b/src/qcommon/vm_x86_64.c
@@ -247,7 +247,7 @@ void emit(const char* fmt, ...)
#else
#define JMPIARG \
emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \
- emit("jmpq *%rax");
+ emit("jmpq *%%rax");
#endif
// integer compare and jump
diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c
index f90b8026..ce2b8642 100644
--- a/src/renderer/tr_init.c
+++ b/src/renderer/tr_init.c
@@ -99,6 +99,7 @@ cvar_t *r_depthbits;
cvar_t *r_colorbits;
cvar_t *r_primitives;
cvar_t *r_texturebits;
+cvar_t *r_ext_multisample;
cvar_t *r_drawBuffer;
cvar_t *r_lightmap;
@@ -388,7 +389,7 @@ void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) {
}
// gamma correct
- if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {
+ if ( glConfig.deviceSupportsGamma ) {
R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 );
}
@@ -410,7 +411,7 @@ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName
qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
// gamma correct
- if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {
+ if ( glConfig.deviceSupportsGamma ) {
R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 );
}
@@ -530,7 +531,7 @@ void R_LevelShot( void ) {
float xScale, yScale;
int xx, yy;
- sprintf( checkname, "levelshots/%s.tga", tr.world->baseName );
+ Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName);
source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 );
@@ -565,7 +566,7 @@ void R_LevelShot( void ) {
}
// gamma correct
- if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) {
+ if ( glConfig.deviceSupportsGamma ) {
R_GammaCorrect( buffer + 18, 128 * 128 * 3 );
}
@@ -714,7 +715,7 @@ const void *RB_TakeVideoFrameCmd( const void *data )
GL_UNSIGNED_BYTE, cmd->captureBuffer );
// gamma correct
- if( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma )
+ if( glConfig.deviceSupportsGamma )
R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
if( cmd->motionJpeg )
@@ -913,6 +914,8 @@ void R_Register( void )
r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH );
r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue );
r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH);
r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE );
diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h
index ef434718..9f8e44f9 100644
--- a/src/renderer/tr_local.h
+++ b/src/renderer/tr_local.h
@@ -1002,6 +1002,7 @@ extern cvar_t *r_stencilbits; // number of desired stencil bits
extern cvar_t *r_depthbits; // number of desired depth bits
extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen
extern cvar_t *r_texturebits; // number of desired texture bits
+extern cvar_t *r_ext_multisample;
// 0 = use framebuffer depth
// 16 = use 16-bit textures
// 32 = use 32-bit textures
diff --git a/src/renderer/tr_main.c b/src/renderer/tr_main.c
index 3d908316..105dfdf2 100644
--- a/src/renderer/tr_main.c
+++ b/src/renderer/tr_main.c
@@ -457,7 +457,7 @@ void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, floa
float oppleg, adjleg, length;
int i;
- if(stereoSep == 0 && xmin != -xmax)
+ if(stereoSep == 0 && xmin == -xmax)
{
// symmetric case can be simplified
VectorCopy(dest->or.origin, ofsorigin);
@@ -524,9 +524,9 @@ void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum)
if(stereoSep != 0)
{
if(dest->stereoFrame == STEREO_LEFT)
- stereoSep = zProj / r_stereoSeparation->value;
+ stereoSep = zProj / stereoSep;
else if(dest->stereoFrame == STEREO_RIGHT)
- stereoSep = zProj / -r_stereoSeparation->value;
+ stereoSep = zProj / -stereoSep;
else
stereoSep = 0;
}
diff --git a/src/renderer/tr_noise.c b/src/renderer/tr_noise.c
index c8eeeed3..3a38d9d8 100644
--- a/src/renderer/tr_noise.c
+++ b/src/renderer/tr_noise.c
@@ -45,8 +45,6 @@ void R_NoiseInit( void )
{
int i;
- srand( 1001 );
-
for ( i = 0; i < NOISE_SIZE; i++ )
{
s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) );
diff --git a/src/renderer/tr_scene.c b/src/renderer/tr_scene.c
index 22b3842b..e11c0a3d 100644
--- a/src/renderer/tr_scene.c
+++ b/src/renderer/tr_scene.c
@@ -212,6 +212,14 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) {
if ( r_numentities >= MAX_ENTITIES ) {
return;
}
+ if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) {
+ static qboolean first_time = qtrue;
+ if (first_time) {
+ first_time = qfalse;
+ Com_Printf(S_COLOR_YELLOW "WARNING: You might have built ioquake3 with a buggy compiler!\n");
+ }
+ return;
+ }
if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) {
ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType );
}
diff --git a/src/renderer/tr_surface.c b/src/renderer/tr_surface.c
index 2a291c84..fca9841c 100644
--- a/src/renderer/tr_surface.c
+++ b/src/renderer/tr_surface.c
@@ -190,7 +190,7 @@ static void RB_SurfaceSprite( void ) {
RB_SurfacePolychain
=============
*/
-void RB_SurfacePolychain( srfPoly_t *p ) {
+static void RB_SurfacePolychain( srfPoly_t *p ) {
int i;
int numv;
@@ -224,7 +224,7 @@ void RB_SurfacePolychain( srfPoly_t *p ) {
RB_SurfaceTriangles
=============
*/
-void RB_SurfaceTriangles( srfTriangles_t *srf ) {
+static void RB_SurfaceTriangles( srfTriangles_t *srf ) {
int i;
drawVert_t *dv;
float *xyz, *normal, *texCoords;
@@ -285,7 +285,7 @@ void RB_SurfaceTriangles( srfTriangles_t *srf ) {
RB_SurfaceBeam
==============
*/
-void RB_SurfaceBeam( void )
+static void RB_SurfaceBeam( void )
{
#define NUM_BEAM_SEGS 6
refEntity_t *e;
@@ -455,7 +455,7 @@ static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, cons
/*
** RB_SurfaceRailRinges
*/
-void RB_SurfaceRailRings( void ) {
+static void RB_SurfaceRailRings( void ) {
refEntity_t *e;
int numSegs;
int len;
@@ -485,7 +485,7 @@ void RB_SurfaceRailRings( void ) {
/*
** RB_SurfaceRailCore
*/
-void RB_SurfaceRailCore( void ) {
+static void RB_SurfaceRailCore( void ) {
refEntity_t *e;
int len;
vec3_t right;
@@ -515,7 +515,7 @@ void RB_SurfaceRailCore( void ) {
/*
** RB_SurfaceLightningBolt
*/
-void RB_SurfaceLightningBolt( void ) {
+static void RB_SurfaceLightningBolt( void ) {
refEntity_t *e;
int len;
vec3_t right;
@@ -857,7 +857,7 @@ static void LerpMeshVertexes(md3Surface_t *surf, float backlerp)
RB_SurfaceMesh
=============
*/
-void RB_SurfaceMesh(md3Surface_t *surface) {
+static void RB_SurfaceMesh(md3Surface_t *surface) {
int j;
float backlerp;
int *triangles;
@@ -904,7 +904,7 @@ void RB_SurfaceMesh(md3Surface_t *surface) {
RB_SurfaceFace
==============
*/
-void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
+static void RB_SurfaceFace( srfSurfaceFace_t *surf ) {
int i;
unsigned *indices, *tessIndexes;
float *v;
@@ -994,7 +994,7 @@ RB_SurfaceGrid
Just copy the grid of points and triangulate
=============
*/
-void RB_SurfaceGrid( srfGridMesh_t *cv ) {
+static void RB_SurfaceGrid( srfGridMesh_t *cv ) {
int i, j;
float *xyz;
float *texCoords;
@@ -1161,7 +1161,7 @@ RB_SurfaceAxis
Draws x/y/z lines from the origin for orientation debugging
===================
*/
-void RB_SurfaceAxis( void ) {
+static void RB_SurfaceAxis( void ) {
GL_Bind( tr.whiteImage );
qglLineWidth( 3 );
qglBegin( GL_LINES );
@@ -1187,7 +1187,7 @@ RB_SurfaceEntity
Entities that have a single procedurally generated surface
====================
*/
-void RB_SurfaceEntity( surfaceType_t *surfType ) {
+static void RB_SurfaceEntity( surfaceType_t *surfType ) {
switch( backEnd.currentEntity->e.reType ) {
case RT_SPRITE:
RB_SurfaceSprite();
@@ -1211,23 +1211,23 @@ void RB_SurfaceEntity( surfaceType_t *surfType ) {
return;
}
-void RB_SurfaceBad( surfaceType_t *surfType ) {
+static void RB_SurfaceBad( surfaceType_t *surfType ) {
ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" );
}
-void RB_SurfaceFlare(srfFlare_t *surf)
+static void RB_SurfaceFlare(srfFlare_t *surf)
{
if (r_flares->integer)
RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal);
}
-void RB_SurfaceDisplayList( srfDisplayList_t *surf ) {
+static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) {
// all apropriate state must be set in RB_BeginSurface
// this isn't implemented yet...
qglCallList( surf->listNum );
}
-void RB_SurfaceSkip( void *surf ) {
+static void RB_SurfaceSkip( void *surf ) {
}
diff --git a/src/sdl/sdl_glimp.c b/src/sdl/sdl_glimp.c
index 6125a321..1bbccb84 100644
--- a/src/sdl/sdl_glimp.c
+++ b/src/sdl/sdl_glimp.c
@@ -79,6 +79,7 @@ static SDL_Surface *screen = NULL;
static const SDL_VideoInfo *videoInfo = NULL;
cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained
+cvar_t *r_allowResize; // make window resizable
cvar_t *r_sdlDriver;
void (APIENTRYP qglActiveTextureARB) (GLenum texture);
@@ -214,12 +215,16 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen )
int sdlcolorbits;
int colorbits, depthbits, stencilbits;
int tcolorbits, tdepthbits, tstencilbits;
+ int samples;
int i = 0;
SDL_Surface *vidscreen = NULL;
Uint32 flags = SDL_OPENGL;
ri.Printf( PRINT_ALL, "Initializing OpenGL display\n");
+ if ( r_allowResize->integer )
+ flags |= SDL_RESIZABLE;
+
#if !SDL_VERSION_ATLEAST(1, 2, 10)
// 1.2.10 is needed to get the desktop resolution
glConfig.displayAspect = 4.0f / 3.0f;
@@ -240,12 +245,20 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen )
sVideoInfo.vfmt = &sPixelFormat;
videoInfo = &sVideoInfo;
- // Guess the display aspect ratio through the desktop resolution
- // by assuming (relatively safely) that it is set at or close to
- // the display's native aspect ratio
- glConfig.displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h;
+ if( videoInfo->current_h > 0 )
+ {
+ // Guess the display aspect ratio through the desktop resolution
+ // by assuming (relatively safely) that it is set at or close to
+ // the display's native aspect ratio
+ glConfig.displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h;
- ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", glConfig.displayAspect );
+ ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", glConfig.displayAspect );
+ }
+ else
+ {
+ ri.Printf( PRINT_ALL,
+ "Cannot estimate display aspect, assuming 1.333\n" );
+ }
}
#endif
@@ -279,16 +292,16 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen )
else
glConfig.isFullscreen = qfalse;
- if (!r_colorbits->value)
+ colorbits = r_colorbits->value;
+ if ((!colorbits) || (colorbits >= 32))
colorbits = 24;
- else
- colorbits = r_colorbits->value;
if (!r_depthbits->value)
depthbits = 24;
else
depthbits = r_depthbits->value;
stencilbits = r_stencilbits->value;
+ samples = r_ext_multisample->value;
for (i = 0; i < 16; i++)
{
@@ -350,12 +363,23 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen )
if (tcolorbits == 24)
sdlcolorbits = 8;
+#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */
+ if (sdlcolorbits == 4)
+ sdlcolorbits = 0; /* Use minimum size for 16-bit color */
+
+ /* Need alpha or else SGIs choose 36+ bit RGB mode */
+ SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1);
+#endif
+
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits );
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits );
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits );
+ SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 );
+ SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples );
+
if(r_stereoEnabled->integer)
{
glConfig.stereoEnabled = qtrue;
@@ -677,23 +701,30 @@ of OpenGL
*/
void GLimp_Init( void )
{
- qboolean success = qtrue;
-
r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM );
+ r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE );
Sys_GLimpInit( );
- // create the window and set up the context
- if( !GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) )
- {
- if( !GLimp_StartDriverAndSetMode( qtrue, r_fullscreen->integer ) )
- success = qfalse;
- }
+ // Create the window and set up the context
+ if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) )
+ goto success;
+
+ // Try again, this time in a platform specific "safe mode"
+ Sys_GLimpSafeInit( );
+
+ if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) )
+ goto success;
+
+ // Finally, try the default screen resolution
+ if( GLimp_StartDriverAndSetMode( qtrue, r_fullscreen->integer ) )
+ goto success;
- if( !success )
- ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
+ // Nothing worked, give up
+ ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" );
+success:
// This values force the UI to disable driver selection
glConfig.driverType = GLDRV_ICD;
glConfig.hardwareType = GLHW_GENERIC;
diff --git a/src/sdl/sdl_input.c b/src/sdl/sdl_input.c
index 3263932a..2949c8fd 100644
--- a/src/sdl/sdl_input.c
+++ b/src/sdl/sdl_input.c
@@ -70,6 +70,8 @@ static cvar_t *in_joystickDebug = NULL;
static cvar_t *in_joystickThreshold = NULL;
static cvar_t *in_joystickNo = NULL;
+static int vidRestartTime = 0;
+
#define CTRL(a) ((a)-'a'+1)
/*
@@ -949,6 +951,20 @@ static void IN_ProcessEvents( void )
Sys_Quit( );
break;
+ case SDL_VIDEORESIZE:
+ {
+ char width[32], height[32];
+ Com_sprintf( width, sizeof(width), "%d", e.resize.w );
+ Com_sprintf( height, sizeof(height), "%d", e.resize.h );
+ ri.Cvar_Set( "r_width", width );
+ ri.Cvar_Set( "r_height", height );
+ /* wait until user stops dragging for 1 second, so
+ we aren't constantly recreating the GL context while
+ he tries to drag...*/
+ vidRestartTime = Sys_Milliseconds() + 1000;
+ }
+ break;
+
default:
break;
}
@@ -1001,6 +1017,13 @@ void IN_Frame( void )
SDL_GetMouseState( &x, &y );
IN_SetUIMousePosition( x, y );
}
+
+ // In case we had to delay actual restart of video system
+ if( ( vidRestartTime != 0 ) && ( vidRestartTime < Sys_Milliseconds( ) ) )
+ {
+ vidRestartTime = 0;
+ Cbuf_AddText( "vid_restart" );
+ }
}
/*
diff --git a/src/server/server.h b/src/server/server.h
index eb3766e8..fe78026c 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -205,6 +205,7 @@ typedef struct client_s {
typedef struct {
netadr_t adr;
int challenge;
+ int clientChallenge; // challenge number coming from the client
int time; // time the last packet was sent to the autherize server
int pingTime; // time the challenge response was sent to client
int firstTime; // time the adr was first used, for authorize timeout checks
@@ -313,7 +314,7 @@ void SV_SpawnServer( char *server, qboolean killBots );
//
// sv_client.c
//
-void SV_GetChallenge( netadr_t from );
+void SV_GetChallenge(netadr_t from);
void SV_DirectConnect( netadr_t from );
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index 4b7b3bb6..4449f1c8 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -42,12 +42,21 @@ to be sent to the authorize server.
When an authorizeip is returned, a challenge response will be
sent to that ip.
+
+ioquake3: we added a possibility for clients to add a challenge
+to their packets, to make it more difficult for malicious servers
+to hi-jack client connections.
+Also, the auth stuff is completely disabled for com_standalone games
+as well as IPv6 connections, since there is no way to use the
+v4-only auth server for these new types of connections.
=================
*/
-void SV_GetChallenge( netadr_t from ) {
+void SV_GetChallenge(netadr_t from)
+{
int i;
int oldest;
int oldestTime;
+ const char *clientChallenge = Cmd_Argv(1);
challenge_t *challenge;
oldest = 0;
@@ -65,21 +74,24 @@ void SV_GetChallenge( netadr_t from ) {
}
}
- if (i == MAX_CHALLENGES) {
+ if (i == MAX_CHALLENGES)
+ {
// this is the first time this client has asked for a challenge
challenge = &svs.challenges[oldest];
-
challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time;
+ challenge->clientChallenge = 0;
challenge->adr = from;
challenge->firstTime = svs.time;
challenge->time = svs.time;
challenge->connected = qfalse;
- i = oldest;
}
// send the challengeResponse
challenge->pingTime = svs.time;
NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge );
+
+ challenge->pingTime = svs.time;
+ NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge);
}
/*
@@ -339,7 +351,7 @@ void SV_DropClient( client_t *drop, const char *reason ) {
for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) {
if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) {
- challenge->connected = qfalse;
+ Com_Memset(challenge, 0, sizeof(*challenge));
break;
}
}
@@ -350,7 +362,6 @@ void SV_DropClient( client_t *drop, const char *reason ) {
// tell everyone why they got dropped
SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason );
-
if (drop->download) {
FS_FCloseFile( drop->download );
drop->download = 0;
@@ -394,7 +405,7 @@ It will be resent if the client acknowledges a later message but has
the wrong gamestate.
================
*/
-void SV_SendClientGameState( client_t *client ) {
+static void SV_SendClientGameState( client_t *client ) {
int start;
entityState_t *base, nullstate;
msg_t msg;
@@ -531,7 +542,7 @@ SV_StopDownload_f
Abort a download if in progress
==================
*/
-void SV_StopDownload_f( client_t *cl ) {
+static void SV_StopDownload_f( client_t *cl ) {
if (*cl->downloadName)
Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", (int) (cl - svs.clients), cl->downloadName );
@@ -545,7 +556,7 @@ SV_DoneDownload_f
Downloads are finished
==================
*/
-void SV_DoneDownload_f( client_t *cl ) {
+static void SV_DoneDownload_f( client_t *cl ) {
Com_DPrintf( "clientDownload: %s Done\n", cl->name);
// resend the game state to update any clients that entered during the download
SV_SendClientGameState(cl);
@@ -559,7 +570,7 @@ The argument will be the last acknowledged block from the client, it should be
the same as cl->downloadClientBlock
==================
*/
-void SV_NextDownload_f( client_t *cl )
+static void SV_NextDownload_f( client_t *cl )
{
int block = atoi( Cmd_Argv(1) );
@@ -588,7 +599,7 @@ void SV_NextDownload_f( client_t *cl )
SV_BeginDownload_f
==================
*/
-void SV_BeginDownload_f( client_t *cl ) {
+static void SV_BeginDownload_f( client_t *cl ) {
// Kill any existing download
SV_CloseDownload( cl );
diff --git a/src/server/sv_game.c b/src/server/sv_game.c
index d375c095..1efa6d5f 100644
--- a/src/server/sv_game.c
+++ b/src/server/sv_game.c
@@ -182,17 +182,14 @@ qboolean SV_inPVSIgnorePortals( const vec3_t p1, const 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 qfalse;
diff --git a/src/server/sv_init.c b/src/server/sv_init.c
index 43eb2c09..34ced5c5 100644
--- a/src/server/sv_init.c
+++ b/src/server/sv_init.c
@@ -105,7 +105,7 @@ SV_SetConfigstring
===============
*/
void SV_SetConfigstring (int index, const char *val) {
- int len, i;
+ int i;
client_t *client;
if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
@@ -141,8 +141,6 @@ void SV_SetConfigstring (int index, const char *val) {
continue;
}
-
- len = strlen( val );
SV_SendConfigstring(client, index);
}
}
@@ -217,7 +215,7 @@ to the clients -- only the fields that differ from the
baseline will be transmitted
================
*/
-void SV_CreateBaseline( void ) {
+static void SV_CreateBaseline( void ) {
sharedEntity_t *svent;
int entnum;
@@ -242,7 +240,7 @@ SV_BoundMaxClients
===============
*/
-void SV_BoundMaxClients( int minimum ) {
+static void SV_BoundMaxClients( int minimum ) {
// get the current maxclients value
Cvar_Get( "sv_maxclients", "8", 0 );
@@ -266,7 +264,7 @@ NOT cause this to be called, unless the game is exited to
the menu system first.
===============
*/
-void SV_Startup( void ) {
+static void SV_Startup( void ) {
if ( svs.initialized ) {
Com_Error( ERR_FATAL, "SV_Startup: svs.initialized" );
}
@@ -364,7 +362,7 @@ void SV_ChangeMaxClients( void ) {
SV_ClearServer
================
*/
-void SV_ClearServer(void) {
+static void SV_ClearServer(void) {
int i;
for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
@@ -382,7 +380,7 @@ SV_TouchCGame
touch the cgame.vm so that a pure client can load it if it's in a seperate pk3
================
*/
-void SV_TouchCGame(void) {
+static void SV_TouchCGame(void) {
fileHandle_t f;
char filename[MAX_QPATH];
@@ -470,7 +468,6 @@ void SV_SpawnServer( char *server, qboolean killBots ) {
Cvar_Set("cl_paused", "0");
// get a new checksum feed and restart the file system
- srand(Com_Milliseconds());
sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds();
FS_Restart( sv.checksumFeed );
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index 305cf299..41bfec4a 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -74,7 +74,7 @@ SV_ExpandNewlines
Converts newlines to "\n" so a line prints nicer
===============
*/
-char *SV_ExpandNewlines( char *in ) {
+static char *SV_ExpandNewlines( char *in ) {
static char string[1024];
int l;
@@ -97,10 +97,11 @@ char *SV_ExpandNewlines( char *in ) {
======================
SV_ReplacePendingServerCommands
- This is ugly
+FIXME: This is ugly
======================
*/
-int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
+#if 0 // unused
+static int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
int i, index, csnum1, csnum2;
for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) {
@@ -117,6 +118,7 @@ int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
}
return qfalse;
}
+#endif
/*
======================
@@ -223,52 +225,89 @@ but not on every player enter or exit.
#define HEARTBEAT_MSEC 300*1000
#define HEARTBEAT_GAME "Tremulous"
void SV_MasterHeartbeat( void ) {
- static netadr_t adr[MAX_MASTER_SERVERS];
+ static netadr_t adr[MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string.
int i;
int res;
+ int netenabled;
+
+ netenabled = Cvar_VariableIntegerValue("net_enabled");
// "dedicated 1" is for lan play, "dedicated 2" is for inet public play
- if ( !com_dedicated || com_dedicated->integer != 2 ) {
+ if (!com_dedicated || com_dedicated->integer != 2 || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6)))
return; // only dedicated servers send heartbeats
- }
// if not time yet, don't send anything
- if ( svs.time < svs.nextHeartbeatTime ) {
+ if ( svs.time < svs.nextHeartbeatTime )
return;
- }
- svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;
+ svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;
// send to group masters
- for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) {
- if ( !sv_master[i]->string[0] ) {
+ for (i = 0; i < MAX_MASTER_SERVERS; i++)
+ {
+ if(!sv_master[i]->string[0])
continue;
- }
// see if we haven't already resolved the name
// resolving usually causes hitches on win95, so only
// do it when needed
- if ( sv_master[i]->modified ) {
+ if(sv_master[i]->modified || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD))
+ {
sv_master[i]->modified = qfalse;
-
- Com_Printf( "Resolving %s\n", sv_master[i]->string );
- res = NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC );
- if ( !res ) {
- Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string );
- continue;
+
+ if(netenabled & NET_ENABLEV4)
+ {
+ Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string);
+ res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP);
+
+ if(res == 2)
+ {
+ // if no port was specified, use the default master port
+ adr[i][0].port = BigShort(PORT_MASTER);
+ }
+
+ if(res)
+ Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0]));
+ else
+ Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string);
}
- if ( res == 2 ) {
- // if no port was specified, use the default master port
- adr[i].port = BigShort( PORT_MASTER );
+
+ if(netenabled & NET_ENABLEV6)
+ {
+ Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string);
+ res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6);
+
+ if(res == 2)
+ {
+ // if no port was specified, use the default master port
+ adr[i][1].port = BigShort(PORT_MASTER);
+ }
+
+ if(res)
+ Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1]));
+ else
+ Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string);
+ }
+
+ if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)
+ {
+ Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string);
+ Cvar_Set(sv_master[i]->name, "");
+ sv_master[i]->modified = qfalse;
+ continue;
}
- Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i]));
}
Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string );
+
// this command should be changed if the server info / status format
// ever incompatably changes
- NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME );
+
+ if(adr[i][0].type != NA_BAD)
+ NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", HEARTBEAT_GAME );
+ if(adr[i][1].type != NA_BAD)
+ NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", HEARTBEAT_GAME );
}
}
@@ -342,7 +381,7 @@ and all connected players. Used for getting detailed information after
the simple info query.
================
*/
-void SVC_Status( netadr_t from ) {
+static void SVC_Status( netadr_t from ) {
char player[1024];
char status[MAX_MSGLEN];
int i;
@@ -449,7 +488,7 @@ SVC_FlushRedirect
================
*/
-void SV_FlushRedirect( char *outputbuf ) {
+static void SV_FlushRedirect( char *outputbuf ) {
NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
}
@@ -462,7 +501,7 @@ Shift down the remaining args
Redirect all printfs
===============
*/
-void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
+static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
qboolean valid;
unsigned int time;
char remaining[1024];
@@ -483,10 +522,10 @@ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
if ( !strlen( sv_rconPassword->string ) ||
strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
valid = qfalse;
- Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) );
+ Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
} else {
valid = qtrue;
- Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) );
+ Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
}
// start redirecting all print outputs to the packet
@@ -532,7 +571,7 @@ Clients that are in the game can still send
connectionless packets.
=================
*/
-void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
+static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
char *s;
char *c;
@@ -554,7 +593,7 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
} else if (!Q_stricmp(c, "getinfo")) {
SVC_Info( from );
} else if (!Q_stricmp(c, "getchallenge")) {
- SV_GetChallenge( from );
+ SV_GetChallenge(from);
} else if (!Q_stricmp(c, "connect")) {
SV_DirectConnect( from );
} else if (!Q_stricmp(c, "rcon")) {
@@ -641,7 +680,7 @@ SV_CalcPings
Updates the cl->ping variables
===================
*/
-void SV_CalcPings( void ) {
+static void SV_CalcPings( void ) {
int i, j;
client_t *cl;
int total, count;
@@ -697,7 +736,7 @@ for a few seconds to make sure any final reliable message gets resent
if necessary
==================
*/
-void SV_CheckTimeouts( void ) {
+static void SV_CheckTimeouts( void ) {
int i;
client_t *cl;
int droppoint;
@@ -738,7 +777,7 @@ void SV_CheckTimeouts( void ) {
SV_CheckPaused
==================
*/
-qboolean SV_CheckPaused( void ) {
+static qboolean SV_CheckPaused( void ) {
int count;
client_t *cl;
int i;
diff --git a/src/server/sv_net_chan.c b/src/server/sv_net_chan.c
index 0de49d4f..dd2bb204 100644
--- a/src/server/sv_net_chan.c
+++ b/src/server/sv_net_chan.c
@@ -35,28 +35,29 @@ SV_Netchan_Encode
==============
*/
static void SV_Netchan_Encode( client_t *client, msg_t *msg ) {
- long reliableAcknowledge, i, index;
+ long i, index;
byte key, *string;
- int srdc, sbit, soob;
-
+ int srdc, sbit;
+ qboolean soob;
+
if ( msg->cursize < SV_ENCODE_START ) {
return;
}
- srdc = msg->readcount;
- sbit = msg->bit;
- soob = msg->oob;
-
- msg->bit = 0;
- msg->readcount = 0;
- msg->oob = 0;
-
- reliableAcknowledge = MSG_ReadLong(msg);
+ srdc = msg->readcount;
+ sbit = msg->bit;
+ soob = msg->oob;
+
+ msg->bit = 0;
+ msg->readcount = 0;
+ msg->oob = qfalse;
+
+ /* reliableAcknowledge = */ MSG_ReadLong(msg);
+
+ msg->oob = soob;
+ msg->bit = sbit;
+ msg->readcount = srdc;
- msg->oob = soob;
- msg->bit = sbit;
- msg->readcount = srdc;
-
string = (byte *)client->lastClientCommandString;
index = 0;
// xor the client challenge with the netchan sequence number
@@ -90,23 +91,24 @@ SV_Netchan_Decode
*/
static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
int serverId, messageAcknowledge, reliableAcknowledge;
- int i, index, srdc, sbit, soob;
+ int i, index, srdc, sbit;
+ qboolean soob;
byte key, *string;
- srdc = msg->readcount;
- sbit = msg->bit;
- soob = msg->oob;
-
- msg->oob = 0;
-
- serverId = MSG_ReadLong(msg);
+ srdc = msg->readcount;
+ sbit = msg->bit;
+ soob = msg->oob;
+
+ msg->oob = qfalse;
+
+ serverId = MSG_ReadLong(msg);
messageAcknowledge = MSG_ReadLong(msg);
reliableAcknowledge = MSG_ReadLong(msg);
- msg->oob = soob;
- msg->bit = sbit;
- msg->readcount = srdc;
-
+ msg->oob = soob;
+ msg->bit = sbit;
+ msg->readcount = srdc;
+
string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
index = 0;
//
@@ -137,7 +139,7 @@ void SV_Netchan_TransmitNextFragment( client_t *client ) {
if (!client->netchan.unsentFragments)
{
// make sure the netchan queue has been properly initialized (you never know)
- if (!client->netchan_end_queue) {
+ if ((!client->netchan_end_queue) && (client->state >= CS_CONNECTED)) {
Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
}
// the last fragment was transmitted, check wether we have queued messages
diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c
index 037b772d..d813aad4 100644
--- a/src/server/sv_snapshot.c
+++ b/src/server/sv_snapshot.c
@@ -299,7 +299,6 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra
int l;
int clientarea, clientcluster;
int leafnum;
- int c_fullsend;
byte *clientpvs;
byte *bitvector;
@@ -319,8 +318,6 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra
clientpvs = CM_ClusterPVS (clientcluster);
- c_fullsend = 0;
-
for ( e = 0 ; e < sv.num_entities ; e++ ) {
ent = SV_GentityNum(e);
diff --git a/src/server/sv_world.c b/src/server/sv_world.c
index d40cc217..508ff0cc 100644
--- a/src/server/sv_world.c
+++ b/src/server/sv_world.c
@@ -104,7 +104,7 @@ SV_CreateworldSector
Builds a uniformly subdivided tree for the given world size
===============
*/
-worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) {
+static worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) {
worldSector_t *anode;
vec3_t size;
vec3_t mins1, maxs1, mins2, maxs2;
@@ -380,7 +380,7 @@ SV_AreaEntities_r
====================
*/
-void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) {
+static void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) {
svEntity_t *check, *next;
sharedEntity_t *gcheck;
int count;
@@ -508,7 +508,7 @@ SV_ClipMoveToEntities
====================
*/
-void SV_ClipMoveToEntities( moveclip_t *clip ) {
+static void SV_ClipMoveToEntities( moveclip_t *clip ) {
int i, num;
int touchlist[MAX_GENTITIES];
sharedEntity_t *touch;
diff --git a/src/sys/con_tty.c b/src/sys/con_tty.c
index cdd686a1..6f3376e1 100644
--- a/src/sys/con_tty.c
+++ b/src/sys/con_tty.c
@@ -41,6 +41,7 @@ called before and after a stdout or stderr output
=============================================================
*/
+static qboolean stdin_active;
// general flag to tell about tty console mode
static qboolean ttycon_on = qfalse;
static int ttycon_hide = 0;
@@ -255,6 +256,7 @@ Initialize the console input (tty mode if possible)
void CON_Init( void )
{
struct termios tc;
+ const char* term = getenv("TERM");
// If the process is backgrounded (running non interactively)
// then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP
@@ -264,10 +266,12 @@ void CON_Init( void )
// Make stdin reads non-blocking
fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NONBLOCK );
- if (isatty(STDIN_FILENO)!=1)
+ if (isatty(STDIN_FILENO) != 1
+ || (term && (!strcmp(term, "raw") || !strcmp(term, "dumb"))))
{
- Com_Printf( "stdin is not a tty, tty console mode disabled\n");
+ Com_Printf("tty console mode disabled\n");
ttycon_on = qfalse;
+ stdin_active = qtrue;
return;
}
@@ -409,18 +413,11 @@ char *CON_Input( void )
return NULL;
}
- else
+ else if (stdin_active)
{
int len;
fd_set fdset;
struct timeval timeout;
- static qboolean stdin_active;
-
- if (!com_dedicated || !com_dedicated->value)
- return NULL;
-
- if (!stdin_active)
- return NULL;
FD_ZERO(&fdset);
FD_SET(0, &fdset); // stdin
@@ -444,6 +441,7 @@ char *CON_Input( void )
return text;
}
+ return NULL;
}
/*
diff --git a/src/sys/sys_cocoa.m b/src/sys/sys_cocoa.m
new file mode 100644
index 00000000..cfc754dd
--- /dev/null
+++ b/src/sys/sys_cocoa.m
@@ -0,0 +1,40 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+#ifndef MACOS_X
+#error This file is for Mac OS X only. You probably should not compile it.
+#endif
+
+// Please note that this file is just some Mac-specific bits. Most of the
+// Mac OS X code is shared with other Unix platforms in sys_unix.c ...
+
+#import <Cocoa/Cocoa.h>
+
+void Cocoa_MsgBox( const char *text )
+{
+ NSRunInformationalAlertPanel(@"ioquake3",
+ [NSString stringWithUTF8String:text],
+ @"OK", nil, nil);
+}
+
+// end of sys_cocoa.m ...
+
diff --git a/src/sys/sys_local.h b/src/sys/sys_local.h
index 6d001046..4ecc9227 100644
--- a/src/sys/sys_local.h
+++ b/src/sys/sys_local.h
@@ -48,6 +48,7 @@ unsigned int CON_LogRead( char *out, unsigned int outSize );
char *Sys_StripAppBundle( char *pwd );
#endif
+void Sys_GLimpSafeInit( void );
void Sys_GLimpInit( void );
void Sys_PlatformInit( void );
void Sys_SigHandler( int signal );
diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c
index 0d682261..0a4183c7 100644
--- a/src/sys/sys_main.c
+++ b/src/sys/sys_main.c
@@ -517,8 +517,6 @@ int main( int argc, char **argv )
// Run time
const SDL_version *ver = SDL_Linked_Version( );
-#define STRING(s) #s
-#define XSTRING(s) STRING(s)
#define MINSDL_VERSION \
XSTRING(MINSDL_MAJOR) "." \
XSTRING(MINSDL_MINOR) "." \
@@ -534,6 +532,9 @@ int main( int argc, char **argv )
Sys_PlatformInit( );
+ // Set the initial time base
+ Sys_Milliseconds( );
+
Sys_ParseArgs( argc, argv );
Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
@@ -541,7 +542,15 @@ int main( int argc, char **argv )
// Concatenate the command line for passing to Com_Init
for( i = 1; i < argc; i++ )
{
+ const qboolean containsSpaces = strchr(argv[i], ' ') != NULL;
+ if (containsSpaces)
+ Q_strcat( commandLine, sizeof( commandLine ), "\"" );
+
Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] );
+
+ if (containsSpaces)
+ Q_strcat( commandLine, sizeof( commandLine ), "\"" );
+
Q_strcat( commandLine, sizeof( commandLine ), " " );
}
diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c
index b55bbe6d..3360469d 100644
--- a/src/sys/sys_unix.c
+++ b/src/sys/sys_unix.c
@@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <sys/time.h>
#include <pwd.h>
#include <libgen.h>
+#include <fcntl.h>
// Used to determine where to store user-specific files
static char homePath[ MAX_OSPATH ] = { 0 };
@@ -54,11 +55,15 @@ char *Sys_DefaultHomePath(void)
{
Q_strncpyz( homePath, p, sizeof( homePath ) );
#ifdef MACOS_X
- Q_strcat( homePath, sizeof( homePath ), "/Library/Application Support/Tremulous" );
+ Q_strcat( homePath, sizeof( homePath ), "/Library" );
+ mkdir( homePath, 0750 );
+ Q_strcat( homePath, sizeof( homePath ), "/Application Support" );
+ mkdir( homePath, 0750 );
+ Q_strcat( homePath, sizeof( homePath ), "/Tremulous" );
#else
Q_strcat( homePath, sizeof( homePath ), "/.tremulous" );
#endif
- if( mkdir( homePath, 0777 ) )
+ if( mkdir( homePath, 0750 ) )
{
if( errno != EEXIST )
{
@@ -497,23 +502,58 @@ void Sys_ErrorDialog( const char *error )
{
char buffer[ 1024 ];
unsigned int size;
- fileHandle_t f;
+ int f = -1;
+ const char *homepath = Cvar_VariableString( "fs_homepath" );
+ const char *gamedir = Cvar_VariableString( "fs_gamedir" );
const char *fileName = "crashlog.txt";
+ char *ospath = FS_BuildOSPath( homepath, gamedir, fileName );
Sys_Print( va( "%s\n", error ) );
- // Write console log to file
- f = FS_FOpenFileWrite( fileName );
- if( !f )
+#if defined(MACOS_X) && !DEDICATED
+ /* This function has to be in a separate file, compiled as Objective-C. */
+ extern void Cocoa_MsgBox( const char *text );
+ if (!com_dedicated || !com_dedicated->integer)
+ Cocoa_MsgBox(error);
+#endif
+
+ /* make sure the write path for the crashlog exists... */
+ if( FS_CreatePath( ospath ) ) {
+ Com_Printf( "ERROR: couldn't create path '%s' for crash log.\n", ospath );
+ return;
+ }
+
+ /* we might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
+ which will come through here, so we don't want to recurse forever by
+ calling FS_FOpenFileWrite()...use the Unix system APIs instead. */
+ f = open(ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640);
+ if( f == -1 )
{
Com_Printf( "ERROR: couldn't open %s\n", fileName );
return;
}
- while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 )
- FS_Write( buffer, size, f );
+ /* We're crashing, so we don't care much if write() or close() fails. */
+ while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) {
+ if (write( f, buffer, size ) != size) {
+ Com_Printf( "ERROR: couldn't fully write to %s\n", fileName );
+ break;
+ }
+ }
- FS_FCloseFile( f );
+ close(f);
+}
+
+/*
+==============
+Sys_GLimpSafeInit
+
+Unix specific "safe" GL implementation initialisation
+==============
+*/
+void Sys_GLimpSafeInit( void )
+{
+ // NOP
}
/*
diff --git a/src/sys/sys_win32.c b/src/sys/sys_win32.c
index aac4384d..18efe406 100644
--- a/src/sys/sys_win32.c
+++ b/src/sys/sys_win32.c
@@ -583,6 +583,25 @@ static qboolean SDL_VIDEODRIVER_externallySet = qfalse;
/*
==============
+Sys_GLimpSafeInit
+
+Windows specific "safe" GL implementation initialisation
+==============
+*/
+void Sys_GLimpSafeInit( void )
+{
+#ifndef DEDICATED
+ if( !SDL_VIDEODRIVER_externallySet )
+ {
+ // Here, we want to let SDL decide what do to unless
+ // explicitly requested otherwise
+ _putenv( "SDL_VIDEODRIVER=" );
+ }
+#endif
+}
+
+/*
+==============
Sys_GLimpInit
Windows specific GL implementation initialisation
diff --git a/src/tools/asm/cmdlib.c b/src/tools/asm/cmdlib.c
index ac088675..aca34313 100644
--- a/src/tools/asm/cmdlib.c
+++ b/src/tools/asm/cmdlib.c
@@ -186,7 +186,7 @@ void _printf( const char *format, ... ) {
vsprintf (text, format, argptr);
va_end (argptr);
- printf(text);
+ printf("%s", text);
#ifdef WIN32
if (!lookedForServer) {
@@ -397,10 +397,12 @@ void Q_getwd (char *out)
int i = 0;
#ifdef WIN32
- _getcwd (out, 256);
+ if (_getcwd (out, 256) == NULL)
+ strcpy(out, "."); /* shrug */
strcat (out, "\\");
#else
- getcwd (out, 256);
+ if (getcwd (out, 256) == NULL)
+ strcpy(out, "."); /* shrug */
strcat (out, "/");
#endif
diff --git a/src/tools/asm/q3asm.c b/src/tools/asm/q3asm.c
index 3c334815..481a1acb 100644
--- a/src/tools/asm/q3asm.c
+++ b/src/tools/asm/q3asm.c
@@ -490,10 +490,10 @@ static void CodeError( char *fmt, ... ) {
errorCount++;
- report( "%s:%i ", currentFileName, currentFileLine );
+ fprintf( stderr, "%s:%i ", currentFileName, currentFileLine );
va_start( argptr,fmt );
- vprintf( fmt,argptr );
+ vfprintf( stderr, fmt, argptr );
va_end( argptr );
}
@@ -1521,12 +1521,13 @@ static void ShowHelp( char *argv0 ) {
Error("Usage: %s [OPTION]... [FILES]...\n\
Assemble LCC bytecode assembly to Q3VM bytecode.\n\
\n\
- -o OUTPUT Write assembled output to file OUTPUT.qvm\n\
- -f LISTFILE Read options and list of files to assemble from LISTFILE.q3asm\n\
- -b BUCKETS Set symbol hash table to BUCKETS buckets\n\
- -v Verbose compilation report\n\
- -vq3 Produce a qvm file compatible with Q3 1.32b\n\
- -h --help -? Show this help\n\
+ -o OUTPUT Write assembled output to file OUTPUT.qvm\n\
+ -f LISTFILE Read options and list of files to assemble from LISTFILE.q3asm\n\
+ -b BUCKETS Set symbol hash table to BUCKETS buckets\n\
+ -m Generate a mapfile for each OUTPUT.qvm\n\
+ -v Verbose compilation report\n\
+ -vq3 Produce a qvm file compatible with Q3 1.32b\n\
+ -h --help -? Show this help\n\
", argv0);
}