From 8ae45223dc7b6fcaac613516b8ed8afc65161427 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 14 Jul 2012 16:25:18 +0000 Subject: [PATCH] Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables. Some memory leaks fixed. latency with the nq protocol over loopback is much reduced. Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 161 ++- engine/client/cl_ents.c | 2 +- engine/client/cl_main.c | 34 +- engine/client/cl_parse.c | 14 +- engine/client/cl_pred.c | 6 +- engine/client/cl_screen.c | 14 +- engine/client/cl_tent.c | 1 + engine/client/console.c | 8 + engine/client/in_droid.c | 61 +- engine/client/in_macos.c | 4 +- engine/client/in_morphos.c | 4 +- engine/client/in_sdl.c | 4 +- engine/client/keys.c | 50 +- engine/client/keys.h | 3 + engine/client/m_mp3.c | 9 +- engine/client/net_master.c | 21 +- engine/client/p_script.c | 30 +- engine/client/pr_csqc.c | 1 + engine/client/pr_menu.c | 2 + engine/client/r_2d.c | 17 + engine/client/r_partset.c | 71 +- engine/client/r_surf.c | 103 +- engine/client/render.h | 2 +- engine/client/renderer.c | 20 +- engine/client/snd_dma.c | 22 + engine/client/sys_droid.c | 38 +- engine/client/view.c | 4 + engine/client/wad.c | 15 +- engine/common/bothdefs.h | 4 + engine/common/com_mesh.c | 1 + engine/common/common.c | 22 +- engine/common/console.h | 2 +- engine/common/fs.c | 90 +- engine/common/log.c | 2 +- engine/common/pr_bgcmd.c | 2 +- engine/common/pr_common.h | 2 +- engine/common/q1bsp.c | 10 + engine/common/sys.h | 2 + engine/common/zone.c | 2 +- engine/d3d/vid_d3d.c | 3 - engine/dotnet2005/ftequake.vcproj | 328 ++++++ engine/droid/AndroidManifest.xml | 1 + .../droid/src/com/fteqw/FTEDroidActivity.java | 126 ++- .../droid/src/com/fteqw/FTEDroidEngine.java | 5 +- engine/gl/gl_alias.c | 4 +- engine/gl/gl_backend.c | 34 +- engine/gl/gl_font.c | 4 +- engine/gl/gl_heightmap.c | 947 +++++++++++++----- engine/gl/gl_model.c | 72 +- engine/gl/gl_rmain.c | 5 +- engine/gl/gl_screen.c | 3 - engine/gl/gl_shader.c | 29 +- engine/gl/gl_shadow.c | 8 +- engine/gl/glmod_doom.c | 3 +- engine/gl/glquake.h | 8 +- engine/gl/r_bishaders.h | 46 + engine/partcfgs/high.cfg | 71 +- engine/shaders/generatebuiltinsl.c | 1 + engine/shaders/glsl/terrain.glsl | 42 + engine/sw/sw_rast.c | 1 + 60 files changed, 2031 insertions(+), 570 deletions(-) create mode 100644 engine/shaders/glsl/terrain.glsl diff --git a/engine/Makefile b/engine/Makefile index 9447e4f02..b5b1225b7 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -324,7 +324,7 @@ ifeq ($(FTE_TARGET),vc) else WARNINGFLAGS=-Wall -Wno-pointer-sign - GNUC_FUNCS= -Dstrnicmp=strncasecmp -Dstricmp=strcasecmp -D_vsnprintf=vsnprintf -D_snprintf=snprintf + GNUC_FUNCS= -Dstrnicmp=strncasecmp -Dstricmp=strcasecmp endif BASE_CFLAGS=$(WARNINGFLAGS) $(GNUC_FUNCS) -I$(CLIENT_DIR) -I$(SERVER_DIR) -I$(COMMON_DIR) -I$(GL_DIR) -I$(D3D_DIR) -I$(PROGS_DIR) -I$(BOTLIB_DIR) -I$(LIBS_DIR) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/sdl/include -I/usr/include/SDL -I$(LIBS_DIR)/sdl/include/SDL -I./libs/freetype2/include -I./libs/freetype2/include/freetype -I./libs/speex -DBOTLIB $(SVNREVISION) @@ -335,10 +335,11 @@ DEBUG_CFLAGS=-ggdb -g RELEASE_CFLAGS?=-O3 -ffast-math $(CPUOPTIMIZATIONS) #incase our compiler doesn't support it (mingw) -ifeq ($(shell $(CC) -rdynamic 2>&1 | grep unrecognised),) +ifeq ($(shell LANG=c $(CC) -rdynamic 2>&1 | grep unrecognized),) DEBUG_CFLAGS+= -rdynamic endif +OBJS+=$(SPEEX_OBJS) PROFILE_CFLAGS=-pg DX7SDK=-I./libs/dxsdk7/include/ @@ -347,6 +348,49 @@ GLCFLAGS=-DGLQUAKE D3DCFLAGS=-DD3DQUAKE NPFTECFLAGS=-DNPFTE +SPEEX_OBJS = \ + bits.o \ + buffer.o \ + cb_search.o \ + exc_10_16_table.o \ + exc_10_32_table.o \ + exc_20_32_table.o \ + exc_5_256_table.o \ + exc_5_64_table.o \ + exc_8_128_table.o \ + fftwrap.o \ + filterbank.o \ + filters.o \ + gain_table.o \ + gain_table_lbr.o \ + hexc_10_32_table.o \ + hexc_table.o \ + high_lsp_tables.o \ + jitter.o \ + kiss_fft.o \ + kiss_fftr.o \ + lpc.o \ + lsp.o \ + lsp_tables_nb.o \ + ltp.o \ + mdf.o \ + modes.o \ + modes_wb.o \ + nb_celp.o \ + preprocess.o \ + quant_lsp.o \ + resample.o \ + sb_celp.o \ + scal.o \ + smallft.o \ + speex.o \ + speex_callbacks.o \ + speex_header.o \ + stereo.o \ + vbr.o \ + vq.o \ + window.o + CLIENT_OBJS = \ textedit.o \ fragstats.o \ @@ -731,6 +775,8 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),) BITS=64 endif + BASELDFLAGS= + SV_CFLAGS=$(SERVER_ONLY_CFLAGS) $(W32_CFLAGS) LIBS_DIR = $(BASE_DIR)/libs @@ -985,6 +1031,13 @@ endif VPATH = $(BASE_DIR) : $(CLIENT_DIR) : $(GL_DIR) : $(COMMON_DIR) : $(SERVER_DIR) : $(HTTP_DIR) : $(BASE_DIR)/irc : $(BASE_DIR)/email : $(QUX_DIR) : $(PROGS_DIR) : $(NACL_DIR) : $(SNDCODEC_DIR) : $(D3D_DIR) : $(BOTLIB_DIR) +ifneq ($(findstring -DSPEEX_STATIC, $(CFLAGS)),) + #add these to statically link libspeex + VPATH += : $(BASE_DIR)/libs/speex-1.2rc1/libspeex + BASE_CFLAGS += -DSPEEX_STATIC -I$(BASE_DIR)/libs/speex-1.2rc1/include -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" + CLIENT_OBJS += $(SPEEX_OBJS) +endif + # This is for linking the FTE icon to the MinGW target $(OUT_DIR)/resources.o : winquake.rc $(WINDRES) -I$(CLIENT_DIR) -O coff $< $@ @@ -1054,75 +1107,75 @@ $(OUT_DIR)/$(EXE_NAME): $(PRECOMPHEADERS) $(foreach fn, $(CUSTOMOBJS) $(foreac $(DO_LD) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS) $(LTO_END), $($(ol))),$(if $(findstring ltox,$(fn)),$(subst ltox,-x ,$(fn)),$(OUT_DIR)/$(fn)) ) $(LDFLAGS) _out-rel: - $(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(RELEASE_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(RELEASE_LDFLAGS)" OBJS="$(OBJS)" + @$(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(RELEASE_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(RELEASE_LDFLAGS)" OBJS="$(OBJS)" $(STRIP) $(STRIPFLAGS) $(OUT_DIR)/$(EXE_NAME) _out-dbg: - $(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(DEBUG_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(DEBUG_LDFLAGS)" OBJS="$(OBJS)" + @$(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(DEBUG_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(DEBUG_LDFLAGS)" OBJS="$(OBJS)" _out-profile: - $(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(PROFILE_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(PROFILE_LDFLAGS)" OBJS="$(OBJS)" + @$(MAKE) $(OUT_DIR)/$(EXE_NAME) EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(WCFLAGS) $(PROFILE_CFLAGS)" LDFLAGS="$(BASELDFLAGS) $(LDFLAGS) $(PROFILE_LDFLAGS)" OBJS="$(OBJS)" _cl-rel: reldir - $(MAKE) _out-rel EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS" + @$(MAKE) _out-rel EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS" _cl-dbg: debugdir - $(MAKE) _out-dbg EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS" + @$(MAKE) _out-dbg EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS" _cl-profile: reldir - $(MAKE) _out-profile EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS" + @$(MAKE) _out-profile EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(CLIENT_ONLY_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS" _clsv-rel: reldir - $(MAKE) _out-rel EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(JOINT_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS SERVER_OBJS" + @$(MAKE) _out-rel EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(JOINT_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS SERVER_OBJS" _clsv-dbg: debugdir - $(MAKE) _out-dbg EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(JOINT_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS SERVER_OBJS" + @$(MAKE) _out-dbg EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(JOINT_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS SERVER_OBJS" _clsv-profile: reldir - $(MAKE) _out-profile EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(JOINT_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS SERVER_OBJS" + @$(MAKE) _out-profile EXE_NAME="$(EXE_NAME)" OUT_DIR="$(OUT_DIR)" WCFLAGS="$(JOINT_CFLAGS) $(WCFLAGS)" LDFLAGS="$(LDFLAGS)" SOBJS="$(SOBJS)" OBJS="SOBJS COMMON_OBJS CLIENT_OBJS PROGS_OBJS SERVER_OBJS" sv-tmp: reldir debugdir - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SV_EXE_NAME)" WCFLAGS="$(SV_CFLAGS)" LDFLAGS="$(SV_LDFLAGS) $(LDFLAGS)" OBJS="SV_OBJS" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(SV_EXE_NAME)" WCFLAGS="$(SV_CFLAGS)" LDFLAGS="$(SV_LDFLAGS) $(LDFLAGS)" OBJS="SV_OBJS" sv-rel: - $(MAKE) sv-tmp TYPE=_out-rel OUT_DIR="$(RELEASE_DIR)/$(SV_DIR)" + @$(MAKE) sv-tmp TYPE=_out-rel OUT_DIR="$(RELEASE_DIR)/$(SV_DIR)" sv-dbg: - $(MAKE) sv-tmp TYPE=_out-dbg OUT_DIR="$(DEBUG_DIR)/$(SV_DIR)" + @$(MAKE) sv-tmp TYPE=_out-dbg OUT_DIR="$(DEBUG_DIR)/$(SV_DIR)" sv-profile: - $(MAKE) sv-tmp TYPE=_out-profile OUT_DIR="$(PROFILE_DIR)/$(SV_DIR)" + @$(MAKE) sv-tmp TYPE=_out-profile OUT_DIR="$(PROFILE_DIR)/$(SV_DIR)" d3dcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(D3DCL_EXE_NAME)" WCFLAGS="$(D3D_CFLAGS)" LDFLAGS="$(D3D_LDFLAGS) $(LDFLAGS)" SOBJS="$(D3DCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(D3DCL_EXE_NAME)" WCFLAGS="$(D3D_CFLAGS)" LDFLAGS="$(D3D_LDFLAGS) $(LDFLAGS)" SOBJS="$(D3DCL_OBJS)" d3d-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(D3D_EXE_NAME)" WCFLAGS="$(D3D_CFLAGS)" LDFLAGS="$(D3D_LDFLAGS) $(LDFLAGS)" SOBJS="$(D3DCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(D3D_EXE_NAME)" WCFLAGS="$(D3D_CFLAGS)" LDFLAGS="$(D3D_LDFLAGS) $(LDFLAGS)" SOBJS="$(D3DCL_OBJS)" d3dcl-rel: - $(MAKE) d3dcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(D3DCL_DIR)" + @$(MAKE) d3dcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(D3DCL_DIR)" d3dcl-dbg: - $(MAKE) d3dcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(D3DCL_DIR)" + @$(MAKE) d3dcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(D3DCL_DIR)" d3dcl-profile: - $(MAKE) d3dcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(D3DCL_DIR)" + @$(MAKE) d3dcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(D3DCL_DIR)" d3d-rel: - $(MAKE) d3d-tmp TYPE=_clsv-rel OUT_DIR="$(RELEASE_DIR)/$(D3DB_DIR)" + @$(MAKE) d3d-tmp TYPE=_clsv-rel OUT_DIR="$(RELEASE_DIR)/$(D3DB_DIR)" d3d-dbg: - $(MAKE) d3d-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(D3DB_DIR)" + @$(MAKE) d3d-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(D3DB_DIR)" d3d-profile: - $(MAKE) d3d-tmp TYPE=_clsv-profile OUT_DIR="$(PROFILE_DIR)/$(D3DB_DIR)" + @$(MAKE) d3d-tmp TYPE=_clsv-profile OUT_DIR="$(PROFILE_DIR)/$(D3DB_DIR)" npqtvcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(NPFTECL_DLL_NAME)" WCFLAGS="$(NPFTE_CFLAGS)" LDFLAGS="$(NPFTE_LDFLAGS) $(LDFLAGS)" SOBJS="$(NPFTECL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(NPFTECL_DLL_NAME)" WCFLAGS="$(NPFTE_CFLAGS)" LDFLAGS="$(NPFTE_LDFLAGS) $(LDFLAGS)" SOBJS="$(NPFTECL_OBJS)" npfte-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(NPFTE_DLL_NAME)" WCFLAGS="$(NPFTE_CFLAGS)" LDFLAGS="$(NPFTE_LDFLAGS) $(LDFLAGS)" SOBJS="$(NPFTECL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(NPFTE_DLL_NAME)" WCFLAGS="$(NPFTE_CFLAGS)" LDFLAGS="$(NPFTE_LDFLAGS) $(LDFLAGS)" SOBJS="$(NPFTECL_OBJS)" npqtvcl-rel: - $(MAKE) npqtvcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(NPFTECL_DIR)" + @$(MAKE) npqtvcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(NPFTECL_DIR)" npqtvcl-dbg: - $(MAKE) npqtvcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(NPFTECL_DIR)" + @$(MAKE) npqtvcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(NPFTECL_DIR)" npqtvcl-profile: - $(MAKE) npqtvcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(NPFTECL_DIR)" + @$(MAKE) npqtvcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(NPFTECL_DIR)" npfte-rel: - $(MAKE) npfte-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(NPFTEB_DIR)" + @$(MAKE) npfte-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(NPFTEB_DIR)" cp $(RELEASE_DIR)/npfte.dll npfte/plugins cd npfte && zip $(abspath $(RELEASE_DIR)/npfte.xpi) install.rdf plugins/npfte.dll rm -rf /tmp/npfte @@ -1132,54 +1185,54 @@ npfte-rel: cd $(RELEASE_DIR)/ && ../npfte/crxmake.sh /tmp/npfte ../npfte/chrome.pem rm -rf /tmp/npfte npfte-dbg: - $(MAKE) npfte-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(NPFTEB_DIR)" + @$(MAKE) npfte-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(NPFTEB_DIR)" npfte-profile: - $(MAKE) npfte-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(NPFTEB_DIR)" + @$(MAKE) npfte-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(NPFTEB_DIR)" glcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GLCL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GLCL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" gl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(GL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS)" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" glcl-rel: - $(MAKE) glcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(GLCL_DIR)" + @$(MAKE) glcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(GLCL_DIR)" glcl-dbg: - $(MAKE) glcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(GLCL_DIR)" + @$(MAKE) glcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(GLCL_DIR)" glcl-profile: - $(MAKE) glcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(GLCL_DIR)" + @$(MAKE) glcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(GLCL_DIR)" gl-rel: - $(MAKE) gl-tmp TYPE=_clsv-rel OUT_DIR="$(RELEASE_DIR)/$(GLB_DIR)" + @$(MAKE) gl-tmp TYPE=_clsv-rel OUT_DIR="$(RELEASE_DIR)/$(GLB_DIR)" gl-dbg: - $(MAKE) gl-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(GLB_DIR)" + @$(MAKE) gl-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(GLB_DIR)" gl-profile: - $(MAKE) gl-tmp TYPE=_clsv-profile OUT_DIR="$(PROFILE_DIR)/$(GLB_DIR)" + @$(MAKE) gl-tmp TYPE=_clsv-profile OUT_DIR="$(PROFILE_DIR)/$(GLB_DIR)" mingl-tmp: reldir - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MINGL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS) -DMINIMAL" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MINGL_EXE_NAME)" WCFLAGS="$(GL_CFLAGS) -DMINIMAL" LDFLAGS="$(GL_LDFLAGS) $(LDFLAGS)" SOBJS="$(GLCL_OBJS)" mingl-rel: - $(MAKE) mingl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(MINGL_DIR)" + @$(MAKE) mingl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(MINGL_DIR)" mingl-dbg: - $(MAKE) mingl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(MINGL_DIR)" + @$(MAKE) mingl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(MINGL_DIR)" mingl-profile: - $(MAKE) mingl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(MINGL_DIR)" + @$(MAKE) mingl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(MINGL_DIR)" mcl-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MCL_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS) $(LDFLAGS)" SOBJS="$(MCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(MCL_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS) $(LDFLAGS)" SOBJS="$(MCL_OBJS)" m-tmp: - $(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(M_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS) $(LDFLAGS)" SOBJS="$(MCL_OBJS)" + @$(MAKE) $(TYPE) OUT_DIR="$(OUT_DIR)" EXE_NAME="$(M_EXE_NAME)" WCFLAGS="$(M_CFLAGS)" LDFLAGS="$(M_LDFLAGS) $(LDFLAGS)" SOBJS="$(MCL_OBJS)" mcl-rel: - $(MAKE) mcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(MCL_DIR)" + @$(MAKE) mcl-tmp TYPE=_cl-rel OUT_DIR="$(RELEASE_DIR)/$(MCL_DIR)" mcl-dbg: - $(MAKE) mcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(MCL_DIR)" + @$(MAKE) mcl-tmp TYPE=_cl-dbg OUT_DIR="$(DEBUG_DIR)/$(MCL_DIR)" mcl-profile: - $(MAKE) mcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(MCL_DIR)" + @$(MAKE) mcl-tmp TYPE=_cl-profile OUT_DIR="$(PROFILE_DIR)/$(MCL_DIR)" m-rel: - $(MAKE) m-tmp TYPE=_clsv-rel OUT_DIR="$(RELEASE_DIR)/$(MB_DIR)" + @$(MAKE) m-tmp TYPE=_clsv-rel OUT_DIR="$(RELEASE_DIR)/$(MB_DIR)" m-dbg: - $(MAKE) m-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(MB_DIR)" + @$(MAKE) m-tmp TYPE=_clsv-dbg OUT_DIR="$(DEBUG_DIR)/$(MB_DIR)" m-profile: - $(MAKE) m-tmp TYPE=_clsv-profile OUT_DIR="$(PROFILE_DIR)/$(MB_DIR)" + @$(MAKE) m-tmp TYPE=_clsv-profile OUT_DIR="$(PROFILE_DIR)/$(MB_DIR)" .PHONY: m-tmp mcl-tmp mingl-tmp glcl-tmp gl-tmp sv-tmp _clsv-dbg _clsv-rel _cl-dbg _cl-rel _out-rel _out-dbg @@ -1313,9 +1366,9 @@ droid-opt: droid/build.xml droid/ftekeystore #build FTE as a library, then build the java+package (release). also installs it onto the 'current' device. droid-dbg: droid/build.xml - $(MAKE) FTE_TARGET=droid gl-dbg - @mkdir -p droid/libs/armeabi - @cp $(DEBUG_DIR)/libftedroid.so droid/libs/armeabi/ + $(foreach a, $(DROID_ARCH), $(MAKE) FTE_TARGET=droid gl-dbg DROID_ARCH=$a; ) + @$(foreach a, $(DROID_ARCH), mkdir -p droid/libs/$a; ) + -@$(foreach a, $(DROID_ARCH), cp $(DEBUG_DIR)/gl_droid-$a/libftedroid.so droid/libs/$a/libftedroid.so; ) @cd droid && $(ANT) debug && $(ANT) debug install cp droid/bin/FTEDroid-debug.apk $(DEBUG_DIR)/FTEDroid.apk diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 3a0eaa52b..886c6db2d 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -820,7 +820,7 @@ void CLFTE_ParseEntities(void) break; /*update the prediction info if needed*/ - if (e->u.q1.pmovetype) +// if (e->u.q1.pmovetype) { frame_t *fram; fram = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 21927b382..2acb5778d 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -3273,6 +3273,7 @@ void CL_Init (void) Cmd_AddCommand ("god", NULL); //cheats Cmd_AddCommand ("give", NULL); Cmd_AddCommand ("noclip", NULL); + Cmd_AddCommand ("notarget", NULL); Cmd_AddCommand ("fly", NULL); Cmd_AddCommand ("setpos", NULL); @@ -3465,15 +3466,6 @@ double Host_Frame (double time) // if (cls.demoplayback && cl_demospeed.value>0) // realframetime *= cl_demospeed.value; // this probably screws up other timings -#ifndef CLIENTONLY - if (sv.state) - { - RSpeedRemark(); - SV_Frame(); - RSpeedEnd(RSPEED_SERVER); - } -#endif - if (cl.gamespeed<0.1) cl.gamespeed = 1; time *= cl.gamespeed; @@ -3510,7 +3502,17 @@ double Host_Frame (double time) if (idlesec > 0.1) idlesec = 0.1; // limit to at least 10 fps if ((realtime - oldrealtime) < idlesec) + { +#ifndef CLIENTONLY + if (sv.state) + { + RSpeedRemark(); + SV_Frame(); + RSpeedEnd(RSPEED_SERVER); + } +#endif return idlesec - (realtime - oldrealtime); + } } /* @@ -3598,7 +3600,6 @@ double Host_Frame (double time) // fetch results from server CL_ReadPackets (); - CL_CalcClientTime(); // send intentions now // resend a connection request if necessary @@ -3620,6 +3621,19 @@ double Host_Frame (double time) RSpeedEnd(RSPEED_PROTOCOL); +#ifndef CLIENTONLY + if (sv.state) + { + float ohft = host_frametime; + RSpeedRemark(); + SV_Frame(); + RSpeedEnd(RSPEED_SERVER); + host_frametime = ohft; + CL_ReadPackets (); + } +#endif + CL_CalcClientTime(); + // update video if (host_speeds.ival) time1 = Sys_DoubleTime (); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index f457391ad..44f17c984 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1032,7 +1032,14 @@ int CL_LoadModels(int stage, qboolean dontactuallyload) s = Info_ValueForKey(cl.serverinfo, "*csprogs"); if (anycsqc || *s || cls.demoplayback) //only allow csqc if the server says so, and the 'checksum' matches. { - unsigned int chksum = strtoul(s, NULL, 0); + char *endptr; + unsigned int chksum = strtoul(s, &endptr, 0); + if (*endptr) + { + Con_Printf("corrupt *csprogs key in serverinfo\n"); + anycsqc = true; + chksum = 0; + } SCR_SetLoadingFile("csprogs"); if (!CSQC_Init(anycsqc, chksum)) { @@ -1291,8 +1298,9 @@ void Sound_CheckDownloads (void) if (*s) //only allow csqc if the server says so, and the 'checksum' matches. { extern cvar_t cl_download_csprogs, cl_nocsqc; - unsigned int chksum = strtoul(s, NULL, 0); - if (cl_nocsqc.ival || cls.demoplayback) + char *endptr; + unsigned int chksum = strtoul(s, &endptr, 0); + if (cl_nocsqc.ival || cls.demoplayback || *endptr) { } else if (cl_download_csprogs.ival) diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 14bc25d5a..edee50dce 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -981,7 +981,11 @@ void CL_PredictMovePNum (int pnum) { if (cl_lerp_players.ival && !cls.demoplayback) { - lerpents_t *le = &cl.lerpplayers[spec_track[pnum]]; + lerpents_t *le; + if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) + le = &cl.lerpents[spec_track[pnum]+1]; + else + le = &cl.lerpplayers[spec_track[pnum]]; org = le->origin; vel = vec3_origin; } diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 21ee1cd20..e6c8ed814 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1744,8 +1744,18 @@ void SCR_SetUpToDrawConsole (void) // decide on the height of the console if (!scr_disabled_for_loading) { - if ((key_dest == key_console || key_dest == key_game) && !cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload) - Con_ForceActiveNow(); + float fullscreenpercent = 1; +#ifdef ANDROID + //android has an onscreen imm that we don't want to obscure + fullscreenpercent = scr_consize.value; +#endif + if ((key_dest == key_console || key_dest == key_game) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload)) + { + key_dest = key_console; + scr_conlines = scr_con_current = vid.height * fullscreenpercent; + } + else if ((key_dest == key_console || key_dest == key_game) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active) + scr_con_current = scr_conlines = vid.height * fullscreenpercent; else if (key_dest == key_console || scr_chatmode) { scr_conlines = vid.height*scr_consize.value; // half screen diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 182271b36..f42527c2d 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -521,6 +521,7 @@ CL_ClearTEnts void CL_ClearTEnts (void) { CL_ClearTEntParticleState(); + CL_ShutdownTEnts(); cl_beams_max = 0; BZ_Free(cl_beams); diff --git a/engine/client/console.c b/engine/client/console.c index ca9013fd9..f78806c54 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -772,8 +772,16 @@ void VARGS Con_DPrintf (char *fmt, ...) char msg[MAXPRINTMSG]; extern cvar_t log_developer; +#ifdef CRAZYDEBUGGING + va_start (argptr,fmt); + vsnprintf (msg,sizeof(msg)-1, fmt,argptr); + va_end (argptr); + Sys_Printf("%s", msg); + return; +#else if (!developer.value && !log_developer.value) return; // early exit +#endif va_start (argptr,fmt); vsnprintf (msg,sizeof(msg)-1, fmt,argptr); diff --git a/engine/client/in_droid.c b/engine/client/in_droid.c index ad4f4eb77..194b7460f 100644 --- a/engine/client/in_droid.c +++ b/engine/client/in_droid.c @@ -5,7 +5,9 @@ extern qboolean mouse_active; cvar_t m_filter = CVARF("m_filter", "0", CVAR_ARCHIVE); -cvar_t m_strafeonright = CVARFD("m_strafeonright", "1", CVAR_ARCHIVE, "If 1, touching the right half of the touchscreen will strafe/move, while the left side will turn."); +cvar_t m_strafeonleft = CVARFD("m_strafeonleft", "1", CVAR_ARCHIVE, "If 1, touching the right half of the touchscreen will strafe/move, while the left side will turn."); +cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.5", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press."); +cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "5", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event."); extern cvar_t _windowed_mouse; @@ -32,6 +34,7 @@ struct eventlist_s struct { float x, y; + float tsize; //the size of the touch } mouse; struct { @@ -72,13 +75,14 @@ void IN_Shutdown(void) void IN_ReInit() { - Cvar_Register (&m_filter, "input controls"); - Cvar_Register (&m_strafeonright, "input controls"); } void IN_Init(void) { - IN_ReInit(); + Cvar_Register (&m_filter, "input controls"); + Cvar_Register (&m_strafeonleft, "input controls"); + Cvar_Register (&m_fatpressthreshold, "input controls"); + Cvar_Register (&m_slidethreshold, "input controls"); } /*on android, each 'pointer' is a separate touch location*/ @@ -95,31 +99,44 @@ void IN_Commands(void) if (ev->keyboard.scancode == K_MOUSE1 && ev->devid < MAXPOINTERS) { if (Key_MouseShouldBeFree()) - ptr[ev->devid].down = false; + ptr[ev->devid].down = 0; else { if (ev->type == IEV_KEYDOWN) { - ptr[ev->devid].down = true; + ptr[ev->devid].down = 1; ptr[ev->devid].movedist = 0; ptr[ev->devid].downpos[0] = ptr[ev->devid].oldpos[0]; ptr[ev->devid].downpos[1] = ptr[ev->devid].oldpos[1]; ptr[ev->devid].move[0] = 0; ptr[ev->devid].move[1] = 0; + + if (ev->mouse.tsize > m_fatpressthreshold.value) + { + int key = (m_strafeonleft.ival && ptr[ev->devid].downpos[0] > vid.pixelwidth/2)?K_MOUSE2:K_MOUSE1; + Key_Event(ev->devid, key, 0, true); + ptr[ev->devid].down = 2; + } } else { + if (ptr[ev->devid].down > 1) + { + int key = (m_strafeonleft.ival && ptr[ev->devid].downpos[0] > vid.pixelwidth/2)?K_MOUSE2:K_MOUSE1; + Key_Event(ev->devid, key, 0, false); + ptr[ev->devid].down = 1; + } if (ptr[ev->devid].down) { - if (ptr[ev->devid].movedist < 5) + if (ptr[ev->devid].movedist < m_slidethreshold.value) { /*if its on the right, make it a mouse2*/ - int key = (m_strafeonright.ival && ptr[ev->devid].downpos[0] > vid.pixelwidth/2)?K_MOUSE3:K_MOUSE1; + int key = (m_strafeonleft.ival && ptr[ev->devid].downpos[0] > vid.pixelwidth/2)?K_MOUSE2:K_MOUSE1; Key_Event(ev->devid, key, 0, true); Key_Event(ev->devid, key, 0, false); } } - ptr[ev->devid].down = false; + ptr[ev->devid].down = 0; } break; } @@ -130,8 +147,11 @@ void IN_Commands(void) /*mouse cursors only really work with one pointer*/ if (ev->devid == 0) { - mousecursor_x = bound(0, ev->mouse.x, vid.width - 1); - mousecursor_y = bound(0, ev->mouse.y, vid.height - 1); + float fl; + fl = ev->mouse.x * vid.width / vid.pixelwidth; + mousecursor_x = bound(0, fl, vid.width-1); + fl = ev->mouse.y * vid.height / vid.pixelheight; + mousecursor_y = bound(0, fl, vid.height-1); } if (ev->devid < MAXPOINTERS) @@ -143,6 +163,20 @@ void IN_Commands(void) ptr[ev->devid].oldpos[0] = ev->mouse.x; ptr[ev->devid].oldpos[1] = ev->mouse.y; + + + if (ptr[ev->devid].down > 1 && ev->mouse.tsize < m_fatpressthreshold.value) + { + int key = (m_strafeonleft.ival && ptr[ev->devid].downpos[0] > vid.pixelwidth/2)?K_MOUSE2:K_MOUSE1; + Key_Event(ev->devid, key, 0, false); + ptr[ev->devid].down = 1; + } + if (ptr[ev->devid].down == 1 && ev->mouse.tsize > m_fatpressthreshold.value) + { + int key = (m_strafeonleft.ival && ptr[ev->devid].downpos[0] > vid.pixelwidth/2)?K_MOUSE2:K_MOUSE1; + Key_Event(ev->devid, key, 0, true); + ptr[ev->devid].down = 2; + } } break; } @@ -169,7 +203,7 @@ static void IN_Update(qboolean ingame) { if (!CSQC_MouseMove(ptr[i].move[0], ptr[i].move[1], i)) { - if (ptr[i].down && m_strafeonright.ival && ptr[i].downpos[0] > vid.pixelwidth/2 && ingame) + if (ptr[i].down && m_strafeonleft.ival && ptr[i].downpos[0] > vid.pixelwidth/2 && ingame) { mousestrafe_x += ptr[i].oldpos[0] - ptr[i].downpos[0]; mousestrafe_y += ptr[i].oldpos[1] - ptr[i].downpos[1]; @@ -273,7 +307,7 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_keypress(JNIEnv *env, jobje } JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject obj, - jint act, jint ptrid, jfloat x, jfloat y) + jint act, jint ptrid, jfloat x, jfloat y, jfloat size) { struct eventlist_s *ev = in_newevent(); if (!ev) @@ -290,6 +324,7 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_motion(JNIEnv *env, jobject ev->type = IEV_MOUSEABS; ev->mouse.x = x; ev->mouse.y = y; + ev->mouse.tsize = size; } in_finishevent(); } diff --git a/engine/client/in_macos.c b/engine/client/in_macos.c index 14970e053..683f232f7 100644 --- a/engine/client/in_macos.c +++ b/engine/client/in_macos.c @@ -83,7 +83,7 @@ void IN_Move (float *movements, int pnum) } else { - cl.viewanglechange[pnum][YAW] -= m_yaw.value * mouse_x; + cl.playerview[pnum].viewanglechange[YAW] -= m_yaw.value * mouse_x; } if (in_mlook.state[pnum]) @@ -91,7 +91,7 @@ void IN_Move (float *movements, int pnum) if (in_mlook.state[pnum] && !(in_strafe.state[pnum] & 1)) { - cl.viewanglechange[pnum][PITCH] += m_pitch.value * mouse_y; + cl.playerview[pnum].viewanglechange[PITCH] += m_pitch.value * mouse_y; } else { diff --git a/engine/client/in_morphos.c b/engine/client/in_morphos.c index adada42db..dec655ee7 100644 --- a/engine/client/in_morphos.c +++ b/engine/client/in_morphos.c @@ -281,13 +281,13 @@ void IN_Move (float *movements, int pnum) } else { - cl.viewanglechange[pnum][YAW] -= m_yaw.value * mouse_x; + cl.playerview[pnum].viewanglechange[YAW] -= m_yaw.value * mouse_x; } if (in_mlook.state[pnum] & 1) V_StopPitchDrift (pnum); if ( (in_mlook.state[pnum] & 1) && !(in_strafe.state[pnum] & 1)) { - cl.viewanglechange[pnum][PITCH] += m_pitch.value * mouse_y; + cl.playerview[pnum].viewanglechange[PITCH] += m_pitch.value * mouse_y; } else { if (movements) { diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index 7bd97f0b4..2b9aec277 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -315,14 +315,14 @@ void IN_Move (float *movements, int pnum) //add mouse movement to cmd if ( (in_strafe.state[pnum] & 1) || (lookstrafe.value && (in_mlook.state[pnum] & 1) )) movements[1] += m_side.value * mouse_x; else - cl.viewanglechange[pnum][YAW] -= m_yaw.value * mouse_x; + cl.playerview[pnum].viewanglechange[YAW] -= m_yaw.value * mouse_x; if (in_mlook.state[pnum] & 1) V_StopPitchDrift (pnum); if ( (in_mlook.state[pnum] & 1) && !(in_strafe.state[pnum] & 1)) { - cl.viewanglechange[pnum][PITCH] += m_pitch.value * mouse_y; + cl.playerview[pnum].viewanglechange[PITCH] += m_pitch.value * mouse_y; } else { diff --git a/engine/client/keys.c b/engine/client/keys.c index 73d72878a..c80374de6 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -161,7 +161,12 @@ keyname_t keynames[] = {"LWIN", K_LWIN}, {"RWIN", K_RWIN}, {"APP", K_APP}, - + {"MENU", K_APP}, + {"SEARCH", K_SEARCH}, + {"POWER", K_POWER}, + {"VOLUP", K_VOLUP}, + {"VOLDOWN", K_VOLDOWN}, + {"JOY1", K_JOY1}, {"JOY2", K_JOY2}, {"JOY3", K_JOY3}, @@ -390,28 +395,41 @@ qboolean Key_GetConsoleSelectionBox(int *sx, int *sy, int *ex, int *ey) { extern int mousecursor_x, mousecursor_y; - if (!con_mousedown[2]) - { - *sx = *sy = *ex = *ey = 0; - return false; - } - *sx = con_mousedown[0]; - *sy = con_mousedown[1]; - *ex = mousecursor_x; - *ey = mousecursor_y; + *sx = *sy = *ex = *ey = 0; - return true; + if (con_mousedown[2] == 1) + { + while (mousecursor_y - con_mousedown[1] > 8 && con_current->display->older) + { + con_mousedown[1] += 8; + con_current->display = con_current->display->older; + } + while (mousecursor_y - con_mousedown[1] < -8 && con_current->display->newer) + { + con_mousedown[1] -= 8; + con_current->display = con_current->display->newer; + } + } + else if (con_mousedown[2] == 2) + { + *sx = con_mousedown[0]; + *sy = con_mousedown[1]; + *ex = mousecursor_x; + *ey = mousecursor_y; + return true; + } + return false; } void Key_ConsoleRelease(int key, int unicode) { if (key == K_MOUSE1) - con_mousedown[2] = false; - if (key == K_MOUSE2 && con_mousedown[2]) + con_mousedown[2] = 0; + if (key == K_MOUSE2 && con_mousedown[2] == 2) { extern int mousecursor_x, mousecursor_y; char *buffer; - con_mousedown[2] = false; + con_mousedown[2] = 0; buffer = Con_CopyConsole(); if (!buffer) return; @@ -478,9 +496,9 @@ void Key_Console (unsigned int unicode, int key) } } else if (key == K_MOUSE2) - con_mousedown[2] = true; + con_mousedown[2] = 2; else - con_mousedown[2] = false; + con_mousedown[2] = 1; return; } diff --git a/engine/client/keys.h b/engine/client/keys.h index 4ce83ef0a..1d195e7f8 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -155,6 +155,9 @@ K_AUX32 = 238, K_LWIN = 239, K_RWIN = 240, K_APP = 241, +K_SEARCH = 242, +K_VOLUP = 243, +K_VOLDOWN = 244, K_MAX = 256 }; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index a50a1f6b5..f3574c113 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -3289,10 +3289,6 @@ sfxcache_t *S_MP3_Locate(sfx_t *sfx, sfxcache_t *buf, int start, int length) #ifndef WAVE_FORMAT_MPEGLAYER3 #define WAVE_FORMAT_MPEGLAYER3 0x0055 -#define MPEGLAYER3_WFX_EXTRA_BYTES 12 -#define MPEGLAYER3_FLAG_PADDING_OFF 2 -#define MPEGLAYER3_ID_MPEG 1 - typedef struct { WAVEFORMATEX wfx; @@ -3303,6 +3299,11 @@ typedef struct WORD nCodecDelay; } MPEGLAYER3WAVEFORMAT; #endif +#ifndef MPEGLAYER3_ID_MPEG +#define MPEGLAYER3_WFX_EXTRA_BYTES 12 +#define MPEGLAYER3_FLAG_PADDING_OFF 2 +#define MPEGLAYER3_ID_MPEG 1 +#endif qboolean S_LoadMP3Sound (sfx_t *s, qbyte *data, int datalen, int sndspeed) { diff --git a/engine/client/net_master.c b/engine/client/net_master.c index a673ea594..7c10a0aeb 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -628,6 +628,17 @@ void Master_AddMaster (char *address, int type, char *description) master = mast; } +void MasterInfo_Shutdown(void) +{ + master_t *mast; + while(master) + { + mast = master; + master = mast->next; + Z_Free(mast); + } +} + void Master_AddMasterHTTP (char *address, int mastertype, char *description) { master_t *mast; @@ -1539,11 +1550,11 @@ void MasterInfo_Refresh(void) //q3 { - //Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTPQW, "gameaholic's Q3 master"); - Master_AddMaster("master.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master server."); - Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERQ3, "team exhale"); - //Master_AddMaster("master3.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master3 server."); - Master_AddMaster("255.255.255.255:27960", MT_BCASTQ3, "Nearby Quake3 UDP servers."); + //Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake3", MT_MASTERHTTPQW, "gameaholic's Q3 master"); + Master_AddMaster("master.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master server."); + Master_AddMaster("masterserver.exhale.de:27950", MT_MASTERQ3, "team exhale"); + //Master_AddMaster("master3.quake3arena.com:27950", MT_MASTERQ3, "Quake3 master3 server."); + Master_AddMaster("255.255.255.255:27960", MT_BCASTQ3, "Nearby Quake3 UDP servers."); } } diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 8cd65ebe3..581b8e9e6 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -246,7 +246,7 @@ typedef struct part_type_s { float gravity; vec3_t friction; float clipbounce; - int stainonimpact; + float stainonimpact; vec3_t dl_rgb; float dl_radius; @@ -1135,13 +1135,15 @@ static void P_ParticleEffect_f(void) ptype->rgbrandsync[2] = atof(value); else if (!strcmp(var, "stains")) - ptype->stainonimpact = atoi(value); + ptype->stainonimpact = atof(value); else if (!strcmp(var, "blend")) { if (!strcmp(value, "add")) ptype->looks.blendmode = BM_ADD; else if (!strcmp(value, "subtract")) ptype->looks.blendmode = BM_SUBTRACT; + else if (!strcmp(value, "invmod")) + ptype->looks.blendmode = BM_INVMOD; else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor")) ptype->looks.blendmode = BM_BLENDCOLOUR; else @@ -2187,6 +2189,16 @@ static void PScript_Shutdown (void) Cmd_RemoveCommand("r_beaminfo"); #endif + while (numparticletypes > 0) + { + numparticletypes--; + if (part_type[numparticletypes].ramp) + BZ_Free(part_type[numparticletypes].ramp); + } + BZ_Free (part_type); + part_type = NULL; + part_run_list = NULL; + BZ_Free (particles); BZ_Free (beams); BZ_Free (decals); @@ -5354,10 +5366,16 @@ static void PScript_DrawParticleTypes (void) { if (traces-->0&&tr(oldorg, p->org, stop, normal)) { - R_AddStain(stop, (p->rgba[1]*-10+p->rgba[2]*-10), - (p->rgba[0]*-10+p->rgba[2]*-10), - (p->rgba[0]*-10+p->rgba[1]*-10), - 30*p->rgba[3]*type->stainonimpact); + if (type->stainonimpact < 0) + R_AddStain(stop, (p->rgba[0]*-1), + (p->rgba[1]*-1), + (p->rgba[2]*-1), + p->scale*-type->stainonimpact); + else + R_AddStain(stop, (p->rgba[1]*-10+p->rgba[2]*-10), + (p->rgba[0]*-10+p->rgba[2]*-10), + (p->rgba[0]*-10+p->rgba[1]*-10), + 30*p->rgba[3]*type->stainonimpact); p->die = -1; continue; } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 6f89b821b..c65906e3b 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1223,6 +1223,7 @@ static void QCBUILTIN PF_R_GetViewFlag(progfuncs_t *prinst, struct globalvars_s case VF_SIZE: r[0] = r_refdef.vrect.width; r[1] = r_refdef.vrect.height; + r[2] = 0; break; case VF_MIN_X: diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 9a007ae07..805f9e832 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -603,6 +603,8 @@ void QCBUILTIN PF_CL_drawrawstring (progfuncs_t *prinst, struct globalvars_s *pr } while(*text) { + //FIXME: which charset is this meant to be using? + //quakes? 8859-1? utf8? some weird hacky mixture? x = Font_DrawScaleChar(x, y, size[0], size[1], CON_WHITEMASK|/*0xe000|*/(*text++&0xff)); } Font_InvalidateColour(); diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index c9f68fb77..3d87663df 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -92,6 +92,23 @@ void R2D_Shutdown(void) Cvar_Unhook(&crosshair); Cvar_Unhook(&crosshairimage); Cvar_Unhook(&crosshaircolor); + + BZ_Free(cl_stris); + cl_stris = NULL; + BZ_Free(cl_strisvertv); + cl_strisvertv = NULL; + BZ_Free(cl_strisvertc); + cl_strisvertc = NULL; + BZ_Free(cl_strisvertt); + cl_strisvertt = NULL; + BZ_Free(cl_strisidx); + cl_strisidx = NULL; + cl_numstrisidx = 0; + cl_maxstrisidx = 0; + cl_numstrisvert = 0; + cl_maxstrisvert = 0; + cl_numstris = 0; + cl_maxstris = 0; } /* diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index f0ea34091..56d74489e 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -1624,6 +1624,8 @@ char *particle_set_high = "friction 4\n" "scalefactor 0.825\n" "blend add\n" +"spawnmode spiral\n" +"spawnvel -50\n" "}\n" ///////////////////////////////////////// @@ -1658,46 +1660,91 @@ char *particle_set_high = //{ //} +"r_part te_blood\n" +"{\n" +"texture fte_bloodparticle\n" +"blend subtract\n" +"count 1\n" +"scale 32\n" +"alpha 0\n" +"die 1\n" +"randomvel 64\n" +"veladd 10\n" +"rotationspeed 90\n" +"rotationstart 0 360\n" +"rgb 64 128 128\n" +"rgbdelta -64 -128 -128\n" +"gravity 200\n" +"scalefactor 0.8\n" +// scaledelta -10 +"}\n" + +"r_part pe_73\n" +"{\n" +"assoc te_blood\n" +"}\n" + +"r_part te_lightningblood\n" +"{\n" +"texture fte_bloodparticle\n" +"blend subtract\n" +"count 1\n" +"scale 32\n" +"alpha 0\n" +"die 1\n" +"randomvel 64\n" +"veladd 10\n" +"rotationspeed 90\n" +"rotationstart 0 360\n" +"rgb 0 128 128\n" +"rgbdelta 0 -128 -128\n" +"gravity 200\n" +"scalefactor 0.8\n" +"}\n" + ///////////////////////////////////////// //zombie body-part blood trails "r_part tr_slightblood\n" "{\n" -"texture \"particles/fteparticlefont.tga\"\n" -"tcoords 1 1 63 63 256 2 64\n" +"texture fte_bloodparticle\n" +"blend subtract\n" +// tcoords 1 1 63 63 256 2 64 "step 16\n" "scale 64\n" -"alpha 0.6\n" +"alpha 0\n" "die 1\n" "randomvel 32\n" "veladd 10\n" "rotationspeed 90\n" "rotationstart 0 360\n" -"rgb 32 0 0\n" +"rgb 64 128 128 \n" +"rgbdelta -64 -128 -128\n" "gravity 200\n" "scalefactor 0.8\n" "scaledelta -10\n" -"stains 5\n" +"stains -0.5\n" "}\n" ////////////////////////////////////////// //regular ol' blood trails "r_part tr_blood\n" "{\n" -"texture \"particles/fteparticlefont.tga\"\n" -"tcoords 1 1 63 63 256 2 64\n" -"step 4\n" +"texture fte_bloodparticle\n" +"blend subtract\n" +"step 8\n" "scale 64\n" -"alpha 0.3\n" +"alpha 0\n" "die 1\n" "randomvel 32\n" "veladd 10\n" "rotationspeed 90\n" "rotationstart 0 360\n" -"rgb 64 0 0\n" +"rgb 32 128 128 \n" +"rgbdelta -32 -128 -128\n" "gravity 200\n" "scalefactor 0.8\n" "scaledelta -10\n" -"stains 5\n" +"stains -0.5\n" "}\n" ////////////////////////////////// @@ -1729,6 +1776,8 @@ char *particle_set_high = "randomvel 2\n" "friction 4\n" "scalefactor 0.825\n" +"spawnmode spiral\n" +"spawnvel 25\n" "blend add\n" "}\n" diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 7e3e9f014..6c29a1cd3 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2286,7 +2286,7 @@ void Surf_DrawWorld (void) ============================================================================= */ -#ifdef TERRAIN +#if 0//def TERRAIN // returns a texture number and the position inside it int Surf_LM_AllocBlock (int w, int h, int *x, int *y, shader_t *shader) { @@ -2685,9 +2685,7 @@ void Surf_DeInit(void) void Surf_Clear(model_t *mod) { - batch_t *b; vbo_t *vbo; - int i; if (mod->fromgame == fg_doom3) return;/*they're on the hunk*/ while(mod->vbos) @@ -2748,6 +2746,51 @@ void Surf_LightmapMode(void) } } +//needs to be followed by a BE_UploadAllLightmaps at some point +int Surf_NewLightmaps(int count, int width, int height) +{ + int first = numlightmaps; + int i, k; + + if (!count) + return -1; + + i = numlightmaps + count; + lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(i)); + while(i > first) + { + i--; + + lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*8 + sizeof(stmap)*3)*width*height); + lightmap[i]->width = width; + lightmap[i]->height = height; + lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1); + lightmap[i]->deluxmaps = (qbyte*)(lightmap[i]->lightmaps+4*width*height); + lightmap[i]->stainmaps = (stmap*)(lightmap[i]->deluxmaps+4*width*height); + + lightmap[i]->modified = true; +// lightmap[i]->shader = NULL; + lightmap[i]->external = false; + // reset stainmap since it now starts at 255 + memset(lightmap[i]->stainmaps, 255, width*height*3*sizeof(stmap)); + + //clear out the deluxmaps incase there is none on the map. + for (k = 0; k < width*height*3; k+=3) + { + lightmap[i]->deluxmaps[k+0] = 128; + lightmap[i]->deluxmaps[k+1] = 128; + lightmap[i]->deluxmaps[k+2] = 255; + } + + TEXASSIGN(lightmap[i]->lightmap_texture, R_AllocNewTexture("***lightmap***", width, height)); + TEXASSIGN(lightmap[i]->deluxmap_texture, R_AllocNewTexture("***deluxmap***", width, height)); + } + + numlightmaps += count; + + return first; +} + /* ================== GL_BuildLightmaps @@ -2759,16 +2802,13 @@ Groups surfaces into their respective batches (based on the lightmap number). */ void Surf_BuildLightmaps (void) { - int i, j, k, t; + int i, j, t; model_t *m; int shift; msurface_t *surf; - batch_t *batch, *bstop; - vec3_t sn; + batch_t *batch; int sortid; int ptype; - void *mem; - unsigned int memsize; int newfirst; r_framecount = 1; // no dlightcache @@ -2783,6 +2823,11 @@ void Surf_BuildLightmaps (void) Surf_LightmapMode(); + r_oldviewleaf = NULL; + r_oldviewleaf2 = NULL; + r_oldviewcluster = -1; + r_oldviewcluster2 = -1; + if (cl.worldmodel->fromgame == fg_doom) return; //no lightmaps. @@ -2793,6 +2838,12 @@ void Surf_BuildLightmaps (void) m = cl.model_precache[j]; if (!m) break; + +#ifdef TERRAIN + if (m->terrain) + Terr_PurgeTerrainModel(m, true); +#endif + if (m->type != mod_brush) continue; @@ -2807,41 +2858,7 @@ void Surf_BuildLightmaps (void) if (*m->name == '*' && m->fromgame == fg_quake3) //FIXME: should be all bsp formats newfirst = cl.model_precache[1]->lightmaps.first; else - { - newfirst = numlightmaps; - - i = numlightmaps + m->lightmaps.count; - lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(i)); - while(i > numlightmaps) - { - i--; - - lightmap[i] = Z_Malloc(sizeof(*lightmap[i]) + (sizeof(qbyte)*8 + sizeof(stmap)*3)*m->lightmaps.width*m->lightmaps.height); - lightmap[i]->width = m->lightmaps.width; - lightmap[i]->height = m->lightmaps.height; - lightmap[i]->lightmaps = (qbyte*)(lightmap[i]+1); - lightmap[i]->deluxmaps = (qbyte*)(lightmap[i]->lightmaps+4*lightmap[i]->width*lightmap[i]->height); - lightmap[i]->stainmaps = (stmap*)(lightmap[i]->deluxmaps+4*lightmap[i]->width*lightmap[i]->height); - - lightmap[i]->modified = true; - // lightmap[i]->shader = NULL; - lightmap[i]->external = false; - // reset stainmap since it now starts at 255 - memset(lightmap[i]->stainmaps, 255, LMBLOCK_WIDTH*LMBLOCK_HEIGHT*3*sizeof(stmap)); - - //clear out the deluxmaps incase there is none on the map. - for (k = 0; k < lightmap[i]->width*lightmap[i]->height*3; k+=3) - { - lightmap[i]->deluxmaps[k+0] = 128; - lightmap[i]->deluxmaps[k+1] = 128; - lightmap[i]->deluxmaps[k+2] = 255; - } - - TEXASSIGN(lightmap[i]->lightmap_texture, R_AllocNewTexture("***lightmap***", lightmap[i]->width, lightmap[i]->height)); - TEXASSIGN(lightmap[i]->deluxmap_texture, R_AllocNewTexture("***deluxmap***", lightmap[i]->width, lightmap[i]->height)); - } - numlightmaps += m->lightmaps.count; - } + newfirst = Surf_NewLightmaps(m->lightmaps.count, m->lightmaps.width, m->lightmaps.height); //fixup batch lightmaps for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) diff --git a/engine/client/render.h b/engine/client/render.h index 9034db804..4201ad770 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -222,7 +222,7 @@ typedef struct { int height; glRect_t rectchange; glRect_t deluxrectchange; -#ifdef TERRAIN +#if 0 //def TERRAIN int allocated[LMBLOCK_WIDTH]; #endif qbyte *lightmaps;//[4*LMBLOCK_WIDTH*LMBLOCK_HEIGHT]; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 1cd9ee731..8fdfceeca 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -210,8 +210,14 @@ extern cvar_t r_novis; extern cvar_t r_speeds; extern cvar_t r_waterwarp; +#ifdef ANDROID +//on android, these numbers seem to be generating major weirdness, so disable these. +cvar_t r_polygonoffset_submodel_factor = SCVAR("r_polygonoffset_submodel_factor", "0"); +cvar_t r_polygonoffset_submodel_offset = SCVAR("r_polygonoffset_submodel_offset", "0"); +#else cvar_t r_polygonoffset_submodel_factor = SCVAR("r_polygonoffset_submodel_factor", "0.05"); cvar_t r_polygonoffset_submodel_offset = SCVAR("r_polygonoffset_submodel_offset", "25"); +#endif cvar_t r_polygonoffset_stencil_factor = SCVAR("r_polygonoffset_stencil_factor", "0.01"); cvar_t r_polygonoffset_stencil_offset = SCVAR("r_polygonoffset_stencil_offset", "1"); @@ -2384,7 +2390,19 @@ void R_InitParticleTexture (void) data[y*16+x][3] = exptexture[x][y]*255/9.0; } } - explosiontexture = R_LoadTexture32("", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP); + explosiontexture = R_LoadTexture32("fte_fuzzyparticle", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP); + + for (x=0 ; x<16 ; x++) + { + for (y=0 ; y<16 ; y++) + { + data[y*16+x][0] = exptexture[x][y]*255/9.0; + data[y*16+x][1] = exptexture[x][y]*255/9.0; + data[y*16+x][2] = exptexture[x][y]*255/9.0; + data[y*16+x][3] = exptexture[x][y]*255/9.0; + } + } + R_LoadTexture32("fte_bloodparticle", 16, 16, data, IF_NOMIPMAP|IF_NOPICMIP); memset(data, 255, sizeof(data)); for (y = 0;y < PARTICLETEXTURESIZE;y++) diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 612c57368..0cba54448 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -225,6 +225,24 @@ static struct void *driverctx; /*capture driver context*/ } s_speex; +#ifdef SPEEX_STATIC +#define qspeex_lib_get_mode speex_lib_get_mode +#define qspeex_bits_init speex_bits_init +#define qspeex_bits_reset speex_bits_reset +#define qspeex_bits_write speex_bits_write + +#define qspeex_preprocess_state_init speex_preprocess_state_init +#define qspeex_preprocess_ctl speex_preprocess_ctl +#define qspeex_preprocess_run speex_preprocess_run + +#define qspeex_encoder_init speex_encoder_init +#define qspeex_encoder_ctl speex_encoder_ctl +#define qspeex_encode_int speex_encode_int + +#define qspeex_decoder_init speex_decoder_init +#define qspeex_decode_int speex_decode_int +#define qspeex_bits_read_from speex_bits_read_from +#else static const SpeexMode *(VARGS *qspeex_lib_get_mode)(int mode); static void (VARGS *qspeex_bits_init)(SpeexBits *bits); static void (VARGS *qspeex_bits_reset)(SpeexBits *bits); @@ -267,6 +285,7 @@ static dllfunction_t qspeexdspfuncs[] = {NULL} }; +#endif snd_capture_driver_t DSOUND_Capture; snd_capture_driver_t OSS_Capture; @@ -275,6 +294,8 @@ static qboolean S_Speex_Init(void) { int i; const SpeexMode *mode; + +#ifndef SPEEX_STATIC if (s_speex.inited) return s_speex.loaded; s_speex.inited = true; @@ -292,6 +313,7 @@ static qboolean S_Speex_Init(void) Con_Printf("libspeexdsp not found. Voice chat is not available.\n"); return false; } +#endif mode = qspeex_lib_get_mode(SPEEX_MODEID_NB); diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index cc4912b09..d3c9b7547 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -20,6 +20,9 @@ qboolean isDedicated = false; void *sys_window; /*public so the renderer can attach to the correct place*/ static qboolean sys_running = false; int sys_glesversion; +cvar_t sys_vibrate = CVAR("sys_vibrate", "1"); +cvar_t sys_osk = CVAR("sys_osk", "0"); //to be toggled +cvar_t sys_keepscreenon = CVAR("sys_keepscreenon", "1"); //to be toggled #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, DISTRIBUTION"Droid", __VA_ARGS__)) @@ -27,9 +30,23 @@ int sys_glesversion; static void *sys_memheap; static unsigned int sys_lastframe; -JNIEXPORT int JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj, +static unsigned int vibrateduration; + +void Sys_Vibrate(int count) +{ + vibrateduration = count*10*sys_vibrate.value; +} +JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_getvibrateduration(JNIEnv *env, jobject obj) +{ + unsigned int dur = vibrateduration; + vibrateduration = 0; + return dur; +} + +JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject obj, jfloat ax, jfloat ay, jfloat az) { + int ret; static vec3_t oac; #ifdef SERVERONLY SV_Frame(); @@ -38,6 +55,9 @@ JNIEXPORT int JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject o double tdelta = (now - sys_lastframe) * 0.001; if (oac[0] != ax || oac[1] != ay || oac[2] != az) { + //down: x= +9.8 + //left: y= -9.8 + //up: z= +9.8 CSQC_Accelerometer(ax, ay, az); oac[0] = ax; oac[1] = ay; @@ -47,9 +67,14 @@ JNIEXPORT int JNICALL Java_com_fteqw_FTEDroidEngine_frame(JNIEnv *env, jobject o sys_lastframe = now; #endif - if (key_dest == key_console || key_dest == key_message) - return 1; - return 0; + ret = 0; + if (key_dest == key_console || key_dest == key_message || (key_dest == key_game && cls.state == ca_disconnected) || sys_osk.ival) + ret |= 1; + if (vibrateduration) + ret |= 2; + if (sys_keepscreenon.ival) + ret |= 4; + return ret; } JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject obj, @@ -78,7 +103,7 @@ JNIEXPORT void JNICALL Java_com_fteqw_FTEDroidEngine_init(JNIEnv *env, jobject o parms.basedir = NULL; /*filled in later*/ parms.argc = 3; parms.argv = args; - parms.memsize = 16*1024*1024; + parms.memsize = 512*1024*1024; parms.membase = sys_memheap = malloc(parms.memsize); if (!parms.membase) { @@ -249,6 +274,9 @@ void Sys_SendKeyEvents(void) } void Sys_Init(void) { + Cvar_Register(&sys_vibrate, "android stuff"); + Cvar_Register(&sys_osk, "android stuff"); + Cvar_Register(&sys_keepscreenon, "android stuff"); } qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate) diff --git a/engine/client/view.c b/engine/client/view.c index 38cefa9fa..cde705aac 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -392,6 +392,10 @@ void V_ParseDamage (int pnum) if (count < 10) count = 10; +#ifdef ANDROID + Sys_Vibrate(count); +#endif + if (v_damagecshift.value >= 0) count *= v_damagecshift.value; diff --git a/engine/client/wad.c b/engine/client/wad.c index dc741292c..4b091e3f1 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -639,15 +639,12 @@ void Mod_ParseInfoFromEntityLump(model_t *wmodel, char *data, char *mapname) //a else if (!strcmp("fog", key)) { char *s; - Q_strncpyz(key, com_token, sizeof(key)); - s = COM_Parse(key); - cl.fog_density = atof(com_token); - s = COM_Parse(s); - cl.fog_colour[0] = atof(com_token); - s = COM_Parse(s); - cl.fog_colour[1] = atof(com_token); - s = COM_Parse(s); - cl.fog_colour[2] = atof(com_token); + void CL_Fog_f(void); + key[0] = 'f'; + key[1] = ' '; + Q_strncpyz(key+2, com_token, sizeof(key)-2); + Cmd_TokenizeString(key, false, false); + CL_Fog_f(); } else if (!strcmp("sky", key)) // for Quake2 maps { diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index a8b4f19e8..12a1acb46 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -233,7 +233,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef ANDROID #undef RTLIGHTS +#ifndef SPEEX_STATIC #undef VOICECHAT +#endif #undef TEXTEDITOR #endif #ifdef NACL @@ -360,6 +362,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #else #define PLATFORM "Win32" #endif + #elif defined(ANDROID) + #define PLATFORM "Android" /*technically also linux*/ #elif defined(__linux__) #if defined(__amd64__) #define PLATFORM "Linux64" diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 1eb111828..e06a3bafc 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -712,6 +712,7 @@ static float Alias_CalculateSkeletalNormals(galiasinfo_t *model) Z_Free(inversepose); Z_Free(normals); Z_Free(xyz); + Z_Free(mvert); model = next; modnum++; diff --git a/engine/common/common.c b/engine/common/common.c index b31a52c35..afb5e2b1a 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2210,7 +2210,7 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t continue; } } - if (*str == '&' && str[1] == 'c') + else if (*str == '&' && str[1] == 'c') { // ezQuake color codes @@ -2261,6 +2261,15 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t } } } + else if (*str == '&' && str[1] == 'r') + { + ext = (COLOR_WHITE << CON_FGSHIFT) | (ext&~CON_FGMASK); + if (!keepmarkup) + { + str+=2; + continue; + } + } messedup: if (!--outsize) break; @@ -2270,6 +2279,8 @@ messedup: { if (strchr("\n\r\t ", *str)) *out++ = (unsigned char)(*str++) | (ext&~CON_HIGHCHARSMASK); + else if (*str >= 32 && *str < 127 && !(ext&CON_HIGHCHARSMASK)) + *out++ = (unsigned char)(*str++) | ext; else *out++ = (unsigned char)(*str++) | ext | 0xe000; } @@ -3324,6 +3335,13 @@ void COM_Version_f (void) #endif } +void COM_CrashMe_f(void) +{ + int *crashaddr = (int*)0x05; + + *crashaddr = 0; +} + /* ================ COM_Init @@ -3360,7 +3378,7 @@ void COM_Init (void) Cmd_AddCommand ("flocate", COM_Locate_f); //prints the pak or whatever where this file can be found. Cmd_AddCommand ("version", COM_Version_f); //prints the pak or whatever where this file can be found. - Cmd_AddCommand ("crashme", (void*)1); //debugging feature, makes it jump to an invalid address + Cmd_AddCommand ("crashme", COM_CrashMe_f); COM_InitFilesystem (); COM_CheckRegistered (); diff --git a/engine/common/console.h b/engine/common/console.h index dcf74b34e..63a93d6df 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -169,7 +169,7 @@ void Con_PrintCon (console_t *con, char *txt); void Con_NotifyBox (char *text); // during startup for sound / cd warnings #ifdef CRAZYDEBUGGING -#define TRACE(x) Con_Printf x +#define TRACE(x) Sys_Printf x #else #define TRACE(x) #endif diff --git a/engine/common/fs.c b/engine/common/fs.c index 8196f8b21..d4eeb8ace 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -1645,6 +1645,40 @@ char *FS_GetBasedir(void) { return com_quakedir; } + +void FS_CleanDir(char *in, char *out, int outlen) +{ + char *end; + if (!outlen) + return; + end = in + strlen(in); + //skip over any trailing slashes + while (end > in) + { + if (end[-1] == '/' || end[-1] == '\\') + end--; + else + break; + } + + //skip over the path + while (end > in) + { + if (end[-1] != '/' && end[-1] != '\\') + end--; + else + break; + } + + //copy string into the dest + while (--outlen) + { + if (*end == '/' || *end == '\\' || !*end) + break; + *out++ = *end++; + } + *out = 0; +} /* ================ COM_Gamedir @@ -1654,9 +1688,9 @@ Sets the gamedir and path to a different directory. */ void COM_Gamedir (const char *dir) { + char thispath[64]; searchpath_t *next; - int plen, dlen; - char *p; + int dlen; qboolean isbase; if (!*dir || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") @@ -1674,41 +1708,18 @@ void COM_Gamedir (const char *dir) isbase = true; if (next->funcs == &osfilefuncs) { - p = next->handle; - plen = strlen(p); - if (plen == dlen) + FS_CleanDir(next->purepath, thispath, sizeof(thispath)); + if (!strcmp(dir, thispath)) { - //no basedir, maybe - if (!strcmp(p, dir)) + if (isbase && com_searchpaths == com_base_searchpaths) { - if (isbase && com_searchpaths == com_base_searchpaths) - { - Q_strncpyz (gamedirfile, dir, sizeof(gamedirfile)); - return; - } - if (!isbase) - return; - break; + Q_strncpyz (gamedirfile, dir, sizeof(gamedirfile)); + return; } + if (!isbase) + return; + break; } - else if (plen > dlen) - { - if (*(p+plen-dlen-1) == '/') - { - if (!strcmp(p+plen-dlen, dir)) - { - if (isbase && com_searchpaths == com_base_searchpaths) - { - Q_strncpyz (gamedirfile, dir, sizeof(gamedirfile)); - return; - } - if (!isbase) - return; - break; - } - } - } - } } @@ -1807,6 +1818,7 @@ void COM_Gamedir (const char *dir) #define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset r_particlesdesc \"spikeset tsshaft h2part\"\nset sv_maxspeed 640\nset watervis 1\nset r_wateralpha 0.5\nset sv_pupglow 1\nset cl_model_bobbing 1\nsv_sound_land \"fx/thngland.wav\"\n" /*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/ #define Q3CFG "gl_overbright 2\nseta model sarge\nseta headmodel sarge\nseta handicap 100\n" +#define RMQCFG "sv_bigcoords 1\n" typedef struct { const char *argname; //used if this was used as a parameter. @@ -1834,6 +1846,7 @@ const gamemode_info_t gamemode_info[] = { {"-spark", "spark", "Spark", {"base/src/progs.src", "base/qwprogs.dat", "base/pak0.pak"}, DMFCFG, {"base", }, "Spark"}, + {"-rmq", "rmq", "RMQ", {NULL}, RMQCFG, {"id1", "qw", "rmq", "fte"}, "Remake Quake"}, //supported commercial mods (some are currently only partially supported) {"-portals", "h2mp", "FTE-H2MP", {"portals/hexen.rc", @@ -2147,7 +2160,16 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) com_base_searchpaths = com_searchpaths; if (oldpaths->isexplicit) - FS_AddPathHandle(oldpaths->purepath, oldpaths->purepath, oldpaths->funcs, oldpaths->handle, oldpaths->copyprotected, false, true, reloadflags); + { + if (oldpaths->funcs == &osfilefuncs) + { + char pure[64]; + FS_CleanDir(oldpaths->purepath, pure, sizeof(pure)); + FS_AddPathHandle(pure, oldpaths->purepath, oldpaths->funcs, oldpaths->handle, oldpaths->copyprotected, false, true, reloadflags); + } + else + FS_AddPathHandle(oldpaths->purepath, oldpaths->purepath, oldpaths->funcs, oldpaths->handle, oldpaths->copyprotected, false, true, reloadflags); + } else oldpaths->funcs->ClosePath(oldpaths->handle); Z_Free(oldpaths); diff --git a/engine/common/log.c b/engine/common/log.c index 4355f84fc..de9bc1ec0 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -376,7 +376,7 @@ void Log_Init(void) // cmd line options, debug options #ifdef CRAZYDEBUGGING - Cvar_ForceSet(&log_enable, "1"); + Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1"); TRACE(("dbg: Con_Init: log_enable forced\n")); #endif diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index f1cacd879..afee8ca38 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -3583,7 +3583,7 @@ lh_extension_t QSG_Extensions[] = { {"EXT_CSQC_SHARED"}, //this is a separate extension because it requires protocol modifications. note: this is also the extension that extends the allowed stats. - {NULL}, + {"PEXT_DPFLAGS"}, //{"EXT_CSQC"}, //this is the base csqc extension. I'm not sure what needs to be separate and what does not. //{"EXT_CSQC_DELTAS"},//this is a separate extension because the feature may be banned in a league due to cheat protection. diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index af0f28a38..16de02a24 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -500,4 +500,4 @@ enum GE_ABSMIN = 14, GE_ABSMAX = 15, GE_LIGHT = 16 -}; \ No newline at end of file +}; diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 24c9305cc..274825e7c 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -1,6 +1,8 @@ #include "quakedef.h" #include "pr_common.h" + +qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, trace_t *trace); /* ============================================================================ @@ -998,6 +1000,14 @@ qboolean Q1BSP_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3] } } + if (model->terrain && trace->fraction) + { + trace_t hmt; + Heightmap_Trace(model, forcehullnum, frame, axis, start, end, mins, maxs, hitcontentsmask, &hmt); + if (hmt.fraction < trace->fraction) + *trace = hmt; + } + return trace->fraction != 1; } diff --git a/engine/common/sys.h b/engine/common/sys.h index e46712915..2ab7ed836 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -85,6 +85,8 @@ void Sys_SendKeyEvents (void); int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm); +void Sys_Vibrate(int count); + qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate); #ifdef MULTITHREAD diff --git a/engine/common/zone.c b/engine/common/zone.c index cdc2cd9ed..eb1d979b2 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -1384,7 +1384,7 @@ void *Hunk_AllocName (int size, char *name) #ifdef _WIN32 Sys_Error ("Not enough RAM allocated on allocation of \"%s\". Try starting using \"-heapsize 16000\" on the QuakeWorld command line.", name); #else - Sys_Error ("Not enough RAM allocated. Try starting using \"-mem 16\" on the QuakeWorld command line."); + Sys_Error ("Not enough RAM allocated. Try starting using \"-mem %u\" on the QuakeWorld command line.", (hunk_size + 8*1024*1024) / 1024*1024); #endif #endif diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index c515e0d8c..cfd77bf50 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -1069,9 +1069,6 @@ static void (D3D9_SCR_UpdateScreen) (void) scr_con_forcedraw = false; if (noworld) { - if ((key_dest == key_console || key_dest == key_game) && SCR_GetLoadingStage() == LS_NONE) - scr_con_current = vid.height; - if (scr_con_current != vid.height) R2D_ConsoleBackground(0, vid.height, true); else diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 9f987525b..10308c913 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -20879,6 +20879,170 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21207,6 +21371,170 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/droid/AndroidManifest.xml b/engine/droid/AndroidManifest.xml index b9208c8c1..20dc4c94c 100644 --- a/engine/droid/AndroidManifest.xml +++ b/engine/droid/AndroidManifest.xml @@ -7,6 +7,7 @@ + type == mod_heightmap) - GL_DrawHeightmapModel(batches, &r_worldentity); + if (cl.worldmodel && cl.worldmodel->terrain) + Terr_DrawTerrainModel(batches, &r_worldentity); #endif if (!r_drawentities.ival) diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index c07543ca8..4b50b2750 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1618,12 +1618,24 @@ static void colourgen(const shaderpass_t *pass, int cnt, vec4_t *src, vec4_t *ds } break; case RGB_GEN_IDENTITY_LIGHTING: - //compensate for overbrights - while((cnt)--) + if (shaderstate.curbatch->lightstyle[0] != 255) { - dst[cnt][0] = shaderstate.identitylighting; - dst[cnt][1] = shaderstate.identitylighting; - dst[cnt][2] = shaderstate.identitylighting; + while((cnt)--) + { + dst[cnt][0] = shaderstate.identitylighting * d_lightstylevalue[shaderstate.curbatch->lightstyle[0]]/256.0f; + dst[cnt][1] = shaderstate.identitylighting * d_lightstylevalue[shaderstate.curbatch->lightstyle[0]]/256.0f; + dst[cnt][2] = shaderstate.identitylighting * d_lightstylevalue[shaderstate.curbatch->lightstyle[0]]/256.0f; + } + } + else + { + //compensate for overbrights + while((cnt)--) + { + dst[cnt][0] = shaderstate.identitylighting; + dst[cnt][1] = shaderstate.identitylighting; + dst[cnt][2] = shaderstate.identitylighting; + } } break; default: @@ -3525,6 +3537,7 @@ void GLBE_DrawMesh_List(shader_t *shader, int nummeshes, mesh_t **meshlist, vbo_ shaderstate.sourcevbo = &shaderstate.dummyvbo; shaderstate.curshader = shader; shaderstate.flags = beflags; + TRACE(("GLBE_DrawMesh_List: shader %s\n", shader->name)); if (shaderstate.curentity != &r_worldentity) { BE_SelectEntity(&r_worldentity); @@ -3719,10 +3732,15 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) continue; if (batch->buildmeshes) + { + TRACE(("GLBE_SubmitMeshesSortList: build\n")); batch->buildmeshes(batch); + } else if (batch->texture) batch->shader = R_TextureAnimation(batch->ent->framestate.g[FS_REG].frame[0], batch->texture)->shader; + TRACE(("GLBE_SubmitMeshesSortList: shader %s\n", batch->shader->name)); + if (batch->shader->flags & SHADER_NODRAW) continue; if (batch->shader->flags & SHADER_NODLIGHT) @@ -4111,6 +4129,8 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) GL_DoSwap(); + TRACE(("GLBE_DrawWorld: %i %p\n", drawworld, vis)); + if (!r_refdef.recurse) { if (shaderstate.wbatch + 50 > shaderstate.maxwbatches) @@ -4210,9 +4230,11 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) if (vis) { RSpeedRemark(); + TRACE(("GLBE_DrawWorld: drawing lights\n")); BE_SelectEntity(&r_worldentity); Sh_DrawLights(vis); RSpeedEnd(RSPEED_STENCILSHADOWS); + TRACE(("GLBE_DrawWorld: lights drawn\n")); } #endif @@ -4239,5 +4261,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) shaderstate.identitylighting = 1; shaderstate.mbatches = ob; + + TRACE(("GLBE_DrawWorld: drawn everything\n")); } #endif diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 0a81e6477..ce8d9d1cb 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1522,8 +1522,8 @@ float Font_DrawScaleChar(float px, float py, float cw, float ch, unsigned int ch } else { - sx = ((px+c->left)); - sy = ((py+c->top)); + sx = ((px+(c->left*(int)vid.width) / (float)vid.rotpixelwidth)); + sy = ((py+(c->top*(int)vid.height) / (float)vid.rotpixelheight)); sw = ((c->bmw*cw)); sh = ((c->bmh*ch)); v = Font_BeginChar(fontplanes.texnum[c->texplane]); diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index aa411fb72..eaa262bcf 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -6,8 +6,6 @@ #include "pr_common.h" -int Surf_LM_AllocBlock (int w, int h, int *x, int *y, shader_t *shader); - //heightmaps work thusly: //there is one raw heightmap file //the file is split to 4*4 sections. @@ -17,21 +15,47 @@ int Surf_LM_AllocBlock (int w, int h, int *x, int *y, shader_t *shader); //we get 20->130 //perhaps we should build it with multitexture? (no - slower on ati) +int Surf_NewLightmaps(int count, int width, int height); + #define MAXSECTIONS 64 //this many sections max in each direction #define SECTTEXSIZE 64 //this many texture samples per section #define SECTHEIGHTSIZE 16 //this many height samples per section +//each section is this many sections higher in world space, to keep the middle centered at '0 0' +#define CHUNKBIAS (MAXSECTIONS*MAXSECTIONS/2) +#define CHUNKLIMIT (MAXSECTIONS*MAXSECTIONS) + +#define LMCHUNKS 2 + +#define HMLMSTRIDE (LMCHUNKS*SECTTEXSIZE) + +#define SECTION_MAGIC (*(int*)"HMMS") +#define SECTION_VER 0 + +enum +{ + SECTION_HASWATER = 1, +}; + typedef struct { + int magic; + int ver; + unsigned int flags; char texname[4][32]; unsigned int texmap[SECTTEXSIZE][SECTTEXSIZE]; float heights[SECTHEIGHTSIZE*SECTHEIGHTSIZE]; unsigned short holes; + float waterheight; } dsection_t; typedef struct { float heights[SECTHEIGHTSIZE*SECTHEIGHTSIZE]; unsigned short holes; + unsigned int flags; + float waterheight; + struct heightmap_s *hmmod; + #ifndef SERVERONLY char texname[4][32]; int lightmap; @@ -39,74 +63,142 @@ typedef struct texnums_t textures; vbo_t vbo; - unsigned short minh, maxh; + float minh, maxh; mesh_t mesh; mesh_t *amesh; qboolean modified:1; #endif } hmsection_t; -typedef struct { - char path[MAX_QPATH]; - int numsegsx, numsegsy; //tex/cull sections - float sectionsize; //each section is this big, in world coords +typedef struct +{ hmsection_t *section[MAXSECTIONS*MAXSECTIONS]; +} hmcluster_t; +typedef struct heightmap_s { + char path[MAX_QPATH]; + int firstsegx, firstsegy; + int maxsegx, maxsegy; //tex/cull sections + float sectionsize; //each section is this big, in world coords + hmcluster_t *cluster[MAXSECTIONS*MAXSECTIONS]; shader_t *skyshader; shader_t *shader; mesh_t skymesh; mesh_t *askymesh; + unsigned int exteriorcontents; + + struct lmsect_s + { + struct lmsect_s *next; + int lm, x, y; + } *unusedlmsects; } heightmap_t; -static void GL_LoadSectionTextures(hmsection_t *s) +static void Terr_LoadSectionTextures(hmsection_t *s) { #ifndef SERVERONLY + extern texid_t missing_texture; //CL_CheckOrEnqueDownloadFile(s->texname[0], NULL, 0); //CL_CheckOrEnqueDownloadFile(s->texname[1], NULL, 0); //CL_CheckOrEnqueDownloadFile(s->texname[2], NULL, 0); //CL_CheckOrEnqueDownloadFile(s->texname[3], NULL, 0); - s->textures.base = R_LoadHiResTexture(s->texname[0], NULL, 0); - s->textures.upperoverlay = R_LoadHiResTexture(s->texname[1], NULL, 0); - s->textures.loweroverlay = R_LoadHiResTexture(s->texname[2], NULL, 0); - s->textures.fullbright = R_LoadHiResTexture(s->texname[3], NULL, 0); - s->textures.bump = R_LoadHiResTexture(va("%s_norm", s->texname[0]), NULL, 0); - s->textures.specular = R_LoadHiResTexture(va("%s_spec", s->texname[0]), NULL, 0); + s->textures.base = *s->texname[0]?R_LoadHiResTexture(s->texname[0], NULL, 0):missing_texture; + s->textures.upperoverlay = *s->texname[1]?R_LoadHiResTexture(s->texname[1], NULL, 0):missing_texture; + s->textures.loweroverlay = *s->texname[2]?R_LoadHiResTexture(s->texname[2], NULL, 0):missing_texture; + s->textures.fullbright = *s->texname[3]?R_LoadHiResTexture(s->texname[3], NULL, 0):missing_texture; + s->textures.bump = *s->texname[0]?R_LoadHiResTexture(va("%s_norm", s->texname[0]), NULL, 0):r_nulltex; + s->textures.specular = *s->texname[0]?R_LoadHiResTexture(va("%s_spec", s->texname[0]), NULL, 0):r_nulltex; #endif } -static char *GL_DiskSectionName(heightmap_t *hm, int sx, int sy) +static void Terr_InitLightmap(hmsection_t *s) { - return va("maps/%s/sect_%02i_%02i.hms", hm->path, sx, sy); + heightmap_t *hm = s->hmmod; + struct lmsect_s *lms; + + if (!hm->unusedlmsects) + { + int lm; + int i; + lm = Surf_NewLightmaps(1, SECTTEXSIZE*LMCHUNKS, SECTTEXSIZE*LMCHUNKS); + for (i = 0; i < LMCHUNKS*LMCHUNKS; i++) + { + lms = malloc(sizeof(*lms)); + lms->lm = lm; + BE_UploadAllLightmaps(); + lms->x = (i & (LMCHUNKS-1))*SECTTEXSIZE; + lms->y = (i / LMCHUNKS)*SECTTEXSIZE; + lms->next = hm->unusedlmsects; + hm->unusedlmsects = lms; + } + } + + lms = hm->unusedlmsects; + hm->unusedlmsects = lms->next; + + s->lightmap = lms->lm; + s->lmx = lms->x; + s->lmy = lms->y; + + free(lms); } -static hmsection_t *GL_LoadSection(heightmap_t *hm, int sx, int sy) + +static char *Terr_DiskSectionName(heightmap_t *hm, int sx, int sy) { - hmsection_t *s; - dsection_t *ds; + sx -= CHUNKBIAS; + sy -= CHUNKBIAS; + //wrap cleanly + sx &= CHUNKLIMIT-1; + sy &= CHUNKLIMIT-1; + return va("maps/%s/sect_%03x_%03x.hms", hm->path, sx, sy); +} +static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) +{ + dsection_t *ds = NULL; int i; #ifndef SERVERONLY unsigned char *lm; #endif - s = malloc(sizeof(*s)); - if (!s) + /*queue the file for download if we don't have it yet*/ + if (FS_LoadFile(Terr_DiskSectionName(hm, sx, sy), &ds) < 0 +#ifndef CLIENTONLY + && !sv.state +#endif + ) + { + CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, sx, sy), NULL, 0); return NULL; - memset(s, 0, sizeof(*s)); + } + + if (ds) + { + if (ds->magic != SECTION_MAGIC) + return NULL; + if (ds->ver != SECTION_VER) + return NULL; + } + + if (!s) + { + s = malloc(sizeof(*s)); + if (!s) + { + FS_FreeFile(ds); + return NULL; + } + memset(s, 0, sizeof(*s)); + s->lightmap = -1; + } + + s->hmmod = hm; #ifndef SERVERONLY - s->lightmap = -1; - - Q_strncpyz(s->texname[0], va("maps/%s/grass", hm->path), sizeof(s->texname[0])); - Q_strncpyz(s->texname[1], va("maps/%s/rock", hm->path), sizeof(s->texname[1])); - Q_strncpyz(s->texname[2], va("maps/%s/road", hm->path), sizeof(s->texname[2])); - Q_strncpyz(s->texname[3], va("maps/%s/ground", hm->path), sizeof(s->texname[3])); s->modified = true; - if (s->lightmap < 0) - { - s->lightmap = Surf_LM_AllocBlock(SECTTEXSIZE, SECTTEXSIZE, &s->lmx, &s->lmy, hm->shader); - BE_UploadAllLightmaps(); - } + if (s->lightmap < 0 && qrenderer != QR_NONE) + Terr_InitLightmap(s); #endif - if (FS_LoadFile(GL_DiskSectionName(hm, sx, sy), &ds) >= 0) + if (ds) { #ifndef SERVERONLY Q_strncpyz(s->texname[0], ds->texname[0], sizeof(s->texname[0])); @@ -114,18 +206,26 @@ static hmsection_t *GL_LoadSection(heightmap_t *hm, int sx, int sy) Q_strncpyz(s->texname[2], ds->texname[2], sizeof(s->texname[2])); Q_strncpyz(s->texname[3], ds->texname[3], sizeof(s->texname[3])); - lm = lightmap[s->lightmap]->lightmaps; - lm += (s->lmx * LMBLOCK_WIDTH + s->lmy) * lightmap_bytes; - for (i = 0; i < SECTTEXSIZE; i++) + CL_CheckOrEnqueDownloadFile(s->texname[0], NULL, 0); + CL_CheckOrEnqueDownloadFile(s->texname[1], NULL, 0); + CL_CheckOrEnqueDownloadFile(s->texname[2], NULL, 0); + CL_CheckOrEnqueDownloadFile(s->texname[3], NULL, 0); + + if (s->lightmap >= 0) { - memcpy(lm, ds->texmap + i, sizeof(ds->texmap[0])); - lm += (LMBLOCK_WIDTH)*lightmap_bytes; + lm = lightmap[s->lightmap]->lightmaps; + lm += (s->lmx * HMLMSTRIDE + s->lmy) * lightmap_bytes; + for (i = 0; i < SECTTEXSIZE; i++) + { + memcpy(lm, ds->texmap + i, sizeof(ds->texmap[0])); + lm += (HMLMSTRIDE)*lightmap_bytes; + } + lightmap[s->lightmap]->modified = true; + lightmap[s->lightmap]->rectchange.l = 0; + lightmap[s->lightmap]->rectchange.t = 0; + lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE; + lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE; } - lightmap[s->lightmap]->modified = true; - lightmap[s->lightmap]->rectchange.l = 0; - lightmap[s->lightmap]->rectchange.t = 0; - lightmap[s->lightmap]->rectchange.w = LMBLOCK_WIDTH; - lightmap[s->lightmap]->rectchange.h = LMBLOCK_HEIGHT; #endif /*load the heights too*/ @@ -152,7 +252,7 @@ static hmsection_t *GL_LoadSection(heightmap_t *hm, int sx, int sy) if (splatter) { lm = lightmap[s->lightmap]->lightmaps; - lm += (s->lmx * LMBLOCK_WIDTH + s->lmy) * lightmap_bytes; + lm += (s->lmx * HMLMSTRIDE + s->lmy) * lightmap_bytes; for (vx = 0; vx < SECTTEXSIZE; vx++) { @@ -171,15 +271,15 @@ static hmsection_t *GL_LoadSection(heightmap_t *hm, int sx, int sy) lm[3] = splatter[(y + x*sh)*4+3]; lm += 4; } - lm += (LMBLOCK_WIDTH - SECTTEXSIZE)*lightmap_bytes; + lm += (HMLMSTRIDE - SECTTEXSIZE)*lightmap_bytes; } BZ_Free(splatter); lightmap[s->lightmap]->modified = true; lightmap[s->lightmap]->rectchange.l = 0; lightmap[s->lightmap]->rectchange.t = 0; - lightmap[s->lightmap]->rectchange.w = LMBLOCK_WIDTH; - lightmap[s->lightmap]->rectchange.h = LMBLOCK_HEIGHT; + lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE; + lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE; } FS_FreeFile(f); } @@ -224,78 +324,175 @@ static hmsection_t *GL_LoadSection(heightmap_t *hm, int sx, int sy) #endif } - GL_LoadSectionTextures(s); - - hm->section[sx+sy*MAXSECTIONS] = s; + Terr_LoadSectionTextures(s); return s; } -static void GL_SaveSection(heightmap_t *hm, int sx, int sy) +static void Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) { #ifndef SERVERONLY - hmsection_t *s = hm->section[sx+sy*MAXSECTIONS]; dsection_t ds; unsigned char *lm; int i; + //if its invalid or doesn't contain all the data... if (!s || s->lightmap < 0) return; + ds.magic = SECTION_MAGIC; + ds.ver = SECTION_VER; + ds.flags = 0; + Q_strncpyz(ds.texname[0], s->texname[0], sizeof(ds.texname[0])); Q_strncpyz(ds.texname[1], s->texname[1], sizeof(ds.texname[1])); Q_strncpyz(ds.texname[2], s->texname[2], sizeof(ds.texname[2])); Q_strncpyz(ds.texname[3], s->texname[3], sizeof(ds.texname[3])); lm = lightmap[s->lightmap]->lightmaps; - lm += (s->lmx * LMBLOCK_WIDTH + s->lmy) * lightmap_bytes; + lm += (s->lmx * HMLMSTRIDE + s->lmy) * lightmap_bytes; for (i = 0; i < SECTTEXSIZE; i++) { memcpy(ds.texmap + i, lm, sizeof(ds.texmap[0])); - lm += (LMBLOCK_WIDTH)*lightmap_bytes; + lm += (HMLMSTRIDE)*lightmap_bytes; } for (i = 0; i < SECTHEIGHTSIZE*SECTHEIGHTSIZE; i++) { ds.heights[i] = LittleFloat(s->heights[i]); } + ds.holes = s->holes; - FS_WriteFile(GL_DiskSectionName(hm, sx, sy), &ds, sizeof(ds), FS_GAMEONLY); + FS_WriteFile(Terr_DiskSectionName(hm, sx, sy), &ds, sizeof(ds), FS_GAMEONLY); #endif } +/*convienience function*/ +static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean doload) +{ + hmcluster_t *cluster; + hmsection_t *section; + int cx = x / MAXSECTIONS; + int cy = y / MAXSECTIONS; + int sx = x & (MAXSECTIONS-1); + int sy = y & (MAXSECTIONS-1); + cluster = hm->cluster[cx + cy*MAXSECTIONS]; + if (!cluster) + { + if (doload) + { + cluster = malloc(sizeof(*cluster)); + memset(cluster, 0, sizeof(*cluster)); + hm->cluster[cx + cy*MAXSECTIONS] = cluster; + } + else + return NULL; + } + section = cluster->section[sx + sy*MAXSECTIONS]; + if (!section) + { + if (doload) + { + section = cluster->section[sx + sy*MAXSECTIONS] = Terr_LoadSection(hm, section, x, y); + } + } + return section; +} + /*save all currently loaded sections*/ void HeightMap_Save(heightmap_t *hm) { hmsection_t *s; int x, y; - for (x = 0; x < hm->numsegsx; x++) + for (x = hm->firstsegx; x < hm->maxsegx; x++) { - for (y = 0; y < hm->numsegsy; y++) + for (y = hm->firstsegy; y < hm->maxsegy; y++) { - s = hm->section[x+y*MAXSECTIONS]; - GL_SaveSection(hm, x, y); + s = Terr_GetSection(hm, x, y, false); + if (!s) + continue; + Terr_SaveSection(hm, s, x, y); } } } -/*purge all sections*/ -void HeightMap_Purge(model_t *mod) +void Terr_DestroySection(heightmap_t *hm, hmsection_t *s) +{ + if (hm && s->lightmap >= 0) + { + struct lmsect_s *lms; + + lms = malloc(sizeof(*lms)); + lms->lm = s->lightmap; + lms->x = s->lmx; + lms->y = s->lmy; + lms->next = hm->unusedlmsects; + hm->unusedlmsects = lms; + } + +#ifdef GLQUAKE + if (qrenderer == QR_OPENGL) + { + qglDeleteBuffersARB(1, &s->vbo.coord.gl.vbo); + qglDeleteBuffersARB(1, &s->vbo.indicies.gl.vbo); + } +#endif + + free(s->mesh.xyz_array); + free(s->mesh.indexes); + free(s); +} + +/*purge all sections +lightmaps only are purged whenever the client rudely kills lightmaps +we'll reload those when its next seen. +(lightmaps will already have been destroyed, so no poking them) +*/ +void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly) { heightmap_t *hm = mod->terrain; + hmcluster_t *c; hmsection_t *s; - int x, y; - for (x = 0; x < hm->numsegsx; x++) + int cx, cy; + int sx, sy; + for (cy = 0; cy < MAXSECTIONS; cy++) + for (cx = 0; cx < MAXSECTIONS; cx++) { - for (y = 0; y < hm->numsegsy; y++) + c = hm->cluster[cx + cy*MAXSECTIONS]; + if (!c) + continue; + + for (sy = 0; sy < MAXSECTIONS; sy++) + for (sx = 0; sx < MAXSECTIONS; sx++) { - s = hm->section[x+y*MAXSECTIONS]; - hm->section[x+y*MAXSECTIONS] = NULL; - free(s); + s = c->section[sx + sy*MAXSECTIONS]; + if (!s) + { + } + else if (lightmapsonly) + s->lightmap = -1; + else + { + c->section[sx+sy*MAXSECTIONS] = NULL; + + Terr_DestroySection(NULL, s); + } } + if (!lightmapsonly) + { + hm->cluster[cx + cy*MAXSECTIONS] = NULL; + free(c); + } + } + while (hm->unusedlmsects) + { + struct lmsect_s *lms; + lms = hm->unusedlmsects; + hm->unusedlmsects = lms->next; + free(lms); } } #ifndef SERVERONLY -void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) +void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) { //a 512*512 heightmap //will draw 2 tris per square, drawn twice for detail @@ -309,6 +506,7 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) mesh_t *mesh; batch_t *b; hmsection_t *s; + int bounds[4]; if (e->model == cl.worldmodel) { @@ -336,22 +534,56 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) } } - for (x = 0; x < hm->numsegsx; x++) + if (r_refdef.gfog_rgbd[3] || gl_maxdist.value>0) { - mins[0] = (x+0)*hm->sectionsize; - maxs[0] = (x+1)*hm->sectionsize; - for (y = 0; y < hm->numsegsy; y++) - { - mins[1] = (y+0)*hm->sectionsize; - maxs[1] = (y+1)*hm->sectionsize; + float culldist; + extern cvar_t r_fog_exp2; - s = hm->section[x+y*MAXSECTIONS]; + if (r_refdef.gfog_rgbd[3]) + { + //figure out the eyespace distance required to reach that fog value + culldist = log(0.5/255.0f); + if (r_fog_exp2.ival) + culldist = sqrt(culldist / (-r_refdef.gfog_rgbd[3] * r_refdef.gfog_rgbd[3])); + else + culldist = culldist / (-r_refdef.gfog_rgbd[3]); + //anything drawn beyond this point is fully obscured by fog + culldist += 4096; + } + else + culldist = 999999999999999; + + if (culldist > gl_maxdist.value && gl_maxdist.value>0) + culldist = gl_maxdist.value; + + bounds[0] = bound(hm->firstsegx, (r_refdef.vieworg[0] + (CHUNKBIAS + 0)*hm->sectionsize - culldist) / hm->sectionsize, hm->maxsegx); + bounds[1] = bound(hm->firstsegx, (r_refdef.vieworg[0] + (CHUNKBIAS + 1)*hm->sectionsize + culldist) / hm->sectionsize, hm->maxsegx); + bounds[2] = bound(hm->firstsegy, (r_refdef.vieworg[1] + (CHUNKBIAS + 0)*hm->sectionsize - culldist) / hm->sectionsize, hm->maxsegy); + bounds[3] = bound(hm->firstsegy, (r_refdef.vieworg[1] + (CHUNKBIAS + 1)*hm->sectionsize + culldist) / hm->sectionsize, hm->maxsegy); + } + else + { + bounds[0] = hm->firstsegx; + bounds[1] = hm->maxsegx; + bounds[2] = hm->firstsegy; + bounds[3] = hm->maxsegy; + } + + for (x = bounds[0]; x < bounds[1]; x++) + { + mins[0] = (x+0 - CHUNKBIAS)*hm->sectionsize; + maxs[0] = (x+1 - CHUNKBIAS)*hm->sectionsize; + for (y = bounds[2]; y < bounds[3]; y++) + { + mins[1] = (y+0 - CHUNKBIAS)*hm->sectionsize; + maxs[1] = (y+1 - CHUNKBIAS)*hm->sectionsize; + + s = Terr_GetSection(hm, x, y, true); if (!s) - { - s = GL_LoadSection(hm, x, y); - if (!s) - continue; - } + continue; + if (s->lightmap < 0) + Terr_LoadSection(hm, s, x, y); + mesh = &s->mesh; if (s->modified) { @@ -362,12 +594,11 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) if (s->lightmap < 0) { - s->lightmap = Surf_LM_AllocBlock(SECTTEXSIZE, SECTTEXSIZE, &s->lmx, &s->lmy, hm->shader); - BE_UploadAllLightmaps(); + Terr_InitLightmap(s); } - s->minh = 999999999999999; - s->maxh = -999999999999999; + s->minh = 9999999999999999; + s->maxh = -9999999999999999; if (!mesh->xyz_array) { @@ -382,8 +613,8 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) for (vy = 0; vy < SECTHEIGHTSIZE; vy++) { v = mesh->numvertexes++; - mesh->xyz_array[v][0] = (x + vx/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; - mesh->xyz_array[v][1] = (y + vy/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; + mesh->xyz_array[v][0] = (x-CHUNKBIAS + vx/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; + mesh->xyz_array[v][1] = (y-CHUNKBIAS + vy/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; mesh->xyz_array[v][2] = s->heights[vx + vy*SECTHEIGHTSIZE]; if (s->maxh < mesh->xyz_array[v][2]) @@ -391,18 +622,18 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) if (s->minh > mesh->xyz_array[v][2]) s->minh = mesh->xyz_array[v][2]; - mesh->st_array[v][0] = mesh->xyz_array[v][0] / 64; - mesh->st_array[v][1] = mesh->xyz_array[v][1] / 64; + mesh->st_array[v][0] = mesh->xyz_array[v][0] / 128; + mesh->st_array[v][1] = mesh->xyz_array[v][1] / 128; //calc the position in the range -0.5 to 0.5 mesh->lmst_array[0][v][0] = (((float)vx / (SECTHEIGHTSIZE-1))-0.5); mesh->lmst_array[0][v][1] = (((float)vy / (SECTHEIGHTSIZE-1))-0.5); //scale down to a half-texel - mesh->lmst_array[0][v][0] *= (SECTTEXSIZE-1.0f)/LMBLOCK_WIDTH; - mesh->lmst_array[0][v][1] *= (SECTTEXSIZE-1.0f)/LMBLOCK_HEIGHT; + mesh->lmst_array[0][v][0] *= (SECTTEXSIZE-1.0f)/HMLMSTRIDE; + mesh->lmst_array[0][v][1] *= (SECTTEXSIZE-1.0f)/HMLMSTRIDE; //bias it - mesh->lmst_array[0][v][0] += ((float)SECTTEXSIZE/(LMBLOCK_WIDTH*2)) + ((float)(s->lmy) / LMBLOCK_WIDTH); - mesh->lmst_array[0][v][1] += ((float)SECTTEXSIZE/(LMBLOCK_HEIGHT*2)) + ((float)(s->lmx) / LMBLOCK_HEIGHT); + mesh->lmst_array[0][v][0] += ((float)SECTTEXSIZE/(HMLMSTRIDE*2)) + ((float)(s->lmy) / HMLMSTRIDE); + mesh->lmst_array[0][v][1] += ((float)SECTTEXSIZE/(HMLMSTRIDE*2)) + ((float)(s->lmx) / HMLMSTRIDE); //TODO: include colour tints } @@ -416,16 +647,36 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) { for (vy = 0; vy < SECTHEIGHTSIZE-1; vy++) { - //TODO: holes - if (s->holes & (vx / (SECTHEIGHTSIZE/4)) << (vy / (SECTHEIGHTSIZE/4)) ) + float d1,d2; + int holebit; + + //skip generation of the mesh above holes + holebit = (vy / (SECTHEIGHTSIZE/4))+(vx / (SECTHEIGHTSIZE/4))*4; + holebit = 1u<holes & holebit) continue; v = vx + vy*(SECTHEIGHTSIZE); - mesh->indexes[mesh->numindexes++] = v+0; - mesh->indexes[mesh->numindexes++] = v+1; - mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; - mesh->indexes[mesh->numindexes++] = v+1; - mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; - mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + + d1 = fabs(mesh->xyz_array[v][2] - mesh->xyz_array[v+1+SECTHEIGHTSIZE][2]); + d2 = fabs(mesh->xyz_array[v+1][2] - mesh->xyz_array[v+SECTHEIGHTSIZE][2]); + if (d1 > d2) + { + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + } + else + { + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + } } } @@ -440,7 +691,7 @@ void GL_DrawHeightmapModel (batch_t **batches, entity_t *e) GL_SelectVBO(0); s->vbo.texcoord.gl.addr = (void*)((char*)mesh->st_array - (char*)mesh->xyz_array); s->vbo.texcoord.gl.vbo = s->vbo.coord.gl.vbo; - s->vbo.lmcoord[0].gl.addr = (void*)((char*)mesh->lmst_array - (char*)mesh->xyz_array); + s->vbo.lmcoord[0].gl.addr = (void*)((char*)mesh->lmst_array[0] - (char*)mesh->xyz_array); s->vbo.lmcoord[0].gl.vbo = s->vbo.coord.gl.vbo; // Z_Free(mesh->xyz_array); // mesh->xyz_array = NULL; @@ -496,31 +747,36 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t float x, y; float z, tz; int sx, sy; - int sectidx; + unsigned int holebit; hmsection_t *s; + const float wbias = CHUNKBIAS * hm->sectionsize; - sx = org[0]/hm->sectionsize; - sy = org[1]/hm->sectionsize; - if (sx < 0 || sy < 0) - return FTECONTENTS_SOLID; - if (sx >= hm->numsegsx || sy >= hm->numsegsy) - return FTECONTENTS_SOLID; - sectidx = sx + sy*MAXSECTIONS; - s = hm->section[sectidx]; + sx = (org[0]+wbias)/hm->sectionsize; + sy = (org[1]+wbias)/hm->sectionsize; + if (sx < hm->firstsegx || sy < hm->firstsegy) + return hm->exteriorcontents; + if (sx >= hm->maxsegx || sy >= hm->maxsegy) + return hm->exteriorcontents; + s = Terr_GetSection(hm, sx, sy, true); if (!s) { - s = GL_LoadSection(hm, sx, sy); - if (!s) - return FTECONTENTS_SOLID; + return FTECONTENTS_SOLID; } - x = (org[0] - (sx*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; - y = (org[1] - (sy*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; + x = (org[0]+wbias - (sx*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; + y = (org[1]+wbias - (sy*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; z = (org[2]+clipmipsz); + if (z < s->minh-16) + return hm->exteriorcontents; + sx = x; x-=sx; sy = y; y-=sy; + holebit = sx*4/SECTHEIGHTSIZE + (sy*4/SECTHEIGHTSIZE)*4; + if (s->holes & (1u<1) //the 1, 1 triangle { @@ -551,6 +807,9 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t } if (z <= tz) return FTECONTENTS_SOLID; //contained within + if (s->flags & SECTION_HASWATER) + if (z < s->waterheight) + return FTECONTENTS_WATER; return FTECONTENTS_EMPTY; } @@ -1056,19 +1315,30 @@ static unsigned char *ted_getlightmap(hmsection_t *s, int idx) int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE; if (s->lightmap < 0) { - s->lightmap = Surf_LM_AllocBlock(SECTTEXSIZE, SECTTEXSIZE, &s->lmx, &s->lmy, NULL); - BE_UploadAllLightmaps(); + Terr_InitLightmap(s); } lightmap[s->lightmap]->modified = true; lightmap[s->lightmap]->rectchange.l = 0; lightmap[s->lightmap]->rectchange.t = 0; - lightmap[s->lightmap]->rectchange.w = LMBLOCK_WIDTH; - lightmap[s->lightmap]->rectchange.h = LMBLOCK_HEIGHT; + lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE; + lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE; lm = lightmap[s->lightmap]->lightmaps; - lm += ((s->lmx+y) * LMBLOCK_WIDTH + (s->lmy+x)) * lightmap_bytes; + lm += ((s->lmx+y) * HMLMSTRIDE + (s->lmy+x)) * lightmap_bytes; return lm; } +static void ted_sethole(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) +{ + unsigned int bit; + unsigned int mask; + mask = 1u<modified = true; + s->holes = (s->holes & ~mask) | bit; +} static void ted_heighttally(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) { /*raise the terrain*/ @@ -1079,7 +1349,11 @@ static void ted_heightsmooth(void *ctx, hmsection_t *s, int idx, float wx, float { s->modified = true; /*interpolate the terrain towards a certain value*/ - s->heights[idx] = s->heights[idx]*(1-w) + w**(float*)ctx; + + if (IS_NAN(s->heights[idx])) + s->heights[idx] = *(float*)ctx; + else + s->heights[idx] = s->heights[idx]*(1-w) + w**(float*)ctx; } static void ted_heightraise(void *ctx, hmsection_t *s, int idx, float wx, float wy, float strength) { @@ -1142,9 +1416,51 @@ static void ted_mixnoise(void *ctx, hmsection_t *s, int idx, float wx, float wy, lm[2] = lm[2]*(1-w) + (v[2]*(w)); } +static void ted_mixpaint(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) +{ + unsigned char *lm = ted_getlightmap(s, idx); + char *texname = ctx; + int t; + vec3_t newval; + if (w > 1) + w = 1; + + for (t = 0; t < 4; t++) + { + if (!strncmp(s->texname[t], texname, sizeof(s->texname[t])-1)) + { + newval[0] = (t == 0); + newval[1] = (t == 1); + newval[2] = (t == 2); + lm[2] = lm[2]*(1-w) + (255*newval[0]*(w)); + lm[1] = lm[1]*(1-w) + (255*newval[1]*(w)); + lm[0] = lm[0]*(1-w) + (255*newval[2]*(w)); + return; + } + } + for (t = 0; t < 4; t++) + { + if (!*s->texname[t]) + { + Q_strncpyz(s->texname[t], texname, sizeof(s->texname[t])); + + newval[0] = (t == 0); + newval[1] = (t == 1); + newval[2] = (t == 2); + lm[2] = lm[2]*(1-w) + (255*newval[0]*(w)); + lm[1] = lm[1]*(1-w) + (255*newval[1]*(w)); + lm[0] = lm[0]*(1-w) + (255*newval[2]*(w)); + + Terr_LoadSectionTextures(s); + return; + } + } +} static void ted_mixset(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) { unsigned char *lm = ted_getlightmap(s, idx); + if (w > 1) + w = 1; lm[2] = lm[2]*(1-w) + (255*((float*)ctx)[0]*(w)); lm[1] = lm[1]*(1-w) + (255*((float*)ctx)[1]*(w)); lm[0] = lm[0]*(1-w) + (255*((float*)ctx)[2]*(w)); @@ -1176,10 +1492,10 @@ static void ted_itterate(heightmap_t *hm, float *pos, float radius, float streng max[0] = ceil((pos[0] + radius)/(hm->sectionsize) + 1); max[1] = ceil((pos[1] + radius)/(hm->sectionsize) + 1); - min[0] = bound(0, min[0], hm->numsegsx); - min[1] = bound(0, min[1], hm->numsegsy); - max[0] = bound(0, max[0], hm->numsegsx); - max[1] = bound(0, max[1], hm->numsegsy); + min[0] = bound(hm->firstsegx, min[0], hm->maxsegx); + min[1] = bound(hm->firstsegx, min[1], hm->maxsegy); + max[0] = bound(hm->firstsegx, max[0], hm->maxsegx); + max[1] = bound(hm->firstsegx, max[1], hm->maxsegy); sc[0] = hm->sectionsize/(steps-1); sc[1] = hm->sectionsize/(steps-1); @@ -1188,9 +1504,7 @@ static void ted_itterate(heightmap_t *hm, float *pos, float radius, float streng { for (sy = min[1]; sy < max[1]; sy++) { - s = hm->section[(int)(sx) + (int)(sy)*MAXSECTIONS]; - if (!s) - s = GL_LoadSection(hm, sx, sy); + s = Terr_GetSection(hm, sx, sy, true); if (!s) continue; @@ -1219,16 +1533,18 @@ enum { ter_reload, ter_save, + ter_sethole, ter_height_set, ter_height_smooth, + ter_height_spread, ter_raise, ter_lower, - ter_tex_set, + ter_tex_kill, ter_tex_get, - ter_mixset, + ter_mixpaint, ter_mixconcentrate, ter_mixnoise, - ter_mixblur, + ter_mixblur }; void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -1245,18 +1561,36 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob G_FLOAT(OFS_RETURN) = 0; - if (!mod || mod->type != mod_heightmap) + if (!mod || !mod->terrain) return; hm = mod->terrain; + pos[0] += hm->sectionsize * CHUNKBIAS; + pos[1] += hm->sectionsize * CHUNKBIAS; + switch(action) { case ter_reload: - HeightMap_Purge(mod); + Terr_PurgeTerrainModel(mod, false); break; case ter_save: HeightMap_Save(hm); break; + case ter_sethole: + { + int x, y; + hmsection_t *s; + x = pos[0]*4 / hm->sectionsize; + y = pos[1]*4 / hm->sectionsize; + x = bound(hm->firstsegx*4, x, hm->maxsegy*4-1); + y = bound(hm->firstsegy*4, y, hm->maxsegy*4-1); + + s = Terr_GetSection(hm, x/4, y/4, true); + if (!s) + return; + ted_sethole(&quant, s, (x&3) + (y&3)*4, x/4, y/4, 0); + } + break; case ter_height_set: ted_itterate(hm, pos, radius, 1, SECTHEIGHTSIZE, ted_heightset, &quant); break; @@ -1265,6 +1599,17 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob tally[1] = 0; ted_itterate(hm, pos, radius, 1, SECTHEIGHTSIZE, ted_heighttally, &tally); tally[0] /= tally[1]; + if (IS_NAN(tally[0])) + tally[0] = 0; + ted_itterate(hm, pos, radius, 1, SECTHEIGHTSIZE, ted_heightsmooth, &tally); + break; + case ter_height_spread: + tally[0] = 0; + tally[1] = 0; + ted_itterate(hm, pos, radius/2, 1, SECTHEIGHTSIZE, ted_heighttally, &tally); + tally[0] /= tally[1]; + if (IS_NAN(tally[0])) + tally[0] = 0; ted_itterate(hm, pos, radius, 1, SECTHEIGHTSIZE, ted_heightsmooth, &tally); break; case ter_lower: @@ -1272,8 +1617,11 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob case ter_raise: ted_itterate(hm, pos, radius, quant, SECTHEIGHTSIZE, ted_heightraise, &quant); break; - case ter_mixset: - ted_itterate(hm, pos, radius, 1, SECTTEXSIZE, ted_mixset, G_VECTOR(OFS_PARM4)); +// case ter_mixset: +// ted_itterate(hm, pos, radius, 1, SECTTEXSIZE, ted_mixset, G_VECTOR(OFS_PARM4)); +// break; + case ter_mixpaint: + ted_itterate(hm, pos, radius, quant/10, SECTTEXSIZE, ted_mixpaint, PR_GetStringOfs(prinst, OFS_PARM4)); break; case ter_mixconcentrate: ted_itterate(hm, pos, radius, 1, SECTTEXSIZE, ted_mixconcentrate, NULL); @@ -1284,55 +1632,79 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob case ter_mixblur: Vector4Set(tally, 0, 0, 0, 0); ted_itterate(hm, pos, radius, 1, SECTTEXSIZE, ted_mixtally, &tally); - VectorScale(tally, 1/tally[3], tally); + VectorScale(tally, 1/(tally[3]*255), tally); ted_itterate(hm, pos, radius, quant, SECTTEXSIZE, ted_mixset, &tally); break; - case ter_tex_set: - ted_itterate(hm, pos, radius, 1, SECTTEXSIZE, ted_mixset, NULL); -/* radius *= (float)hm->numsegsx / hm->tilesx; - for (x = 0; x < hm->numsegsx; x++) - { - for (y = 0; y < hm->numsegsy; y++) - { - xd = (sc[0] - x) * (float)hm->numsegsx / hm->tilesx; - yd = (sc[1] - y) * (float)hm->numsegsy / hm->tilesy; - w = sqrt(radius*radius - (xd*xd+yd*yd)); - if (w > 0) - { - s = hm->section[(int)(x) + (int)(y)*MAXSECTIONS]; - if (!s) - s = GL_LoadSection(hm, x, y); - if (s) - { - if (quant < 0 || quant >= 4) - quant = 0; - Q_strncpyz(s->texname[(int)quant], PR_GetStringOfs(prinst, OFS_PARM4), sizeof(s->texname[0])); - s->modified = true; - - GL_LoadSectionTextures(s); - } - } - } - } -*/ - break; case ter_tex_get: -/* - x = sc[0]*hm->numsegsx / hm->tilesx; - y = sc[1]*hm->numsegsy / hm->tilesy; - x = bound(0, x, hm->numsegsx-1); - y = bound(0, y, hm->numsegsy-1); - - G_INT(OFS_RETURN) = 0; - s = hm->section[(int)(x) + (int)(y)*MAXSECTIONS]; - if (!s) - s = GL_LoadSection(hm, x, y); - if (s) { + int x, y; + hmsection_t *s; + x = pos[0] / hm->sectionsize; + y = pos[1] / hm->sectionsize; + x = bound(hm->firstsegx, x, hm->maxsegy-1); + y = bound(hm->firstsegy, y, hm->maxsegy-1); + + s = Terr_GetSection(hm, x, y, true); + if (!s) + return; x = bound(0, quant, 3); G_INT(OFS_RETURN) = PR_TempString(prinst, s->texname[x]); } -*/ + break; + case ter_tex_kill: + { + char *killtex = PR_GetStringOfs(prinst, OFS_PARM4); + int x, y, t, to; + hmsection_t *s; + x = pos[0] / hm->sectionsize; + y = pos[1] / hm->sectionsize; + x = bound(hm->firstsegx, x, hm->maxsegy-1); + y = bound(hm->firstsegy, y, hm->maxsegy-1); + + s = Terr_GetSection(hm, x, y, true); + if (!s) + return; + for (t = 0; t < 4; t++) + { + if (!strcmp(s->texname[t], killtex)) + { + unsigned char *lm = ted_getlightmap(s, 0); + s->texname[t][0] = 0; + for (to = 0; to < 4; to++) + if (*s->texname[to]) + break; + if (to == 4) + to = 0; + + if (to == 0 || to == 2) + to = 2 - to; + if (t == 0 || t == 2) + t = 2 - t; + + for (y = 0; y < SECTTEXSIZE; y++) + { + for (x = 0; x < SECTTEXSIZE; x++, lm+=4) + { + if (t == 3) + { + //to won't be 3 + lm[to] = lm[to] + (255 - (lm[0] + lm[1] + lm[2])); + } + else + { + if (to != 3) + lm[to] += lm[t]; + lm[t] = 0; + } + } + lm += SECTTEXSIZE*4*(LMCHUNKS-1); + } + if (t == 0 || t == 2) + t = 2 - t; + Terr_LoadSectionTextures(s); + } + } + } break; } } @@ -1343,20 +1715,51 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob } #endif -qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) +void Terr_ParseEntityLump(char *data, float *scale, int *minx, int *maxx, int *miny, int *maxy) +{ + char key[128]; + + if (data) + if ((data=COM_Parse(data))) //read the map info. + if (com_token[0] == '{') + while (1) + { + if (!(data=COM_Parse(data))) + break; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strcpy(key, com_token + 1); //_ vars are for comments/utility stuff that arn't visible to progs. Ignore them. + else + strcpy(key, com_token); + if (!((data=COM_Parse(data)))) + break; // error + if (!strcmp("segmentsize", key)) // for HalfLife maps + *scale = atof(com_token); + else if (!strcmp("minxsegment", key)) + *minx = atoi(com_token) + CHUNKBIAS; + else if (!strcmp("minysegment", key)) + *miny = atoi(com_token) + CHUNKBIAS; + else if (!strcmp("maxxsegment", key)) + *maxx = atoi(com_token) + CHUNKBIAS; + else if (!strcmp("maxysegment", key)) + *maxy = atoi(com_token) + CHUNKBIAS; + } +} + + +qboolean Terr_LoadTerrainModel (model_t *mod, void *buffer) { heightmap_t *hm; float skyrotate; vec3_t skyaxis; char shadername[MAX_QPATH]; - char entfile[MAX_QPATH]; char skyname[MAX_QPATH]; int numsegsx = 0, numsegsy = 0; int sectsize = 0; COM_FileBase(mod->name, shadername, sizeof(shadername)); - Q_snprintfz(entfile, sizeof(entfile), "maps/%s/entities.ent", shadername); strcpy(shadername, "terrainshader"); strcpy(skyname, "night"); @@ -1372,94 +1775,32 @@ qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) return false; } - for(;;) - { - buffer = COM_Parse(buffer); - if (!buffer) - break; - - if (!strcmp(com_token, "shadername")) - { - buffer = COM_Parse(buffer); - Q_strncpyz(shadername, com_token, sizeof(shadername)); - } - else if (!strcmp(com_token, "segmentsize")) //size of each segment in quake units - { - buffer = COM_Parse(buffer); - sectsize = atof(com_token); - } - else if (!strcmp(com_token, "entfile")) - { - buffer = COM_Parse(buffer); - Q_strncpyz(entfile, com_token, sizeof(entfile)); - } - else if (!strcmp(com_token, "skybox")) - { - buffer = COM_Parse(buffer); - Q_strncpyz(skyname, com_token, sizeof(skyname)); - } - else if (!strcmp(com_token, "skyrotate")) - { - buffer = COM_Parse(buffer); - skyaxis[0] = atof(com_token); - buffer = COM_Parse(buffer); - skyaxis[1] = atof(com_token); - buffer = COM_Parse(buffer); - skyaxis[2] = atof(com_token); - skyrotate = VectorNormalize(skyaxis); - } - else if (!strcmp(com_token, "texturesegments")) - { - buffer = COM_Parse(buffer); - numsegsx = numsegsy = atoi(com_token); - } - else if (!strcmp(com_token, "texturesegmentsx")) - { - buffer = COM_Parse(buffer); - numsegsx = atoi(com_token); - } - else if (!strcmp(com_token, "texturesegmentsy")) - { - buffer = COM_Parse(buffer); - numsegsy = atoi(com_token); - } - else - { - Con_Printf(CON_ERROR "%s, unrecognised token \"%s\" in terrain map\n", mod->name, com_token); - return false; - } - } - - if (!sectsize) - sectsize = 1024; - - if (!numsegsx) - numsegsx = 16; - if (!numsegsy) - numsegsy = 16; - - if (numsegsx > MAXSECTIONS || numsegsy > MAXSECTIONS) - { - Con_Printf(CON_ERROR "%s, heightmap uses too many sections max is %i\n", mod->name, MAXSECTIONS); - return false; - } mod->type = mod_heightmap; hm = BZ_Malloc(sizeof(*hm)); memset(hm, 0, sizeof(*hm)); COM_FileBase(mod->name, hm->path, sizeof(hm->path)); - mod->entities = COM_LoadHunkFile(entfile); - if (!mod->entities) - { - BZ_Free(hm); - Con_Printf(CON_ERROR "unable to read %s\n", entfile); - return false; - } + mod->entities = Hunk_AllocName(strlen(buffer)+1, mod->name); + strcpy(mod->entities, buffer); hm->sectionsize = sectsize; - hm->numsegsx = numsegsx; - hm->numsegsy = numsegsy; + hm->firstsegx = CHUNKBIAS - 1; + hm->firstsegy = CHUNKBIAS - 1; + hm->maxsegx = CHUNKBIAS + 1; + hm->maxsegy = CHUNKBIAS + 1; + hm->exteriorcontents = FTECONTENTS_SKY|FTECONTENTS_SOLID; //sky outside the map + +// Terr_ParseEntityLump(hm, mod->entities); + + if (hm->firstsegx < 0) + hm->firstsegx = 0; + if (hm->firstsegy < 0) + hm->firstsegy = 0; + if (hm->maxsegx > CHUNKLIMIT) + hm->maxsegx = CHUNKLIMIT; + if (hm->maxsegy > CHUNKLIMIT) + hm->maxsegy = CHUNKLIMIT; #ifndef SERVERONLY if (qrenderer != QR_NONE) @@ -1519,4 +1860,86 @@ qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer) return true; } + +void *Mod_LoadTerrainInfo(model_t *mod, char *loadname) +{ + heightmap_t *hm; + float scale = 0; + int bounds[4] = {0}; + if (!mod->entities) + return NULL; + + if (!strcmp(loadname, "start")) + { + bounds[0] = 0; + bounds[1] = 4; + bounds[2] = 0; + bounds[3] = 4; + } + + Terr_ParseEntityLump(mod->entities, &scale, &bounds[0], &bounds[1], &bounds[2], &bounds[3]); + + bounds[0] += CHUNKBIAS; + bounds[1] += CHUNKBIAS; + bounds[2] += CHUNKBIAS; + bounds[3] += CHUNKBIAS; + + if (bounds[0] < 0) + bounds[0] = 0; + if (bounds[2] < 0) + bounds[2] = 0; + if (bounds[1] > CHUNKLIMIT) + bounds[1] = CHUNKLIMIT; + if (bounds[3] > CHUNKLIMIT) + bounds[3] = CHUNKLIMIT; + + if (!scale && (bounds[0] == bounds[1] || bounds[2] == bounds[3])) + return NULL; + + if (scale < 1) + scale = 1024; + + hm = Z_Malloc(sizeof(*hm)); + Q_strncpyz(hm->path, loadname, sizeof(hm->path)); + hm->sectionsize = scale; + hm->firstsegx = bounds[0]; + hm->maxsegx = bounds[1]; + hm->firstsegy = bounds[2]; + hm->maxsegy = bounds[3]; + + hm->exteriorcontents = FTECONTENTS_EMPTY; //bsp geometry outside the heightmap + + +#ifndef SERVERONLY + if (qrenderer != QR_NONE) + { + hm->skyshader = R_RegisterCustom(va("skybox_%s", loadname), Shader_DefaultSkybox, NULL); + hm->shader = R_RegisterShader("terrainshader", + "{\n" + "{\n" + "map $diffuse\n" + "}\n" + "{\n" + "map $upperoverlay\n" + "}\n" + "{\n" + "map $loweroverlay\n" + "}\n" + "{\n" + "map $fullbright\n" + "}\n" + "{\n" + "map $lightmap\n" + "}\n" + "program terrain\n" + "if r_terraindebug\n" + "[\n" + "program terraindebug\n" + "]\n" + "}\n" + ); + } +#endif + return hm; +} #endif diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index d581fb252..5683b9ba4 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -39,7 +39,6 @@ char loadname[32]; // for hunk tags void CM_Init(void); -qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer); qboolean RMod_LoadSpriteModel (model_t *mod, void *buffer); qboolean RMod_LoadSprite2Model (model_t *mod, void *buffer); qboolean RMod_LoadBrushModel (model_t *mod, void *buffer); @@ -400,9 +399,10 @@ void RMod_ClearAll (void) Surf_Clear(mod); } #ifdef TERRAIN - if (mod->type == mod_heightmap) + if (mod->terrain) { - HeightMap_Purge(mod); + Terr_PurgeTerrainModel(mod, false); + mod->terrain = NULL; } #endif @@ -667,10 +667,15 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) while (replstr) { replstr = COM_ParseStringSet(replstr); + if (replstr) + { + TRACE(("RMod_LoadModel: Trying to load (replacement) model \"%s.%s\"\n", mdlbase, com_token)); buf = (unsigned *)COM_LoadStackFile (va("%s.%s", mdlbase, com_token), stackbuf, sizeof(stackbuf)); + } else { + TRACE(("RMod_LoadModel: Trying to load model \"%s\"\n", mod->name)); buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); if (!buf) { @@ -678,6 +683,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) if (doomsprite) // special case needed for doom sprites { mod->needload = false; + TRACE(("RMod_LoadModel: doomsprite: \"%s\"\n", mod->name)); RMod_LoadDoomSprite(mod); return mod; } @@ -703,12 +709,14 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) //The binary 3d mesh model formats case RAPOLYHEADER: case IDPOLYHEADER: + TRACE(("RMod_LoadModel: Q1 mdl\n")); if (!Mod_LoadQ1Model(mod, buf)) continue; break; #ifdef MD2MODELS case MD2IDALIASHEADER: + TRACE(("RMod_LoadModel: md2\n")); if (!Mod_LoadQ2Model(mod, buf)) continue; break; @@ -716,6 +724,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef MD3MODELS case MD3_IDENT: + TRACE(("RMod_LoadModel: md3\n")); if (!Mod_LoadQ3Model (mod, buf)) continue; break; @@ -723,6 +732,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef HALFLIFEMODELS case (('T'<<24)+('S'<<16)+('D'<<8)+'I'): + TRACE(("RMod_LoadModel: HL mdl\n")); if (!Mod_LoadHLModel (mod, buf)) continue; break; @@ -731,12 +741,14 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) //Binary skeletal model formats #ifdef ZYMOTICMODELS case (('O'<<24)+('M'<<16)+('Y'<<8)+'Z'): + TRACE(("RMod_LoadModel: zym\n")); if (!Mod_LoadZymoticModel(mod, buf)) continue; break; #endif #ifdef DPMMODELS case (('K'<<24)+('R'<<16)+('A'<<8)+'D'): + TRACE(("RMod_LoadModel: dpm\n")); if (!Mod_LoadDarkPlacesModel(mod, buf)) continue; break; @@ -744,6 +756,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef PSKMODELS case ('A'<<0)+('C'<<8)+('T'<<16)+('R'<<24): + TRACE(("RMod_LoadModel: psk\n")); if (!Mod_LoadPSKModel (mod, buf)) continue; break; @@ -751,6 +764,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef INTERQUAKEMODELS case ('I'<<0)+('N'<<8)+('T'<<16)+('E'<<24): + TRACE(("RMod_LoadModel: IQM\n")); if (!Mod_LoadInterQuakeModel (mod, buf)) continue; break; @@ -759,12 +773,14 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) //Binary Sprites #ifdef SP2MODELS case IDSPRITE2HEADER: + TRACE(("RMod_LoadModel: q2 sp2\n")); if (!RMod_LoadSprite2Model (mod, buf)) continue; break; #endif case IDSPRITEHEADER: + TRACE(("RMod_LoadModel: q1 spr\n")); if (!RMod_LoadSpriteModel (mod, buf)) continue; break; @@ -775,6 +791,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) case ('F'<<0)+('B'<<8)+('S'<<16)+('P'<<24): case ('R'<<0)+('B'<<8)+('S'<<16)+('P'<<24): case IDBSPHEADER: //looks like id switched to have proper ids + TRACE(("RMod_LoadModel: q2/q3/raven/fusion bsp\n")); if (!Mod_LoadQ2BrushModel (mod, buf)) continue; break; @@ -782,6 +799,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef MAP_DOOM case (('D'<<24)+('A'<<16)+('W'<<8)+'I'): //the id is hacked by the FS .wad loader (main wad). case (('D'<<24)+('A'<<16)+('W'<<8)+'P'): //the id is hacked by the FS .wad loader (patch wad). + TRACE(("RMod_LoadModel: doom iwad/pwad map\n")); if (!Mod_LoadDoomLevel (mod)) continue; break; @@ -791,6 +809,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) case 29: //q1 case 28: //prerel case BSPVERSION_LONG: + TRACE(("RMod_LoadModel: hl/q1 bsp\n")); if (!RMod_LoadBrushModel (mod, buf)) continue; break; @@ -802,12 +821,14 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef MD5MODELS if (!strcmp(com_token, "MD5Version")) //doom3 format, text based, skeletal { + TRACE(("RMod_LoadModel: md5mesh/md5anim\n")); if (!Mod_LoadMD5MeshModel (mod, buf)) continue; break; } if (!strcmp(com_token, "EXTERNALANIM")) //custom format, text based, specifies skeletal models to load and which md5anim files to use. { + TRACE(("RMod_LoadModel: blurgh\n")); if (!Mod_LoadCompositeAnim (mod, buf)) continue; break; @@ -816,6 +837,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef MAP_PROC if (!strcmp(com_token, "CM")) //doom3 map. { + TRACE(("RMod_LoadModel: doom3 CM\n")); if (!D3_LoadMap_CollisionMap (mod, (char*)buf)) continue; break; @@ -824,7 +846,8 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) #ifdef TERRAIN if (!strcmp(com_token, "terrain")) //custom format, text based. { - if (!GL_LoadHeightmapModel(mod, buf)) + TRACE(("RMod_LoadModel: terrain\n")); + if (!Terr_LoadTerrainModel(mod, buf)) continue; break; } @@ -837,6 +860,8 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash) P_LoadedModel(mod); Validation_IncludeFile(mod->name, (char *)buf, com_filesize); + TRACE(("RMod_LoadModel: Loaded\n")); + return mod; } @@ -3816,6 +3841,7 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) crouchhullfile = NULL; + TRACE(("Loading info\n")); #ifndef CLIENTONLY if (sv.state) //if the server is running { @@ -3832,38 +3858,61 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) // load into heap if (!isDedicated || ode) { + TRACE(("Loading verts\n")); noerrors = noerrors && RMod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); + TRACE(("Loading edges\n")); noerrors = noerrors && RMod_LoadEdges (&header->lumps[LUMP_EDGES], longm); + TRACE(("Loading Surfedges\n")); noerrors = noerrors && RMod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); } if (!isDedicated) { + TRACE(("Loading Textures\n")); noerrors = noerrors && RMod_LoadTextures (&header->lumps[LUMP_TEXTURES]); + TRACE(("Loading Lighting\n")); if (noerrors) RMod_LoadLighting (&header->lumps[LUMP_LIGHTING]); } + TRACE(("Loading Submodels\n")); noerrors = noerrors && RMod_LoadSubmodels (&header->lumps[LUMP_MODELS]); if (noerrors) + { + TRACE(("Loading CH\n")); RMod_LoadCrouchHull(); + } + TRACE(("Loading Planes\n")); noerrors = noerrors && RMod_LoadPlanes (&header->lumps[LUMP_PLANES]); if (!isDedicated || ode) { + TRACE(("Loading Texinfo\n")); noerrors = noerrors && RMod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + TRACE(("Loading Faces\n")); noerrors = noerrors && RMod_LoadFaces (&header->lumps[LUMP_FACES], longm, &meshlist); } if (!isDedicated) + { + TRACE(("Loading MarkSurfaces\n")); noerrors = noerrors && RMod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES], longm); + } if (noerrors) + { + TRACE(("Loading Vis\n")); RMod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + } noerrors = noerrors && RMod_LoadLeafs (&header->lumps[LUMP_LEAFS], longm); + TRACE(("Loading Nodes\n")); noerrors = noerrors && RMod_LoadNodes (&header->lumps[LUMP_NODES], longm); + TRACE(("Loading Clipnodes\n")); noerrors = noerrors && RMod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES], longm); if (noerrors) { + TRACE(("Loading Entities\n")); RMod_LoadEntities (&header->lumps[LUMP_ENTITIES]); + TRACE(("Loading hull 0\n")); RMod_MakeHull0 (); } + TRACE(("sorting shaders\n")); if (!isDedicated && noerrors) Mod_SortShaders(); @@ -3879,8 +3928,11 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) return false; } + TRACE(("LoadBrushModel %i\n", __LINE__)); Q1BSP_LoadBrushes(mod); + TRACE(("LoadBrushModel %i\n", __LINE__)); Q1BSP_SetModelFuncs(mod); + TRACE(("LoadBrushModel %i\n", __LINE__)); mod->funcs.LightPointValues = GLQ1BSP_LightPointValues; mod->funcs.StainNode = Q1BSP_StainNode; mod->funcs.MarkLights = Q1BSP_MarkLights; @@ -3899,7 +3951,7 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) mod->hulls[0].available = true; Q1BSP_CheckHullNodes(&mod->hulls[0]); - +TRACE(("LoadBrushModel %i\n", __LINE__)); for (j=1 ; jhulls[j].firstclipnode = bm->headnode[j]; @@ -3925,10 +3977,12 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) memset(&mod->batches, 0, sizeof(mod->batches)); mod->vbos = NULL; + TRACE(("LoadBrushModel %i\n", __LINE__)); if (meshlist) { RMod_Batches_Build(meshlist, mod, NULL, NULL); } + TRACE(("LoadBrushModel %i\n", __LINE__)); if (i < mod->numsubmodels-1) { // duplicate the basic information @@ -3940,15 +3994,21 @@ qboolean RMod_LoadBrushModel (model_t *mod, void *buffer) strcpy (loadmodel->name, name); mod = loadmodel; } + TRACE(("LoadBrushModel %i\n", __LINE__)); } #ifdef RUNTIMELIGHTING + TRACE(("LoadBrushModel %i\n", __LINE__)); if (lightmodel == lm) LightLoadEntities(lightmodel->entities); #endif - +TRACE(("LoadBrushModel %i\n", __LINE__)); if (1) RMod_FixupMinsMaxs(); +TRACE(("LoadBrushModel %i\n", __LINE__)); +#ifdef TERRAIN + lm->terrain = Mod_LoadTerrainInfo(lm, loadname); +#endif return true; } diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 8c3331083..0555e6d62 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -665,8 +665,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) if (DotProduct(r_refdef.vieworg, plane.normal)-plane.dist < 0) return; - //if (!view) - // return; + TRACE(("GLR_DrawPortal: portal type %i\n", portaltype)); oldrefdef = r_refdef; r_refdef.recurse = true; @@ -824,6 +823,8 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) GL_CullFace(0); + TRACE(("GLR_DrawPortal: portal drawn\n")); + #ifdef warningmsg #pragma warningmsg("warning: there's a bug with rtlights in portals, culling is broken or something. May also be loading the wrong matrix") #endif diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index dc9001bad..5bcc65dc1 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -188,9 +188,6 @@ void GLSCR_UpdateScreen (void) { extern char levelshotname[]; - if ((key_dest == key_console || key_dest == key_game) && SCR_GetLoadingStage() == LS_NONE) - scr_con_current = scr_conlines = vid.height; - //draw the levelshot or the conback fullscreen if (*levelshotname) R2D_ScalePic(0, 0, vid.width, vid.height, R2D_SafeCachePic (levelshotname)); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 2bc2c0795..53da8d1b7 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -3358,11 +3358,14 @@ static qboolean Shader_Parsetok (shader_t *shader, shaderpass_t *pass, shaderkey } } +// Con_Printf("Unknown shader directive: \"%s\"\n", token); + // Next Line while (ptr) { token = COM_ParseExt ( ptr, false ); - if ( !token[0] ) { + if ( !token[0] ) + { break; } } @@ -4605,19 +4608,19 @@ static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode) token = COM_ParseExt (&shadersource, true); if ( !token[0] ) continue; - else if (token[0] == ']') - { - if (--nest <= 0) - { - nest++; + else if (token[0] == ']') + { + if (--nest <= 0) + { + nest++; if (!strcmp(token, "][")) - conditionistrue = !conditionistrue; - else - break; - } - } - else if (token[0] == '[') - nest++; + conditionistrue = !conditionistrue; + else + break; + } + } + else if (token[0] == '[') + nest++; else if (conditionistrue) { if (token[0] == '{') diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index c16c15c06..240b805e4 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -1568,12 +1568,12 @@ static qboolean Sh_ScissorForBox(vec3_t mins, vec3_t maxs, srect_t *r) x2 = 0; if (y2 < 0) y2 = 0; - if (x1 > r_refdef.vrect.width) - x1 = r_refdef.vrect.width; + if (x1 > r_refdef.vrect.width * vid.pixelwidth / vid.width) + x1 = r_refdef.vrect.width * vid.pixelwidth / vid.width; if (y1 > r_refdef.vrect.height * vid.pixelheight / vid.height) y1 = r_refdef.vrect.height * vid.pixelheight / vid.height; - if (x2 > r_refdef.vrect.width) - x2 = r_refdef.vrect.width; + if (x2 > r_refdef.vrect.width * vid.pixelwidth / vid.width) + x2 = r_refdef.vrect.width * vid.pixelwidth / vid.width; if (y2 > r_refdef.vrect.height * vid.pixelheight / vid.height) y2 = r_refdef.vrect.height * vid.pixelheight / vid.height; r->x = floor(x1); diff --git a/engine/gl/glmod_doom.c b/engine/gl/glmod_doom.c index d6ec58a17..89b80f957 100644 --- a/engine/gl/glmod_doom.c +++ b/engine/gl/glmod_doom.c @@ -2210,8 +2210,9 @@ void Doom_MarkLights(struct dlight_s *light, int bit, struct mnode_s *node) void Doom_SetModelFunc(model_t *mod) { +#ifndef SERVERONLY mod->funcs.PurgeModel = Doom_Purge; - +#endif mod->funcs.FatPVS = Doom_FatPVS; mod->funcs.EdictInFatPVS = Doom_EdictInFatPVS; mod->funcs.FindTouchedLeafs = Doom_FindTouchedLeafs; diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index d854e123a..f4996aaaa 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -407,9 +407,11 @@ void R_SaveRTLights_f(void); // gl_heightmap.c // #ifdef TERRAIN -void GL_DrawHeightmapModel (batch_t **batch, entity_t *e); -qboolean GL_LoadHeightmapModel (model_t *mod, void *buffer); -void HeightMap_Purge(model_t *mod); +void Terr_DrawTerrainModel (batch_t **batch, entity_t *e); +qboolean Terr_LoadTerrainModel (model_t *mod, void *buffer); +void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly); +void *Mod_LoadTerrainInfo(model_t *mod, char *loadname); //call this after loading a bsp +qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, trace_t *trace); #endif //doom diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 568ceb526..bd84123c3 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -1101,3 +1101,49 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" }, #endif +#ifdef GLQUAKE +{QR_OPENGL, 110, "terrain", +"!!permu FOG\n" +"#include \"sys/fog.h\"\n" +"varying vec2 tc;\n" +"varying vec2 lm;\n" + +"#ifdef VERTEX_SHADER\n" +"attribute vec2 v_texcoord;\n" +"attribute vec2 v_lmcoord;\n" +"void main (void)\n" +"{\n" +"tc = v_texcoord.st;\n" +"lm = v_lmcoord.st;\n" +"gl_Position = ftetransform();\n" +"}\n" +"#endif\n" + + + + +"#ifdef FRAGMENT_SHADER\n" +//four texture passes +"uniform sampler2D s_t0;\n" +"uniform sampler2D s_t1;\n" +"uniform sampler2D s_t2;\n" +"uniform sampler2D s_t3;\n" + +//mix values +"uniform sampler2D s_t4;\n" + + +"void main (void)\n" +"{\n" +"vec4 m = texture2D(s_t4, lm);\n" + +"gl_FragColor = fog4(\n" +"texture2D(s_t0, tc)*m.r\n" +"+ texture2D(s_t1, tc)*m.g\n" +"+ texture2D(s_t2, tc)*m.b\n" +"+ texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b))\n" +");\n" +"}\n" +"#endif\n" +}, +#endif diff --git a/engine/partcfgs/high.cfg b/engine/partcfgs/high.cfg index f1ba498d9..f829d4c18 100644 --- a/engine/partcfgs/high.cfg +++ b/engine/partcfgs/high.cfg @@ -327,6 +327,8 @@ r_part tr_knightspike friction 4 scalefactor 0.825 blend add + spawnmode spiral + spawnvel -50 } ///////////////////////////////////////// @@ -361,46 +363,91 @@ r_trail "progs/v_spike.mdl" tr_vorespike //{ //} +r_part te_blood +{ + texture fte_bloodparticle + blend subtract + count 1 + scale 32 + alpha 0 + die 1 + randomvel 64 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 64 128 128 + rgbdelta -64 -128 -128 + gravity 200 + scalefactor 0.8 +// scaledelta -10 +} + +r_part pe_73 +{ + assoc te_blood +} + +r_part te_lightningblood +{ + texture fte_bloodparticle + blend subtract + count 1 + scale 32 + alpha 0 + die 1 + randomvel 64 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 0 128 128 + rgbdelta 0 -128 -128 + gravity 200 + scalefactor 0.8 +} + ///////////////////////////////////////// //zombie body-part blood trails r_part tr_slightblood { - texture "particles/fteparticlefont.tga" - tcoords 1 1 63 63 256 2 64 + texture fte_bloodparticle + blend subtract +// tcoords 1 1 63 63 256 2 64 step 16 scale 64 - alpha 0.6 + alpha 0 die 1 randomvel 32 veladd 10 rotationspeed 90 rotationstart 0 360 - rgb 32 0 0 + rgb 64 128 128 + rgbdelta -64 -128 -128 gravity 200 scalefactor 0.8 scaledelta -10 - stains 5 + stains -0.5 } ////////////////////////////////////////// //regular ol' blood trails r_part tr_blood { - texture "particles/fteparticlefont.tga" - tcoords 1 1 63 63 256 2 64 - step 4 + texture fte_bloodparticle + blend subtract + step 8 scale 64 - alpha 0.3 + alpha 0 die 1 randomvel 32 veladd 10 rotationspeed 90 rotationstart 0 360 - rgb 64 0 0 + rgb 32 128 128 + rgbdelta -32 -128 -128 gravity 200 scalefactor 0.8 scaledelta -10 - stains 5 + stains -0.5 } ////////////////////////////////// @@ -432,6 +479,8 @@ r_part pe_defaulttrail randomvel 2 friction 4 scalefactor 0.825 + spawnmode spiral + spawnvel 25 blend add } diff --git a/engine/shaders/generatebuiltinsl.c b/engine/shaders/generatebuiltinsl.c index 9e63c0d6d..e12815617 100644 --- a/engine/shaders/generatebuiltinsl.c +++ b/engine/shaders/generatebuiltinsl.c @@ -26,6 +26,7 @@ char shaders[][64] = "postproc_panorama", "rtlight", "underwaterwarp", + "terrain", "" }; diff --git a/engine/shaders/glsl/terrain.glsl b/engine/shaders/glsl/terrain.glsl new file mode 100644 index 000000000..73c5f3aaf --- /dev/null +++ b/engine/shaders/glsl/terrain.glsl @@ -0,0 +1,42 @@ +!!permu FOG +#include "sys/fog.h" +varying vec2 tc; +varying vec2 lm; + +#ifdef VERTEX_SHADER +attribute vec2 v_texcoord; +attribute vec2 v_lmcoord; +void main (void) +{ + tc = v_texcoord.st; + lm = v_lmcoord.st; + gl_Position = ftetransform(); +} +#endif + + + + +#ifdef FRAGMENT_SHADER +//four texture passes +uniform sampler2D s_t0; +uniform sampler2D s_t1; +uniform sampler2D s_t2; +uniform sampler2D s_t3; + +//mix values +uniform sampler2D s_t4; + + +void main (void) +{ + vec4 m = texture2D(s_t4, lm); + + gl_FragColor = fog4( + texture2D(s_t0, tc)*m.r + + texture2D(s_t1, tc)*m.g + + texture2D(s_t2, tc)*m.b + + texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b)) + ); +} +#endif \ No newline at end of file diff --git a/engine/sw/sw_rast.c b/engine/sw/sw_rast.c index c5235a926..ea462b2c8 100644 --- a/engine/sw/sw_rast.c +++ b/engine/sw/sw_rast.c @@ -751,6 +751,7 @@ void SW_Draw_Init(void) } void SW_Draw_Shutdown(void) { + R2D_Shutdown(); } void SW_R_Init(void) {