diff --git a/engine/Makefile b/engine/Makefile index eadc06be2..e8b867ff0 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -28,6 +28,9 @@ WHOAMI:=$(shell whoami) #linux->macosx (FTE_TARGET=macosx) or (FTE_TARGET=macosx_x86) #linux->javascript (FTE_TARGET=web) #linux->nacl (FTE_TARGET=nacl NARCH=x86_64) +#win32->nacl +#linux->droid (make droid) +#win32->droid (make droid) #if you are cross compiling, you'll need to use FTE_TARGET=mytarget #cygwin's make's paths confuses non-cygwin things @@ -35,9 +38,14 @@ RELEASE_DIR=$(BASE_DIR)/release DEBUG_DIR=$(BASE_DIR)/debug PROFILE_DIR=$(BASE_DIR)/profile ifneq ($(shell uname -o 2>&1 | grep Cygwin),) - NATIVE_RELEASE_DIR=$(shell cygpath -m $(RELEASE_DIR)) - NATIVE_DEBUG_DIR=$(shell cygpath -m $(DEBUG_DIR)) + OUT_DIR?=. + NATIVE_OUT_DIR:=$(shell cygpath -m $(OUT_DIR)) + NATIVE_BASE_DIR:=$(shell cygpath -m $(BASE_DIR)) + NATIVE_RELEASE_DIR:=$(shell cygpath -m $(RELEASE_DIR)) + NATIVE_DEBUG_DIR:=$(shell cygpath -m $(DEBUG_DIR)) endif +NATIVE_OUT_DIR?=$(OUT_DIR) +NATIVE_BASE_DIR?=$(BASE_DIR) NATIVE_RELEASE_DIR?=$(RELEASE_DIR) NATIVE_DEBUG_DIR?=$(DEBUG_DIR) @@ -346,11 +354,6 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -v win),) IMAGELDFLAGS=$(MINGW_LIBS_DIR)/libpng.a $(MINGW_LIBS_DIR)/libz.a $(MINGW_LIBS_DIR)/libjpeg.a OGGVORBISLDFLAGS=$(MINGW_LIBS_DIR)/libvorbisfile.a $(MINGW_LIBS_DIR)/libvorbis.a $(MINGW_LIBS_DIR)/libogg.a - - ifeq ($(shell echo $(FTE_TARGET)|grep -v -i _SDL),) - RELEASE_CFLAGS+= -D_SDL - SDL_LDFLAGS=$(MINGW_LIBS_DIR)/libSDL.a $(MINGW_LIBS_DIR)/libSDLmain.a -L./libs/mingw64-libs - endif endif IMAGELDFLAGS ?= -lpng -ljpeg @@ -369,13 +372,15 @@ else GNUC_FUNCS= -Dstrnicmp=strncasecmp -Dstricmp=strcasecmp endif -SDL_INCLUDES=-I$(LIBS_DIR)/sdl/include -I/usr/include/SDL -I$(LIBS_DIR)/sdl/include/SDL +SDL_INCLUDES= +#-I$(LIBS_DIR)/sdl/include -I/usr/include/SDL -I$(LIBS_DIR)/sdl/include/SDL BOTLIB_CFLAGS=-I$(BOTLIB_DIR) -DBOTLIB BASE_CFLAGS=$(WARNINGFLAGS) $(GNUC_FUNCS) -I$(CLIENT_DIR) -I$(SERVER_DIR) -I$(COMMON_DIR) -I$(GL_DIR) -I$(D3D_DIR) -I$(PROGS_DIR) -I. -I$(LIBS_DIR) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/dxsdk7/include $(SDL_INCLUDES) -I./libs/freetype2/include -I./libs/freetype2/include/freetype -I./libs/speex $(BOTLIB_CFLAGS) $(SVNREVISION) CLIENT_ONLY_CFLAGS=-DCLIENTONLY SERVER_ONLY_CFLAGS=-DSERVERONLY JOINT_CFLAGS= -DEBUG_CFLAGS=-ggdb -g -DDEBUG +DEBUG_CFLAGS?=-ggdb -g +DEBUG_CFLAGS+=-DDEBUG RELEASE_CFLAGS?=-O3 -ffast-math $(CPUOPTIMIZATIONS) #incase our compiler doesn't support it (mingw) @@ -682,12 +687,15 @@ BOTLIB_OBJS = \ GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o GL_EXE_NAME=../fteqw_sdl.gl$(BITS) GLCL_EXE_NAME=../fteqwcl_sdl.gl$(BITS) +SDLCONFIG?=sdl-config +CC_MACHINE:=$(shell $(CC) -dumpmachine) +#SDLCONFIG:=libs/sdl2_mingw/$(CC_MACHINE)/bin/sdl2-config --prefix=libs/sdl2_mingw/$(CC_MACHINE) ifdef windir - GL_LDFLAGS=$(GLLDFLAGS) -lmingw32 -lws2_32 `sdl-config --libs` + GL_LDFLAGS=$(GLLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --libs` else - GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) `sdl-config --libs` + GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) `$(SDLCONFIG) --libs` endif -GL_CFLAGS=$(GLCFLAGS) `sdl-config --cflags` +GL_CFLAGS=$(GLCFLAGS) `$(SDLCONFIG) --cflags` GLB_DIR=gl_sdl$(FTE_TARGET)$(BITS) GLCL_DIR=glcl_sdl$(FTE_TARGET)$(BITS) @@ -702,14 +710,14 @@ MINGL_EXE_NAME=../fteqw_sdl.mingl$(BITS) MB_DIR=m_sdl$(FTE_TARGET)$(BITS) M_EXE_NAME=../fteqw_sdl$(BITS) MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o -M_CFLAGS=$(GLCFLAGS) `sdl-config --cflags` -D_MERGED_SDL +M_CFLAGS=$(GLCFLAGS) `$(SDLCONFIG) --cflags` -D_MERGED_SDL M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) ifdef windir - M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 -lSDLmain -lSDL + M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --libs` else #pthread is needed because of SDL. - M_LDFLAGS=$(MLDFLAGS) `sdl-config --libs` $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) + M_LDFLAGS=$(MLDFLAGS) `$(SDLCONFIG) --libs` $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) endif @@ -793,12 +801,12 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win(32|64)_sdl$$"),) GL_EXE_NAME=../fteqw_sdl_gl$(BITS)$(EXEPOSTFIX) GLCL_EXE_NAME=../fteqwcl_sdl$(BITS)$(EXEPOSTFIX) ifdef windir - GL_LDFLAGS=$(GLLDFLAGS) -lmingw32 -lws2_32 `sdl-config --libs` + GL_LDFLAGS=$(GLLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --libs` else - GL_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 $(GLLDFLAGS) `sdl-config --libs` + GL_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 $(GLLDFLAGS) `$(SDLCONFIG) --libs` endif - GL_CFLAGS=-D_SDL -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -I$(LIBS_DIR) $(GLCFLAGS) -DLIBVORBISFILE_STATIC `sdl-config --cflags` $(DX7SDK) $(SPEEXCFLAGS) + GL_CFLAGS=-D_SDL -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -I$(LIBS_DIR) $(GLCFLAGS) -DLIBVORBISFILE_STATIC `$(SDLCONFIG) --cflags` $(DX7SDK) $(SPEEXCFLAGS) ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win32.*sdl"),) GL_CFLAGS+= -D_MINGW_VFPRINTF endif @@ -817,7 +825,7 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win(32|64)_sdl$$"),) MB_DIR=m_mgw_sdl$(BITS) M_EXE_NAME=../fteqw_sdl$(BITS)$(EXEPOSTFIX) MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(LTO_END) resources.o $(LTO_START) - M_CFLAGS=$(D3DCFLAGS) -D_SDL -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) $(GLCFLAGS) -DLIBVORBISFILE_STATIC `sdl-config --cflags` -D_MERGED_SDL $(DX7SDK) $(SPEEXCFLAGS) + M_CFLAGS=$(D3DCFLAGS) -D_SDL -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) $(GLCFLAGS) -DLIBVORBISFILE_STATIC `$(SDL_CONFIG) --cflags` -D_MERGED_SDL $(DX7SDK) $(SPEEXCFLAGS) ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win32.*sdl"),) M_CFLAGS+= -D_MINGW_VFPRINTF @@ -826,17 +834,17 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win(32|64)_sdl$$"),) M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) ifdef windir - M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 -lSDLmain -lSDL + M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --libs` else #pthread is needed because of SDL. - M_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(MINGW_LIBS_DIR)/libSDL.a $(MINGW_LIBS_DIR)/libSDLmain.a -mwindows -ldxguid -lwinmm -lole32 $(MLDFLAGS) `sdl-config --libs` $(IMAGELDFLAGS) + M_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 -mwindows -ldxguid -lwinmm -lole32 $(MLDFLAGS) `$(SDL_CONFIG) --libs` $(IMAGELDFLAGS) endif D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) D3D_EXE_NAME=../fted3d_sdl_qw$(BITS)$(EXEPOSTFIX) D3DCL_EXE_NAME=../fted3d_sdl_clqw$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 - D3D_CFLAGS=$(D3DCFLAGS) -D_SDL -DNO_XFLIP -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -DLIBVORBISFILE_STATIC `sdl-config --cflags` $(DX7SDK) $(SPEEXCFLAGS) + D3D_CFLAGS=$(D3DCFLAGS) -D_SDL -DNO_XFLIP -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -DLIBVORBISFILE_STATIC `$(SDL_CONFIG) --cflags` $(DX7SDK) $(SPEEXCFLAGS) ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win32.*sdl"),) D3D_CFLAGS+= -D_MINGW_VFPRINTF endif @@ -847,19 +855,23 @@ endif #FTE_TARGET=vc (Visual C) ifeq ($(FTE_TARGET),vc) + DEBUG_CFLAGS= + MSVCDIR=Microsoft Visual Studio 10.0 + WINDOWSSDKDIR=C:/Program Files/Microsoft SDKs/Windows/v7.1 ifeq ($(BITS),64) WINDRES=x86_64-w64-mingw32-windres - MSVCPATH=C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN/amd64/ + MSVCPATH=C:/Program Files (x86)/$(MSVCDIR)/VC/BIN/amd64/ - MSVCINC=-I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\include" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\include" - MSVCLIB=/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\ATLMFC\LIB\amd64" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\LIB\amd64" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\lib\amd64" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\LIB\AMD64" + MSVCINC=-I"C:\Program Files (x86)\$(MSVCDIR)\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\$(MSVCDIR)\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\include" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\include" + MSVCLIB=/LIBPATH:"C:\Program Files (x86)\$(MSVCPATH)\VC\ATLMFC\LIB\amd64" /LIBPATH:"C:\Program Files (x86)\$(MSVCPATH)\VC\LIB\amd64" /LIBPATH:"$(WINDOWSSDKDIR)\lib\amd64" /LIBPATH:"C:\Program Files (x86)\$(MSVCPATH)\SDK\v2.0\LIB\AMD64" JPEGLIB=libs/libjpeg$(BITS).lib else - MSVCPATH=C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN/ + WINDRES=i686-w64-mingw32-windres + MSVCPATH=C:/Program Files (x86)/$(MSVCDIR)/VC/BIN/ - MSVCINC=-I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\include" -I"C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\include" - MSVCLIB=/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\ATLMFC\LIB" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\LIB" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\PlatformSDK\lib" /LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\LIB" + MSVCINC=-I"C:\Program Files (x86)\$(MSVCDIR)\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\$(MSVCDIR)\VC\INCLUDE" -I"C:\Program Files (x86)\$(MSVCDIR)\VC\PlatformSDK\include" -I"C:\Program Files (x86)\$(MSVCDIR)\SDK\v2.0\include" + MSVCLIB=/LIBPATH:"C:\Program Files (x86)\$(MSVCDIR)\VC\ATLMFC\LIB" /LIBPATH:"C:\Program Files (x86)\$(MSVCDIR)\VC\LIB" /LIBPATH:"$(WINDOWSSDKDIR)\lib" /LIBPATH:"C:\Program Files (x86)\$(MSVCDIR)\SDK\v2.0\LIB" JPEGLIB=libs/jpeg.lib endif STRIP=@echo strip @@ -869,11 +881,12 @@ ifeq ($(FTE_TARGET),vc) DEBUG_CFLAGS ?= -Od $(CPUOPTIMIZATIONS) /fp:fast PROFILE_CFLAGS = -O2 -Ot -Ox -GL $(CPUOPTIMISATIONS) /fp:fast PROFILE_LDFLAGS = /LTCG:PGINSTRUMENT - RELEASE_CFLAGS = -O2 -Ot -Ox -GL $(CPUOPTIMIZATIONS) /fp:fast - RELEASE_LDFLAGS = /LTCG:PGOPTIMIZE + RELEASE_CFLAGS = -O2 -Ot -Ox -GL -GS- -Gr $(CPUOPTIMIZATIONS) /fp:fast + RELEASE_LDFLAGS = /LTCG +# /LTCG:PGOPTIMIZE - DO_CC=@$(CC) /nologo $(ALL_CFLAGS) -Fo$@ -c $< - DO_LD=$(DO_ECHO) "$(MSVCPATH)link" /nologo /out:"$@" /nodefaultlib:libc.lib /LARGEADDRESSAWARE /nodefaultlib:MSVCRT $(MSVCLIB) /manifest:no /OPT:REF wsock32.lib user32.lib advapi32.lib winmm.lib libs/zlib$(BITS).lib shell32.lib + DO_CC=@$(CC) /nologo $(ALL_CFLAGS) -Fo$(shell cygpath -m $@) -c $(shell cygpath -m $<) + DO_LD=$(DO_ECHO) "$(MSVCPATH)link" /nologo /out:"$(shell cygpath -m $@)" /nodefaultlib:libc.lib /LARGEADDRESSAWARE /nodefaultlib:MSVCRT $(MSVCLIB) /manifest:no /OPT:REF wsock32.lib user32.lib kernel32.lib advapi32.lib winmm.lib libs/zlib$(BITS).lib shell32.lib PRECOMPHEADERS = DEPCC= @@ -881,6 +894,7 @@ ifeq ($(FTE_TARGET),vc) SPEEXCFLAGS+= -Dinline=_inline -D_USE_MATH_DEFINES + BASE_CFLAGS:=$(WARNINGFLAGS) $(GNUC_FUNCS) -I$(shell cygpath -m $(CLIENT_DIR)) -I$(shell cygpath -m $(SERVER_DIR)) -I$(shell cygpath -m $(COMMON_DIR)) -I$(shell cygpath -m $(GL_DIR)) -I$(shell cygpath -m $(D3D_DIR)) -I$(shell cygpath -m $(PROGS_DIR)) -I. -I$(LIBS_DIR) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/dxsdk7/include $(SDL_INCLUDES) -I./libs/freetype2/include -I./libs/freetype2/include/freetype -I./libs/speex $(BOTLIB_CFLAGS) $(SVNREVISION) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) $(W32_CFLAGS) -DMULTITHREAD -DMSVCLIBSPATH="libs/" SV_EXE_NAME=../fteqwsv$(BITS)$(EXEPOSTFIX) @@ -1311,7 +1325,7 @@ PRECOMPHEADERS ?= $(OUT_DIR)/quakedef.h.gch DO_LD ?= $(CC) -o $@ $(LTO_LD) $(WCFLAGS) $(CFLAGS) $(OUT_DIR)/$(EXE_NAME): $(PRECOMPHEADERS) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS), $($(ol))),$(if $(findstring ltox,$(fn)),,$(OUT_DIR)/$(fn))) - $(DO_LD) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS) $(LTO_END), $($(ol))),$(if $(findstring ltox,$(fn)),$(subst ltox,-x ,$(fn)),$(OUT_DIR)/$(fn)) ) $(LDFLAGS) + $(DO_LD) $(foreach fn, $(CUSTOMOBJS) $(foreach ol, $(OBJS) $(LTO_END), $($(ol))),$(if $(findstring ltox,$(fn)),$(subst ltox,-x ,$(fn)),$(NATIVE_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)" @@ -1415,7 +1429,7 @@ m-dbg: m-profile: @$(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 +.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 reldir debugdir _qcc-tmp: $(REQDIR) diff --git a/engine/client/cd_sdl.c b/engine/client/cd_sdl.c index 79032cdb8..051be11af 100644 --- a/engine/client/cd_sdl.c +++ b/engine/client/cd_sdl.c @@ -2,6 +2,11 @@ #include +#if SDL_MAJOR_VERSION >= 2 +//sdl2 has no cd support. sod off. +#include "cd_null.c" +#else + extern cvar_t bgmvolume; static qboolean initialized = false; @@ -121,3 +126,4 @@ void CDAudio_Shutdown(void) cddevice = NULL; initialized = false; } +#endif diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 15bab104e..0fececff0 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1646,7 +1646,7 @@ void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *dl, char *filename, void CL_PlayDemo(char *demoname) { char name[256]; - int start; + qofs_t start; vfsfile_t *f; // diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 8cb10dc67..d694ed88d 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -4489,12 +4489,6 @@ void CL_LinkViewModel(void) extern cvar_t cl_gunx, cl_guny, cl_gunz; extern cvar_t cl_gunanglex, cl_gunangley, cl_gunanglez; -#ifdef SIDEVIEWS - extern qboolean r_secondaryview; - if (r_secondaryview==1) - return; -#endif - if (r_drawviewmodel.value <= 0 || !Cam_DrawViewModel(r_refdef.playerview)) return; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index e1f3c01df..02df09ef6 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1734,9 +1734,12 @@ void CL_SendCmd (double frametime, qboolean mainloop) // if (skipcmd) // return; - if (!fullsend) + if (!fullsend || !msecstouse) return; // when we're actually playing we try to match netfps exactly to avoid gameplay problems + if (msecstouse > 127) + Con_Printf("%i\n", msecstouse, msecs); + #ifdef NQPROT if (cls.protocol != CP_NETQUAKE || cls.netchan.nqreliable_allowed) #endif diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 995d2f6f5..caa232621 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -3988,7 +3988,7 @@ void Host_DoRunFile(hrf_t *f) qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file) { hrf_t *f; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_SDL) //win32 file urls are basically fucked, so defer to the windows api. char utf8[MAX_OSPATH*3]; if (nlen >= 7 && !strncmp(fname, "file://", 7)) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 1bd791447..4d6475931 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -411,6 +411,21 @@ void CL_AckedInputFrame(int inseq, int outseq, qboolean worldstateokay) //============================================================================= +int CL_IsDownloading(char *localname) +{ + downloadlist_t *dl; + /*check for dupes*/ + for (dl = cl.downloadlist; dl; dl = dl->next) //It's already on our list. Ignore it. + { + if (!strcmp(dl->localname, localname)) + return 2; //queued + } + + if (!strcmp(cls.downloadlocalname, localname)) + return 1; //downloading + return 0; +} + //note: this will overwrite existing files. //returns true if the download is going to be downloaded after the call. qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags) @@ -461,21 +476,19 @@ qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags) } /*check for dupes*/ - for (dl = cl.downloadlist; dl; dl = dl->next) //It's already on our list. Ignore it. - { - if (!strcmp(dl->rname, filename)) - { - if (flags & DLLF_VERBOSE) - Con_Printf("Already waiting for \"%s\"\n", filename); - return true; - } - } - - if (!strcmp(cls.downloadremotename, filename)) + switch(CL_IsDownloading(localname)) { + case 2: + if (flags & DLLF_VERBOSE) + Con_Printf("Already waiting for \"%s\"\n", filename); + return true; + default: + case 1: if (flags & DLLF_VERBOSE) Con_Printf("Already downloading \"%s\"\n", filename); return true; + case 0: + break; } if (!*filename) @@ -1699,7 +1712,7 @@ void CL_ParseChunkedDownload(void) qbyte *svname; //qbyte osname[MAX_OSPATH]; //unreferenced int totalsize; - int chunknum, ridx; + qofs_t chunknum, ridx; char data[DLBLOCKSIZE]; chunknum = MSG_ReadLong(); @@ -2076,7 +2089,7 @@ qboolean CL_ParseOOBDownload(void) void CLDP_ParseDownloadData(void) { unsigned char buffer[1<<16]; - int start; + qofs_t start; int size; start = MSG_ReadLong(); size = (unsigned short)MSG_ReadShort(); diff --git a/engine/client/client.h b/engine/client/client.h index 3cad80bce..6dd68372d 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1027,6 +1027,7 @@ void CLQ2_ParseServerMessage (void); #endif void CL_NewTranslation (int slot); +int CL_IsDownloading(char *localname); qboolean CL_CheckOrEnqueDownloadFile (char *filename, char *localname, unsigned int flags); qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags); downloadlist_t *CL_DownloadFailed(char *name, qboolean cancel); @@ -1105,7 +1106,7 @@ void CL_ParsePlayerinfo (void); void CL_ParseClientPersist(void); //these last ones are needed for csqc handling of engine-bound ents. void CL_ClearEntityLists(void); -void CL_EditExternalModels(int newviewentity); +int CL_EditExternalModels(int newviewentity, entity_t *viewentities, int maxviewenties); void CL_FreeVisEdicts(void); void CL_LinkViewModel(void); void CL_LinkPlayers (void); diff --git a/engine/client/clq2_cin.c b/engine/client/clq2_cin.c index 04667ec87..15e744589 100644 --- a/engine/client/clq2_cin.c +++ b/engine/client/clq2_cin.c @@ -489,7 +489,7 @@ cinematics_t *CIN_PlayCinematic (char *arg) } else { - Con_Printf(CON_WARNING "Cinematic %s not found.\n", name); + Con_Printf(CON_WARNING "Cinematic %s not found.\n", arg); } return cin; } diff --git a/engine/client/console.c b/engine/client/console.c index 2c88dad17..d1d7cc6a9 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -732,7 +732,7 @@ void Con_PrintCon (console_t *con, char *txt) reuse->newer = NULL; reuse->older = NULL; } - reuse->id = ++con->nextlineid; + reuse->id = (++con->nextlineid) & 0xffff; reuse->older = con->current; con->current->newer = reuse; con->current = reuse; @@ -1286,7 +1286,7 @@ void Con_DrawNotify (void) conchar_t *ends[8]; conchar_t markup[MAXCMDLINE+64]; conchar_t *c, *end; - char *foo = va(chat_team?"say_team: %s":"say: %s", chat_buffer?chat_buffer:""); + char *foo = va(chat_team?"say_team: %s":"say: %s", chat_buffer?(char*)chat_buffer:""); int lines, i, pos; Font_BeginString(font_console, 0, 0, &x, &y); y = con_main.notif_l * Font_CharHeight(); diff --git a/engine/client/image.c b/engine/client/image.c index d1541911e..a0cf76bf4 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -670,16 +670,21 @@ qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, qboolean * #define PNG_ALLOCATED #endif -#define png_const_infop png_infop -#define png_const_structp png_structp -#define png_const_bytep png_bytep +#if PNG_LIBPNG_VER < 10500 + #define png_const_infop png_infop + #define png_const_structp png_structp + #define png_const_bytep png_bytep +#endif +#if PNG_LIBPNG_VER < 10600 + #define png_const_inforp png_const_infop +#endif void (PNGAPI *qpng_error) PNGARG((png_structp png_ptr, png_const_charp error_message)) PSTATIC(png_error); void (PNGAPI *qpng_read_end) PNGARG((png_structp png_ptr, png_infop info_ptr)) PSTATIC(png_read_end); void (PNGAPI *qpng_read_image) PNGARG((png_structp png_ptr, png_bytepp image)) PSTATIC(png_read_image); -png_byte (PNGAPI *qpng_get_bit_depth) PNGARG((png_const_structp png_ptr, png_const_infop info_ptr)) PSTATIC(png_get_bit_depth); -png_byte (PNGAPI *qpng_get_channels) PNGARG((png_const_structp png_ptr, png_const_infop info_ptr)) PSTATIC(png_get_channels); -png_size_t (PNGAPI *qpng_get_rowbytes) PNGARG((png_const_structp png_ptr, png_const_infop info_ptr)) PSTATIC(png_get_rowbytes); +png_byte (PNGAPI *qpng_get_bit_depth) PNGARG((png_const_structp png_ptr, png_const_inforp info_ptr)) PSTATIC(png_get_bit_depth); +png_byte (PNGAPI *qpng_get_channels) PNGARG((png_const_structp png_ptr, png_const_inforp info_ptr)) PSTATIC(png_get_channels); +png_size_t (PNGAPI *qpng_get_rowbytes) PNGARG((png_const_structp png_ptr, png_const_inforp info_ptr)) PSTATIC(png_get_rowbytes); void (PNGAPI *qpng_read_update_info) PNGARG((png_structp png_ptr, png_infop info_ptr)) PSTATIC(png_read_update_info); void (PNGAPI *qpng_set_strip_16) PNGARG((png_structp png_ptr)) PSTATIC(png_set_strip_16); void (PNGAPI *qpng_set_expand) PNGARG((png_structp png_ptr)) PSTATIC(png_set_expand); @@ -759,9 +764,16 @@ qboolean LibPNG_Init(void) }; if (!LIBPNG_LOADED()) - libpng_handle = Sys_LoadLibrary("libpng", pngfuncs); - if (!LIBPNG_LOADED()) - libpng_handle = Sys_LoadLibrary("libpng12", pngfuncs); + { + #ifdef _WIN32 + libpng_handle = Sys_LoadLibrary("libpng"STRINGIFY(PNG_LIBPNG_VER_DLLNUM), pngfuncs); + #else + libpng_handle = Sys_LoadLibrary("libpng.so."STRINGIFY(PNG_LIBPNG_VER_SONUM), pngfuncs); + #endif + } +// if (!LIBPNG_LOADED()) +// libpng_handle = Sys_LoadLibrary("libpng", pngfuncs); + #endif return LIBPNG_LOADED(); } @@ -2509,15 +2521,18 @@ qbyte *Read32BitImageFile(qbyte *buf, int len, int *width, int *height, qboolean int i; if (w >= 4 && h >= 4 && w*h+sizeof(int)*2 == com_filesize) { - unsigned int *in = (unsigned int*)buf+2; + qboolean foundalpha = false; + qbyte *in = (qbyte*)((int*)buf+2); data = BZ_Malloc(w * h * sizeof(int)); for (i = 0; i < w * h; i++) { + if (in[i] == 255) + foundalpha = true; ((unsigned int*)data)[i] = d_8to24rgbtable[in[i]]; } *width = w; *height = h; - *hasalpha = false; + *hasalpha = foundalpha; return data; } } @@ -2629,6 +2644,72 @@ static struct }; int image_width, image_height; +qboolean R_LoadTextureFromMemory(texid_t *tex, int flags, char *iname, char *fname, qbyte *filedata, int filesize) +{ + qboolean hasalpha; + qbyte *rgbadata; + + //these formats have special handling, because they cannot be implemented via Read32BitImageFile - they don't result in rgba images. +#ifdef IMAGEFMT_DDS + *tex = GL_ReadTextureDDS(iname, filedata, filesize); + if (TEXVALID(*tex)) + return true; +#endif +#ifdef IMAGEFMT_BLP + if (filedata[0] == 'B' && filedata[1] == 'L' && filedata[2] == 'P' && filedata[3] == '2') + { + *tex = GL_ReadBLPFile(iname, filedata, filesize); + if (TEXVALID(*tex)) + return true; + } +#endif + + hasalpha = false; + if ((rgbadata = Read32BitImageFile(filedata, filesize, &image_width, &image_height, &hasalpha, fname))) + { + extern cvar_t vid_hardwaregamma; + if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) + BoostGamma(rgbadata, image_width, image_height); + + if (hasalpha) + flags &= ~IF_NOALPHA; + else if (!(flags & IF_NOALPHA)) + { + unsigned int alpha_width, alpha_height, p; + char aname[MAX_QPATH]; + unsigned char *alphadata; + char *alph; + COM_StripExtension(fname, aname, sizeof(aname)); + Q_strncatz(aname, "_alpha", sizeof(aname)); + Q_strncatz(aname, COM_FileExtension(fname), sizeof(aname)); + if ((alph = COM_LoadFile (aname, 5))) + { + if ((alphadata = Read32BitImageFile(alph, filesize, &alpha_width, &alpha_height, &hasalpha, aname))) + { + if (alpha_width == image_width && alpha_height == image_height) + { + for (p = 0; p < alpha_width*alpha_height; p++) + { + rgbadata[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; + } + } + BZ_Free(alphadata); + } + BZ_Free(alph); + } + } + + TRACE(("dbg: Mod_LoadHiResTexture: %s loaded\n", iname)); + *tex = R_LoadTexture32 (iname, image_width, image_height, rgbadata, flags); + + BZ_Free(rgbadata); + + return true; + } + else + Con_Printf("Unable to read file %s (format unsupported)\n", fname); + return false; +} texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) { qboolean alphaed; @@ -2636,7 +2717,7 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) unsigned char *data; texid_t tex; // int h; - char fname[MAX_QPATH], nicename[MAX_QPATH]; + char fname[MAX_QPATH], nicename[MAX_QPATH], iname[MAX_QPATH]; qboolean hasalpha; int i, e; @@ -2682,6 +2763,7 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) } } + //cubemaps need special all-at-once handling or something, and is not individual textures. if ((flags & IF_TEXTYPE) == IF_CUBEMAP) { int j; @@ -2809,85 +2891,17 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) TRACE(("dbg: Mod_LoadHiResTexture: trying %s\n", fname)); if ((buf = COM_LoadFile (fname, 5))) { - //these formats have special handling, because they cannot be implemented via Read32BitImageFile - they don't result in rgba images. -#ifdef IMAGEFMT_DDS - tex = GL_ReadTextureDDS(name, buf, com_filesize); - if (TEXVALID(tex)) - { - BZ_Free(buf); - return tex; - } -#endif -#ifdef IMAGEFMT_BLP - if (buf[0] == 'B' && buf[1] == 'L' && buf[2] == 'P' && buf[3] == '2') - { - tex = GL_ReadBLPFile(name, buf, com_filesize); - if (TEXVALID(tex)) - { - BZ_Free(buf); - return tex; - } - } -#endif - - hasalpha = false; - if ((data = Read32BitImageFile(buf, com_filesize, &image_width, &image_height, &hasalpha, fname))) - { - extern cvar_t vid_hardwaregamma; - if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) - BoostGamma(data, image_width, image_height); - - if (hasalpha) - flags &= ~IF_NOALPHA; - else if (!(flags & IF_NOALPHA)) - { - unsigned int alpha_width, alpha_height, p; - char aname[MAX_QPATH]; - unsigned char *alphadata; - char *alph; - if (tex_path[i].args >= 3) - snprintf(aname, sizeof(aname)-1, tex_path[i].path, subpath, nicename, va("_alpha%s", tex_extensions[e].name)); - else - snprintf(aname, sizeof(aname)-1, tex_path[i].path, nicename, va("_alpha%s", tex_extensions[e].name)); - if ((alph = COM_LoadFile (aname, 5))) - { - if ((alphadata = Read32BitImageFile(alph, com_filesize, &alpha_width, &alpha_height, &hasalpha, aname))) - { - if (alpha_width == image_width && alpha_height == image_height) - { - for (p = 0; p < alpha_width*alpha_height; p++) - { - data[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; - } - } - BZ_Free(alphadata); - } - BZ_Free(alph); - } - } - - - TRACE(("dbg: Mod_LoadHiResTexture: %s loaded\n", name)); - if (tex_path[i].args >= 3) - { //if it came from a special subpath (eg: map specific), upload it using the subpath prefix - snprintf(fname, sizeof(fname)-1, "%s/%s", subpath, name); - tex = R_LoadTexture32 (fname, image_width, image_height, data, flags); - } - else - tex = R_LoadTexture32 (name, image_width, image_height, data, flags); - - BZ_Free(data); - - BZ_Free(buf); - - return tex; - } + if (tex_path[i].args >= 3) + snprintf(iname, sizeof(iname)-1, "%s/%s", subpath, name); /*should be safe if its null*/ else + snprintf(iname, sizeof(iname)-1, "%s", name); /*should be safe if its null*/ + + if (R_LoadTextureFromMemory(&tex, flags, iname, fname, buf, com_filesize)) { - Con_Printf("Unable to read file %s (format unsupported)\n", fname); BZ_Free(buf); - continue; + return tex; } + BZ_Free(buf); } } } @@ -2895,25 +2909,17 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) if (!(flags & IF_SUBDIRONLY)) { /*still failed? attempt to load quake lmp files, which have no real format id*/ - if (flags & IF_EXACTEXTENSION) - Q_strncpyz(fname, nicename, sizeof(fname)); - else - snprintf(fname, sizeof(fname)-1, "%s%s", nicename, ".lmp"); + Q_strncpyz(fname, name, sizeof(fname)); + COM_DefaultExtension(fname, ".lmp", sizeof(fname)); if ((buf = COM_LoadFile (fname, 5))) { - extern cvar_t vid_hardwaregamma; - TEXASSIGNF(tex, r_nulltex); - if (com_filesize >= 8) + if (R_LoadTextureFromMemory(&tex, flags, name, fname, buf, com_filesize)) { - image_width = LittleLong(((int*)buf)[0]); - image_height = LittleLong(((int*)buf)[1]); - if (image_width >= 4 && image_height >= 4 && image_width*image_height+8 == com_filesize) - { - tex = R_LoadTexture8(name, image_width, image_height, buf+8, flags, 1); - } + BZ_Free(buf); + return tex; } BZ_Free(buf); - return tex; + return r_nulltex; } //now look in wad files. (halflife compatability) diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index 15d28b488..2be2f97c3 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -10,8 +10,9 @@ static cvar_t m_accel = CVARF("m_accel", "0", CVAR_ARCHIVE); static cvar_t m_forcewheel = CVARD("m_forcewheel", "1", "0: ignore mousewheels in apis where it is abiguous.\n1: Use mousewheel when it is treated as a third axis. Motion above a threshold is ignored, to avoid issues with an unknown threshold.\n2: Like 1, but excess motion is retained. The threshold specifies exact z-axis distance per notice."); static cvar_t m_forcewheel_threshold = CVARD("m_forcewheel_threshold", "32", "Mousewheel graduations smaller than this will not trigger mousewheel deltas."); static 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."); -static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.5", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press (touchscreens)."); -static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "5", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens)."); +static cvar_t m_fatpressthreshold = CVARFD("m_fatpressthreshold", "0.2", CVAR_ARCHIVE, "How fat your thumb has to be to register a fat press (touchscreens)."); +static cvar_t m_touchmajoraxis = CVARFD("m_touchmajoraxis", "1", CVAR_ARCHIVE, "When using a touchscreen, use only the major axis for strafing."); +static cvar_t m_slidethreshold = CVARFD("m_slidethreshold", "10", CVAR_ARCHIVE, "How far your finger needs to move to be considered a slide event (touchscreens)."); extern cvar_t cl_forcesplitclient; //all devices claim to be a single player extern cvar_t _windowed_mouse; @@ -108,6 +109,7 @@ void IN_Init(void) Cvar_Register (&m_strafeonright, "input controls"); Cvar_Register (&m_fatpressthreshold, "input controls"); Cvar_Register (&m_slidethreshold, "input controls"); + Cvar_Register (&m_touchmajoraxis, "input controls"); INS_Init(); } @@ -354,14 +356,27 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum) //if they're strafing, calculate the speed to move at based upon their displacement if (mouse->down) { - mx = (mouse->oldpos[0] - mouse->downpos[0])*0.1; - my = (mouse->oldpos[1] - mouse->downpos[1])*0.1; + mx = mouse->oldpos[0] - (vid.pixelwidth*3)/4; + my = mouse->oldpos[1] - (vid.pixelheight*3)/4; + + //mx = (mouse->oldpos[0] - mouse->downpos[0])*0.1; + //my = (mouse->oldpos[1] - mouse->downpos[1])*0.1; } else { mx = 0; my = 0; } + + if (m_touchmajoraxis.ival) + { + //major axis only + if (fabs(mx) > fabs(my)) + my = 0; + else + mx = 0; + } + strafe_x = true; strafe_y = true; } @@ -369,6 +384,10 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum) { strafe_x = false; strafe_y = false; + + //boost sensitivity so that the default works okay. + mx *= 1.75; + my *= 1.75; } } else diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index 21b3f2e04..04c11fe79 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -2,19 +2,20 @@ #include -SDL_Surface *sdlsurf; +#if SDL_MAJOR_VERSION >=2 +SDL_Window *sdlwindow; +#else +extern SDL_Surface *sdlsurf; +#endif qboolean ActiveApp; qboolean mouseactive; extern qboolean mouseusedforgui; extern qboolean vid_isfullscreen; -#ifdef FTE_TARGET_WEB //theoretically generic, but the IME is probably going to be more annoying on systems where its actually implemented properly. - #if SDL_MAJOR_VERSION > 1 || (SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3) #define HAVE_SDL_TEXTINPUT #endif -#endif void IN_ActivateMouse(void) { @@ -23,7 +24,13 @@ void IN_ActivateMouse(void) mouseactive = true; SDL_ShowCursor(0); + +#if SDL_MAJOR_VERSION >= 2 + SDL_SetRelativeMouseMode(true); + SDL_SetWindowGrab(sdlwindow, true); +#else SDL_WM_GrabInput(SDL_GRAB_ON); +#endif } void IN_DeactivateMouse(void) @@ -33,9 +40,266 @@ void IN_DeactivateMouse(void) mouseactive = false; SDL_ShowCursor(1); +#if SDL_MAJOR_VERSION >= 2 + SDL_SetRelativeMouseMode(false); + SDL_SetWindowGrab(sdlwindow, false); +#else SDL_WM_GrabInput(SDL_GRAB_OFF); +#endif } +#if SDL_MAJOR_VERSION >= 2 +unsigned int MySDL_MapKey(unsigned int sdlkey) +{ + switch(sdlkey) + { + default: return 0; + //any ascii chars can be mapped directly to keys, even if they're only ever accessed with shift etc... oh well. + case SDLK_RETURN: return K_ENTER; + case SDLK_ESCAPE: return K_ESCAPE; + case SDLK_BACKSPACE: return K_BACKSPACE; + case SDLK_TAB: return K_TAB; + case SDLK_SPACE: return K_SPACE; + case SDLK_EXCLAIM: + case SDLK_QUOTEDBL: + case SDLK_HASH: + case SDLK_PERCENT: + case SDLK_DOLLAR: + case SDLK_AMPERSAND: + case SDLK_QUOTE: + case SDLK_LEFTPAREN: + case SDLK_RIGHTPAREN: + case SDLK_ASTERISK: + case SDLK_PLUS: + case SDLK_COMMA: + case SDLK_MINUS: + case SDLK_PERIOD: + case SDLK_SLASH: + case SDLK_0: + case SDLK_1: + case SDLK_2: + case SDLK_3: + case SDLK_4: + case SDLK_5: + case SDLK_6: + case SDLK_7: + case SDLK_8: + case SDLK_9: + case SDLK_COLON: + case SDLK_SEMICOLON: + case SDLK_LESS: + case SDLK_EQUALS: + case SDLK_GREATER: + case SDLK_QUESTION: + case SDLK_AT: + case SDLK_LEFTBRACKET: + case SDLK_BACKSLASH: + case SDLK_RIGHTBRACKET: + case SDLK_CARET: + case SDLK_UNDERSCORE: + case SDLK_BACKQUOTE: + case SDLK_a: + case SDLK_b: + case SDLK_c: + case SDLK_d: + case SDLK_e: + case SDLK_f: + case SDLK_g: + case SDLK_h: + case SDLK_i: + case SDLK_j: + case SDLK_k: + case SDLK_l: + case SDLK_m: + case SDLK_n: + case SDLK_o: + case SDLK_p: + case SDLK_q: + case SDLK_r: + case SDLK_s: + case SDLK_t: + case SDLK_u: + case SDLK_v: + case SDLK_w: + case SDLK_x: + case SDLK_y: + case SDLK_z: + return sdlkey; + case SDLK_CAPSLOCK: return K_CAPSLOCK; + case SDLK_F1: return K_F1; + case SDLK_F2: return K_F2; + case SDLK_F3: return K_F3; + case SDLK_F4: return K_F4; + case SDLK_F5: return K_F5; + case SDLK_F6: return K_F6; + case SDLK_F7: return K_F7; + case SDLK_F8: return K_F8; + case SDLK_F9: return K_F9; + case SDLK_F10: return K_F10; + case SDLK_F11: return K_F11; + case SDLK_F12: return K_F12; + case SDLK_PRINTSCREEN: return K_PRINTSCREEN; + case SDLK_SCROLLLOCK: return K_SCRLCK; + case SDLK_PAUSE: return K_PAUSE; + case SDLK_INSERT: return K_INS; + case SDLK_HOME: return K_HOME; + case SDLK_PAGEUP: return K_PGUP; + case SDLK_DELETE: return K_DEL; + case SDLK_END: return K_END; + case SDLK_PAGEDOWN: return K_PGDN; + case SDLK_RIGHT: return K_RIGHTARROW; + case SDLK_LEFT: return K_LEFTARROW; + case SDLK_DOWN: return K_DOWNARROW; + case SDLK_UP: return K_UPARROW; + case SDLK_NUMLOCKCLEAR: return K_KP_NUMLOCK; + case SDLK_KP_DIVIDE: return K_KP_SLASH; + case SDLK_KP_MULTIPLY: return K_KP_STAR; + case SDLK_KP_MINUS: return K_KP_MINUS; + case SDLK_KP_PLUS: return K_KP_PLUS; + case SDLK_KP_ENTER: return K_KP_ENTER; + case SDLK_KP_1: return K_KP_END; + case SDLK_KP_2: return K_KP_DOWNARROW; + case SDLK_KP_3: return K_KP_PGDN; + case SDLK_KP_4: return K_KP_LEFTARROW; + case SDLK_KP_5: return K_KP_5; + case SDLK_KP_6: return K_KP_RIGHTARROW; + case SDLK_KP_7: return K_KP_HOME; + case SDLK_KP_8: return K_KP_UPARROW; + case SDLK_KP_9: return K_KP_PGDN; + case SDLK_KP_0: return K_KP_INS; + case SDLK_KP_PERIOD: return K_KP_DEL; + case SDLK_APPLICATION: return K_APP; + case SDLK_POWER: return K_POWER; + case SDLK_KP_EQUALS: return K_KP_EQUALS; + case SDLK_F13: return K_F13; + case SDLK_F14: return K_F14; + case SDLK_F15: return K_F15; +/* + case SDLK_F16: return K_; + case SDLK_F17: return K_; + case SDLK_F18: return K_; + case SDLK_F19: return K_; + case SDLK_F20: return K_; + case SDLK_F21: return K_; + case SDLK_F22: return K_; + case SDLK_F23: return K_; + case SDLK_F24: return K_; + case SDLK_EXECUTE: return K_; + case SDLK_HELP: return K_; + case SDLK_MENU: return K_; + case SDLK_SELECT: return K_; + case SDLK_STOP: return K_; + case SDLK_AGAIN: return K_; + case SDLK_UNDO: return K_; + case SDLK_CUT: return K_; + case SDLK_COPY: return K_; + case SDLK_PASTE: return K_; + case SDLK_FIND: return K_; + case SDLK_MUTE: return K_; +*/ + case SDLK_VOLUMEUP: return K_VOLUP; + case SDLK_VOLUMEDOWN: return K_VOLDOWN; +/* + case SDLK_KP_COMMA: return K_; + case SDLK_KP_EQUALSAS400: return K_; + case SDLK_ALTERASE: return K_; + case SDLK_SYSREQ: return K_; + case SDLK_CANCEL: return K_; + case SDLK_CLEAR: return K_; + case SDLK_PRIOR: return K_; + case SDLK_RETURN2: return K_; + case SDLK_SEPARATOR: return K_; + case SDLK_OUT: return K_; + case SDLK_OPER: return K_; + case SDLK_CLEARAGAIN: return K_; + case SDLK_CRSEL: return K_; + case SDLK_EXSEL: return K_; + case SDLK_KP_00: return K_; + case SDLK_KP_000: return K_; + case SDLK_THOUSANDSSEPARATOR: return K_; + case SDLK_DECIMALSEPARATOR: return K_; + case SDLK_CURRENCYUNIT: return K_; + case SDLK_CURRENCYSUBUNIT: return K_; + case SDLK_KP_LEFTPAREN: return K_; + case SDLK_KP_RIGHTPAREN: return K_; + case SDLK_KP_LEFTBRACE: return K_; + case SDLK_KP_RIGHTBRACE: return K_; + case SDLK_KP_TAB: return K_; + case SDLK_KP_BACKSPACE: return K_; + case SDLK_KP_A: return K_; + case SDLK_KP_B: return K_; + case SDLK_KP_C: return K_; + case SDLK_KP_D: return K_; + case SDLK_KP_E: return K_; + case SDLK_KP_F: return K_; + case SDLK_KP_XOR: return K_; + case SDLK_KP_POWER: return K_; + case SDLK_KP_PERCENT: return K_; + case SDLK_KP_LESS: return K_; + case SDLK_KP_GREATER: return K_; + case SDLK_KP_AMPERSAND: return K_; + case SDLK_KP_DBLAMPERSAND: return K_; + case SDLK_KP_VERTICALBAR: return K_; + case SDLK_KP_DBLVERTICALBAR: return K_; + case SDLK_KP_COLON: return K_; + case SDLK_KP_HASH: return K_; + case SDLK_KP_SPACE: return K_; + case SDLK_KP_AT: return K_; + case SDLK_KP_EXCLAM: return K_; + case SDLK_KP_MEMSTORE: return K_; + case SDLK_KP_MEMRECALL: return K_; + case SDLK_KP_MEMCLEAR: return K_; + case SDLK_KP_MEMADD: return K_; + case SDLK_KP_MEMSUBTRACT: return K_; + case SDLK_KP_MEMMULTIPLY: return K_; + case SDLK_KP_MEMDIVIDE: return K_; + case SDLK_KP_PLUSMINUS: return K_; + case SDLK_KP_CLEAR: return K_; + case SDLK_KP_CLEARENTRY: return K_; + case SDLK_KP_BINARY: return K_; + case SDLK_KP_OCTAL: return K_; + case SDLK_KP_DECIMAL: return K_; + case SDLK_KP_HEXADECIMAL: return K_; +*/ + case SDLK_LCTRL: return K_LCTRL; + case SDLK_LSHIFT: return K_LSHIFT; + case SDLK_LALT: return K_LALT; + case SDLK_LGUI: return K_APP; + case SDLK_RCTRL: return K_RCTRL; + case SDLK_RSHIFT: return K_RSHIFT; + case SDLK_RALT: return K_RALT; +/* + case SDLK_RGUI: return K_; + case SDLK_MODE: return K_; + case SDLK_AUDIONEXT: return K_; + case SDLK_AUDIOPREV: return K_; + case SDLK_AUDIOSTOP: return K_; + case SDLK_AUDIOPLAY: return K_; + case SDLK_AUDIOMUTE: return K_; + case SDLK_MEDIASELECT: return K_; + case SDLK_WWW: return K_; + case SDLK_MAIL: return K_; + case SDLK_CALCULATOR: return K_; + case SDLK_COMPUTER: return K_; + case SDLK_AC_SEARCH: return K_; + case SDLK_AC_HOME: return K_; + case SDLK_AC_BACK: return K_; + case SDLK_AC_FORWARD: return K_; + case SDLK_AC_STOP: return K_; + case SDLK_AC_REFRESH: return K_; + case SDLK_AC_BOOKMARKS: return K_; + case SDLK_BRIGHTNESSDOWN: return K_; + case SDLK_BRIGHTNESSUP: return K_; + case SDLK_DISPLAYSWITCH: return K_; + case SDLK_KBDILLUMTOGGLE: return K_; + case SDLK_KBDILLUMDOWN: return K_; + case SDLK_KBDILLUMUP: return K_; + case SDLK_EJECT: return K_; + case SDLK_SLEEP: return K_; +*/ + } +} +#else #define tenoh 0,0,0,0,0, 0,0,0,0,0 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh #define hundredoh fiftyoh, fiftyoh @@ -188,6 +452,7 @@ static unsigned int tbl_sdltoquake[] = 'e', //SDLK_EURO = 321, /* Some european keyboards */ 0 //SDLK_UNDO = 322, /* Atari keyboard has Undo */ }; +#endif static unsigned int tbl_sdltoquakemouse[] = { @@ -212,6 +477,37 @@ void Sys_SendKeyEvents(void) { switch(event.type) { +#if SDL_MAJOR_VERSION >= 2 + case SDL_WINDOWEVENT: + switch(event.window.event) + { + default: + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + #if SDL_PATCHLEVEL >= 1 + SDL_GL_GetDrawableSize(sdlwindow, &vid.pixelwidth, &vid.pixelheight); //get the proper physical size. + #else + SDL_GetWindowSize(sdlwindow, &vid.pixelwidth, &vid.pixelheight); + #endif + { + extern cvar_t vid_conautoscale, vid_conwidth; //make sure the screen is updated properly. + Cvar_ForceCallback(&vid_conautoscale); + Cvar_ForceCallback(&vid_conwidth); + } + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + ActiveApp = true; + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + ActiveApp = false; + break; + case SDL_WINDOWEVENT_CLOSE: + Cbuf_AddText("quit prompt\n", RESTRICT_LOCAL); + break; + } + break; +#else + case SDL_ACTIVEEVENT: if (event.active.state & SDL_APPINPUTFOCUS) { //follow keyboard status @@ -231,17 +527,21 @@ void Sys_SendKeyEvents(void) } #endif break; +#endif case SDL_KEYUP: case SDL_KEYDOWN: { - int u = event.key.keysym.unicode; int s = event.key.keysym.sym; int qs; +#if SDL_MAJOR_VERSION >= 2 + qs = MySDL_MapKey(s); +#else if (s < sizeof(tbl_sdltoquake) / sizeof(tbl_sdltoquake[0])) qs = tbl_sdltoquake[s]; else qs = 0; +#endif #ifdef FTE_TARGET_WEB if (s == 1249) @@ -250,14 +550,13 @@ void Sys_SendKeyEvents(void) #ifdef HAVE_SDL_TEXTINPUT IN_KeyEvent(0, event.key.state, qs, 0); #else - IN_KeyEvent(0, event.key.state, qs, u); + IN_KeyEvent(0, event.key.state, qs, event.key.keysym.unicode); #endif } break; #ifdef HAVE_SDL_TEXTINPUT case SDL_TEXTINPUT: { - int i; unsigned int uc; int err; char *text = event.text.text; @@ -274,23 +573,50 @@ void Sys_SendKeyEvents(void) break; #endif +#if SDL_MAJOR_VERSION >= 2 + case SDL_FINGERDOWN: + case SDL_FINGERUP: + IN_MouseMove(event.tfinger.fingerId, true, event.tfinger.x * vid.pixelwidth, event.tfinger.y * vid.pixelheight, 0, event.tfinger.pressure); + IN_KeyEvent(event.tfinger.fingerId, event.type==SDL_FINGERDOWN, K_MOUSE1, 0); + break; + case SDL_FINGERMOTION: + IN_MouseMove(event.tfinger.fingerId, true, event.tfinger.x * vid.pixelwidth, event.tfinger.y * vid.pixelheight, 0, event.tfinger.pressure); + break; + + case SDL_DROPFILE: + Host_RunFile(event.drop.file, strlen(event.drop.file), NULL); + SDL_free(event.drop.file); + break; +#endif + case SDL_MOUSEMOTION: +#if SDL_MAJOR_VERSION >= 2 + if (event.motion.which == SDL_TOUCH_MOUSEID) + break; //ignore legacy touch events. +#endif if (!mouseactive) - IN_MouseMove(0, true, event.motion.x, event.motion.y, 0, 0); + IN_MouseMove(event.motion.which, true, event.motion.x, event.motion.y, 0, 0); else - IN_MouseMove(0, false, event.motion.xrel, event.motion.yrel, 0, 0); + IN_MouseMove(event.motion.which, false, event.motion.xrel, event.motion.yrel, 0, 0); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: - //Hmm. SDL allows for 255 buttons... +#if SDL_MAJOR_VERSION >= 2 + if (event.button.which == SDL_TOUCH_MOUSEID) + break; //ignore legacy touch events. +#endif + //Hmm. SDL allows for 255 buttons, but only defines 5... if (event.button.button > sizeof(tbl_sdltoquakemouse)/sizeof(tbl_sdltoquakemouse[0])) event.button.button = sizeof(tbl_sdltoquakemouse)/sizeof(tbl_sdltoquakemouse[0]); - IN_KeyEvent(0, event.button.state, tbl_sdltoquakemouse[event.button.button-1], 0); + IN_KeyEvent(event.button.which, event.button.state, tbl_sdltoquakemouse[event.button.button-1], 0); break; + case SDL_APP_TERMINATING: + Cbuf_AddText("quit force\n", RESTRICT_LOCAL); + break; case SDL_QUIT: - Cbuf_AddText("quit", RESTRICT_LOCAL); + Cbuf_AddText("quit\n", RESTRICT_LOCAL); break; } } @@ -315,6 +641,9 @@ void INS_ReInit (void) #else SDL_EnableUNICODE(SDL_ENABLE); #endif +#if SDL_MAJOR_VERSION >= 2 + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); +#endif } //stubs, all the work is done in Sys_SendKeyEvents diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 68de6cd15..5a95b008a 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -701,7 +701,7 @@ void M_Media_Draw (void) char compleatenamepath[MAX_OSPATH]; char compleatenamename[MAX_OSPATH]; qboolean compleatenamemultiple; -int QDECL Com_CompleatenameCallback(const char *name, int size, void *data, searchpathfuncs_t *spath) +int QDECL Com_CompleatenameCallback(const char *name, qofs_t size, void *data, searchpathfuncs_t *spath) { if (*compleatenamename) compleatenamemultiple = true; @@ -1480,7 +1480,7 @@ cin_t *Media_WinAvi_TryLoad(char *name) FS_FLocateFile(name, FSLFRT_DEPTH_OSONLY, &loc); - if (!loc.offset && !qAVIFileOpenA(&pavi, loc.rawname, OF_READ, NULL))//!AVIStreamOpenFromFile(&pavi, name, streamtypeVIDEO, 0, OF_READ, NULL)) + if (!loc.offset && *loc.rawname && !qAVIFileOpenA(&pavi, loc.rawname, OF_READ, NULL))//!AVIStreamOpenFromFile(&pavi, name, streamtypeVIDEO, 0, OF_READ, NULL)) { int filmwidth; int filmheight; diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index ca842d2d7..28e1312ac 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -188,7 +188,7 @@ typedef struct { int match; } q2skinsearch_t; -int QDECL q2skin_enumerate(const char *name, int fsize, void *parm, searchpathfuncs_t *spath) +int QDECL q2skin_enumerate(const char *name, qofs_t fsize, void *parm, searchpathfuncs_t *spath) { char blah[MAX_QPATH]; q2skinsearch_t *s = parm; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index d33631b8b..31132e490 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -369,7 +369,7 @@ void M_Menu_Audio_f (void) MB_SPACING(8), MB_CONSOLECMD("Restart Sound", "snd_restart\n", "Restart audio systems and apply set options."), MB_SPACING(4), - MB_COMBOCVAR("Output Device", snd_device, info->outdevdescs, info->outdevnames, NULL), + MB_COMBOCVAR("Output Device", snd_device, (const char**)info->outdevdescs, (const char**)info->outdevnames, NULL), MB_SLIDER("Volume", volume, 0, 1, 0.1, NULL), MB_COMBOCVAR("Speaker Setup", snd_speakers, speakeroptions, speakervalues, NULL), MB_COMBOCVAR("Frequency", snd_khz, soundqualityoptions, soundqualityvalues, NULL), @@ -394,7 +394,7 @@ void M_Menu_Audio_f (void) #ifdef VOICECHAT MB_REDTEXT("Voice Options", false), MB_TEXT("\x80\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x82", false), - MB_COMBOCVAR("Microphone Device", snd_voip_capturedevice, info->capdevdescs, info->capdevnames, NULL), + MB_COMBOCVAR("Microphone Device", snd_voip_capturedevice, (const char**)info->capdevdescs, (const char**)info->capdevnames, NULL), MB_SLIDER("Voice Volume", snd_voip_play, 0, 2, 0.1, NULL), MB_CHECKBOXCVAR("Microphone Test", snd_voip_test, 0), MB_SLIDER("Microphone Volume", snd_voip_micamp, 0, 2, 0.1, NULL), @@ -547,7 +547,7 @@ const char *presetexec[] = "r_shadow_realtime_dlight 0;" "r_shadow_realtime_world 0;" "r_glsl_offsetmapping 0;" - "gl_detail 0;" +// "gl_detail 0;" "gl_load24bit 0;" "r_replacemodels \"\";" "r_waterwarp 0;" @@ -595,7 +595,7 @@ const char *presetexec[] = "gl_texturemode ll;" #ifndef MINIMAL "r_particlesystem script;" - "r_particledesc \"spikeset tsshaft\";" + "r_particledesc \"high tsshaft\";" #endif "gl_specular 1;" "r_loadlit 2;" @@ -603,7 +603,7 @@ const char *presetexec[] = "gl_blendsprites 1;" // "r_fastsky -1;" "r_shadow_realtime_dlight 1;" - "gl_detail 1;" +// "gl_detail 1;" "r_lightstylesmooth 1;" "gl_texture_anisotropic_filtering 4;" @@ -898,7 +898,7 @@ void M_Menu_Textures_f (void) MB_SPACING(4), MB_CHECKBOXCVAR("Deluxemapping", r_deluxemapping, 0), MB_CHECKBOXCVAR("Specular Highlights", gl_specular, 0), - MB_CHECKBOXCVAR("Detail Textures", gl_detail, 0), +// MB_CHECKBOXCVAR("Detail Textures", gl_detail, 0), MB_CHECKBOXCVAR("offsetmapping", r_glsl_offsetmapping, 0), MB_SPACING(4), MB_CHECKBOXCVAR("Texture Compression", gl_compress, 0), // merge the save compressed tex options into here? @@ -2329,7 +2329,7 @@ void M_Menu_Video_f (void) "Wait for Display Enable", NULL }; - extern cvar_t _vid_wait_override; + extern cvar_t vid_vsync; */ videomenuinfo_t *info; static char current3dres[32]; // enough to fit 1920x1200 @@ -2429,7 +2429,7 @@ void M_Menu_Video_f (void) y+=4;info->customwidth = MC_AddEdit(menu, 16, y, " Custom width", vid_width.string); y+=8; y+=4;info->customheight = MC_AddEdit(menu, 16, y, " Custom height", vid_height.string); y+=12; info->vsynccombo = MC_AddCombo(menu, 16, y, " VSync", vsyncoptions, currentvsync); y+=8; - //MC_AddCheckBox(menu, 16, y, " Override VSync", &_vid_wait_override,0); y+=8; + //MC_AddCheckBox(menu, 16, y, " Override VSync", &vid_vsync,0); y+=8; MC_AddCheckBox(menu, 16, y, " Desktop Settings", &vid_desktopsettings,0); y+=8; y+=8; MC_AddCommand(menu, 16, y, "= Apply Changes =", M_VideoApply); y+=8; diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 31d4a2dc6..7f7f3fc91 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -500,7 +500,7 @@ static qboolean M_DemoKey(menucustom_t *control, menu_t *menu, int key) return false; } -static int QDECL DemoAddItem(const char *filename, int size, void *parm, searchpathfuncs_t *spath) +static int QDECL DemoAddItem(const char *filename, qofs_t size, void *parm, searchpathfuncs_t *spath) { int extnum; demomenu_t *menu = parm; diff --git a/engine/client/menu.c b/engine/client/menu.c index f7d3b0e32..2edf8a3fb 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -914,6 +914,7 @@ void M_Menu_Quit_f (void) break; case 2: Key_Dest_Add(kdm_menu); + Key_Dest_Remove(kdm_console); m_state = m_complex; quitmenu = M_CreateMenuInfront(0); @@ -932,6 +933,7 @@ void M_Menu_Quit_f (void) break; case 1: Key_Dest_Add(kdm_menu); + Key_Dest_Remove(kdm_console); m_state = m_complex; quitmenu = M_CreateMenuInfront(0); diff --git a/engine/client/merged.h b/engine/client/merged.h index 0408a17d0..88407c84b 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -256,10 +256,17 @@ typedef enum uploadfmt TF_H2_TRANS8_0, /*8bit data, 0 is transparent, not 255*/ TF_H2_T4A4, /*8bit data, weird packing*/ - /*anything below requires a palette*/ + /*this block requires a palette*/ TF_PALETTES, TF_8PAL24, - TF_8PAL32 + TF_8PAL32, + + /*for render targets*/ + TF_DEPTH16, + TF_DEPTH24, + TF_DEPTH32, + TF_RGBA16F, + TF_RGBA32F } uploadfmt_t; //not all modes accept meshes - STENCIL(intentional) and DEPTHONLY(not implemented) @@ -369,3 +376,7 @@ typedef struct rendererinfo_s { #define BE_VBO_Finish rf->BE_VBO_Finish #define BE_VBO_Destroy rf->BE_VBO_Destroy #define BE_Scissor rf->BE_Scissor + +texid_t R2D_RT_Configure(unsigned int id, int width, int height, uploadfmt_t rtfmt); +texid_t R2D_RT_GetTexture(unsigned int id, unsigned int *width, unsigned int *height); + diff --git a/engine/client/net_master.c b/engine/client/net_master.c index d16437abb..3886e6626 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -902,17 +902,18 @@ void NET_SendPollPacket(int len, void *data, netadr_t to) if (ret == -1) { + int er = neterrno(); // wouldblock is silent - if (qerrno == EWOULDBLOCK) + if (er == NET_EWOULDBLOCK) return; - if (qerrno == ECONNREFUSED) + if (er == NET_ECONNREFUSED) return; - if (qerrno == EADDRNOTAVAIL) - Con_DPrintf("NET_SendPollPacket Warning: %i\n", qerrno); + if (er == NET_EADDRNOTAVAIL) + Con_DPrintf("NET_SendPollPacket Warning: %i\n", er); else - Con_Printf ("NET_SendPollPacket ERROR: %i\n", qerrno); + Con_Printf ("NET_SendPollPacket ERROR: %i\n", er); } } @@ -937,23 +938,24 @@ int Master_CheckPollSockets(void) if (ret == -1) { - if (qerrno == EWOULDBLOCK) + int e = neterrno(); + if (e == NET_EWOULDBLOCK) continue; - if (qerrno == EMSGSIZE) + if (e == NET_EMSGSIZE) { SockadrToNetadr (&from, &net_from); Con_Printf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &net_from)); continue; } - if (qerrno == ECONNABORTED || qerrno == ECONNRESET) + if (e == NET_ECONNABORTED || e == NET_ECONNRESET) { // Con_Printf ("Connection lost or aborted\n"); continue; } - Con_Printf ("NET_CheckPollSockets: %i, %s\n", qerrno, strerror(qerrno)); + Con_Printf ("NET_CheckPollSockets: %i, %s\n", e, strerror(e)); continue; } SockadrToNetadr (&from, &net_from); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 7629c56c9..568668651 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -1432,7 +1432,7 @@ static void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars case VF_VIEWENTITY: //switches over EXTERNALMODEL flags and clears WEAPONMODEL flagged entities. //FIXME: make affect addentities(MASK_ENGINE) calls too. - CL_EditExternalModels(*p); + CL_EditExternalModels(*p, NULL, 0); break; case VF_FOV: //explicit fov overrides aproximate fov @@ -1543,6 +1543,47 @@ static void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars r_refdef.useperspective = *p; break; + case VF_RT_DESTCOLOUR: + if (prinst->callargc >= 4) + { + float fmt = G_FLOAT(OFS_PARM2); + float *size = G_VECTOR(OFS_PARM3); + R2D_RT_Configure(*p, size[0], size[1], fmt); + } + r_refdef.rt_destcolour = *p; + GLBE_RenderToTextureUpdate2d(true); + break; + case VF_RT_SOURCECOLOUR: + if (prinst->callargc >= 4) + { + float fmt = G_FLOAT(OFS_PARM2); + float *size = G_VECTOR(OFS_PARM3); + R2D_RT_Configure(*p, size[0], size[1], fmt); + } + r_refdef.rt_sourcecolour = *p; + GLBE_RenderToTextureUpdate2d(false); + break; + case VF_RT_DEPTH: + if (prinst->callargc >= 4) + { + float fmt = G_FLOAT(OFS_PARM2); + float *size = G_VECTOR(OFS_PARM3); + R2D_RT_Configure(*p, size[0], size[1], fmt); + } + r_refdef.rt_depth = *p; + GLBE_RenderToTextureUpdate2d(false); + break; + case VF_RT_RIPPLE: + if (prinst->callargc >= 4) + { + float fmt = G_FLOAT(OFS_PARM2); + float *size = G_VECTOR(OFS_PARM3); + R2D_RT_Configure(*p, size[0], size[1], fmt); + } + r_refdef.rt_ripplemap = *p; + GLBE_RenderToTextureUpdate2d(false); + break; + default: Con_DPrintf("SetViewFlag: %i not recognised\n", parametertype); G_FLOAT(OFS_RETURN) = 0; @@ -1566,10 +1607,10 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars { srect_t srect; - srect.x = (float)r_refdef.grect.x / vid.width; - srect.y = (float)r_refdef.grect.y / vid.height; - srect.width = (float)r_refdef.grect.width / vid.width; - srect.height = (float)r_refdef.grect.height / vid.height; + srect.x = (float)r_refdef.grect.x / vid.fbvwidth; + srect.y = (float)r_refdef.grect.y / vid.fbvheight; + srect.width = (float)r_refdef.grect.width / vid.fbvwidth; + srect.height = (float)r_refdef.grect.height / vid.fbvheight; srect.dmin = -99999; srect.dmax = 99999; srect.y = (1-srect.y) - srect.height; @@ -3982,7 +4023,7 @@ static void QCBUILTIN PF_getentity(pubprogfuncs_t *prinst, struct globalvars_s * if (entnum >= cl.maxlerpents || !cl.lerpentssequence || cl.lerpents[entnum].sequence != cl.lerpentssequence) { - Con_Printf("PF_getentity: entity %i is not valid\n", fldnum); + Con_DPrintf("PF_getentity: entity %i is not valid\n", entnum); VectorCopy(vec3_origin, G_VECTOR(OFS_RETURN)); return; } @@ -4494,6 +4535,7 @@ static struct { {"hash_getkey", PF_hash_getkey, 292}, {"hash_getcb", PF_hash_getcb, 293}, {"checkcommand", PF_checkcommand, 294}, + {"argescape", PF_argescape, 295}, //300 {"clearscene", PF_R_ClearScene, 300}, // #300 void() clearscene (EXT_CSQC) {"addentities", PF_R_AddEntityMask, 301}, // #301 void(float mask) addentities (EXT_CSQC) @@ -4808,6 +4850,12 @@ static struct { {"soundlength", PF_soundlength, 534}, {"buf_loadfile", PF_buf_loadfile, 535}, {"buf_writefile", PF_buf_writefile, 536}, +// {"bufstr_find", PF_Fixme, 537}, +// {"matchpattern", PF_Fixme, 538}, +// {"undefined", PF_Fixme, 539}, + {"physics_enable", PF_physics_enable, 540}, + {"physics_addforce", PF_physics_addforce, 541}, + {"physics_addtorque", PF_physics_addtorque, 542}, {"setmousetarget", PF_cl_setmousetarget, 603}, {"getmousetarget", PF_cl_getmousetarget, 604}, diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index f0f99f93e..22abeb6a1 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -439,7 +439,14 @@ void QCBUILTIN PF_CL_drawpic (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl p = R2D_SafeCachePic(picname); if (!p) p = R2D_SafePicFromWad(picname); - G_FLOAT(OFS_RETURN) = !!p; + + if (!p) + { + if (!CL_IsDownloading(picname)) + p = R2D_SafeCachePic("no_texture"); + } + else + G_FLOAT(OFS_RETURN) = 0; r2d_be_flags = PF_SelectDPDrawFlag(flag); R2D_ImageColours(rgb[0], rgb[1], rgb[2], alpha); diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index 940b9d9c7..974feb7de 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -318,7 +318,7 @@ static dollcreatectx_t *rag_createdoll(model_t *mod, char *fname, int numbones) memset(&ctx->defbody, 0, sizeof(ctx->defbody)); ctx->defbody.animate = true; - ctx->defbody.shape = SOLID_PHYSICS_BOX; + ctx->defbody.geomshape = GEOMTYPE_BOX; ctx->defbody.dimensions[0] = 4; ctx->defbody.dimensions[1] = 4; ctx->defbody.dimensions[2] = 4; @@ -458,13 +458,13 @@ static qboolean rag_dollline(dollcreatectx_t *ctx, int linenum) else if (ctx->body && argc == 2 && !stricmp(cmd, "shape")) { if (!stricmp(val, "box")) - ctx->body->shape = SOLID_PHYSICS_BOX; + ctx->body->geomshape = GEOMTYPE_BOX; else if (!stricmp(val, "sphere")) - ctx->body->shape = SOLID_PHYSICS_SPHERE; + ctx->body->geomshape = GEOMTYPE_SPHERE; else if (!stricmp(val, "cylinder")) - ctx->body->shape = SOLID_PHYSICS_CYLINDER; + ctx->body->geomshape = GEOMTYPE_CYLINDER; else if (!stricmp(val, "capsule")) - ctx->body->shape = SOLID_PHYSICS_CAPSULE; + ctx->body->geomshape = GEOMTYPE_CAPSULE; else if (!ctx->errors++) Con_Printf("^[Joint shape \"%s\" not recognised\\edit\\%s %i^]\n", val, d->name, linenum); } @@ -1259,23 +1259,23 @@ void rag_derive(skelobject_t *sko, skelobject_t *asko, float *emat) World_ODE_RagMatrixFromBody(sko->world, &sko->body[i].odebody, bodymat); - switch(doll->body[i].shape) + switch(doll->body[i].geomshape) { default: - case SOLID_PHYSICS_BOX: + case GEOMTYPE_BOX: VectorScale(doll->body[i].dimensions, -0.5, mins); VectorScale(doll->body[i].dimensions, 0.5, maxs); CLQ1_AddOrientedCube(debugshader, mins, maxs, bodymat, 0.2, 0.2, 0.2, 1); break; - case SOLID_PHYSICS_CYLINDER: + case GEOMTYPE_CYLINDER: rad = (doll->body[i].dimensions[0] + doll->body[i].dimensions[1])*0.5; CLQ1_AddOrientedCylinder(debugshader, rad, doll->body[i].dimensions[2], false, bodymat, 0.2, 0.2, 0.2, 1); break; - case SOLID_PHYSICS_CAPSULE: + case GEOMTYPE_CAPSULE: rad = (doll->body[i].dimensions[0] + doll->body[i].dimensions[1])*0.5; CLQ1_AddOrientedCylinder(debugshader, rad, doll->body[i].dimensions[2], true, bodymat, 0.2, 0.2, 0.2, 1); break; - case SOLID_PHYSICS_SPHERE: + case GEOMTYPE_SPHERE: rad = (doll->body[i].dimensions[0] + doll->body[i].dimensions[1] + doll->body[i].dimensions[2])/3; CLQ1_AddOrientedCylinder(debugshader, rad, rad, true, bodymat, 0.2, 0.2, 0.2, 1); break; diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index d73d31907..a9550b815 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -34,6 +34,15 @@ static avec4_t draw_mesh_colors[4]; index_t r_quad_indexes[6] = {0, 1, 2, 2, 3, 0}; unsigned int r2d_be_flags; +static struct +{ + texid_t id; + int width; + int height; + uploadfmt_t fmt; +} *rendertargets; +static unsigned int numrendertargets; + extern cvar_t scr_conalpha; extern cvar_t gl_conback; extern cvar_t gl_font; @@ -116,6 +125,11 @@ void R2D_Shutdown(void) cl_numstris = 0; cl_maxstris = 0; + while (numrendertargets>0) + R_DestroyTexture(rendertargets[--numrendertargets].id); + free(rendertargets); + rendertargets = NULL; + if (font_console == font_default) font_console = NULL; @@ -344,8 +358,8 @@ mpic_t *R2D_SafePicFromWad (char *name) char newnamegfx[32]; shader_t *s; - snprintf(newnamewad, sizeof(newnamewad), "wad/%s.lmp", name); - snprintf(newnamegfx, sizeof(newnamegfx), "gfx/%s.lmp", name); + snprintf(newnamewad, sizeof(newnamewad), "wad/%s", name); + snprintf(newnamegfx, sizeof(newnamegfx), "gfx/%s", name); s = R_RegisterPic(newnamewad); if (!(s->flags & SHADER_NOIMAGE)) @@ -615,7 +629,7 @@ void R2D_Conback_Callback(struct cvar_s *var, char *oldvalue) } } -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_SDL) #include qboolean R2D_Font_WasAdded(char *buffer, char *fontfilename) { @@ -1279,6 +1293,77 @@ void R2D_DrawCrosshair(void) R2D_ImageColours(1, 1, 1, 1); } +//resize a texture for a render target and specify the format of it. +//pass TF_INVALID and sizes=0 to get without configuring (shaders that hardcode an $rt1 etc). +texid_t R2D_RT_Configure(unsigned int id, int width, int height, uploadfmt_t rtfmt) +{ + id--; //0 is invalid. + if (id < 0 || id > 255) //sanity limit + return r_nulltex; + + //extend the array if needed. these should be fairly light. + if (id >= numrendertargets) + { + rendertargets = realloc(rendertargets, (id+1) * sizeof(*rendertargets)); + while(numrendertargets <= id) + { + rendertargets[numrendertargets].id = r_nulltex; + rendertargets[numrendertargets].width = 0; + rendertargets[numrendertargets].height = 0; + rendertargets[numrendertargets].fmt = TF_INVALID; + numrendertargets++; + } + } + + if (!TEXVALID(rendertargets[id].id)) + rendertargets[id].id = R_AllocNewTexture(va("", id+1), 0, 0, IF_NOMIPMAP); + if (rtfmt) + { + switch(rtfmt) + { + case 1: rtfmt = TF_RGBA32; break; + case 2: rtfmt = TF_RGBA16F; break; + case 3: rtfmt = TF_RGBA32F; break; + case 4: rtfmt = TF_DEPTH16; break; + case 5: rtfmt = TF_DEPTH24; break; + case 6: rtfmt = TF_DEPTH32; break; + default:rtfmt = TF_INVALID; break; + } + +// if (rendertargets[id].fmt != rtfmt || rendertargets[id].width != width || rendertargets[id].height != height) + { + rendertargets[id].fmt = rtfmt; + rendertargets[id].width = width; + rendertargets[id].height = height; + R_Upload(rendertargets[id].id, "", rtfmt, NULL, NULL, width, height, IF_NOMIPMAP); + } + } + return rendertargets[id].id; +} +texid_t R2D_RT_GetTexture(unsigned int id, unsigned int *width, unsigned int *height) +{ + if (!id) + { + *width = 0; + *height = 0; + return r_nulltex; + } + id--; + if (id >= numrendertargets) + { + Con_Printf("Render target %u is not configured\n", id); + R2D_RT_Configure(id, 0, 0, TF_INVALID); + if (id >= numrendertargets) + { + *width = 0; + *height = 0; + return r_nulltex; + } + } + *width = rendertargets[id].width; + *height = rendertargets[id].height; + return rendertargets[id].id; +} #endif diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index 39df8a366..8d81ac781 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -1510,12 +1510,11 @@ char *particle_set_high = "scalefactor 1\n" "scaledelta -15\n" "randomvel 0\n" - -"lightradius 350\n" -"lightrgb 1.4 1.2 1.05\n" -"lighttime 0.5\n" -"lightradiusfade 350\n" -"lightrgbfade 2 2 2 \n" +// lightradius 350 +// lightrgb 1.4 1.2 1.05 +// lighttime 0.5 +// lightradiusfade 350 +// lightrgbfade 2 2 2 "}\n" //smoke "r_part +te_explosion\n" @@ -1558,7 +1557,7 @@ char *particle_set_high = "}\n" //hide lights in explosions. -"r_explosionlight 0\n" +//r_explosionlight 0 //hide the explosion sprite in nq+qw - WARNING: some mods use this sprite as a flame thrower. "cl_expsprite 0\n" diff --git a/engine/client/render.h b/engine/client/render.h index d485b0ba6..7cc16319d 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -150,6 +150,7 @@ typedef struct mplane_s #define MAXFRUSTUMPLANES 7 //4 side, 1 near, 1 far (fog), 1 water plane. #define R_MAX_RECURSE 6 +#define R_POSTPROC_PASSES 6 #define RDFD_FOV 1 typedef struct { @@ -188,8 +189,10 @@ typedef struct unsigned int flipcull; /*reflected/flipped view, requires inverted culling (should be set to SHADER_CULL_FLIPPED or 0)*/ qboolean useperspective; /*not orthographic*/ - int postprocshader; /*if set, renders to texture then invokes this shader*/ - int postproccube; /*postproc shader wants a cubemap, this is the mask of sides required*/ + int rt_destcolour; /*used for 2d. written by 3d*/ + int rt_sourcecolour; /*read by 2d. not used for 3d. */ + int rt_depth; /*read by 2d. used by 3d (renderbuffer used if not set)*/ + int rt_ripplemap; /*read by 2d. used by 3d (internal ripplemap buffer used if not set)*/ qbyte *forcedvis; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index fb2c9ef26..798d17e58 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -45,8 +45,8 @@ void GL_Texturemode2d_Callback (struct cvar_s *var, char *oldvalue); void GL_Texture_Anisotropic_Filtering_Callback (struct cvar_s *var, char *oldvalue); #endif -cvar_t _vid_wait_override = CVARAF ("vid_wait", "0", - "_vid_wait_override", CVAR_ARCHIVE); +cvar_t vid_vsync = CVARAF ("vid_wait", "0", + "vid_vsync", CVAR_ARCHIVE); cvar_t _windowed_mouse = CVARF ("_windowed_mouse","1", CVAR_ARCHIVE); @@ -63,7 +63,7 @@ cvar_t gl_part_flame = CVARFD ("gl_part_flame", "1", CVAR_ARCHIVE, "Enable //opengl library, blank means try default. static cvar_t gl_driver = CVARF ("gl_driver", "", CVAR_ARCHIVE | CVAR_RENDERERLATCH); -cvar_t gl_shadeq1_name = CVAR ("gl_shadeq1_name", "*"); +cvar_t gl_shadeq1_name = CVARD ("gl_shadeq1_name", "*", "Rename all surfaces from quake1 bsps using this pattern for the purposes of shader names."); extern cvar_t r_vertexlight; cvar_t mod_md3flags = CVAR ("mod_md3flags", "1"); @@ -107,8 +107,8 @@ cvar_t r_floorcolour = CVARAF ("r_floorcolour", "64 64 128", "r_floorcolor", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); cvar_t r_floortexture = SCVARF ("r_floortexture", "", CVAR_RENDERERCALLBACK|CVAR_SHADERSYSTEM); -cvar_t r_fullbright = SCVARF ("r_fullbright", "0", - CVAR_CHEAT|CVAR_SHADERSYSTEM); +cvar_t r_fullbright = CVARFD ("r_fullbright", "0", + CVAR_CHEAT|CVAR_SHADERSYSTEM, "Ignore world lightmaps, drawing everything fully lit."); cvar_t r_fullbrightSkins = SCVARF ("r_fullbrightSkins", "0.8", /*don't default to 1, as it looks a little ugly (too bright), but don't default to 0 either because then you're handicapped in the dark*/ CVAR_SEMICHEAT|CVAR_SHADERSYSTEM); cvar_t r_lightmap_saturation = SCVAR ("r_lightmap_saturation", "1"); @@ -145,8 +145,8 @@ cvar_t r_wateralpha = CVARF ("r_wateralpha", "1", cvar_t r_waterwarp = CVARF ("r_waterwarp", "1", CVAR_ARCHIVE); -cvar_t r_replacemodels = CVARF ("r_replacemodels", IFMINIMAL("","md3 md2"), - CVAR_ARCHIVE); +cvar_t r_replacemodels = CVARFD ("r_replacemodels", IFMINIMAL("","md3 md2"), + CVAR_ARCHIVE, "A list of filename extensions to attempt to use instead of mdl."); //otherwise it would defeat the point. cvar_t scr_allowsnap = CVARF ("scr_allowsnap", "1", @@ -184,33 +184,33 @@ cvar_t vid_conheight = CVARF ("vid_conheight", "0", cvar_t vid_conwidth = CVARF ("vid_conwidth", "0", CVAR_ARCHIVE | CVAR_RENDERERCALLBACK); //see R_RestartRenderer_f for the effective default 'if (newr.renderer == -1)'. -cvar_t vid_renderer = CVARF ("vid_renderer", "", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); +cvar_t vid_renderer = CVARFD ("vid_renderer", "", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Specifies which backend is used. Values that might work are: sv (dedicated server), gl (opengl), egl (opengl es), d3d9 (direct3d 9), d3d11 (direct3d 11, with default hardware rendering), d3d11 warp (direct3d 11, with software rendering)."); -cvar_t vid_bpp = CVARF ("vid_bpp", "32", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); -cvar_t vid_desktopsettings = CVARF ("vid_desktopsettings", "0", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); +cvar_t vid_bpp = CVARFD ("vid_bpp", "32", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The number of colour bits to request from the renedering context"); +cvar_t vid_desktopsettings = CVARFD ("vid_desktopsettings", "0", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Ignore the values of vid_width and vid_height, and just use the same settings that are used for the desktop."); #ifdef NACL cvar_t vid_fullscreen = CVARF ("vid_fullscreen", "0", CVAR_ARCHIVE); #else //these cvars will be given their names when they're registered, based upon whether -plugin was used. this means code can always use vid_fullscreen without caring, but gets saved properly. -cvar_t vid_fullscreen = CVARAF (NULL, "1", "vid_fullscreen", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); -cvar_t vid_fullscreen_alternative = CVARF (NULL, "1", - CVAR_ARCHIVE); +cvar_t vid_fullscreen = CVARAFD (NULL, "1", "vid_fullscreen", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Whether to use fullscreen or not."); +cvar_t vid_fullscreen_alternative = CVARFD (NULL, "1", + CVAR_ARCHIVE, "Whether to use fuollscreen or not. This cvar is saved to your config but not otherwise used in this operating mode."); #endif -cvar_t vid_height = CVARF ("vid_height", "0", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); +cvar_t vid_height = CVARFD ("vid_height", "0", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The screen height to attempt to use, in physical pixels. 0 means use desktop resolution."); cvar_t vid_multisample = CVARF ("vid_multisample", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH); cvar_t vid_refreshrate = CVARF ("vid_displayfrequency", "0", CVAR_ARCHIVE | CVAR_RENDERERLATCH); cvar_t vid_wndalpha = CVAR ("vid_wndalpha", "1"); //more readable defaults to match conwidth/conheight. -cvar_t vid_width = CVARF ("vid_width", "0", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); +cvar_t vid_width = CVARFD ("vid_width", "0", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "The screen width to attempt to use, in physical pixels. 0 means use desktop resolution."); cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far your eyes are apart, in quake units. A non-zero value will enable stereoscoping rendering. You might need some of them retro 3d glasses. Hardware support is recommended, see r_stereo_context."); cvar_t r_stereo_method = CVARD("r_stereo_method", "0", "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain."); @@ -223,7 +223,7 @@ extern cvar_t r_drawentities; extern cvar_t r_drawviewmodel; extern cvar_t r_drawworld; extern cvar_t r_fullbright; -cvar_t r_mirroralpha = SCVARF("r_mirroralpha","1", CVAR_CHEAT|CVAR_SHADERSYSTEM); +cvar_t r_mirroralpha = CVARFD("r_mirroralpha","1", CVAR_CHEAT|CVAR_SHADERSYSTEM, "Specifies how the default shader is generated for the 'window02_1' texture. Values less than 1 will turn it into a mirror."); extern cvar_t r_netgraph; extern cvar_t r_norefresh; extern cvar_t r_novis; @@ -246,11 +246,11 @@ rendererstate_t currentrendererstate; #if defined(GLQUAKE) cvar_t gl_workaround_ati_shadersource = CVARD ("gl_workaround_ati_shadersource", "1", "Work around ATI driver bugs in the glShaderSource function. Can safely be enabled with other drivers too."); -cvar_t vid_gl_context_version = SCVAR ("vid_gl_context_version", ""); -cvar_t vid_gl_context_forwardcompatible = SCVAR ("vid_gl_context_forwardcompatible", "0"); -cvar_t vid_gl_context_compatibility = SCVAR ("vid_gl_context_compatibility", "1"); -cvar_t vid_gl_context_debug = SCVAR ("vid_gl_context_debug", "0"); //for my ati drivers, debug 1 only works if version >= 3 -cvar_t vid_gl_context_es2 = SCVAR ("vid_gl_context_es2", "0"); //requires version set correctly, no debug, no compat +cvar_t vid_gl_context_version = CVARD ("vid_gl_context_version", "", "Specifies the version of OpenGL to try to create."); +cvar_t vid_gl_context_forwardcompatible = CVARD ("vid_gl_context_forwardcompatible", "0", "Requests an opengl context with no depricated features enabled."); +cvar_t vid_gl_context_compatibility = CVARD ("vid_gl_context_compatibility", "1", "Requests an OpenGL context with fixed-function backwards compat."); +cvar_t vid_gl_context_debug = CVARD ("vid_gl_context_debug", "0", "Requests a debug opengl context. This provides better error oreporting."); //for my ati drivers, debug 1 only works if version >= 3 +cvar_t vid_gl_context_es = CVARD ("vid_gl_context_es", "0", "Requests an OpenGLES context. Be sure to set vid_gl_context_version to 2 or so."); //requires version set correctly, no debug, no compat #endif #if defined(GLQUAKE) || defined(D3DQUAKE) @@ -258,23 +258,22 @@ cvar_t gl_ati_truform = CVAR ("gl_ati_truform", "0"); cvar_t gl_ati_truform_type = CVAR ("gl_ati_truform_type", "1"); cvar_t gl_ati_truform_tesselation = CVAR ("gl_ati_truform_tesselation", "3"); cvar_t gl_blend2d = CVAR ("gl_blend2d", "1"); -cvar_t gl_blendsprites = CVAR ("gl_blendsprites", "0"); -cvar_t r_deluxemapping = CVARAF ("r_deluxemapping", "0", "r_glsl_deluxemapping", - CVAR_ARCHIVE | CVAR_RENDERERLATCH); -cvar_t gl_compress = CVARF ("gl_compress", "0", - CVAR_ARCHIVE); -cvar_t gl_conback = CVARFC ("gl_conback", "", - CVAR_RENDERERCALLBACK, R2D_Conback_Callback); -cvar_t gl_detail = CVARF ("gl_detail", "0", - CVAR_ARCHIVE); -cvar_t gl_detailscale = CVAR ("gl_detailscale", "5"); +cvar_t gl_blendsprites = CVARD ("gl_blendsprites", "0", "Blend sprites instead of alpha testing them"); +cvar_t r_deluxemapping = CVARAFD ("r_deluxemapping", "0", "r_glsl_deluxemapping", + CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Enables bumpmapping based upon precomputed light directions"); +cvar_t gl_compress = CVARFD ("gl_compress", "0", CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed."); +cvar_t gl_conback = CVARFDC ("gl_conback", "", + CVAR_RENDERERCALLBACK, "Specifies which conback shader/image to use. The Quake fallback is gfx/conback.lmp", R2D_Conback_Callback); +//cvar_t gl_detail = CVARF ("gl_detail", "0", +// CVAR_ARCHIVE); +//cvar_t gl_detailscale = CVAR ("gl_detailscale", "5"); cvar_t gl_font = CVARFD ("gl_font", "", CVAR_RENDERERCALLBACK, ("Specifies the font file to use. a value such as FONT:ALTFONT specifies an alternative font to be used when ^^a is used.\n" "When using TTF fonts, you will likely need to scale text to at least 150% - vid_conautoscale 1.5 will do this.\n" "TTF fonts may be loaded from your windows directory. \'gl_font cour:couri\' loads eg: c:\\windows\\fonts\\cour.ttf, and uses the italic version of courier for alternative text." )); cvar_t gl_lateswap = CVAR ("gl_lateswap", "0"); -cvar_t gl_lerpimages = CVARF ("gl_lerpimages", "1", CVAR_ARCHIVE); +cvar_t gl_lerpimages = CVARFD ("gl_lerpimages", "1", CVAR_ARCHIVE, "Enables smoother resampling for images which are not power-of-two, when the drivers do not support non-power-of-two textures."); //cvar_t gl_lightmapmode = SCVARF("gl_lightmapmode", "", // CVAR_ARCHIVE); cvar_t gl_load24bit = SCVARF ("gl_load24bit", "1", @@ -282,14 +281,14 @@ cvar_t gl_load24bit = SCVARF ("gl_load24bit", "1", cvar_t r_clear = CVARAF("r_clear","0", "gl_clear", 0); -cvar_t gl_max_size = SCVARF ("gl_max_size", "2048", CVAR_RENDERERLATCH); +cvar_t gl_max_size = CVARFD ("gl_max_size", "8192", CVAR_RENDERERLATCH, "Specifies the maximum texture size that the engine may use. Textures larger than this will be downsized. Clamped by the value the driver supports."); cvar_t gl_maxshadowlights = SCVARF ("gl_maxshadowlights", "2", CVAR_ARCHIVE); -cvar_t gl_menutint_shader = SCVAR ("gl_menutint_shader", "1"); +cvar_t gl_menutint_shader = CVARD ("gl_menutint_shader", "1", "Controls the use of GLSL to desaturate the background when drawing the menu, like quake's dos software renderer used to do before the ugly dithering of winquake."); //by setting to 64 or something, you can use this as a wallhack -cvar_t gl_mindist = SCVARF ("gl_mindist", "4", - CVAR_CHEAT); +cvar_t gl_mindist = CVARFD ("gl_mindist", "4", + CVAR_CHEAT, "Distance to the near clip plane. Smaller values may damage depth precision, high values can potentialy be used to see through walls..."); cvar_t gl_motionblur = SCVARF ("gl_motionblur", "0", CVAR_ARCHIVE); @@ -299,14 +298,14 @@ cvar_t gl_overbright = CVARFC ("gl_overbright", "1", Surf_RebuildLightmap_Callback); cvar_t gl_overbright_all = SCVARF ("gl_overbright_all", "0", CVAR_ARCHIVE); -cvar_t gl_picmip = CVARF ("gl_picmip", "0", CVAR_ARCHIVE); -cvar_t gl_picmip2d = CVARF ("gl_picmip2d", "0", CVAR_ARCHIVE); -cvar_t gl_nohwblend = SCVAR ("gl_nohwblend","1"); -cvar_t gl_savecompressedtex = SCVAR ("gl_savecompressedtex", "0"); -cvar_t gl_schematics = SCVAR ("gl_schematics", "0"); -cvar_t gl_skyboxdist = SCVAR ("gl_skyboxdist", "0"); //0 = guess. +cvar_t gl_picmip = CVARFD ("gl_picmip", "0", CVAR_ARCHIVE, "Reduce world/model texture sizes by some exponential factor."); +cvar_t gl_picmip2d = CVARFD ("gl_picmip2d", "0", CVAR_ARCHIVE, "Reduce hud/menu texture sizes by some exponential factor."); +cvar_t gl_nohwblend = CVARD ("gl_nohwblend","1", "If 1, don't use hardware gamma ramps for transient effects that change each frame (does not affect long-term effects like holding quad or underwater tints)."); +cvar_t gl_savecompressedtex = CVARD ("gl_savecompressedtex", "0", "Write out a copy of textures in a compressed format. The driver will do the compression on the fly, thus this setting is likely inferior to software which does not care so much about compression times."); +//cvar_t gl_schematics = CVARD ("gl_schematics", "0", "Gimmick rendering mode that draws the length of various world edges."); +cvar_t gl_skyboxdist = CVARD ("gl_skyboxdist", "0", "The distance of the skybox. If 0, the engine will determine it based upon the far clip plane distance."); //0 = guess. cvar_t gl_smoothcrosshair = SCVAR ("gl_smoothcrosshair", "1"); -cvar_t gl_maxdist = SCVAR("gl_maxdist", "8192"); +cvar_t gl_maxdist = CVARD ("gl_maxdist", "8192", "The distance of the far clip plane. If set to 0, some fancy maths will be used to place it at an infinite distance."); #ifdef SPECULAR cvar_t gl_specular = CVARF ("gl_specular", "1", CVAR_ARCHIVE); @@ -329,33 +328,30 @@ cvar_t gl_texturemode2d = CVARFC("gl_texturemode2d", "GL_LINEAR", GL_Texturemode2d_Callback); #endif -cvar_t vid_triplebuffer = CVARAF ("vid_triplebuffer", "1", - "gl_triplebuffer", CVAR_ARCHIVE); +cvar_t vid_triplebuffer = CVARAFD ("vid_triplebuffer", "1", "gl_triplebuffer", CVAR_ARCHIVE, "Specifies whether the hardware is forcing tripplebuffering on us, this is the number of extra page swaps required before old data has been completely overwritten."); cvar_t r_portalrecursion = CVARD ("r_portalrecursion", "1", "The number of portals the camera is allowed to recurse through."); cvar_t dpcompat_psa_ungroup = SCVAR ("dpcompat_psa_ungroup", "0"); -cvar_t r_noaliasshadows = SCVARF ("r_noaliasshadows", "0", - CVAR_ARCHIVE); -cvar_t r_shadows = SCVARF ("r_shadows", "0", - CVAR_ARCHIVE); +cvar_t r_noaliasshadows = SCVARF ("r_noaliasshadows", "0", CVAR_ARCHIVE); +cvar_t r_shadows = CVARFD ("r_shadows", "0", CVAR_ARCHIVE, "Draw basic blob shadows underneath entities without using realtime lighting."); cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground."); cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism."); cvar_t r_shadow_bumpscale_basetexture = CVARD ("r_shadow_bumpscale_basetexture", "0", "bumpyness scaler for generation of fallback normalmap textures from models"); cvar_t r_shadow_bumpscale_bumpmap = CVARD ("r_shadow_bumpscale_bumpmap", "4", "bumpyness scaler for _bump textures"); -cvar_t r_glsl_offsetmapping = CVARF ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM); +cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures."); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); -cvar_t r_glsl_offsetmapping_reliefmapping = CVARF("r_glsl_offsetmapping_reliefmapping", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM); -cvar_t r_glsl_turbscale = CVARF ("r_glsl_turbscale", "1", CVAR_ARCHIVE); +cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer. r_glsl_offsetmapping must be set."); +//cvar_t r_glsl_turbscale = CVARF ("r_glsl_turbscale", "1", CVAR_ARCHIVE); cvar_t r_waterstyle = CVARFD ("r_waterstyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes how water, and teleporters are drawn. Possible values are:\n0: fastturb-style block colour.\n1: regular q1-style water.\n2: refraction(ripply and transparent)\n3: refraction with reflection at an angle\n4: ripplemapped without reflections (requires particle effects)\n5: ripples+reflections"); cvar_t r_slimestyle = CVARFD ("r_slimestyle", "", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only slime. If empty, defers to r_waterstyle."); cvar_t r_lavastyle = CVARFD ("r_lavastyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only lava. If empty, defers to r_waterstyle."); -cvar_t r_vertexdlights = SCVAR ("r_vertexdlights", "0"); +cvar_t r_vertexdlights = CVARD ("r_vertexdlights", "0", "Determine model lighting with respect to nearby dlights. Poor-man's rtlights."); -cvar_t vid_preservegamma = SCVAR ("vid_preservegamma", "0"); +cvar_t vid_preservegamma = CVARD ("vid_preservegamma", "0", "Restore initial hardware gamma ramps when quitting."); cvar_t vid_hardwaregamma = CVARFD ("vid_hardwaregamma", "1", CVAR_ARCHIVE | CVAR_RENDERERLATCH, "Use hardware gamma ramps. 0=loadtime-gamma, 1=glsl(windowed) or hardware(fullscreen), 2=always glsl, 3=always hardware gamma."); cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0", @@ -386,7 +382,7 @@ void GLRenderer_Init(void) Cvar_Register (&vid_gl_context_debug, GLRENDEREROPTIONS); Cvar_Register (&vid_gl_context_forwardcompatible, GLRENDEREROPTIONS); Cvar_Register (&vid_gl_context_compatibility, GLRENDEREROPTIONS); - Cvar_Register (&vid_gl_context_es2, GLRENDEREROPTIONS); + Cvar_Register (&vid_gl_context_es, GLRENDEREROPTIONS); //screen Cvar_Register (&vid_preservegamma, GLRENDEREROPTIONS); @@ -424,7 +420,7 @@ void GLRenderer_Init(void) Cvar_Register (&r_glsl_offsetmapping, GRAPHICALNICETIES); Cvar_Register (&r_glsl_offsetmapping_scale, GRAPHICALNICETIES); Cvar_Register (&r_glsl_offsetmapping_reliefmapping, GRAPHICALNICETIES); - Cvar_Register (&r_glsl_turbscale, GRAPHICALNICETIES); +// Cvar_Register (&r_glsl_turbscale, GRAPHICALNICETIES); #ifdef R_XFLIP @@ -442,8 +438,8 @@ void GLRenderer_Init(void) Cvar_Register (&gl_texture_anisotropic_filtering, GLRENDEREROPTIONS); Cvar_Register (&gl_savecompressedtex, GLRENDEREROPTIONS); Cvar_Register (&gl_compress, GLRENDEREROPTIONS); - Cvar_Register (&gl_detail, GRAPHICALNICETIES); - Cvar_Register (&gl_detailscale, GRAPHICALNICETIES); +// Cvar_Register (&gl_detail, GRAPHICALNICETIES); +// Cvar_Register (&gl_detailscale, GRAPHICALNICETIES); Cvar_Register (&gl_overbright, GRAPHICALNICETIES); Cvar_Register (&gl_overbright_all, GRAPHICALNICETIES); Cvar_Register (&gl_dither, GRAPHICALNICETIES); @@ -464,7 +460,7 @@ void GLRenderer_Init(void) Cvar_Register (&r_vertexdlights, GLRENDEREROPTIONS); - Cvar_Register (&gl_schematics, GLRENDEREROPTIONS); +// Cvar_Register (&gl_schematics, GLRENDEREROPTIONS); Cvar_Register (&r_vertexlight, GLRENDEREROPTIONS); @@ -562,7 +558,7 @@ void Renderer_Init(void) //but register ALL vid_ commands. Cvar_Register (&gl_driver, GLRENDEREROPTIONS); - Cvar_Register (&_vid_wait_override, VIDCOMMANDGROUP); + Cvar_Register (&vid_vsync, VIDCOMMANDGROUP); Cvar_Register (&_windowed_mouse, VIDCOMMANDGROUP); Cvar_Register (&vid_renderer, VIDCOMMANDGROUP); Cvar_Register (&vid_wndalpha, VIDCOMMANDGROUP); @@ -1360,10 +1356,10 @@ qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) newr->rate = vid_refreshrate.value; newr->stereo = (r_stereo_method.ival == 1); - if (!*_vid_wait_override.string || _vid_wait_override.value < 0) + if (!*vid_vsync.string || vid_vsync.value < 0) newr->wait = -1; else - newr->wait = _vid_wait_override.value; + newr->wait = vid_vsync.value; newr->renderer = NULL; diff --git a/engine/client/roq.h b/engine/client/roq.h index b3d8f8c31..cab0e4b1e 100644 --- a/engine/client/roq.h +++ b/engine/client/roq.h @@ -28,7 +28,7 @@ typedef struct { roq_cell cells[256]; roq_qcell qcells[256]; short snd_sqr_arr[256]; - long roq_start, aud_pos, vid_pos; + qofs_t roq_start, aud_pos, vid_pos; long *frame_offset; unsigned long num_frames, num_audio_bytes; int width, height, frame_num, audio_channels; diff --git a/engine/client/roq_read.c b/engine/client/roq_read.c index 5c3aea5db..8f2ad5943 100644 --- a/engine/client/roq_read.c +++ b/engine/client/roq_read.c @@ -70,7 +70,7 @@ static int roq_parse_file(vfsfile_t *fp, roq_info *ri) { unsigned int head1, head3, chunk_id;//, chunk_arg; long head2, chunk_size; -long fpos; +qofs_t fpos; #ifndef FAST int max_frame; #endif @@ -400,7 +400,7 @@ unsigned char *tp, *buf; int frame_stats[2][4] = {{0},{0}}; roq_qcell *qcell; -long fpos = ri->vid_pos; +qofs_t fpos = ri->vid_pos; VFS_SEEK(fp, fpos); while(fpos+8 < ri->maxpos) diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index e07aced40..7246bab2d 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -50,7 +50,7 @@ vec3_t listener_up = {0, 0, 1}; vec3_t listener_velocity; vec_t sound_nominal_clip_dist=1000.0; -#define MAX_SFX 2048 +#define MAX_SFX 8192 sfx_t *known_sfx; // hunk allocated [MAX_SFX] int num_sfx; @@ -3085,9 +3085,9 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, { soundcardinfo_t *si; int i; - int prepadl; - int spare; - int outsamples; + int prepadl; //this is the amount of data that was previously available, and will be removed from the buffer. + int spare; //the amount of existing data that is still left to be played + int outsamples; //the amount of data we're going to add (at the output rate) double speedfactor; qbyte *newcache; streaming_t *s, *free=NULL; @@ -3150,7 +3150,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, s->width = width; s->numchannels = channels; s->length = 0; -// Con_Printf("Restarting raw stream\n"); + Con_Printf("Restarting raw stream\n"); } speedfactor = (double)speed/snd_speed; @@ -3188,7 +3188,7 @@ void S_RawAudio(int sourceid, qbyte *data, int speed, int samples, int channels, if (spare < 0) //remaining samples since last time spare = 0; - if (spare > snd_speed*2) // more than 2 seconds of sound + if (spare > snd_speed*2) // more than 2 seconds of sound. don't buffer more than 2 seconds. 1: its probably buggy if we need to. 2: takes too much memory, and we use malloc+copies. { Con_DPrintf("Sacrificed raw sound stream\n"); spare = 0; //too far out. sacrifice it all diff --git a/engine/client/snd_mix.c b/engine/client/snd_mix.c index aa9c8dcd2..3a4763696 100644 --- a/engine/client/snd_mix.c +++ b/engine/client/snd_mix.c @@ -104,16 +104,16 @@ CHANNEL MIXING =============================================================================== */ -void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime); -void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime); -void SND_PaintChannelFrom8_4Speaker (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom16_4Speaker (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom8_6Speaker (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom16_6Speaker (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom8_8Speaker (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom16_8Speaker (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom8Stereo (channel_t *ch, sfxcache_t *sc, int count); -void SND_PaintChannelFrom16Stereo (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count); +static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count); +static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count); +static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count); +static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count); //NOTE: MAY NOT CALL SYS_ERROR void S_PaintChannels(soundcardinfo_t *sc, int endtime) @@ -216,28 +216,28 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) if (scache->width == 1) { if (scache->numchannels==2) - SND_PaintChannelFrom8Stereo(ch, scache, count); - else if (sc->sn.numchannels == 8) - SND_PaintChannelFrom8_8Speaker(ch, scache, count); - else if (sc->sn.numchannels == 6) - SND_PaintChannelFrom8_6Speaker(ch, scache, count); - else if (sc->sn.numchannels == 4) - SND_PaintChannelFrom8_4Speaker(ch, scache, count); + SND_PaintChannel8_O2I2(ch, scache, ltime-sc->paintedtime, count); + else if (sc->sn.numchannels <= 2) + SND_PaintChannel8_O2I1(ch, scache, ltime-sc->paintedtime, count); + else if (sc->sn.numchannels <= 4) + SND_PaintChannel8_O4I1(ch, scache, count); + else if (sc->sn.numchannels <= 6) + SND_PaintChannel8_O6I1(ch, scache, count); else - SND_PaintChannelFrom8(ch, scache, count); + SND_PaintChannel8_O8I1(ch, scache, count); } else { if (scache->numchannels==2) - SND_PaintChannelFrom16Stereo(ch, scache, count); - else if (sc->sn.numchannels == 8) - SND_PaintChannelFrom16_8Speaker(ch, scache, count); - else if (sc->sn.numchannels == 6) - SND_PaintChannelFrom16_6Speaker(ch, scache, count); - else if (sc->sn.numchannels == 4) - SND_PaintChannelFrom16_4Speaker(ch, scache, count); + SND_PaintChannel16_O2I2(ch, scache, ltime-sc->paintedtime, count); + else if (sc->sn.numchannels <= 2) + SND_PaintChannel16_O2I1(ch, scache, ltime-sc->paintedtime, count); + else if (sc->sn.numchannels <= 4) + SND_PaintChannel16_O4I1(ch, scache, count); + else if (sc->sn.numchannels <= 6) + SND_PaintChannel16_O6I1(ch, scache, count); else - SND_PaintChannelFrom16(ch, scache, count); + SND_PaintChannel16_O8I1(ch, scache, count); } ltime += count; ch->pos += ch->rate * count; @@ -282,7 +282,7 @@ void S_PaintChannels(soundcardinfo_t *sc, int endtime) } } -void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count) { int data; signed char *sfx; @@ -296,8 +296,8 @@ void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) { data = sfx[pos>>PITCHSHIFT]; pos += ch->rate; - paintbuffer[i].s[0] += ch->vol[0] * data; - paintbuffer[i].s[1] += ch->vol[1] * data; + paintbuffer[starttime+i].s[0] += ch->vol[0] * data; + paintbuffer[starttime+i].s[1] += ch->vol[1] * data; } } else @@ -306,13 +306,13 @@ void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) for (i=0 ; ivol[0] * data; - paintbuffer[i].s[1] += ch->vol[1] * data; + paintbuffer[starttime+i].s[0] += ch->vol[0] * data; + paintbuffer[starttime+i].s[1] += ch->vol[1] * data; } } } -void SND_PaintChannelFrom8Stereo (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count) { // int data; signed char *sfx; @@ -324,8 +324,8 @@ void SND_PaintChannelFrom8Stereo (channel_t *ch, sfxcache_t *sc, int count) sfx = (signed char *)sc->data; for (i=0 ; ivol[0] * sfx[(pos>>(PITCHSHIFT-1))&~1]; - paintbuffer[i].s[1] += ch->vol[1] * sfx[(pos>>(PITCHSHIFT-1))|1]; + paintbuffer[starttime+i].s[0] += ch->vol[0] * sfx[(pos>>(PITCHSHIFT-1))&~1]; + paintbuffer[starttime+i].s[1] += ch->vol[1] * sfx[(pos>>(PITCHSHIFT-1))|1]; pos += ch->rate; } } @@ -334,13 +334,13 @@ void SND_PaintChannelFrom8Stereo (channel_t *ch, sfxcache_t *sc, int count) sfx = (signed char *)sc->data + (pos>>PITCHSHIFT)*2; for (i=0 ; ivol[0] * sfx[(i<<1)]; - paintbuffer[i].s[1] += ch->vol[1] * sfx[(i<<1)+1]; + paintbuffer[starttime+i].s[0] += ch->vol[0] * sfx[(i<<1)]; + paintbuffer[starttime+i].s[1] += ch->vol[1] * sfx[(i<<1)+1]; } } } -void SND_PaintChannelFrom8_4Speaker (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O4I1 (channel_t *ch, sfxcache_t *sc, int count) { signed char *sfx; int i; @@ -373,7 +373,7 @@ void SND_PaintChannelFrom8_4Speaker (channel_t *ch, sfxcache_t *sc, int count) } } -void SND_PaintChannelFrom8_6Speaker (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O6I1 (channel_t *ch, sfxcache_t *sc, int count) { signed char *sfx; int i; @@ -410,7 +410,7 @@ void SND_PaintChannelFrom8_6Speaker (channel_t *ch, sfxcache_t *sc, int count) } } -void SND_PaintChannelFrom8_8Speaker (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel8_O8I1 (channel_t *ch, sfxcache_t *sc, int count) { signed char *sfx; int i; @@ -452,7 +452,7 @@ void SND_PaintChannelFrom8_8Speaker (channel_t *ch, sfxcache_t *sc, int count) } -void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O2I1 (channel_t *ch, sfxcache_t *sc, int starttime, int count) { int data; int left, right; @@ -472,8 +472,8 @@ void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) { data = sfx[pos>>PITCHSHIFT]; pos += ch->rate; - paintbuffer[i].s[0] += (leftvol * data)>>8; - paintbuffer[i].s[1] += (rightvol * data)>>8; + paintbuffer[starttime+i].s[0] += (leftvol * data)>>8; + paintbuffer[starttime+i].s[1] += (rightvol * data)>>8; } } else @@ -484,13 +484,13 @@ void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) data = sfx[i]; left = (data * leftvol) >> 8; right = (data * rightvol) >> 8; - paintbuffer[i].s[0] += left; - paintbuffer[i].s[1] += right; + paintbuffer[starttime+i].s[0] += left; + paintbuffer[starttime+i].s[1] += right; } } } -void SND_PaintChannelFrom16Stereo (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O2I2 (channel_t *ch, sfxcache_t *sc, int starttime, int count) { int leftvol, rightvol; signed short *sfx; @@ -509,8 +509,8 @@ void SND_PaintChannelFrom16Stereo (channel_t *ch, sfxcache_t *sc, int count) l = sfx[(pos>>(PITCHSHIFT-1))&~1]; r = sfx[(pos>>(PITCHSHIFT-1))|1]; pos += ch->rate; - paintbuffer[i].s[0] += (ch->vol[0] * l)>>8; - paintbuffer[i].s[1] += (ch->vol[1] * r)>>8; + paintbuffer[starttime+i].s[0] += (ch->vol[0] * l)>>8; + paintbuffer[starttime+i].s[1] += (ch->vol[1] * r)>>8; } } else @@ -518,13 +518,13 @@ void SND_PaintChannelFrom16Stereo (channel_t *ch, sfxcache_t *sc, int count) sfx = (signed short *)sc->data + (pos>>PITCHSHIFT)*2; for (i=0 ; i> 8; - paintbuffer[i].s[1] += (*sfx++ * rightvol) >> 8; + paintbuffer[starttime+i].s[0] += (*sfx++ * leftvol) >> 8; + paintbuffer[starttime+i].s[1] += (*sfx++ * rightvol) >> 8; } } } -void SND_PaintChannelFrom16_4Speaker (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O4I1 (channel_t *ch, sfxcache_t *sc, int count) { int vol[4]; signed short *sfx; @@ -563,7 +563,7 @@ void SND_PaintChannelFrom16_4Speaker (channel_t *ch, sfxcache_t *sc, int count) } } -void SND_PaintChannelFrom16_6Speaker (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O6I1 (channel_t *ch, sfxcache_t *sc, int count) { int vol[6]; signed short *sfx; @@ -608,7 +608,7 @@ void SND_PaintChannelFrom16_6Speaker (channel_t *ch, sfxcache_t *sc, int count) } } -void SND_PaintChannelFrom16_8Speaker (channel_t *ch, sfxcache_t *sc, int count) +static void SND_PaintChannel16_O8I1 (channel_t *ch, sfxcache_t *sc, int count) { int vol[8]; signed short *sfx; diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index e12edfb4d..6052b6794 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -461,7 +461,7 @@ void Sys_SaveClipboard(char *text) } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -537,7 +537,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const #if 0 #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *), void *parm) { qboolean go = true; const char *f; diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 82ff09e54..24889d669 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -408,7 +408,7 @@ int Sys_DebugLog(char *file, char *fmt, ...) return 1; } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -566,7 +566,7 @@ dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) lib = NULL; if (!lib) lib = dlopen (name, RTLD_LAZY); - if (!lib && strcmp(COM_FileExtension(name), "so")) + if (!lib && !strstr(name, ".so")) lib = dlopen (va("%s.so", name), RTLD_LAZY); if (!lib) { diff --git a/engine/client/sys_morphos.c b/engine/client/sys_morphos.c index adedd9993..00edcee9f 100755 --- a/engine/client/sys_morphos.c +++ b/engine/client/sys_morphos.c @@ -199,7 +199,7 @@ int Sys_FileTime(char *path) return ret; } -int Sys_EnumerateFiles(const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles(const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *), void *parm) { char *pattern; char pattrans[256]; diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index dc06843d7..dca049535 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -19,9 +19,14 @@ #include #endif +#if SDL_MAJOR_VERSION >= 2 +SDL_Window *sdlwindow; +#endif + #ifndef isDedicated qboolean isDedicated; #endif +extern qboolean ActiveApp; void Sys_Error (const char *error, ...) { @@ -33,9 +38,11 @@ void Sys_Error (const char *error, ...) va_end (argptr); fprintf(stderr, "Error: %s\n", string); - Con_Print ("Quake Error: "); - Con_Print (string); - Con_Print ("\n"); + Sys_Printf ("Quake Error: %s\n", string); + +#if SDL_MAJOR_VERSION >= 2 + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Sys_Error", string, sdlwindow); +#endif if (COM_CheckParm("-crashonerror")) *(int*)-3 = 0; @@ -122,7 +129,8 @@ void Sys_mkdir (char *path) #if WIN32 _mkdir (path); #else - mkdir (path, 0777); //WARNING: DO NOT RUN AS ROOT! + //user, group, others + mkdir (path, 0755); //WARNING: DO NOT RUN AS ROOT! #endif } @@ -152,7 +160,7 @@ void Sys_Quit (void) //SDL provides no file enumeration facilities. #if defined(_WIN32) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { HANDLE r; WIN32_FIND_DATA fd; @@ -218,7 +226,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const } #elif defined(linux) || defined(__unix__) || defined(__MACH__) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { DIR *dir; char apath[MAX_OSPATH]; @@ -292,7 +300,7 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const return true; } #else -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, void *), void *parm, void *spath) { Con_Printf("Warning: Sys_EnumerateFiles not implemented\n"); return false; @@ -497,8 +505,13 @@ int QDECL main(int argc, char **argv) double sleeptime; // yield the CPU for a little while when paused, minimized, or not the focus - if (!(SDL_GetAppState() & SDL_APPACTIVE)) +#if SDL_MAJOR_VERSION >= 2 + if (!ActiveApp) SDL_Delay(1); +#else + if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) + SDL_Delay(1); +#endif newtime = Sys_DoubleTime (); time = newtime - oldtime; @@ -536,12 +549,23 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate) { +#if SDL_MAJOR_VERSION >= 2 + SDL_DisplayMode mode; + if (!SDL_GetDesktopDisplayMode(0, &mode)) + { + *width = mode.w; + *height = mode.h; + *bpp = (SDL_PIXELTYPE(mode.format) == SDL_PIXELTYPE_PACKED32)?32:16; + *refreshrate = mode.refresh_rate; + return true; + } +#endif return false; } -#if SDL_MAJOR_VERSION >= 2 //probably could inclued 1.3 +#if SDL_MAJOR_VERSION >= 2 //probably could include 1.3 #include char *Sys_GetClipboard(void) { @@ -549,7 +573,7 @@ char *Sys_GetClipboard(void) } void Sys_CloseClipboard(char *bf) { - SDL_Free(bf); + SDL_free(bf); } void Sys_SaveClipboard(char *text) { @@ -578,7 +602,11 @@ void Sys_SaveClipboard(char *text) void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize) { // SDL threads do not support setting thread stack size +#if SDL_MAJOR_VERSION >= 2 + return (void *)SDL_CreateThread(func, name, args); +#else return (void *)SDL_CreateThread(func, args); +#endif } void Sys_WaitOnThread(void *thread) diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index e860da157..4e9086283 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -63,6 +63,8 @@ unsigned int sys_parentheight; int qwinvermaj; int qwinvermin; +char *sys_argv[MAX_NUM_ARGVS]; + #ifdef RESTARTTEST jmp_buf restart_jmpbuf; @@ -730,7 +732,7 @@ qboolean Sys_Rename (char *oldfname, char *newfname) return !rename(oldfname, newfname); } -static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { qboolean go; if (!WinNT) @@ -818,7 +820,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); } } } @@ -829,7 +831,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(fd.cFileName) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, fd.cFileName); - go = func(file, fd.nFileSizeLow, parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); } } } @@ -933,7 +935,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 2 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s/", tmproot+matchstart, utf8); - go = func(file, fd.nFileSizeLow, parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); } } } @@ -944,7 +946,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart if (strlen(tmproot+matchstart) + strlen(utf8) + 1 < MAX_OSPATH) { Q_snprintfz(file, sizeof(file), "%s%s", tmproot+matchstart, utf8); - go = func(file, fd.nFileSizeLow, parm, spath); + go = func(file, qofs_Make(fd.nFileSizeLow, fd.nFileSizeHigh), parm, spath); } } } @@ -954,7 +956,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart } return go; } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) { char fullmatch[MAX_OSPATH]; int start; @@ -1127,6 +1129,7 @@ void Sys_Init (void) void Sys_Shutdown(void) { + int i; if (tevent) CloseHandle (tevent); tevent = NULL; @@ -1134,6 +1137,14 @@ void Sys_Shutdown(void) if (qwclsemaphore) CloseHandle (qwclsemaphore); qwclsemaphore = NULL; + + for (i = 0; i < MAX_NUM_ARGVS; i++) + { + if (!sys_argv[i]) + break; + free(sys_argv[i]); + sys_argv[i] = NULL; + } } @@ -1762,7 +1773,6 @@ WinMain */ HINSTANCE global_hInstance; int global_nCmdShow; -char *argv[MAX_NUM_ARGVS]; HWND hwnd_dialog; @@ -2105,9 +2115,9 @@ void Win7_TaskListInit(void) #if defined(SVNREVISION) && !defined(MINIMAL) #define SVNREVISIONSTR STRINGIFY(SVNREVISION) #if defined(OFFICIAL_RELEASE) - #define BUILDTYPE "rel" + #define UPD_BUILDTYPE "rel" #else - #define BUILDTYPE "test" + #define UPD_BUILDTYPE "test" #define UPDATE_URL "http://triptohell.info/moodles/" #define UPDATE_URL_VERSION UPDATE_URL "version.txt" #ifdef _WIN64 @@ -2285,7 +2295,7 @@ void Update_Version_Updated(struct dl_download *dl) char pendingname[MAX_OSPATH]; vfsfile_t *pending; Update_GetHomeDirectory(pendingname, sizeof(pendingname)); - Q_strncatz(pendingname, DISTRIBUTION BUILDTYPE EXETYPE".tmp", sizeof(pendingname)); + Q_strncatz(pendingname, DISTRIBUTION UPD_BUILDTYPE EXETYPE".tmp", sizeof(pendingname)); Update_CreatePath(pendingname); pending = VFSOS_Open(pendingname, "wb"); if (!pending) @@ -2302,7 +2312,7 @@ void Update_Version_Updated(struct dl_download *dl) VFS_CLOSE(pending); if (VFS_GETLEN(dl->file) == size) { - MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE, REG_SZ, pendingname, strlen(pendingname)+1); + MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE, REG_SZ, pendingname, strlen(pendingname)+1); } } } @@ -2372,19 +2382,19 @@ qboolean Sys_CheckUpdated(void) char pendingpath[MAX_OSPATH]; char updatedpath[MAX_OSPATH]; - MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE, pendingpath, sizeof(pendingpath)); + MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE, pendingpath, sizeof(pendingpath)); if (*pendingpath) { - MyRegDeleteKeyValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" BUILDTYPE EXETYPE); + MyRegDeleteKeyValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE); Update_GetHomeDirectory(updatedpath, sizeof(updatedpath)); Update_CreatePath(updatedpath); - Q_strncatz(updatedpath, "cur" BUILDTYPE EXETYPE".exe", sizeof(updatedpath)); + Q_strncatz(updatedpath, "cur" UPD_BUILDTYPE EXETYPE".exe", sizeof(updatedpath)); DeleteFile(updatedpath); if (MoveFile(pendingpath, updatedpath)) - MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, BUILDTYPE EXETYPE, REG_SZ, updatedpath, strlen(updatedpath)+1); + MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, UPD_BUILDTYPE EXETYPE, REG_SZ, updatedpath, strlen(updatedpath)+1); } - MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, BUILDTYPE EXETYPE, updatedpath, sizeof(updatedpath)); + MyRegGetStringValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, UPD_BUILDTYPE EXETYPE, updatedpath, sizeof(updatedpath)); if (*updatedpath) { @@ -2638,9 +2648,11 @@ static int Sys_ProcessCommandline(char **argv, int maxargc, char *argv0) } } } - argv[argc] = argv0; if (argc < 1) + { + argv[0] = argv0; argc = 1; + } for (i = 0; i < argc; i++) argv[i] = strdup(argv[i]); return i; @@ -2745,9 +2757,9 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin } else GetModuleFileNameA(NULL, bindir, sizeof(bindir)-1); - parms.argc = Sys_ProcessCommandline(argv, MAX_NUM_ARGVS, bindir); + parms.argc = Sys_ProcessCommandline(sys_argv, MAX_NUM_ARGVS, bindir); *COM_SkipPath(bindir) = 0; - parms.argv = (const char **)argv; + parms.argv = (const char **)sys_argv; host_parms.binarydir = bindir; COM_InitArgv (parms.argc, parms.argv); diff --git a/engine/client/vid.h b/engine/client/vid.h index 7a635c505..b85c4a1d5 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -61,8 +61,14 @@ typedef struct qboolean isminimized; //can omit rendering as it won't be seen anyway. int fullbright; // index of first fullbright color - unsigned width; /*virtual 2d width*/ - unsigned height; /*virtual 2d height*/ + unsigned fbvwidth; /*virtual 2d width*/ + unsigned fbvheight; /*virtual 2d height*/ + unsigned fbpwidth; /*virtual 2d width*/ + unsigned fbpheight; /*virtual 2d height*/ + + unsigned width; /*virtual 2d screen width*/ + unsigned height; /*virtual 2d screen height*/ + int numpages; unsigned rotpixelwidth; /*width after rotation in pixels*/ diff --git a/engine/client/view.c b/engine/client/view.c index 44e726426..0ce956888 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -145,15 +145,15 @@ float V_CalcBob (playerview_t *pv, qboolean queryold) if (cl.spectator) return 0; + if (cl_bobcycle.value <= 0 || cl.intermission) + return 0; + if (!pv->onground || cl.paused) { pv->bobcltime = cl.time; return pv->bob; // just use old value } - if (cl_bobcycle.value <= 0) - return 0; - pv->bobtime += cl.time - pv->bobcltime; pv->bobcltime = cl.time; cycle = pv->bobtime - (int)(pv->bobtime/cl_bobcycle.value)*cl_bobcycle.value; @@ -1158,9 +1158,11 @@ void V_ApplyRefdef (void) } //if the view entities differ, removes all externalmodel flags except for adding it to the new entity, and removes weaponmodels. -void CL_EditExternalModels(int newviewentity) +//returns the number of view entities that were stripped out +int CL_EditExternalModels(int newviewentity, entity_t *viewentities, int maxviewenties) { int i; + int viewents = 0; for (i = 0; i < cl_numvisedicts; ) { if (cl_visedicts[i].keynum == newviewentity && newviewentity) @@ -1170,12 +1172,15 @@ void CL_EditExternalModels(int newviewentity) if (cl_visedicts[i].flags & Q2RF_WEAPONMODEL) { + if (viewents < maxviewenties) + viewentities[viewents++] = cl_visedicts[i]; memmove(&cl_visedicts[i], &cl_visedicts[i+1], sizeof(*cl_visedicts) * (cl_numvisedicts-(i+1))); cl_numvisedicts--; } else i++; } + return viewents; } /* @@ -1197,6 +1202,10 @@ void V_ClearRefdef(playerview_t *pv) r_refdef.drawsbar = !cl.intermission; r_refdef.flags = 0; + +// memset(r_refdef.postprocshader, 0, sizeof(r_refdef.postprocshader)); +// memset(r_refdef.postprocsize, 0, sizeof(r_refdef.postprocsize)); +// r_refdef.postproccube = 0; } /* @@ -1491,6 +1500,7 @@ void V_RenderPlayerViews(playerview_t *pv) VectorCopy(pv->cam_desired_position, r_refdef.vieworg); R_RenderView (); } + r_secondaryview = true; #ifdef SIDEVIEWS @@ -1514,8 +1524,6 @@ void V_RenderPlayerViews(playerview_t *pv) float ofx; float ofy; - r_secondaryview = true; - if (vsec_x[viewnum].value < 0) vsec_x[viewnum].value = 0; if (vsec_y[viewnum].value < 0) @@ -1536,6 +1544,10 @@ void V_RenderPlayerViews(playerview_t *pv) r_refdef.vrect.y += r_refdef.vrect.height*vsec_y[viewnum].value; r_refdef.vrect.width *= vsec_scalex[viewnum].value; r_refdef.vrect.height *= vsec_scaley[viewnum].value; + + r_refdef.fov_x = 0; + r_refdef.fov_y = 0; + V_ApplyAFov(NULL); #ifdef PEXT_VIEW2 //secondary view entity. e=NULL; @@ -1565,7 +1577,7 @@ void V_RenderPlayerViews(playerview_t *pv) } - CL_EditExternalModels(e->keynum); + CL_EditExternalModels(e->keynum, NULL, 0); R_RenderView (); // r_framecount = old_framecount; @@ -1579,7 +1591,7 @@ void V_RenderPlayerViews(playerview_t *pv) r_refdef.viewangles[PITCH] *= -cos((vsec_yaw[viewnum].value / 180 * 3.14)+3.14); if (vsec_enabled[viewnum].value!=2) { - CL_EditExternalModels(0); + CL_EditExternalModels(0, NULL, 0); R_RenderView (); } } @@ -1612,7 +1624,7 @@ void V_RenderView (void) if (viewnum) { //should be enough to just hack a few things. - CL_EditExternalModels(cl.playerview[viewnum].viewentity); + CL_EditExternalModels(cl.playerview[viewnum].viewentity, NULL, 0); } else { diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 0e7ae8695..c1dd7852c 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -3541,7 +3541,10 @@ void CL_Say (qboolean team, char *extra) CLQ3_SendClientCommand("%s %s%s", team ? "say_team" : "say", extra?extra:"", sendtext); else #endif - CL_SendClientCommand(true, "%s \"%s%s\"", team ? "say_team" : "say", extra?extra:"", sendtext); + { + int split = CL_TargettedSplit(true); + CL_SendClientCommand(true, "%s%s \"%s%s\"", split?va("%i ", split+1):"", team ? "say_team" : "say", extra?extra:"", sendtext); + } } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index c50ffa31e..f43f7f62f 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -588,7 +588,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_SSPARTICLESPRE 1024 // precached particle effect names, for server-side pointparticles/trailparticles. #define MAX_VWEP_MODELS 32 -#define MAX_CSMODELS 512 // these live entirly clientside +#define MAX_CSMODELS 1024 // these live entirly clientside #define MAX_CSPARTICLESPRE 1024 #define SAVEGAME_COMMENT_LENGTH 39 diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 1dc32cbba..ea479eec1 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -526,9 +526,9 @@ void Cmd_Exec_f (void) else Q_strncpyz(name, Cmd_Argv(1), sizeof(name)); - if (FS_LoadFile(name, (void **)&f) != -1) + if (!qofs_Error(FS_LoadFile(name, (void **)&f))) ; - else if (FS_LoadFile(va("%s.cfg", name), (void **)&f) != -1) + else if (!qofs_Error(FS_LoadFile(va("%s.cfg", name), (void **)&f))) ; else { @@ -1928,7 +1928,13 @@ void Cmd_ForwardToServer_f (void) } if (Cmd_Argc() > 1) - CL_SendClientCommand(true, "%s", Cmd_Args()); + { + int split = CL_TargettedSplit(true); + if (split) + CL_SendClientCommand(true, "%i %s", split+1, Cmd_Args()); + else + CL_SendClientCommand(true, "%s", Cmd_Args()); + } } #else void Cmd_ForwardToServer (void) diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index a894c888b..af2386f3f 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -2270,7 +2270,7 @@ static void Mod_FloodFillSkin( qbyte *skin, int skinwidth, int skinheight ) char ** skinfilelist; int skinfilecount; -static qboolean VARGS Mod_TryAddSkin(const char *skinname, ...) +static qboolean VARGS Mod_TryAddSkin(qboolean force, const char *skinname, ...) { va_list argptr; char string[MAX_QPATH]; @@ -2290,7 +2290,7 @@ static qboolean VARGS Mod_TryAddSkin(const char *skinname, ...) return true; //already added } - if (!COM_FCheckExists(string)) + if (!force && !COM_FCheckExists(string)) return false; skinfilelist = BZ_Realloc(skinfilelist, sizeof(*skinfilelist)*(skinfilecount+1)); @@ -2300,13 +2300,13 @@ static qboolean VARGS Mod_TryAddSkin(const char *skinname, ...) return true; } -int QDECL Mod_EnumerateSkins(const char *name, int size, void *param, searchpathfuncs_t *spath) +int QDECL Mod_EnumerateSkins(const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) { - Mod_TryAddSkin(name); + Mod_TryAddSkin(false, name); return true; } -int Mod_BuildSkinFileList(char *modelname) +int Mod_BuildSkinFileList(qboolean forcedefault, char *modelname) { int i; char skinfilename[MAX_QPATH]; @@ -2324,31 +2324,31 @@ int Mod_BuildSkinFileList(char *modelname) //try and add numbered skins, and then try fixed names. for (i = 0; ; i++) { - if (!Mod_TryAddSkin("%s_%i.skin", modelname, i)) + if (!Mod_TryAddSkin(false, "%s_%i.skin", modelname, i)) { if (i == 0) { - if (!Mod_TryAddSkin("%s_default.skin", skinfilename, i)) + if (!Mod_TryAddSkin(forcedefault, "%s_default.skin", skinfilename, i)) break; } else if (i == 1) { - if (!Mod_TryAddSkin("%s_blue.skin", skinfilename, i)) + if (!Mod_TryAddSkin(false, "%s_blue.skin", skinfilename, i)) break; } else if (i == 2) { - if (!Mod_TryAddSkin("%s_red.skin", skinfilename, i)) + if (!Mod_TryAddSkin(false, "%s_red.skin", skinfilename, i)) break; } else if (i == 3) { - if (!Mod_TryAddSkin("%s_green.skin", skinfilename, i)) + if (!Mod_TryAddSkin(false, "%s_green.skin", skinfilename, i)) break; } else if (i == 4) { - if (!Mod_TryAddSkin("%s_yellow.skin", skinfilename, i)) + if (!Mod_TryAddSkin(false, "%s_yellow.skin", skinfilename, i)) break; } else @@ -2442,11 +2442,11 @@ void Mod_ParseQ3SkinFile(char *out, char *surfname, char *modelname, int skinnum } #if defined(D3DQUAKE) || defined(GLQUAKE) -shader_t *Mod_LoadSkinFile(char *surfacename, int skinnumber, unsigned char *rawdata, int width, int height, unsigned char *palette) +shader_t *Mod_LoadSkinFile(char *defaultshadername, char *surfacename, int skinnumber, unsigned char *rawdata, int width, int height, unsigned char *palette) { shader_t *shader; char shadername[MAX_QPATH]; - Q_strncpyz(shadername, surfacename, sizeof(shadername)); + Q_strncpyz(shadername, defaultshadername?defaultshadername:surfacename, sizeof(shadername)); Mod_ParseQ3SkinFile(shadername, surfacename, loadmodel->name, skinnumber, NULL); @@ -4164,7 +4164,7 @@ qboolean QDECL Mod_LoadQ3Model(model_t *mod, void *buffer) root = NULL; #ifndef SERVERONLY - externalskins = Mod_BuildSkinFileList(mod->name); + externalskins = Mod_BuildSkinFileList(false, mod->name); #else externalskins = 0; #endif @@ -4610,9 +4610,7 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer) } #ifndef SERVERONLY - skinfiles = Mod_BuildSkinFileList(loadmodel->name); - if (skinfiles < 1) - skinfiles = 1; + skinfiles = Mod_BuildSkinFileList(true, loadmodel->name); #endif for (i = 0; i < header->numsurfaces; i++, surfname+=32) @@ -4633,7 +4631,7 @@ qboolean QDECL Mod_LoadZymoticModel(model_t *mod, void *buffer) skin[j].numshaders = 1; //non-sequenced skins. skin[j].ofsshaders = shaders; - shaders[0] = Mod_LoadSkinFile(surfname, j, NULL, 0, 0, NULL); + shaders[0] = Mod_LoadSkinFile(NULL, surfname, j, NULL, 0, 0, NULL); } root[i].ofsskins = skin; @@ -5657,9 +5655,7 @@ qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer) } #ifndef SERVERONLY - skinfiles = Mod_BuildSkinFileList(loadmodel->name); - if (skinfiles < 1) - skinfiles = 1; + skinfiles = Mod_BuildSkinFileList(true, loadmodel->name); #endif mesh = (dpmmesh_t*)((char*)buffer + header->ofs_meshs); @@ -5690,7 +5686,7 @@ qboolean QDECL Mod_LoadDarkPlacesModel(model_t *mod, void *buffer) skin[j].numshaders = 1; //non-sequenced skins. skin[j].ofsshaders = shaders; - shaders[0] = Mod_LoadSkinFile(mesh->shadername, j, NULL, 0, 0, NULL); + shaders[0] = Mod_LoadSkinFile(NULL, mesh->shadername, j, NULL, 0, 0, NULL); } m->ofsskins = skin; @@ -5889,6 +5885,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) #ifndef SERVERONLY galiasskin_t *skin; shader_t **shaders; + int skinfiles; #endif galiasgroup_t *fgroup; galiasbone_t *bones; @@ -5997,7 +5994,8 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) memsize += sizeof(*fgroup)*numgroups + sizeof(float)*12*(h->num_joints + (h->num_poses*h->num_frames)) + sizeof(*bones)*h->num_joints; memsize += (sizeof(*opos) + sizeof(*onorm1) + sizeof(*onorm2) + sizeof(*onorm3) + sizeof(*otcoords) + (noweights?0:(sizeof(*oindex)+sizeof(*oweight)))) * h->num_vertexes; #ifndef SERVERONLY - memsize += sizeof(*skin)*h->num_meshes + sizeof(*shaders)*h->num_meshes; + skinfiles = Mod_BuildSkinFileList(true, loadmodel->name); + memsize += (sizeof(*skin)*h->num_meshes + sizeof(*shaders)*h->num_meshes)*skinfiles; #endif /*allocate a nice big block of memory and figure out where stuff is*/ @@ -6024,7 +6022,7 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) opose = oposebase + 12*h->num_joints; #ifndef SERVERONLY skin = (galiasskin_t*)(opose + 12*(h->num_poses*h->num_frames)); - shaders = (shader_t**)(skin + h->num_meshes); + shaders = (shader_t**)(skin + h->num_meshes*skinfiles); #endif //no code to load animations or bones @@ -6162,21 +6160,26 @@ galiasinfo_t *Mod_ParseIQMMeshModel(model_t *mod, char *buffer) offset = LittleLong(mesh[i].first_vertex); #ifndef SERVERONLY - /*skins*/ - gai[i].numskins = 1; - gai[i].ofsskins = &skin[i]; - Q_strncpyz(skin[i].name, strings+mesh[i].material, sizeof(skin[i].name)); - skin[i].skinwidth = 1; - skin[i].skinheight = 1; - skin[i].ofstexels = 0; /*doesn't support 8bit colourmapping*/ - skin[i].skinspeed = 10; /*something to avoid div by 0*/ - skin[i].numshaders = 1; - skin[i].ofsshaders = &shaders[i]; - shaders[i] = R_RegisterSkin(skin[i].name, mod->name); - R_BuildDefaultTexnums(NULL, shaders[i]); - if (shaders[i]->flags & SHADER_NOIMAGE) - Con_Printf("Unable to load texture for shader \"%s\" on polyset \"%s\" for model \"%s\"\n", shaders[i]->name, strings+mesh[i].name, loadmodel->name); + /*texture coords*/ gai[i].ofs_st_array = (otcoords+offset); + /*skins*/ + gai[i].numskins = skinfiles; + gai[i].ofsskins = skin; + + for (j = 0; j < skinfiles; j++) + { + Q_strncpyz(skin->name, skinfilelist[j], sizeof(skin[i].name)); + skin->skinwidth = 1; + skin->skinheight = 1; + skin->ofstexels = 0; /*doesn't support 8bit colourmapping*/ + skin->skinspeed = 10; /*something to avoid div by 0*/ + skin->numshaders = 1; //non-sequenced skins. + skin->ofsshaders = shaders; + skin++; + + *shaders++ = Mod_LoadSkinFile(strings+mesh[i].material, strings+mesh[i].name, j, NULL, 0, 0, NULL); + } + skin += skinfiles; #endif nt = LittleLong(mesh[i].num_triangles); @@ -6958,7 +6961,7 @@ qboolean QDECL Mod_LoadCompositeAnim(model_t *mod, void *buffer) { char namebkup[MAX_QPATH]; Q_strncpyz(namebkup, com_token, sizeof(namebkup)); - if (!Mod_ParseMD5Anim(file, root, &poseofs[numgroups], &grouplist[numgroups])) + if (!Mod_ParseMD5Anim(file, root, (void**)&poseofs[numgroups], &grouplist[numgroups])) { return false; } @@ -6976,7 +6979,7 @@ qboolean QDECL Mod_LoadCompositeAnim(model_t *mod, void *buffer) { char namebkup[MAX_QPATH]; Q_strncpyz(namebkup, com_token, sizeof(namebkup)); - if (!Mod_ParseMD5Anim(file, root, &poseofs[numgroups], &grouplist[numgroups])) + if (!Mod_ParseMD5Anim(file, root, (void**)&poseofs[numgroups], &grouplist[numgroups])) { return false; } diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index 0a950e2b2..b3331598b 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -363,10 +363,10 @@ const dReal * (ODE_API *dBodyGetAngularVel)(dBodyID); void (ODE_API *dBodySetMass)(dBodyID, const dMass *mass); //void (ODE_API *dBodyGetMass)(dBodyID, dMass *mass); //void (ODE_API *dBodyAddForce)(dBodyID, dReal fx, dReal fy, dReal fz); -//void (ODE_API *dBodyAddTorque)(dBodyID, dReal fx, dReal fy, dReal fz); +void (ODE_API *dBodyAddTorque)(dBodyID, dReal fx, dReal fy, dReal fz); //void (ODE_API *dBodyAddRelForce)(dBodyID, dReal fx, dReal fy, dReal fz); //void (ODE_API *dBodyAddRelTorque)(dBodyID, dReal fx, dReal fy, dReal fz); -//void (ODE_API *dBodyAddForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); +void (ODE_API *dBodyAddForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); //void (ODE_API *dBodyAddForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); //void (ODE_API *dBodyAddRelForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); //void (ODE_API *dBodyAddRelForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); @@ -389,8 +389,8 @@ dJointID (ODE_API *dBodyGetJoint)(dBodyID, int index); //void (ODE_API *dBodySetDynamic)(dBodyID); //void (ODE_API *dBodySetKinematic)(dBodyID); //int (ODE_API *dBodyIsKinematic)(dBodyID); -//void (ODE_API *dBodyEnable)(dBodyID); -//void (ODE_API *dBodyDisable)(dBodyID); +void (ODE_API *dBodyEnable)(dBodyID); +void (ODE_API *dBodyDisable)(dBodyID); //int (ODE_API *dBodyIsEnabled)(dBodyID); void (ODE_API *dBodySetGravityMode)(dBodyID b, int mode); int (ODE_API *dBodyGetGravityMode)(dBodyID b); @@ -828,10 +828,10 @@ static dllfunction_t odefuncs[] = {(void **) &dBodySetMass, "dBodySetMass"}, // {"dBodyGetMass", (void **) &dBodyGetMass}, // {"dBodyAddForce", (void **) &dBodyAddForce}, -// {"dBodyAddTorque", (void **) &dBodyAddTorque}, + {(void **) &dBodyAddTorque, "dBodyAddTorque"}, // {"dBodyAddRelForce", (void **) &dBodyAddRelForce}, // {"dBodyAddRelTorque", (void **) &dBodyAddRelTorque}, -// {"dBodyAddForceAtPos", (void **) &dBodyAddForceAtPos}, + {(void **) &dBodyAddForceAtPos, "dBodyAddForceAtPos"}, // {"dBodyAddForceAtRelPos", (void **) &dBodyAddForceAtRelPos}, // {"dBodyAddRelForceAtPos", (void **) &dBodyAddRelForceAtPos}, // {"dBodyAddRelForceAtRelPos", (void **) &dBodyAddRelForceAtRelPos}, @@ -854,8 +854,8 @@ static dllfunction_t odefuncs[] = // {"dBodySetDynamic", (void **) &dBodySetDynamic}, // {"dBodySetKinematic", (void **) &dBodySetKinematic}, // {"dBodyIsKinematic", (void **) &dBodyIsKinematic}, -// {"dBodyEnable", (void **) &dBodyEnable}, -// {"dBodyDisable", (void **) &dBodyDisable}, + {(void **) &dBodyEnable, "dBodyEnable"}, + {(void **) &dBodyDisable, "dBodyDisable"}, // {"dBodyIsEnabled", (void **) &dBodyIsEnabled}, {(void **) &dBodySetGravityMode, "dBodySetGravityMode"}, {(void **) &dBodyGetGravityMode, "dBodyGetGravityMode"}, @@ -1171,6 +1171,8 @@ static dllfunction_t odefuncs[] = dllhandle_t ode_dll = NULL; #endif +static void World_ODE_RunCmd(world_t *world, odecommandqueue_t *cmd); + void World_ODE_Init(void) { #ifdef ODE_DYNAMIC @@ -1798,22 +1800,22 @@ qboolean World_ODE_RagCreateBody(world_t *world, odebody_t *bodyptr, odebodyinfo world->ode.hasodeents = true; //I don't like this, but we need the world etc to be solid. world->ode.hasextraobjs = true; - switch(bodyinfo->shape) + switch(bodyinfo->geomshape) { - case SOLID_PHYSICS_CAPSULE: + case GEOMTYPE_CAPSULE: radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5; bodyptr->ode_geom = (void *)dCreateCapsule(world->ode.ode_space, radius, bodyinfo->dimensions[2]); dMassSetCapsuleTotal(&mass, bodyinfo->mass, 3, radius, bodyinfo->dimensions[2]); //aligned along the geom's local z axis break; - case SOLID_PHYSICS_SPHERE: + case GEOMTYPE_SPHERE: //radius radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1] + bodyinfo->dimensions[2]) / 3; bodyptr->ode_geom = dCreateSphere(world->ode.ode_space, radius); dMassSetSphereTotal(&mass, bodyinfo->mass, radius); //aligned along the geom's local z axis break; - case SOLID_PHYSICS_CYLINDER: + case GEOMTYPE_CYLINDER: //radius, length radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5; bodyptr->ode_geom = dCreateCylinder(world->ode.ode_space, radius, bodyinfo->dimensions[2]); @@ -1821,7 +1823,7 @@ qboolean World_ODE_RagCreateBody(world_t *world, odebody_t *bodyptr, odebodyinfo //alignment is irreleevnt, thouse I suppose it might be scaled wierdly. break; default: - case SOLID_PHYSICS_BOX: + case GEOMTYPE_BOX: //diameter bodyptr->ode_geom = dCreateBox(world->ode.ode_space, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); dMassSetBoxTotal(&mass, bodyinfo->mass, bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]); @@ -2074,6 +2076,7 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) int modelindex = 0; int movetype = MOVETYPE_NONE; int solid = SOLID_NOT; + int geomtype = GEOMTYPE_SOLID; qboolean modified = false; vec3_t angles; vec3_t avelocity; @@ -2099,15 +2102,32 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) if (!ode_dll) return; #endif + geomtype = (int)ed->xv->geomtype; solid = (int)ed->v->solid; movetype = (int)ed->v->movetype; scale = ed->xv->scale?ed->xv->scale:1; modelindex = 0; model = NULL; - switch(solid) + if (!geomtype) { - case SOLID_BSP: + switch((int)ed->v->solid) + { + case SOLID_NOT: geomtype = GEOMTYPE_NONE; break; + case SOLID_TRIGGER: geomtype = GEOMTYPE_NONE; break; + case SOLID_BSP: geomtype = GEOMTYPE_TRIMESH; break; + case SOLID_PHYSICS_TRIMESH: geomtype = GEOMTYPE_TRIMESH; break; + case SOLID_PHYSICS_BOX: geomtype = GEOMTYPE_BOX; break; + case SOLID_PHYSICS_SPHERE: geomtype = GEOMTYPE_SPHERE; break; + case SOLID_PHYSICS_CAPSULE: geomtype = GEOMTYPE_CAPSULE; break; + case SOLID_PHYSICS_CYLINDER:geomtype = GEOMTYPE_CYLINDER; break; + default: geomtype = GEOMTYPE_BOX; break; + } + } + + switch(geomtype) + { + case GEOMTYPE_TRIMESH: modelindex = (int)ed->v->modelindex; model = world->Get_CModel(world, modelindex); if (model) @@ -2123,18 +2143,16 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) massval = 1.0f; } break; - case SOLID_BBOX: - case SOLID_SLIDEBOX: - case SOLID_CORPSE: - case SOLID_PHYSICS_BOX: - case SOLID_PHYSICS_SPHERE: - case SOLID_PHYSICS_CAPSULE: + case GEOMTYPE_BOX: + case GEOMTYPE_SPHERE: + case GEOMTYPE_CAPSULE: VectorCopy(ed->v->mins, entmins); VectorCopy(ed->v->maxs, entmaxs); if (ed->xv->mass) massval = ed->xv->mass; break; default: +// case GEOMTYPE_NONE: if (ed->ode.ode_physics) World_ODE_RemoveFromEntity(world, ed); return; @@ -2177,9 +2195,9 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) VectorSet(geomsize, 1.0f, 1.0f, 1.0f); } - switch(solid) + switch(geomtype) { - case SOLID_BSP: + case GEOMTYPE_TRIMESH: Matrix4x4_Identity(ed->ode.ode_offsetmatrix); ed->ode.ode_geom = NULL; if (!model) @@ -2203,20 +2221,17 @@ static void World_ODE_Frame_BodyFromEntity(world_t *world, wedict_t *ed) ed->ode.ode_geom = (void *)dCreateTriMesh(world->ode.ode_space, dataID, NULL, NULL, NULL); dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); break; - case SOLID_BBOX: - case SOLID_SLIDEBOX: - case SOLID_CORPSE: - case SOLID_PHYSICS_BOX: + case GEOMTYPE_BOX: Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); ed->ode.ode_geom = (void *)dCreateBox(world->ode.ode_space, geomsize[0], geomsize[1], geomsize[2]); dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]); break; - case SOLID_PHYSICS_SPHERE: + case GEOMTYPE_SPHERE: Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]); ed->ode.ode_geom = (void *)dCreateSphere(world->ode.ode_space, geomsize[0] * 0.5f); dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f); break; - case SOLID_PHYSICS_CAPSULE: + case GEOMTYPE_CAPSULE: axisindex = 0; if (geomsize[axisindex] < geomsize[1]) axisindex = 1; @@ -2627,6 +2642,15 @@ void World_ODE_Frame(world_t *world, double frametime, double gravity) if (!ed->isfree) World_ODE_Frame_JointFromEntity(world, ed); } + while(world->ode.cmdqueuehead) + { + odecommandqueue_t *cmd = world->ode.cmdqueuehead; + world->ode.cmdqueuehead = cmd->next; + if (!cmd->next) + world->ode.cmdqueuetail = NULL; + World_ODE_RunCmd(world, cmd); + Z_Free(cmd); + } } for (i = 0;i < world->ode.ode_iterations;i++) @@ -2671,4 +2695,81 @@ void World_ODE_Frame(world_t *world, double frametime, double gravity) } } +static void World_ODE_RunCmd(world_t *world, odecommandqueue_t *cmd) +{ + switch(cmd->command) + { + case ODECMD_ENABLE: + if (cmd->edict->ode.ode_body) + dBodyEnable(cmd->edict->ode.ode_body); + break; + case ODECMD_DISABLE: + if (cmd->edict->ode.ode_body) + dBodyDisable(cmd->edict->ode.ode_body); + break; + case ODECMD_FORCE: + if (cmd->edict->ode.ode_body) + { + dBodyEnable(cmd->edict->ode.ode_body); + dBodyAddForceAtPos(cmd->edict->ode.ode_body, cmd->v1[0], cmd->v1[1], cmd->v1[2], cmd->v2[0], cmd->v2[1], cmd->v2[2]); + } + break; + case ODECMD_TORQUE: + if (cmd->edict->ode.ode_body) + { + dBodyEnable(cmd->edict->ode.ode_body); + dBodyAddTorque(cmd->edict->ode.ode_body, cmd->v1[0], cmd->v1[1], cmd->v1[2]); + } + break; + } +} + +static odecommandqueue_t *physics_queuecommand(world_t *world) +{ + odecommandqueue_t *cmd = Z_Malloc(sizeof(*cmd)); + world->ode.hasodeents = true; //just in case. + + //add on the end of the queue, so that order is preserved. + if (world->ode.cmdqueuehead) + world->ode.cmdqueuetail->next = world->ode.cmdqueuetail = cmd; + else + world->ode.cmdqueuetail = world->ode.cmdqueuehead = cmd; + return cmd; +} + +void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t*e = G_WEDICT(prinst, OFS_PARM0); + int isenable = G_FLOAT(OFS_PARM1); + world_t *world = prinst->parms->user; + odecommandqueue_t *cmd = physics_queuecommand(world); + + cmd->command = isenable?ODECMD_ENABLE:ODECMD_DISABLE; + cmd->edict = e; +} +void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t*e = G_WEDICT(prinst, OFS_PARM0); + float *force = G_VECTOR(OFS_PARM1); + float *relative_ofs = G_VECTOR(OFS_PARM2); + world_t *world = prinst->parms->user; + odecommandqueue_t *cmd = physics_queuecommand(world); + + cmd->command = ODECMD_FORCE; + cmd->edict = e; + VectorCopy(force, cmd->v1); + VectorCopy(relative_ofs, cmd->v2); +} +void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + wedict_t*e = G_WEDICT(prinst, OFS_PARM0); + float *torque = G_VECTOR(OFS_PARM1); + world_t *world = prinst->parms->user; + odecommandqueue_t *cmd = physics_queuecommand(world); + + cmd->command = ODECMD_TORQUE; + cmd->edict = e; + VectorCopy(torque, cmd->v1); +} + #endif diff --git a/engine/common/common.c b/engine/common/common.c index f40074b78..5263a6932 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -40,7 +40,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "./mingw-libs/jpeglib.h" #endif #ifdef _SDL - #include "./mingw-libs/SDL_version.h" + #include #endif #elif defined(_WIN32) #if defined(AVAIL_PNGLIB) && !defined(SERVERONLY) @@ -55,7 +55,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "jpeglib.h" #endif #ifdef _SDL - #include "SDL_version.h" + #include #endif #else #if defined(AVAIL_PNGLIB) && !defined(SERVERONLY) @@ -69,7 +69,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif #ifdef _SDL - #include + #include #endif #endif @@ -2160,7 +2160,7 @@ unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen) { shift = bcount*6; shift = shift-6; - *((unsigned char *)out) = (unsigned char)((unicode>>shift)&(0x0000007f>>bcount)) | (0xffffff00 >> bcount); + *((unsigned char *)out) = (unsigned char)((unicode>>shift)&(0x0000007f>>bcount)) | ((0xffffff00 >> bcount) & 0xff); out = (char*)out + 1; do { @@ -2181,7 +2181,7 @@ unsigned int qchar_encode(char *out, unsigned int unicode, int maxlen, qboolean { //quake compatible chars if (maxlen < 1) return 0; - *out++ = unicode; + *out++ = unicode & 0xff; return 1; } else if (!markup) @@ -5282,12 +5282,12 @@ int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ... #endif // libSDL.a and libSDLmain.a mingw32 libs use this function for some reason, just here to shut gcc up -#ifdef _MINGW_VFPRINTF +/*#ifdef _MINGW_VFPRINTF int __mingw_vfprintf (FILE *__stream, const char *__format, __VALIST __local_argv) { return vfprintf( __stream, __format, __local_argv ); } -#endif +#endif*/ int version_number(void) { diff --git a/engine/common/common.h b/engine/common/common.h index 9fa6e4346..8dc79c674 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -338,12 +338,30 @@ extern char com_configdir[MAX_OSPATH]; //dir to put cfg_save configs in void COM_WriteFile (const char *filename, const void *data, int len); +//qofs_Make is used to 'construct' a variable of qofs_t type. this is so the code can merge two 32bit ints on old systems and use a long long type internally without generating warnings about bit shifts when qofs_t is only 32bit instead. +#if defined(__amd64__) || defined(_AMD64_) || __WORDSIZE == 64 + #define FS_64BIT +#endif +#ifdef FS_64BIT + typedef unsigned long long qofs_t; //type to use for a file offset + #define qofs_Make(low,high) (low | (((qofs_t)(high))<<32)) + #define qofs_Low(o) ((o)&0xffffffffu) + #define qofs_High(o) ((o)>>32) + #define qofs_Error(o) ((o) == ~0ull) +#else + typedef unsigned int qofs_t; //type to use for a file offset + #define qofs_Make(low,high) (low) + #define qofs_Low(o) (o) + #define qofs_High(o) (0) + #define qofs_Error(o) ((o) == ~0ul) +#endif + typedef struct { - struct searchpath_s *search; - int index; - char rawname[MAX_OSPATH]; - int offset; - int len; + struct searchpath_s *search; //used to say which filesystem driver to open the file from + int index; //used by the filesystem driver as a simple reference to the file + char rawname[MAX_OSPATH]; //blank means not readable directly + qofs_t offset; //only usable if rawname is set. + qofs_t len; //uncompressed length } flocation_t; struct vfsfile_s; @@ -372,14 +390,13 @@ FTE_DEPRECATED void COM_CloseFile (FILE *h); #define COM_FDepthFile(filename,ignorepacks) FS_FLocateFile(filename,ignorepacks?FSLFRT_DEPTH_OSONLY:FSLFRT_DEPTH_ANYPATH, NULL) #define COM_FCheckExists(filename) FS_FLocateFile(filename,FSLFRT_IFFOUND, NULL) - typedef struct vfsfile_s { int (QDECL *ReadBytes) (struct vfsfile_s *file, void *buffer, int bytestoread); int (QDECL *WriteBytes) (struct vfsfile_s *file, const void *buffer, int bytestoread); - qboolean (QDECL *Seek) (struct vfsfile_s *file, unsigned long pos); //returns false for error - unsigned long (QDECL *Tell) (struct vfsfile_s *file); - unsigned long (QDECL *GetLen) (struct vfsfile_s *file); //could give some lag + qboolean (QDECL *Seek) (struct vfsfile_s *file, qofs_t pos); //returns false for error + qofs_t (QDECL *Tell) (struct vfsfile_s *file); + qofs_t (QDECL *GetLen) (struct vfsfile_s *file); //could give some lag void (QDECL *Close) (struct vfsfile_s *file); void (QDECL *Flush) (struct vfsfile_s *file); qboolean seekingisabadplan; @@ -476,15 +493,15 @@ char *FS_GetBasedir(void); struct zonegroup_s; void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path); qbyte *FS_LoadMallocFile (const char *path); -int FS_LoadFile(char *name, void **file); +qofs_t FS_LoadFile(char *name, void **file); void FS_FreeFile(void *file); qbyte *COM_LoadFile (const char *path, int usehunk); -qboolean COM_LoadMapPackFile(const char *name, int offset); +qboolean COM_LoadMapPackFile(const char *name, qofs_t offset); void COM_FlushTempoaryPacks(void); -void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm); +void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm); extern struct cvar_s registered; extern qboolean standard_quake; //fixme: remove diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 7bd8fb1c3..0efb26723 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -92,6 +92,7 @@ typedef struct cvar_s #define CVARAFD(ConsoleName,Value,ConsoleName2,Flags,Description)CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, Description, NULL) #define CVARAFC(ConsoleName,Value,ConsoleName2,Flags,Callback) CVARAFC(ConsoleName, Value, ConsoleName2, Flags, NULL, Callback) #define CVARAF(ConsoleName,Value,ConsoleName2,Flags) CVARAFDC(ConsoleName, Value, ConsoleName2, Flags, NULL, NULL) +#define CVARFDC(ConsoleName,Value,Flags,Description,Callback) CVARAFDC(ConsoleName, Value, NULL, Flags, Description, Callback) #define CVARFC(ConsoleName,Value,Flags,Callback) CVARAFDC(ConsoleName, Value, NULL, Flags, NULL, Callback) #define CVARAD(ConsoleName,Value,ConsoleName2,Description) CVARAFDC(ConsoleName, Value, ConsoleName2, 0, Description, NULL) #define CVARFD(ConsoleName,Value,Flags,Description) CVARAFDC(ConsoleName, Value, NULL, Flags, Description, NULL) diff --git a/engine/common/fs.c b/engine/common/fs.c index 5f5545432..86ce9e653 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -12,12 +12,7 @@ #include "winquake.h" #endif -#if defined(MINGW) && defined(_SDL) -#include "./mingw-libs/SDL_syswm.h" // mingw sdl cross binary complains off sys_parentwindow -#endif - hashtable_t filesystemhash; -qboolean blockcache = true; qboolean com_fschanged = true; static unsigned int fs_restarts; extern cvar_t com_fs_cache; @@ -315,27 +310,27 @@ static void FS_Manifest_ParseTokens(ftemanifest_t *man) if (*fname == '*') fname++; - if (!stricmp(fname, "game")) + if (!Q_strcasecmp(fname, "game")) { Z_Free(man->installation); man->installation = Z_StrDup(Cmd_Argv(1)); } - else if (!stricmp(fname, "name")) + else if (!Q_strcasecmp(fname, "name")) { Z_Free(man->formalname); man->formalname = Z_StrDup(Cmd_Argv(1)); } - else if (!stricmp(fname, "protocolname")) + else if (!Q_strcasecmp(fname, "protocolname")) { Z_Free(man->protocolname); man->protocolname = Z_StrDup(Cmd_Argv(1)); } - else if (!stricmp(fname, "defaultexec")) + else if (!Q_strcasecmp(fname, "defaultexec")) { Z_Free(man->defaultexec); man->defaultexec = Z_StrDup(Cmd_Argv(1)); } - else if (!stricmp(fname, "basegame") || !stricmp(fname, "gamedir")) + else if (!Q_strcasecmp(fname, "basegame") || !Q_strcasecmp(fname, "gamedir")) { int i; char *newdir = Cmd_Argv(1); @@ -351,7 +346,7 @@ static void FS_Manifest_ParseTokens(ftemanifest_t *man) { if (!man->gamepath[i].path) { - man->gamepath[i].base = !stricmp(fname, "basegame"); + man->gamepath[i].base = !Q_strcasecmp(fname, "basegame"); man->gamepath[i].path = Z_StrDup(newdir); break; } @@ -367,7 +362,7 @@ static void FS_Manifest_ParseTokens(ftemanifest_t *man) qboolean crcknown; int crc; int i, j; - if (!stricmp(fname, "package")) + if (!Q_strcasecmp(fname, "package")) Cmd_ShiftArgs(1, false); crcknown = (strcmp(Cmd_Argv(1), "-") && *Cmd_Argv(1)); @@ -527,7 +522,7 @@ COM_Dir_f ============ */ -static int QDECL COM_Dir_List(const char *name, int size, void *parm, searchpathfuncs_t *spath) +static int QDECL COM_Dir_List(const char *name, qofs_t size, void *parm, searchpathfuncs_t *spath) { searchpath_t *s; for (s=com_searchpaths ; s ; s=s->next) @@ -535,7 +530,14 @@ static int QDECL COM_Dir_List(const char *name, int size, void *parm, searchpath if (s->handle == spath) break; } - Con_Printf("%s (%i) (%s)\n", name, size, s?s->logicalpath:"??"); + if (size > 1.0*1024*1024*1024) + Con_Printf("%s \t(%#.3ggb) (%s)\n", name, size/(1024.0*1024*1024), s?s->logicalpath:"??"); + else if (size > 1.0*1024*1024) + Con_Printf("%s \t(%#.3gmb) (%s)\n", name, size/(1024.0*1024), s?s->logicalpath:"??"); + else if (size > 1.0*1024) + Con_Printf("%s \t(%#.3gkb) (%s)\n", name, size/1024.0, s?s->logicalpath:"??"); + else + Con_Printf("%s \t(%ub) (%s)\n", name, (unsigned int)size, s?s->logicalpath:"??"); return 1; } @@ -668,26 +670,32 @@ static void COM_CopyFile (char *netpath, char *cachepath) int fs_hash_dups; int fs_hash_files; +//normally the filesystem drivers pass a pre-allocated bucket and static strings to us +//the OS driver can't really be expected to track things that reliably however, so it just gives names via the stack. +//these files are grouped up to avoid excessive memory allocations. +struct fsbucketblock +{ + struct fsbucketblock *prev; + int used; + int total; + qbyte data[1]; +}; +static struct fsbucketblock *fs_hash_filebuckets; + void FS_FlushFSHashReally(void) { if (filesystemhash.numbuckets) { int i; - fsbucket_t *bucket, *next; - for (i = 0; i < filesystemhash.numbuckets; i++) - { - bucket = (fsbucket_t*)filesystemhash.bucket[i]; filesystemhash.bucket[i] = NULL; - while(bucket) - { - next = (fsbucket_t*)bucket->buck.next; - /*if the string starts right after the bucket, free it*/ - if (bucket->depth < 0) - Z_Free(bucket); - bucket = next; - } - } + } + + while (fs_hash_filebuckets) + { + struct fsbucketblock *n = fs_hash_filebuckets->prev; + Z_Free(fs_hash_filebuckets); + fs_hash_filebuckets = n; } com_fschanged = true; @@ -710,27 +718,34 @@ static void QDECL FS_AddFileHash(int depth, const char *fname, fsbucket_t *fileh if (old) { fs_hash_dups++; - if (depth >= ((old->depth<0)?(-old->depth-1):old->depth)) + if (depth >= old->depth) { return; } //remove the old version Hash_RemoveBucket(&filesystemhash, fname, &old->buck); - if (old->depth < 0) - Z_Free(old); } if (!filehandle) { - filehandle = Z_Malloc(sizeof(*filehandle) + strlen(fname)+1); + int nlen = strlen(fname)+1; + if (!fs_hash_filebuckets || fs_hash_filebuckets->used+sizeof(*filehandle)+nlen > fs_hash_filebuckets->total) + { + void *o = fs_hash_filebuckets; + fs_hash_filebuckets = Z_Malloc(65536); + fs_hash_filebuckets->total = 65536 - sizeof(*fs_hash_filebuckets); + fs_hash_filebuckets->prev = o; + } + filehandle = (fsbucket_t*)(fs_hash_filebuckets->data+fs_hash_filebuckets->used); + fs_hash_filebuckets->used += sizeof(*filehandle)+nlen; + if (!filehandle) return; //eep! - strcpy((char*)(filehandle+1), fname); + memcpy((char*)(filehandle+1), fname, nlen); fname = (char*)(filehandle+1); - filehandle->depth = -depth-1; } - else filehandle->depth = depth; + filehandle->depth = depth; Hash_AddInsensative(&filesystemhash, fname, pathhandle, &filehandle->buck); fs_hash_files++; @@ -740,6 +755,9 @@ void FS_RebuildFSHash(void) { int depth = 1; searchpath_t *search; + if (!com_fschanged) + return; + if (!filesystemhash.numbuckets) { filesystemhash.numbuckets = 1024; @@ -810,10 +828,8 @@ int FS_FLocateFile(const char *filename, FSLF_ReturnType_e returntype, flocation goto fail; } - if (com_fs_cache.ival && !blockcache) + if (com_fs_cache.ival && !com_fschanged) { - if (com_fschanged) - FS_RebuildFSHash(); pf = Hash_GetInsensative(&filesystemhash, filename); if (!pf) goto fail; @@ -1088,71 +1104,6 @@ void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags) fs_referencetype = refflag; } - -#if 0 -int COM_FOpenLocationFILE(flocation_t *loc, FILE **file) -{ - if (!*loc->rawname) - { - if (!loc->len) - { - *file = NULL; - return -1; - } - - if (loc->search->funcs->ReadFile) - {//create a new, temp file, bung the contents of the compressed file into it, then continue. - char *buf; - FILE *f = tmpfile(); - buf = BZ_Malloc(loc->len); - loc->search->funcs->ReadFile(loc->search->handle, loc, buf); - fwrite(buf, 1, loc->len, f); - BZ_Free(buf); - fseek(f, 0, SEEK_SET); - - *file = f; - com_pathforfile = loc->search; - return loc->len; - } - return -1; - } -// Con_Printf("Opening %s\n", loc->rawname); - *file = fopen(loc->rawname, "rb"); - if (!*file) - return -1; - fseek(*file, loc->offset, SEEK_SET); - com_pathforfile = loc->search; - return loc->len; -} - -int COM_FOpenFile(char *filename, FILE **file) -{ - flocation_t loc; - Con_Printf(CON_ERROR "COM_FOpenFile is obsolete\n"); - FS_FLocateFile(filename, FSLFRT_LENGTH, &loc); - - com_filesize = -1; - if (loc.search) - { - com_file_copyprotected = loc.search->copyprotected; - com_file_untrusted = !!(loc.search->flags & SPF_UNTRUSTED); - com_filesize = COM_FOpenLocationFILE(&loc, file); - } - else - *file = NULL; - return com_filesize; -} -/* -int COM_FOpenWriteFile(char *filename, FILE **file) -{ - COM_CreatePath(filename); - *file = fopen(filename, "wb"); - return !!*file; -} -*/ -#endif -//int COM_FOpenFile (char *filename, FILE **file) {file_from_pak=0;return COM_FOpenFile2 (filename, file, false);} //FIXME: TEMPORARY - //outbuf might not be written into static const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen) { @@ -1219,7 +1170,7 @@ vfsfile_t *VFS_Filter(const char *filename, vfsfile_t *handle) return handle; // ext = COM_FileExtension (filename); #ifdef AVAIL_ZLIB -// if (!stricmp(ext, ".gz")) +// if (!Q_strcasecmp(ext, ".gz")) { return FS_DecompressGZip(handle, NULL); } @@ -1482,7 +1433,7 @@ qbyte *COM_LoadFile (const char *path, int usehunk) { vfsfile_t *f; qbyte *buf; - int len; + qofs_t len; char base[MAX_OSPATH]; flocation_t loc; FS_FLocateFile(path, FSLFRT_LENGTH, &loc); @@ -1490,6 +1441,8 @@ qbyte *COM_LoadFile (const char *path, int usehunk) if (!loc.search) return NULL; //wasn't found + if (loc.len > 0x7fffffff) //don't malloc 5000gb sparse files or anything crazy on a 32bit system... + return NULL; f = loc.search->handle->OpenVFS(loc.search->handle, &loc, "rb"); if (!f) @@ -1581,11 +1534,11 @@ qbyte *QDECL COM_LoadStackFile (const char *path, void *buffer, int bufsize) /*warning: at some point I'll change this function to return only read-only buffers*/ -int FS_LoadFile(char *name, void **file) +qofs_t FS_LoadFile(char *name, void **file) { *file = FS_LoadMallocFile(name); if (!*file) - return -1; + return (qofs_t)-1; return com_filesize; } void FS_FreeFile(void *file) @@ -1595,7 +1548,7 @@ void FS_FreeFile(void *file) -void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t*), void *parm) +void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t*), void *parm) { searchpath_t *search; for (search = com_searchpaths; search ; search = search->next) @@ -1628,7 +1581,7 @@ void COM_FlushTempoaryPacks(void) com_purepaths = NULL; } -qboolean COM_LoadMapPackFile (const char *filename, int ofs) +qboolean COM_LoadMapPackFile (const char *filename, qofs_t ofs) { return false; } @@ -1643,7 +1596,7 @@ searchpathfuncs_t *FS_GetOldPath(searchpath_t **oldpaths, const char *dir, unsig { p = *oldpaths; - if (!stricmp(p->logicalpath, dir)) + if (!Q_strcasecmp(p->logicalpath, dir)) { *keepflags |= p->flags & (SPF_REFERENCED | SPF_UNTRUSTED); *oldpaths = p->next; @@ -1664,7 +1617,7 @@ typedef struct { const char *puredesc; } wildpaks_t; -static int QDECL FS_AddWildDataFiles (const char *descriptor, int size, void *vparam, searchpathfuncs_t *funcs) +static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, void *vparam, searchpathfuncs_t *funcs) { wildpaks_t *param = vparam; vfsfile_t *vfs; @@ -1679,7 +1632,7 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, int size, void *vp for (search = com_searchpaths; search; search = search->next) { - if (!stricmp(search->logicalpath, pakfile)) //assumption: first member of structure is a char array + if (!Q_strcasecmp(search->logicalpath, pakfile)) //assumption: first member of structure is a char array return true; //already loaded (base paths?) } @@ -1791,9 +1744,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const for (oldp = com_searchpaths; oldp; oldp = oldp->next) { - if (!stricmp(oldp->purepath, fs_manifest->package[i].path)) + if (!Q_strcasecmp(oldp->purepath, fs_manifest->package[i].path)) break; - if (!stricmp(oldp->logicalpath, lname)) + if (!Q_strcasecmp(oldp->logicalpath, lname)) break; } if (!oldp) @@ -1902,6 +1855,9 @@ void COM_FlushFSCache(void) com_fschanged |= search->handle->PollChanges(search->handle); } } + + //rebuild it if needed + FS_RebuildFSHash(); } /*since should start as 0, otherwise this can be used to poll*/ @@ -1940,7 +1896,7 @@ void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, const ch for (search = com_searchpaths; search; search = search->next) { - if (!stricmp(search->logicalpath, dir)) + if (!Q_strcasecmp(search->logicalpath, dir)) return; //already loaded (base paths?) } @@ -2554,7 +2510,7 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) //this works around 1.01 vs 1.06 issues. for (sp = com_searchpaths; sp; sp = sp->next) { - if (!stricmp(pname, sp->purepath)) + if (!Q_strcasecmp(pname, sp->purepath)) break; } } @@ -2847,17 +2803,7 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base BROWSEINFO bi; LPITEMIDLIST il; memset(&bi, 0, sizeof(bi)); - - #if defined(_SDL) && defined (WIN32) && defined (MINGW) // mingw32 sdl cross compiled binary, code completely untested, doesn't crash so good sign ~moodles - SDL_SysWMinfo wmInfo; - SDL_GetWMInfo(&wmInfo); - HWND sys_parentwindow = wmInfo.window; - - if (sys_parentwindow) - bi.hwndOwner = sys_parentwindow; //note that this is usually still null - else - #endif - bi.hwndOwner = mainwindow; //note that this is usually still null + bi.hwndOwner = mainwindow; //note that this is usually still null bi.pidlRoot = NULL; bi.pszDisplayName = resultpath; bi.lpszTitle = va("Please locate your existing %s installation", poshname); @@ -3461,8 +3407,6 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs) } fs_manifest = man; - blockcache = true; - if (man->installation && *man->installation) { for (i = 0; gamemode_info[i].argname; i++) @@ -3562,7 +3506,9 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs) } } } - blockcache = false; + + //rebuild the cache now, should be safe to waste some cycles on it + FS_RebuildFSHash(); COM_Effectinfo_Clear(); #ifndef SERVERONLY @@ -3589,7 +3535,7 @@ void FS_ChangeGame_f(void) { for (i = 0; gamemode_info[i].argname; i++) { - if (!stricmp(gamemode_info[i].argname+1, arg)) + if (!Q_strcasecmp(gamemode_info[i].argname+1, arg)) { Con_Printf("Switching to %s\n", gamemode_info[i].argname+1); FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, i), true); diff --git a/engine/common/fs.h b/engine/common/fs.h index 8b43a77ed..f9ce1e49a 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -21,13 +21,13 @@ struct searchpathfuncs_s int fsver; void (QDECL *ClosePath)(searchpathfuncs_t *handle); - void (QDECL *GetPathDetails)(searchpathfuncs_t *handle, char *outdetails, unsigned int sizeofdetails); + void (QDECL *GetPathDetails)(searchpathfuncs_t *handle, char *outdetails, size_t sizeofdetails); void (QDECL *BuildHash)(searchpathfuncs_t *handle, int depth, void (QDECL *FS_AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)); unsigned int (QDECL *FindFile)(searchpathfuncs_t *handle, flocation_t *loc, const char *name, void *hashedresult); //true if found (hashedresult can be NULL) //note that if rawfile and offset are set, many Com_FileOpens will read the raw file //otherwise ReadFile will be called instead. void (QDECL *ReadFile)(searchpathfuncs_t *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives) - int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm); + int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm); int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, int seed, int usepure); diff --git a/engine/common/fs_pak.c b/engine/common/fs_pak.c index b74ec6add..53bf454db 100644 --- a/engine/common/fs_pak.c +++ b/engine/common/fs_pak.c @@ -55,7 +55,7 @@ typedef struct #define MAX_FILES_IN_PACK 2048 -static void QDECL FSPAK_GetPathDetails(searchpathfuncs_t *handle, char *out, unsigned int outlen) +static void QDECL FSPAK_GetPathDetails(searchpathfuncs_t *handle, char *out, size_t outlen) { pack_t *pak = (pack_t*)handle; @@ -87,7 +87,7 @@ static void QDECL FSPAK_BuildHash(searchpathfuncs_t *handle, int depth, void (QD AddFileHash(depth, pak->files[i].name, &pak->files[i].bucket, &pak->files[i]); } } -static int QDECL FSPAK_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) +static unsigned int QDECL FSPAK_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) { mpackfile_t *pf = hashedresult; int i; @@ -125,7 +125,7 @@ static int QDECL FSPAK_FLocate(searchpathfuncs_t *handle, flocation_t *loc, cons } return FF_NOTFOUND; } -static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) { pack_t *pak = (pack_t*)handle; int num; @@ -174,9 +174,9 @@ static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int typedef struct { vfsfile_t funcs; pack_t *parentpak; - unsigned long startpos; - unsigned long length; - unsigned long currentpos; + qofs_t startpos; + qofs_t length; + qofs_t currentpos; } vfspack_t; static int QDECL VFSPAK_ReadBytes (struct vfsfile_s *vfs, void *buffer, int bytestoread) { @@ -206,7 +206,7 @@ static int QDECL VFSPAK_WriteBytes (struct vfsfile_s *vfs, const void *buffer, i Sys_Error("Cannot write to pak files\n"); return 0; } -static qboolean QDECL VFSPAK_Seek (struct vfsfile_s *vfs, unsigned long pos) +static qboolean QDECL VFSPAK_Seek (struct vfsfile_s *vfs, qofs_t pos) { vfspack_t *vfsp = (vfspack_t*)vfs; if (pos < 0 || pos > vfsp->length) @@ -215,12 +215,12 @@ static qboolean QDECL VFSPAK_Seek (struct vfsfile_s *vfs, unsigned long pos) return true; } -static unsigned long QDECL VFSPAK_Tell (struct vfsfile_s *vfs) +static qofs_t QDECL VFSPAK_Tell (struct vfsfile_s *vfs) { vfspack_t *vfsp = (vfspack_t*)vfs; return vfsp->currentpos - vfsp->startpos; } -static unsigned long QDECL VFSPAK_GetLen (struct vfsfile_s *vfs) +static qofs_t QDECL VFSPAK_GetLen (struct vfsfile_s *vfs) { vfspack_t *vfsp = (vfspack_t*)vfs; return vfsp->length; @@ -269,15 +269,6 @@ static void QDECL FSPAK_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, ch return; VFS_READ(f, buffer, loc->len); VFS_CLOSE(f); -/* - FILE *f; - f = fopen(loc->rawname, "rb"); - if (!f) //err... - return; - fseek(f, loc->offset, SEEK_SET); - fread(buffer, 1, loc->len, f); - fclose(f); -*/ } diff --git a/engine/common/fs_stdio.c b/engine/common/fs_stdio.c index c86f74dec..be57c3cc5 100644 --- a/engine/common/fs_stdio.c +++ b/engine/common/fs_stdio.c @@ -34,12 +34,12 @@ static int QDECL VFSSTDIO_WriteBytes (struct vfsfile_s *file, const void *buffer vfsstdiofile_t *intfile = (vfsstdiofile_t*)file; return fwrite(buffer, 1, bytestoread, intfile->handle); } -static qboolean QDECL VFSSTDIO_Seek (struct vfsfile_s *file, unsigned long pos) +static qboolean QDECL VFSSTDIO_Seek (struct vfsfile_s *file, qofs_t pos) { vfsstdiofile_t *intfile = (vfsstdiofile_t*)file; return fseek(intfile->handle, pos, SEEK_SET) == 0; } -static unsigned long QDECL VFSSTDIO_Tell (struct vfsfile_s *file) +static qofs_t QDECL VFSSTDIO_Tell (struct vfsfile_s *file) { vfsstdiofile_t *intfile = (vfsstdiofile_t*)file; return ftell(intfile->handle); @@ -49,7 +49,7 @@ static void QDECL VFSSTDIO_Flush(struct vfsfile_s *file) vfsstdiofile_t *intfile = (vfsstdiofile_t*)file; fflush(intfile->handle); } -static unsigned long QDECL VFSSTDIO_GetSize (struct vfsfile_s *file) +static qofs_t QDECL VFSSTDIO_GetSize (struct vfsfile_s *file) { vfsstdiofile_t *intfile = (vfsstdiofile_t*)file; @@ -218,7 +218,7 @@ static qboolean QDECL FSSTDIO_PollChanges(searchpathfuncs_t *handle) // stdiopath_t *np = handle; return true; //can't verify that or not, so we have to assume the worst } -static int QDECL FSSTDIO_RebuildFSHash(const char *filename, int filesize, void *data, searchpathfuncs_t *spath) +static int QDECL FSSTDIO_RebuildFSHash(const char *filename, qofs_t filesize, void *data, searchpathfuncs_t *spath) { stdiopath_t *sp = (void*)spath; void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle) = data; @@ -240,7 +240,7 @@ static void QDECL FSSTDIO_BuildHash(searchpathfuncs_t *handle, int depth, void ( sp->AddFileHash = AddFileHash; Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, AddFileHash, handle); } -static int QDECL FSSTDIO_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) +static unsigned int QDECL FSSTDIO_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) { stdiopath_t *sp = (void*)handle; int len; @@ -304,7 +304,7 @@ static void QDECL FSSTDIO_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, fclose(f); } -static int QDECL FSSTDIO_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSSTDIO_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) { stdiopath_t *sp = (stdiopath_t*)handle; return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle); diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index 8fc9c6d04..399f3dc54 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -16,6 +16,7 @@ typedef struct { searchpathfuncs_t pub; HANDLE changenotification; + void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle); int hashdepth; char rootpath[1]; } vfsw32path_t; @@ -133,9 +134,9 @@ static int QDECL VFSW32_WriteBytes (struct vfsfile_s *file, const void *buffer, return 0; return written; } -static qboolean QDECL VFSW32_Seek (struct vfsfile_s *file, unsigned long pos) +static qboolean QDECL VFSW32_Seek (struct vfsfile_s *file, qofs_t pos) { - unsigned long upper, lower; + DWORD hi, lo; vfsw32file_t *intfile = (vfsw32file_t*)file; if (intfile->mmap) { @@ -143,17 +144,18 @@ static qboolean QDECL VFSW32_Seek (struct vfsfile_s *file, unsigned long pos) return true; } - lower = (pos & 0xffffffff); - upper = ((pos>>16)>>16); - - return SetFilePointer(intfile->hand, lower, &upper, FILE_BEGIN) != INVALID_SET_FILE_POINTER; + lo = qofs_Low(pos); + hi = qofs_High(pos); + return SetFilePointer(intfile->hand, lo, &hi, FILE_BEGIN) != INVALID_SET_FILE_POINTER; } -static unsigned long QDECL VFSW32_Tell (struct vfsfile_s *file) +static qofs_t QDECL VFSW32_Tell (struct vfsfile_s *file) { + DWORD hi = 0, lo; vfsw32file_t *intfile = (vfsw32file_t*)file; if (intfile->mmap) return intfile->offset; - return SetFilePointer(intfile->hand, 0, NULL, FILE_CURRENT); + lo = SetFilePointer(intfile->hand, 0, &hi, FILE_CURRENT); + return qofs_Make(lo,hi); } static void QDECL VFSW32_Flush(struct vfsfile_s *file) { @@ -162,13 +164,15 @@ static void QDECL VFSW32_Flush(struct vfsfile_s *file) FlushViewOfFile(intfile->mmap, intfile->length); FlushFileBuffers(intfile->hand); } -static unsigned long QDECL VFSW32_GetSize (struct vfsfile_s *file) +static qofs_t QDECL VFSW32_GetSize (struct vfsfile_s *file) { + DWORD lo, hi = 0; vfsw32file_t *intfile = (vfsw32file_t*)file; if (intfile->mmap) return intfile->length; - return GetFileSize(intfile->hand, NULL); + lo = GetFileSize(intfile->hand, &hi); + return qofs_Make(lo,hi); } static void QDECL VFSW32_Close(vfsfile_t *file) { @@ -180,15 +184,15 @@ static void QDECL VFSW32_Close(vfsfile_t *file) } CloseHandle(intfile->hand); Z_Free(file); - - COM_FlushFSCache(); } -vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode) +//WARNING: handle can be null +static vfsfile_t *QDECL VFSW32_OpenInternal(vfsw32path_t *handle, const char *quakename, const char *osname, const char *mode) { HANDLE h, mh; unsigned int fsize; void *mmap; + qboolean didexist = true; vfsw32file_t *file; qboolean read = !!strchr(mode, 'r'); @@ -214,18 +218,45 @@ vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode) { wchar_t wide[MAX_OSPATH]; widen(wide, sizeof(wide), osname); - if ((write && read) || append) - h = CreateFileW(wide, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + h = INVALID_HANDLE_VALUE; + if (write || append) + { + h = CreateFileW(wide, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + { + didexist = false; + if (!read) //if we're not reading, the file will be created anew. make sure we don't just reuse it. we do want to avoid rebuilding our name->location cache though. + { + CloseHandle(h); + h = INVALID_HANDLE_VALUE; + } + } + } + + if (h != INVALID_HANDLE_VALUE) + ; + else if ((write && read) || append) + h = CreateFileW(wide, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); else if (write) - h = CreateFileW(wide, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + h = CreateFileW(wide, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); else if (read) - h = CreateFileW(wide, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + h = CreateFileW(wide, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); else h = INVALID_HANDLE_VALUE; } if (h == INVALID_HANDLE_VALUE) return NULL; + if (!didexist) + { + if (handle && handle->AddFileHash) + handle->AddFileHash(handle->hashdepth, quakename, NULL, handle); + else + COM_RefreshFSCache_f(); //no idea where this path is. if its inside a quake path, make sure it gets flushed properly. FIXME: his shouldn't be needed if we have change notifications working properly. + } + + fsize = GetFileSize(h, NULL); if (write || append || text || fsize > 1024*1024*5) { @@ -273,11 +304,17 @@ vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode) return (vfsfile_t*)file; } +vfsfile_t *QDECL VFSW32_Open(const char *osname, const char *mode) +{ + //called without regard to a search path + return VFSW32_OpenInternal(NULL, NULL, osname, mode); +} + static vfsfile_t *QDECL VFSW32_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode) { //path is already cleaned, as anything that gets a valid loc needs cleaning up first. - - return VFSW32_Open(loc->rawname, mode); + vfsw32path_t *wp = (void*)handle; + return VFSW32_OpenInternal(wp, loc->rawname+strlen(wp->rootpath)+1, loc->rawname, mode); } static void QDECL VFSW32_ClosePath(searchpathfuncs_t *handle) { @@ -311,10 +348,9 @@ static qboolean QDECL VFSW32_PollChanges(searchpathfuncs_t *handle) } return result; } -static int QDECL VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle, searchpathfuncs_t *spath) +static int QDECL VFSW32_RebuildFSHash(const char *filename, qofs_t filesize, void *handle, searchpathfuncs_t *spath) { vfsw32path_t *wp = (void*)spath; - void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle) = handle; if (filename[strlen(filename)-1] == '/') { //this is actually a directory @@ -324,16 +360,17 @@ static int QDECL VFSW32_RebuildFSHash(const char *filename, int filesize, void * return true; } - AddFileHash(wp->hashdepth, filename, NULL, wp); + wp->AddFileHash(wp->hashdepth, filename, NULL, wp); return true; } static void QDECL VFSW32_BuildHash(searchpathfuncs_t *handle, int hashdepth, void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)) { vfsw32path_t *wp = (void*)handle; + wp->AddFileHash = AddFileHash; wp->hashdepth = hashdepth; Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, AddFileHash, handle); } -static int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) +static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) { vfsw32path_t *wp = (void*)handle; FILE *f; @@ -392,7 +429,7 @@ static void QDECL VFSW32_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, c fread(buffer, 1, loc->len, f); fclose(f); } -static int QDECL VFSW32_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL VFSW32_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) { vfsw32path_t *wp = (vfsw32path_t*)handle; return Sys_EnumerateFiles(wp->rootpath, match, func, parm, handle); diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 986e7ff0e..52c518a95 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -225,38 +225,56 @@ vfsfile_t *FS_DecompressGZip(vfsfile_t *infile, vfsfile_t *outfile) return temp; } -#include "unzip.c" + + + + + + + + + + + + + + + typedef struct { fsbucket_t bucket; char name[MAX_QPATH]; - int filepos, filelen; + qofs_t localpos, filelen; + unsigned int crc; + unsigned int flags; } zpackfile_t; +#define ZFL_DEFLATED 1 //need to use zlib +#define ZFL_STORED 2 //direct access is okay +#define ZFL_SYMLINK 4 //file is a symlink +#define ZFL_CORRUPT 8 //file is corrupt or otherwise unreadable. typedef struct zipfile_s { searchpathfuncs_t pub; - char filename[MAX_OSPATH]; - unzFile handle; - int numfiles; - zpackfile_t *files; + char filename[MAX_OSPATH]; + unsigned int numfiles; + zpackfile_t *files; #ifdef HASH_FILESYSTEM - hashtable_t hash; + hashtable_t hash; #endif - vfsfile_t *raw; - vfsfile_t *currentfile; //our unzip.c can only handle one active file at any one time - //so we have to keep closing and switching. - //slow, but it works. most of the time we'll only have a single file open anyway. - int references; //and a reference count + qofs_t curpos; //cache position to avoid excess seeks + qofs_t rawsize; + vfsfile_t *raw; + int references; //number of files open inside, so things don't crash if is closed in the wrong order. } zipfile_t; -static void QDECL FSZIP_GetPathDetails(searchpathfuncs_t *handle, char *out, unsigned int outlen) +static void QDECL FSZIP_GetPathDetails(searchpathfuncs_t *handle, char *out, size_t outlen) { zipfile_t *zip = (void*)handle; @@ -272,7 +290,7 @@ static void QDECL FSZIP_ClosePath(searchpathfuncs_t *handle) if (--zip->references > 0) return; //not yet time - unzClose(zip->handle); + VFS_CLOSE(zip->raw); if (zip->files) Z_Free(zip->files); Z_Free(zip); @@ -284,10 +302,12 @@ static void QDECL FSZIP_BuildHash(searchpathfuncs_t *handle, int depth, void (QD for (i = 0; i < zip->numfiles; i++) { + if (zip->files[i].flags & ZFL_CORRUPT) + continue; AddFileHash(depth, zip->files[i].name, &zip->files[i].bucket, &zip->files[i]); } } -static int QDECL FSZIP_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) +static unsigned int QDECL FSZIP_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) { zpackfile_t *pf = hashedresult; int i; @@ -305,8 +325,10 @@ static int QDECL FSZIP_FLocate(searchpathfuncs_t *handle, flocation_t *loc, cons { for (i=0 ; inumfiles ; i++) //look for the file { - if (!stricmp (zip->files[i].name, filename)) + if (!Q_strcasecmp (zip->files[i].name, filename)) { + if (zip->files[i].flags & ZFL_CORRUPT) + continue; pf = &zip->files[i]; break; } @@ -319,13 +341,16 @@ static int QDECL FSZIP_FLocate(searchpathfuncs_t *handle, flocation_t *loc, cons if (loc) { loc->index = pf - zip->files; - strcpy(loc->rawname, zip->filename); - loc->offset = pf->filepos; + *loc->rawname = 0; + loc->offset = (qofs_t)-1; loc->len = pf->filelen; - if (unzLocateFileMy (zip->handle, loc->index, zip->files[loc->index].filepos) == 2) + if (pf->flags & ZFL_SYMLINK) ret = FF_SYMLINK; - loc->offset = unzGetCurrentFileUncompressedPos(zip->handle); + + // if (unzLocateFileMy (zip->handle, loc->index, zip->files[loc->index].filepos) == 2) + // ret = FF_SYMLINK; + // loc->offset = unzGetCurrentFileUncompressedPos(zip->handle); // if (loc->offset<0) // { //file not found, or is compressed. // *loc->rawname = '\0'; @@ -339,26 +364,18 @@ static int QDECL FSZIP_FLocate(searchpathfuncs_t *handle, flocation_t *loc, cons return FF_NOTFOUND; } +static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode); static void QDECL FSZIP_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer) { - zipfile_t *zip = (void*)handle; - int err; - - unzLocateFileMy (zip->handle, loc->index, zip->files[loc->index].filepos); - - unzOpenCurrentFile (zip->handle); - err = unzReadCurrentFile (zip->handle, buffer, zip->files[loc->index].filelen); - unzCloseCurrentFile (zip->handle); - - if (err!=zip->files[loc->index].filelen) - { - Con_Printf ("Can't extract file \"%s:%s\" (corrupt)\n", zip->filename, zip->files[loc->index].name); + vfsfile_t *f; + f = FSZIP_OpenVFS(handle, loc, "rb"); + if (!f) //err... return; - } - return; + VFS_READ(f, buffer, loc->len); + VFS_CLOSE(f); } -static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, int, void *, searchpathfuncs_t *spath), void *parm) +static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *, qofs_t, void *, searchpathfuncs_t *spath), void *parm) { zipfile_t *zip = (void*)handle; int num; @@ -378,7 +395,6 @@ static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *ma static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype) { zipfile_t *zip = (void*)handle; - unz_file_info file_info; int result; int *filecrcs; @@ -388,18 +404,13 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int filecrcs = BZ_Malloc((zip->numfiles+1)*sizeof(int)); filecrcs[numcrcs++] = seed; - unzGoToFirstFile(zip->handle); for (i = 0; i < zip->numfiles; i++) { if (zip->files[i].filelen>0) - { - unzGetCurrentFileInfo (zip->handle, &file_info, NULL, 0, NULL, 0, NULL, 0); - filecrcs[numcrcs++] = file_info.crc; - } - unzGoToNextFile (zip->handle); + filecrcs[numcrcs++] = zip->files[i].crc; } - if (crctype) + if (crctype || numcrcs < 1) result = Com_BlockChecksum(filecrcs, numcrcs*sizeof(int)); else result = Com_BlockChecksum(filecrcs+1, (numcrcs-1)*sizeof(int)); @@ -408,59 +419,102 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int return result; } +struct decompressstate +{ + zipfile_t *source; + qofs_t cstart; //position of start of data + qofs_t cofs; //current read offset + qofs_t cend; //compressed data ends at this point. + qofs_t usize; //data remaining. refuse to read more bytes than this. + unsigned char inbuffer[16384]; + unsigned char outbuffer[16384]; + + z_stream strm; +}; + +struct decompressstate *FSZIP_Decompress_Init(zipfile_t *source, qofs_t start, qofs_t csize, qofs_t usize) +{ + struct decompressstate *st; + if (!ZLIB_LOADED()) + return NULL; + st = Z_Malloc(sizeof(*st)); + st->cstart = st->cofs = start; + st->cend = start + csize; + st->strm.data_type = Z_UNKNOWN; + st->source = source; + qinflateInit2(&st->strm, -MAX_WBITS); + return st; +} + +qofs_t FSZIP_Decompress_Read(struct decompressstate *st, qbyte *buffer, qofs_t bytes) +{ + qboolean eof = false; + int err; + qofs_t read = 0; + while(bytes) + { + if (st->strm.total_out) + { + unsigned int consume = st->strm.total_out; + if (consume > bytes) + consume = bytes; + memcpy(buffer, st->outbuffer, consume); + st->strm.total_out -= consume; + buffer += consume; + bytes -= consume; + read += consume; + continue; + } + else if (eof) + break; //no input available, and nothing in the buffers. + + st->strm.avail_out = sizeof(st->outbuffer); + st->strm.next_out = st->outbuffer; + if (!st->strm.avail_in) + { + qofs_t sz; + sz = st->cend - st->cofs; + if (sz > sizeof(st->inbuffer)) + sz = sizeof(st->inbuffer); + if (sz) + { + //feed it. + VFS_SEEK(st->source->raw, st->cofs); + st->strm.avail_in = VFS_READ(st->source->raw, st->inbuffer, sz); + st->strm.next_in = st->inbuffer; + st->cofs += st->strm.avail_in; + } + if (!st->strm.avail_in) + eof = true; + } + err = qinflate(&st->strm,Z_SYNC_FLUSH); + if (err == Z_STREAM_END) + eof = true; + else if (err != Z_OK) + break; + } + return read; +} + +void FSZIP_Decompress_Destroy(struct decompressstate *st) +{ + qinflateEnd(&st->strm); + Z_Free(st); +} + typedef struct { vfsfile_t funcs; - vfsfile_t *defer; + vfsfile_t *defer; //if set, reads+seeks are defered to this file instead. //in case we're forced away. zipfile_t *parent; - qboolean iscompressed; - int pos; - int length; //try and optimise some things - int index; - int startpos; + struct decompressstate *decompress; + qofs_t pos; + qofs_t length; //try and optimise some things +// int index; + qofs_t startpos; //file data offset } vfszip_t; -static qboolean VFSZIP_MakeActive(vfszip_t *vfsz) -{ - int i; - char buffer[8192]; //must be power of two - - if ((vfszip_t*)vfsz->parent->currentfile == vfsz) - return true; //already us - if (vfsz->parent->currentfile) - unzCloseCurrentFile(vfsz->parent->handle); - - unzLocateFileMy(vfsz->parent->handle, vfsz->index, vfsz->startpos); - if (unzOpenCurrentFile(vfsz->parent->handle) == UNZ_BADZIPFILE) - { - unz_file_info file_info; - buffer[0] = '?'; - buffer[1] = 0; - if (unzGetCurrentFileInfo (vfsz->parent->handle, &file_info, buffer, sizeof(buffer), NULL, 0, NULL, 0) != UNZ_OK) - Con_Printf("Zip Error\n"); - if (file_info.compression_method && file_info.compression_method != Z_DEFLATED) - Con_Printf("unsupported compression method on %s/%s\n", vfsz->parent->filename, buffer); - else - Con_Printf("corrupt file within zip, %s/%s\n", vfsz->parent->filename, buffer); - vfsz->parent->currentfile = NULL; - return false; - } - - - if (vfsz->pos > 0) - { - Con_DPrintf("VFSZIP_MakeActive: Shockingly inefficient\n"); - - //now we need to seek up to where we had previously gotten to. - for (i = 0; i < vfsz->pos-sizeof(buffer); i++) - unzReadCurrentFile(vfsz->parent->handle, buffer, sizeof(buffer)); - unzReadCurrentFile(vfsz->parent->handle, buffer, vfsz->pos - i); - } - - vfsz->parent->currentfile = (vfsfile_t*)vfsz; - return true; -} static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread) { @@ -470,20 +524,13 @@ static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int byt if (vfsz->defer) return VFS_READ(vfsz->defer, buffer, bytestoread); - if (vfsz->iscompressed) + if (vfsz->decompress) { - if (!VFSZIP_MakeActive(vfsz)) - return 0; - read = unzReadCurrentFile(vfsz->parent->handle, buffer, bytestoread); + read = FSZIP_Decompress_Read(vfsz->decompress, buffer, bytestoread); } else { - if (vfsz->parent->currentfile != file) - { - unzCloseCurrentFile(vfsz->parent->handle); - VFS_SEEK(vfsz->parent->raw, vfsz->pos+vfsz->startpos); - vfsz->parent->currentfile = file; - } + VFS_SEEK(vfsz->parent->raw, vfsz->pos+vfsz->startpos); if (vfsz->pos + bytestoread > vfsz->length) bytestoread = max(0, vfsz->length - vfsz->pos); read = VFS_READ(vfsz->parent->raw, buffer, bytestoread); @@ -492,12 +539,7 @@ static int QDECL VFSZIP_ReadBytes (struct vfsfile_s *file, void *buffer, int byt vfsz->pos += read; return read; } -//static int QDECL VFSZIP_WriteBytes (struct vfsfile_s *file, void *buffer, int bytestoread) -//{ -// Sys_Error("VFSZIP_WriteBytes: Not supported\n"); -// return 0; -//} -static qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos) +static qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, qofs_t pos) { vfszip_t *vfsz = (vfszip_t*)file; @@ -505,61 +547,38 @@ static qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos) return VFS_SEEK(vfsz->defer, pos); //This is *really* inefficient - if (vfsz->iscompressed) + if (vfsz->decompress) { //if they're going to seek on a file in a zip, let's just copy it out - char buffer[8192]; - unsigned int chunk; - unsigned int i; - unsigned int length; + qofs_t cstart = vfsz->decompress->cstart, csize = vfsz->decompress->cend - cstart; + qofs_t upos = 0, usize = vfsz->length; + qofs_t chunk; + struct decompressstate *nc; + qbyte buffer[16384]; vfsz->defer = FS_OpenTemp(); if (vfsz->defer) { - if (vfsz->pos) - { - unzCloseCurrentFile(vfsz->parent->handle); - vfsz->parent->currentfile = NULL; //make it not us - } + FSZIP_Decompress_Destroy(vfsz->decompress); + vfsz->decompress = NULL; - length = vfsz->length; - i = 0; - vfsz->pos = 0; - if (!VFSZIP_MakeActive(vfsz)) - { - /*shouldn't really happen*/ - VFS_CLOSE(vfsz->defer); - vfsz->defer = NULL; - return false; - } + nc = FSZIP_Decompress_Init(vfsz->parent, cstart, csize, usize); - while (1) + while (upos < usize) { - chunk = length - i; + chunk = usize - upos; if (chunk > sizeof(buffer)) chunk = sizeof(buffer); - if (chunk == 0) + if (!FSZIP_Decompress_Read(nc, buffer, chunk)) break; - unzReadCurrentFile(vfsz->parent->handle, buffer, chunk); - VFS_WRITE(vfsz->defer, buffer, chunk); - - i += chunk; + if (VFS_WRITE(vfsz->defer, buffer, chunk) != chunk) + break; + upos += chunk; } - } + FSZIP_Decompress_Destroy(nc); - unzCloseCurrentFile(vfsz->parent->handle); - vfsz->parent->currentfile = NULL; //make it not us - - if (vfsz->defer) return VFS_SEEK(vfsz->defer, pos); - else - { - unzCloseCurrentFile(vfsz->parent->handle); - vfsz->parent->currentfile = NULL; //make it not us, so the next read starts at the right place } - } - else - { - vfsz->parent->currentfile = NULL; + return false; } if (pos < 0 || pos > vfsz->length) @@ -568,7 +587,7 @@ static qboolean QDECL VFSZIP_Seek (struct vfsfile_s *file, unsigned long pos) return true; } -static unsigned long QDECL VFSZIP_Tell (struct vfsfile_s *file) +static qofs_t QDECL VFSZIP_Tell (struct vfsfile_s *file) { vfszip_t *vfsz = (vfszip_t*)file; @@ -577,7 +596,7 @@ static unsigned long QDECL VFSZIP_Tell (struct vfsfile_s *file) return vfsz->pos; } -static unsigned long QDECL VFSZIP_GetLen (struct vfsfile_s *file) +static qofs_t QDECL VFSZIP_GetLen (struct vfsfile_s *file) { vfszip_t *vfsz = (vfszip_t*)file; return vfsz->length; @@ -586,9 +605,6 @@ static void QDECL VFSZIP_Close (struct vfsfile_s *file) { vfszip_t *vfsz = (vfszip_t*)file; - if (vfsz->parent->currentfile == file) - vfsz->parent->currentfile = NULL; //make it not us - if (vfsz->defer) VFS_CLOSE(vfsz->defer); @@ -596,11 +612,14 @@ static void QDECL VFSZIP_Close (struct vfsfile_s *file) Z_Free(vfsz); } +static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qofs_t *datastart, qofs_t *datasize); + static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode) { - int rawofs; zipfile_t *zip = (void*)handle; vfszip_t *vfsz; + unsigned int flags; + qofs_t datasize = 0; if (strcmp(mode, "rb")) return NULL; //urm, unable to write/append @@ -608,11 +627,13 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo if (loc->len < 0) return NULL; + flags = zip->files[loc->index].flags; + if (flags & ZFL_CORRUPT) + return NULL; + vfsz = Z_Malloc(sizeof(vfszip_t)); vfsz->parent = zip; - vfsz->index = loc->index; - vfsz->startpos = zip->files[loc->index].filepos; vfsz->length = loc->len; #ifdef _DEBUG @@ -627,28 +648,24 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo vfsz->funcs.WriteBytes = NULL; vfsz->funcs.seekingisabadplan = true; - unzLocateFileMy(vfsz->parent->handle, vfsz->index, vfsz->startpos); - rawofs = unzGetCurrentFileUncompressedPos(zip->handle); - vfsz->iscompressed = rawofs<0; - if (!vfsz->iscompressed) - { - vfsz->startpos = rawofs; - VFS_SEEK(zip->raw, vfsz->startpos); - vfsz->parent->currentfile = (vfsfile_t*)vfsz; - } - else if (!ZLIB_LOADED()) + if (!FSZIP_ValidateLocalHeader(zip, &zip->files[loc->index], &vfsz->startpos, &datasize)) { Z_Free(vfsz); return NULL; } - else if (!VFSZIP_MakeActive(vfsz)) /*this is called purely as a test*/ + + if (flags & ZFL_DEFLATED) { - /* - windows explorer tends to use deflate64 on large files, which zlib and thus we, do not support, thus this is a 'common' failure path - this might also trigger from other errors, of course. - */ - Z_Free(vfsz); - return NULL; + vfsz->decompress = FSZIP_Decompress_Init(zip, vfsz->startpos, datasize, vfsz->length); + if (!vfsz->decompress) + { + /* + windows explorer tends to use deflate64 on large files, which zlib and thus we, do not support, thus this is a 'common' failure path + this might also trigger from other errors, of course. + */ + Z_Free(vfsz); + return NULL; + } } zip->references++; @@ -656,6 +673,545 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo return (vfsfile_t*)vfsz; } + +//ZIP features: +//zip64 for huge zips +//utf-8 encoding support (non-utf-8 is always ibm437) +//symlink flag +//compression mode: store +//compression mode: deflate (via zlib) +//bigendian cpus. everything misaligned. + +//NOT supported: +//compression mode: deflate64 +//other compression modes +//split archives +//if central dir is crypted/compressed, the archive will fail to open +//if a file is crypted/compressed, the file will (internally) be marked as corrupt +//crc verification +//infozip utf-8 name override. +//other 'extra' fields. + +struct zipinfo +{ + unsigned int thisdisk; //this disk number + unsigned int centraldir_startdisk; //central directory starts on this disk + qofs_t centraldir_numfiles_disk; //number of files in the centraldir on this disk + qofs_t centraldir_numfiles_all; //number of files in the centraldir on all disks + qofs_t centraldir_size; //total size of the centraldir + qofs_t centraldir_offset; //start offset of the centraldir with respect to the first disk that contains it + unsigned short commentlength; //length of the comment at the end of the archive. + + unsigned int zip64_centraldirend_disk; //zip64 weirdness + qofs_t zip64_centraldirend_offset; + unsigned int zip64_diskcount; + qofs_t zip64_eocdsize; + unsigned short zip64_version_madeby; + unsigned short zip64_version_needed; + + unsigned short centraldir_compressionmethod; + unsigned short centraldir_algid; + + qofs_t centraldir_end; + qofs_t zipoffset; +}; +struct zipcentralentry +{ + unsigned char *fname; + qofs_t cesize; + unsigned int flags; + + //PK12 + unsigned short version_madeby; + unsigned short version_needed; + unsigned short gflags; + unsigned short cmethod; + unsigned short lastmodfiletime; + unsigned short lastmodfiledate; + unsigned int crc32; + qofs_t csize; + qofs_t usize; + unsigned short fnane_len; + unsigned short extra_len; + unsigned short comment_len; + unsigned int disknum; + unsigned short iattributes; + unsigned int eattributes; + qofs_t localheaderoffset; //from start of disk +}; + +struct ziplocalentry +{ + //PK34 + unsigned short version_needed; + unsigned short gpflags; + unsigned short cmethod; + unsigned short lastmodfiletime; + unsigned short lastmodfiledate; + unsigned int crc32; + qofs_t csize; + qofs_t usize; + unsigned short fname_len; + unsigned short extra_len; +}; + +#define LittleU2FromPtr(p) (unsigned int)((p)[0] | ((p)[1]<<8u)) +#define LittleU4FromPtr(p) (unsigned int)((p)[0] | ((p)[1]<<8u) | ((p)[2]<<16u) | ((p)[3]<<24u)) +#define LittleU8FromPtr(p) qofs_Make(LittleU4FromPtr(p), LittleU4FromPtr((p)+4)) + +#define SIZE_LOCALENTRY 30 +#define SIZE_ENDOFCENTRALDIRECTORY 22 +#define SIZE_ZIP64ENDOFCENTRALDIRECTORY 56 +#define SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR 20 + +//check the local header and determine the place the data actually starts. +//we don't do much checking, just validating a few fields that are copies of fields we tracked elsewhere anyway. +//don't bother with the crc either +static qboolean FSZIP_ValidateLocalHeader(zipfile_t *zip, zpackfile_t *zfile, qofs_t *datastart, qofs_t *datasize) +{ + struct ziplocalentry local; + qbyte localdata[SIZE_LOCALENTRY]; + qofs_t localstart = zfile->localpos; + + VFS_SEEK(zip->raw, localstart); + VFS_READ(zip->raw, localdata, sizeof(localdata)); + + //make sure we found the right sort of table. + if (localdata[0] != 'P' || + localdata[1] != 'K' || + localdata[2] != 3 || + localdata[3] != 4) + return false; + + local.version_needed = LittleU2FromPtr(localdata+4); + local.gpflags = LittleU2FromPtr(localdata+6); + local.cmethod = LittleU2FromPtr(localdata+8); + local.lastmodfiletime = LittleU2FromPtr(localdata+10); + local.lastmodfiledate = LittleU2FromPtr(localdata+12); + local.crc32 = LittleU4FromPtr(localdata+14); + local.csize = LittleU4FromPtr(localdata+18); + local.usize = LittleU4FromPtr(localdata+22); + local.fname_len = LittleU2FromPtr(localdata+26); + local.extra_len = LittleU2FromPtr(localdata+28); + + localstart += SIZE_LOCALENTRY; + localstart += local.fname_len; + + //parse extra + if (local.usize == 0xffffffffu || local.csize == 0xffffffffu) //don't bother otherwise. + if (local.extra_len) + { + qbyte extradata[65536]; + qbyte *extra = extradata; + qbyte *extraend = extradata + local.extra_len; + unsigned short extrachunk_tag; + unsigned short extrachunk_len; + + VFS_SEEK(zip->raw, localstart); + VFS_READ(zip->raw, extradata, sizeof(extradata)); + + + while(extra+4 < extraend) + { + extrachunk_tag = LittleU2FromPtr(extra+0); + extrachunk_len = LittleU2FromPtr(extra+2); + if (extra + extrachunk_len > extraend) + break; //error + extra += 4; + + switch(extrachunk_tag) + { + case 1: //zip64 extended information extra field. the attributes are only present if the reegular file info is nulled out with a -1 + if (local.usize == 0xffffffffu) + { + local.usize = LittleU8FromPtr(extra); + extra += 8; + } + if (local.csize == 0xffffffffu) + { + local.csize = LittleU8FromPtr(extra); + extra += 8; + } + break; + default: + Con_Printf("Unknown chunk %x\n", extrachunk_tag); + case 0x5455: //extended timestamp + case 0x7875: //unix uid/gid + extra += extrachunk_len; + break; + } + } + } + localstart += local.extra_len; + *datastart = localstart; //this is the end of the local block, and the start of the data block (well, actually, should be encryption, but we don't support that). + *datasize = local.csize; + + if (local.gpflags & (1u<<3)) + { + //crc, usize, and csize were not known at the time the file was compressed. + //there is a 'data descriptor' after the file data, but to parse that we would need to decompress the file. + //instead, just depend upon upon the central directory and don't bother checking. + } + else + { + if (local.crc32 != zfile->crc) + return false; + if (local.usize != zfile->filelen) + return false; + } + + //FIXME: with pure paths, we still don't bother checking the crc (again, would require decompressing the entire file in advance). + + if (local.cmethod == 0) + return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_STORED; + if (local.cmethod == 8) + return (zfile->flags & (ZFL_STORED|ZFL_CORRUPT|ZFL_DEFLATED)) == ZFL_DEFLATED; + return false; //some other method that we don't know. +} + +static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipcentralentry *entry) +{ + entry->flags = 0; + entry->fname = ""; + entry->fnane_len = 0; + + if (data[0] != 'P' || + data[1] != 'K' || + data[2] != 1 || + data[3] != 2) + return false; //verify the signature + + //if we read too much, we'll catch it after. + entry->version_madeby = LittleU2FromPtr(data+4); + entry->version_needed = LittleU2FromPtr(data+6); + entry->gflags = LittleU2FromPtr(data+8); + entry->cmethod = LittleU2FromPtr(data+10); + entry->lastmodfiletime = LittleU2FromPtr(data+12); + entry->lastmodfiledate = LittleU2FromPtr(data+12); + entry->crc32 = LittleU4FromPtr(data+16); + entry->csize = LittleU4FromPtr(data+20); + entry->usize = LittleU4FromPtr(data+24); + entry->fnane_len = LittleU2FromPtr(data+28); + entry->extra_len = LittleU2FromPtr(data+30); + entry->comment_len = LittleU2FromPtr(data+32); + entry->disknum = LittleU2FromPtr(data+34); + entry->iattributes = LittleU2FromPtr(data+36); + entry->eattributes = LittleU4FromPtr(data+38); + entry->localheaderoffset = LittleU4FromPtr(data+42); + entry->cesize = 46; + + //mark the filename position + entry->fname = data+entry->cesize; + entry->cesize += entry->fnane_len; + + //parse extra + if (entry->extra_len) + { + qbyte *extra = data + entry->cesize; + qbyte *extraend = extra + entry->extra_len; + unsigned short extrachunk_tag; + unsigned short extrachunk_len; + while(extra+4 < extraend) + { + extrachunk_tag = LittleU2FromPtr(extra+0); + extrachunk_len = LittleU2FromPtr(extra+2); + if (extra + extrachunk_len > extraend) + break; //error + extra += 4; + + switch(extrachunk_tag) + { + case 1: //zip64 extended information extra field. the attributes are only present if the reegular file info is nulled out with a -1 + if (entry->usize == 0xffffffffu) + { + entry->usize = LittleU8FromPtr(extra); + extra += 8; + } + if (entry->csize == 0xffffffffu) + { + entry->csize = LittleU8FromPtr(extra); + extra += 8; + } + if (entry->localheaderoffset == 0xffffffffu) + { + entry->localheaderoffset = LittleU8FromPtr(extra); + extra += 8; + } + if (entry->disknum == 0xffffu) + { + entry->disknum = LittleU4FromPtr(extra); + extra += 4; + } + break; + default: + Con_Printf("Unknown chunk %x\n", extrachunk_tag); + case 0x5455: //extended timestamp + case 0x7875: //unix uid/gid + extra += extrachunk_len; + break; + } + } + entry->cesize += entry->extra_len; + } + + //parse comment + entry->cesize += entry->comment_len; + + //check symlink flags + { + qbyte madeby = entry->version_madeby>>8; //system + //vms, unix, or beos file attributes includes a symlink attribute. + //symlinks mean the file contents is just the name of another file. + if (madeby == 2 || madeby == 3 || madeby == 16) + { + unsigned short unixattr = entry->eattributes>>16; + if ((unixattr & 0xF000) == 0xA000)//fa&S_IFMT==S_IFLNK + entry->flags |= ZFL_SYMLINK; + else if ((unixattr & 0xA000) == 0xA000)//fa&S_IFMT==S_IFLNK + entry->flags |= ZFL_SYMLINK; + } + } + + if (entry->gflags & (1u<<0)) //encrypted + entry->flags |= ZFL_CORRUPT; + else if (entry->gflags & (1u<<5)) //is patch data + entry->flags |= ZFL_CORRUPT; + else if (entry->gflags & (1u<<6)) //strong encryption + entry->flags |= ZFL_CORRUPT; + else if (entry->gflags & (1u<<13)) //strong encryption + entry->flags |= ZFL_CORRUPT; + else if (entry->cmethod == 0) + entry->flags |= ZFL_STORED; + else if (entry->cmethod == 8) + entry->flags |= ZFL_DEFLATED; + else + entry->flags |= ZFL_CORRUPT; //unsupported compression method. + return true; +} + +//for compatibility with windows, this is an IBM437 -> unicode translation (ucs-2 is sufficient here) +//the zip codepage is defined as either IBM437(aka: dos) or UTF-8. Systems that use a different codepage are buggy. +unsigned short ibmtounicode[256] = +{ + 0x0000,0x263A,0x263B,0x2665,0x2666,0x2663,0x2660,0x2022,0x25D8,0x25CB,0x25D9,0x2642,0x2640,0x266A,0x266B,0x263C, //0x00(non-ascii, display-only) + 0x25BA,0x25C4,0x2195,0x203C,0x00B6,0x00A7,0x25AC,0x21A8,0x2191,0x2193,0x2192,0x2190,0x221F,0x2194,0x25B2,0x25BC, //0x10(non-ascii, display-only) + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, //0x20(ascii) + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, //0x30(ascii) + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F, //0x40(ascii) + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, //0x50(ascii) + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, //0x60(ascii) + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x2302, //0x70(mostly ascii, one display-only) + 0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7,0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5, //0x80(non-ascii, printable) + 0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9,0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192, //0x90(non-ascii, printable) + 0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA,0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB, //0xa0(non-ascii, printable) + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510, //0xb0(box-drawing, printable) + 0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F,0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567, //0xc0(box-drawing, printable) + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B,0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580, //0xd0(box-drawing, printable) + 0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x00B5,0x03C4,0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229, //0xe0(maths(greek), printable) + 0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248,0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0, //0xf0(maths, printable) +}; + +static qboolean FSZIP_EnumerateCentralDirectory(zipfile_t *zip, struct zipinfo *info) +{ + qboolean success = false; + zpackfile_t *f; + struct zipcentralentry entry; + qofs_t ofs = 0; + unsigned int i; + //lazily read the entire thing. + qbyte *centraldir = BZ_Malloc(info->centraldir_size); + if (centraldir) + { + VFS_SEEK(zip->raw, info->centraldir_offset+info->zipoffset); + if (VFS_READ(zip->raw, centraldir, info->centraldir_size) == info->centraldir_size) + { + zip->numfiles = info->centraldir_numfiles_disk; + zip->files = f = Z_Malloc (zip->numfiles * sizeof(zpackfile_t)); + + for (i = 0; i < zip->numfiles; i++) + { + if (!FSZIP_ReadCentralEntry(zip, centraldir+ofs, &entry) || ofs + entry.cesize > info->centraldir_size) + break; + + f->crc = entry.crc32; + + //copy out the filename and lowercase it + if (entry.gflags & (1u<<11)) + { //unicode encoding + if (entry.fnane_len > sizeof(f->name)-1) + entry.fnane_len = sizeof(f->name)-1; + memcpy(f->name, entry.fname, entry.fnane_len); + f->name[entry.fnane_len] = 0; + } + else + { + int i; + int nlen = 0; + int cl; + for (i = 0; i < entry.fnane_len; i++) + { + cl = utf8_encode(f->name+nlen, ibmtounicode[entry.fname[i]], sizeof(f->name)-1 - nlen); + if (!cl) //overflowed, truncate cleanly. + break; + nlen += cl; + } + f->name[nlen] = 0; + + } + Q_strlwr(f->name); + + f->filelen = entry.usize; + f->localpos = entry.localheaderoffset+info->zipoffset; + f->flags = entry.flags; + + ofs += entry.cesize; + f++; + } + + success = i == zip->numfiles; + if (!success) + { + Z_Free(zip->files); + zip->files = NULL; + zip->numfiles = 0; + } + } + } + + BZ_Free(centraldir); + return success; +} + +static qboolean FSZIP_FindEndCentralDirectory(zipfile_t *zip) +{ + struct zipinfo info; + qboolean result = false; + //zip comment is capped to 65k or so, so we can use a single buffer for this + qbyte traildata[0x10000 + SIZE_ENDOFCENTRALDIRECTORY+SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR]; + qbyte *magic; + unsigned int trailsize = 0x10000 + SIZE_ENDOFCENTRALDIRECTORY+SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR; + if (trailsize > zip->rawsize) + trailsize = zip->rawsize; + //FIXME: do in a loop to avoid a huge block of stack use + VFS_SEEK(zip->raw, zip->rawsize - trailsize); + VFS_READ(zip->raw, traildata, trailsize); + + memset(&info, 0, sizeof(info)); + + for (magic = traildata+trailsize-SIZE_ENDOFCENTRALDIRECTORY; magic >= traildata; magic--) + { + if (magic[0] == 'P' && + magic[1] == 'K' && + magic[2] == 5 && + magic[3] == 6) + { + info.centraldir_end = (zip->rawsize-trailsize)+(magic-traildata); + + info.thisdisk = LittleU2FromPtr(magic+4); + info.centraldir_startdisk = LittleU2FromPtr(magic+6); + info.centraldir_numfiles_disk = LittleU2FromPtr(magic+8); + info.centraldir_numfiles_all = LittleU2FromPtr(magic+10); + info.centraldir_size = LittleU4FromPtr(magic+12); + info.centraldir_offset = LittleU4FromPtr(magic+16); + info.commentlength = LittleU2FromPtr(magic+20); + + result = true; + break; + } + } + + if (!result) + Con_Printf("zip: unable to find end-of-central-directory\n"); + else + + //now look for a zip64 header. + //this gives more larger archives, more files, larger files, more spanned disks. + //note that the central directory itself is the same, it just has a couple of extra attributes on files that need them. + for (magic -= SIZE_ZIP64ENDOFCENTRALDIRECTORYLOCATOR; magic >= traildata; magic--) + { + if (magic[0] == 'P' && + magic[1] == 'K' && + magic[2] == 6 && + magic[3] == 7) + { + qbyte z64eocd[SIZE_ZIP64ENDOFCENTRALDIRECTORY]; + + info.zip64_centraldirend_disk = LittleU4FromPtr(magic+4); + info.zip64_centraldirend_offset = LittleU8FromPtr(magic+8); + info.zip64_diskcount = LittleU4FromPtr(magic+16); + + if (info.zip64_diskcount != 1 || info.zip64_centraldirend_disk != 0) + { + Con_Printf("zip: archive is spanned\n"); + return false; + } + + VFS_SEEK(zip->raw, info.zip64_centraldirend_offset); + VFS_READ(zip->raw, z64eocd, sizeof(z64eocd)); + + if (z64eocd[0] == 'P' && + z64eocd[1] == 'K' && + z64eocd[2] == 6 && + z64eocd[3] == 6) + { + info.zip64_eocdsize = LittleU8FromPtr(z64eocd+4) + 12; + info.zip64_version_madeby = LittleU2FromPtr(z64eocd+12); + info.zip64_version_needed = LittleU2FromPtr(z64eocd+14); + info.thisdisk = LittleU4FromPtr(z64eocd+16); + info.centraldir_startdisk = LittleU4FromPtr(z64eocd+20); + info.centraldir_numfiles_disk = LittleU8FromPtr(z64eocd+24); + info.centraldir_numfiles_all = LittleU8FromPtr(z64eocd+32); + info.centraldir_size = LittleU8FromPtr(z64eocd+40); + info.centraldir_offset = LittleU8FromPtr(z64eocd+48); + + if (info.zip64_eocdsize >= 84) + { + info.centraldir_compressionmethod = LittleU2FromPtr(z64eocd+56); +// info.zip64_2_centraldir_csize = LittleU8FromPtr(z64eocd+58); +// info.zip64_2_centraldir_usize = LittleU8FromPtr(z64eocd+66); + info.centraldir_algid = LittleU2FromPtr(z64eocd+74); +// info.zip64_2_bitlen = LittleU2FromPtr(z64eocd+76); +// info.zip64_2_flags = LittleU2FromPtr(z64eocd+78); +// info.zip64_2_hashid = LittleU2FromPtr(z64eocd+80); +// info.zip64_2_hashlength = LittleU2FromPtr(z64eocd+82); + //info.zip64_2_hashdata = LittleUXFromPtr(z64eocd+84, info.zip64_2_hashlength); + } + } + else + { + Con_Printf("zip: zip64 end-of-central directory at unknown offset.\n"); + result = false; + } + + break; + } + } + + if (info.thisdisk || info.centraldir_startdisk || info.centraldir_numfiles_disk != info.centraldir_numfiles_all) + { + Con_Printf("zip: archive is spanned\n"); + result = false; + } + if (info.centraldir_compressionmethod || info.centraldir_algid) + { + Con_Printf("zip: encrypted centraldir\n"); + result = false; + } + + if (result) + { + result = FSZIP_EnumerateCentralDirectory(zip, &info); + if (!result && !info.zip64_diskcount) + { + //uh oh... the central directory wasn't where it was meant to be! + //assuming that the endofcentraldir is packed at the true end of the centraldir (and that we're not zip64 and thus don't have an extra block), then we can guess based upon the offset difference + info.zipoffset = info.centraldir_end - (info.centraldir_offset+info.centraldir_size); + result = FSZIP_EnumerateCentralDirectory(zip, &info); + } + } + return result; +} + /* ================= COM_LoadZipFile @@ -668,30 +1224,21 @@ of the list so they override previous pack files. */ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *desc) { - int i; - int nextfileziphandle; - zipfile_t *zip; - zpackfile_t *newfiles; - - unz_global_info globalinf = {0}; - unz_file_info file_info; zip = Z_Malloc(sizeof(zipfile_t)); Q_strncpyz(zip->filename, desc, sizeof(zip->filename)); - zip->handle = unzOpen ((zip->raw = packhandle)); - if (!zip->handle) + zip->raw = packhandle; + zip->rawsize = VFS_GETLEN(zip->raw); + + if (!FSZIP_FindEndCentralDirectory(zip)) { Z_Free(zip); Con_TPrintf ("Failed opening zipfile \"%s\" corrupt?\n", desc); return NULL; } - unzGetGlobalInfo (zip->handle, &globalinf); - - zip->numfiles = globalinf.number_entry; - - zip->files = newfiles = Z_Malloc (zip->numfiles * sizeof(zpackfile_t)); +/* for (i = 0; i < zip->numfiles; i++) { if (unzGetCurrentFileInfo (zip->handle, &file_info, newfiles[i].name, sizeof(newfiles[i].name), NULL, 0, NULL, 0) != UNZ_OK) @@ -709,9 +1256,9 @@ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, const char *d else if (nextfileziphandle != UNZ_OK) Con_Printf("Zip Error\n"); } + */ zip->references = 1; - zip->currentfile = NULL; Con_TPrintf ("Added zipfile %s (%i files)\n", desc, zip->numfiles); diff --git a/engine/common/net_ice.c b/engine/common/net_ice.c index 84e448c0a..32f63cc25 100644 --- a/engine/common/net_ice.c +++ b/engine/common/net_ice.c @@ -311,46 +311,41 @@ struct icestate_s *QDECL ICE_Create(void *module, char *conname, char *peername, if (collection) { - int i; - int adrno, adrcount=1; - netadr_t adr; - for (i = 0; i < MAX_CONNECTIONS; i++) + int i, m; + + netadr_t addr[64]; + struct ftenet_generic_connection_s *gcon[sizeof(addr)/sizeof(addr[0])]; + int flags[sizeof(addr)/sizeof(addr[0])]; + + m = NET_EnumerateAddresses(collection, gcon, flags, addr, sizeof(addr)/sizeof(addr[0])); + + for (i = 0; i < m; i++) { - if (!collection->conn[i]) - continue; - adrno = 0; - if (collection->conn[i]->GetLocalAddress) + if (addr[i].type == NA_IP || addr[i].type == NA_IPV6) { - for (adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++) - { - if (adr.type == NA_IP || adr.type == NA_IPV6) - { - adr.connum = i; - ICE_AddLCandidateInfo(con, &adr, adrno, ICE_HOST); + ICE_AddLCandidateInfo(con, &addr[i], i, ICE_HOST); - /* - cand = Z_Malloc(sizeof(*cand)); - cand->info.network = i; - cand->info.port = ntohs(adr.port); - adr.port = 0; //to make sure its not part of the string... - Q_strncpyz(cand->info.addr, NET_AdrToString(adrbuf, sizeof(adrbuf), &adr), sizeof(cand->info.addr)); - cand->info.generation = 0; - cand->info.component = 1; - cand->info.foundation = 1; - cand->info.priority = - (1<<24)*(126) + - (1<<8)*((adr.type == NA_IP?32768:0)+net*256+(255-adrno)) + - (1<<0)*(256 - cand->info.component); + /* + cand = Z_Malloc(sizeof(*cand)); + cand->info.network = i; + cand->info.port = ntohs(adr.port); + adr.port = 0; //to make sure its not part of the string... + Q_strncpyz(cand->info.addr, NET_AdrToString(adrbuf, sizeof(adrbuf), &adr), sizeof(cand->info.addr)); + cand->info.generation = 0; + cand->info.component = 1; + cand->info.foundation = 1; + cand->info.priority = + (1<<24)*(126) + + (1<<8)*((adr.type == NA_IP?32768:0)+net*256+(255-adrno)) + + (1<<0)*(256 - cand->info.component); - Sys_RandomBytes((void*)rnd, sizeof(rnd)); - Q_strncpyz(cand->info.candidateid, va("x%08x%08x", rnd[0], rnd[1]), sizeof(cand->info.candidateid)); - cand->dirty = true; + Sys_RandomBytes((void*)rnd, sizeof(rnd)); + Q_strncpyz(cand->info.candidateid, va("x%08x%08x", rnd[0], rnd[1]), sizeof(cand->info.candidateid)); + cand->dirty = true; - cand->next = con->lc; - con->lc = cand; - */ - } - } + cand->next = con->lc; + con->lc = cand; + */ } } } diff --git a/engine/common/net_ssl_winsspi.c b/engine/common/net_ssl_winsspi.c index cd505c221..5f66f6fb6 100644 --- a/engine/common/net_ssl_winsspi.c +++ b/engine/common/net_ssl_winsspi.c @@ -573,17 +573,17 @@ static int QDECL SSPI_WriteBytes (struct vfsfile_s *file, const void *buffer, in return bytestowrite; } -static qboolean QDECL SSPI_Seek (struct vfsfile_s *file, unsigned long pos) +static qboolean QDECL SSPI_Seek (struct vfsfile_s *file, qofs_t pos) { SSPI_Error((sslfile_t*)file, "unable to seek on streams\n"); return false; } -static unsigned long QDECL SSPI_Tell (struct vfsfile_s *file) +static qofs_t QDECL SSPI_Tell (struct vfsfile_s *file) { SSPI_Error((sslfile_t*)file, "unable to seek on streams\n"); return 0; } -static unsigned long QDECL SSPI_GetLen (struct vfsfile_s *file) +static qofs_t QDECL SSPI_GetLen (struct vfsfile_s *file) { return 0; } diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index fd77882f3..7d0342332 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1557,14 +1557,16 @@ void NET_SendLoopPacket (int sock, int length, void *data, netadr_t *to) loop->msgs[i].datalen = length; } -int FTENET_Loop_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *out, int adrnum) +int FTENET_Loop_GetLocalAddresses(struct ftenet_generic_connection_s *con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses) { - if (adrnum==0) + if (maxaddresses) { - out->type = NA_LOOPBACK; - out->port = con->thesocket+1; + addresses->type = NA_LOOPBACK; + addresses->port = con->thesocket+1; + *adrflags = 0; + return 1; } - return 1; + return 0; } qboolean FTENET_Loop_GetPacket(ftenet_generic_connection_t *con) @@ -1613,7 +1615,7 @@ static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean iss { loopbacks[sock].inited = true; - newcon->GetLocalAddress = FTENET_Loop_GetLocalAddress; + newcon->GetLocalAddresses = FTENET_Loop_GetLocalAddresses; newcon->GetPacket = FTENET_Loop_GetPacket; newcon->SendPacket = FTENET_Loop_SendPacket; newcon->Close = FTENET_Loop_Close; @@ -1664,7 +1666,7 @@ typedef struct unsigned int refreshtime; } pmpcon_t; -int FTENET_NATPMP_GetLocalAddress(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx); +int FTENET_NATPMP_GetLocalAddresses(struct ftenet_generic_connection_s *con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses); static qboolean NET_Was_NATPMP(ftenet_connections_t *collection) { pmpcon_t *pmp; @@ -1688,7 +1690,7 @@ static qboolean NET_Was_NATPMP(ftenet_connections_t *collection) { if (!collection->conn[i]) continue; - if (collection->conn[i]->GetLocalAddress == FTENET_NATPMP_GetLocalAddress) + if (collection->conn[i]->GetLocalAddresses == FTENET_NATPMP_GetLocalAddresses) { pmp = (pmpcon_t*)collection->conn[i]; if (NET_CompareAdr(&pmp->pmpaddr, &net_from)) @@ -1704,7 +1706,7 @@ static qboolean NET_Was_NATPMP(ftenet_connections_t *collection) pmp->natadr.port = 0; memcpy(pmp->natadr.address.ip, pmpreqrep->ipv4, sizeof(pmp->natadr.address.ip)); NET_AdrToString(adrbuf, sizeof(adrbuf), &pmp->natadr); - pmp->natadr.connum = i; + pmp->natadr.connum = i+1; Con_DPrintf("NAT-PMP: Public ip is %s\n", adrbuf); if (pmp->natadr.type && pmp->natadr.port) @@ -1752,9 +1754,13 @@ static qboolean NET_Was_NATPMP(ftenet_connections_t *collection) static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connections_t *collection) { - int i; - int adrno, adrcount=1; + int i, m; netadr_t adr; + + netadr_t addr[64]; + struct ftenet_generic_connection_s *con[sizeof(addr)/sizeof(addr[0])]; + int flags[sizeof(addr)/sizeof(addr[0])]; + struct { qbyte ver; qbyte op; short reserved1; @@ -1772,78 +1778,90 @@ static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connectio if (!collection) return; - for (i = 0; i < MAX_CONNECTIONS; i++) + m = NET_EnumerateAddresses(collection, con, flags, addr, sizeof(addr)/sizeof(addr[0])); + + for (i = 0; i < m; i++) { - if (!collection->conn[i]) + //ignore any ips which are proxied by other people. that would be too weird. + if (flags[i] & (ADDR_NATPMP|ADDR_UPNPIGP)) continue; - if (collection->conn[i]->GetLocalAddress && collection->conn[i]->GetLocalAddress != FTENET_NATPMP_GetLocalAddress) + + adr = addr[i]; + + //unipv6ify it if its a hybrid socket. + if (adr.type == NA_IPV6 && + !*(int*)&adr.address.ip6[0] && + !*(int*)&adr.address.ip6[4] && + !*(short*)&adr.address.ip6[8] && + *(short*)&adr.address.ip6[10]==(short)0xffff && + !*(int*)&adr.address.ip6[12]) { - for (adrno = 0, adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++) - { -// Con_Printf("net address (%s): %s\n", collection->conn[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), adr)); - - //unipv6ify it if its a hybrid socket. - if (adr.type == NA_IPV6 && - !*(int*)&adr.address.ip6[0] && - !*(int*)&adr.address.ip6[4] && - !*(short*)&adr.address.ip6[8] && - *(short*)&adr.address.ip6[10]==(short)0xffff && - !*(int*)&adr.address.ip6[12]) - { - *(int*)adr.address.ip = *(int*)&adr.address.ip6[12]; - adr.type = NA_IP; - } - - if (adr.type == NA_IP) - { - if (adr.address.ip[0] == 127) //yes. loopback has a lot of ip addresses. wasteful but whatever. - continue; - - //assume a netmask of 255.255.255.0 - adr.address.ip[3] = 1; - } -// else if (adr.type == NA_IPV6) -// { -// } - else - continue; - - pmpreqmsg.privport = adr.port; - pmpreqmsg.pubport = oldport?oldport:adr.port; - - if (*(int*)pmp->reqpmpaddr.address.ip == INADDR_ANY) - { - pmp->pmpaddr = adr; - pmp->pmpaddr.port = pmp->reqpmpaddr.port; - } - else - pmp->pmpaddr = pmp->reqpmpaddr; - - if (*(int*)pmp->pmpaddr.address.ip == INADDR_ANY) - continue; - - //get the public ip. - pmpreqmsg.op = 0; - NET_SendPacket(NS_SERVER, 2, &pmpreqmsg, &pmp->pmpaddr); - - //open the firewall/nat. - pmpreqmsg.op = 1; - NET_SendPacket(NS_SERVER, sizeof(pmpreqmsg), &pmpreqmsg, &pmp->pmpaddr); - - break; - } + *(int*)adr.address.ip = *(int*)&adr.address.ip6[12]; + adr.type = NA_IP; } + + if (adr.type == NA_IP) + { + if (adr.address.ip[0] == 127) //yes. loopback has a lot of ip addresses. wasteful but whatever. + continue; + + //assume a netmask of 255.255.255.0 + adr.address.ip[3] = 1; + } +// else if (adr.type == NA_IPV6) +// { +// } + else + continue; + + pmpreqmsg.privport = adr.port; + pmpreqmsg.pubport = oldport?oldport:adr.port; + + if (*(int*)pmp->reqpmpaddr.address.ip == INADDR_ANY) + { + pmp->pmpaddr = adr; + pmp->pmpaddr.port = pmp->reqpmpaddr.port; + } + else + pmp->pmpaddr = pmp->reqpmpaddr; + + if (*(int*)pmp->pmpaddr.address.ip == INADDR_ANY) + continue; + + //get the public ip. + pmpreqmsg.op = 0; + NET_SendPacket(NS_SERVER, 2, &pmpreqmsg, &pmp->pmpaddr); + + //open the firewall/nat. + pmpreqmsg.op = 1; + NET_SendPacket(NS_SERVER, sizeof(pmpreqmsg), &pmpreqmsg, &pmp->pmpaddr); + + break; } } #define PMP_POLL_TIME (1000*30)//every 30 seconds -int FTENET_NATPMP_GetLocalAddress(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx) +qboolean Net_OpenUDPPort(char *privateip, int privateport, char *publicip, size_t publiciplen, int *publicport); +int FTENET_NATPMP_GetLocalAddresses(struct ftenet_generic_connection_s *con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses) { pmpcon_t *pmp = (pmpcon_t*)con; - local->type = NA_INVALID; +/* + char pubip[256]; + int pubport; - if (adridx == 0) - *local = pmp->natadr; - return (pmp->natadr.type != NA_INVALID) && (pmp->natadr.port != 0); + if (Net_OpenUDPPort("192.168.1.4", 27500, pubip, sizeof(pubip), &pubport)) + { + *adrflags = ADDR_UPNPIGP; + NET_StringToAdr(pubip, pubport, addresses); + return 1; + } +*/ + if (maxaddresses) + { + *adrflags = ADDR_NATPMP; + *addresses = pmp->natadr; + return (pmp->natadr.type != NA_INVALID) && (pmp->natadr.port != 0); + } + return 0; } qboolean FTENET_NATPMP_GetPacket(struct ftenet_generic_connection_s *con) { @@ -1876,12 +1894,12 @@ ftenet_generic_connection_t *FTENET_NATPMP_EstablishConnection(qboolean isserver pmpadr.type = NA_IP; if (pmpadr.type != NA_IP) return NULL; - + pmp = Z_Malloc(sizeof(*pmp)); pmp->col = svs.sockets; Q_strncpyz(pmp->pub.name, "natpmp", sizeof(pmp->pub.name)); pmp->reqpmpaddr = pmpadr; - pmp->pub.GetLocalAddress = FTENET_NATPMP_GetLocalAddress; + pmp->pub.GetLocalAddresses = FTENET_NATPMP_GetLocalAddresses; pmp->pub.GetPacket = FTENET_NATPMP_GetPacket; //qboolean (*ChangeLocalAddress)(struct ftenet_generic_connection_s *con, const char *newaddress); pmp->pub.SendPacket = FTENET_NATPMP_SendPacket; @@ -1896,10 +1914,6 @@ ftenet_generic_connection_t *FTENET_NATPMP_EstablishConnection(qboolean isserver } #endif -#ifdef UPNP -ftenet_generic_connection_t *FTENET_NATUPNP_EstablishConnection(qboolean isserver, const char *address); -#endif - qboolean FTENET_AddToCollection_Ptr(ftenet_connections_t *col, const char *name, const char *address, ftenet_generic_connection_t *(*establish)(qboolean isserver, const char *address), qboolean islisten) { int count = 0; @@ -2029,15 +2043,14 @@ void FTENET_Generic_Close(ftenet_generic_connection_t *con) } #ifdef _WIN32 -int FTENET_GetLocalAddress(netadr_t *out, int port, int count, qboolean ipx, qboolean ipv4, qboolean ipv6) +int FTENET_GetLocalAddress(int port, qboolean ipx, qboolean ipv4, qboolean ipv6, unsigned int *adrflags, netadr_t *addresses, int maxaddresses) { //in win32, we can look up our own hostname to retrieve a list of local interface addresses. - netadr_t adr; #ifdef USE_GETHOSTNAME_LOCALLISTING char adrs[MAX_ADR_SIZE]; int b; #endif - int idx = 0; + int found = 0; gethostname(adrs, sizeof(adrs)); #ifdef IPPROTO_IPV6 @@ -2060,28 +2073,35 @@ int FTENET_GetLocalAddress(netadr_t *out, int port, int count, qboolean ipx, qbo || (itr->ai_addr->sa_family == AF_IPX && ipx) #endif ) - if (idx++ == count) + if (maxaddresses) { - SockadrToNetadr((struct sockaddr_qstorage*)itr->ai_addr, out); - out->port = port; + SockadrToNetadr((struct sockaddr_qstorage*)itr->ai_addr, addresses); + addresses->port = port; + *adrflags++ = 0; + addresses++; + maxaddresses--; + found++; } } pfreeaddrinfo(result); /*if none found, fill in the 0.0.0.0 or whatever*/ - if (!idx) + if (!found && maxaddresses) { - idx++; - memset(out, 0, sizeof(*out)); - out->port = port; + memset(addresses, 0, sizeof(*addresses)); + addresses->port = port; if (ipv6) - out->type = NA_IPV6; + addresses->type = NA_IPV6; else if (ipv4) - out->type = NA_IP; + addresses->type = NA_IP; else if (ipx) - out->type = NA_IPX; + addresses->type = NA_IPX; else - out->type = NA_INVALID; + addresses->type = NA_INVALID; + *adrflags++ = 0; + addresses++; + maxaddresses--; + found++; } } } @@ -2094,33 +2114,38 @@ int FTENET_GetLocalAddress(netadr_t *out, int port, int count, qboolean ipx, qbo #ifdef HAVE_IPV4 if(h && h->h_addrtype == AF_INET) { - for (b = 0; h->h_addr_list[b]; b++) + for (b = 0; h->h_addr_list[b] && maxaddresses; b++) { struct sockaddr_in from; from.sin_family = AF_INET; memcpy(&from.sin_addr, h->h_addr_list[b], sizeof(&from.sin_addr)); - SockadrToNetadr((struct sockaddr_qstorage*)&from, &adr); - if (idx++ == count) - *out = adr; + SockadrToNetadr((struct sockaddr_qstorage*)&from, addresses); + + *adrflags++ = 0; + addresses++; + maxaddresses--; + found++; } } #endif #ifdef IPPROTO_IPV6 if(h && h->h_addrtype == AF_INET6) { - for (b = 0; h->h_addr_list[b]; b++) + for (b = 0; h->h_addr_list[b] && maxaddresses; b++) { struct sockaddr_in6 from; from.sin6_family = AF_INET6; memcpy(&from.sin6_addr, h->h_addr_list[b], sizeof(((struct sockaddr_in6*)&from)->sin6_addr)); - SockadrToNetadr((struct sockaddr_qstorage*)&from, &adr); - if (idx++ == count) - *out = adr; + SockadrToNetadr((struct sockaddr_qstorage*)&from, addresses); + *adrflags++ = 0; + addresses++; + maxaddresses--; + found++; } } #endif } - return idx; + return found; } #elif defined(__linux__) && !defined(ANDROID) @@ -2185,7 +2210,7 @@ int FTENET_GetLocalAddress(netadr_t *out, int count) } #endif -int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *out, int count) +int FTENET_Generic_GetLocalAddresses(struct ftenet_generic_connection_s *con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses) { #ifndef HAVE_PACKET return 0; @@ -2193,7 +2218,7 @@ int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *o struct sockaddr_qstorage from; int fromsize = sizeof(from); netadr_t adr; - int idx = 0; + int found = 0; if (getsockname (con->thesocket, (struct sockaddr*)&from, &fromsize) != -1) { @@ -2211,7 +2236,7 @@ int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *o { //ipv6 socket bound to the ipv4-any address is a bit weird, but oh well. //FIXME: should we first validate that we support hybrid sockets? - idx = FTENET_GetLocalAddress(out, adr.port, count, false, true, false); + found = FTENET_GetLocalAddress(adr.port, false, true, false, adrflags, addresses, maxaddresses); } else { @@ -2239,32 +2264,42 @@ int FTENET_Generic_GetLocalAddress(ftenet_generic_connection_t *con, netadr_t *o ipv6 = true; } - idx = FTENET_GetLocalAddress(out, adr.port, count, ipx, ipv4, ipv6); + found = FTENET_GetLocalAddress(adr.port, ipx, ipv4, ipv6, adrflags, addresses, maxaddresses); } } #endif //and use the bound address (even if its 0.0.0.0) if we didn't grab a list from the system. - if (!idx) + if (!found) { - if (adr.type == NA_IPV6 && + if (maxaddresses && adr.type == NA_IPV6 && !*(int*)&adr.address.ip6[0] && !*(int*)&adr.address.ip6[4] && !*(int*)&adr.address.ip6[8] && !*(int*)&adr.address.ip6[12]) { - if (idx++ == count) - { - *out = adr; - out->type = NA_IP; - } + *addresses = adr; + addresses->type = NA_IP; + + *adrflags++ = 0; + addresses++; + maxaddresses--; + found++; + } + + if (maxaddresses) + { + *addresses = adr; + + *adrflags++ = 0; + addresses++; + maxaddresses--; + found++; } - if (idx++ == count) - *out = adr; } } - return idx; + return found; #endif } @@ -2287,18 +2322,18 @@ qboolean FTENET_Generic_GetPacket(ftenet_generic_connection_t *con) if (ret == -1) { - err = qerrno; + err = neterrno(); - if (err == EWOULDBLOCK) + if (err == NET_EWOULDBLOCK) return false; - if (err == EMSGSIZE) + if (err == NET_EMSGSIZE) { SockadrToNetadr (&from, &net_from); Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &net_from)); return false; } - if (err == ECONNABORTED || err == ECONNRESET) + if (err == NET_ECONNABORTED || err == NET_ECONNRESET) { Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost. #ifndef SERVERONLY @@ -2391,22 +2426,22 @@ qboolean FTENET_Generic_SendPacket(ftenet_generic_connection_t *con, int length, ret = sendto (con->thesocket, data, length, 0, (struct sockaddr*)&addr, size ); if (ret == -1) { - int ecode = qerrno; + int ecode = neterrno(); // wouldblock is silent - if (ecode == EWOULDBLOCK) + if (ecode == NET_EWOULDBLOCK) return true; - if (ecode == ECONNREFUSED) + if (ecode == NET_ECONNREFUSED) return true; - if (ecode == EACCES) + if (ecode == NET_EACCES) { Con_Printf("Access denied: check firewall\n"); return true; } #ifndef SERVERONLY - if (ecode == EADDRNOTAVAIL) + if (ecode == NET_EADDRNOTAVAIL) Con_DPrintf("NET_SendPacket Warning: %i\n", ecode); else #endif @@ -2542,7 +2577,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i } if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) - Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); // @@ -2554,7 +2589,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i newcon = Z_Malloc(sizeof(*newcon)); if (newcon) { - newcon->GetLocalAddress = FTENET_Generic_GetLocalAddress; + newcon->GetLocalAddresses = FTENET_Generic_GetLocalAddresses; newcon->GetPacket = FTENET_Generic_GetPacket; newcon->SendPacket = FTENET_Generic_SendPacket; newcon->Close = FTENET_Generic_Close; @@ -2720,17 +2755,17 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon) } else if (ret == -1) { - err = qerrno; + err = neterrno(); - if (err == EWOULDBLOCK) + if (err == NET_EWOULDBLOCK) ret = 0; else { - if (err == ECONNABORTED || err == ECONNRESET) + if (err == NET_ECONNABORTED || err == NET_ECONNRESET) { Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost. } - else if (err == ENOTCONN) + else if (err == NET_ENOTCONN) Con_Printf ("TCPConnect_GetPacket: connection failed\n"); else Con_Printf ("TCPConnect_GetPacket: Error (%i): %s\n", err, strerror(err)); @@ -3527,7 +3562,7 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, } if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) - Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); #endif } else @@ -3549,7 +3584,7 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(int affamily, if (newcon) { if (isserver) - newcon->generic.GetLocalAddress = FTENET_Generic_GetLocalAddress; + newcon->generic.GetLocalAddresses = FTENET_Generic_GetLocalAddresses; newcon->generic.GetPacket = FTENET_TCPConnect_GetPacket; newcon->generic.SendPacket = FTENET_TCPConnect_SendPacket; newcon->generic.Close = FTENET_TCPConnect_Close; @@ -3701,11 +3736,11 @@ qboolean FTENET_IRCConnect_GetPacket(ftenet_generic_connection_t *gcon) read = recv(con->generic.thesocket, con->incoming+con->income, sizeof(con->incoming)-1 - con->income, 0); if (read < 0) { - read = qerrno; + read = neterrno(); switch(read) { - case ECONNABORTED: - case ECONNRESET: + case NET_ECONNABORTED: + case NET_ECONNRESET: closesocket(con->generic.thesocket); con->generic.thesocket = INVALID_SOCKET; break; @@ -4622,16 +4657,17 @@ int NET_GetPacket (netsrc_t netsrc, int firstsock) int NET_LocalAddressForRemote(ftenet_connections_t *collection, netadr_t *remote, netadr_t *local, int idx) { + int adrflags; if (!remote->connum) return 0; if (!collection->conn[remote->connum-1]) return 0; - if (!collection->conn[remote->connum-1]->GetLocalAddress) + if (!collection->conn[remote->connum-1]->GetLocalAddresses) return 0; - return collection->conn[remote->connum-1]->GetLocalAddress(collection->conn[remote->connum-1], local, idx); + return collection->conn[remote->connum-1]->GetLocalAddresses(collection->conn[remote->connum-1], &adrflags, local, 1); } qboolean NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t *to) @@ -4710,30 +4746,60 @@ qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char return true; } -void NET_PrintAddresses(ftenet_connections_t *collection) +int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_generic_connection_s **con, int *adrflags, netadr_t *addresses, int maxaddresses) { - int i; - int adrno, adrcount=1; - netadr_t adr; - char adrbuf[MAX_ADR_SIZE]; - - if (!collection) - return; - + unsigned int found = 0, c, i, j; for (i = 0; i < MAX_CONNECTIONS; i++) { if (!collection->conn[i]) continue; - adrno = 0; - if (collection->conn[i]->GetLocalAddress) + + c = collection->conn[i]->GetLocalAddresses(collection->conn[i], adrflags, addresses, maxaddresses); + + if (maxaddresses && !c) { - for (adrcount=1; (adrcount = collection->conn[i]->GetLocalAddress(collection->conn[i], &adr, adrno)) && adrno < adrcount; adrno++) - { - Con_Printf("net address (%s): %s\n", collection->conn[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &adr)); - } + *adrflags = 0; + addresses->type = NA_INVALID; + c = 1; } - if (!adrno) - Con_Printf("net address (%s): no addresses\n", collection->conn[i]->name); + + //fill in connection info + for (j = 0; j < c; j++) + { + con[j] = collection->conn[i]; + addresses[j].connum = i+1; + } + + con += c; + adrflags += c; + addresses += c; + maxaddresses -= c; + found += c; + } + return found; +} + +#define MAXADDRESSES 64 +void NET_PrintAddresses(ftenet_connections_t *collection) +{ + int i; + char adrbuf[MAX_ADR_SIZE]; + int m; + netadr_t addr[64]; + struct ftenet_generic_connection_s *con[sizeof(addr)/sizeof(addr[0])]; + int flags[sizeof(addr)/sizeof(addr[0])]; + + if (!collection) + return; + + m = NET_EnumerateAddresses(collection, con, flags, addr, sizeof(addr)/sizeof(addr[0])); + + for (i = 0; i < m; i++) + { + if (addr[i].type == NA_INVALID) + Con_Printf("net address (%s): no addresses\n", con[i]->name); + else + Con_Printf("net address (%s): %s\n", con[i]->name, NET_AdrToString(adrbuf, sizeof(adrbuf), &addr[i])); } } @@ -4759,7 +4825,7 @@ int TCP_OpenStream (netadr_t *remoteaddr) setsockopt(newsocket, SOL_SOCKET, SO_RCVBUF, (void*)&recvbufsize, sizeof(recvbufsize)); if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) - Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); // memset(&loc, 0, sizeof(loc)); // ((struct sockaddr*)&loc)->sa_family = ((struct sockaddr*)&loc)->sa_family; @@ -4767,19 +4833,19 @@ int TCP_OpenStream (netadr_t *remoteaddr) if (connect(newsocket, (struct sockaddr *)&qs, temp) == INVALID_SOCKET) { - int err = qerrno; - if (err != EWOULDBLOCK && err != EINPROGRESS) + int err = neterrno(); + if (err != NET_EWOULDBLOCK && err != NET_EINPROGRESS) { char buf[256]; NET_AdrToString(buf, sizeof(buf), remoteaddr); - if (err == EADDRNOTAVAIL) + if (err == NET_EADDRNOTAVAIL) { if (remoteaddr->port == 0 && (remoteaddr->type == NA_IP || remoteaddr->type == NA_IPV6)) Con_Printf ("TCP_OpenStream: no port specified (%s)\n", buf); else Con_Printf ("TCP_OpenStream: invalid address trying to connect to %s\n", buf); } - else if (err == EACCES) + else if (err == NET_EACCES) Con_Printf ("TCP_OpenStream: access denied: check firewall (%s)\n", buf); else Con_Printf ("TCP_OpenStream: connect: error %i (%s)\n", err, buf); @@ -4884,7 +4950,7 @@ int maxport = port + 100; return (int)INVALID_SOCKET; if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) - Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); if (bcast) { @@ -4915,10 +4981,10 @@ int maxport = port + 100; if( bind (newsocket, (void *)&address, sizeof(address)) == -1) { if (!port) - Sys_Error ("UDP_OpenSocket: bind: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: bind: %s", strerror(neterrno())); port++; if (port > maxport) - Sys_Error ("UDP_OpenSocket: bind: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: bind: %s", strerror(neterrno())); } else break; @@ -4941,12 +5007,12 @@ int maxport = port + 100; if ((newsocket = socket (PF_INET6, SOCK_DGRAM, 0)) == INVALID_SOCKET) { - Con_Printf("IPV6 is not supported: %s\n", strerror(qerrno)); + Con_Printf("IPV6 is not supported: %s\n", strerror(neterrno())); return (int)INVALID_SOCKET; } if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) - Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); if (bcast) { @@ -4984,7 +5050,7 @@ int maxport = port + 100; { if (!port) { - err = qerrno; + err = neterrno(); Con_Printf ("UDP6_OpenSocket: bind: (%i) %s", err, strerror(err)); closesocket(newsocket); return (int)INVALID_SOCKET; @@ -4992,7 +5058,7 @@ int maxport = port + 100; port++; if (port > maxport) { - err = qerrno; + err = neterrno(); Con_Printf ("UDP6_OpenSocket: bind: (%i) %s", err, strerror(err)); closesocket(newsocket); return (int)INVALID_SOCKET; @@ -5022,15 +5088,16 @@ int IPX_OpenSocket (int port, qboolean bcast) if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET) { - if (qerrno != EAFNOSUPPORT) - Con_Printf ("WARNING: IPX_Socket: socket: %i\n", qerrno); + int e = neterrno(); + if (e != NET_EAFNOSUPPORT) + Con_Printf ("WARNING: IPX_Socket: socket: %i\n", e); return INVALID_SOCKET; } // make it non-blocking if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) { - Con_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %i\n", qerrno); + Con_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %i\n", neterrno()); return INVALID_SOCKET; } @@ -5039,7 +5106,7 @@ int IPX_OpenSocket (int port, qboolean bcast) // make it broadcast capable if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1) { - Con_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %i\n", qerrno); + Con_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %i\n", neterrno()); return INVALID_SOCKET; } } @@ -5054,7 +5121,7 @@ int IPX_OpenSocket (int port, qboolean bcast) if( bind (newsocket, (void *)&address, sizeof(address)) == -1) { - Con_Printf ("WARNING: IPX_Socket: bind: %i\n", qerrno); + Con_Printf ("WARNING: IPX_Socket: bind: %i\n", neterrno()); closesocket (newsocket); return INVALID_SOCKET; } @@ -5258,6 +5325,12 @@ qboolean NET_WasSpecialPacket(netsrc_t netsrc) #endif return false; } + +void NET_UPNPIGP_Callback(cvar_t *var, char *oldval) +{ +} +cvar_t net_upnpigp = CVARCD("net_upnpigp", "0", NET_UPNPIGP_Callback, "If set, enables the use of the upnp-igd protocol to punch holes in your local NAT box."); + /* ==================== NET_Init @@ -5300,6 +5373,9 @@ void NET_Init (void) #ifndef SERVERONLY Cmd_AddCommand("cl_addport", NET_ClientPort_f); #endif + + Cvar_Register (&net_upnpigp, "networking"); + net_upnpigp.restriction = RESTRICT_MAX; } #ifndef SERVERONLY void NET_InitClient(void) @@ -5584,21 +5660,21 @@ int QDECL VFSTCP_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestorea len = recv(tf->sock, tf->readbuffer + tf->readbuffered, trying, 0); if (len == -1) { - int e = qerrno; - if (e != EWOULDBLOCK) + int e = neterrno(); + if (e != NET_EWOULDBLOCK) { switch(e) { - case ENOTCONN: + case NET_ENOTCONN: Con_Printf("connection to \"%s\" failed\n", tf->peer); break; - case ECONNABORTED: + case NET_ECONNABORTED: Con_DPrintf("connection to \"%s\" aborted\n", tf->peer); break; - case ECONNREFUSED: + case NET_ECONNREFUSED: Con_DPrintf("connection to \"%s\" refused\n", tf->peer); break; - case ECONNRESET: + case NET_ECONNRESET: Con_DPrintf("connection to \"%s\" reset\n", tf->peer); break; default: @@ -5665,12 +5741,12 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt len = send(tf->sock, buffer, bytestoread, 0); if (len == -1 || len == 0) { - int e = qerrno; + int e = neterrno(); switch(e) { - case EWOULDBLOCK: + case NET_EWOULDBLOCK: return 0; //nothing available yet. - case ENOTCONN: + case NET_ENOTCONN: Con_Printf("connection to \"%s\" failed\n", tf->peer); break; default: @@ -5684,17 +5760,17 @@ int QDECL VFSTCP_WriteBytes (struct vfsfile_s *file, const void *buffer, int byt } return len; } -qboolean QDECL VFSTCP_Seek (struct vfsfile_s *file, unsigned long pos) +qboolean QDECL VFSTCP_Seek (struct vfsfile_s *file, qofs_t pos) { VFSTCP_Error((tcpfile_t*)file); return false; } -unsigned long QDECL VFSTCP_Tell (struct vfsfile_s *file) +qofs_t QDECL VFSTCP_Tell (struct vfsfile_s *file) { VFSTCP_Error((tcpfile_t*)file); return 0; } -unsigned long QDECL VFSTCP_GetLen (struct vfsfile_s *file) +qofs_t QDECL VFSTCP_GetLen (struct vfsfile_s *file) { return 0; } diff --git a/engine/common/netinc.h b/engine/common/netinc.h index 78576bbc8..9a39c89f0 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -127,18 +127,6 @@ #ifdef ENOTCONN #undef ENOTCONN #endif - - #define EWOULDBLOCK WSAEWOULDBLOCK - #define EINPROGRESS WSAEINPROGRESS - #define EMSGSIZE WSAEMSGSIZE - #define ECONNRESET WSAECONNRESET - #define ECONNABORTED WSAECONNABORTED - #define ECONNREFUSED WSAECONNREFUSED - #define ENOTCONN WSAENOTCONN - #define EACCES WSAEACCES - #define EADDRNOTAVAIL WSAEADDRNOTAVAIL - #define EAFNOSUPPORT WSAEAFNOSUPPORT - #else #include #include @@ -177,11 +165,37 @@ #endif #if defined(_WIN32) - #define qerrno WSAGetLastError() + #define neterrno() WSAGetLastError() + //this madness is because winsock defines its own errors instead of using system error codes. + //*AND* microsoft then went and defined names for all the unix ones too... with different values! oh the insanity of it all! + #define NET_EWOULDBLOCK WSAEWOULDBLOCK + #define NET_EINPROGRESS WSAEINPROGRESS + #define NET_EMSGSIZE WSAEMSGSIZE + #define NET_ECONNRESET WSAECONNRESET + #define NET_ECONNABORTED WSAECONNABORTED + #define NET_ECONNREFUSED WSAECONNREFUSED + #define NET_ENOTCONN WSAENOTCONN + #define NET_EACCES WSAEACCES + #define NET_EADDRNOTAVAIL WSAEADDRNOTAVAIL + #define NET_EAFNOSUPPORT WSAEAFNOSUPPORT #elif defined(__MORPHOS__) && !defined(ixemul) - #define qerrno Errno() + #define neterrno() Errno() #else - #define qerrno errno + #define neterrno() errno +#endif + +#ifndef NET_EWOULDBLOCK + //assume unix codes instead, so our prefix still works. + #define NET_EWOULDBLOCK EWOULDBLOCK + #define NET_EINPROGRESS EINPROGRESS + #define NET_EMSGSIZE EMSGSIZE + #define NET_ECONNRESET ECONNRESET + #define NET_ECONNABORTED ECONNABORTED + #define NET_ECONNREFUSED ECONNREFUSED + #define NET_ENOTCONN ENOTCONN + #define NET_EACCES EACCES + #define NET_EADDRNOTAVAIL EADDRNOTAVAIL + #define NET_EAFNOSUPPORT EAFNOSUPPORT #endif #ifndef INVALID_SOCKET @@ -254,12 +268,14 @@ extern icefuncs_t iceapi; #endif +#define ADDR_NATPMP (1u<<0) +#define ADDR_UPNPIGP (1u<<1) #define FTENET_ADDRTYPES 2 typedef struct ftenet_generic_connection_s { char name[MAX_QPATH]; - int (*GetLocalAddress)(struct ftenet_generic_connection_s *con, netadr_t *local, int adridx); + int (*GetLocalAddresses)(struct ftenet_generic_connection_s *con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses); qboolean (*ChangeLocalAddress)(struct ftenet_generic_connection_s *con, const char *newaddress); qboolean (*GetPacket)(struct ftenet_generic_connection_s *con); qboolean (*SendPacket)(struct ftenet_generic_connection_s *con, int length, void *data, netadr_t *to); @@ -292,3 +308,5 @@ void QDECL ICE_AddLCandidateInfo(struct icestate_s *con, netadr_t *adr, int adrn ftenet_connections_t *FTENET_CreateCollection(qboolean listen); void FTENET_CloseCollection(ftenet_connections_t *col); qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, qboolean islisten); +int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_generic_connection_s **con, int *adrflags, netadr_t *addresses, int maxaddresses); + diff --git a/engine/common/plugin.c b/engine/common/plugin.c index c7df92a70..29639ca76 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -278,7 +278,7 @@ plugin_t *Plug_Load(char *file, int type) return newplug; } -static int QDECL Plug_Emumerated (const char *name, int size, void *param, searchpathfuncs_t *spath) +static int QDECL Plug_Emumerated (const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) { char vmname[MAX_QPATH]; Q_strncpyz(vmname, name, sizeof(vmname)); @@ -288,7 +288,7 @@ static int QDECL Plug_Emumerated (const char *name, int size, void *param, searc return true; } -static int QDECL Plug_EnumeratedRoot (const char *name, int size, void *param, searchpathfuncs_t *spath) +static int QDECL Plug_EnumeratedRoot (const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) { char vmname[MAX_QPATH]; int len; @@ -1086,7 +1086,7 @@ qintptr_t VARGS Plug_Net_Recv(void *offset, quintptr_t mask, const qintptr_t *ar read = recv(pluginstreamarray[handle].socket, dest, destlen, 0); if (read < 0) { - if (qerrno == EWOULDBLOCK) + if (neterrno() == NET_EWOULDBLOCK) return -1; else return -2; @@ -1117,7 +1117,7 @@ qintptr_t VARGS Plug_Net_Send(void *offset, quintptr_t mask, const qintptr_t *ar written = send(pluginstreamarray[handle].socket, src, srclen, 0); if (written < 0) { - if (qerrno == EWOULDBLOCK) + if (neterrno() == NET_EWOULDBLOCK) return -1; else return -2; @@ -1162,7 +1162,7 @@ qintptr_t VARGS Plug_Net_SendTo(void *offset, quintptr_t mask, const qintptr_t * written = sendto(pluginstreamarray[handle].socket, src, srclen, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); if (written < 0) { - if (qerrno == EWOULDBLOCK) + if (neterrno() == NET_EWOULDBLOCK) return -1; else return -2; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 252cb8387..c668f8345 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1718,7 +1718,7 @@ void search_close_progs(pubprogfuncs_t *prinst, qboolean complain) prvm_nextsearchhandle = 0; //might as well. } -int QDECL search_enumerate(const char *name, int fsize, void *parm, searchpathfuncs_t *spath) +int QDECL search_enumerate(const char *name, qofs_t fsize, void *parm, searchpathfuncs_t *spath) { prvmsearch_t *s = parm; @@ -2314,7 +2314,12 @@ void QCBUILTIN PF_str2chr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa if (ofs && (ofs < 0 || ofs > strlen(instr))) G_FLOAT(OFS_RETURN) = '\0'; else - G_FLOAT(OFS_RETURN) = VMUTF8?unicode_decode(&err, instr+ofs, &next, VMUTF8MARKUP):(unsigned char)instr[ofs]; + { + if (VMUTF8) + G_FLOAT(OFS_RETURN) = unicode_decode(&err, instr+ofs, &next, VMUTF8MARKUP); + else + G_FLOAT(OFS_RETURN) = (unsigned char)instr[ofs]; + } } //FTE_STRINGS @@ -3581,6 +3586,13 @@ void QCBUILTIN PF_ArgV (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals RETURN_TSTRING(qctoken[idx].token); } +void QCBUILTIN PF_argescape(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + char temp[8192]; + char *str = PR_GetStringOfs(prinst, OFS_PARM0); + RETURN_TSTRING(COM_QuotedString(str, temp, sizeof(temp))); +} + //Console functions //////////////////////////////////////////////////// //Maths functions diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index cf072749c..cfe105f5c 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -184,6 +184,7 @@ void QCBUILTIN PF_entityfieldtype (pubprogfuncs_t *prinst, struct globalvars_s * void QCBUILTIN PF_getentityfieldstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_putentityfieldstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_checkcommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_argescape(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_getsurfacenumpoints(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -252,6 +253,9 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_ void skel_dodelete(pubprogfuncs_t *prinst); void skel_reset(pubprogfuncs_t *prinst); #endif +void QCBUILTIN PF_physics_enable(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_physics_addforce(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_physics_addtorque(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -484,10 +488,25 @@ pbool QDECL ED_CanFree (edict_t *ed); #define SOLID_CORPSE 5 // non-solid to solid_slidebox entities and itself. #define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER #define SOLID_PORTAL 21 //1: traces always use point-size. 2: various movetypes automatically transform entities. 3: traces that impact portal bbox use a union. 4. traces ignore part of the world within the portal's box -#define SOLID_PHYSICS_BOX 32 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) -#define SOLID_PHYSICS_SPHERE 33 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) -#define SOLID_PHYSICS_CAPSULE 34 ///< physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) -#define SOLID_PHYSICS_CYLINDER 35 +#define SOLID_PHYSICS_BOX 32 // deprecated. physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_SPHERE 33 // deprecated. physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_CAPSULE 34 // deprecated. physics object (mins, maxs, mass, origin, axis_forward, axis_left, axis_up, velocity, spinvelocity) +#define SOLID_PHYSICS_TRIMESH 35 +#define SOLID_PHYSICS_CYLINDER 36 + +#define GEOMTYPE_NONE -1 +#define GEOMTYPE_SOLID 0 +#define GEOMTYPE_BOX 1 +#define GEOMTYPE_SPHERE 2 +#define GEOMTYPE_CAPSULE 3 +#define GEOMTYPE_TRIMESH 4 +#define GEOMTYPE_CYLINDER 5 +#define GEOMTYPE_CAPSULE_X 6 +#define GEOMTYPE_CAPSULE_Y 7 +#define GEOMTYPE_CAPSULE_Z 8 +#define GEOMTYPE_CYLINDER_X 9 +#define GEOMTYPE_CYLINDER_Y 10 +#define GEOMTYPE_CYLINDER_Z 11 #define JOINTTYPE_POINT 1 @@ -549,6 +568,11 @@ typedef enum VF_VIEWENTITY = 206, VF_STATSENTITIY = 207, //the player number for the stats. VF_SCREENVOFFSET = 208, + + VF_RT_DESTCOLOUR = 209, + VF_RT_SOURCECOLOUR = 210, + VF_RT_DEPTH = 211, + VF_RT_RIPPLE = 212, /**/ } viewflags; /*FIXME: this should be changed*/ diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 7f689a2ca..9f5478f52 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -186,7 +186,7 @@ typedef struct { int bufferleft; int skip; } vmsearch_t; -static int QDECL VMEnum(const char *match, int size, void *args, searchpathfuncs_t *spath) +static int QDECL VMEnum(const char *match, qofs_t size, void *args, searchpathfuncs_t *spath) { char *check; int newlen; @@ -210,13 +210,13 @@ static int QDECL VMEnum(const char *match, int size, void *args, searchpathfuncs return true; } -static int QDECL IfFound(const char *match, int size, void *args, searchpathfuncs_t *spath) +static int QDECL IfFound(const char *match, qofs_t size, void *args, searchpathfuncs_t *spath) { *(qboolean*)args = true; return true; } -static int QDECL VMEnumMods(const char *match, int size, void *args, searchpathfuncs_t *spath) +static int QDECL VMEnumMods(const char *match, qofs_t size, void *args, searchpathfuncs_t *spath) { char *check; char desc[1024]; @@ -235,7 +235,7 @@ static int QDECL VMEnumMods(const char *match, int size, void *args, searchpathf return true; if (!stricmp(match, "baseq3/")) - return true; //we don't want baseq3 + return true; //we don't want baseq3. FIXME: should be any basedir, rather than hardcoded. foundone = false; Sys_EnumerateFiles(va("%s%s/", ((vmsearch_t *)args)->dir, match), "*.pk3", IfFound, &foundone, spath); diff --git a/engine/common/sys.h b/engine/common/sys.h index f3bed2e5b..1643bfcab 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -87,7 +87,7 @@ void Sys_ServerActivity(void); void Sys_SendKeyEvents (void); // Perform Key_Event () callbacks until the input que is empty -int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath); +int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath); void Sys_Vibrate(float count); diff --git a/engine/common/translate.c b/engine/common/translate.c index 7f8b2e65d..1ddaeda40 100644 --- a/engine/common/translate.c +++ b/engine/common/translate.c @@ -10,6 +10,7 @@ char sys_language[64] = ""; +struct language_s languages[MAX_LANGUAGES]; void TL_LanguageChanged(struct cvar_s *var, char *oldvalue) { diff --git a/engine/common/translate.h b/engine/common/translate.h index a1342cf6f..be32df93c 100644 --- a/engine/common/translate.h +++ b/engine/common/translate.h @@ -12,7 +12,8 @@ struct language_s { char *name; struct po_s *po; -} languages[MAX_LANGUAGES]; +}; +extern struct language_s languages[MAX_LANGUAGES]; #define langtext(t,l) PO_GetText(languages[l].po, t) int TL_FindLanguage(const char *lang); diff --git a/engine/common/unzip.c b/engine/common/unzip.c deleted file mode 100644 index a7937b511..000000000 --- a/engine/common/unzip.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* unzip.c -- IO on .zip files using zlib - Version 0.15 beta, Mar 19th, 1998, - - Read unzip.h for more info -*/ - -//Spike: ported to AMD64 -//Spike: FTE specific tweeks are in here starting with FTE's VFS filesystem stuff - -//# pragma comment (lib, "zip/zlib.lib") - - -#include -#include -#include -#include "zlib.h" -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - - - -#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ - !defined(CASESENSITIVITYDEFAULT_NO) -#define CASESENSITIVITYDEFAULT_NO -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (16384) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info_internal_s { - unsigned long offset_curfile;/* relative offset of local header 4 bytes */ -} unz_file_info_internal; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct { - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - - unsigned long pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - unsigned long stream_initialised; /* flag set if stream structure is initialised*/ - - unsigned long offset_local_extrafield;/* offset of the local extra field */ - unsigned int size_local_extrafield;/* size of the local extra field */ - unsigned long pos_local_extrafield; /* position in the local extra field in read*/ - - unsigned long crc32; /* crc32 of all data uncompressed */ - unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ - unsigned long rest_read_compressed; /* number of byte to be decompressed */ - unsigned long rest_read_uncompressed;/*number of byte to be obtained after decomp*/ - vfsfile_t* file; /* io structore of the zipfile */ - unsigned long compression_method; /* compression method (0==store) */ - unsigned long byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ -} file_in_zip_read_info_s; - - -/* unz_s contain internal information about the zipfile -*/ -typedef struct { - vfsfile_t* file; /* io structore of the zipfile */ - unz_global_info gi; /* public global information */ - unsigned long byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - unsigned long num_file; /* number of the current file in the zipfile*/ - unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ - unsigned long current_file_ok; /* flag about the usability of the current file*/ - unsigned long central_pos; /* position of the beginning of the central dir*/ - - unsigned long size_central_dir; /* size of the central directory */ - unsigned long offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info cur_file_info; /* public info about the current file in zip*/ - unz_file_info_internal cur_file_info_internal; /* private info about it*/ - file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ -} unz_s; - - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - -local int unzlocal_getShortSane(vfsfile_t *fin, unsigned short *pi) -{ - unsigned short c; - int err = VFS_READ(fin, &c, 2); - if (err==2) - { - *pi = LittleShort(c); - return UNZ_OK; - } - else - { - *pi = 0; - if (VFS_TELL(fin) != VFS_GETLEN(fin)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - -local int unzlocal_getShort(vfsfile_t *fin,unsigned long *pi) -{ - unsigned short c; - int err = VFS_READ(fin, &c, 2); - if (err==2) - { - *pi = LittleShort(c); - return UNZ_OK; - } - else - { - *pi = 0; - if (VFS_TELL(fin) != VFS_GETLEN(fin)) return UNZ_ERRNO; - else return UNZ_EOF; - } -} - -local int unzlocal_getLong(vfsfile_t *fin,unsigned long *pi) -{ - unsigned int c; - int err = VFS_READ(fin, &c, 4); - if (err==4) - { - *pi = LittleLong(c); - return UNZ_OK; - } - else - { - *pi = 0; - if (VFS_TELL(fin) != VFS_GETLEN(fin)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - - -#define BUFREADCOMMENT (0x400) - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local unsigned long unzlocal_SearchCentralDir(vfsfile_t *fin) { - unsigned char* buf; - unsigned long uSizeFile; - unsigned long uBackRead; - unsigned long uMaxBack=0xffff; /* maximum size of global comment */ - unsigned long uPosFound=0; - - uSizeFile = VFS_GETLEN(fin); - - if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (!buf) return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) uBackRead = uMaxBack; - else uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - - if (!VFS_SEEK(fin, uReadPos)) - break; - - if (VFS_READ(fin,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer - "zlib/zlib109.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile ZEXPORT unzOpen (vfsfile_t *fin) { - unz_s us = {0}; - unz_s *s; - unsigned long central_pos,uL; - - unsigned long number_disk = 0; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - unsigned long number_disk_with_CD = 0; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - unsigned long number_entry_CD = 0; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - - if (!fin) return NULL; - - central_pos = unzlocal_SearchCentralDir(fin); - if (!central_pos) err=UNZ_ERRNO; - - if (!VFS_SEEK(fin,central_pos)) err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(fin,&uL)!=UNZ_OK) err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read) unzCloseCurrentFile(file); - - VFS_CLOSE(s->file); - TRYFREE(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info) { - unz_s* s; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -local int unzlocal_GetCurrentFileInfoInternal (unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal *pfile_info_internal, - char *szFileName, unsigned long fileNameBufferSize, - void *extraField, unsigned long extraFieldBufferSize, - char *szComment, unsigned long commentBufferSize, - int *issymlink) { - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal = {0}; - int err=UNZ_OK; - unsigned long uMagic = 0; - long lSeek=0; - - if (issymlink) - *issymlink = 0; - - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!VFS_SEEK(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile)) err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) - { - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; - } - - unzlocal_getShortSane(s->file, &file_info.version); - unzlocal_getShortSane(s->file, &file_info.version_needed); - unzlocal_getShortSane(s->file, &file_info.flag); - unzlocal_getShortSane(s->file, &file_info.compression_method); - unzlocal_getLong(s->file, &file_info.dosDate); - unzlocal_getLong(s->file, &file_info.crc); - unzlocal_getLong(s->file, &file_info.compressed_size); - unzlocal_getLong(s->file, &file_info.uncompressed_size); - unzlocal_getShortSane(s->file, &file_info.size_filename); - unzlocal_getShortSane(s->file, &file_info.size_file_extra); - unzlocal_getShortSane(s->file, &file_info.size_file_comment); - unzlocal_getShortSane(s->file, &file_info.disk_num_start); - unzlocal_getShortSane(s->file, &file_info.internal_fa); - unzlocal_getLong(s->file, &file_info.external_fa); -/* - VFS_READ(s->file, &file_info, sizeof(file_info)-2*4); // 2*4 is the size of 2 my vars - file_info.version = LittleShort(file_info.version); - file_info.version_needed = LittleShort(file_info.version_needed); - file_info.flag = LittleShort(file_info.flag); - file_info.compression_method = LittleShort(file_info.compression_method); - file_info.dosDate = LittleLong(file_info.dosDate); - file_info.crc = LittleLong(file_info.crc); - file_info.compressed_size = LittleLong(file_info.compressed_size); - file_info.uncompressed_size = LittleLong(file_info.uncompressed_size); - file_info.size_filename = LittleShort(file_info.size_filename); - file_info.size_file_extra = LittleShort(file_info.size_file_extra); - file_info.size_file_comment = LittleShort(file_info.size_file_comment); - file_info.disk_num_start = LittleShort(file_info.disk_num_start); - file_info.internal_fa = LittleShort(file_info.internal_fa); - file_info.external_fa = LittleLong(file_info.external_fa); -*/ - if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; - - file_info.offset = file_info_internal.offset_curfile; - file_info.c_offset = s->pos_in_central_dir; - - lSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName)) - { - unsigned long uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (VFS_READ(s->file, szFileName,(unsigned int)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; - lSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField)) - { - unsigned long uSizeRead ; - if (file_info.size_file_extrafile, VFS_TELL(s->file)+lSeek)) lSeek=0; - else err=UNZ_ERRNO; - } - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (VFS_READ(s->file, extraField,(unsigned int)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; - lSeek += file_info.size_file_extra - uSizeRead; - } - else lSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment)) - { - unsigned long uSizeRead ; - if (file_info.size_file_commentfile, VFS_TELL(s->file)+lSeek)) lSeek=0; - else err=UNZ_ERRNO; - } - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (VFS_READ(s->file, szComment,(unsigned int)uSizeRead)!=uSizeRead) err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; - } else lSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info)) *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal)) *pfile_info_internal=file_info_internal; - - if (issymlink) - { - int madeby = file_info.version>>8; - //vms, unix, or beos file attributes includes a symlink attribute. - //symlinks mean the file contents is just the name of another file. - if (madeby == 2 || madeby == 3 || madeby == 16) - { - unsigned short unixattr = file_info.external_fa>>16; - if ((unixattr & 0xF000) == 0xA000)//fa&S_IFMT==S_IFLNK - *issymlink = 1; - else if ((unixattr & 0xA000) == 0xA000)//fa&S_IFMT==S_IFLNK - *issymlink = 1; - } - } - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, - unz_file_info *pfile_info, - char *szFileName, unsigned long fileNameBufferSize, - void *extraField, unsigned long extraFieldBufferSize, - char *szComment, unsigned long commentBufferSize) { - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize, - NULL); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int ZEXPORT unzGoToFirstFile (unzFile file) { - int err=UNZ_OK; - unz_s* s; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0,NULL); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int ZEXPORT unzGoToNextFile (unzFile file) { - unz_s* s; - int err; - - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; - if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0, NULL); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -extern int ZEXPORT unzLocateFileMy (unzFile file, unsigned long num, unsigned long pos) { - int islink; - unz_s* s; - s = (unz_s *)file; - s->pos_in_central_dir = pos; - s->num_file = num; - unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,&s->cur_file_info_internal,NULL,0,NULL,0,NULL,0,&islink); - return islink?2:1; -} - - -/* - Read the local header of the current zipfile - Check the coherency of the local header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in local header - (filename and size of extra field data) -*/ -local int unzlocal_CheckCurrentFileCoherencyHeader (unz_s *s, unsigned int *piSizeVar, - unsigned long *poffset_local_extrafield, - unsigned int *psize_local_extrafield) { - unsigned long uMagic = 0,uData = 0,uFlags = 0; - unsigned long size_filename = 0; - unsigned long size_extra_field = 0; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (!VFS_SEEK(s->file,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile)) return UNZ_ERRNO; - - - if (err==UNZ_OK) - { - if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; - - /* date/time */ - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; - - /* crc */ - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; - - /* size compr */ - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; - - /* size uncompr */ - if (unzlocal_getLong(s->file,&uData) != UNZ_OK) err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; - - *piSizeVar += (unsigned int)size_filename; - - if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (unsigned int)size_extra_field; - - *piSizeVar += (unsigned int)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int ZEXPORT unzOpenCurrentFile (unzFile file) { - int err=UNZ_OK; - int Store; - unsigned int iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - unsigned long offset_local_extrafield; /* offset of the local extra field */ - unsigned int size_local_extrafield; /* size of the local extra field */ - - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read) unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*)ALLOC(sizeof(file_in_zip_read_info_s)); - if (!pfile_in_zip_read_info) return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - - if (!pfile_in_zip_read_info->read_buffer) { - TRYFREE(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; - Store = s->cur_file_info.compression_method==0; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; - pfile_in_zip_read_info->file=s->file; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if (!Store) { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - - err=qinflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=1; - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (unsigned int)0; - - - s->pfile_in_zip_read = pfile_in_zip_read_info; - return UNZ_OK; -} - - - - -//dmw's addition -extern FILE* ZEXPORT unzOpenCurrentFileFile (unzFile file, char *zipwasnamed) -{ - FILE *F; -// int Store; - unsigned int iSizeVar; - unsigned int pos; - unz_s* s; -// file_in_zip_read_info_s* pfile_in_zip_read_info; - unsigned long offset_local_extrafield; /* offset of the local extra field */ - unsigned int size_local_extrafield; /* size of the local extra field */ - - if (!file) return NULL; - s=(unz_s*)file; - if (!s->current_file_ok) return NULL; - - if (s->pfile_in_zip_read) unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return NULL; - - - - if (s->cur_file_info.compression_method!=0) return NULL; - - //opens a file into the uncompressed steam. - pos = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; - - F = fopen (zipwasnamed, "rb"); - - if (!F) - Sys_Error ("Couldn't reopen %s", zipwasnamed); - fseek (F, pos, SEEK_SET); - return F; -} - -extern int ZEXPORT unzGetCurrentFileUncompressedPos (unzFile file) { -// int err=UNZ_OK; -// int Store; - unsigned int iSizeVar; - unsigned int pos; - unz_s* s; -// file_in_zip_read_info_s* pfile_in_zip_read_info; - unsigned long offset_local_extrafield; /* offset of the local extra field */ - unsigned int size_local_extrafield; /* size of the local extra field */ - - if (!file) return -1; - s=(unz_s*)file; - if (!s->current_file_ok) return -1; - - if (s->pfile_in_zip_read) unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return -1; - - - - if (s->cur_file_info.compression_method!=0) return -1; - - //opens a file into the uncompressed steam. - pos = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; - - return pos; -} - - - - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) { - int err=UNZ_OK; - unsigned int iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (!pfile_in_zip_read_info) return UNZ_PARAMERROR; - - - if ((!pfile_in_zip_read_info->read_buffer)) return UNZ_END_OF_LIST_OF_FILE; - if (!len) return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - - pfile_in_zip_read_info->stream.avail_out = (unsigned int)len; - - if (len>pfile_in_zip_read_info->rest_read_uncompressed) - pfile_in_zip_read_info->stream.avail_out = (unsigned int)pfile_in_zip_read_info->rest_read_uncompressed; - - while (pfile_in_zip_read_info->stream.avail_out>0) { - if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { - unsigned int uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (!uReadThis) return UNZ_EOF; - if (!VFS_SEEK(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile)) return UNZ_ERRNO; - if (VFS_READ(pfile_in_zip_read_info->file, pfile_in_zip_read_info->read_buffer,uReadThis)!=uReadThis) return UNZ_ERRNO; - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (unsigned int)uReadThis; - } - - if (pfile_in_zip_read_info->compression_method==0) { - unsigned int uDoCopy,i ; - if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = qcrc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } else { - unsigned long uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - unsigned long uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - err=qinflate(&pfile_in_zip_read_info->stream,flush); - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = qcrc32(pfile_in_zip_read_info->crc32,bufBefore, (unsigned int)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; - - iRead += (unsigned int)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) break; - } - } - - if (err==Z_OK) return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern z_off_t ZEXPORT unztell (unzFile file) { - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (!pfile_in_zip_read_info) return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int ZEXPORT unzeof (unzFile file) { - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (!pfile_in_zip_read_info) return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; - else return 0; -} - - - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int ZEXPORT unzGetLocalExtrafield (unzFile file,voidp buf,unsigned len) { - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - unsigned int read_now; - unsigned long size_to_read; - - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (!pfile_in_zip_read_info) return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); - - if (!buf) return (int)size_to_read; - - if (len>size_to_read) read_now = (unsigned int)size_to_read; - else read_now = (unsigned int)len ; - - if (!read_now) return 0; - - if (!VFS_SEEK(pfile_in_zip_read_info->file, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield)) return UNZ_ERRNO; - - if (VFS_READ(pfile_in_zip_read_info->file, buf,(unsigned int)size_to_read)!=size_to_read) return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int ZEXPORT unzCloseCurrentFile (unzFile file) { - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (!pfile_in_zip_read_info) return UNZ_PARAMERROR; - - - if (!pfile_in_zip_read_info->rest_read_uncompressed) { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; - } - - - TRYFREE(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) qinflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int ZEXPORT unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf) { -// int err=UNZ_OK; - unz_s* s; - unsigned long uReadThis ; - if (!file) return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; - - if (!VFS_SEEK(s->file,s->central_pos+22)) return UNZ_ERRNO; - - if (uReadThis>0) { - *szComment='\0'; - if (VFS_READ(s->file, szComment,(unsigned int)uReadThis)!=uReadThis) return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} diff --git a/engine/common/unzip.h b/engine/common/unzip.h deleted file mode 100644 index 510909e28..000000000 --- a/engine/common/unzip.h +++ /dev/null @@ -1,282 +0,0 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 0.15 beta, Mar 19th, 1998, - - Copyright (C) 1998 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Encryption and multi volume ZipFile (span) are not supported. - Old compressions used by old PKZip 1.x are not supported - - THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE - CAN CHANGE IN FUTURE VERSION !! - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -*/ - -//(2) This source has been modified to compile for AMD64 archetectures with gcc - -/* for more info about .ZIP format, see - ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip */ - -#ifndef _unz_H -#define _unz_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef voidp unzFile; -#endif - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -/* tm_unz contain date/time info */ -//typedef struct tm_unz_s -//{ -// uInt tm_sec; /* seconds after the minute - [0,59] */ -// uInt tm_min; /* minutes after the hour - [0,59] */ -// uInt tm_hour; /* hours since midnight - [0,23] */ -// uInt tm_mday; /* day of the month - [1,31] */ -// uInt tm_mon; /* months since January - [0,11] */ -// uInt tm_year; /* years - [1980..2044] */ -//} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info_s -{ - unsigned long number_entry; /* total number of entries in - the central dir on this disk */ - unsigned long size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - - -/* unz_file_info contain information about a file in the zipfile */ -#pragma pack(push, 1) -typedef struct unz_file_info_s -{ - unsigned short version; /* version made by 2 bytes */ - unsigned short version_needed; /* version needed to extract 2 bytes */ - unsigned short flag; /* general purpose bit flag 2 bytes */ - unsigned short compression_method; /* compression method 2 bytes */ - unsigned long dosDate; /* last mod file date in Dos fmt 4 bytes */ - unsigned long crc; /* crc-32 4 bytes */ - unsigned long compressed_size; /* compressed size 4 bytes */ - unsigned long uncompressed_size; /* uncompressed size 4 bytes */ - unsigned short size_filename; /* filename length 2 bytes */ - unsigned short size_file_extra; /* extra field length 2 bytes */ - unsigned short size_file_comment; /* file comment length 2 bytes */ - - unsigned short disk_num_start; /* disk number start 2 bytes */ - unsigned short internal_fa; /* internal file attributes 2 bytes */ - unsigned long external_fa; /* external file attributes 4 bytes */ - -// tm_unz tmu_date; - unsigned long offset, c_offset; -} unz_file_info; -#pragma pack(pop) -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - - -extern unzFile ZEXPORT unzOpen (vfsfile_t *fin); -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer - "zlib/zlib111.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ - -extern int ZEXPORT unzClose (unzFile file); -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int ZEXPORT unzGetGlobalInfo (unzFile file, - unz_global_info *pglobal_info); -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int ZEXPORT unzGetGlobalComment (unzFile file, - char *szComment, - unsigned long uSizeBuf); -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int ZEXPORT unzGoToFirstFile (unzFile file); -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int ZEXPORT unzGoToNextFile (unzFile file); -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int ZEXPORT unzLocateFile (unzFile file, - const char *szFileName, - int iCaseSensitivity); - -extern int ZEXPORT unzLocateFileMy (unzFile file, unsigned long num, unsigned long pos); -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, - unz_file_info *pfile_info, - char *szFileName, - unsigned long fileNameBufferSize, - void *extraField, - unsigned long extraFieldBufferSize, - char *szComment, - unsigned long commentBufferSize); -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - -/***************************************************************************/ -/* for reading the content of the current zipfile, you can open it, read data - from it, and close it (you can close it before reading all the file) - */ - -extern int ZEXPORT unzOpenCurrentFile (unzFile file); -/* - Open for reading data the current file in the zipfile. - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzCloseCurrentFile (unzFile file); -/* - Close the file in zip opened with unzOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ - - -extern int ZEXPORT unzReadCurrentFile (unzFile file, - voidp buf, - unsigned len); -/* - Read bytes from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ - -extern z_off_t ZEXPORT unztell (unzFile file); -/* - Give the current position in uncompressed data -*/ - -extern int ZEXPORT unzeof (unzFile file); -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -extern int ZEXPORT unzGetLocalExtrafield (unzFile file, - voidp buf, - unsigned len); -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _unz_H */ diff --git a/engine/common/vm.h b/engine/common/vm.h index 191b3a8ef..25ecce6ec 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -17,8 +17,12 @@ #if defined(_WIN64) #define qintptr_t __int64 #define FTE_WORDSIZE 64 + #define quintptr_t unsigned qintptr_t #elif defined(_WIN32) - #define qintptr_t __int32 + typedef __int32 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions + typedef unsigned __int32 quintptr_t; +// #define qintptr_t __int32 +// #define quintptr_t unsigned qintptr_t #define FTE_WORDSIZE 32 #else #if __WORDSIZE == 64 @@ -28,8 +32,8 @@ #define qintptr_t long #define FTE_WORDSIZE 32 #endif + #define quintptr_t unsigned qintptr_t #endif - #define quintptr_t unsigned qintptr_t #endif #ifndef FTE_WORDSIZE diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index ee9b4c93e..6aff31d4a 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -126,8 +126,8 @@ char *D3D_NameForResult(HRESULT hr) static void D3D11_PresentOrCrash(void) { - extern cvar_t _vid_wait_override; - HRESULT hr = IDXGISwapChain_Present(d3dswapchain, _vid_wait_override.ival, 0); + extern cvar_t vid_vsync; + HRESULT hr = IDXGISwapChain_Present(d3dswapchain, vid_vsync.ival, 0); if (FAILED(hr)) Sys_Error("IDXGISwapChain_Present: %s\n", D3D_NameForResult(hr)); } diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 2ed87e8e6..bf19dc662 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -665,6 +665,7 @@ AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include" PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;MULTITHREAD;BOTLIB_STATIC;USE_MSVCRT_DEBUG" BasicRuntimeChecks="3" + SmallerTypeCheck="true" RuntimeLibrary="1" EnableFunctionLevelLinking="true" EnableEnhancedInstructionSet="0" @@ -25093,2458 +25094,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index cd6e5c573..118a645fb 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -89,13 +89,11 @@ struct { texid_t tex_normals; texid_t tex_diffuse; int fbo_current; //the one currently being rendered to - int fbo_diffuse; - int rb_depth; - int rb_stencil; texid_t tex_sourcecol; /*this is used by $sourcecolour tgen*/ texid_t tex_sourcedepth; - int fbo_depthless; - int fbo_reflection; + fbostate_t fbo_2dfbo; + fbostate_t fbo_reflectrefrac; + fbostate_t fbo_lprepass; texid_t tex_reflection; /*basically a portal rendered to texture*/ texid_t tex_refraction; /*the (culled) underwater view*/ texid_t tex_refractiondepth; /*the (culled) underwater view*/ @@ -1501,6 +1499,11 @@ static float *tcgen(unsigned int tcgen, int cnt, float *dst, const mesh_t *mesh) dst[1] = DotProduct(tc_gen_t, src[i]); } return dst; + +// case TC_GEN_SKYBOX: +// case TC_GEN_WOBBLESKY: +// case TC_GEN_REFLECT: +// break; } } @@ -2348,14 +2351,14 @@ static void BE_GeneratePassTC(const shaderpass_t *pass, int tmu) if (!pass->numtcmods) { //if there are no tcmods, pass through here as fast as possible - if (pass->tcgen == TC_GEN_BASE) + switch(pass->tcgen) { + case TC_GEN_BASE: shaderstate.pendingtexcoordparts[tmu] = 2; shaderstate.pendingtexcoordvbo[tmu] = shaderstate.sourcevbo->texcoord.gl.vbo; shaderstate.pendingtexcoordpointer[tmu] = shaderstate.sourcevbo->texcoord.gl.addr; - } - else if (pass->tcgen == TC_GEN_LIGHTMAP) - { + break; + case TC_GEN_LIGHTMAP: if (!shaderstate.sourcevbo->lmcoord[0].gl.addr) { shaderstate.pendingtexcoordparts[tmu] = 2; @@ -2368,29 +2371,30 @@ static void BE_GeneratePassTC(const shaderpass_t *pass, int tmu) shaderstate.pendingtexcoordvbo[tmu] = shaderstate.sourcevbo->lmcoord[0].gl.vbo; shaderstate.pendingtexcoordpointer[tmu] = shaderstate.sourcevbo->lmcoord[0].gl.addr; } - } - else if (pass->tcgen == TC_GEN_NORMAL) - { + break; + case TC_GEN_NORMAL: shaderstate.pendingtexcoordparts[tmu] = 3; shaderstate.pendingtexcoordvbo[tmu] = shaderstate.sourcevbo->normals.gl.vbo; shaderstate.pendingtexcoordpointer[tmu] = shaderstate.sourcevbo->normals.gl.addr; - } - else if (pass->tcgen == TC_GEN_SVECTOR) - { + break; + case TC_GEN_SVECTOR: shaderstate.pendingtexcoordparts[tmu] = 3; shaderstate.pendingtexcoordvbo[tmu] = shaderstate.sourcevbo->svector.gl.vbo; shaderstate.pendingtexcoordpointer[tmu] = shaderstate.sourcevbo->svector.gl.addr; - } - else if (pass->tcgen == TC_GEN_TVECTOR) - { + break; + case TC_GEN_TVECTOR: shaderstate.pendingtexcoordparts[tmu] = 3; shaderstate.pendingtexcoordvbo[tmu] = shaderstate.sourcevbo->tvector.gl.vbo; shaderstate.pendingtexcoordpointer[tmu] = shaderstate.sourcevbo->tvector.gl.addr; - } - else - { + break; + // case TC_GEN_SKYBOX: + //position - viewpos +// case TC_GEN_WOBBLESKY: +// case TC_GEN_REFLECT: + default: //specular highlights and reflections have no fixed data, and must be generated. GenerateTCMods(pass, tmu); + break; } } else @@ -3775,6 +3779,7 @@ static void DrawMeshes(void) case BEM_WIREFRAME: //FIXME: do this with a shader instead? its not urgent as we can draw the shader normally anyway, just faster. + //FIXME: we need to use a shader for vertex blending. not really an issue with mdl, but more significant with iqms (base pose!). GL_DeSelectProgram(); shaderstate.pendingcolourvbo = 0; shaderstate.pendingcolourpointer = NULL; @@ -4210,6 +4215,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) if ((batch->shader->flags & (SHADER_HASREFLECT | SHADER_HASREFRACT | SHADER_HASRIPPLEMAP)) && shaderstate.mode != BEM_WIREFRAME) { + int oldfbo; float oldil; int oldbem; //these flags require rendering some view as an fbo @@ -4234,23 +4240,22 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - GL_ForceDepthWritable(); - GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_reflection, r_nulltex, true); + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, true, FBO_TEX_COLOUR|FBO_RB_DEPTH, shaderstate.tex_reflection, r_nulltex, vid.pixelwidth/2, vid.pixelheight/2); r_refdef.vrect.x = 0; r_refdef.vrect.y = 0; - r_refdef.vrect.width = vid.width/2; - r_refdef.vrect.height = vid.height/2; + r_refdef.vrect.width = vid.fbvwidth/2; + r_refdef.vrect.height = vid.fbvheight/2; r_refdef.pxrect.x = 0; r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = vid.pixelwidth/2; - r_refdef.pxrect.height = vid.pixelheight/2; - r_refdef.pxrect.maxheight = vid.pixelheight/2; + r_refdef.pxrect.width = vid.fbpwidth/2; + r_refdef.pxrect.height = vid.fbpheight/2; + r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac.rb_size[1]; GL_ViewportUpdate(); GL_ForceDepthWritable(); qglClearColor(0, 0, 0, 0); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, 1); - GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); + GLBE_FBO_Pop(oldfbo); r_refdef.vrect = orect; r_refdef.pxrect = oprect; GL_ViewportUpdate(); @@ -4261,7 +4266,6 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) { vrect_t ovrect = r_refdef.vrect; pxrect_t oprect = r_refdef.pxrect; - GL_ForceDepthWritable(); if (!shaderstate.tex_refraction.num) { @@ -4285,27 +4289,29 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_refraction, shaderstate.tex_refractiondepth, true); + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, true, FBO_TEX_COLOUR|FBO_TEX_DEPTH, shaderstate.tex_refraction, shaderstate.tex_refractiondepth, vid.pixelwidth/2, vid.pixelheight/2); } else - GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_refraction, r_nulltex, true); + { + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, true, FBO_TEX_COLOUR|FBO_RB_DEPTH, shaderstate.tex_refraction, r_nulltex, vid.pixelwidth/2, vid.pixelheight/2); + } r_refdef.vrect.x = 0; r_refdef.vrect.y = 0; - r_refdef.vrect.width = vid.width/2; - r_refdef.vrect.height = vid.height/2; + r_refdef.vrect.width = vid.fbvwidth/2; + r_refdef.vrect.height = vid.fbvheight/2; r_refdef.pxrect.x = 0; r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = vid.pixelwidth/2; - r_refdef.pxrect.height = vid.pixelheight/2; - r_refdef.pxrect.maxheight = vid.pixelheight/2; + r_refdef.pxrect.width = vid.fbpwidth/2; + r_refdef.pxrect.height = vid.fbpheight/2; + r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac.rb_size[1]; GL_ViewportUpdate(); GL_ForceDepthWritable(); qglClearColor(0, 0, 0, 0); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLR_DrawPortal(batch, cl.worldmodel->batches, NULL, ((batch->shader->flags & SHADER_HASREFRACTDEPTH)?3:2)); //fixme - GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); + GLBE_FBO_Pop(oldfbo); r_refdef.vrect = ovrect; r_refdef.pxrect = oprect; @@ -4323,22 +4329,22 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) //FIXME: can we use RGB8 instead? shaderstate.tex_ripplemap = GL_AllocNewTexture("***tex_ripplemap***", vid.pixelwidth/2, vid.pixelheight/2, 0); GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_ripplemap); - qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + qglTexImage2D(GL_TEXTURE_2D, 0, /*(gl_config.glversion>3.1)?GL_RGBA8_SNORM:*/GL_RGBA16F_ARB, vid.pixelwidth/2, vid.pixelheight/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - GLBE_RenderToTexture(r_nulltex, r_nulltex, shaderstate.tex_ripplemap, r_nulltex, false); + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_reflectrefrac, true, FBO_TEX_COLOUR, shaderstate.tex_ripplemap, r_nulltex, vid.pixelwidth/2, vid.pixelheight/2); r_refdef.vrect.x = 0; r_refdef.vrect.y = 0; - r_refdef.vrect.width = vid.width/2; - r_refdef.vrect.height = vid.height/2; + r_refdef.vrect.width = vid.fbvwidth/2; + r_refdef.vrect.height = vid.fbvheight/2; r_refdef.pxrect.x = 0; r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = vid.pixelwidth/2; - r_refdef.pxrect.height = vid.pixelheight/2; - r_refdef.pxrect.maxheight = vid.pixelheight/2; + r_refdef.pxrect.width = vid.fbpwidth/2; + r_refdef.pxrect.height = vid.fbpheight/2; + r_refdef.pxrect.maxheight = shaderstate.fbo_reflectrefrac.rb_size[1]; GL_ViewportUpdate(); qglClearColor(0, 0, 0, 0); @@ -4349,7 +4355,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) r_refdef.recurse+=1; //paranoid, should stop potential infinite loops GLBE_SubmitMeshes(true, SHADER_SORT_RIPPLE, SHADER_SORT_RIPPLE); r_refdef.recurse-=1; - GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); + GLBE_FBO_Pop(oldfbo); r_refdef.vrect = orect; r_refdef.pxrect = oprect; @@ -4462,6 +4468,179 @@ void GLBE_BaseEntTextures(void) } #endif +void GLBE_RenderToTextureUpdate2d(qboolean destchanged) +{ + unsigned int width, height; + if (destchanged) + { + if (r_refdef.rt_destcolour) + { + texid_t tex = R2D_RT_GetTexture(r_refdef.rt_destcolour, &width, &height); + GLBE_FBO_Update(&shaderstate.fbo_2dfbo, true, FBO_TEX_COLOUR, tex, r_nulltex, width, height); + } + else + GLBE_FBO_Push(NULL); + GL_Set2D(false); + } + else + { + shaderstate.tex_sourcecol = R2D_RT_GetTexture(r_refdef.rt_sourcecolour, &width, &height); + shaderstate.tex_sourcedepth = R2D_RT_GetTexture(r_refdef.rt_depth, &width, &height); + } +} +void GLBE_FBO_Sources(texid_t sourcecolour, texid_t sourcedepth) +{ + shaderstate.tex_sourcecol = sourcecolour; + shaderstate.tex_sourcedepth = sourcedepth; +} +int GLBE_FBO_Push(fbostate_t *state) +{ + int newfbo; + int oldfbo = shaderstate.fbo_current; + if (state) + newfbo = state->fbo; + else + newfbo = 0; + if (shaderstate.fbo_current == newfbo) //don't bother if its not changed (also avoids crashes when fbos are not supported) + return oldfbo; + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_current=newfbo); + return oldfbo; +} +void GLBE_FBO_Pop(int oldfbo) +{ + qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldfbo); + shaderstate.fbo_current = oldfbo; +} + +void GLBE_FBO_Destroy(fbostate_t *state) +{ + if (state->fbo == shaderstate.fbo_current) + GLBE_FBO_Push(NULL); + + //wasn't initialised anyway. + if (!state->fbo) + return; + + qglDeleteFramebuffersEXT(1, &state->fbo); + state->fbo = 0; + + if (state->rb_depth) + qglDeleteRenderbuffersEXT(1, &state->rb_depth); + state->rb_depth = 0; + if (state->rb_stencil) + qglDeleteRenderbuffersEXT(1, &state->rb_stencil); + state->rb_stencil = 0; + if (state->rb_depthstencil) + qglDeleteRenderbuffersEXT(1, &state->rb_depthstencil); + state->rb_depthstencil = 0; + + state->enables = 0; +} + +//state->colour is created if usedepth is set and it doesn't previously exist +int GLBE_FBO_Update(fbostate_t *state, qboolean bind, unsigned int enables, texid_t destcol, texid_t destdepth, int width, int height) +{ + int old; + + if (TEXVALID(destcol)) + { + enables |= FBO_TEX_COLOUR; + enables &= ~FBO_RB_COLOUR; + } + if (TEXVALID(destdepth)) + { + enables |= FBO_TEX_DEPTH; + enables &= ~FBO_RB_DEPTH; + } + + if ((state->enables ^ enables) & ~FBO_RESET) + { + GLBE_FBO_Destroy(state); + state->enables = enables & ~FBO_RESET; + enables |= FBO_RESET; + } + + if (!state->fbo) + { + qglGenFramebuffersEXT(1, &state->fbo); + old = GLBE_FBO_Push(state); + + enables |= FBO_RESET; + } + else + old = GLBE_FBO_Push(state); + + if (state->rb_size[0] != width || state->rb_size[1] != height || (enables & FBO_RESET)) + { + if (state->rb_depth && !(enables & FBO_RB_DEPTH)) + { + qglDeleteRenderbuffersEXT(1, &state->rb_depth); + state->rb_depth = 0; + } + if (state->rb_stencil && !(enables & FBO_RB_STENCIL)) + { + qglDeleteRenderbuffersEXT(1, &state->rb_stencil); + state->rb_stencil = 0; + } + state->rb_size[0] = width; + state->rb_size[1] = height; + + enables |= FBO_RESET; + + if (enables & (FBO_TEX_COLOUR|FBO_RB_COLOUR)) + { + qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + qglReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + } + else + { + qglDrawBuffer(GL_NONE); + qglReadBuffer(GL_NONE); + } + } + + if (enables & FBO_TEX_DEPTH) + { + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, destdepth.num, 0); + //fixme: no stencil + } + else if (enables & FBO_RB_DEPTH) + { + if (!state->rb_depth) + { + //create an unnamed depth buffer + qglGenRenderbuffersEXT(1, &state->rb_depth); + qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, state->rb_depth); + if (!gl_config.ext_packed_depth_stencil) + qglGenRenderbuffersEXT(1, &state->rb_stencil); + enables |= FBO_RESET; //make sure it gets instanciated + } + + if (enables & FBO_RESET) + { + qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, state->rb_depth); + if (gl_config.ext_packed_depth_stencil) + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, state->rb_size[0], state->rb_size[1]); + else + { + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, state->rb_size[0], state->rb_size[1]); + + qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, state->rb_stencil); + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, state->rb_size[0], state->rb_size[1]); + } + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, state->rb_depth); + if (gl_config.ext_packed_depth_stencil) + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, state->rb_depth); + else + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, state->rb_stencil); + } + } + + if (enables & FBO_TEX_COLOUR) + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, destcol.num, 0); + return old; +} +/* void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth) { shaderstate.tex_sourcecol = sourcecol; @@ -4485,16 +4664,12 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, shaderstate.rb_depth); if (gl_config.ext_packed_depth_stencil) { - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, vid.pixelwidth/2, vid.pixelheight/2); qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth); } else { - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth/2, vid.pixelheight/2); - qglGenRenderbuffersEXT(1, &shaderstate.rb_stencil); qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, shaderstate.rb_stencil); - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, vid.pixelwidth/2, vid.pixelheight/2); qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_stencil); } qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth); @@ -4507,9 +4682,38 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco shaderstate.fbo_current = shaderstate.fbo_diffuse; if (destdepth.num) + { qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, destdepth.num, 0); + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); + } else + { + //resize the depth renderbuffer if its the wrong size now + if (shaderstate.rb_depth_size[0] != r_refdef.fbo_width || shaderstate.rb_depth_size[1] != r_refdef.fbo_height) + { + shaderstate.rb_depth_size[0] = r_refdef.fbo_width; + shaderstate.rb_depth_size[1] = r_refdef.fbo_height; + + qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, shaderstate.rb_depth); + if (gl_config.ext_packed_depth_stencil) + { + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, r_refdef.fbo_width, r_refdef.fbo_height); + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth); + } + else + { + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, r_refdef.fbo_width, r_refdef.fbo_height); + + qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, shaderstate.rb_stencil); + qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, r_refdef.fbo_width, r_refdef.fbo_height); + } + } qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth); + if (gl_config.ext_packed_depth_stencil) + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth); + else + qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_stencil); + } } else { @@ -4530,9 +4734,18 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, destcol.num, 0); } } +*/ void GLBE_DrawLightPrePass(qbyte *vis) { + /* + walls(bumps) -> normalbuffer + lights+normalbuffer -> lightlevelbuffer + walls(diffuse)+lightlevelbuffer -> screen + + normalbuffer contains depth in the alpha channel. an actual depthbuffer is also generated at this time, which is used for depth test stuff but not as a shader input. + */ + int oldfbo; if (!shaderstate.initeddepthnorm) { shaderstate.initeddepthnorm = true; @@ -4579,8 +4792,6 @@ void GLBE_DrawLightPrePass(qbyte *vis) if (!TEXVALID(shaderstate.tex_diffuse)) { - int drb; - shaderstate.tex_diffuse = GL_AllocNewTexture("***prepass diffuse***", vid.pixelwidth, vid.pixelheight, 0); GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_diffuse); qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); @@ -4592,26 +4803,12 @@ void GLBE_DrawLightPrePass(qbyte *vis) r_lightprepass.modified = false; qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - - qglGenFramebuffersEXT(1, &shaderstate.fbo_diffuse); - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_diffuse); - - qglGenRenderbuffersEXT(1, &drb); - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, drb); - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth, vid.pixelheight); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, drb); - - - qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); -// qglReadBuffer(GL_NONE); } - else - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_diffuse); /*set the FB up to draw surface info*/ - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, shaderstate.tex_normals.num, 0); + oldfbo = GLBE_FBO_Update(&shaderstate.fbo_lprepass, true, FBO_TEX_COLOUR|FBO_RB_DEPTH, shaderstate.tex_normals, r_nulltex, vid.pixelwidth, vid.pixelheight); GL_ForceDepthWritable(); + //FIXME: should probably clear colour buffer too. qglClear(GL_DEPTH_BUFFER_BIT); if (GL_FRAMEBUFFER_COMPLETE_EXT != qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)) @@ -4624,8 +4821,8 @@ void GLBE_DrawLightPrePass(qbyte *vis) GLBE_SubmitMeshes(true, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE); /*reconfigure - now drawing diffuse light info using the previous fb image as a source image*/ - shaderstate.tex_sourcecol = shaderstate.tex_normals; - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, shaderstate.tex_diffuse.num, 0); + GLBE_FBO_Sources(shaderstate.tex_normals, r_nulltex); + GLBE_FBO_Update(&shaderstate.fbo_lprepass, true, FBO_TEX_COLOUR|FBO_RB_DEPTH, shaderstate.tex_diffuse, r_nulltex, vid.pixelwidth, vid.pixelheight); BE_SelectMode(BEM_STANDARD); qglClearColor (0,0,0,0); @@ -4636,8 +4833,8 @@ void GLBE_DrawLightPrePass(qbyte *vis) GLBE_SubmitMeshes(true, SHADER_SORT_PRELIGHT, SHADER_SORT_PRELIGHT); /*final reconfigure - now drawing final surface data onto true framebuffer*/ - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - shaderstate.tex_sourcecol = shaderstate.tex_diffuse; + GLBE_FBO_Pop(oldfbo); + GLBE_FBO_Sources(shaderstate.tex_diffuse, r_nulltex); qglDrawBuffer(GL_BACK); /*now draw the postlight passes (this includes blended stuff which will NOT be lit)*/ @@ -4650,9 +4847,7 @@ void GLBE_DrawLightPrePass(qbyte *vis) Sh_DrawLights(vis); #endif - shaderstate.tex_sourcecol = r_nulltex; - shaderstate.tex_sourcedepth = r_nulltex; - + GLBE_FBO_Sources(r_nulltex, r_nulltex); qglClearColor (1,0,0,1); } @@ -4670,7 +4865,6 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) if (!r_refdef.recurse) { - shaderstate.fbo_current = 0; //just in case something crashed GL_DoSwap(); if (shaderstate.wbatch + 50 > shaderstate.maxwbatches) { @@ -4684,6 +4878,10 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) } if (shaderstate.oldwidth != vid.pixelwidth || shaderstate.oldheight != vid.pixelheight) { + GLBE_FBO_Destroy(&shaderstate.fbo_2dfbo); + GLBE_FBO_Destroy(&shaderstate.fbo_reflectrefrac); + GLBE_FBO_Destroy(&shaderstate.fbo_lprepass); + if (shaderstate.tex_reflection.num) { R_DestroyTexture(shaderstate.tex_reflection); @@ -4704,17 +4902,6 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) R_DestroyTexture(shaderstate.temptexture); shaderstate.temptexture = r_nulltex; } - if (shaderstate.fbo_diffuse) - { - qglDeleteFramebuffersEXT(1, &shaderstate.fbo_diffuse); - shaderstate.fbo_diffuse = 0; - } - if (shaderstate.rb_depth) - qglDeleteRenderbuffersEXT(1, &shaderstate.rb_depth); - shaderstate.rb_depth = 0; - if (shaderstate.rb_stencil) - qglDeleteRenderbuffersEXT(1, &shaderstate.rb_stencil); - shaderstate.rb_stencil = 0; shaderstate.oldwidth = vid.pixelwidth; shaderstate.oldheight = vid.pixelheight; diff --git a/engine/gl/gl_bloom.c b/engine/gl/gl_bloom.c index 955456a65..33bc6756a 100644 --- a/engine/gl/gl_bloom.c +++ b/engine/gl/gl_bloom.c @@ -55,6 +55,7 @@ static shader_t *bloomfinal; #define MAXLEVELS 3 texid_t scrtex; texid_t pingtex[2][MAXLEVELS]; +fbostate_t fbo_bloom; static int scrwidth, scrheight; static int texwidth[MAXLEVELS], texheight[MAXLEVELS]; @@ -172,6 +173,7 @@ static void R_SetupBloomTextures(int w, int h) void R_BloomBlend (void) { int i; + int oldfbo = 0; if (!gl_config.ext_framebuffer_objects) return; @@ -198,14 +200,16 @@ void R_BloomBlend (void) if (i == 0) { /*filter the screen into a downscaled image*/ - GLBE_RenderToTexture(scrtex, r_nulltex, pingtex[0][0], r_nulltex, false); + oldfbo = GLBE_FBO_Update(&fbo_bloom, true, FBO_TEX_COLOUR, pingtex[0][0], r_nulltex, 0, 0); + GLBE_FBO_Sources(scrtex, r_nulltex); qglViewport (0, 0, texwidth[0], texheight[0]); R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomfilter); } else { /*simple downscale that multiple times*/ - GLBE_RenderToTexture(pingtex[0][i-1], r_nulltex, pingtex[0][i], r_nulltex, false); + GLBE_FBO_Update(&fbo_bloom, true, FBO_TEX_COLOUR, pingtex[0][i], r_nulltex, 0, 0); + GLBE_FBO_Sources(pingtex[0][i-1], r_nulltex); qglViewport (0, 0, texwidth[i], texheight[i]); R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomrescale); } @@ -218,13 +222,15 @@ void R_BloomBlend (void) */ r_worldentity.glowmod[0] = 1.2 / texwidth[i]; r_worldentity.glowmod[1] = 0; - GLBE_RenderToTexture(pingtex[0][i], r_nulltex, pingtex[1][i], r_nulltex, false); + GLBE_FBO_Update(&fbo_bloom, true, FBO_TEX_COLOUR, pingtex[1][i], r_nulltex, 0, 0); + GLBE_FBO_Sources(pingtex[0][i], r_nulltex); qglViewport (0, 0, texwidth[i], texheight[i]); R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomblur); r_worldentity.glowmod[0] = 0; r_worldentity.glowmod[1] = 1.2 / texheight[i]; - GLBE_RenderToTexture(pingtex[1][i], r_nulltex, pingtex[0][i], r_nulltex, false); + GLBE_FBO_Update(&fbo_bloom, true, FBO_TEX_COLOUR, pingtex[0][i], r_nulltex, 0, 0); + GLBE_FBO_Sources(pingtex[1][i], r_nulltex); qglViewport (0, 0, texwidth[i], texheight[i]); R2D_ScalePic(0, vid.height, vid.width, -(int)vid.height, bloomblur); } @@ -234,7 +240,8 @@ void R_BloomBlend (void) GL_Set2D(false); /*combine them onto the screen*/ - GLBE_RenderToTexture(scrtex, r_nulltex, r_nulltex, r_nulltex, false); + GLBE_FBO_Pop(oldfbo); + GLBE_FBO_Sources(scrtex, r_nulltex); R2D_ScalePic(r_refdef.vrect.x, r_refdef.vrect.y + r_refdef.vrect.height, r_refdef.vrect.width, -r_refdef.vrect.height, bloomfinal); } void R_InitBloomTextures(void) diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 71eba397f..e1a98f903 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -37,6 +37,7 @@ static void GL_Upload32_BGRA (char *name, unsigned *data, int width, int height, static void GL_Upload24BGR_Flip (char *name, qbyte *framedata, int inwidth, int inheight, unsigned int flags); static void GL_Upload8 (char *name, qbyte *data, int width, int height, unsigned int flags, unsigned int alpha); static void GL_Upload8Pal32 (qbyte *data, qbyte *pal, int width, int height, unsigned int flags); +static void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigned int flags, GLenum glcolormode); void GL_UploadFmt(texid_t tex, char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags) { @@ -81,6 +82,23 @@ void GL_UploadFmt(texid_t tex, char *name, enum uploadfmt fmt, void *data, void GL_Upload8Pal32(data, palette, width, height, flags); break; + //render target formats, data is not supported. this means we can just use the 32bit upload. + case TF_DEPTH16: + GL_Upload32_Int(name, NULL, width, height, flags|IF_NOMIPMAP, GL_DEPTH_COMPONENT16_ARB); + break; + case TF_DEPTH24: + GL_Upload32_Int(name, NULL, width, height, flags|IF_NOMIPMAP, GL_DEPTH_COMPONENT24_ARB); + break; + case TF_DEPTH32: + GL_Upload32_Int(name, NULL, width, height, flags|IF_NOMIPMAP, GL_DEPTH_COMPONENT32_ARB); + break; + case TF_RGBA16F: + GL_Upload32_Int(name, NULL, width, height, flags|IF_NOMIPMAP, GL_RGBA16F_ARB); + break; + case TF_RGBA32F: + GL_Upload32_Int(name, NULL, width, height, flags|IF_NOMIPMAP, GL_RGBA32F_ARB); + break; + default: Sys_Error("Unsupported image format type\n"); break; @@ -569,10 +587,25 @@ void GL_Set2D (qboolean flipped) float rad, ang; float tmp[16], tmp2[16]; float w = vid.width, h = vid.height; + qboolean fbo = !!r_refdef.rt_destcolour; + + if (fbo) + { + R2D_RT_GetTexture(r_refdef.rt_destcolour, &vid.fbpwidth, &vid.fbpheight); + vid.fbvwidth = vid.fbpwidth; + vid.fbvheight = vid.fbpheight; + } + else + { + vid.fbvwidth = vid.width; + vid.fbvheight = vid.height; + vid.fbpwidth = vid.pixelwidth; + vid.fbpheight = vid.pixelheight; + } ang = (gl_screenangle.value>0?(gl_screenangle.value+45):(gl_screenangle.value-45))/90; ang = (int)ang * 90; - if (ang) + if (ang && !fbo) { /*more expensive maths*/ rad = (ang * M_PI) / 180; @@ -587,17 +620,20 @@ void GL_Set2D (qboolean flipped) } else { + w = vid.fbvwidth; + h = vid.fbvheight; if (flipped) - Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, 0, vid.height, -99999, 99999); + Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, w, 0, h, -99999, 99999); else - Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, vid.width, vid.height, 0, -99999, 99999); + Matrix4x4_CM_Orthographic(r_refdef.m_projection, 0, w, h, 0, -99999, 99999); Matrix4x4_Identity(r_refdef.m_view); } + //current physical position on the current render target. r_refdef.pxrect.x = 0; r_refdef.pxrect.y = 0; - r_refdef.pxrect.width = vid.pixelwidth; - r_refdef.pxrect.height = vid.pixelheight; - r_refdef.pxrect.maxheight = vid.pixelheight; + r_refdef.pxrect.width = vid.fbpwidth; + r_refdef.pxrect.height = vid.fbpheight; + r_refdef.pxrect.maxheight = vid.fbpheight; r_refdef.time = realtime; /*flush that gl state*/ GL_ViewportUpdate(); @@ -1137,7 +1173,7 @@ void GL_8888to4444(int targ, unsigned char *in, unsigned short *out, unsigned in GL_Upload32 =============== */ -void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigned int flags, GLenum glcolormode) +static void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigned int flags, GLenum glcolormode) { int miplevel=0; int samples; @@ -1150,18 +1186,21 @@ void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigne scaled_width = width; scaled_height = height; - GL_RoundDimensions(&scaled_width, &scaled_height, flags); + if (data) + { + GL_RoundDimensions(&scaled_width, &scaled_height, flags); - if (!(flags & IF_NOALPHA)) - { //make sure it does actually have those alpha pixels (q3 compat) - int i; - flags |= IF_NOALPHA; - for (i = 3; i < width*height*4; i+=4) - { - if (((unsigned char*)data)[i] < 255) + if (!(flags & IF_NOALPHA)) + { //make sure it does actually have those alpha pixels (q3 compat) + int i; + flags |= IF_NOALPHA; + for (i = 3; i < width*height*4; i+=4) { - flags &= ~IF_NOALPHA; - break; + if (((unsigned char*)data)[i] < 255) + { + flags &= ~IF_NOALPHA; + break; + } } } } @@ -1182,14 +1221,25 @@ void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigne TRACE(("dbg: GL_Upload32: %i %i\n", scaled_width, scaled_height)); - if (scaled_width * scaled_height*4 > sizeofuploadmemorybuffer) + if (!data) + scaled = NULL; + else { - sizeofuploadmemorybuffer = scaled_width * scaled_height * 4; - uploadmemorybuffer = BZ_Realloc(uploadmemorybuffer, sizeofuploadmemorybuffer); + if (scaled_width * scaled_height*4 > sizeofuploadmemorybuffer) + { + sizeofuploadmemorybuffer = scaled_width * scaled_height * 4; + uploadmemorybuffer = BZ_Realloc(uploadmemorybuffer, sizeofuploadmemorybuffer); + } + scaled = (unsigned *)uploadmemorybuffer; } - scaled = (unsigned *)uploadmemorybuffer; - if (gl_config.gles) + if (glcolormode == GL_DEPTH_COMPONENT || glcolormode == GL_DEPTH_COMPONENT16_ARB || glcolormode == GL_DEPTH_COMPONENT24_ARB || glcolormode == GL_DEPTH_COMPONENT32_ARB) + { + samples = glcolormode; + glcolormode = GL_DEPTH_COMPONENT; + type = GL_UNSIGNED_BYTE; + } + else if (gl_config.gles) { glcolormode = GL_RGBA; /*our input is RGBA or RGBX, with the internal format restriction, we must therefore always have an alpha value*/ type = GL_UNSIGNED_BYTE; @@ -1266,7 +1316,9 @@ void GL_Upload32_Int (char *name, unsigned *data, int width, int height, unsigne GL_Texturemode_Apply(targ, flags); - if (scaled_width == width && scaled_height == height) + if (!data) + qglTexImage2D (targface, 0, samples, scaled_width, scaled_height, 0, glcolormode, GL_UNSIGNED_BYTE, data); + else if (scaled_width == width && scaled_height == height) { if ((flags&IF_NOMIPMAP)||gl_config.sgis_generate_mipmap) //gotta love this with NPOT textures... :) { diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 8e41f491d..7b449aebf 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -218,6 +218,7 @@ typedef struct font_s ftfontface_t *face[MAX_FTFACES]; #endif struct font_s *alt; + vec3_t tint; vec3_t alttint; } font_t; @@ -1058,7 +1059,18 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename) int i = 0; int defaultplane; char *aname; + char *parms; int height = (vheight * vid.rotpixelheight)/vid.height; + char facename[MAX_QPATH]; + + Q_strncpy(facename, fontfilename, sizeof(facename)); + + aname = strstr(facename, ":"); + if (aname) + *aname++ = 0; + parms = strstr(facename, "?"); + if (parms) + *parms++ = 0; f = Z_Malloc(sizeof(*f)); f->charheight = height; @@ -1073,6 +1085,35 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename) VectorSet(f->alttint, 1.16, 0.54, 0.41); break; } + VectorSet(f->tint, 1, 1, 1); + fontfilename = facename; + + if (parms) + { + while (*parms) + { + if (!strncmp(parms, "col=", 4)) + { + char *t = parms+4; + f->tint[0] = strtod(t, &t); + if (*t == ',') t++; + if (*t == ' ') t++; + f->tint[1] = strtod(t, &t); + if (*t == ',') t++; + if (*t == ' ') t++; + f->tint[2] = strtod(t, &t); + parms = t; + + } + while(*parms && *parms != '&') + parms++; + if (*parms == '&') + { + parms++; + continue; + } + } + } #ifdef DOOMWADS if (!*fontfilename) @@ -1195,21 +1236,28 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename) return f; } - aname = strstr(fontfilename, ":"); if (aname) { - *aname = 0; - if (!strncmp(aname+1, "?col=", 5)) + if (!strncmp(aname, "?col=", 5)) { - char *t = aname+6; + char *t = aname+5; f->alttint[0] = strtod(t, &t); + if (*t == ',') t++; if (*t == ' ') t++; f->alttint[1] = strtod(t, &t); + if (*t == ',') t++; if (*t == ' ') t++; f->alttint[2] = strtod(t, &t); } else - f->alt = Font_LoadFont(vheight, aname+1); + { + f->alt = Font_LoadFont(vheight, aname); + if (f->alt) + { + VectorCopy(f->alt->tint, f->alttint); + VectorCopy(f->alt->tint, f->alt->alttint); + } + } } { @@ -1258,8 +1306,6 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename) f->chars[i].texplane = BITMAPPLANE; } } - if (aname) - *aname = ':'; defaultplane = BITMAPPLANE;/*assume the bitmap plane - don't use the fallback as people don't think to use com_parseutf8*/ if (!TEXVALID(f->singletexture)) @@ -1359,6 +1405,7 @@ void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py) curfont_scale[0] = curfont->charheight; curfont_scale[1] = curfont->charheight; curfont_scaled = false; + font_colourmask = ~0u; //force the colour to be recalculated. } void Font_Transform(float vx, float vy, int *px, int *py) { @@ -1385,6 +1432,7 @@ void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, curfont_scale[0] = (szx * (float)vid.rotpixelheight) / (curfont->charheight * (float)vid.height); curfont_scale[1] = (szy * (float)vid.rotpixelheight) / (curfont->charheight * (float)vid.height); + font_colourmask = ~0u; //force the colour to be recalculated. } void Font_EndString(struct font_s *font) @@ -1601,7 +1649,7 @@ int Font_DrawChar(int px, int py, unsigned int charcode) if (font->alt) { font = font->alt; - charcode &= ~CON_2NDCHARSETTEXT; +// charcode &= ~CON_2NDCHARSETTEXT; } else if ((charcode&CON_CHARMASK) >= 0xe000 && (charcode&CON_CHARMASK) <= 0xe0ff) charcode &= ~CON_2NDCHARSETTEXT; //don't double-dip @@ -1680,6 +1728,12 @@ int Font_DrawChar(int px, int py, unsigned int charcode) font_forecolour[1] = min(font_forecolour[1]*font->alttint[1], 255); font_forecolour[2] = min(font_forecolour[2]*font->alttint[2], 255); } + else + { + font_forecolour[0] = min(font_forecolour[0]*font->tint[0], 255); + font_forecolour[1] = min(font_forecolour[1]*font->tint[1], 255); + font_forecolour[2] = min(font_forecolour[2]*font->tint[2], 255); + } } } @@ -1856,6 +1910,12 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) font_forecolour[1] = min(font_forecolour[1]*font->alttint[1], 255); font_forecolour[2] = min(font_forecolour[2]*font->alttint[2], 255); } + else + { + font_forecolour[0] = min(font_forecolour[0]*font->tint[0], 255); + font_forecolour[1] = min(font_forecolour[1]*font->tint[1], 255); + font_forecolour[2] = min(font_forecolour[2]*font->tint[2], 255); + } } } diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 760a42439..00143f86b 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -163,7 +163,7 @@ struct hmwater_s { struct hmwater_s *next; unsigned int contentmask; - qboolean simple; + qboolean simple; //no holes, one height float minheight; float maxheight; shader_t *shader; @@ -555,6 +555,7 @@ static void *Terr_GenerateWater(hmsection_t *s, float maxheight) w->shader = R_RegisterCustom (s->hmmod->watershadername, SUF_NONE, Shader_DefaultWaterShader, NULL); #endif w->simple = true; + w->contentmask = FTECONTENTS_WATER; memset(w->holes, 0, sizeof(w->holes)); for (i = 0; i < 9*9; i++) w->heights[i] = maxheight; @@ -754,7 +755,7 @@ static void Terr_TrimWater(hmsection_t *s) int i; struct hmwater_s *w, **link; - for (link = &s->water; (w = *link); link = &(*link)->next) + for (link = &s->water; (w = *link); ) { //one has a height above the terrain? for (i = 0; i < 9*9; i++) @@ -766,6 +767,8 @@ static void Terr_TrimWater(hmsection_t *s) Z_Free(w); continue; } + else + link = &(*link)->next; } } static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int sy) @@ -831,7 +834,7 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i for (j = 0, w = s->water; w; j++) w = w->next; Terr_Write_SInt(&strm, j); - for (i = 0; i < j; i++) + for (i = 0, w = s->water; i < j; i++, w = w->next) { char *shadername = w->shader->name; int fl = 0; @@ -917,9 +920,6 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i for (i = 0; i < s->numents; i++) { unsigned int mf; - mf = 0; - if (s->ents[i].scale != 1) - mf |= TMF_SCALE; //make sure we don't overflow. we should always be aligned at this point. if (strm.pos > strm.maxsize/2) @@ -928,6 +928,10 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i strm.pos = 0; } + mf = 0; + if (s->ents[i].scale != 1) + mf |= TMF_SCALE; + Terr_Write_SInt(&strm, mf); if (s->ents[i].model) Terr_Write_String(&strm, s->ents[i].model->name); else @@ -996,6 +1000,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) int fl = Terr_Read_SInt(&strm); w->next = s->water; s->water = w; + w->simple = true; w->contentmask = Terr_Read_SInt(&strm); if (fl & 1) Terr_Read_String(&strm, shadername, sizeof(shadername)); @@ -1009,6 +1014,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) { for (x = 0; x < 8; x++) w->holes[i] = Terr_Read_Byte(&strm); + w->simple = false; } if (fl & 4) { @@ -1016,6 +1022,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) { w->heights[x] = Terr_Read_Float(&strm); } + w->simple = false; } else { //all heights the same can be used as a way to compress the data @@ -1071,7 +1078,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) for (x = 0; x < SECTTEXSIZE; x++) { delta = Terr_Read_Byte(&strm); - last += delta; + last = (last+delta)&0xff; lm[x*4+j] = last; } lm += (HMLMSTRIDE)*lightmap_bytes; @@ -1146,6 +1153,9 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) return ptr; } +//#include "gl_adt.inc" +//#include "gl_m2.inc" + static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) { int i; @@ -1195,7 +1205,7 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) #if 0//def DEBUG void *f; - if (lightmap_bytes == 4 && lightmap_bgra && FS_LoadFile(va("maps/%s/splatt.png", hm->path), &f) >= 0) + if (lightmap_bytes == 4 && lightmap_bgra && FS_LoadFile(va("maps/%s/splatt.png", hm->path), &f) != (qofs_t)-1) { //temp int vx, vy; @@ -1239,7 +1249,7 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) FS_FreeFile(f); } - if (lightmap_bytes == 4 && lightmap_bgra && FS_LoadFile(va("maps/%s/heightmap.png", hm->path), &f) >= 0) + if (lightmap_bytes == 4 && lightmap_bgra && !qofs_Error(FS_LoadFile(va("maps/%s/heightmap.png", hm->path), &f))) { //temp int vx, vy; @@ -1278,7 +1288,6 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s) } #endif } - static hmsection_t *Terr_ReadSection(heightmap_t *hm, int ver, int sx, int sy, void *filebase, unsigned int filelen) { void *ptr = filebase; @@ -1322,7 +1331,7 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, int ver, int sx, int sy, v #ifndef SERVERONLY qboolean Terr_DownloadedSection(char *fname) { - int len; + qofs_t len; dsection_t *fileptr; int x, y; heightmap_t *hm; @@ -1336,9 +1345,9 @@ qboolean Terr_DownloadedSection(char *fname) if (Terr_IsSectionFName(hm, fname, &x, &y)) { fileptr = NULL; - len = FS_LoadFile(fname, &fileptr); + len = FS_LoadFile(fname, (void**)&fileptr); - if (len >= sizeof(*fileptr) && fileptr->magic == SECTION_MAGIC) + if (!qofs_Error(len) && len >= sizeof(*fileptr) && fileptr->magic == SECTION_MAGIC) Terr_ReadSection(hm, ver, x, y, fileptr+1, len - sizeof(*fileptr)); else Terr_ReadSection(hm, ver, x, y, NULL, 0); @@ -1355,7 +1364,7 @@ qboolean Terr_DownloadedSection(char *fname) static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, unsigned int flags) { void *diskimage; - int len; + qofs_t len; int ver = 0; #ifndef SERVERONLY //when using networked terrain, the client will never load a section from disk, but will only load it from the server @@ -1373,7 +1382,7 @@ static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, un #if SECTIONSPERBLOCK > 1 len = FS_LoadFile(Terr_DiskBlockName(hm, sx, sy), (void**)&diskimage); - if (len >= 0) + if (!qofs_Error(len)) { int offset; int x, y; @@ -1416,7 +1425,7 @@ static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, un //legacy one-section-per-file format. len = FS_LoadFile(Terr_DiskSectionName(hm, sx, sy), (void**)&diskimage); - if (len >= 0) + if (!qofs_Error(len)) { dsection_t *h = diskimage; if (len >= sizeof(*h) && h->magic == SECTION_MAGIC) @@ -1439,7 +1448,7 @@ static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, un //download it if it couldn't be loaded. #ifndef SERVERONLY - if (!cl.downloadlist) + if (!cl.downloadlist && !(flags & TGS_NODOWNLOAD)) CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, sx, sy), NULL, 0); #endif } @@ -2013,7 +2022,7 @@ void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmw { cl_strisvertv[cl_numstrisvert][0] = mins[0] + step*x; cl_strisvertv[cl_numstrisvert][1] = mins[1] + step*y; - cl_strisvertv[cl_numstrisvert][2] = w->heights[x + y*8]; + cl_strisvertv[cl_numstrisvert][2] = w->heights[x + y*9]; cl_strisvertt[cl_numstrisvert][0] = cl_strisvertv[cl_numstrisvert][0]/64; cl_strisvertt[cl_numstrisvert][1] = cl_strisvertv[cl_numstrisvert][1]/64; Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1) @@ -2116,6 +2125,7 @@ static void Terr_RebuildMesh(model_t *model, hmsection_t *s, int x, int y) switch(hm->mode) { case HMM_BLOCKS: + //tiles, like dungeon keeper if (mesh->xyz_array) BZ_Free(mesh->xyz_array); { @@ -2314,6 +2324,7 @@ static void Terr_RebuildMesh(model_t *model, hmsection_t *s, int x, int y) } break; case HMM_TERRAIN: + //smooth terrain if (!mesh->xyz_array) { mesh->xyz_array = BZ_Malloc((sizeof(vecV_t)+sizeof(vec2_t)+sizeof(vec2_t)) * (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); @@ -3452,19 +3463,37 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec return trace->fraction < 1; } +typedef struct +{ + int id; + int x, y; +} hmpvs_t; unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int pvssize, qboolean add) { - return 0; + //embed the org onto the pvs + hmpvs_t *hmpvs = (hmpvs_t*)pvsbuffer; + hmpvs->id = 0xdeadbeef; + hmpvs->x = org[0]; + hmpvs->y = org[1]; + return sizeof(*hmpvs); } #ifndef CLIENTONLY qboolean Heightmap_EdictInFatPVS (model_t *mod, struct pvscache_s *edict, qbyte *pvsdata) { - return true; + int x,y; + hmpvs_t *hmpvs = (hmpvs_t*)pvsdata; + //check distance + x = edict->areanum - hmpvs->x; + y = edict->areanum2 - hmpvs->y; + + return (x*x+y*y) < 4096*4096; } void Heightmap_FindTouchedLeafs (model_t *mod, pvscache_t *ent, float *mins, float *maxs) { + ent->areanum = (mins[0] + maxs[0]) * 0.5; + ent->areanum2 = (mins[1] + maxs[1]) * 0.5; } #endif diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 9437f70ea..bdafa8e87 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -4816,7 +4816,7 @@ typedef struct { short xpos; short ypos; } doomimage_t; -static int QDECL FindDoomSprites(const char *name, int size, void *param, searchpathfuncs_t *spath) +static int QDECL FindDoomSprites(const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) { if (*(int *)param + strlen(name)+1 > 16000) Sys_Error("Too many doom sprites\n"); diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index cc1ff1509..cf1f23dba 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -37,17 +37,11 @@ extern int gl_stencilbits; FTEPFNGLCOMPRESSEDTEXIMAGE2DARBPROC qglCompressedTexImage2DARB; FTEPFNGLGETCOMPRESSEDTEXIMAGEARBPROC qglGetCompressedTexImageARB; -vec3_t modelorg, r_entorigin; - extern int r_visframecount; // bumped when going to a new PVS extern int r_framecount; // used for dlight push checking -float r_wateralphaval; //allowed or not... - //mplane_t frustum[4]; -int c_brush_polys, c_alias_polys; - // // view origin // @@ -100,6 +94,8 @@ texid_t scenepp_texture_edge; texid_t scenepp_postproc_cube; int scenepp_postproc_cube_size; +fbostate_t fbo_gameview; + // KrimZon - init post processing - called in GL_CheckExtensions, when they're called // I put it here so that only this file need be changed when messing with the post // processing shaders @@ -381,40 +377,60 @@ void R_SetupGL (float stereooffset) // // set up viewpoint // - x = r_refdef.vrect.x * (int)vid.pixelwidth/(int)vid.width; - x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.pixelwidth/(int)vid.width; - y = (r_refdef.vrect.y) * (int)vid.pixelheight/(int)vid.height; - y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.pixelheight/(int)vid.height; + if (r_refdef.rt_destcolour) + { + //with fbo rendering, we disable all virtual scaling. + x = r_refdef.vrect.x; + x2 = r_refdef.vrect.x + r_refdef.vrect.width; + y = r_refdef.vrect.y; + y2 = r_refdef.vrect.y + r_refdef.vrect.height; - // fudge around because of frac screen scale - if (x > 0) - x--; - if (x2 < vid.pixelwidth) - x2++; - if (y2 < vid.pixelheight) - y2++; - if (y > 0) - y--; + w = x2 - x; + h = y2 - y; - w = x2 - x; - h = y2 - y; + r_refdef.pxrect.x = x; + r_refdef.pxrect.y = y; + r_refdef.pxrect.width = w; + r_refdef.pxrect.height = h; + r_refdef.pxrect.maxheight = vid.fbpheight; + } + else + { + x = r_refdef.vrect.x * (int)vid.pixelwidth/(int)vid.width; + x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * (int)vid.pixelwidth/(int)vid.width; + y = (r_refdef.vrect.y) * (int)vid.pixelheight/(int)vid.height; + y2 = (r_refdef.vrect.y + r_refdef.vrect.height) * (int)vid.pixelheight/(int)vid.height; + + // fudge around because of frac screen scale + if (x > 0) + x--; + if (x2 < vid.pixelwidth) + x2++; + if (y2 < vid.pixelheight) + y2++; + if (y > 0) + y--; + + w = x2 - x; + h = y2 - y; + + if (stereooffset && r_stereo_method.ival == 5) + { + w /= 2; + if (stereooffset > 0) + x += vid.pixelwidth/2; + } + + r_refdef.pxrect.x = x; + r_refdef.pxrect.y = y; + r_refdef.pxrect.width = w; + r_refdef.pxrect.height = h; + r_refdef.pxrect.maxheight = vid.pixelheight; + } fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; - if (stereooffset && r_stereo_method.ival == 5) - { - w /= 2; - if (stereooffset > 0) - x += vid.pixelwidth/2; - } - - r_refdef.pxrect.x = x; - r_refdef.pxrect.y = y; - r_refdef.pxrect.width = w; - r_refdef.pxrect.height = h; - r_refdef.pxrect.maxheight = vid.pixelheight; - GL_ViewportUpdate(); if (r_waterwarp.value<0 && (r_viewcontents & FTECONTENTS_FLUID)) @@ -969,6 +985,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], qglClipPlane(GL_CLIP_PLANE0, glplane); qglEnable(GL_CLIP_PLANE0); }*/ + //fixme: we can probably scissor a smaller frusum R_SetFrustum (r_refdef.m_projection, vmat); if (r_refdef.frustum_numplanes < MAXFRUSTUMPLANES) { @@ -1101,7 +1118,7 @@ void R_Clear (void) /*tbh, this entire function should be in the backend*/ GL_ForceDepthWritable(); { - if (r_clear.ival && r_refdef.grect.x == 0 && r_refdef.grect.y == 0 && r_refdef.grect.width == vid.width && r_refdef.grect.height == vid.height && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) + if (r_clear.ival && r_refdef.grect.x == 0 && r_refdef.grect.y == 0 && (unsigned)r_refdef.grect.width == vid.fbvwidth && (unsigned)r_refdef.grect.height == vid.fbvheight && !(r_refdef.flags & Q2RDF_NOWORLDMODEL)) { qglClearColor(1, 0, 0, 0); qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1208,10 +1225,12 @@ static void R_RenderMotionBlur(void) "}\n" "}\n" ); - GLBE_RenderToTexture(sceneblur_texture, r_nulltex, r_nulltex, r_nulltex, false); +// GLBE_RenderToTexture(sceneblur_texture, r_nulltex, r_nulltex, r_nulltex, false); + Con_Printf("FIXME: tex_sourcecolour = sceneblur_texture\n"); R2D_ImageColours(1, 1, 1, gl_motionblur.value); R2D_Image(0, 0, vid.width, vid.height, cs-vs, ct+vt, cs+vs, ct-vt, shader); - GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); + Con_Printf("FIXME: tex_sourcecolour = reset\n"); +// GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); //grab the current image so we can feed that back into the next frame. GL_MTBind(0, GL_TEXTURE_2D, sceneblur_texture); @@ -1402,21 +1421,22 @@ r_refdef must be set before the first call */ void GLR_RenderView (void) { + int oldfbo = 0; + int dofbo = r_refdef.rt_destcolour || r_refdef.rt_depth; double time1 = 0, time2; checkglerror(); + GL_DoSwap(); + if (r_norefresh.value || !vid.pixelwidth || !vid.pixelheight) - { - GL_DoSwap(); return; - } if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL)) + { + //FIXME: fbo stuff if (!r_worldentity.model || r_worldentity.model->needload || !cl.worldmodel) { - GL_DoSwap(); - GL_Set2D (false); R2D_ImageColours(0, 0, 0, 1); R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height); @@ -1424,8 +1444,52 @@ void GLR_RenderView (void) return; } // Sys_Error ("R_RenderView: NULL worldmodel"); + } + BE_Scissor(NULL); + if (dofbo) + { + unsigned int flags = 0; + texid_t col = r_nulltex, depth = r_nulltex; + unsigned int cw=0, ch=0, dw=0, dh=0; + //3d views generally ignore source colour+depth. + //FIXME: support depth with no colour + if (r_refdef.rt_destcolour) + col = R2D_RT_GetTexture(r_refdef.rt_destcolour, &cw, &ch); + if (r_refdef.rt_depth) + depth = R2D_RT_GetTexture(r_refdef.rt_depth, &dw, &dh); + if (r_refdef.rt_destcolour) + { //colour (with or without depth) + if (r_refdef.rt_depth && (dw != cw || dh != dh)) + { + Con_Printf("RT: destcolour and depth render targets are of different sizes\n"); //should check rgb/depth modes too I guess. + depth = r_nulltex; + } + vid.fbvwidth = vid.fbpwidth = cw; + vid.fbvheight = vid.fbpheight = ch; + } + else + { //depth, with no colour + vid.fbvwidth = vid.fbpwidth = dw; + vid.fbvheight = vid.fbpheight = dh; + } + if (TEXVALID(col)) + flags |= FBO_TEX_COLOUR; + if (TEXVALID(depth)) + flags |= FBO_TEX_DEPTH; + else + flags |= FBO_RB_DEPTH; + oldfbo = GLBE_FBO_Update(&fbo_gameview, true, flags, col, depth, vid.fbpwidth, vid.fbpheight); + //oldfbo will probably be the 2d fbo + } + else + { + vid.fbvwidth = vid.width; + vid.fbvheight = vid.height; + vid.fbpwidth = vid.pixelwidth; + vid.fbpheight = vid.pixelheight; + } if (qglPNTrianglesiATI) { @@ -1452,11 +1516,9 @@ void GLR_RenderView (void) if (r_speeds.ival) { time1 = Sys_DoubleTime (); - c_brush_polys = 0; - c_alias_polys = 0; } - if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL) && R_RenderScene_Cubemap()) + if (!dofbo && !(r_refdef.flags & Q2RDF_NOWORLDMODEL) && R_RenderScene_Cubemap()) { } @@ -1481,16 +1543,23 @@ void GLR_RenderView (void) RQuantAdd(RQUANT_MSECS, (int)((time2-time1)*1000000)); - RQuantAdd(RQUANT_WPOLYS, c_brush_polys); - RQuantAdd(RQUANT_EPOLYS, c_alias_polys); // Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); } checkglerror(); - GL_Set2D (false); + //update stuff now that we're not rendering the 3d scene + if (dofbo) + GLBE_RenderToTextureUpdate2d(true); + else + { + GLBE_RenderToTextureUpdate2d(false); + GL_Set2D (false); + } - if ((r_refdef.flags & Q2RDF_NOWORLDMODEL) || r_secondaryview) + //FIXME: support bloom+waterwarp even when drawing to an fbo? + //FIXME: force waterwarp to a temp fbo always + if ((r_refdef.flags & Q2RDF_NOWORLDMODEL) || r_secondaryview || dofbo) return; if (r_secondaryview) diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index 09d3ea9ab..950a370a9 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -353,16 +353,14 @@ void R_MakeTexWad_f(void) if (buf) break; } + width = 16; + height = 16; if (buf) data = Read32BitImageFile(buf, com_filesize, &width, &height, &hasalpha, imagename); else data = NULL; if (!data) - { - data = Z_Malloc(16*16*4); - width = 16; - height = 16; - } + data = Z_Malloc(width*height*4); dummymip.width = (int)(width/scale) & ~0xf; dummymip.height = (int)(height/scale) & ~0xf; diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 79211033c..632c22a42 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -3097,7 +3097,8 @@ static shaderkey_t shaderpasskeys[] = {"maskalpha", Shaderpass_MaskAlpha}, {"alphatest", Shaderpass_AlphaTest}, {"texgen", Shaderpass_TexGen}, - {"cameracubemap",Shaderpass_CubeMap}, + {"cubemap", Shaderpass_CubeMap}, //one of these is wrong + {"cameracubemap",Shaderpass_CubeMap}, //one of these is wrong {"red", Shaderpass_Red}, {"green", Shaderpass_Green}, {"blue", Shaderpass_Blue}, @@ -3161,7 +3162,7 @@ void Shader_Free (shader_t *shader) -int QDECL Shader_InitCallback (const char *name, int size, void *param, searchpathfuncs_t *spath) +int QDECL Shader_InitCallback (const char *name, qofs_t size, void *param, searchpathfuncs_t *spath) { strcpy(shaderbuf+shaderbuflen, name); Shader_MakeCache(shaderbuf+shaderbuflen); @@ -3311,6 +3312,7 @@ static void Shader_GetPathAndOffset(char *name, char **path, unsigned int *offse void Shader_Reset(shader_t *s) { char name[MAX_QPATH]; + int id = s->id; int uses = s->uses; shader_gen_t *defaultgen = s->generator; char *genargs = s->genargs; @@ -3323,6 +3325,7 @@ void Shader_Reset(shader_t *s) Shader_Free(s); memset(s, 0, sizeof(*s)); + s->id = id; s->width = w; s->height = h; s->defaulttextures = dt; @@ -4163,6 +4166,13 @@ void Shader_UpdateRegistration (void) void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) { + char *h; + char imagename[MAX_QPATH]; + strcpy(imagename, shader->name); + h = strchr(imagename, '#'); + if (h) + *h = 0; + if (!tn) tn = &shader->defaulttextures; if (!TEXVALID(shader->defaulttextures.base)) @@ -4170,7 +4180,7 @@ void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) /*dlights/realtime lighting needs some stuff*/ if (!TEXVALID(tn->base)) { - tn->base = R_LoadHiResTexture(shader->name, NULL, IF_NOALPHA); + tn->base = R_LoadHiResTexture(imagename, NULL, IF_NOALPHA); } if (TEXVALID(tn->base)) shader->flags &= ~SHADER_NOIMAGE; @@ -4178,16 +4188,18 @@ void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) TEXASSIGN(shader->defaulttextures.base, tn->base); } + COM_StripExtension(imagename, imagename, sizeof(imagename)); + if (!TEXVALID(shader->defaulttextures.bump)) { if (r_loadbumpmapping) { if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("%s_norm", shader->name), NULL, IF_NOALPHA); + tn->bump = R_LoadHiResTexture(va("%s_norm", imagename), NULL, IF_NOALPHA); if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("%s_bump", shader->name), NULL, IF_NOALPHA); + tn->bump = R_LoadHiResTexture(va("%s_bump", imagename), NULL, IF_NOALPHA); if (!TEXVALID(tn->bump)) - tn->bump = R_LoadHiResTexture(va("normalmaps/%s", shader->name), NULL, IF_NOALPHA); + tn->bump = R_LoadHiResTexture(va("normalmaps/%s", imagename), NULL, IF_NOALPHA); } TEXASSIGN(shader->defaulttextures.bump, tn->bump); } @@ -4197,7 +4209,7 @@ void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) if (shader->flags & SHADER_HASTOPBOTTOM) { if (!TEXVALID(tn->loweroverlay)) - tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", shader->name), NULL, 0); /*how rude*/ + tn->loweroverlay = R_LoadHiResTexture(va("%s_pants", imagename), NULL, 0); /*how rude*/ } TEXASSIGN(shader->defaulttextures.loweroverlay, tn->loweroverlay); } @@ -4207,7 +4219,7 @@ void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) if (shader->flags & SHADER_HASTOPBOTTOM) { if (!TEXVALID(tn->upperoverlay)) - tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", shader->name), NULL, 0); + tn->upperoverlay = R_LoadHiResTexture(va("%s_shirt", imagename), NULL, 0); } TEXASSIGN(shader->defaulttextures.upperoverlay, tn->upperoverlay); } @@ -4218,7 +4230,7 @@ void R_BuildDefaultTexnums(texnums_t *tn, shader_t *shader) if ((shader->flags & SHADER_HASGLOSS) && gl_specular.value && gl_load24bit.value) { if (!TEXVALID(tn->specular)) - tn->specular = R_LoadHiResTexture(va("%s_gloss", shader->name), NULL, 0); + tn->specular = R_LoadHiResTexture(va("%s_gloss", imagename), NULL, 0); } TEXASSIGN(shader->defaulttextures.specular, tn->specular); } @@ -4436,7 +4448,7 @@ void Shader_DefaultCinematic(char *shortname, shader_t *s, const void *args) "{\n" "program default2d\n" "{\n" - "videomap %s\n" + "videomap \"%s\"\n" "}\n" "}\n" , (const char*)args) @@ -5115,29 +5127,19 @@ void R_UnloadShader(shader_t *shader) static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t *defaultgen, const char *genargs) { int i, f = -1; + char cleanname[MAX_QPATH]; char shortname[MAX_QPATH]; - char *hash; + char *argsstart; shader_t *s; if (!*name) name = "gfx/white"; - hash = strchr(name, '#'); - if (hash) //don't strip anything. - { - Q_strncpyz(shortname, name, sizeof(shortname)); - hash = shortname+(hash-name); - } - else - { - *(int*)shortname = 0; - COM_StripExtension ( name, shortname, sizeof(shortname)); - } - - COM_CleanUpPath(shortname); + Q_strncpyz(cleanname, name, sizeof(cleanname)); + COM_CleanUpPath(cleanname); // check the hash first - s = Hash_Get(&shader_active_hash, shortname); + s = Hash_Get(&shader_active_hash, cleanname); while (s) { //make sure the same texture can be used as either a lightmap or vertexlit shader @@ -5148,7 +5150,7 @@ static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t s->uses++; return s; } - s = Hash_GetNext(&shader_active_hash, shortname, s); + s = Hash_GetNext(&shader_active_hash, cleanname, s); } // not loaded, find a free slot @@ -5183,6 +5185,11 @@ static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t r_maxshaders = nm; } } + if (strlen(cleanname) >= sizeof(s->name)) + { + Sys_Error( "R_LoadShader: Shader name too long."); + return NULL; + } s = r_shaders[f]; if (!s) @@ -5191,7 +5198,7 @@ static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t if (r_numshaders < f+1) r_numshaders = f+1; - Q_strncpyz(s->name, shortname, sizeof(s->name)); + Q_strncpyz(s->name, cleanname, sizeof(s->name)); s->usageflags = usageflags; s->generator = defaultgen; if (genargs) @@ -5199,9 +5206,11 @@ static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t else s->genargs = NULL; - //now strip off the hash so we find the right shader script - if (hash) - *hash = 0; + //now determine the 'short name'. ie: the shader that is loaded off disk (no args, no extension) + argsstart = strchr(cleanname, '#'); + if (argsstart) + *argsstart = 0; + COM_StripExtension (cleanname, shortname, sizeof(shortname)); if (ruleset_allow_shaders.ival) { @@ -5266,13 +5275,13 @@ static shader_t *R_LoadShader (char *name, unsigned int usageflags, shader_gen_t Shader_Reset(s); if (!strcmp(shortname, "textures/common/clip")) - Shader_DefaultScript(shortname, s, + Shader_DefaultScript(cleanname, s, "{\n" "surfaceparm nodraw\n" "surfaceparm nodlight\n" "}\n"); else - s->generator(shortname, s, s->genargs); + s->generator(cleanname, s, s->genargs); return s; } else diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index b6fe8c013..65d2c673e 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -45,6 +45,7 @@ static int shadow_fbo_id; static int shadow_fbo_depth_num; static int crepuscular_fbo_id; texid_t crepuscular_texture_id; +fbostate_t crepuscular_fbo; shader_t *crepuscular_shader; cvar_t r_shadow_shadowmapping_nearclip = CVAR("r_shadow_shadowmapping_nearclip", "1"); @@ -2365,6 +2366,8 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize) switch(qrenderer) { + default: + return false; #ifdef GLQUAKE case QR_OPENGL: if (!TEXVALID(shadowmap[isspot])) @@ -2458,6 +2461,8 @@ qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize) switch(qrenderer) { + default: + break; #ifdef GLQUAKE case QR_OPENGL: /*end framebuffer*/ @@ -3142,6 +3147,7 @@ void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop); void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours) { #ifdef GLQUAKE + int oldfbo; static mesh_t mesh; static vecV_t xyz[4] = { @@ -3209,19 +3215,19 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours) BE_Scissor(NULL); - GLBE_RenderToTexture(r_nulltex, r_nulltex, crepuscular_texture_id, r_nulltex, false); + oldfbo = GLBE_FBO_Update(&crepuscular_fbo, true, FBO_TEX_COLOUR, crepuscular_texture_id, r_nulltex, vid.pixelwidth, vid.pixelheight); BE_SelectMode(BEM_CREPUSCULAR); BE_SelectDLight(dl, colours, LSHADER_STANDARD); GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_BLEND); - GLBE_RenderToTexture(crepuscular_texture_id, r_nulltex, r_nulltex, r_nulltex, false); + GLBE_FBO_Pop(oldfbo); + Con_Printf("FIXME: shaderstate.tex_sourceocolour = crepuscular_texture_id\n"); BE_SelectMode(BEM_STANDARD); GLBE_DrawMesh_Single(crepuscular_shader, &mesh, NULL, &crepuscular_shader->defaulttextures, 0); - - GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); + Con_Printf("FIXME: shaderstate.tex_sourceocolour = reset\n"); #endif } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index dde2af76a..9e41333be 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1294,7 +1294,7 @@ qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *pr } if (!glsl_hdrs[i]) { - if (FS_LoadFile(incname, (void**)&inc) >= 0) + if (FS_LoadFile(incname, (void**)&inc) != (qofs_t)-1) { if (!GLSlang_GenerateIncludes(maxstrings, strings, prstrings, length, inc)) { @@ -1745,6 +1745,9 @@ void GL_Init(void *(*getglfunction) (char *name)) qglBindBufferARB = GL_BindBufferARBStub; #endif + if (!qglGetString) + Sys_Error("qglGetString not set. Serious gl library initialisation error\n"); + gl_vendor = qglGetString (GL_VENDOR); Con_SafePrintf ("GL_VENDOR: %s\n", gl_vendor); gl_renderer = qglGetString (GL_RENDERER); diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 12c6bbc43..749e9bd8b 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -161,7 +161,7 @@ qboolean isPermedia = false; // Note that 0 is MODE_WINDOWED extern cvar_t vid_mode; // Note that 3 is MODE_FULLSCREEN_DEFAULT -extern cvar_t _vid_wait_override; +extern cvar_t vid_vsync; extern cvar_t _windowed_mouse; extern cvar_t vid_hardwaregamma; extern cvar_t vid_desktopgamma; @@ -170,7 +170,7 @@ extern cvar_t vid_preservegamma; extern cvar_t vid_gl_context_version; extern cvar_t vid_gl_context_debug; -extern cvar_t vid_gl_context_es2; +extern cvar_t vid_gl_context_es; extern cvar_t vid_gl_context_forwardcompatible; extern cvar_t vid_gl_context_compatibility; @@ -184,6 +184,9 @@ static char reqminidriver[MAX_OSPATH]; static char opengldllname[MAX_OSPATH]; #ifdef _DEBUG +//this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB. +//functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called. +//this list is just to make it easier to test+debug android gles2 stuff using windows. static char *gles2funcs[] = { #define f(n) #n, @@ -350,7 +353,7 @@ void *getglfunc(char *name) } #ifdef _DEBUG - if (vid_gl_context_es2.ival == 2) + if (vid_gl_context_es.ival == 2) { int i; for (i = 0; gles2funcs[i]; i++) @@ -1154,7 +1157,7 @@ qboolean VID_AttachGL (rendererstate_t *info) char *ver; ver = vid_gl_context_version.string; - if (!*ver && vid_gl_context_es2.ival) + if (!*ver && vid_gl_context_es.ival) ver = "2.0"; mv = ver; @@ -1189,10 +1192,10 @@ qboolean VID_AttachGL (rendererstate_t *info) } /*only switch contexts if there's actually a point*/ - if (i || !vid_gl_context_compatibility.ival || vid_gl_context_es2.ival) + if (i || !vid_gl_context_compatibility.ival || vid_gl_context_es.ival) { attribs[i+1] = 0; - if (vid_gl_context_es2.ival) + if (vid_gl_context_es.ival) attribs[i+1] |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; else if (vid_gl_context_compatibility.ival) attribs[i+1] |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; @@ -1200,7 +1203,7 @@ qboolean VID_AttachGL (rendererstate_t *info) attribs[i+1] |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; attribs[i] = WGL_CONTEXT_PROFILE_MASK_ARB; //WGL_CONTEXT_PROFILE_MASK_ARB is ignored if < 3.2 - however, nvidia do not agree and return errors - if (atof(ver) >= 3.2 || vid_gl_context_es2.ival) + if (atof(ver) >= 3.2 || vid_gl_context_es.ival) i+=2; attribs[i] = 0; @@ -1223,7 +1226,7 @@ qboolean VID_AttachGL (rendererstate_t *info) if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) Con_Printf("Unsupported OpenGL context version (%s).\n", vid_gl_context_version.string); else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) - Con_Printf("Unsupported OpenGL profile (%s).\n", vid_gl_context_es2.ival?"gles":(vid_gl_context_compatibility.ival?"compat":"core")); + Con_Printf("Unsupported OpenGL profile (%s).\n", vid_gl_context_es.ival?"gles":(vid_gl_context_compatibility.ival?"compat":"core")); else if (error == (0xc0070000 | ERROR_INVALID_OPERATION)) Con_Printf("wglCreateContextAttribsARB returned invalid operation.\n"); else if (error == (0xc0070000 | ERROR_DC_NOT_FOUND)) @@ -1255,10 +1258,10 @@ qboolean VID_AttachGL (rendererstate_t *info) qwglChoosePixelFormatARB = getglfunc("wglChoosePixelFormatARB"); qwglSwapIntervalEXT = getglfunc("wglSwapIntervalEXT"); - if (qwglSwapIntervalEXT && *_vid_wait_override.string) + if (qwglSwapIntervalEXT && *vid_vsync.string) { TRACE(("dbg: VID_AttachGL: qwglSwapIntervalEXT\n")); - qwglSwapIntervalEXT(_vid_wait_override.value); + qwglSwapIntervalEXT(vid_vsync.value); } TRACE(("dbg: VID_AttachGL: qSwapBuffers\n")); qglClearColor(0, 0, 0, 0); @@ -1292,8 +1295,8 @@ void GL_BeginRendering (void) void VID_Wait_Override_Callback(struct cvar_s *var, char *oldvalue) { - if (qwglSwapIntervalEXT && *_vid_wait_override.string) - qwglSwapIntervalEXT(_vid_wait_override.value); + if (qwglSwapIntervalEXT && *vid_vsync.string) + qwglSwapIntervalEXT(vid_vsync.value); } void GLVID_Recenter_f(void) @@ -1318,7 +1321,7 @@ void GLVID_Recenter_f(void) sys_parentheight = atoi(Cmd_Argv(4)); if (Cmd_Argc() > 5) { - HWND newparent = (HWND)strtoull(Cmd_Argv(5), NULL, 16); + HWND newparent = (HWND)(DWORD_PTR)strtoull(Cmd_Argv(5), NULL, 16); if (newparent != sys_parentwindow && mainwindow && modestate==MS_WINDOWED) SetParent(mainwindow, sys_parentwindow); sys_parentwindow = newparent; @@ -1623,7 +1626,7 @@ BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) 1, // version number PFD_DRAW_TO_WINDOW // support window | PFD_SUPPORT_OPENGL // support OpenGL - | PFD_DOUBLEBUFFER , // double buffered + | PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 24, // 24-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored @@ -1673,6 +1676,8 @@ BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) { Con_Printf(CON_WARNING "WARNING: software-rendered opengl context\nPlease install appropriate graphics drivers, or try d3d rendering instead\n"); } + else if (pfd.dwFlags & PFD_SWAP_COPY) + Con_Printf(CON_WARNING "WARNING: buffer swaps will use copy operations\n"); return TRUE; } } @@ -1699,6 +1704,8 @@ BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info) { Con_Printf(CON_WARNING "WARNING: software-rendered opengl context\nPlease install appropriate graphics drivers, or try d3d rendering instead\n"); } + else if (pfd.dwFlags & PFD_SWAP_COPY) + Con_Printf(CON_WARNING "WARNING: buffer swaps will use copy operations\n"); FixPaletteInDescriptor(hDC, &pfd); return TRUE; @@ -2061,7 +2068,7 @@ void GLVID_DeInit (void) GLVID_Shutdown(); ActiveApp = false; - Cvar_Unhook(&_vid_wait_override); + Cvar_Unhook(&vid_vsync); Cvar_Unhook(&vid_wndalpha); Cmd_RemoveCommand("vid_recenter"); @@ -2112,7 +2119,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) vid_canalttab = true; - Cvar_Hook(&_vid_wait_override, VID_Wait_Override_Callback); + Cvar_Hook(&vid_vsync, VID_Wait_Override_Callback); Cvar_Hook(&vid_wndalpha, VID_WndAlpha_Override_Callback); Cmd_AddCommand("vid_recenter", GLVID_Recenter_f); diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index bac2642a3..b9c8c0644 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -2,11 +2,23 @@ #include "glquake.h" #include +#include +#if SDL_MAJOR_VERSION >= 2 +SDL_Window *sdlwindow; +static SDL_GLContext *sdlcontext; +#else SDL_Surface *sdlsurf; +#endif +extern cvar_t vid_vsync; extern cvar_t vid_hardwaregamma; extern cvar_t gl_lateswap; +extern cvar_t vid_gl_context_version; +extern cvar_t vid_gl_context_debug; +extern cvar_t vid_gl_context_forwardcompatible; +extern cvar_t vid_gl_context_es; +extern cvar_t vid_gl_context_compatibility; extern int gammaworks; #ifdef _WIN32 //half the rest of the code uses windows apis to focus windows. Should be fixed, but it's not too important. @@ -15,7 +27,9 @@ HWND mainwindow; extern qboolean vid_isfullscreen; +#if SDL_MAJOR_VERSION < 2 unsigned short intitialgammaramps[3][256]; +#endif qboolean ActiveApp; qboolean mouseactive; @@ -34,29 +48,113 @@ static void *GLVID_getsdlglfunction(char *functionname) qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) { - int flags; + int flags = 0; SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE); -#ifndef FTE_TARGET_WEB - SDL_SetVideoMode( 0, 0, 0, 0 ); //to get around some SDL bugs +#if !defined(FTE_TARGET_WEB) && SDL_MAJOR_VERSION < 2 + SDL_SetVideoMode(0, 0, 0, 0); //to get around some SDL bugs #endif - SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); - SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); - SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); - SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); +#if SDL_MAJOR_VERSION >= 2 + SDL_GL_LoadLibrary(NULL); +#endif - SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 ); + if (info->bpp >= 32) + { + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); //technically we don't always need stencil support. + } + else + { + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0); + } + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + if (info->stereo) + SDL_GL_SetAttribute(SDL_GL_STEREO, 1); + +#if 0//SDL_MAJOR_VERSION >= 2 + //FIXME: this stuff isn't part of info. + //this means it shouldn't be exposed to the menu or widely advertised. + if (*vid_gl_context_version.string) + { + int major, minor; + char *ver = vid_gl_context_version.string; + major = strtoul(ver, &ver, 10); + if (*ver == '.') + { + ver++; + minor = strtoul(ver, &ver, 10); + } + else + minor = 0; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); + } + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, + (vid_gl_context_debug.ival?SDL_GL_CONTEXT_DEBUG_FLAG:0) | + (vid_gl_context_forwardcompatible.ival?SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG:0) | + 0); + + if (vid_gl_context_es.ival) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + else if (vid_gl_context_compatibility.ival) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); + else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif if (info->multisample) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, info->multisample); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); } - SDL_GetGammaRamp(intitialgammaramps[0], intitialgammaramps[1], intitialgammaramps[2]); +#if SDL_MAJOR_VERSION >= 2 + if (info->fullscreen) + flags |= SDL_WINDOW_FULLSCREEN; + flags |= SDL_WINDOW_OPENGL; + flags |= SDL_WINDOW_RESIZABLE; + flags |= SDL_WINDOW_INPUT_GRABBED; + flags |= SDL_WINDOW_SHOWN; + #if SDL_PATCHLEVEL >= 1 + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + #endif + sdlwindow = SDL_CreateWindow("My Magic Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, info->width, info->height, flags); + if (!sdlwindow) + { + Con_Printf("Couldn't set video mode: %s\n", SDL_GetError()); + return false; + } + #if SDL_PATCHLEVEL >= 1 + SDL_GL_GetDrawableSize(sdlwindow, &vid.pixelwidth, &vid.pixelheight); //get the proper physical size. + #else + SDL_GetWindowSize(sdlwindow, &vid.pixelwidth, &vid.pixelheight); + #endif + sdlcontext = SDL_GL_CreateContext(sdlwindow); + if (!sdlcontext) + { + Con_Printf("Couldn't initialize GL context: %s\n", SDL_GetError()); + return false; + } + + { + SDL_Surface *iconsurf; + #include "bymorphed.h" + iconsurf = SDL_CreateRGBSurfaceFrom(icon.pixel_data, icon.width, icon.height, 32, 4*icon.height, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); //RGBA byte order on a little endian machine, at least... + SDL_SetWindowIcon(sdlwindow, iconsurf); + SDL_FreeSurface(iconsurf); + } +#else + SDL_GetGammaRamp(intitialgammaramps[0], intitialgammaramps[1], intitialgammaramps[2]); if (info->fullscreen) { flags = SDL_FULLSCREEN; @@ -73,7 +171,7 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) Con_Printf("Couldn't set GL mode: %s\n", SDL_GetError()); return false; } - +#endif ActiveApp = true; GL_Init(GLVID_getsdlglfunction); @@ -84,6 +182,31 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) if (vid_isfullscreen) IN_ActivateMouse(); +#if SDL_MAJOR_VERSION < 2 + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); +#endif + vid_vsync.modified = true; + + SDL_DisableScreenSaver(); + + #ifdef _WIN32 + { //win32 apis are very insistant upon having a window context for things that have nothing to do with windowing system stuff. + #if SDL_MAJOR_VERSION >= 2 + SDL_SysWMinfo info; + SDL_GetWindowWMInfo(sdlwindow, &info); + if (info.subsystem == SDL_SYSWM_WINDOWS) + mainwindow = info.info.win.window; + else + mainwindow = NULL; //if we're using an x11 subsystem but running in windows then don't feck up... here, at least. + #else + SDL_SysWMinfo wmInfo; + SDL_GetWMInfo(&wmInfo); + memset(&bi, 0, sizeof(bi)); + mainwindow = wmInfo.window; //note that this is usually still null + #endif + } + #endif + return true; } @@ -92,7 +215,16 @@ void GLVID_DeInit (void) ActiveApp = false; IN_DeactivateMouse(); + + +#if SDL_MAJOR_VERSION >= 2 + SDL_SetWindowGammaRamp(sdlwindow, NULL, NULL, NULL); + SDL_GL_DeleteContext(sdlcontext); + SDL_DestroyWindow(sdlwindow); +#else SDL_SetGammaRamp (intitialgammaramps[0], intitialgammaramps[1], intitialgammaramps[2]); +#endif + sdlwindow = NULL; SDL_QuitSubSystem(SDL_INIT_VIDEO); } @@ -113,7 +245,22 @@ void GL_DoSwap (void) return; screenflush = 0; - SDL_GL_SwapBuffers( ); + if (vid_vsync.modified) + { + if (*vid_vsync.string) + { + //if swap_tear isn't supported, try without. + if (SDL_GL_SetSwapInterval(vid_vsync.ival) == -1 && vid_vsync.ival < 0) + SDL_GL_SetSwapInterval(-vid_vsync.ival); + } + vid_vsync.modified = false; + } + +#if SDL_MAJOR_VERSION >= 2 + SDL_GL_SwapWindow(sdlwindow); +#else + SDL_GL_SwapBuffers(); +#endif if (!vid_isfullscreen) @@ -141,6 +288,29 @@ void GL_EndRendering (void) qboolean GLVID_ApplyGammaRamps (unsigned short *ramps) { +#if SDL_MAJOR_VERSION >= 2 + if (ramps) + { + if (vid_hardwaregamma.value) + { + if (gammaworks) + { //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck) + SDL_SetWindowGammaRamp (sdlwindow, &ramps[0], &ramps[256], &ramps[512]); + return true; + } + gammaworks = !SDL_SetWindowGammaRamp (sdlwindow, &ramps[0], &ramps[256], &ramps[512]); + } + else + gammaworks = false; + + return gammaworks; + } + else + { + SDL_SetWindowGammaRamp (sdlwindow, NULL, NULL, NULL); + return true; + } +#else if (ramps) { if (vid_hardwaregamma.value) @@ -162,11 +332,16 @@ qboolean GLVID_ApplyGammaRamps (unsigned short *ramps) SDL_SetGammaRamp (intitialgammaramps[0], intitialgammaramps[1], intitialgammaramps[2]); return true; } +#endif } void GLVID_SetCaption(char *text) { - SDL_WM_SetCaption( text, NULL ); +#if SDL_MAJOR_VERSION >= 2 + SDL_SetWindowTitle(sdlwindow, text); +#else + SDL_WM_SetCaption(text, NULL); +#endif } diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 743d10f39..707af4486 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -278,7 +278,6 @@ extern entity_t *currententity; extern int r_visframecount; // ??? what difs? extern int r_framecount; -extern float r_wateralphaval; extern qboolean r_loadbumpmapping; // diff --git a/engine/gl/shader.h b/engine/gl/shader.h index d0e8ab613..a818fcfe8 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -603,11 +603,35 @@ void GLBE_SelectEntity(entity_t *ent); qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode); void GLBE_Scissor(srect_t *rect); void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop); -void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth); +//void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth); +void GLBE_RenderToTextureUpdate2d(qboolean destchanged); void GLBE_VBO_Begin(vbobctx_t *ctx, unsigned int maxsize); void GLBE_VBO_Data(vbobctx_t *ctx, void *data, unsigned int size, vboarray_t *varray); void GLBE_VBO_Finish(vbobctx_t *ctx, void *edata, unsigned int esize, vboarray_t *earray); void GLBE_VBO_Destroy(vboarray_t *vearray); + +typedef struct +{ + int fbo; + int rb_size[2]; + int rb_depth; + int rb_stencil; + int rb_depthstencil; + texid_t colour; + unsigned int enables; +} fbostate_t; +#define FBO_RB_COLOUR 1 +#define FBO_RB_DEPTH 2 +#define FBO_RB_STENCIL 4 +#define FBO_RESET 8 //resize all renderbuffers / free any that are not active. implied if the sizes differ +#define FBO_TEX_COLOUR 16 //internal +#define FBO_TEX_DEPTH 32 //internal +#define FBO_TEX_STENCIL 64 //internal +void GLBE_FBO_Sources(texid_t sourcecolour, texid_t sourcedepth); +int GLBE_FBO_Push(fbostate_t *state); +void GLBE_FBO_Pop(int oldfbo); +void GLBE_FBO_Destroy(fbostate_t *state); +int GLBE_FBO_Update(fbostate_t *state, qboolean bind, unsigned int enables, texid_t destcol, texid_t destdepth, int width, int height); #endif #ifdef D3D9QUAKE void D3D9BE_Init(void); diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index b4f8cd777..2513aeadc 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -21,7 +21,7 @@ #include "netinc.h" static iwboolean ftpserverinitied = false; -static int ftpserversocket = INVALID_SOCKET; +static SOCKET ftpserversocket = INVALID_SOCKET; qboolean ftpserverfailed; @@ -36,8 +36,8 @@ typedef struct FTPclient_s{ int cmdbuflen; int msgbuflen; - int controlsock; - int datasock; //FTP only allows one transfer per connection. + SOCKET controlsock; + SOCKET datasock; //FTP only allows one transfer per connection. int dataislisten; int datadir; //0 no data, 1 reading, 2 writing vfsfile_t *file; @@ -49,13 +49,13 @@ typedef struct FTPclient_s{ FTPclient_t *FTPclient; -int FTP_BeginListening(int aftype, int port) +SOCKET FTP_BeginListening(int aftype, int port) { struct sockaddr_qstorage address; unsigned long _true = true; unsigned long _false = false; int i; - int sock; + SOCKET sock; #ifdef IPPROTO_IPV6 if ((sock = socket ((aftype!=1)?PF_INET6:PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) @@ -63,13 +63,13 @@ int FTP_BeginListening(int aftype, int port) if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) #endif { - IWebPrintf ("FTP_BeginListening: socket: %s\n", strerror(qerrno)); + IWebPrintf ("FTP_BeginListening: socket: %s\n", strerror(neterrno())); return INVALID_SOCKET; } if (ioctlsocket (sock, FIONBIO, &_true) == -1) { - IWebPrintf ("FTP_BeginListening: ioctl FIONBIO: %s", strerror(qerrno)); + IWebPrintf ("FTP_BeginListening: ioctl FIONBIO: %s", strerror(neterrno())); return INVALID_SOCKET; } @@ -134,9 +134,9 @@ void FTP_ServerShutdown(void) } //we ought to filter this to remove duplicates. -static int QDECL SendFileNameTo(const char *rawname, int size, void *param, searchpathfuncs_t *spath) +static int QDECL SendFileNameTo(const char *rawname, qofs_t size, void *param, searchpathfuncs_t *spath) { - int socket = *(int*)param; + SOCKET socket = *(SOCKET*)param; // int i; char buffer[256+1]; char *slash; @@ -171,10 +171,10 @@ static int QDECL SendFileNameTo(const char *rawname, int size, void *param, sear return true; } -int FTP_SV_makelistensocket(unsigned long nblocking) +SOCKET FTP_SV_makelistensocket(unsigned long nblocking) { char name[256]; - int sock; + SOCKET sock; struct hostent *hent; struct sockaddr_in address; @@ -193,12 +193,12 @@ int FTP_SV_makelistensocket(unsigned long nblocking) if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - Sys_Error ("FTP_TCP_OpenSocket: socket: %s", strerror(qerrno)); + Sys_Error ("FTP_TCP_OpenSocket: socket: %s", strerror(neterrno())); } if (ioctlsocket (sock, FIONBIO, &nblocking) == -1) { - Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); } if( bind (sock, (void *)&address, sizeof(address)) == -1) @@ -211,7 +211,7 @@ int FTP_SV_makelistensocket(unsigned long nblocking) return sock; } -iwboolean FTP_SVSocketPortToString (int socket, char *s) +iwboolean FTP_SVSocketPortToString (SOCKET socket, char *s) { struct sockaddr_qstorage addr; int adrlen = sizeof(addr); @@ -226,7 +226,7 @@ iwboolean FTP_SVSocketPortToString (int socket, char *s) return true; } //only to be used for ipv4 sockets. -iwboolean FTP_SVSocketToString (int socket, char *s) +iwboolean FTP_SVSocketToString (SOCKET socket, char *s) { struct sockaddr_in addr; qbyte *baddr; @@ -249,7 +249,7 @@ iwboolean FTP_SVSocketToString (int socket, char *s) sprintf(s, "%i,%i,%i,%i,%i,%i", baddr[0], baddr[1], baddr[2], baddr[3], ((qbyte *)&addr.sin_port)[0], ((qbyte *)&addr.sin_port)[1]); return true; } -iwboolean FTP_SVRemoteSocketToString (int socket, char *s, int slen) +iwboolean FTP_SVRemoteSocketToString (SOCKET socket, char *s, int slen) { struct sockaddr_qstorage addr; netadr_t na; @@ -327,7 +327,7 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) if (sent == -1) { VFS_SEEK(cl->file, pos); - if (qerrno != EWOULDBLOCK) + if (neterrno() != NET_EWOULDBLOCK) { closesocket(cl->datasock); cl->datasock = INVALID_SOCKET; @@ -361,7 +361,7 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) pos = cl->datadir?1:!cl->blocking; if (ioctlsocket (cl->controlsock, FIONBIO, (u_long *)&pos) == -1) { - IWebPrintf ("FTP_ServerRun: blocking error: %s\n", strerror(qerrno)); + IWebPrintf ("FTP_ServerRun: blocking error: %s\n", strerror(neterrno())); return 0; } } @@ -374,7 +374,7 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) } if (len == -1) { - if (qerrno != EWOULDBLOCK) + if (neterrno() != NET_EWOULDBLOCK) { closesocket(cl->datasock); cl->datasock = INVALID_SOCKET; @@ -398,13 +398,14 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) ret = recv(cl->controlsock, cl->commandbuffer+cl->cmdbuflen, sizeof(cl->commandbuffer)-1 - cl->cmdbuflen, 0); if (ret == -1) { - if (qerrno == EWOULDBLOCK) + int e = neterrno(); + if (e == NET_EWOULDBLOCK) return false; //remove - if (qerrno == ECONNABORTED || qerrno == ECONNRESET) + if (e == NET_ECONNABORTED || e == NET_ECONNRESET) return true; - Con_Printf ("NET_GetPacket: %s\n", strerror(qerrno)); + Con_Printf ("NET_GetPacket: %s\n", strerror(e)); return true; } if (*cl->messagebuffer) @@ -583,12 +584,12 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) if ((cl->datasock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - Sys_Error ("FTP_ServerThinkForConnection: socket: %s", strerror(qerrno)); + Sys_Error ("FTP_ServerThinkForConnection: socket: %s", strerror(neterrno())); } if (ioctlsocket (cl->datasock, FIONBIO, (u_long *)&_true) == -1) { - Sys_Error ("FTP_ServerThinkForConnection: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("FTP_ServerThinkForConnection: ioctl FIONBIO: %s", strerror(neterrno())); } from.sin_family = AF_INET; @@ -629,7 +630,7 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) struct sockaddr_qstorage adr; int adrlen = sizeof(adr); temp = accept(cl->datasock, (struct sockaddr *)&adr, &adrlen); - err = qerrno; + err = neterrno(); closesocket(cl->datasock); cl->datasock = temp; cl->dataislisten = false; @@ -690,7 +691,7 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) if (cl->datasock == INVALID_SOCKET) { - QueueMessageva (cl, "425 Can't accept pasv data connection - %i.\r\n", qerrno); + QueueMessageva (cl, "425 Can't accept pasv data connection - %i.\r\n", neterrno()); continue; } else @@ -779,7 +780,7 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl) if (cl->datasock == INVALID_SOCKET) { - QueueMessageva (cl, "425 Can't accept pasv data connection - %i.\r\n", qerrno); + QueueMessageva (cl, "425 Can't accept pasv data connection - %i.\r\n", neterrno()); continue; } else @@ -885,7 +886,7 @@ iwboolean FTP_ServerRun(iwboolean ftpserverwanted, int port) FTPclient_t *cl, *prevcl; struct sockaddr_qstorage from; int fromlen; - int clientsock; + SOCKET clientsock; unsigned long _true = true; if (!ftpserverinitied) @@ -949,23 +950,24 @@ unsigned long _true = true; if (clientsock == INVALID_SOCKET) { - if (qerrno == EWOULDBLOCK) + int e = neterrno(); + if (e == NET_EWOULDBLOCK) return false; - if (qerrno == ECONNABORTED || qerrno == ECONNRESET) + if (e == NET_ECONNABORTED || e == NET_ECONNRESET) { Con_TPrintf ("Connection lost or aborted\n"); return false; } - Con_Printf ("NET_GetPacket: %s\n", strerror(qerrno)); + Con_Printf ("NET_GetPacket: %s\n", strerror(e)); return false; } if (ioctlsocket (clientsock, FIONBIO, &_true) == -1) { - IWebPrintf ("FTP_ServerRun: blocking error: %s\n", strerror(qerrno)); + IWebPrintf ("FTP_ServerRun: blocking error: %s\n", strerror(neterrno())); return false; } cl = IWebMalloc(sizeof(FTPclient_t)); diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index 1cd6b2b2d..5a504e587 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -338,7 +338,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl) if (ammount < 0) { - if (qerrno != EWOULDBLOCK) + if (neterrno() != NET_EWOULDBLOCK) return false; return true; } @@ -358,7 +358,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl) return false; if (ammount < 0) { - if (qerrno != EWOULDBLOCK) + if (neterrno() != NET_EWOULDBLOCK) return false; return true; } @@ -554,7 +554,7 @@ static qboolean HTTP_DL_Work(struct dl_download *dl) ammount = recv(con->sock, con->buffer+con->bufferused, con->bufferlen-con->bufferused-1, 0); if (ammount < 0) { - if (qerrno != EWOULDBLOCK) + if (neterrno() != NET_EWOULDBLOCK) return false; return true; } @@ -1029,7 +1029,7 @@ void QDECL VFSPIPE_Close(vfsfile_t *f) free(p->data); free(p); } -unsigned long QDECL VFSPIPE_GetLen(vfsfile_t *f) +qofs_t QDECL VFSPIPE_GetLen(vfsfile_t *f) { vfspipe_t *p = (vfspipe_t*)f; return p->writepos - p->readpos; diff --git a/engine/http/httpserver.c b/engine/http/httpserver.c index 2fb0211d2..883921e31 100644 --- a/engine/http/httpserver.c +++ b/engine/http/httpserver.c @@ -133,14 +133,14 @@ qboolean HTTP_ServerInit(int port) if ((httpserversocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - IWebPrintf ("HTTP_ServerInit: socket: %s\n", strerror(qerrno)); + IWebPrintf ("HTTP_ServerInit: socket: %s\n", strerror(neterrno())); httpserverfailed = true; return false; } if (ioctlsocket (httpserversocket, FIONBIO, &_true) == -1) { - IWebPrintf ("HTTP_ServerInit: ioctl FIONBIO: %s\n", strerror(qerrno)); + IWebPrintf ("HTTP_ServerInit: ioctl FIONBIO: %s\n", strerror(neterrno())); httpserverfailed = true; return false; } @@ -305,7 +305,7 @@ void HTTP_RunExisting (void) ammount = recv(cl->datasock, cl->inbuffer+cl->inbufferused, ammount, 0); if (ammount < 0) { - if (qerrno != EWOULDBLOCK) //they closed on us. Assume end. + if (neterrno() != NET_EWOULDBLOCK) //they closed on us. Assume end. { cl->closereason = "recv error"; } @@ -622,8 +622,8 @@ notimplemented: if (ammount == -1) { - localerrno = qerrno; - if (localerrno != EWOULDBLOCK) + localerrno = neterrno(); + if (localerrno != NET_EWOULDBLOCK) { cl->closereason = "some error when sending"; } @@ -698,26 +698,27 @@ qboolean HTTP_ServerPoll(qboolean httpserverwanted, int portnum) //loop while tr if (clientsock == -1) { - if (qerrno == EWOULDBLOCK) + int e = neterrno(); + if (e == NET_EWOULDBLOCK) { HTTP_RunExisting(); return false; } - if (qerrno == ECONNABORTED || qerrno == ECONNRESET) + if (e == NET_ECONNABORTED || e == NET_ECONNRESET) { Con_TPrintf ("Connection lost or aborted\n"); return false; } - Con_Printf ("NET_GetPacket: %s\n", strerror(qerrno)); + Con_Printf ("NET_GetPacket: %s\n", strerror(e)); return false; } if (ioctlsocket (clientsock, FIONBIO, (u_long *)&_true) == -1) { - IWebPrintf ("HTTP_ServerInit: ioctl FIONBIO: %s\n", strerror(qerrno)); + IWebPrintf ("HTTP_ServerInit: ioctl FIONBIO: %s\n", strerror(neterrno())); closesocket(clientsock); return false; } diff --git a/engine/http/webgen.c b/engine/http/webgen.c index 6b85fadc5..72893a525 100644 --- a/engine/http/webgen.c +++ b/engine/http/webgen.c @@ -355,7 +355,7 @@ int QDECL VFSGen_WriteBytes(vfsfile_t *f, const void *buffer, int bytes) return 0; } -qboolean QDECL VFSGen_Seek(vfsfile_t *f, unsigned long newpos) +qboolean QDECL VFSGen_Seek(vfsfile_t *f, qofs_t newpos) { vfsgen_t *g = (vfsgen_t*)f; if (newpos < 0 || newpos >= g->buffer->len) @@ -366,13 +366,13 @@ qboolean QDECL VFSGen_Seek(vfsfile_t *f, unsigned long newpos) return true; } -unsigned long QDECL VFSGen_Tell(vfsfile_t *f) +qofs_t QDECL VFSGen_Tell(vfsfile_t *f) { vfsgen_t *g = (vfsgen_t*)f; return g->pos; } -unsigned long QDECL VFSGen_GetLen(vfsfile_t *f) +qofs_t QDECL VFSGen_GetLen(vfsfile_t *f) { vfsgen_t *g = (vfsgen_t*)f; return g->buffer->len; diff --git a/engine/nacl/fs_ppapi.c b/engine/nacl/fs_ppapi.c index 9de949d17..0cb7ff216 100644 --- a/engine/nacl/fs_ppapi.c +++ b/engine/nacl/fs_ppapi.c @@ -201,18 +201,18 @@ static int VFSMEM_WriteBytes (struct vfsfile_s *file, const void *buffer, int by // Sys_Printf("written: %i, file is now at %i\n", total, f->offset); return total; } -static qboolean VFSMEM_Seek (struct vfsfile_s *file, unsigned long pos) +static qboolean VFSMEM_Seek (struct vfsfile_s *file, qofs_t pos) { vfsmfile_t *f = (vfsmfile_t*)file; f->offset = pos; return true; } -static unsigned long VFSMEM_Tell (struct vfsfile_s *file) +static qofs_t VFSMEM_Tell (struct vfsfile_s *file) { vfsmfile_t *f = (vfsmfile_t*)file; return f->offset; } -static unsigned long VFSMEM_GetSize (struct vfsfile_s *file) +static qofs_t VFSMEM_GetSize (struct vfsfile_s *file) { vfsmfile_t *f = (vfsmfile_t*)file; return f->file->length; @@ -395,7 +395,7 @@ static void FSPPAPI_ClosePath(searchpathfuncs_t *handle) Z_Free(handle); } -int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { int rootlen = strlen(rootpath); char *sub; @@ -418,13 +418,13 @@ int Sys_EnumerateFiles (const char *rootpath, const char *match, int (*func)(con } return true; } -static int FSPPAPI_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm) +static int FSPPAPI_EnumerateFiles (searchpathfuncs_t *handle, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm) { pppath_t *sp = (void*)handle; return Sys_EnumerateFiles(sp->rootpath, match, func, parm, handle); } -static int FSPPAPI_RebuildFSHash(const char *filename, int filesize, void *data, searchpathfuncs_t *handle) +static int FSPPAPI_RebuildFSHash(const char *filename, qofs_t filesize, void *data, searchpathfuncs_t *handle) { pppath_t *sp = (void*)handle; void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle) = data; @@ -571,13 +571,13 @@ static int VFSPPAPI_WriteBytes (struct vfsfile_s *file, const void *buffer, int intfile->offset += res; return res; } -static qboolean VFSPPAPI_Seek (struct vfsfile_s *file, unsigned long pos) +static qboolean VFSPPAPI_Seek (struct vfsfile_s *file, qofs_t pos) { vfsppapifile_t *intfile = (vfsppapifile_t*)file; intfile->offset = pos; return true; } -static unsigned long VFSPPAPI_Tell (struct vfsfile_s *file) +static qofs_t VFSPPAPI_Tell (struct vfsfile_s *file) { vfsppapifile_t *intfile = (vfsppapifile_t*)file; return intfile->offset; @@ -587,7 +587,7 @@ static void VFSPPAPI_Flush(struct vfsfile_s *file) vfsppapifile_t *intfile = (vfsppapifile_t*)file; ppb_fileio->Flush(intfile->handle, nullccb); } -static unsigned long VFSPPAPI_GetSize (struct vfsfile_s *file) +static qofs_t VFSPPAPI_GetSize (struct vfsfile_s *file) { vfsppapifile_t *intfile = (vfsppapifile_t*)file; struct PP_FileInfo fileinfo; @@ -710,7 +710,7 @@ static void FSPPAPI_ClosePath(searchpathfuncs_t *handle) { Z_Free(handle); } -static int FSPPAPI_RebuildFSHash(const char *filename, int filesize, void *data) +static int FSPPAPI_RebuildFSHash(const char *filename, qofs_t filesize, void *data) { if (filename[strlen(filename)-1] == '/') { //this is actually a directory diff --git a/engine/nacl/gl_vidppapi.c b/engine/nacl/gl_vidppapi.c index c027dd130..191503b12 100644 --- a/engine/nacl/gl_vidppapi.c +++ b/engine/nacl/gl_vidppapi.c @@ -17,7 +17,7 @@ extern PPB_Instance* instance_interface; int delayedswap = false; qboolean swappending; -extern cvar_t _vid_wait_override; +extern cvar_t vid_vsync; void FrameEvent(void* user_data, int32_t result); qboolean NAGL_SwapPending(void) @@ -49,7 +49,7 @@ void GL_DoSwap(void) { if (delayedswap) { - qboolean vsync = _vid_wait_override.ival || !*_vid_wait_override.string; + qboolean vsync = vid_vsync.ival || !*vid_vsync.string; struct PP_CompletionCallback ccb = { swap_callback, NULL, vsync?PP_COMPLETIONCALLBACK_FLAG_NONE:PP_COMPLETIONCALLBACK_FLAG_OPTIONAL}; glFlush(); delayedswap = false; @@ -63,7 +63,7 @@ void GL_DoSwap(void) break; case PP_ERROR_INPROGRESS: Con_DPrintf("chrome still can't handle vid_wait 0. forcing vsync\n"); - _vid_wait_override.ival = 1; + vid_vsync.ival = 1; break; default: Con_DPrintf("unknown error on SwapBuffers call\n"); diff --git a/engine/nacl/sys_ppapi.c b/engine/nacl/sys_ppapi.c index 7dfe30fc8..77f8c6358 100644 --- a/engine/nacl/sys_ppapi.c +++ b/engine/nacl/sys_ppapi.c @@ -172,7 +172,7 @@ void INS_Shutdown(void) /* //nacl supposedly has no way to implement this (other than us writing a listfile in each directory) -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *), void *parm) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *), void *parm) { return 0; } diff --git a/engine/partcfgs/high.cfg b/engine/partcfgs/high.cfg index 7c65b8665..011e8fca2 100644 --- a/engine/partcfgs/high.cfg +++ b/engine/partcfgs/high.cfg @@ -213,12 +213,11 @@ r_part te_explosion scalefactor 1 scaledelta -15 randomvel 0 - - lightradius 350 - lightrgb 1.4 1.2 1.05 - lighttime 0.5 - lightradiusfade 350 - lightrgbfade 2 2 2 +// lightradius 350 +// lightrgb 1.4 1.2 1.05 +// lighttime 0.5 +// lightradiusfade 350 +// lightrgbfade 2 2 2 } //smoke r_part +te_explosion @@ -261,7 +260,7 @@ r_part +te_explosion } //hide lights in explosions. -r_explosionlight 0 +//r_explosionlight 0 //hide the explosion sprite in nq+qw - WARNING: some mods use this sprite as a flame thrower. cl_expsprite 0 diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 35fc71bb6..ae9aa04a5 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -2309,7 +2309,9 @@ char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, int maxsize, fdef_t *d; int *v; unsigned int i;unsigned int j; - char *name; + char *name, *mname; + char *classname = NULL; + int classnamelen = 0; int type; // if (ed->free) @@ -2338,6 +2340,40 @@ char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, int maxsize, if (j == type_size[type]) continue; + if (strstr(name, "::")) + { + if (*name != ':') + continue; //don't directly generate anything from class::foo + + if (!classname) + { + fdef_t *cnfd; + cnfd = ED_FindField(progfuncs, "classname"); + if (cnfd) + { + string_t *v; + v = (string_t *)((char *)edvars(ed) + cnfd->ofs*4); + classname = PR_StringToNative(&progfuncs->funcs, *v); + } + else + classname = ""; + classnamelen = strlen(classname); + } + for (j = i+1; j < prinst.numfields; j++) + { + if (prinst.field[j].ofs == d->ofs) + { + mname = prinst.field[j].name; + if (!strncmp(mname, classname, classnamelen) && mname[classnamelen] == ':') + { + //okay, we have a match... + name = prinst.field[j].name; + break; + } + } + } + } + //add it to the file AddS("\""); AddS(name); AddS("\" \""); AddS(PR_UglyValueString(&progfuncs->funcs, d->type, (eval_t *)v)); AddS("\"\n"); } diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 1a9259eea..99e5800c3 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -90,7 +90,7 @@ struct pubprogfuncs_s struct progstate_s **progstate; //internal to the library. - func_t (PDECL *FindFunction) (pubprogfuncs_t *prinst, char *funcname, progsnum_t num); + func_t (PDECL *FindFunction) (pubprogfuncs_t *prinst, const char *funcname, progsnum_t num); int (PDECL *StartCompile) (pubprogfuncs_t *prinst, int argv, char **argc); //1 if can compile, 0 if failed to compile int (PDECL *ContinueCompile) (pubprogfuncs_t *prinst); //2 if finished, 1 if more to go, 0 if failed diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 772e0047b..ce44182ca 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4932,6 +4932,16 @@ void QCC_PR_EmitClassFromFunction(QCC_def_t *scope, QCC_type_t *basetype) ed = QCC_PR_GetDef(type_entity, "self", NULL, true, 0, false); + { + QCC_def_t *fclassname = QCC_PR_GetDef(NULL, "classname", NULL, false, 0, false); + if (fclassname) + { + QCC_def_t *point = QCC_PR_Statement(&pr_opcodes[OP_ADDRESS], ed, fclassname, NULL); + type_pointer->aux_type = type_string; + QCC_PR_Statement(&pr_opcodes[OP_STOREP_FNC], QCC_MakeStringConst(basetype->name), point, NULL); + } + } + QCC_PR_EmitClassFunctionTable(basetype, basetype, ed); //FIXME: these constructors are called in the wrong order diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 8956525e0..f47d9c869 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -1319,7 +1319,7 @@ void QCC_PR_LexString (void) void QCC_PR_LexString (void) { int c; - int len; + int len = 0; char *end, *cnst; int raw; char rawdelim[64]; @@ -1356,6 +1356,18 @@ void QCC_PR_LexString (void) rawdelim[raw++] = c; } rawdelim[raw++] = '\"'; + + //these two conditions are generally part of the C preprocessor. + if (!strncmp(pr_file_p, "\\\r\n", 3)) + { //dos format + pr_file_p += 3; + pr_source_line++; + } + else if (!strncmp(pr_file_p, "\\\r", 2) || !strncmp(pr_file_p, "\\\n", 2)) + { //mac + unix format + pr_file_p += 2; + pr_source_line++; + } } else if (*pr_file_p == '\"') pr_file_p++; @@ -1365,14 +1377,13 @@ void QCC_PR_LexString (void) break; first = false; - len = 0; for(;;) { c = *pr_file_p++; if (!c) QCC_PR_ParseError (ERR_EOF, "EOF inside quote"); - //these two conditions are generally part of the C preprocessor. +/* //these two conditions are generally part of the C preprocessor. if (c == '\\' && *pr_file_p == '\r' && pr_file_p[1] == '\n') { //dos format pr_file_p += 2; @@ -1385,10 +1396,10 @@ void QCC_PR_LexString (void) pr_source_line++; continue; } - +*/ if (raw) { - //raw strings contain very little parsing. just delimiter and \NL support. + //raw strings contain very little parsing. just delimiter and initial \NL support. if (c == rawdelim[0] && !strncmp(pr_file_p, rawdelim+1, raw-1)) { pr_file_p += raw-1; diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 02fc860df..7f1e3d349 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -580,11 +580,16 @@ void QCC_InitData (void) qcc_sourcefile = NULL; memset(stringtablist, 0, sizeof(stringtablist)); - numstatements = 1; - strofs = 2; - numfunctions = 1; - numglobaldefs = 1; - numfielddefs = 1; + numstatements = 1; //first statement should be an OP_DONE, matching the null function(ish), in case it somehow doesn't get caught by the vm. + strofs = 2; //null, empty, *other stuff* + numfunctions = 1; //first function is a null function. + numglobaldefs = 1; //first globaldef is a null def. just because. doesn't include parms+ret. is there any point to this? + + numfielddefs = 0; + fields[numfielddefs].type = ev_void; + fields[numfielddefs].s_name = 0; //should map to null + fields[numfielddefs].ofs = 0; + numfielddefs++; //FIXME: do we actually need a null field? is there any point to this at all? memset(&ret_temp, 0, sizeof(ret_temp)); @@ -3478,10 +3483,14 @@ void QCC_ContinueCompile(void) if (newstylesource) { + char *ofp = pr_file_p; do { new_QCC_ContinueCompile(); } while(currentchunk); //while parsing through preprocessor, make sure nothing gets hurt. + if (ofp == pr_file_p && qcc_compileactive && pr_token_type != tt_eof) + QCC_Error (ERR_INTERNAL, "Syntax error\n"); + return; } diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 4ed2bd808..7a98a5adb 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -1290,8 +1290,6 @@ void NPP_NQWriteAngle(int dest, float in) //replacement write func (nq to qw) } void NPP_NQWriteCoord(int dest, float in) //replacement write func (nq to qw) { - short datas = (int)(in*8); - float dataf = in; NPP_NQCheckDest(dest); if (!bufferlen) Con_Printf("NQWriteCoord: Messages should start with WriteByte\n"); @@ -1323,11 +1321,15 @@ void NPP_NQWriteCoord(int dest, float in) //replacement write func (nq to qw) if (destprim->coordsize==4) { + float dataf = in; + dataf = LittleFloat(dataf); NPP_AddData(&dataf, sizeof(float)); } else { + short datas = (int)(in*8); + datas = LittleShort(datas); NPP_AddData(&datas, sizeof(short)); } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index a33d4a76c..aa0777625 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9352,6 +9352,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"hash_getkey", PF_hash_getkey, 0, 0, 0, 292, D("string(float table, float idx)", "gets some random key name. add+delete can change return values of this, so don't blindly increment the key index if you're removing all.")}, {"hash_getcb", PF_hash_getcb, 0, 0, 0, 293, D("void(float table, void(string keyname, __variant val) callback, optional string name)", "For each item in the table that matches the name, call the callback. if name is omitted, will enumerate ALL keys.")}, {"checkcommand", PF_checkcommand, 0, 0, 0, 294, D("float(string name)", "Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist.")}, + {"argescape", PF_argescape, 0, 0, 0, 295, D("string(string s)", "Marks up a string so that it can be reliably tokenized as a single argument later.")}, {"clearscene", PF_Fixme, 0, 0, 0, 300, D("void()", "Forgets all rentities, polygons, and temporary dlights. Resets all view properties to their default values.")},// (EXT_CSQC) @@ -9675,9 +9676,10 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs // {"bufstr_find", PF_Fixme, 0, 0, 0, 537, "float(float bufhandle, string match, float matchrule, float startpos)"}, // {"matchpattern", PF_Fixme, 0, 0, 0, 538, "float(string s, string pattern, float matchrule)"}, // {"undefined", PF_Fixme, 0, 0, 0, 539, ""}, - {"physics_enable", PF_Ignore, 0, 0, 0, 540, "void(entity e, float physics_enabled)" STUB}, - {"physics_addforce",PF_Ignore, 0, 0, 0, 541, "void(entity e, vector force, vector relative_ofs)" STUB}, - {"physics_addtorque",PF_Ignore, 0, 0, 0, 542, "void(entity e, vector torque)" STUB}, + + {"physics_enable", PF_physics_enable, 0, 0, 0, 540, D("void(entity e, float physics_enabled)", "Enable or disable the physics attached to a MOVETYPE_PHYSICS entity. Entities which have been disabled in this way will stop taking so much cpu time.")}, + {"physics_addforce",PF_physics_addforce,0, 0, 0, 541, D("void(entity e, vector force, vector relative_ofs)", "Apply some impulse directional force upon a MOVETYPE_PHYSICS entity.")}, + {"physics_addtorque",PF_physics_addtorque,0, 0, 0, 542, D("void(entity e, vector torque)", "Apply some impulse rotational force upon a MOVETYPE_PHYSICS entity.")}, {"setkeydest", PF_Fixme, 0, 0, 0, 601, "void(float dest)"}, {"getkeydest", PF_Fixme, 0, 0, 0, 602, "float()"}, @@ -10529,6 +10531,11 @@ void PR_DumpPlatform_f(void) {"VF_SCREENPSIZE", "const float", CS, "Provides a reliable way to retrieve the current physical screen size (cvars need vid_restart for them to take effect).", VF_SCREENPSIZE}, {"VF_VIEWENTITY", "const float", CS, "Changes the RF_EXTERNALMODEL flag on entities to match the new selection, and removes entities flaged with RF_VIEWENTITY. Requires cunning use of .entnum and typically requires calling addentities(MASK_VIEWMODEL) too.", VF_VIEWENTITY}, + {"VF_RT_DESTCOLOUR", "const float", CS, "The FrameBuffer texture index to write colour info into. 1-based. Additional arguments are: format (rgba8=1,rgba16f=2,rgba32f=3), sizexy. Written to by both 3d and 2d rendering.", VF_RT_DESTCOLOUR}, + {"VF_RT_SOURCECOLOUR", "const float", CS, "The FrameBuffer texture index to use with shaders that specify a $sourcecolour map.", VF_RT_SOURCECOLOUR}, + {"VF_RT_DEPTH", "const float", CS, "The FrameBuffer texture index to use as a depth buffer. Also used for shaders that specify $sourcedepth. 1-based. Additional arguments are: format (16=4,24=5,32=6), sizexy.", VF_RT_DEPTH}, + {"VF_RT_RIPPLE", "const float", CS, "The FrameBuffer texture index to use as a ripplemap (target for shaders with 'sort ripple'). Also used for shaders that specify $ripplemap. 1-based. Additional arguments are: format, sizexy.", VF_RT_RIPPLE}, + {"RF_VIEWMODEL", "const float", CS, "Specifies that the entity is a view model, and that its origin is relative to the current view position. These entities are also subject to viewweapon bob.", CSQCRF_VIEWMODEL}, {"RF_EXTERNALMODEL", "const float", CS, "Specifies that this entity should be displayed in mirrors (and may still cast shadows), but will not otherwise be visible.", CSQCRF_EXTERNALMODEL}, {"RF_DEPTHHACK", "const float", CS, "Hacks the depth values such that the entity uses depth values as if it were closer to the screen. This is useful when combined with viewmodels to avoid weapons poking in to walls.", CSQCRF_DEPTHHACK}, diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 8b235914e..9745d1d34 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -207,6 +207,7 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldvector(gravitydir,NULL)\ comfieldfunction(camera_transform,".vector(vector org, vector ang)", NULL)\ comfieldfloat(pmove_flags,NULL)/*EXT_CSQC_1*/\ + comfieldfloat(geomtype,NULL)/*DP_...PHYSICS*/\ comfieldfloat(friction,NULL)/*DP_...PHYSICS*/\ comfieldfloat(erp,NULL)/*DP_...PHYSICS*/\ comfieldfloat(jointtype,NULL)/*DP_...PHYSICS*/\ @@ -240,21 +241,21 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldvector(color,NULL)/*Hexen2 has a .float color, the warnings should be benign*/ \ comfieldfloat(light_lev,NULL)\ comfieldfloat(style,NULL)\ - comfieldfloat(pflags,NULL)\ + comfieldfloat(pflags,"Realtime lighting flags")\ comfieldfloat(clientcolors,NULL)\ - comfieldfloat(dimension_see,NULL)/*EXT_DIMENSION_VISIBLE*/\ - comfieldfloat(dimension_seen,NULL)/*EXT_DIMENSION_VISIBLE*/\ - comfieldfloat(dimension_ghost,NULL)/*EXT_DIMENSION_GHOST*/\ - comfieldfloat(dimension_ghost_alpha,NULL)/*EXT_DIMENSION_GHOST*/\ + comfieldfloat(dimension_see,"This is the dimension mask (bitfield) that the client is allowed to see. Entities and events not in this dimension mask will be invisible.")/*EXT_DIMENSION_VISIBLE*/\ + comfieldfloat(dimension_seen,"This is the dimension mask (bitfield) that the client is visible within. Clients that cannot see this dimension mask will not see this entity.")/*EXT_DIMENSION_VISIBLE*/\ + comfieldfloat(dimension_ghost,"If this entity is visible only within these dimensions, it will become transparent, as if a ghost.")/*EXT_DIMENSION_GHOST*/\ + comfieldfloat(dimension_ghost_alpha,"If this entity is subject to dimension_ghost, this is the scaler for its alpha value. If 0, 0.5 will be used instead.")/*EXT_DIMENSION_GHOST*/\ comfieldfloat(playerclass,NULL)/*hexen2 requirements*/\ comfieldfloat(drawflags,NULL)/*hexen2*/\ comfieldfloat(hasted,NULL)/*hexen2 uses this AS WELL as maxspeed*/\ comfieldfloat(light_level,NULL)/*hexen2's grabbing light level from client*/\ - comfieldfloat(abslight,NULL)/*hexen2's force a lightlevel*/\ + comfieldfloat(abslight,"Allows overriding light levels. Use drawflags to state that this field should actually be used.")/*hexen2's force a lightlevel*/\ comfieldfunction(SendEntity, ".float(entity playerent, float changedflags)",NULL)/*EXT_CSQC*/\ comfieldfloat(SendFlags,NULL)/*EXT_CSQC_1 (one of the DP guys came up with it)*/\ - comfieldfloat(Version,NULL)/*EXT_CSQC (obsolete)*/\ - comfieldfloat(pvsflags,NULL)/*EXT_CSQC_1*/\ + comfieldfloat(Version,"Obsolete")/*EXT_CSQC (obsolete)*/\ + comfieldfloat(pvsflags,"Reconfigures when the entity is visible to clients")/*EXT_CSQC_1*/\ comfieldfloat(modelflags,NULL)\ comfieldfloat(uniquespawnid,NULL)/*FTE_ENT_UNIQUESPAWNID*/\ comfieldfunction(customizeentityforclient, ".float()",NULL) @@ -379,7 +380,7 @@ typedef struct int orientpeer; //ode info - int shape; + int geomshape; vec3_t dimensions; float mass; } odebodyinfo_t; @@ -411,6 +412,21 @@ typedef struct vec3_t axis, axis2; } odejointinfo_t; +typedef struct odecommandqueue_s +{ + struct odecommandqueue_s *next; + enum + { + ODECMD_ENABLE, + ODECMD_DISABLE, + ODECMD_FORCE, + ODECMD_TORQUE, + } command; + struct wedict_s *edict; + vec3_t v1; + vec3_t v2; +} odecommandqueue_t; + typedef struct { // physics parameters @@ -469,5 +485,7 @@ typedef struct // max velocity for a 1-unit radius object at current step to prevent // missed collisions vec_t ode_movelimit; + odecommandqueue_t *cmdqueuehead; + odecommandqueue_t *cmdqueuetail; } worldode_t; #endif diff --git a/engine/server/server.h b/engine/server/server.h index 860cf0794..926da70a7 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -834,7 +834,7 @@ typedef struct #define SOLID_BSP 4 // bsp clip, touch on edge, block #define SOLID_PHASEH2 5 #define SOLID_CORPSE 5 -#define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER +#define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER. deprecated. use solid_bsp and skin=-16 #define DAMAGE_NO 0 #define DAMAGE_YES 1 @@ -1266,7 +1266,11 @@ void SV_ConSay_f(void); //this header gives supported version numbers and stuff typedef struct mvdpendingdest_s { qboolean error; //disables writers, quit ASAP. +#ifdef _WIN32 + qintptr_t socket; +#else int socket; +#endif char inbuffer[2048]; char outbuffer[2048]; diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index a8561cfb7..db5a3a507 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -374,7 +374,7 @@ void SV_Give_f (void) } } -int QDECL ShowMapList (const char *name, int flags, void *parm, searchpathfuncs_t *spath) +int QDECL ShowMapList (const char *name, qofs_t flags, void *parm, searchpathfuncs_t *spath) { if (name[5] == 'b' && name[6] == '_') //skip box models return true; @@ -630,10 +630,13 @@ void SV_Map_f (void) for (i=0, host_client = svs.clients ; icontroller == NULL) + { + if (ISNQCLIENT(host_client)) + SV_StuffcmdToClient(host_client, va("reconnect \"%s\"\n", level)); + else + SV_StuffcmdToClient(host_client, va("changing \"%s\"\n", level)); + } host_client->prespawn_stage = PRESPAWN_INVALID; host_client->prespawn_idx = 0; } @@ -1711,6 +1714,9 @@ void SV_SendServerInfoChange(char *key, const char *value) FOREACHCLIENT(i, cl) { + if (cl->controller) + continue; + if (ISQWCLIENT(cl)) { ClientReliableWrite_Begin(cl, svc_serverinfo, strlen(key) + strlen(value)+3); diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 88f4a927e..8c4e3a9de 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -29,6 +29,17 @@ extern cvar_t sv_cullentities_trace; extern cvar_t sv_cullplayers_trace; extern cvar_t sv_nopvs; +#define SV_PVS_CAMERAS 16 +typedef struct +{ + int numents; + edict_t *ent[SV_PVS_CAMERAS]; //ents in this list are always sent, even if the server thinks that they are invisible. + vec3_t org[SV_PVS_CAMERAS]; + + qbyte pvs[(MAX_MAP_LEAFS+7)>>3]; +} pvscamera_t; + + /* ============================================================================= @@ -917,13 +928,13 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_ if (bits & 0x0000ff00) bits |= UF_EXTEND1; - MSG_WriteByte(msg, bits>>0); + MSG_WriteByte(msg, (bits>>0) & 0xff); if (bits & UF_EXTEND1) - MSG_WriteByte(msg, bits>>8); + MSG_WriteByte(msg, (bits>>8) & 0xff); if (bits & UF_EXTEND2) - MSG_WriteByte(msg, bits>>16); + MSG_WriteByte(msg, (bits>>16) & 0xff); if (bits & UF_EXTEND3) - MSG_WriteByte(msg, bits>>24); + MSG_WriteByte(msg, (bits>>24) & 0xff); if (bits & UF_FRAME) { @@ -1148,7 +1159,10 @@ void SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t client->sentents.max_entities = j; } while(j > client->sentents.num_entities) - client->pendingentbits[client->sentents.num_entities++] = UF_RESET|UF_RESET2; + { + client->sentents.entities[client->sentents.num_entities].number = 0; + client->sentents.num_entities++; + } } /*figure out the entitys+bits that changed (removed and active)*/ @@ -1986,32 +2000,37 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent) #endif -qboolean Cull_Traceline(edict_t *viewer, edict_t *seen) +qboolean Cull_Traceline(pvscamera_t *cameras, edict_t *seen) { int i; trace_t tr; - vec3_t start; vec3_t end; + int c; if (seen->v->solid == SOLID_BSP) return false; //bsp ents are never culled this way //stage 1: check against their origin - VectorAdd(viewer->v->origin, viewer->v->view_ofs, start); - tr.fraction = 1; - if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, start, seen->v->origin, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) - return false; //wasn't blocked + for (c = 0; c < cameras->numents; c++) + { + tr.fraction = 1; + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, cameras->org[c], seen->v->origin, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) + return false; //wasn't blocked + } //stage 2: check against their bbox - for (i = 0; i < 8; i++) + for (c = 0; c < cameras->numents; c++) { - end[0] = seen->v->origin[0] + ((i&1)?seen->v->mins[0]:seen->v->maxs[0]); - end[1] = seen->v->origin[1] + ((i&2)?seen->v->mins[1]:seen->v->maxs[1]); - end[2] = seen->v->origin[2] + ((i&4)?seen->v->mins[2]+0.1:seen->v->maxs[2]); + for (i = 0; i < 8; i++) + { + end[0] = seen->v->origin[0] + ((i&1)?seen->v->mins[0]:seen->v->maxs[0]); + end[1] = seen->v->origin[1] + ((i&2)?seen->v->mins[1]:seen->v->maxs[1]); + end[2] = seen->v->origin[2] + ((i&4)?seen->v->mins[2]+0.1:seen->v->maxs[2]); - tr.fraction = 1; - if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, start, end, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) - return false; //this trace went through, so don't cull + tr.fraction = 1; + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, 0, NULL, cameras->org[c], end, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr)) + return false; //this trace went through, so don't cull + } } return true; @@ -2109,7 +2128,7 @@ SV_WritePlayersToClient ============= */ -void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *clent, qbyte *pvs, sizebuf_t *msg) +void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *clent, pvscamera_t *cameras, sizebuf_t *msg) { qboolean isbot; int j; @@ -2304,13 +2323,13 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t * continue; // ignore if not touching a PV leaf - if (pvs && !sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &ent->pvsinfo, pvs)) + if (cameras && !sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &ent->pvsinfo, cameras->pvs)) continue; if (!((int)clent->xv->dimension_see & ((int)ent->xv->dimension_seen | (int)ent->xv->dimension_ghost))) continue; //not in this dimension - sorry... - if (sv_cullplayers_trace.value || sv_cullentities_trace.value) - if (Cull_Traceline(clent, ent)) + if (cameras && (sv_cullplayers_trace.value || sv_cullentities_trace.value)) + if (Cull_Traceline(cameras, ent)) continue; } @@ -2951,12 +2970,10 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli } if (state->effects & DPEF_LOWPRECISION) - state->effects &= DPEF_LOWPRECISION; //we don't support it, nor does dp any more. strip it. + state->effects &= ~DPEF_LOWPRECISION; //we don't support it, nor does dp any more. strip it. if (state->effects & EF_FULLBRIGHT) //wrap the field for fte clients (this is horrible) - { state->hexen2flags |= MLS_FULLBRIGHT; - } if (progstype != PROG_QW && state->effects && client && ISQWCLIENT(client)) //don't send extra nq effects to a qw client. { @@ -3046,11 +3063,11 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli #pragma warningmsg("TODO: Fix attachments for more vanilla clients") } -void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, edict_t *clent, qboolean ignorepvs) +void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t *cameras, edict_t *clent) { //pvs and clent can be null, but only if the other is also null int e, i; - edict_t *ent, *trackent, *tracecullent; + edict_t *ent, *tracecullent; //tracecullent is different from ent because attached models cull the parent instead. also, null for entities which are not culled. entity_state_t *state; #define DEPTHOPTIMISE #ifdef DEPTHOPTIMISE @@ -3061,22 +3078,11 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, globalvars_t *pr_globals = PR_globals(svprogfuncs, PR_CURRENT); int pvsflags; int limit; + int c, maxc = cameras?cameras->numents:0; - if (client->spectator) - trackent = EDICT_NUM(svprogfuncs, client->spec_track); - else if (clent) - trackent = PROG_TO_EDICT(svprogfuncs, clent->xv->view2); - else - trackent = NULL; - - if (client->viewent - #ifdef NQPROT - && ISQWCLIENT(client) - #endif - ) //this entity is watching from outside themselves. The client is tricked into thinking that they themselves are in the view ent, and a new dummy ent (the old them) must be spawned. - + //this entity is watching from outside themselves. The client is tricked into thinking that they themselves are in the view ent, and a new dummy ent (the old them) must be spawned. + if (client->viewent && ISQWCLIENT(client)) { - //FIXME: this hack needs cleaning up #ifdef DEPTHOPTIMISE distances[0] = 0; @@ -3153,21 +3159,26 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, } pvsflags = ent->xv->pvsflags; - if (ent->xv->viewmodelforclient) + for (c = 0; c < maxc; c++) + { + if (ent == cameras->ent[c]) + break; + } + if (c < maxc) + tracecullent = NULL; + else if (ent->xv->viewmodelforclient) { if (ent->xv->viewmodelforclient != (clent?EDICT_TO_PROG(svprogfuncs, clent):0)) continue; tracecullent = NULL; } - else if (ent == clent || ent == trackent) - tracecullent = NULL; else { // ignore ents without visible models if (!ent->xv->SendEntity && (!ent->v->modelindex || !*PR_GetString(svprogfuncs, ent->v->model)) && !((int)ent->xv->pflags & PFLAGS_FULLDYNAMIC) && ent->v->skin >= 0) continue; - if (pvs) //self doesn't get a pvs test, to cover teleporters + if (cameras) //self doesn't get a pvs test, to cover teleporters { if ((int)ent->v->effects & EF_NODEPTHTEST) tracecullent = NULL; @@ -3193,13 +3204,13 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, } else { - if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)tracecullent)->pvsinfo, pvs)) + if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)tracecullent)->pvsinfo, cameras->pvs)) continue; } } else { - if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, pvs)) + if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, cameras->pvs)) continue; tracecullent = ent; } @@ -3255,10 +3266,10 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, continue; //not in this dimension - sorry... - if (!ignorepvs && ent != clent && tracecullent && !((unsigned int)ent->v->effects & (EF_DIMLIGHT|EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_BRIGHTFIELD|EF_NODEPTHTEST))) + if (cameras && tracecullent && !((unsigned int)ent->v->effects & (EF_DIMLIGHT|EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_BRIGHTFIELD|EF_NODEPTHTEST))) { //more expensive culling if ((e <= sv.allocated_client_slots && sv_cullplayers_trace.value) || sv_cullentities_trace.value) - if (Cull_Traceline(clent, tracecullent)) + if (Cull_Traceline(cameras, tracecullent)) continue; } @@ -3339,36 +3350,49 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, qbyte *pvs, } } -qbyte *SV_Snapshot_SetupPVS(client_t *client, qbyte *pvs, unsigned int pvsbufsize) +void SV_AddCameraEntity(pvscamera_t *cameras, edict_t *ent, vec3_t viewofs) { + int i; vec3_t org; - int leavepvs = false; -/* - if (r_novis.ival) + + for (i = 0; i < cameras->numents; i++) { - memset(pvs, 0xff, (sv.world.worldmodel->numleafs+31)>>3); - return pvs; + if (cameras->ent[i] == ent) + return; //don't add the same ent multiple times (.view2 or portals that can see themselves through other portals). } -*/ + + if (viewofs) + VectorAdd (ent->v->origin, viewofs, org); + else + VectorCopy (ent->v->origin, org); + + sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org, cameras->pvs, sizeof(cameras->pvs), cameras->numents!=0); + if (cameras->numents < SV_PVS_CAMERAS) + { + cameras->ent[cameras->numents] = ent; + VectorCopy(org, cameras->org[cameras->numents]); + cameras->numents++; + } +} + +void SV_Snapshot_SetupPVS(client_t *client, pvscamera_t *camera) +{ + camera->numents = 0; for (; client; client = client->controlled) { - if (client->viewent) - { - edict_t *e = PROG_TO_EDICT(svprogfuncs, client->viewent); - VectorAdd (e->v->origin, client->edict->v->view_ofs, org); - } + if (client->viewent) //svc_viewentity hack + SV_AddCameraEntity(camera, EDICT_NUM(svprogfuncs, client->viewent), client->edict->v->view_ofs); else - VectorAdd (client->edict->v->origin, client->edict->v->view_ofs, org); - sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org, pvs, pvsbufsize, leavepvs); - leavepvs = true; + SV_AddCameraEntity(camera, client->edict, client->edict->v->view_ofs); -#ifdef PEXT_VIEW2 - if (client->edict->xv->view2) //add a second view point to the pvs - sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, PROG_TO_EDICT(svprogfuncs, client->edict->xv->view2)->v->origin, pvs, pvsbufsize, leavepvs); -#endif + //spectators should always see their targetted player + if (client->spec_track) + SV_AddCameraEntity(camera, EDICT_NUM(svprogfuncs, client->spec_track), client->edict->v->view_ofs); + + //view2 support should always see the extra entity + if (client->edict->xv->view2) + SV_AddCameraEntity(camera, PROG_TO_EDICT(svprogfuncs, client->edict->xv->view2), NULL); } - - return pvs; } void SV_Snapshot_Clear(packet_entities_t *pack) @@ -3388,11 +3412,10 @@ Builds a temporary q1 style entity packet for a q3 client */ void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack) { - qbyte pvsbuf[(MAX_MAP_LEAFS+7)>>3]; - qbyte *pvs; + pvscamera_t cameras; SV_Snapshot_Clear(pack); - pvs = SV_Snapshot_SetupPVS(client, pvsbuf, sizeof(pvsbuf)); - SV_Snapshot_BuildQ1(client, pack, pvs, client->edict, false); + SV_Snapshot_SetupPVS(client, &cameras); + SV_Snapshot_BuildQ1(client, pack, &cameras, client->edict); } /* @@ -3408,11 +3431,10 @@ svc_playerinfo messages void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs) { int e; - qbyte *pvs; packet_entities_t *pack; edict_t *clent; client_frame_t *frame; - qbyte pvsbuffer[(MAX_MAP_LEAFS+7)/8]; + pvscamera_t camerasbuf, *cameras = &camerasbuf; // this is the frame we are creating frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK]; @@ -3421,21 +3443,21 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore // find the client's PVS if (ignorepvs) - { + { //mvd... clent = NULL; - pvs = NULL; + cameras = NULL; } else { clent = client->edict; if (sv_nopvs.ival) - pvs = NULL; + cameras = NULL; #ifdef HLSERVER else if (svs.gametype == GT_HALFLIFE) pvs = SVHL_Snapshot_SetupPVS(client, pvsbuffer, sizeof(pvsbuffer)); #endif else - pvs = SV_Snapshot_SetupPVS(client, pvsbuffer, sizeof(pvsbuffer)); + SV_Snapshot_SetupPVS(client, cameras); } host_client = client; @@ -3468,7 +3490,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore SVHL_Snapshot_Build(client, pack, pvs, clent, ignorepvs); else #endif - SV_Snapshot_BuildQ1(client, pack, pvs, clent, ignorepvs); + SV_Snapshot_BuildQ1(client, pack, cameras, clent); } #ifdef NQPROT @@ -3534,7 +3556,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore if (client == &demo.recorder) SV_WritePlayersToMVD(client, frame, msg); else - SV_WritePlayersToClient (client, frame, clent, pvs, msg); + SV_WritePlayersToClient (client, frame, clent, cameras, msg); } SVQW_EmitPacketEntities (client, pack, msg); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 80b1a1b02..66d52a310 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -951,13 +951,17 @@ void SV_FullClientUpdate (client_t *client, client_t *to) if (ISQWCLIENT(to)) { + int ping = SV_CalcPing (client, false); + if (ping > 0xffff) + ping = 0xffff; + ClientReliableWrite_Begin(to, svc_updatefrags, 4); ClientReliableWrite_Byte (to, i); ClientReliableWrite_Short(to, client->old_frags); ClientReliableWrite_Begin (to, svc_updateping, 4); ClientReliableWrite_Byte (to, i); - ClientReliableWrite_Short (to, SV_CalcPing (client, false)); + ClientReliableWrite_Short (to, ping); ClientReliableWrite_Begin (to, svc_updatepl, 3); ClientReliableWrite_Byte (to, i); @@ -3817,6 +3821,7 @@ void SV_GetConsoleCommands (void) cmd = Sys_ConsoleInput (); if (!cmd) break; + Log_String(LOG_CONSOLE, cmd); Cbuf_AddText (cmd, RESTRICT_LOCAL); } } diff --git a/engine/server/sv_master.c b/engine/server/sv_master.c index bafada9d2..ea569b5bf 100644 --- a/engine/server/sv_master.c +++ b/engine/server/sv_master.c @@ -30,7 +30,7 @@ typedef struct svm_server_s { } svm_server_t; typedef struct { - int socketudp; + SOCKET socketudp; float time; int port; @@ -151,7 +151,7 @@ void SVM_Think(int port) net_message.cursize = recvfrom(svm.socketudp, net_message_buffer, sizeof(net_message_buffer)-1, 0, (struct sockaddr *)&addr, &addrlen); if (net_message.cursize <= 0) { - addrlen = qerrno; + addrlen = neterrno(); return; diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 852f60621..6d39f103d 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -152,8 +152,8 @@ void DestFlush(qboolean compleate) else { //error of some kind. would block or something int e; - e = qerrno; - if (e != EWOULDBLOCK) + e = neterrno(); + if (e != NET_EWOULDBLOCK) d->error = true; } } @@ -229,8 +229,8 @@ void SV_MVD_RunPendingConnections(void) else { //error of some kind. would block or something int e; - e = qerrno; - if (e != EWOULDBLOCK) + e = neterrno(); + if (e != NET_EWOULDBLOCK) p->error = true; } } @@ -550,9 +550,8 @@ void SV_MVD_RunPendingConnections(void) p->error = true; else { //error of some kind. would block or something - int e; - e = qerrno; - if (e != EWOULDBLOCK) + int e = neterrno(); + if (e != NET_EWOULDBLOCK) p->error = true; } } @@ -683,7 +682,7 @@ typedef struct #define SORT_NO 0 #define SORT_BY_DATE 1 -int QDECL Sys_listdirFound(const char *fname, int fsize, void *uptr, searchpathfuncs_t *spath) +int QDECL Sys_listdirFound(const char *fname, qofs_t fsize, void *uptr, searchpathfuncs_t *spath) { file_t *f; dir_t *dir = uptr; @@ -2107,20 +2106,20 @@ void SV_MVD_QTVReverse_f (void) if ((sock = socket (adrfam, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { - Con_Printf ("qtvreverse: socket: %s\n", strerror(qerrno)); + Con_Printf ("qtvreverse: socket: %s\n", strerror(neterrno())); return; } if (connect(sock, (void*)&remote, adrsz) == INVALID_SOCKET) { closesocket(sock); - Con_Printf ("qtvreverse: connect: %s\n", strerror(qerrno)); + Con_Printf ("qtvreverse: connect: %s\n", strerror(neterrno())); return; } if (ioctlsocket (sock, FIONBIO, (u_long *)&nonblocking) == INVALID_SOCKET) { closesocket(sock); - Con_Printf ("qtvreverse: ioctl FIONBIO: %s\n", strerror(qerrno)); + Con_Printf ("qtvreverse: ioctl FIONBIO: %s\n", strerror(neterrno())); return; } @@ -2130,7 +2129,7 @@ void SV_MVD_QTVReverse_f (void) if (send(sock, data, strlen(data), 0) == INVALID_SOCKET) { closesocket(sock); - Con_Printf ("qtvreverse: send: %s\n", strerror(qerrno)); + Con_Printf ("qtvreverse: send: %s\n", strerror(neterrno())); return; } @@ -2366,9 +2365,9 @@ void SV_MVDEasyRecord_f (void) } #ifdef HAVE_TCP -static int MVD_StreamStartListening(int port) +static SOCKET MVD_StreamStartListening(int port) { - int sock; + SOCKET sock; struct sockaddr_in address; // int fromlen; @@ -2383,12 +2382,12 @@ static int MVD_StreamStartListening(int port) if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { - Sys_Error ("MVD_StreamStartListening: socket: %s", strerror(qerrno)); + Sys_Error ("MVD_StreamStartListening: socket: %s", strerror(neterrno())); } if (ioctlsocket (sock, FIONBIO, (u_long *)&nonblocking) == INVALID_SOCKET) { - Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno)); + Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO: %s", strerror(neterrno())); } if( bind (sock, (void *)&address, sizeof(address)) == INVALID_SOCKET) @@ -2406,7 +2405,7 @@ static int MVD_StreamStartListening(int port) void SV_MVDStream_Poll(void) { #ifdef HAVE_TCP - static int listensocket=INVALID_SOCKET; + static SOCKET listensocket=INVALID_SOCKET; static int listenport; int _true = true; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 9a2a75c48..b7c4cec96 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -60,6 +60,8 @@ void SV_FlushRedirect (void) if (!*outputbuf) return; + Log_String(LOG_CONSOLE, va("{\n%s}\n", outputbuf)); + if (sv_redirected == RD_PACKET) { send[0] = 0xff; @@ -111,6 +113,8 @@ SV_BeginRedirect */ void SV_BeginRedirect (redirect_t rd, int lang) { + SV_FlushRedirect(); + sv_redirected = rd; sv_redirectedlang = lang; outputbuf[0] = 0; @@ -234,6 +238,9 @@ EVENT MESSAGES //Directly print to a client without translating nor printing into an mvd. generally for error messages due to the lack of mvd thing. void SV_PrintToClient(client_t *cl, int level, const char *string) { + if (cl->controller) + cl = cl->controller; + switch (cl->protocol) { case SCP_BAD: //bot @@ -385,7 +392,9 @@ void VARGS SV_BroadcastPrintf (int level, char *fmt, ...) if(strlen(string) >= sizeof(string)) Sys_Error("SV_BroadcastPrintf: Buffer stomped\n"); - Sys_Printf ("%s", string); // print to the console + //pretend to print on the server, but not to the client's console + Sys_Printf ("%s", string); // print to the system console + Log_String(LOG_CONSOLE, string); //dump into log for (i=0, cl = svs.clients ; i= sizeof(string)) Sys_Error("SV_BroadcastPrintf: Buffer stomped\n"); + //pretend to print on the server, but not to the client's console Sys_Printf ("%s", string); // print to the console + Log_String(LOG_CONSOLE, string); //dump into log for (i=0, cl = svs.clients ; iworldmodel->funcs.FindTouchedLeafs(w->worldmodel, &ent->pvsinfo, ent->v->absmin, ent->v->absmax); } -// if (ent->v->solid == SOLID_NOT) -// return; - // find the first node that the ent's box crosses node = w->areanodes; while (1) diff --git a/engine/web/sys_web.c b/engine/web/sys_web.c index 35d936eab..c3415494f 100644 --- a/engine/web/sys_web.c +++ b/engine/web/sys_web.c @@ -107,7 +107,7 @@ void Sys_Quit (void) exit (0); } -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, qofs_t, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { Con_DPrintf("Warning: Sys_EnumerateFiles not implemented\n"); return false; diff --git a/plugins/avplug/avdecode.c b/plugins/avplug/avdecode.c index f9543b679..036ee96ec 100644 --- a/plugins/avplug/avdecode.c +++ b/plugins/avplug/avdecode.c @@ -352,10 +352,16 @@ static void *AVDec_DisplayFrame(void *vctx, qboolean nosound, uploadfmt_t *fmt, { float *in = (void*)auddata; signed short *out = (void*)auddata; + int v; unsigned int i; for (i = 0; i < auddatasize/sizeof(*in); i++) { - out[i] = (short)(in[i]*32767); + v = (short)(in[i]*32767); + if (v < -32767) + v = -32767; + else if (v > 32767) + v = 32767; + out[i] = v; } auddatasize/=2; width = 2; diff --git a/plugins/berkelium/plugapi.cpp b/plugins/berkelium/plugapi.cpp index 07ed72b91..f19a15deb 100644 --- a/plugins/berkelium/plugapi.cpp +++ b/plugins/berkelium/plugapi.cpp @@ -439,7 +439,7 @@ extern "C" qintptr_t Plug_Init(qintptr_t *args) Con_Printf("Berkelium plugin failed: Engine doesn't support Shutdown feature\n"); return false; } - if (!Plug_ExportNative("Media_VideoDecoder", &decoderfuncs)) + if (!pPlug_ExportNative("Media_VideoDecoder", &decoderfuncs)) { Con_Printf("Berkelium plugin failed: Engine doesn't support media decoder plugins\n"); return false; diff --git a/plugins/mpq/fs_mpq.c b/plugins/mpq/fs_mpq.c index 2fd415ee8..3744dc0d6 100644 --- a/plugins/mpq/fs_mpq.c +++ b/plugins/mpq/fs_mpq.c @@ -90,9 +90,9 @@ typedef struct unsigned int flags; unsigned int encryptkey; mpqarchive_t *archive; - unsigned int foffset; - unsigned int flength; - unsigned int alength; + qofs_t foffset; + qofs_t flength; //decompressed size + qofs_t alength; //size on disk ofs_t archiveoffset; @@ -106,7 +106,7 @@ typedef struct static qboolean crypt_table_initialized = false; static unsigned int crypt_table[0x500]; -void mpq_init_cryptography(void) +static void mpq_init_cryptography(void) { // prepare crypt_table unsigned int seed = 0x00100001; @@ -140,7 +140,7 @@ void mpq_init_cryptography(void) #define HASH_NAME_A 1 #define HASH_NAME_B 2 #define HASH_KEY 3 -unsigned int mpq_hash_cstring(const char *string, unsigned int type) +static unsigned int mpq_hash_cstring(const char *string, unsigned int type) { unsigned int seed1 = 0x7FED7FED; unsigned int seed2 = 0xEEEEEEEE; @@ -167,7 +167,7 @@ unsigned int mpq_hash_cstring(const char *string, unsigned int type) #define MPQSwapInt32LittleToHost(a) (a) #define MPQSwapInt32HostToLittle(a) (a) -void mpq_decrypt(void* data, size_t length, unsigned int key, qboolean disable_output_swapping) +static void mpq_decrypt(void* data, size_t length, unsigned int key, qboolean disable_output_swapping) { unsigned int* buffer32 = (unsigned int*)data; unsigned int seed = 0xEEEEEEEE; @@ -213,7 +213,7 @@ void mpq_decrypt(void* data, size_t length, unsigned int key, qboolean disable_o #define HASH_TABLE_EMPTY 0xffffffff #define HASH_TABLE_DELETED 0xfffffffe -unsigned int mpq_lookuphash(mpqarchive_t *mpq, const char *filename, int locale) +static unsigned int mpq_lookuphash(mpqarchive_t *mpq, const char *filename, int locale) { unsigned int initial_position = mpq_hash_cstring(filename, HASH_POSITION) % mpq->hashentries; unsigned int current_position = initial_position; @@ -245,8 +245,8 @@ unsigned int mpq_lookuphash(mpqarchive_t *mpq, const char *filename, int locale) return HASH_TABLE_EMPTY; } -vfsfile_t *MPQ_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode); -void MPQ_ClosePath(searchpathfuncs_t *handle) +static vfsfile_t *MPQ_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode); +static void MPQ_ClosePath(searchpathfuncs_t *handle) { mpqarchive_t *mpq = (void*)handle; VFS_CLOSE(mpq->file); @@ -255,7 +255,7 @@ void MPQ_ClosePath(searchpathfuncs_t *handle) free(mpq->listfile); free(mpq); } -qboolean MPQ_FindFile(searchpathfuncs_t *handle, flocation_t *loc, const char *name, void *hashedresult) +static int MPQ_FindFile(searchpathfuncs_t *handle, flocation_t *loc, const char *name, void *hashedresult) { mpqarchive_t *mpq = (void*)handle; unsigned int blockentry; @@ -266,16 +266,16 @@ qboolean MPQ_FindFile(searchpathfuncs_t *handle, flocation_t *loc, const char *n if (block >= mpq->blockdata && block <= mpq->blockdata + mpq->blockentries) blockentry = (mpqblock_t*)block - mpq->blockdata; else - return false; + return FF_NOTFOUND; } else { unsigned int hashentry = mpq_lookuphash(mpq, name, 0); if (hashentry == HASH_TABLE_EMPTY) - return false; + return FF_NOTFOUND; blockentry = mpq->hashdata[hashentry].block_table_index; if (blockentry > mpq->blockentries) - return false; + return FF_NOTFOUND; } if (loc) { @@ -289,11 +289,11 @@ qboolean MPQ_FindFile(searchpathfuncs_t *handle, flocation_t *loc, const char *n if (mpq->blockdata[blockentry].flags & MPQFilePatch) { Con_DPrintf("Cannot cope with patch files\n"); - return false; + return FF_NOTFOUND; } - return true; + return FF_FOUND; } -void MPQ_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer) +static void MPQ_ReadFile(searchpathfuncs_t *handle, flocation_t *loc, char *buffer) { vfsfile_t *f; f = MPQ_OpenVFS(handle, loc, "rb"); @@ -343,7 +343,7 @@ static int mpqwildcmp(const char *wild, const char *string, char **end) } return !*wild; } -int MPQ_EnumerateFiles(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, int fsize, void *parm, searchpathfuncs_t *spath), void *parm) +static int MPQ_EnumerateFiles(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, void *parm, searchpathfuncs_t *spath), void *parm) { int ok = 1; char *s, *n; @@ -371,7 +371,7 @@ int MPQ_EnumerateFiles(searchpathfuncs_t *handle, const char *match, int (QDECL } return ok; } -void MPQ_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)) +static void MPQ_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)) { char *s, *n; char name[MAX_QPATH]; @@ -403,17 +403,17 @@ void MPQ_BuildHash(searchpathfuncs_t *handle, int depth, void (QDECL *AddFileHas } } -int MPQ_GeneratePureCRC (searchpathfuncs_t *handle, int seed, int usepure) +static int MPQ_GeneratePureCRC (searchpathfuncs_t *handle, int seed, int usepure) { return 0; } -qboolean MPQ_PollChanges(searchpathfuncs_t *handle) +static qboolean MPQ_PollChanges(searchpathfuncs_t *handle) { return false; } -searchpathfuncs_t *MPQ_OpenArchive(vfsfile_t *file, const char *desc) +static searchpathfuncs_t *MPQ_OpenArchive(vfsfile_t *file, const char *desc) { flocation_t lloc; mpqarchive_t *mpq; @@ -524,13 +524,13 @@ struct blastdata_s void *indata; unsigned int inlen; }; -unsigned mpqf_blastin(void *how, unsigned char **buf) +static unsigned mpqf_blastin(void *how, unsigned char **buf) { struct blastdata_s *args = how; *buf = args->indata; return args->inlen; } -int mpqf_blastout(void *how, unsigned char *buf, unsigned len) +static int mpqf_blastout(void *how, unsigned char *buf, unsigned len) { struct blastdata_s *args = how; if (len > args->outlen) @@ -540,7 +540,7 @@ int mpqf_blastout(void *how, unsigned char *buf, unsigned len) args->outlen -= len; return 0; } -void MPQF_decompress(qboolean legacymethod, void *outdata, unsigned int outlen, void *indata, unsigned int inlen) +static void MPQF_decompress(qboolean legacymethod, void *outdata, unsigned int outlen, void *indata, unsigned int inlen) { int ret; @@ -619,7 +619,7 @@ void MPQF_decompress(qboolean legacymethod, void *outdata, unsigned int outlen, } } -int MPQF_readbytes (struct vfsfile_s *file, void *buffer, int bytestoread) +static int MPQF_readbytes (struct vfsfile_s *file, void *buffer, int bytestoread) { int bytesread = 0; mpqfile_t *f = (mpqfile_t *)file; @@ -747,12 +747,12 @@ int MPQF_readbytes (struct vfsfile_s *file, void *buffer, int bytestoread) return bytesread; } -int MPQF_writebytes (struct vfsfile_s *file, const void *buffer, int bytestoread) +static int MPQF_writebytes (struct vfsfile_s *file, const void *buffer, int bytestoread) { // mpqfile_t *f = (mpqfile_t *)file; return 0; } -qboolean MPQF_seek (struct vfsfile_s *file, unsigned long pos) +static qboolean MPQF_seek (struct vfsfile_s *file, qofs_t pos) { mpqfile_t *f = (mpqfile_t *)file; if (pos > f->flength) @@ -760,17 +760,17 @@ qboolean MPQF_seek (struct vfsfile_s *file, unsigned long pos) f->foffset = pos; return true; } -unsigned long MPQF_tell (struct vfsfile_s *file) +static qofs_t MPQF_tell (struct vfsfile_s *file) { mpqfile_t *f = (mpqfile_t *)file; return f->foffset; } -unsigned long MPQF_getlen (struct vfsfile_s *file) +static qofs_t MPQF_getlen (struct vfsfile_s *file) { mpqfile_t *f = (mpqfile_t *)file; return f->flength; } -void MPQF_close (struct vfsfile_s *file) +static void MPQF_close (struct vfsfile_s *file) { mpqfile_t *f = (mpqfile_t *)file; if (f->buffer) @@ -779,11 +779,11 @@ void MPQF_close (struct vfsfile_s *file) free(f->sectortab); free(f); } -void MPQF_flush (struct vfsfile_s *file) +static void MPQF_flush (struct vfsfile_s *file) { } -qboolean MPQF_GetKey(unsigned int flags, unsigned int blockoffset, unsigned int blocksize, unsigned int *key) +static qboolean MPQF_GetKey(unsigned int flags, unsigned int blockoffset, unsigned int blocksize, unsigned int *key) { if (flags & MPQFileEncrypted) { @@ -798,7 +798,7 @@ qboolean MPQF_GetKey(unsigned int flags, unsigned int blockoffset, unsigned int return true; } -vfsfile_t *MPQ_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode) +static vfsfile_t *MPQ_OpenVFS(searchpathfuncs_t *handle, flocation_t *loc, const char *mode) { mpqarchive_t *mpq = (void*)handle; mpqblock_t *block = &mpq->blockdata[loc->index]; diff --git a/plugins/plugin.h b/plugins/plugin.h index e8c2db340..034b88e55 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -3,6 +3,11 @@ #ifdef FTEPLUGIN #include "quakedef.h" +#define QPREFIX +#endif + +#if !defined(NOQPREFIX) && !defined(QPREFIX) +#define QPREFIX #endif #ifdef Q3_VM @@ -83,7 +88,7 @@ typedef unsigned long quintptr_t; #endif -#ifndef FTEPLUGIN +#ifndef QPREFIX #define pPlug_GetEngineFunction Plug_GetEngineFunction #define pCon_Print Con_Print #define pCvar_GetFloat Cvar_GetFloat @@ -98,7 +103,7 @@ extern "C" { //DLLs need a wrapper to add the extra parameter and call a boring function. #define TEST -#ifdef FTEPLUGIN +#ifdef QPREFIX #define EBUILTIN(t, n, args) extern qintptr_t BUILTIN_##n; t p##n args #define BUILTINR(t, n, args) qintptr_t BUILTIN_##n; t p##n args {qintptr_t res; if (!BUILTINISVALID(n))pSys_Error("Builtin "#n" is not valid\n");res = plugin_syscall(BUILTIN_##n ARGNAMES); return *(t*)&res;} #define BUILTIN(t, n, args) qintptr_t BUILTIN_##n; t p##n args {if (!BUILTINISVALID(n))pSys_Error("Builtin "#n" is not valid\n");plugin_syscall(BUILTIN_##n ARGNAMES);} diff --git a/specs/particles.txt b/specs/particles.txt index c1e4fa1a2..146bbcb56 100644 --- a/specs/particles.txt +++ b/specs/particles.txt @@ -17,6 +17,21 @@ will give transparent (0.5) red particles that will fade to fully white when the they will spawn within a ball of 32 units radius. +Types: +Always try to include a type. The engine will guess what your particle is meant to be otherwise, based on textures and other nonsense. That stuff is generally unreliable, and probably not what you want. + +Chaining: +You can add multiple particle descriptions to a single effect. The first should be 'r_part foo', and the others should be 'r_part +foo'. Particles without a + will reset the chain. + +Effect naming: +Effects loaded by r_particledesc will be given an internal prefix, eg: foo.cfg. +If the gamecode explicitly states foo.bar, your foo.cfg will automatically be executed, and will automatically use the bar effect from it. +The effect can still be overriden from a custom config by explicitly naming the effect foo.bar - the effect bar in the config foo will not override this, but would override bar on its own. + +Scale: +scale values are defined in 1/4th qu, for some reason. +scalefactor typically needs to be explicitly set to 1. this value affects how the particle scales with distance from view, rather than the actual size of the particle. + texture @@ -42,7 +57,7 @@ beamtexspeed scale [max] particles will start with a diameter of this many quake units. - actual scale will be randomly chosen between min and max (max defaults to equal min is missing) + actual scale will be randomly chosen between min and max (max defaults to equal if min is missing) scalerand obsolete @@ -116,7 +131,7 @@ assoc inwater Specifies a replacement effect to use when this one is spawned underwater. - assoc used is the replacement effect. the assoc value from the replaced effect is ignored. + assoc used is the replacement effect. the assoc value from the replaced effect is ignored (this includes +foo chains). colorindex [rand] Specifies a palette index to spawn the particle with. @@ -200,8 +215,14 @@ blend spawnmode [arg1] [arg2] This affects how particles are positioned when they first spawn, and their initial velocities. for point effects, mode may be one of: - circle: particles spawn within a ball with uniform distance from the center + box: simple axially aligned box of particles. + circle: particles spawn within a ball with uniform distance from the center. none will appear in the middle. + arg1: percentage of the circle to cover. a value of 5 will go around the circle 5 separate times. this can be used for weird beam effects. + areaspread: the radius of the ball + areaspreadvert: the height of the ball. if 0, will be a flat circle ball: particles spawn randomly within a ball. + areaspread: the radius of the ball + areaspreadvert: the height of the ball. if 0, will be a flat circle. telebox: matches quake's telebox lavasplash: like chthon's lava splash uniformcircle: particles are spawned in a circle with uniform distance between and from the center. z=0. @@ -221,7 +242,7 @@ spawnparam2 obsolete. see spawnmode. up - the particle's origin is moved upwards by this amount + the particle's starting origin is moved upwards by this amount (worldspace). type How the particles look. @@ -229,8 +250,9 @@ type beam: valid only for trails. Particles form a single textured beam acting as nodes along it. spark: particles are lines, their length depending upon their speed. sparkfan: particles are non-planar triangle fans, their length depending upon their speed. - texturedspark: textured particles are aligned along their direction of movement, their length depending upon their speed. - decal: particles are spawned only upon bsp geometry. They are clipped by it. + texturedspark: textured particles are aligned along their direction of movement, their length depending upon their speed, width equal to their scale. + cdecal/decal: particles are spawned only upon bsp geometry. They are clipped by it. + udecal: unclipped decal. exact semantics are subject to change. *default*: Particles are regular, rotating, 2d images. isbeam @@ -271,3 +293,25 @@ nospreadfirst nospreadlast don't randomize org/vel for last generated particle + +sound [pitch] [delay] + When the effect is first spawned, the named sound will play with the given volume and attenuation at the center point. This may not work with all spawn methods, as it will ignore any count scales. + +lightradius +lightradiusfade +lightrgb +lightrgbfade +lighttime + Spawns a dlight when the effect is spawned. + dlight is removed when radius drops to 0 or the age is exceeded. + at this time it is not possible to override the corona/specular levels. + +lightcubemap + value 0 means no cubemap. + otherwise with eg cubemap 5, uses image files cubemaps/5ft.tga, cubemaps/5bk.tga, etc. + fixme: at the current time, the cubemap is world-aligned and cannot rotate. + +model + spawns sprites or models that fly away with random angles and run through some frame sequence. handy for simple gib effects. + +spawnstain \ No newline at end of file