diff options
author | Tim Angus <tim@ngus.net> | 2009-11-16 00:23:28 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:17:20 +0000 |
commit | 21674b587ca1aa1e956b66ae6e613d5afb2111d3 (patch) | |
tree | ef74238d6371114ac0f773eacd209f728225ffb9 | |
parent | d22e46c9afdaf65a06ed0836d4f7e2b9e689e4d9 (diff) |
* Merge ioq3-r1752
-rw-r--r-- | Makefile | 212 | ||||
-rw-r--r-- | src/client/cl_input.c | 96 | ||||
-rw-r--r-- | src/client/cl_main.c | 43 | ||||
-rw-r--r-- | src/client/client.h | 2 | ||||
-rw-r--r-- | src/client/snd_dma.c | 13 | ||||
-rw-r--r-- | src/client/snd_local.h | 1 | ||||
-rw-r--r-- | src/client/snd_main.c | 41 | ||||
-rw-r--r-- | src/client/snd_mix.c | 5 | ||||
-rw-r--r-- | src/client/snd_openal.c | 47 | ||||
-rw-r--r-- | src/null/null_client.c | 4 | ||||
-rw-r--r-- | src/qcommon/common.c | 131 | ||||
-rw-r--r-- | src/qcommon/cvar.c | 306 | ||||
-rw-r--r-- | src/qcommon/files.c | 56 | ||||
-rw-r--r-- | src/qcommon/net_ip.c | 6 | ||||
-rw-r--r-- | src/qcommon/q_shared.h | 55 | ||||
-rw-r--r-- | src/qcommon/qcommon.h | 9 | ||||
-rw-r--r-- | src/qcommon/vm.c | 16 | ||||
-rw-r--r-- | src/qcommon/vm_interpreted.c | 21 | ||||
-rw-r--r-- | src/qcommon/vm_local.h | 11 | ||||
-rw-r--r-- | src/qcommon/vm_x86_64.c | 229 | ||||
-rw-r--r-- | src/qcommon/vm_x86_64_assembler.c | 41 | ||||
-rw-r--r-- | src/renderer/tr_init.c | 2 | ||||
-rw-r--r-- | src/renderer/tr_local.h | 1 | ||||
-rw-r--r-- | src/sdl/sdl_glimp.c | 24 | ||||
-rw-r--r-- | src/sys/con_tty.c | 6 | ||||
-rw-r--r-- | src/sys/sys_unix.c | 40 | ||||
-rw-r--r-- | src/sys/sys_win32.c | 31 |
27 files changed, 1035 insertions, 414 deletions
@@ -149,6 +149,10 @@ ifndef BUILD_MASTER_SERVER BUILD_MASTER_SERVER=0 endif +ifndef DEBUG_CFLAGS +DEBUG_CFLAGS=-g -O0 +endif + ############################################################################# BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH) @@ -243,38 +247,43 @@ ifeq ($(PLATFORM),linux) endif BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ - -pipe -DUSE_ICON $(SDL_CFLAGS) + -pipe -DUSE_ICON + CLIENT_CFLAGS = $(SDL_CFLAGS) + SERVER_CFLAGS = ifeq ($(USE_OPENAL),1) - BASE_CFLAGS += -DUSE_OPENAL + CLIENT_CFLAGS += -DUSE_OPENAL ifeq ($(USE_OPENAL_DLOPEN),1) - BASE_CFLAGS += -DUSE_OPENAL_DLOPEN + CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN endif endif ifeq ($(USE_CURL),1) - BASE_CFLAGS += -DUSE_CURL + CLIENT_CFLAGS += -DUSE_CURL ifeq ($(USE_CURL_DLOPEN),1) - BASE_CFLAGS += -DUSE_CURL_DLOPEN + CLIENT_CFLAGS += -DUSE_CURL_DLOPEN endif endif ifeq ($(USE_CODEC_VORBIS),1) - BASE_CFLAGS += -DUSE_CODEC_VORBIS + CLIENT_CFLAGS += -DUSE_CODEC_VORBIS endif - OPTIMIZE = -O3 -ffast-math -funroll-loops -fomit-frame-pointer + OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer + OPTIMIZE = $(OPTIMIZEVM) -ffast-math ifeq ($(ARCH),x86_64) - OPTIMIZE = -O3 -fomit-frame-pointer -ffast-math -funroll-loops \ + OPTIMIZEVM = -O3 -fomit-frame-pointer -funroll-loops \ -falign-loops=2 -falign-jumps=2 -falign-functions=2 \ -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) -ffast-math HAVE_VM_COMPILED = true else ifeq ($(ARCH),x86) - OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \ + OPTIMIZEVM = -O3 -march=i586 -fomit-frame-pointer \ -funroll-loops -falign-loops=2 -falign-jumps=2 \ -falign-functions=2 -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) -ffast-math HAVE_VM_COMPILED=true else ifeq ($(ARCH),ppc) @@ -287,6 +296,7 @@ ifeq ($(PLATFORM),linux) endif ifeq ($(ARCH),sparc) OPTIMIZE += -mtune=ultrasparc3 -mv8plus + OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus HAVE_VM_COMPILED=true endif endif @@ -326,7 +336,7 @@ ifeq ($(PLATFORM),linux) endif ifeq ($(USE_LOCAL_HEADERS),1) - BASE_CFLAGS += -I$(SDLHDIR)/include + CLIENT_CFLAGS += -I$(SDLHDIR)/include endif ifeq ($(ARCH),x86) @@ -337,10 +347,6 @@ ifeq ($(PLATFORM),linux) BASE_CFLAGS += -m64 endif endif - - DEBUG_CFLAGS = $(BASE_CFLAGS) -g -O0 - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE) - else # ifeq Linux ############################################################################# @@ -350,19 +356,21 @@ else # ifeq Linux ifeq ($(PLATFORM),darwin) HAVE_VM_COMPILED=true CLIENT_LIBS= - OPTIMIZE= + OPTIMIZEVM= BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes + CLIENT_CFLAGS = + SERVER_CFLAGS = ifeq ($(ARCH),ppc) BASE_CFLAGS += -faltivec - OPTIMIZE += -O3 + OPTIMIZEVM += -O3 endif ifeq ($(ARCH),ppc64) BASE_CFLAGS += -faltivec endif ifeq ($(ARCH),x86) - OPTIMIZE += -march=prescott -mfpmath=sse + OPTIMIZEVM += -march=prescott -mfpmath=sse # x86 vm will crash without -mstackrealign since MMX instructions will be # used no matter what and they corrupt the frame pointer in VM calls BASE_CFLAGS += -mstackrealign @@ -375,21 +383,21 @@ ifeq ($(PLATFORM),darwin) ifneq ($(USE_OPENAL_DLOPEN),1) CLIENT_LIBS += -framework OpenAL else - BASE_CFLAGS += -DUSE_OPENAL_DLOPEN + CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN endif endif ifeq ($(USE_CURL),1) - BASE_CFLAGS += -DUSE_CURL + CLIENT_CFLAGS += -DUSE_CURL ifneq ($(USE_CURL_DLOPEN),1) CLIENT_LIBS += -lcurl else - BASE_CFLAGS += -DUSE_CURL_DLOPEN + CLIENT_CFLAGS += -DUSE_CURL_DLOPEN endif endif ifeq ($(USE_CODEC_VORBIS),1) - BASE_CFLAGS += -DUSE_CODEC_VORBIS + CLIENT_CFLAGS += -DUSE_CODEC_VORBIS CLIENT_LIBS += -lvorbisfile -lvorbis -logg endif @@ -406,16 +414,13 @@ ifeq ($(PLATFORM),darwin) CLIENT_LIBS += -framework Cocoa -framework IOKit -framework OpenGL \ $(LIBSDIR)/macosx/libSDL-1.2.0.dylib - OPTIMIZE += -ffast-math -falign-loops=16 + OPTIMIZEVM += -falign-loops=16 + OPTIMIZE = $(OPTIMIZEVM) -ffast-math ifneq ($(HAVE_VM_COMPILED),true) BASE_CFLAGS += -DNO_VM_COMPILED endif - DEBUG_CFLAGS = $(BASE_CFLAGS) -g -O0 - - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE) - SHLIBEXT=dylib SHLIBCFLAGS=-fPIC -fno-common SHLIBLDFLAGS=-dynamiclib $(LDFLAGS) @@ -447,6 +452,8 @@ ifeq ($(PLATFORM),mingw32) BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ -DUSE_ICON + CLIENT_CFLAGS = + SERVER_CFLAGS = # In the absence of wspiapi.h, require Windows XP or later ifeq ($(shell test -e $(CMDIR)/wspiapi.h; echo $$?),1) @@ -454,22 +461,23 @@ ifeq ($(PLATFORM),mingw32) endif ifeq ($(USE_OPENAL),1) - BASE_CFLAGS += -DUSE_OPENAL - BASE_CFLAGS += $(OPENAL_CFLAGS) + CLIENT_CFLAGS += -DUSE_OPENAL + CLIENT_CFLAGS += $(OPENAL_CFLAGS) ifeq ($(USE_OPENAL_DLOPEN),1) - BASE_CFLAGS += -DUSE_OPENAL_DLOPEN + CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN else CLIENT_LDFLAGS += $(OPENAL_LDFLAGS) endif endif ifeq ($(USE_CODEC_VORBIS),1) - BASE_CFLAGS += -DUSE_CODEC_VORBIS + CLIENT_CFLAGS += -DUSE_CODEC_VORBIS endif - OPTIMIZE = -O3 -march=i586 -fno-omit-frame-pointer -ffast-math \ + OPTIMIZEVM = -O3 -march=i586 -fno-omit-frame-pointer \ -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \ -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) -ffast-math HAVE_VM_COMPILED = true @@ -484,11 +492,11 @@ ifeq ($(PLATFORM),mingw32) CLIENT_LIBS = -lgdi32 -lole32 -lopengl32 ifeq ($(USE_CURL),1) - BASE_CFLAGS += -DUSE_CURL - BASE_CFLAGS += $(CURL_CFLAGS) + CLIENT_CFLAGS += -DUSE_CURL + CLIENT_CFLAGS += $(CURL_CFLAGS) ifneq ($(USE_CURL_DLOPEN),1) ifeq ($(USE_LOCAL_HEADERS),1) - BASE_CFLAGS += -DCURL_STATICLIB + CLIENT_CFLAGS += -DCURL_STATICLIB CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a else CLIENT_LIBS += $(CURL_LIBS) @@ -505,22 +513,17 @@ ifeq ($(PLATFORM),mingw32) BASE_CFLAGS += -m32 endif - DEBUG_CFLAGS=$(BASE_CFLAGS) -g -O0 - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE) - # libmingw32 must be linked before libSDLmain CLIENT_LIBS += -lmingw32 ifeq ($(USE_LOCAL_HEADERS),1) - BASE_CFLAGS += -I$(SDLHDIR)/include + CLIENT_CFLAGS += -I$(SDLHDIR)/include CLIENT_LIBS += $(LIBSDIR)/win32/libSDLmain.a \ $(LIBSDIR)/win32/libSDL.dll.a else - BASE_CFLAGS += $(SDL_CFLAGS) + CLIENT_CFLAGS += $(SDL_CFLAGS) CLIENT_LIBS += $(SDL_LIBS) endif - - BUILD_CLIENT_SMP = 0 else # ifeq mingw32 @@ -537,38 +540,39 @@ ifeq ($(PLATFORM),freebsd) ARCH=x86 endif #alpha test - BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ - -DUSE_ICON $(SDL_CFLAGS) + -DUSE_ICON + CLIENT_CFLAGS = $(SDL_CFLAGS) + SERVER_CFLAGS = ifeq ($(USE_OPENAL),1) - BASE_CFLAGS += -DUSE_OPENAL + CLIENT_CFLAGS += -DUSE_OPENAL ifeq ($(USE_OPENAL_DLOPEN),1) - BASE_CFLAGS += -DUSE_OPENAL_DLOPEN + CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN endif endif ifeq ($(USE_CODEC_VORBIS),1) - BASE_CFLAGS += -DUSE_CODEC_VORBIS + CLIENT_CFLAGS += -DUSE_CODEC_VORBIS endif + OPTIMIZEVM = -DNDEBUG -O3 -funroll-loops -fomit-frame-pointer + ifeq ($(ARCH),axp) BASE_CFLAGS += -DNO_VM_COMPILED - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -ffast-math -funroll-loops \ - -fomit-frame-pointer -fexpensive-optimizations + OPTIMIZEVM += -fexpensive-optimizations else ifeq ($(ARCH),x86) - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -mtune=pentiumpro \ - -march=pentium -fomit-frame-pointer -pipe -ffast-math \ - -falign-loops=2 -falign-jumps=2 -falign-functions=2 \ - -funroll-loops -fstrength-reduce + OPTIMIZEVM += -mtune=pentiumpro \ + -march=pentium -pipe -falign-loops=2 -falign-jumps=2 \ + -falign-functions=2 -funroll-loops -fstrength-reduce HAVE_VM_COMPILED=true else BASE_CFLAGS += -DNO_VM_COMPILED endif endif - DEBUG_CFLAGS=$(BASE_CFLAGS) -g + OPTIMIZE = $(OPTIMIZEVM) -ffast-math SHLIBEXT=so SHLIBCFLAGS=-fPIC @@ -603,32 +607,30 @@ ifeq ($(PLATFORM),openbsd) #default to i386, no tests done on anything else ARCH=i386 - BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ - -DUSE_ICON $(SDL_CFLAGS) + -DUSE_ICON + CLIENT_CFLAGS = $(SDL_CFLAGS) + SERVER_CFLAGS = ifeq ($(USE_OPENAL),1) - BASE_CFLAGS += -DUSE_OPENAL + CLIENT_CFLAGS += -DUSE_OPENAL ifeq ($(USE_OPENAL_DLOPEN),1) - BASE_CFLAGS += -DUSE_OPENAL_DLOPEN + CLIENT_CFLAGS += -DUSE_OPENAL_DLOPEN endif endif ifeq ($(USE_CODEC_VORBIS),1) - BASE_CFLAGS += -DUSE_CODEC_VORBIS + CLIENT_CFLAGS += -DUSE_CODEC_VORBIS endif ifeq ($(USE_CURL),1) - BASE_CFLAGS += -DUSE_CURL $(CURL_CFLAGS) + CLIENT_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 @@ -676,13 +678,13 @@ ifeq ($(PLATFORM),netbsd) THREAD_LIBS=-lpthread BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes + CLIENT_CFLAGS = + SERVER_CFLAGS = ifneq ($(ARCH),x86) BASE_CFLAGS += -DNO_VM_COMPILED endif - DEBUG_CFLAGS=$(BASE_CFLAGS) -g - BUILD_CLIENT = 0 BUILD_GAME_QVM = 0 @@ -700,10 +702,10 @@ ifeq ($(PLATFORM),irix64) MKDIR = mkdir -p BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \ - -I. $(SDL_CFLAGS) -I$(ROOT)/usr/include -DNO_VM_COMPILED - RELEASE_CFLAGS=$(BASE_CFLAGS) -O3 - DEBUG_CFLAGS=$(BASE_CFLAGS) -g - + -I. -I$(ROOT)/usr/include -DNO_VM_COMPILED + CLIENT_CFLAGS = $(SDL_CFLAGS) + OPTIMIZE = -O3 + SHLIBEXT=so SHLIBCFLAGS= SHLIBLDFLAGS=-shared @@ -739,36 +741,35 @@ ifeq ($(PLATFORM),sunos) endif BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ - -pipe -DUSE_ICON $(SDL_CFLAGS) + -pipe -DUSE_ICON + CLIENT_CFLAGS = $(SDL_CFLAGS) + SERVER_CFLAGS = - OPTIMIZE = -O3 -ffast-math -funroll-loops + OPTIMIZEVM = -O3 -funroll-loops -DNDEBUG ifeq ($(ARCH),sparc) - OPTIMIZE = -O3 -ffast-math \ + OPTIMIZEVM += -O3 \ -fstrength-reduce -falign-functions=2 \ - -mtune=ultrasparc3 -mv8plus -mno-faster-structs \ - -funroll-loops #-mv8plus + -mtune=ultrasparc3 -mv8plus -mno-faster-structs HAVE_VM_COMPILED=true else ifeq ($(ARCH),x86) - OPTIMIZE = -O3 -march=i586 -fomit-frame-pointer -ffast-math \ - -funroll-loops -falign-loops=2 -falign-jumps=2 \ + OPTIMIZEVM += -march=i586 -fomit-frame-pointer \ + -falign-loops=2 -falign-jumps=2 \ -falign-functions=2 -fstrength-reduce HAVE_VM_COMPILED=true BASE_CFLAGS += -m32 - BASE_CFLAGS += -I/usr/X11/include/NVIDIA + CLIENT_CFLAGS += -I/usr/X11/include/NVIDIA CLIENT_LDFLAGS += -L/usr/X11/lib/NVIDIA -R/usr/X11/lib/NVIDIA endif endif + + OPTIMIZE = $(OPTIMIZEVM) -ffast-math ifneq ($(HAVE_VM_COMPILED),true) BASE_CFLAGS += -DNO_VM_COMPILED endif - DEBUG_CFLAGS = $(BASE_CFLAGS) -ggdb -O0 - - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG $(OPTIMIZE) - SHLIBEXT=so SHLIBCFLAGS=-fPIC SHLIBLDFLAGS=-shared $(LDFLAGS) @@ -786,8 +787,7 @@ else # ifeq sunos # SETUP AND BUILD -- GENERIC ############################################################################# BASE_CFLAGS=-DNO_VM_COMPILED - DEBUG_CFLAGS=$(BASE_CFLAGS) -g - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 + OPTIMIZE = -DNDEBUG -O3 SHLIBEXT=so SHLIBCFLAGS=-fPIC @@ -840,13 +840,13 @@ ifneq ($(BUILD_GAME_QVM),0) endif ifeq ($(USE_MUMBLE),1) - BASE_CFLAGS += -DUSE_MUMBLE + CLIENT_CFLAGS += -DUSE_MUMBLE endif ifeq ($(USE_VOIP),1) - BASE_CFLAGS += -DUSE_VOIP + CLIENT_CFLAGS += -DUSE_VOIP ifeq ($(USE_INTERNAL_SPEEX),1) - BASE_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include + CLIENT_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include else CLIENT_LIBS += -lspeex -lspeexdsp endif @@ -897,12 +897,12 @@ endif define DO_CC $(echo_cmd) "CC $<" -$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -o $@ -c $< +$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -o $@ -c $< endef define DO_SMP_CC $(echo_cmd) "SMP_CC $<" -$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) -DSMP -o $@ -c $< +$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -DSMP -o $@ -c $< endef ifeq ($(GENERATE_DEPENDENCIES),1) @@ -911,36 +911,36 @@ endif define DO_SHLIB_CC $(echo_cmd) "SHLIB_CC $<" -$(Q)$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +$(Q)$(CC) $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< $(Q)$(DO_QVM_DEP) endef define DO_GAME_CC $(echo_cmd) "GAME_CC $<" -$(Q)$(CC) -DGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +$(Q)$(CC) -DGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< $(Q)$(DO_QVM_DEP) endef define DO_CGAME_CC $(echo_cmd) "CGAME_CC $<" -$(Q)$(CC) -DCGAME $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +$(Q)$(CC) -DCGAME $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< $(Q)$(DO_QVM_DEP) endef define DO_UI_CC $(echo_cmd) "UI_CC $<" -$(Q)$(CC) -DUI $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +$(Q)$(CC) -DUI $(SHLIBCFLAGS) $(CFLAGS) $(OPTIMIZEVM) -o $@ -c $< $(Q)$(DO_QVM_DEP) endef define DO_AS $(echo_cmd) "AS $<" -$(Q)$(CC) $(CFLAGS) -x assembler-with-cpp -o $@ -c $< +$(Q)$(CC) $(CFLAGS) $(OPTIMIZE) -x assembler-with-cpp -o $@ -c $< endef define DO_DED_CC $(echo_cmd) "DED_CC $<" -$(Q)$(CC) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) -o $@ -c $< +$(Q)$(CC) $(NOTSHLIBCFLAGS) -DDEDICATED $(CFLAGS) $(SERVER_CFLAGS) $(OPTIMIZE) -o $@ -c $< endef define DO_WINDRES @@ -957,15 +957,17 @@ default: release all: debug release debug: - @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(DEPEND_CFLAGS) \ - $(DEBUG_CFLAGS)" V=$(V) + @$(MAKE) targets B=$(BD) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \ + OPTIMIZE="$(DEBUG_CFLAGS)" OPTIMIZEVM="$(DEBUG_CFLAGS)" \ + CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V) ifeq ($(BUILD_MASTER_SERVER),1) $(MAKE) -C $(MASTERDIR) debug endif release: - @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(DEPEND_CFLAGS) \ - $(RELEASE_CFLAGS)" V=$(V) + @$(MAKE) targets B=$(BR) CFLAGS="$(CFLAGS) $(BASE_CFLAGS) $(DEPEND_CFLAGS)" \ + OPTIMIZE="$(OPTIMIZE)" OPTIMIZEVM="$(OPTIMIZEVM)" \ + CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V) ifeq ($(BUILD_MASTER_SERVER),1) $(MAKE) -C $(MASTERDIR) release endif @@ -987,6 +989,22 @@ targets: makedirs do \ echo " $$i"; \ done + -@for i in $(OPTIMIZE); \ + do \ + echo " $$i"; \ + done + @echo "" + @echo " CLIENT_CFLAGS:" + -@for i in $(CLIENT_CFLAGS); \ + do \ + echo " $$i"; \ + done + @echo "" + @echo " SERVER_CFLAGS:" + -@for i in $(SERVER_CFLAGS); \ + do \ + echo " $$i"; \ + done @echo "" @echo " LDFLAGS:" -@for i in $(LDFLAGS); \ diff --git a/src/client/cl_input.c b/src/client/cl_input.c index 49551662..19bdb95a 100644 --- a/src/client/cl_input.c +++ b/src/client/cl_input.c @@ -436,52 +436,88 @@ void CL_JoystickMove( usercmd_t *cmd ) { CL_MouseMove ================= */ -void CL_MouseMove( usercmd_t *cmd ) { - float mx, my; - float accelSensitivity; - float rate; + +void CL_MouseMove(usercmd_t *cmd) +{ + float mx, my; // allow mouse smoothing - if ( m_filter->integer ) { - mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5; - my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5; - } else { + if (m_filter->integer) + { + mx = (cl.mouseDx[0] + cl.mouseDx[1]) * 0.5f; + my = (cl.mouseDy[0] + cl.mouseDy[1]) * 0.5f; + } + else + { mx = cl.mouseDx[cl.mouseIndex]; my = cl.mouseDy[cl.mouseIndex]; } + cl.mouseIndex ^= 1; cl.mouseDx[cl.mouseIndex] = 0; cl.mouseDy[cl.mouseIndex] = 0; - rate = sqrt( mx * mx + my * my ) / (float)frame_msec; - accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value; - - // scale by FOV - accelSensitivity *= cl.cgameSensitivity; - - if ( rate && cl_showMouseRate->integer ) { - Com_Printf( "%f : %f\n", rate, accelSensitivity ); - } - - mx *= accelSensitivity; - my *= accelSensitivity; - - if (!mx && !my) { + if (mx == 0.0f && my == 0.0f) return; + + if (cl_mouseAccel->value != 0.0f) + { + if(cl_mouseAccelStyle->integer == 0) + { + float accelSensitivity; + float rate; + + rate = sqrt(mx * mx + my * my) / (float) frame_msec; + + accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value; + mx *= accelSensitivity; + my *= accelSensitivity; + + if(cl_showMouseRate->integer) + Com_Printf("rate: %f, accelSensitivity: %f\n", rate, accelSensitivity); + } + else + { + float rate[2]; + float power[2]; + + // sensitivity remains pretty much unchanged at low speeds + // cl_mouseAccel is a power value to how the acceleration is shaped + // cl_mouseAccelOffset is the rate for which the acceleration will have doubled the non accelerated amplification + // NOTE: decouple the config cvars for independent acceleration setup along X and Y? + + rate[0] = fabs(mx) / (float) frame_msec; + rate[1] = fabs(my) / (float) frame_msec; + power[0] = powf(rate[0] / cl_mouseAccelOffset->value, cl_mouseAccel->value); + power[1] = powf(rate[1] / cl_mouseAccelOffset->value, cl_mouseAccel->value); + + mx = cl_sensitivity->value * (mx + ((mx < 0) ? -power[0] : power[0]) * cl_mouseAccelOffset->value); + my = cl_sensitivity->value * (my + ((my < 0) ? -power[1] : power[1]) * cl_mouseAccelOffset->value); + + if(cl_showMouseRate->integer) + Com_Printf("ratex: %f, ratey: %f, powx: %f, powy: %f\n", rate[0], rate[1], power[0], power[1]); + } } + else + { + mx *= cl_sensitivity->value; + my *= cl_sensitivity->value; + } + + // ingame FOV + mx *= cl.cgameSensitivity; + my *= cl.cgameSensitivity; // add mouse X/Y movement to cmd - if ( in_strafe.active ) { - cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx ); - } else { + if(in_strafe.active) + cmd->rightmove = ClampChar(cmd->rightmove + m_side->value * mx); + else cl.viewangles[YAW] -= m_yaw->value * mx; - } - if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) { + if ((in_mlooking || cl_freelook->integer) && !in_strafe.active) cl.viewangles[PITCH] += m_pitch->value * my; - } else { - cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my ); - } + else + cmd->forwardmove = ClampChar(cmd->forwardmove - m_forward->value * my); } diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 4c8ded12..ff86ee2f 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -74,6 +74,8 @@ cvar_t *cl_freelook; cvar_t *cl_sensitivity; cvar_t *cl_mouseAccel; +cvar_t *cl_mouseAccelOffset; +cvar_t *cl_mouseAccelStyle; cvar_t *cl_showMouseRate; cvar_t *m_pitch; @@ -977,7 +979,7 @@ void CL_PlayDemo_f( void ) { char retry[MAX_OSPATH]; if (Cmd_Argc() != 2) { - Com_Printf ("playdemo <demoname>\n"); + Com_Printf ("demo <demoname>\n"); return; } @@ -985,14 +987,17 @@ void CL_PlayDemo_f( void ) { // 2 means don't force disconnect of local client Cvar_Set( "sv_killserver", "2" ); - CL_Disconnect( qtrue ); - // open the demo file arg = Cmd_Argv(1); + CL_Disconnect( qtrue ); + // check for an extension .dm_?? (?? is protocol) ext_test = arg + strlen(arg) - 6; - if ((strlen(arg) > 6) && (ext_test[0] == '.') && ((ext_test[1] == 'd') || (ext_test[1] == 'D')) && ((ext_test[2] == 'm') || (ext_test[2] == 'M')) && (ext_test[3] == '_')) + if ((strlen(arg) > 6) && (ext_test[0] == '.') && + ((ext_test[1] == 'd') || (ext_test[1] == 'D')) && + ((ext_test[2] == 'm') || (ext_test[2] == 'M')) && + (ext_test[3] == '_')) { protocol = atoi(ext_test+4); i=0; @@ -1343,6 +1348,9 @@ void CL_Disconnect( qboolean showMainMenu ) { CL_WritePacket(); } + // Remove pure paks + FS_PureServerSetLoadedPaks("", ""); + CL_ClearState (); // wipe the client connection @@ -1752,17 +1760,29 @@ void CL_Vid_Restart_f( void ) { /* ================= -CL_Snd_Restart_f +CL_Snd_Restart Restart the sound subsystem -The cgame and game must also be forced to restart because -handles will be invalid ================= */ -void CL_Snd_Restart_f( void ) { +void CL_Snd_Restart(void) +{ S_Shutdown(); S_Init(); +} +/* +================= +CL_Snd_Restart_f + +Restart the sound subsystem +The cgame and game must also be forced to restart because +handles will be invalid +================= +*/ +void CL_Snd_Restart_f(void) +{ + CL_Snd_Restart(); CL_Vid_Restart_f(); } @@ -3337,6 +3357,13 @@ void CL_Init( void ) { cl_mouseAccel = Cvar_Get ("cl_mouseAccel", "0", CVAR_ARCHIVE); cl_freelook = Cvar_Get( "cl_freelook", "1", CVAR_ARCHIVE ); + // 0: legacy mouse acceleration + // 1: new implementation + cl_mouseAccelStyle = Cvar_Get( "cl_mouseAccelStyle", "0", CVAR_ARCHIVE ); + // offset for the power function (for style 1, ignored otherwise) + // this should be set to the max rate value + cl_mouseAccelOffset = Cvar_Get( "cl_mouseAccelOffset", "5", CVAR_ARCHIVE ); + cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0); cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); diff --git a/src/client/client.h b/src/client/client.h index 1e18a9ad..0dc2490e 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -387,6 +387,8 @@ extern cvar_t *cl_sensitivity; extern cvar_t *cl_freelook; extern cvar_t *cl_mouseAccel; +extern cvar_t *cl_mouseAccelOffset; +extern cvar_t *cl_mouseAccelStyle; extern cvar_t *cl_showMouseRate; extern cvar_t *m_pitch; diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c index 472af0d8..ad6193c8 100644 --- a/src/client/snd_dma.c +++ b/src/client/snd_dma.c @@ -34,10 +34,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_codec.h" #include "client.h" -void S_Play_f(void); -void S_SoundList_f(void); -void S_Music_f(void); - void S_Update_( void ); void S_Base_StopAllSounds(void); void S_Base_StopBackgroundTrack( void ); @@ -953,7 +949,10 @@ void S_Base_RawSamples( int stream, int samples, int rate, int width, int s_chan } rawsamples = s_rawsamples[stream]; - intVolume = 256 * volume * s_volume->value; + if(s_muted->integer) + intVolume = 0; + else + intVolume = 256 * volume * s_volume->value; if ( s_rawend[stream] < s_soundtime ) { Com_DPrintf( "S_Base_RawSamples: resetting minimum: %i < %i\n", s_rawend[stream], s_soundtime ); @@ -1328,7 +1327,9 @@ void S_Base_StartBackgroundTrack( const char *intro, const char *loop ){ } Com_DPrintf( "S_StartBackgroundTrack( %s, %s )\n", intro, loop ); - if ( !intro[0] ) { + if(!*intro) + { + S_Base_StopBackgroundTrack(); return; } diff --git a/src/client/snd_local.h b/src/client/snd_local.h index a926e7f9..24ddc54d 100644 --- a/src/client/snd_local.h +++ b/src/client/snd_local.h @@ -195,6 +195,7 @@ extern int s_rawend[MAX_RAW_STREAMS]; extern cvar_t *s_volume; extern cvar_t *s_musicVolume; +extern cvar_t *s_muted; extern cvar_t *s_doppler; extern cvar_t *s_testsound; diff --git a/src/client/snd_main.c b/src/client/snd_main.c index c386cd75..66c3f9e7 100644 --- a/src/client/snd_main.c +++ b/src/client/snd_main.c @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "snd_public.h" cvar_t *s_volume; +cvar_t *s_muted; cvar_t *s_musicVolume; cvar_t *s_doppler; cvar_t *s_backend; @@ -231,12 +232,25 @@ S_Update */ void S_Update( void ) { - if( ( s_muteWhenMinimized->integer && com_minimized->integer ) || - ( s_muteWhenUnfocused->integer && com_unfocused->integer ) ) { - S_StopAllSounds( ); - return; + if(s_muted->integer) + { + if(!(s_muteWhenMinimized->integer && com_minimized->integer) && + !(s_muteWhenUnfocused->integer && com_unfocused->integer)) + { + s_muted->integer = qfalse; + s_muted->modified = qtrue; + } } - + else + { + if((s_muteWhenMinimized->integer && com_minimized->integer) || + (s_muteWhenUnfocused->integer && com_unfocused->integer)) + { + s_muted->integer = qtrue; + s_muted->modified = qtrue; + } + } + if( si.Update ) { si.Update( ); } @@ -449,6 +463,20 @@ void S_Music_f( void ) { } +/* +================= +S_Music_f +================= +*/ +void S_StopMusic_f( void ) +{ + if(!si.StopBackgroundTrack) + return; + + si.StopBackgroundTrack(); +} + + //============================================================================= /* @@ -465,6 +493,7 @@ void S_Init( void ) s_volume = Cvar_Get( "s_volume", "0.8", CVAR_ARCHIVE ); s_musicVolume = Cvar_Get( "s_musicvolume", "0.25", CVAR_ARCHIVE ); + s_muted = Cvar_Get("s_muted", "0", CVAR_ROM); 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 ); @@ -479,6 +508,7 @@ void S_Init( void ) Cmd_AddCommand( "play", S_Play_f ); Cmd_AddCommand( "music", S_Music_f ); + Cmd_AddCommand( "stopmusic", S_StopMusic_f ); Cmd_AddCommand( "s_list", S_SoundList ); Cmd_AddCommand( "s_stop", S_StopAllSounds ); Cmd_AddCommand( "s_info", S_SoundInfo ); @@ -525,6 +555,7 @@ void S_Shutdown( void ) Cmd_RemoveCommand( "play" ); Cmd_RemoveCommand( "music"); + Cmd_RemoveCommand( "stopmusic"); Cmd_RemoveCommand( "s_list" ); Cmd_RemoveCommand( "s_stop" ); Cmd_RemoveCommand( "s_info" ); diff --git a/src/client/snd_mix.c b/src/client/snd_mix.c index fa2a841d..a9d4c794 100644 --- a/src/client/snd_mix.c +++ b/src/client/snd_mix.c @@ -638,7 +638,10 @@ void S_PaintChannels( int endtime ) { int ltime, count; int sampleOffset; - snd_vol = s_volume->value*255; + if(s_muted->integer) + snd_vol = 0; + else + snd_vol = s_volume->value*255; //Com_Printf ("%i to %i\n", s_paintedtime, endtime); while ( s_paintedtime < endtime ) { diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c index 96068075..12df259c 100644 --- a/src/client/snd_openal.c +++ b/src/client/snd_openal.c @@ -581,6 +581,21 @@ static void _S_AL_SanitiseVector( vec3_t v, int line ) /* ================= +S_AL_Gain +Set gain to 0 if muted, otherwise set it to given value. +================= +*/ + +static void S_AL_Gain(ALuint source, float gainval) +{ + if(s_muted->integer) + qalSourcef(source, AL_GAIN, 0.0f); + else + qalSourcef(source, AL_GAIN, gainval); +} + +/* +================= S_AL_ScaleGain Adapt the gain if necessary to get a quicker fadeout when the source is too far away. ================= @@ -609,13 +624,13 @@ static void S_AL_ScaleGain(src_t *chksrc, vec3_t origin) if(chksrc->scaleGain != scaleFactor); { chksrc->scaleGain = scaleFactor; - qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain); + S_AL_Gain(chksrc->alSource, chksrc->scaleGain); } } else if(chksrc->scaleGain != chksrc->curGain) { chksrc->scaleGain = chksrc->curGain; - qalSourcef(chksrc->alSource, AL_GAIN, chksrc->scaleGain); + S_AL_Gain(chksrc->alSource, chksrc->scaleGain); } } @@ -757,7 +772,7 @@ static void S_AL_SrcSetup(srcHandle_t src, sfxHandle_t sfx, alSrcPriority_t prio // Set up OpenAL source qalSourcei(curSource->alSource, AL_BUFFER, buffer); qalSourcef(curSource->alSource, AL_PITCH, 1.0f); - qalSourcef(curSource->alSource, AL_GAIN, curSource->curGain); + S_AL_Gain(curSource->alSource, curSource->curGain); qalSourcefv(curSource->alSource, AL_POSITION, vec3_origin); qalSourcefv(curSource->alSource, AL_VELOCITY, vec3_origin); qalSourcei(curSource->alSource, AL_LOOPING, AL_FALSE); @@ -1615,6 +1630,10 @@ static void S_AL_AllocateStreamChannel( int stream ) S_AL_SrcLock(streamSourceHandles[stream]); streamSources[stream] = S_AL_SrcGet(streamSourceHandles[stream]); + // make sure that after unmuting the S_AL_Gain in S_Update() does not turn + // volume up prematurely for this source + srcList[streamSourceHandles[stream]].scaleGain = 0.0f; + // Set some streamSource parameters qalSourcei (streamSources[stream], AL_BUFFER, 0 ); qalSourcei (streamSources[stream], AL_LOOPING, AL_FALSE ); @@ -1678,7 +1697,7 @@ void S_AL_RawSamples(int stream, int samples, int rate, int width, int channels, qalSourceQueueBuffers(streamSources[stream], 1, &buffer); // Volume - qalSourcef (streamSources[stream], AL_GAIN, volume * s_volume->value * s_alGain->value); + S_AL_Gain (streamSources[stream], volume * s_volume->value * s_alGain->value); } /* @@ -1792,6 +1811,10 @@ static void S_AL_MusicSourceGet( void ) S_AL_SrcLock(musicSourceHandle); musicSource = S_AL_SrcGet(musicSourceHandle); + // make sure that after unmuting the S_AL_Gain in S_Update() does not turn + // volume up prematurely for this source + srcList[musicSourceHandle].scaleGain = 0.0f; + // Set some musicSource parameters qalSource3f(musicSource, AL_POSITION, 0.0, 0.0, 0.0); qalSource3f(musicSource, AL_VELOCITY, 0.0, 0.0, 0.0); @@ -1995,7 +2018,7 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop ) qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers); // Set the initial gain property - qalSourcef(musicSource, AL_GAIN, s_alGain->value * s_musicVolume->value); + S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value); // Start playing qalSourcePlay(musicSource); @@ -2038,7 +2061,7 @@ void S_AL_MusicUpdate( void ) } // Set the gain property - qalSourcef(musicSource, AL_GAIN, s_alGain->value * s_musicVolume->value); + S_AL_Gain(musicSource, s_alGain->value * s_musicVolume->value); } @@ -2117,6 +2140,18 @@ void S_AL_Update( void ) { int i; + if(s_muted->modified) + { + // muted state changed. Let S_AL_Gain turn up all sources again. + for(i = 0; i < srcCount; i++) + { + if(srcList[i].isActive) + S_AL_Gain(srcList[i].alSource, srcList[i].scaleGain); + } + + s_muted->modified = qfalse; + } + // Update SFX channels S_AL_SrcUpdate(); diff --git a/src/null/null_client.c b/src/null/null_client.c index e7340804..419339da 100644 --- a/src/null/null_client.c +++ b/src/null/null_client.c @@ -86,4 +86,8 @@ void CL_FlushMemory( void ) { void CL_StartHunkUsers( qboolean rendererOnly ) { } +void CL_Snd_Restart(void) +{ +} + void CL_ShutdownAll(void) {} diff --git a/src/qcommon/common.c b/src/qcommon/common.c index ddd3c023..d1e702c6 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -92,8 +92,9 @@ int com_frameTime; int com_frameMsec; int com_frameNumber; -qboolean com_errorEntered; -qboolean com_fullyInitialized; +qboolean com_errorEntered = qfalse; +qboolean com_fullyInitialized = qfalse; +qboolean com_gameRestarting = qfalse; char com_errorMessage[MAXPRINTMSG]; @@ -244,9 +245,23 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { va_list argptr; static int lastErrorTime; static int errorCount; + static qboolean calledSysError = qfalse; int currentTime; - Cvar_Set( "com_errorCode", va( "%i", code ) ); + if(com_errorEntered) + { + if(!calledSysError) + { + calledSysError = qtrue; + Sys_Error("recursive error after: %s", com_errorMessage); + } + + return; + } + + com_errorEntered = qtrue; + + Cvar_Set("com_errorCode", va("%i", code)); // when we are running automated scripts, make sure we // know if anything failed @@ -265,11 +280,6 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { } lastErrorTime = currentTime; - if ( com_errorEntered ) { - Sys_Error( "recursive error after: %s", com_errorMessage ); - } - com_errorEntered = qtrue; - va_start (argptr,fmt); Q_vsnprintf (com_errorMessage, sizeof(com_errorMessage),fmt,argptr); va_end (argptr); @@ -304,12 +314,13 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { VM_Forced_Unload_Start(); CL_FlushMemory( ); VM_Forced_Unload_Done(); - com_errorEntered = qfalse; CL_CDDialog(); } else { Com_Printf("Server didn't have CD\n" ); } FS_PureServerSetLoadedPaks("", ""); + + com_errorEntered = qfalse; longjmp (abortframe, -1); } else { CL_Shutdown (); @@ -318,6 +329,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { Com_Shutdown (); + calledSysError = qtrue; Sys_Error ("%s", com_errorMessage); } @@ -2363,15 +2375,7 @@ void Com_Setenv_f(void) { char *arg2 = Cmd_ArgsFrom(2); -#ifdef _WIN32 - // windows already removes env variable if value is an empty string - _putenv(va("%s=%s", arg1, arg2)); -#else - if(!*arg2) - unsetenv(arg1); - else - setenv(arg1, arg2, 1); -#endif + Sys_SetEnv(arg1, arg2); } else if(argc == 2) { @@ -2384,6 +2388,85 @@ void Com_Setenv_f(void) } } +/* +================== +Com_ExecuteCfg + +For controlling environment variables +================== +*/ + +void Com_ExecuteCfg(void) +{ + Cbuf_ExecuteText(EXEC_NOW, "exec default.cfg\n"); + Cbuf_Execute(); // Always execute after exec to prevent text buffer overflowing + + if(!Com_SafeMode()) + { + // skip the q3config.cfg and autoexec.cfg if "safe" is on the command line + Cbuf_ExecuteText(EXEC_NOW, "exec " Q3CONFIG_CFG "\n"); + Cbuf_Execute(); + Cbuf_ExecuteText(EXEC_NOW, "exec autoexec.cfg\n"); + Cbuf_Execute(); + } +} + +/* +================== +Com_GameRestart + +Change to a new mod properly with cleaning up cvars before switching. +================== +*/ + +void Com_GameRestart(int checksumFeed, qboolean clientRestart) +{ + // make sure no recursion can be triggered + if(!com_gameRestarting && com_fullyInitialized) + { + com_gameRestarting = qtrue; + + if(clientRestart) + { + CL_Disconnect(qfalse); + CL_ShutdownAll(); + } + + // Kill server if we have one + if(com_sv_running->integer) + SV_Shutdown("Game directory changed"); + + FS_Restart(checksumFeed); + + // Clean out any user and VM created cvars + Cvar_Restart(qtrue); + Com_ExecuteCfg(); + + // Restart sound subsystem so old handles are flushed + CL_Snd_Restart(); + + if(clientRestart) + CL_StartHunkUsers(qfalse); + + com_gameRestarting = qfalse; + } +} + +/* +================== +Com_GameRestart_f + +Expose possibility to change current running mod to the user +================== +*/ + +void Com_GameRestart_f(void) +{ + Cvar_Set("fs_game", Cmd_Argv(1)); + + Com_GameRestart(0, qtrue); +} + static void Com_DetectAltivec(void) { // Only detect if user hasn't forcibly disabled it. @@ -2480,17 +2563,9 @@ void Com_Init( char *commandLine ) { Cmd_AddCommand ("changeVectors", MSG_ReportChangeVectors_f ); Cmd_AddCommand ("writeconfig", Com_WriteConfig_f ); Cmd_SetCommandCompletionFunc( "writeconfig", Cmd_CompleteCfgName ); + Cmd_AddCommand("game_restart", Com_GameRestart_f); - // Make it execute the configuration files - Cbuf_AddText ("exec default.cfg\n"); - - // skip the autogen.cfg if "safe" is on the command line - if (!Com_SafeMode()) - Cbuf_AddText("exec " Q3CONFIG_CFG "\n"); - - Cbuf_AddText ("exec autoexec.cfg\n"); - - Cbuf_Execute (); + Com_ExecuteCfg(); // override anything from the config files with command line args Com_StartupVariable( NULL ); diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c index f82eb78f..459f602b 100644 --- a/src/qcommon/cvar.c +++ b/src/qcommon/cvar.c @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -cvar_t *cvar_vars; +cvar_t *cvar_vars = NULL; cvar_t *cvar_cheats; int cvar_modifiedFlags; @@ -34,7 +34,7 @@ cvar_t cvar_indexes[MAX_CVARS]; int cvar_numIndexes; #define FILE_HASH_SIZE 256 -static cvar_t* hashTable[FILE_HASH_SIZE]; +static cvar_t *hashTable[FILE_HASH_SIZE]; cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force); @@ -182,11 +182,14 @@ int Cvar_Flags(const char *var_name) Cvar_CommandCompletion ============ */ -void Cvar_CommandCompletion( void(*callback)(const char *s) ) { +void Cvar_CommandCompletion(void (*callback)(const char *s)) +{ cvar_t *cvar; - for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) { - callback( cvar->name ); + for(cvar = cvar_vars; cvar; cvar = cvar->next) + { + if(cvar->name) + callback(cvar->name); } } @@ -305,6 +308,7 @@ The flags will be or'ed in if the variable exists. cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { cvar_t *var; long hash; + int index; if ( !var_name || ! var_value ) { Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" ); @@ -323,13 +327,15 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { #endif var = Cvar_FindVar (var_name); - if ( var ) { - var_value = Cvar_Validate( var, var_value, qfalse ); + + if(var) + { + var_value = Cvar_Validate(var, var_value, qfalse); // if the C code is now specifying a variable that the user already // set a value for, take the new value as the reset value - if ( ( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED ) - && var_value[0] ) { + if(var->flags & CVAR_USER_CREATED) + { var->flags &= ~CVAR_USER_CREATED; Z_Free( var->resetString ); var->resetString = CopyString( var_value ); @@ -344,13 +350,22 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { var->latchedString = CopyString(var_value); } - - // ZOID--needs to be set so that cvars the game sets as - // SERVERINFO get sent to clients - cvar_modifiedFlags |= flags; } - + + // Make sure the game code cannot mark engine-added variables as gamecode vars + if(var->flags & CVAR_VM_CREATED) + { + if(!(flags & CVAR_VM_CREATED)) + var->flags &= ~CVAR_VM_CREATED; + } + else + { + if(flags & CVAR_VM_CREATED) + flags &= ~CVAR_VM_CREATED; + } + var->flags |= flags; + // only allow one non-empty reset string without a warning if ( !var->resetString[0] ) { // we don't have a reset string yet @@ -368,6 +383,10 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { var->latchedString = NULL; // otherwise cvar_set2 would free it Cvar_Set2( var_name, s, qtrue ); Z_Free( s ); + + // ZOID--needs to be set so that cvars the game sets as + // SERVERINFO get sent to clients + cvar_modifiedFlags |= flags; } return var; @@ -376,11 +395,27 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { // // allocate a new cvar // - if ( cvar_numIndexes >= MAX_CVARS ) { - Com_Error( ERR_FATAL, "MAX_CVARS" ); + + // find a free cvar + for(index = 0; index < MAX_CVARS; index++) + { + if(!cvar_indexes[index].name) + break; + } + + if(index >= MAX_CVARS) + { + if(!com_errorEntered) + Com_Error(ERR_FATAL, "Error: Too many cvars, cannot create a new one!"); + + return NULL; } - var = &cvar_indexes[cvar_numIndexes]; - cvar_numIndexes++; + + var = &cvar_indexes[index]; + + if(index >= cvar_numIndexes) + cvar_numIndexes = index + 1; + var->name = CopyString (var_name); var->string = CopyString (var_value); var->modified = qtrue; @@ -392,6 +427,10 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { // link the variable in var->next = cvar_vars; + if(cvar_vars) + cvar_vars->prev = var; + + var->prev = NULL; cvar_vars = var; var->flags = flags; @@ -399,7 +438,13 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { cvar_modifiedFlags |= var->flags; hash = generateHashValue(var_name); + var->hashIndex = hash; + var->hashNext = hashTable[hash]; + if(hashTable[hash]) + hashTable[hash]->hashPrev = var; + + var->hashPrev = NULL; hashTable[hash] = var; return var; @@ -471,15 +516,23 @@ cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) { value = var->resetString; } - value = Cvar_Validate( var, value, qtrue ); + value = Cvar_Validate(var, value, qtrue); - if((var->flags & CVAR_LATCH) && var->latchedString) { - if(!strcmp(value,var->latchedString)) + if((var->flags & CVAR_LATCH) && var->latchedString) + { + if(!strcmp(value, var->string)) + { + Z_Free(var->latchedString); + var->latchedString = NULL; + return var; + } + + if(!strcmp(value, var->latchedString)) return var; } - else if (!strcmp(value,var->string)) { + else if(!strcmp(value, var->string)) return var; - } + // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo) cvar_modifiedFlags |= var->flags; @@ -610,12 +663,15 @@ Cvar_SetCheatState Any testing variables will be reset to the safe values ============ */ -void Cvar_SetCheatState( void ) { +void Cvar_SetCheatState(void) +{ cvar_t *var; // set all default vars to the safe value - for ( var = cvar_vars ; var ; var = var->next ) { - if ( var->flags & CVAR_CHEAT ) { + 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) @@ -623,9 +679,8 @@ void Cvar_SetCheatState( void ) { Z_Free(var->latchedString); var->latchedString = NULL; } - if (strcmp(var->resetString,var->string)) { - Cvar_Set( var->name, var->resetString ); - } + if (strcmp(var->resetString,var->string)) + Cvar_Set(var->name, var->resetString); } } } @@ -803,11 +858,16 @@ Appends lines containing "set variable value" for all variables with the archive flag set to qtrue. ============ */ -void Cvar_WriteVariables( fileHandle_t f ) { +void Cvar_WriteVariables(fileHandle_t f) +{ cvar_t *var; char buffer[1024]; - for (var = cvar_vars ; var ; var = var->next) { + for (var = cvar_vars; var; var = var->next) + { + if(!var->name) + continue; + if( var->flags & CVAR_ARCHIVE ) { // write the latched value, even if it hasn't taken effect yet if ( var->latchedString ) { @@ -849,7 +909,8 @@ void Cvar_List_f( void ) { i = 0; for (var = cvar_vars ; var ; var = var->next, i++) { - if (match && !Com_Filter(match, var->name, qfalse)) continue; + if(!var->name || (match && !Com_Filter(match, var->name, qfalse))) + continue; if (var->flags & CVAR_SERVERINFO) { Com_Printf("S"); @@ -906,74 +967,141 @@ void Cvar_List_f( void ) { /* ============ -Cvar_Restart_f +Cvar_Unset -Resets all cvars to their hardcoded values +Unsets a cvar ============ */ -void Cvar_Restart_f( void ) { - cvar_t *var; - cvar_t **prev; - prev = &cvar_vars; - while ( 1 ) { - var = *prev; - if ( !var ) { - break; - } +cvar_t *Cvar_Unset(cvar_t *cv) +{ + cvar_t *next = cv->next; + + if(cv->name) + Z_Free(cv->name); + if(cv->string) + Z_Free(cv->string); + if(cv->latchedString) + Z_Free(cv->latchedString); + if(cv->resetString) + Z_Free(cv->resetString); + + if(cv->prev) + cv->prev->next = cv->next; + else + cvar_vars = cv->next; + if(cv->next) + cv->next->prev = cv->prev; - // don't mess with rom values, or some inter-module - // communication will get broken (com_cl_running, etc) - if ( var->flags & ( CVAR_ROM | CVAR_INIT | CVAR_NORESTART ) ) { - prev = &var->next; - continue; - } + if(cv->hashPrev) + cv->hashPrev->hashNext = cv->hashNext; + else + hashTable[cv->hashIndex] = cv->hashNext; + if(cv->hashNext) + cv->hashNext->hashPrev = cv->hashPrev; - // throw out any variables the user created - if ( var->flags & CVAR_USER_CREATED ) { - *prev = var->next; - if ( var->name ) { - Z_Free( var->name ); - } - if ( var->string ) { - Z_Free( var->string ); - } - if ( var->latchedString ) { - Z_Free( var->latchedString ); - } - if ( var->resetString ) { - Z_Free( var->resetString ); - } - // clear the var completely, since we - // can't remove the index from the list - Com_Memset( var, 0, sizeof( var ) ); - continue; - } + Com_Memset(cv, '\0', sizeof(*cv)); + + return next; +} - Cvar_Set( var->name, var->resetString ); +/* +============ +Cvar_Unset_f + +Unsets a userdefined cvar +============ +*/ - prev = &var->next; +void Cvar_Unset_f(void) +{ + cvar_t *cv; + + if(Cmd_Argc() != 2) + { + Com_Printf("Usage: %s <varname>\n", Cmd_Argv(0)); + return; } + + cv = Cvar_FindVar(Cmd_Argv(1)); + + if(!cv) + return; + + if(cv->flags & CVAR_USER_CREATED) + Cvar_Unset(cv); + else + Com_Printf("Error: %s: Variable %s is not user created.\n", Cmd_Argv(0), cv->name); } /* +============ +Cvar_Restart + +Resets all cvars to their hardcoded values and removes userdefined variables +and variables added via the VMs if requested. +============ +*/ + +void Cvar_Restart(qboolean unsetVM) +{ + cvar_t *curvar; + + curvar = cvar_vars; + + while(curvar) + { + if((curvar->flags & CVAR_USER_CREATED) || + (unsetVM && (curvar->flags & CVAR_VM_CREATED))) + { + // throw out any variables the user/vm created + curvar = Cvar_Unset(curvar); + continue; + } + + if(!(curvar->flags & (CVAR_ROM | CVAR_INIT | CVAR_NORESTART))) + { + // Just reset the rest to their default values. + Cvar_Set2(curvar->name, curvar->resetString, qfalse); + } + + curvar = curvar->next; + } +} + + +/* +============ +Cvar_Restart_f + +Resets all cvars to their hardcoded values +============ +*/ +void Cvar_Restart_f(void) +{ + Cvar_Restart(qfalse); +} + +/* ===================== Cvar_InfoString ===================== */ -char *Cvar_InfoString( int bit ) { +char *Cvar_InfoString(int bit) +{ static char info[MAX_INFO_STRING]; cvar_t *var; info[0] = 0; - for (var = cvar_vars ; var ; var = var->next) { - if (var->flags & bit) { + for(var = cvar_vars; var; var = var->next) + { + if(var->name && (var->flags & bit)) Info_SetValueForKey (info, var->name, var->string); - } } + return info; } @@ -984,16 +1112,17 @@ Cvar_InfoString_Big handles large info strings ( CS_SYSTEMINFO ) ===================== */ -char *Cvar_InfoString_Big( int bit ) { +char *Cvar_InfoString_Big(int bit) +{ static char info[BIG_INFO_STRING]; cvar_t *var; info[0] = 0; - for (var = cvar_vars ; var ; var = var->next) { - if (var->flags & bit) { + for (var = cvar_vars; var; var = var->next) + { + if(var->name && (var->flags & bit)) Info_SetValueForKey_Big (info, var->name, var->string); - } } return info; } @@ -1032,13 +1161,15 @@ Cvar_Register basically a slightly modified Cvar_Get for the interpreted modules ===================== */ -void Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) { +void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags) +{ cvar_t *cv; - cv = Cvar_Get( varName, defaultValue, flags ); - if ( !vmCvar ) { + cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED); + + if (!vmCvar) return; - } + vmCvar->handle = cv - cvar_indexes; vmCvar->modificationCount = -1; Cvar_Update( vmCvar ); @@ -1103,7 +1234,11 @@ Cvar_Init Reads in all archived cvars ============ */ -void Cvar_Init (void) { +void Cvar_Init (void) +{ + Com_Memset(cvar_indexes, '\0', sizeof(cvar_indexes)); + Com_Memset(hashTable, '\0', sizeof(hashTable)); + cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO ); Cmd_AddCommand ("print", Cvar_Print_f); @@ -1119,6 +1254,9 @@ void Cvar_Init (void) { Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName ); Cmd_AddCommand ("reset", Cvar_Reset_f); Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName ); + Cmd_AddCommand ("unset", Cvar_Unset_f); + Cmd_SetCommandCompletionFunc("unset", Cvar_CompleteCvarName); + Cmd_AddCommand ("cvarlist", Cvar_List_f); Cmd_AddCommand ("cvar_restart", Cvar_Restart_f); } diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 87301441..bb1f3f15 100644 --- a/src/qcommon/files.c +++ b/src/qcommon/files.c @@ -249,7 +249,7 @@ static searchpath_t *fs_searchpaths; static int fs_readCount; // total bytes read static int fs_loadCount; // total files read static int fs_loadStack; // total files in memory -static int fs_packFiles; // total number of files in packs +static int fs_packFiles = 0; // total number of files in packs static int fs_checksumFeed; @@ -281,7 +281,7 @@ static fileHandleData_t fsh[MAX_FILE_HANDLES]; static qboolean fs_reordered; // never load anything from pk3 files that are not present at the server when pure -static int fs_numServerPaks; +static int fs_numServerPaks = 0; static int fs_serverPaks[MAX_SEARCH_PATHS]; // checksums static char *fs_serverPakNames[MAX_SEARCH_PATHS]; // pk3 names @@ -438,10 +438,18 @@ Fix things up differently for win/unix/mac */ static void FS_ReplaceSeparators( char *path ) { char *s; + qboolean lastCharWasSep = qfalse; for ( s = path ; *s ; s++ ) { if ( *s == '/' || *s == '\\' ) { - *s = PATH_SEP; + if ( !lastCharWasSep ) { + *s = PATH_SEP; + lastCharWasSep = qtrue; + } else { + memmove (s, s + 1, strlen (s)); + } + } else { + lastCharWasSep = qfalse; } } } @@ -465,7 +473,7 @@ char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ) { } Com_sprintf( temp, sizeof(temp), "/%s/%s", game, qpath ); - FS_ReplaceSeparators( temp ); + FS_ReplaceSeparators( temp ); Com_sprintf( ospath[toggle], sizeof( ospath[0] ), "%s%s", base, temp ); return ospath[toggle]; @@ -481,6 +489,7 @@ Creates any directories needed to store the given filename */ qboolean FS_CreatePath (char *OSPath) { char *ofs; + char path[MAX_OSPATH]; // make absolutely sure that it can't back up the path // FIXME: is c: allowed??? @@ -489,14 +498,25 @@ qboolean FS_CreatePath (char *OSPath) { return qtrue; } - for (ofs = OSPath+1 ; *ofs ; ofs++) { - if (*ofs == PATH_SEP) { + Q_strncpyz( path, OSPath, sizeof( path ) ); + FS_ReplaceSeparators( path ); + + // Skip creation of the root directory as it will always be there + ofs = strchr( path, PATH_SEP ); + ofs++; + + for (; ofs != NULL && *ofs ; ofs++) { + if (*ofs == PATH_SEP) { // create the directory *ofs = 0; - Sys_Mkdir (OSPath); + if (!Sys_Mkdir (path)) { + Com_Error( ERR_FATAL, "FS_CreatePath: failed to create path \"%s\"\n", + path ); + } *ofs = PATH_SEP; } } + return qfalse; } @@ -2839,6 +2859,8 @@ static void FS_Startup( const char *gameName ) Com_Printf( "----- FS_Startup -----\n" ); + fs_packFiles = 0; + fs_debug = Cvar_Get( "fs_debug", "0", 0 ); fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT ); fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT ); @@ -2864,11 +2886,12 @@ static void FS_Startup( const char *gameName ) // NOTE: same filtering below for mods and basegame if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { + FS_CreatePath ( fs_homepath->string ); FS_AddGameDirectory ( fs_homepath->string, gameName ); } // check for additional base game so mods can be based upon other mods - if ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) { + if ( fs_basegame->string[0] && Q_stricmp( fs_basegame->string, gameName ) ) { if (fs_basepath->string[0]) { FS_AddGameDirectory(fs_basepath->string, fs_basegame->string); } @@ -2878,7 +2901,7 @@ static void FS_Startup( const char *gameName ) } // check for additional game folder for mods - if ( fs_gamedirvar->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_gamedirvar->string, gameName ) ) { + if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, gameName ) ) { if (fs_basepath->string[0]) { FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string); } @@ -3348,11 +3371,20 @@ FS_ConditionalRestart restart if necessary ================= */ -qboolean FS_ConditionalRestart( int checksumFeed ) { - if( fs_gamedirvar->modified || checksumFeed != fs_checksumFeed ) { - FS_Restart( checksumFeed ); +qboolean FS_ConditionalRestart(int checksumFeed) +{ + if(fs_gamedirvar->modified) + { + Com_GameRestart(checksumFeed, qfalse); return qtrue; } + + else if(checksumFeed != fs_checksumFeed) + { + FS_Restart(checksumFeed); + return qtrue; + } + return qfalse; } diff --git a/src/qcommon/net_ip.c b/src/qcommon/net_ip.c index 9ad4a821..db9f2924 100644 --- a/src/qcommon/net_ip.c +++ b/src/qcommon/net_ip.c @@ -995,7 +995,7 @@ void NET_SetMulticast6(void) if(*net_mcast6iface->string) { #ifdef _WIN32 - curgroup.ipv6mr_interface = atoi(net_mcast6iface->string); + curgroup.ipv6mr_interface = net_mcast6iface->integer; #else curgroup.ipv6mr_interface = if_nametoindex(net_mcast6iface->string); #endif @@ -1470,7 +1470,11 @@ static qboolean NET_GetCvars( void ) { modified += net_mcast6addr->modified; net_mcast6addr->modified = qfalse; +#ifdef _WIN32 net_mcast6iface = Cvar_Get( "net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE ); +#else + net_mcast6iface = Cvar_Get( "net_mcast6iface", "", CVAR_LATCH | CVAR_ARCHIVE ); +#endif modified += net_mcast6iface->modified; net_mcast6iface->modified = qfalse; diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 29cc4b9b..186bb461 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -863,30 +863,33 @@ default values. ========================================================== */ -#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc - // used for system variables, not for player - // specific configurations -#define CVAR_USERINFO 2 // sent to server on connect or change -#define CVAR_SERVERINFO 4 // sent in response to front end requests -#define CVAR_SYSTEMINFO 8 // these cvars will be duplicated on all clients -#define CVAR_INIT 16 // don't allow change from console at all, - // but can be set from the command line -#define CVAR_LATCH 32 // will only change when C code next does - // a Cvar_Get(), so it can't be changed - // without proper initialization. modified - // will be set, even though the value hasn't - // changed yet -#define CVAR_ROM 64 // display only, cannot be set by user at all -#define CVAR_USER_CREATED 128 // created by a set command -#define CVAR_TEMP 256 // can be set even when cheats are disabled, but is not archived -#define CVAR_CHEAT 512 // can not be changed if cheats are disabled -#define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued - -#define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to. +#define CVAR_ARCHIVE 0x0001 // set to cause it to be saved to vars.rc + // used for system variables, not for player + // specific configurations +#define CVAR_USERINFO 0x0002 // sent to server on connect or change +#define CVAR_SERVERINFO 0x0004 // sent in response to front end requests +#define CVAR_SYSTEMINFO 0x0008 // these cvars will be duplicated on all clients +#define CVAR_INIT 0x0010 // don't allow change from console at all, + // but can be set from the command line +#define CVAR_LATCH 0x0020 // will only change when C code next does + // a Cvar_Get(), so it can't be changed + // without proper initialization. modified + // will be set, even though the value hasn't + // changed yet +#define CVAR_ROM 0x0040 // display only, cannot be set by user at all +#define CVAR_USER_CREATED 0x0080 // created by a set command +#define CVAR_TEMP 0x0100 // can be set even when cheats are disabled, but is not archived +#define CVAR_CHEAT 0x0200 // can not be changed if cheats are disabled +#define CVAR_NORESTART 0x0400 // do not clear when a cvar_restart is issued + +#define CVAR_SERVER_CREATED 0x0800 // cvar was created by a server the client connected to. +#define CVAR_VM_CREATED 0x1000 // cvar was created exclusively in one of the VMs. #define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist. // nothing outside the Cvar_*() functions should modify these fields! -typedef struct cvar_s { +typedef struct cvar_s cvar_t; + +struct cvar_s { char *name; char *string; char *resetString; // cvar_restart will reset to this value @@ -900,9 +903,13 @@ typedef struct cvar_s { qboolean integral; float min; float max; - struct cvar_s *next; - struct cvar_s *hashNext; -} cvar_t; + + cvar_t *next; + cvar_t *prev; + cvar_t *hashNext; + cvar_t *hashPrev; + int hashIndex; +}; #define MAX_CVAR_VALUE_STRING 256 diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 1f9e744d..690e89c6 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -534,6 +534,7 @@ char *Cvar_InfoString_Big( int bit ); void Cvar_InfoStringBuffer( int bit, char *buff, int buffsize ); void Cvar_CheckRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral ); +void Cvar_Restart(qboolean unsetVM); void Cvar_Restart_f( void ); void Cvar_CompleteCvarName( char *args, int argNum ); @@ -784,6 +785,7 @@ void QDECL Com_Printf( const char *fmt, ... ) __attribute__ ((format (printf, void QDECL Com_DPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2))); void QDECL Com_Error( int code, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3))); void Com_Quit_f( void ); +void Com_GameRestart(int checksumFeed, qboolean clientRestart); int Com_Milliseconds( void ); // will be journaled properly unsigned Com_BlockChecksum( const void *buffer, int length ); @@ -961,6 +963,9 @@ void CL_FlushMemory( void ); void CL_StartHunkUsers( qboolean rendererOnly ); // start all the client stuff using the hunk +void CL_Snd_Restart(void); +// Restart sound subsystem + void Key_KeynameCompletion( void(*callback)(const char *s) ); // for keyname autocompletion @@ -1057,7 +1062,7 @@ qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ); qboolean Sys_IsLANAddress (netadr_t adr); void Sys_ShowIP(void); -void Sys_Mkdir( const char *path ); +qboolean Sys_Mkdir( const char *path ); char *Sys_Cwd( void ); void Sys_SetDefaultInstallPath(const char *path); char *Sys_DefaultInstallPath(void); @@ -1078,6 +1083,8 @@ void Sys_Sleep(int msec); qboolean Sys_LowPhysicalMemory( void ); +void Sys_SetEnv(const char *name, const char *value); + /* This is based on the Adaptive Huffman algorithm described in Sayood's Data * Compression book. The ranks are not actually stored, but implicitly defined * by the location of a node within a doubly-linked list */ diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c index 876d36d5..5956c89a 100644 --- a/src/qcommon/vm.c +++ b/src/qcommon/vm.c @@ -246,7 +246,7 @@ void VM_LoadSymbols( vm_t *vm ) { return; } - numInstructions = vm->instructionPointersLength >> 2; + numInstructions = vm->instructionCount; // parse the symbols text_p = mapfile.c; @@ -358,8 +358,6 @@ intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) { } -#define STACK_SIZE 0x20000 - /* ================= VM_LoadQVM @@ -431,7 +429,7 @@ 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 + STACK_SIZE; + header.h->bssLength; for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) { } dataLength = 1 << i; @@ -577,8 +575,8 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), } // allocate space for the jump targets, which will be filled in by the compile/prep functions - vm->instructionPointersLength = header->instructionCount * 4; - vm->instructionPointers = Hunk_Alloc( vm->instructionPointersLength, h_high ); + vm->instructionCount = header->instructionCount; + vm->instructionPointers = Hunk_Alloc( vm->instructionCount*4, h_high ); // copy or compile the instructions vm->codeLength = header->codeLength; @@ -610,7 +608,7 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), // the stack is implicitly at the end of the image vm->programStack = vm->dataMask + 1; - vm->stackBottom = vm->programStack - STACK_SIZE; + vm->stackBottom = vm->programStack - PROGRAM_STACK_SIZE; Com_Printf("%s loaded in %d bytes on the hunk\n", module, remaining - Hunk_MemoryRemaining()); @@ -734,8 +732,6 @@ an OP_ENTER instruction, which will subtract space for locals from sp ============== */ -#define MAX_STACK 256 -#define STACK_MASK (MAX_STACK-1) intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) { vm_t *oldVM; @@ -896,7 +892,7 @@ void VM_VmInfo_f( void ) { Com_Printf( "interpreted\n" ); } Com_Printf( " code length : %7i\n", vm->codeLength ); - Com_Printf( " table length: %7i\n", vm->instructionPointersLength ); + Com_Printf( " table length: %7i\n", vm->instructionCount*4 ); Com_Printf( " data length : %7i\n", vm->dataMask + 1 ); } } diff --git a/src/qcommon/vm_interpreted.c b/src/qcommon/vm_interpreted.c index cb6ae2f2..5f755623 100644 --- a/src/qcommon/vm_interpreted.c +++ b/src/qcommon/vm_interpreted.c @@ -312,13 +312,11 @@ an OP_ENTER instruction, which will subtract space for locals from sp ============== */ -#define MAX_STACK 256 -#define STACK_MASK (MAX_STACK-1) #define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack ) int VM_CallInterpreted( vm_t *vm, int *args ) { - int stack[MAX_STACK]; + int stack[OPSTACK_SIZE]; int *opStack; int programCounter; int programStack; @@ -393,7 +391,7 @@ nextInstruction2: if ( opStack < stack ) { Com_Error( ERR_DROP, "VM opStack underflow" ); } - if ( opStack >= stack+MAX_STACK ) { + if ( opStack >= stack+OPSTACK_SIZE ) { Com_Error( ERR_DROP, "VM opStack overflow" ); } @@ -441,10 +439,10 @@ nextInstruction2: Com_Error( ERR_DROP, "OP_LOAD4 misaligned" ); } #endif - r0 = *opStack = *(int *)&image[ r0&dataMask ]; + r0 = *opStack = *(int *)&image[ r0&dataMask&~3 ]; goto nextInstruction2; case OP_LOAD2: - r0 = *opStack = *(unsigned short *)&image[ r0&dataMask ]; + r0 = *opStack = *(unsigned short *)&image[ r0&dataMask&~1 ]; goto nextInstruction2; case OP_LOAD1: r0 = *opStack = image[ r0&dataMask ]; @@ -465,7 +463,7 @@ nextInstruction2: case OP_ARG: // single byte offset from programStack - *(int *)&image[ codeImage[programCounter] + programStack ] = r0; + *(int *)&image[ (codeImage[programCounter] + programStack)&dataMask&~3 ] = r0; opStack--; programCounter += 1; goto nextInstruction; @@ -549,7 +547,7 @@ nextInstruction2: Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) ); } #endif - } else if ( (unsigned)programCounter >= vm->codeLength ) { + } else if ( (unsigned)programCounter >= vm->instructionCount ) { Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" ); } else { programCounter = vm->instructionPointers[ programCounter ]; @@ -618,8 +616,11 @@ nextInstruction2: */ case OP_JUMP: - programCounter = r0; - programCounter = vm->instructionPointers[ programCounter ]; + if ( (unsigned)r0 >= vm->instructionCount ) + Com_Error( ERR_DROP, "VM program counter out of range in OP_JUMP" ); + + programCounter = vm->instructionPointers[ r0 ]; + opStack--; goto nextInstruction; diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h index e1545d37..75ffee55 100644 --- a/src/qcommon/vm_local.h +++ b/src/qcommon/vm_local.h @@ -23,6 +23,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" +#define OPSTACK_SIZE 256 +#define OPSTACK_MASK (OPSTACK_SIZE-1) + +// don't change +// Hardcoded in q3asm an reserved at end of bss +#define PROGRAM_STACK_SIZE 0x10000 +#define PROGRAM_STACK_MASK (PROGRAM_STACK_SIZE-1) + typedef enum { OP_UNDEF, @@ -147,7 +155,7 @@ struct vm_s { int codeLength; int *instructionPointers; - int instructionPointersLength; + int instructionCount; byte *dataBase; int dataMask; @@ -181,4 +189,3 @@ vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ); int VM_SymbolToValue( vm_t *vm, const char *symbol ); const char *VM_ValueToSymbol( vm_t *vm, int value ); void VM_LogSyscalls( int *args ); - diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c index 02e7bf9c..3f950b2a 100644 --- a/src/qcommon/vm_x86_64.c +++ b/src/qcommon/vm_x86_64.c @@ -229,12 +229,47 @@ void emit(const char* fmt, ...) assemble_line(line, strlen(line)); } +#define CHECK_INSTR_REG(reg) \ + emit("cmpl $%u, %%"#reg, header->instructionCount); \ + emit("jb jmp_ok_i_%08x", instruction); \ + emit("movq $%lu, %%rax", (unsigned long)jmpviolation); \ + emit("callq *%%rax"); \ + emit("jmp_ok_i_%08x:", instruction); + +#define PREPARE_JMP(reg) \ + CHECK_INSTR_REG(reg) \ + emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); \ + emit("movl (%%rbx, %%rax, 4), %%eax"); \ + emit("addq %%r10, %%rax"); + +#define CHECK_INSTR(nr) \ + do { if(nr < 0 || nr >= header->instructionCount) { \ + Com_Error( ERR_DROP, \ + "%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \ + } } while(0) + #define JMPIARG \ + CHECK_INSTR(iarg); \ emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ emit("jmpq *%%rax"); +#define CONST_OPTIMIZE +#ifdef CONST_OPTIMIZE +#define MAYBE_EMIT_CONST() \ + if (got_const) \ + { \ + got_const = 0; \ + vm->instructionPointers[instruction-1] = assembler_get_code_size(); \ + emit("addq $4, %%rsi"); \ + emit("movl $%d, 0(%%rsi)", const_value); \ + } +#else +#define MAYBE_EMIT_CONST() +#endif + // integer compare and jump #define IJ(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $8, %%rsi"); \ emit("movl 4(%%rsi), %%eax"); \ emit("cmpl 8(%%rsi), %%eax"); \ @@ -244,6 +279,7 @@ void emit(const char* fmt, ...) #ifdef USE_X87 #define FJ(bits, op) \ + MAYBE_EMIT_CONST(); \ emit("subq $8, %%rsi");\ emit("flds 4(%%rsi)");\ emit("fcomps 8(%%rsi)");\ @@ -256,6 +292,7 @@ void emit(const char* fmt, ...) #else #define FJ(x, y) #define XJ(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $8, %%rsi");\ emit("movss 4(%%rsi), %%xmm0");\ emit("ucomiss 8(%%rsi), %%xmm0");\ @@ -266,12 +303,14 @@ void emit(const char* fmt, ...) #endif #define SIMPLE(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("movl 4(%%rsi), %%eax"); \ emit(op " %%eax, 0(%%rsi)"); #ifdef USE_X87 #define FSIMPLE(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("flds 0(%%rsi)"); \ emit(op " 4(%%rsi)"); \ @@ -280,6 +319,7 @@ void emit(const char* fmt, ...) #else #define FSIMPLE(op) #define XSIMPLE(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("movss 0(%%rsi), %%xmm0"); \ emit(op " 4(%%rsi), %%xmm0"); \ @@ -287,26 +327,28 @@ void emit(const char* fmt, ...) #endif #define SHIFT(op) \ + MAYBE_EMIT_CONST(); \ emit("subq $4, %%rsi"); \ emit("movl 4(%%rsi), %%ecx"); \ emit("movl 0(%%rsi), %%eax"); \ emit(op " %%cl, %%eax"); \ emit("movl %%eax, 0(%%rsi)"); -#if 1 -#define RANGECHECK(reg) \ - emit("andl $0x%x, %%" #reg, vm->dataMask); -#elif 0 -#define RANGECHECK(reg) \ - emit("pushl %%" #reg); \ - emit("andl $0x%x, %%" #reg, ~vm->dataMask); \ - emit("jz rangecheck_ok_i_%08x", instruction); \ - emit("int3"); \ - emit("rangecheck_ok_i_%08x:", instruction); \ - emit("popl %%" #reg); \ - emit("andl $0x%x, %%" #reg, vm->dataMask); +#ifdef DEBUG_VM +#define RANGECHECK(reg, bytes) \ + emit("movl %%" #reg ", %%ecx"); \ + emit("andl $0x%x, %%ecx", vm->dataMask &~(bytes-1)); \ + emit("cmpl %%" #reg ", %%ecx"); \ + emit("jz rc_ok_i_%08x", instruction); \ + emit("movq $%lu, %%rax", (unsigned long)memviolation); \ + emit("callq *%%rax"); \ + emit("rc_ok_i_%08x:", instruction); +#elif 1 +// check is too expensive, so just confine memory access +#define RANGECHECK(reg, bytes) \ + emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1)); #else -#define RANGECHECK(reg) +#define RANGECHECK(reg, bytes) #endif #ifdef DEBUG_VM @@ -337,6 +379,26 @@ static void block_copy_vm(unsigned dest, unsigned src, unsigned count) memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count); } +static void eop(void) +{ + Com_Error(ERR_DROP, "end of program reached without return!\n"); + exit(1); +} + +static void jmpviolation(void) +{ + Com_Error(ERR_DROP, "program tried to execute code outside VM\n"); + exit(1); +} + +#ifdef DEBUG_VM +static void memviolation(void) +{ + Com_Error(ERR_DROP, "program tried to access memory outside VM\n"); + exit(1); +} +#endif + /* ================= VM_Compile @@ -358,6 +420,9 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { int pass; size_t compiledOfs = 0; + // const optimization + unsigned got_const = 0, const_value = 0; + gettimeofday(&tvstart, NULL); for (pass = 0; pass < 2; ++pass) { @@ -394,7 +459,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { vm->instructionPointers[instruction] = assembler_get_code_size(); /* store current instruction number in r15 for debugging */ -#if DEBUG_VM +#if DEBUG_VM0 emit("nop"); emit("movq $%d, %%r15", instruction); emit("nop"); @@ -428,31 +493,52 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { NOTIMPL(op); break; case OP_IGNORE: + MAYBE_EMIT_CONST(); emit("nop"); break; case OP_BREAK: + MAYBE_EMIT_CONST(); emit("int3"); break; case OP_ENTER: + MAYBE_EMIT_CONST(); emit("subl $%d, %%edi", iarg); - RANGECHECK(edi); break; case OP_LEAVE: + MAYBE_EMIT_CONST(); emit("addl $%d, %%edi", iarg); // get rid of stack frame emit("ret"); break; case OP_CALL: - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); + RANGECHECK(edi, 4); emit("movl $%d, 0(%%r8, %%rdi, 1)", instruction+1); // save next instruction - emit("orl %%eax, %%eax"); - emit("jl callSyscall%d", instruction); - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); - emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address - emit("addq %%r10, %%rax"); - emit("callq *%%rax"); - emit("jmp i_%08x", instruction+1); - emit("callSyscall%d:", instruction); + if(got_const) + { + if ((int)const_value < 0) + goto emit_do_syscall; + + CHECK_INSTR(const_value); + emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[const_value]); + emit("callq *%%rax"); + got_const = 0; + break; + } + else + { + MAYBE_EMIT_CONST(); + emit("movl 0(%%rsi), %%eax"); // get instr from stack + emit("subq $4, %%rsi"); + + emit("orl %%eax, %%eax"); + emit("jl callSyscall%d", instruction); + + PREPARE_JMP(eax); + emit("callq *%%rax"); + + emit("jmp i_%08x", instruction+1); + emit("callSyscall%d:", instruction); + } +emit_do_syscall: // emit("fnsave 4(%%rsi)"); emit("push %%rsi"); emit("push %%rdi"); @@ -464,10 +550,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("andq $127, %%rbx"); // | emit("subq %%rbx, %%rsp"); // <-+ emit("push %%rbx"); - emit("negl %%eax"); // convert to actual number - emit("decl %%eax"); - // first argument already in rdi - emit("movq %%rax, %%rsi"); // second argument in rsi + if(got_const) { + got_const = 0; + emit("movq $%u, %%rsi", -1-const_value); // second argument in rsi + } else { + emit("negl %%eax"); // convert to actual number + emit("decl %%eax"); + // first argument already in rdi + emit("movq %%rax, %%rsi"); // second argument in rsi + } emit("movq $%lu, %%rax", (unsigned long)callAsmCall); emit("callq *%%rax"); emit("pop %%rbx"); @@ -483,28 +574,42 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { neednilabel = 1; break; case OP_PUSH: + MAYBE_EMIT_CONST(); emit("addq $4, %%rsi"); break; case OP_POP: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); break; case OP_CONST: + MAYBE_EMIT_CONST(); +#ifdef CONST_OPTIMIZE + got_const = 1; + const_value = iarg; +#else emit("addq $4, %%rsi"); emit("movl $%d, 0(%%rsi)", iarg); +#endif break; case OP_LOCAL: + MAYBE_EMIT_CONST(); emit("movl %%edi, %%ebx"); emit("addl $%d,%%ebx", iarg); emit("addq $4, %%rsi"); emit("movl %%ebx, 0(%%rsi)"); break; case OP_JUMP: - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); - emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address - emit("addq %%r10, %%rax"); - emit("jmp *%%rax"); + if(got_const) { + iarg = const_value; + got_const = 0; + JMPIARG; + } else { + emit("movl 0(%%rsi), %%eax"); // get instr from stack + emit("subq $4, %%rsi"); + + PREPARE_JMP(eax); + emit("jmp *%%rax"); + } break; case OP_EQ: IJ("jne"); @@ -543,6 +648,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { case OP_NEF: FJ(0x40, "jnz"); #ifndef USE_X87 + MAYBE_EMIT_CONST(); emit("subq $8, %%rsi"); emit("movss 4(%%rsi), %%xmm0"); emit("ucomiss 8(%%rsi), %%xmm0"); @@ -570,56 +676,64 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { XJ("jb"); break; case OP_LOAD1: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack - RANGECHECK(eax); + RANGECHECK(eax, 1); emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax emit("andq $255, %%rax"); emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_LOAD2: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack - RANGECHECK(eax); + RANGECHECK(eax, 2); emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_LOAD4: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack - RANGECHECK(eax); // not a pointer!? + RANGECHECK(eax, 4); // not a pointer!? emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax emit("movl %%eax, 0(%%rsi)"); // store on stack break; case OP_STORE1: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack emit("andq $255, %%rax"); emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx); + RANGECHECK(ebx, 1); emit("movb %%al, 0(%%r8, %%rbx, 1)"); // store in memory emit("subq $8, %%rsi"); break; case OP_STORE2: + MAYBE_EMIT_CONST(); emit("movl 0(%%rsi), %%eax"); // get value from stack emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx); + RANGECHECK(ebx, 2); emit("movw %%ax, 0(%%r8, %%rbx, 1)"); // store in memory emit("subq $8, %%rsi"); break; case OP_STORE4: + MAYBE_EMIT_CONST(); emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx); + RANGECHECK(ebx, 4); emit("movl 0(%%rsi), %%ecx"); // get value from stack emit("movl %%ecx, 0(%%r8, %%rbx, 1)"); // store in memory emit("subq $8, %%rsi"); break; case OP_ARG: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 4(%%rsi), %%eax"); // get value from stack emit("movl $0x%hhx, %%ebx", barg); emit("addl %%edi, %%ebx"); - RANGECHECK(ebx); + RANGECHECK(ebx, 4); emit("movl %%eax, 0(%%r8,%%rbx, 1)"); // store in args space break; case OP_BLOCK_COPY: + MAYBE_EMIT_CONST(); emit("subq $8, %%rsi"); emit("push %%rsi"); emit("push %%rdi"); @@ -639,6 +753,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { break; case OP_SEX8: + MAYBE_EMIT_CONST(); emit("movw 0(%%rsi), %%ax"); emit("andq $255, %%rax"); emit("cbw"); @@ -646,11 +761,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); break; case OP_SEX16: + MAYBE_EMIT_CONST(); emit("movw 0(%%rsi), %%ax"); emit("cwde"); emit("movl %%eax, 0(%%rsi)"); break; case OP_NEGI: + MAYBE_EMIT_CONST(); emit("negl 0(%%rsi)"); break; case OP_ADD: @@ -660,6 +777,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { SIMPLE("subl"); break; case OP_DIVI: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("cdq"); @@ -667,6 +785,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); break; case OP_DIVU: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorq %%rdx, %%rdx"); @@ -674,6 +793,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%eax, 0(%%rsi)"); break; case OP_MODI: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorl %%edx, %%edx"); @@ -682,6 +802,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%edx, 0(%%rsi)"); break; case OP_MODU: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("xorl %%edx, %%edx"); @@ -689,12 +810,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { emit("movl %%edx, 0(%%rsi)"); break; case OP_MULI: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("imull 4(%%rsi)"); emit("movl %%eax, 0(%%rsi)"); break; case OP_MULU: + MAYBE_EMIT_CONST(); emit("subq $4, %%rsi"); emit("movl 0(%%rsi), %%eax"); emit("mull 4(%%rsi)"); @@ -710,6 +833,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { SIMPLE("xorl"); break; case OP_BCOM: + MAYBE_EMIT_CONST(); emit("notl 0(%%rsi)"); break; case OP_LSH: @@ -722,6 +846,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { SHIFT("shrl"); break; case OP_NEGF: + MAYBE_EMIT_CONST(); #ifdef USE_X87 emit("flds 0(%%rsi)"); emit("fchs"); @@ -748,6 +873,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { XSIMPLE("mulss"); break; case OP_CVIF: + MAYBE_EMIT_CONST(); #ifdef USE_X87 emit("filds 0(%%rsi)"); emit("fstps 0(%%rsi)"); @@ -758,6 +884,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { #endif break; case OP_CVFI: + MAYBE_EMIT_CONST(); #ifdef USE_X87 emit("flds 0(%%rsi)"); emit("fnstcw 4(%%rsi)"); @@ -775,8 +902,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { NOTIMPL(op); break; } + + } + if(got_const) { + Com_Error(ERR_DROP, "leftover const\n"); + } + + emit("movq $%lu, %%rax", (unsigned long)eop); + emit("callq *%%rax"); + } // pass loop assembler_init(0); @@ -789,6 +925,15 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) { #ifdef DEBUG_VM fflush(qdasmout); fclose(qdasmout); + +#if 0 + strcpy(fn_d,vm->name); + strcat(fn_d, ".bin"); + qdasmout = fopen(fn_d, "w"); + fwrite(vm->codeBase, compiledOfs, 1, qdasmout); + fflush(qdasmout); + fclose(qdasmout); +#endif #endif if(vm->compiled) diff --git a/src/qcommon/vm_x86_64_assembler.c b/src/qcommon/vm_x86_64_assembler.c index 5747626a..c36c7a66 100644 --- a/src/qcommon/vm_x86_64_assembler.c +++ b/src/qcommon/vm_x86_64_assembler.c @@ -68,10 +68,15 @@ static void _crap(const char* func, const char* fmt, ...) static void emit1(unsigned char v) { + int writecnt; + if(assembler_pass) { out[compiledOfs++] = v; - if(fout) fwrite(&v, 1, 1, fout); + + if(fout) + writecnt = fwrite(&v, 1, 1, fout); + debug("%02hhx ", v); } else @@ -811,24 +816,34 @@ static void emit_call(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) { u8 rex, modrm, sib; - if(arg1.type != T_REGISTER || arg2.type != T_NONE) + if((arg1.type != T_REGISTER && arg1.type != T_IMMEDIATE) || arg2.type != T_NONE) CRAP_INVALID_ARGS; - if(!arg1.absolute) - crap("call must be absolute"); + if(arg1.type == T_REGISTER) + { + if(!arg1.absolute) + crap("call must be absolute"); - if((arg1.v.reg & R_64) != R_64) - crap("register must be 64bit"); + if((arg1.v.reg & R_64) != R_64) + crap("register must be 64bit"); - arg1.v.reg ^= R_64; // no rex required for call + arg1.v.reg ^= R_64; // no rex required for call - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); + compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - modrm |= 0x2 << 3; + modrm |= 0x2 << 3; - if(rex) emit1(rex); - emit1(0xff); - emit1(modrm); + if(rex) emit1(rex); + emit1(0xff); + emit1(modrm); + } + else + { + if(!isu32(arg1.v.imm)) + crap("must be 32bit argument"); + emit1(0xe8); + emit4(arg1.v.imm); + } } @@ -875,7 +890,7 @@ static opparam_t params_or = { subcode: 1, rmcode: 0x09, }; static opparam_t params_and = { subcode: 4, rmcode: 0x21, }; static opparam_t params_sub = { subcode: 5, rmcode: 0x29, }; static opparam_t params_xor = { subcode: 6, rmcode: 0x31, }; -static opparam_t params_cmp = { subcode: 6, rmcode: 0x39, mrcode: 0x3b, }; +static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, }; static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, }; static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, }; static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, }; diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c index 6fb7fed3..b08cdbb8 100644 --- a/src/renderer/tr_init.c +++ b/src/renderer/tr_init.c @@ -131,6 +131,7 @@ cvar_t *r_subdivisions; cvar_t *r_lodCurveError; cvar_t *r_fullscreen; +cvar_t *r_noborder; cvar_t *r_width; cvar_t *r_height; @@ -921,6 +922,7 @@ void R_Register( void ) 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 ); + r_noborder = Cvar_Get("r_noborder", "0", CVAR_ARCHIVE); r_width = ri.Cvar_Get( "r_width", "640", CVAR_ARCHIVE | CVAR_LATCH ); r_height = ri.Cvar_Get( "r_height", "480", CVAR_ARCHIVE | CVAR_LATCH ); r_pixelAspect = ri.Cvar_Get( "r_pixelAspect", "1", CVAR_ARCHIVE | CVAR_LATCH ); diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h index 03908826..f0f3cada 100644 --- a/src/renderer/tr_local.h +++ b/src/renderer/tr_local.h @@ -1042,6 +1042,7 @@ extern cvar_t *r_height; extern cvar_t *r_pixelAspect; extern cvar_t *r_fullscreen; +extern cvar_t *r_noborder; extern cvar_t *r_gamma; extern cvar_t *r_displayRefresh; // optional display refresh option extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities diff --git a/src/sdl/sdl_glimp.c b/src/sdl/sdl_glimp.c index 58e9c7ed..8028eb59 100644 --- a/src/sdl/sdl_glimp.c +++ b/src/sdl/sdl_glimp.c @@ -73,6 +73,7 @@ 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_centerWindow; cvar_t *r_sdlDriver; void (APIENTRYP qglActiveTextureARB) (GLenum texture); @@ -133,9 +134,10 @@ static int GLimp_CompareModes( const void *a, const void *b ) else if( aspectDiffsDiff < -ASPECT_EPSILON ) return -1; else - return areaA - areaB; + return areaA - areaB; } + /* =============== GLimp_DetectAvailableModes @@ -193,7 +195,7 @@ static void GLimp_DetectAvailableModes(void) GLimp_SetMode =============== */ -static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) +static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen, qboolean noborder ) { const char* glstring; int sdlcolorbits; @@ -267,7 +269,12 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) glConfig.isFullscreen = qtrue; } else + { + if (noborder) + flags |= SDL_NOFRAME; + glConfig.isFullscreen = qfalse; + } colorbits = r_colorbits->value; if ((!colorbits) || (colorbits >= 32)) @@ -446,7 +453,7 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) GLimp_StartDriverAndSetMode =============== */ -static qboolean GLimp_StartDriverAndSetMode( qboolean failSafe, qboolean fullscreen ) +static qboolean GLimp_StartDriverAndSetMode( qboolean failSafe, qboolean fullscreen, qboolean noborder ) { rserr_t err; @@ -474,7 +481,7 @@ static qboolean GLimp_StartDriverAndSetMode( qboolean failSafe, qboolean fullscr fullscreen = qfalse; } - err = GLimp_SetMode( failSafe, fullscreen ); + err = GLimp_SetMode( failSafe, fullscreen, noborder ); switch ( err ) { @@ -681,21 +688,24 @@ void GLimp_Init( void ) 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 ); + r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE ); + + Sys_SetEnv( "SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "" ); Sys_GLimpInit( ); // Create the window and set up the context - if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) ) + if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer, r_noborder->integer ) ) goto success; // Try again, this time in a platform specific "safe mode" Sys_GLimpSafeInit( ); - if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) ) + if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer, qfalse ) ) goto success; // Finally, try the default screen resolution - if( GLimp_StartDriverAndSetMode( qtrue, r_fullscreen->integer ) ) + if( GLimp_StartDriverAndSetMode( qtrue, r_fullscreen->integer, qfalse ) ) goto success; // Nothing worked, give up diff --git a/src/sys/con_tty.c b/src/sys/con_tty.c index a66a3faf..b0990032 100644 --- a/src/sys/con_tty.c +++ b/src/sys/con_tty.c @@ -327,7 +327,7 @@ CON_Input char *CON_Input( void ) { // we use this when sending back commands - static char text[256]; + static char text[MAX_EDIT_LINE]; int avail; char key; field_t *history; @@ -358,7 +358,7 @@ char *CON_Input( void ) { // push it in history Hist_Add(&TTY_con); - strcpy(text, TTY_con.buffer); + Q_strncpyz(text, TTY_con.buffer, sizeof(text)); Field_Clear(&TTY_con); key = '\n'; size = write(1, &key, 1); @@ -420,6 +420,8 @@ char *CON_Input( void ) CON_FlushIn(); return NULL; } + if (TTY_con.cursor >= sizeof(text) - 1) + return NULL; // push regular character TTY_con.buffer[TTY_con.cursor] = key; TTY_con.cursor++; diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c index 3360469d..60623a27 100644 --- a/src/sys/sys_unix.c +++ b/src/sys/sys_unix.c @@ -55,22 +55,11 @@ char *Sys_DefaultHomePath(void) { Q_strncpyz( homePath, p, sizeof( homePath ) ); #ifdef MACOS_X - 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" ); + Q_strcat( homePath, sizeof( homePath ), + "/Library/Application Support/Tremulous" ); #else Q_strcat( homePath, sizeof( homePath ), "/.tremulous" ); #endif - if( mkdir( homePath, 0750 ) ) - { - if( errno != EEXIST ) - { - Sys_Error( "Unable to create directory \"%s\", error is %s(%d)\n", - homePath, strerror( errno ), errno ); - } - } } } @@ -222,9 +211,14 @@ const char *Sys_Dirname( char *path ) Sys_Mkdir ================== */ -void Sys_Mkdir( const char *path ) +qboolean Sys_Mkdir( const char *path ) { - mkdir( path, 0777 ); + int result = mkdir( path, 0750 ); + + if( result != 0 ) + return errno == EEXIST; + + return qtrue; } /* @@ -583,3 +577,19 @@ void Sys_PlatformInit( void ) signal( SIGIOT, Sys_SigHandler ); signal( SIGBUS, Sys_SigHandler ); } + +/* +============== +Sys_SetEnv + +set/unset environment variables (empty value removes it) +============== +*/ + +void Sys_SetEnv(const char *name, const char *value) +{ + if(value && *value) + setenv(name, value, 1); + else + unsetenv(name); +} diff --git a/src/sys/sys_win32.c b/src/sys/sys_win32.c index 18efe406..e5b0cb00 100644 --- a/src/sys/sys_win32.c +++ b/src/sys/sys_win32.c @@ -77,14 +77,6 @@ char *Sys_DefaultHomePath( void ) Q_strncpyz( homePath, szPath, sizeof( homePath ) ); Q_strcat( homePath, sizeof( homePath ), "\\Tremulous" ); FreeLibrary(shfolder); - if( !CreateDirectory( homePath, NULL ) ) - { - if( GetLastError() != ERROR_ALREADY_EXISTS ) - { - Com_Printf("Unable to create directory \"%s\"\n", homePath ); - return NULL; - } - } } return homePath; @@ -279,9 +271,15 @@ const char *Sys_Dirname( char *path ) Sys_Mkdir ============== */ -void Sys_Mkdir( const char *path ) +qboolean Sys_Mkdir( const char *path ) { - _mkdir (path); + if( !CreateDirectory( path, NULL ) ) + { + if( GetLastError( ) != ERROR_ALREADY_EXISTS ) + return qfalse; + } + + return qtrue; } /* @@ -652,3 +650,16 @@ void Sys_PlatformInit( void ) SDL_VIDEODRIVER_externallySet = qfalse; #endif } + +/* +============== +Sys_SetEnv + +set/unset environment variables (empty value removes it) +============== +*/ + +void Sys_SetEnv(const char *name, const char *value) +{ + _putenv(va("%s=%s", name, value)); +} |