From 5aa11ddbb1e04bbe9018ae0fbf8fc33283a0a095 Mon Sep 17 00:00:00 2001 From: Spoike Date: Fri, 12 Jun 2020 23:29:58 +0000 Subject: [PATCH] makefile: attempt to fix freetype when not using makelibs (should make it slightly easier for people to compile with msys2 without needing to resort to cmake). emenu: clean up hexen2's maplist options slightly. emenu: modelviewer should now be slightly more friendly (click+wasd to move around). particles: fix up randomised s coords. csqc: try to fix issue with applycustomskin not refcounting properly. client: [s_]precache and (new) mod_precache cvars can be set to 2 to precache the resources after load, for faster loading at the expense of some early stutter, without risking later mid-game stuttering. gltf: add support for morphweights in a cpu-fallback path. don't expect good performance on surfaces with morphtargets for now. gtlf: add some support for gltf1 files. far from perfect. shaders: gltf1 semantics handling shaders: const correctness iqmtool: fix up mdl skin export. iqmtool: integrate the engine's gltf2 loader. works with animated models, but unanimated ones suffer from basepose-different-from-bindpose issues. q3bsp: hopefully fixed bih traces. still disabled for now. qc: change default value of pr_gc_threaded to 1. qcext: add the '__deprecated' keyword to various symbols in fteextensions.qc, now that fteqcc supports it. ssqc: spit out a more readable error for WriteByte(MSG_CSQC,...) outside of SendEntity. ssqc: add registercommand builtin, for consistency with menuqc and csqc (though only one can register any single command). sv: report userinfo/serverinfo sizes (some clients still have arbitrary limits, plus its nice to see how abusive things are) sv: try to optimise sv_cullentities_trace a little. movechain: relink moved ents. csqc: add spriteframe builtin, for freecs to use instead of more ugly less reliable hacks. menuqc: fopen("tls://host:port", FILE_STREAM) should now open a tls stream. tcp:// should also work. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5703 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 147 ++++++++----- engine/client/cl_main.c | 23 +- engine/client/cl_master.h | 2 +- engine/client/cl_parse.c | 11 +- engine/client/image.c | 54 ++--- engine/client/m_options.c | 428 ++++++++++++++---------------------- engine/client/merged.h | 4 +- engine/client/p_script.c | 3 + engine/client/pr_csqc.c | 20 +- engine/client/quakedef.h | 14 +- engine/client/snd_al.c | 1 + engine/client/snd_dma.c | 6 +- engine/client/sys_linux.c | 2 +- engine/client/vid.h | 1 + engine/common/bothdefs.h | 2 +- engine/common/com_mesh.c | 84 +++++-- engine/common/com_mesh.h | 4 + engine/common/common.c | 30 +-- engine/common/gl_q2bsp.c | 422 +++++++++++++++++++++++++++++------ engine/common/mathlib.h | 2 +- engine/common/pr_bgcmd.c | 100 ++++++++- engine/common/pr_common.h | 2 + engine/d3d/d3d_backend.c | 13 +- engine/d3d/d3d_shader.c | 18 +- engine/d3d/vid_d3d.c | 7 +- engine/d3d/vid_d3d11.c | 17 +- engine/d3d/vid_d3d8.c | 2 +- engine/gl/gl_backend.c | 75 ++++--- engine/gl/gl_heightmap.c | 12 +- engine/gl/gl_model.c | 5 + engine/gl/gl_model.h | 2 + engine/gl/gl_shader.c | 409 +++++++++++++++++++++------------- engine/gl/gl_shadow.c | 1 + engine/gl/gl_vidcommon.c | 195 +++++++++------- engine/gl/gl_videgl.c | 2 +- engine/gl/gl_vidlinuxglx.c | 2 +- engine/gl/gl_vidnt.c | 2 +- engine/gl/glquake.h | 2 + engine/gl/shader.h | 30 ++- engine/qclib/Makefile | 14 +- engine/qclib/initlib.c | 8 +- engine/qclib/progslib.h | 8 +- engine/qclib/test.c | 36 +-- engine/server/pr_cmds.c | 262 +++++++++++++--------- engine/server/progdefs.h | 40 ++-- engine/server/server.h | 3 + engine/server/sv_ccmds.c | 8 +- engine/server/sv_ents.c | 83 +++++-- engine/server/sv_main.c | 6 +- engine/server/sv_phys.c | 41 ++-- engine/server/sv_sys_unix.c | 8 +- engine/server/sv_user.c | 10 +- engine/vk/vk_backend.c | 2 - engine/vk/vk_init.c | 15 +- 54 files changed, 1715 insertions(+), 985 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index de9d35ee..8d728596 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -10,12 +10,12 @@ COMPILE_SYS:=$(shell uname -o 2>&1) #canonicalize the source path. except emscripten warns about that like crazy. *sigh* ifeq ($(FTE_TARGET),web) - BASE_DIR:=. + BASE_DIR:=. else ifeq ($(FTE_TARGET),droid) #android tools suck, but plugins need to find the engine directory. - BASE_DIR:=../engine + BASE_DIR:=../engine else - BASE_DIR:=$(realpath .) + BASE_DIR:=$(realpath .) endif ifeq ($(SVNREVISION),) @@ -75,12 +75,12 @@ DEBUG_DIR=$(BASE_DIR)/debug PROFILE_DIR=$(BASE_DIR)/profile NATIVE_ABSBASE_DIR:=$(realpath $(BASE_DIR)) ifeq ($(COMPILE_SYS),Cygwin) - 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)) - NATIVE_ABSBASE_DIR:=$(shell cygpath -m $(NATIVE_ABSBASE_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)) + NATIVE_ABSBASE_DIR:=$(shell cygpath -m $(NATIVE_ABSBASE_DIR)) endif NATIVE_OUT_DIR?=$(OUT_DIR) NATIVE_BASE_DIR?=$(BASE_DIR) @@ -91,56 +91,56 @@ EXE_NAME=fteqw #include the appropriate games. ifneq (,$(BRANDING)) - BRANDFLAGS+=-DBRANDING_INC=../game_$(BRANDING).h - -include game_$(BRANDING).mak + BRANDFLAGS+=-DBRANDING_INC=../game_$(BRANDING).h + -include game_$(BRANDING).mak endif FTE_CONFIG?=fteqw ifneq ($(FTE_TARGET),vc) ifeq (,$(FTE_CONFIG_EXTRA)) - export FTE_CONFIG_EXTRA := $(shell $(CC) -xc -E -P -DFTE_TARGET_$(FTE_TARGET) -DCOMPILE_OPTS common/config_$(FTE_CONFIG).h) + export FTE_CONFIG_EXTRA := $(shell $(CC) -xc -E -P -DFTE_TARGET_$(FTE_TARGET) -DCOMPILE_OPTS common/config_$(FTE_CONFIG).h) endif endif BRANDFLAGS+=-DCONFIG_FILE_NAME=config_$(FTE_CONFIG).h $(FTE_CONFIG_EXTRA) EXE_NAME=$(FTE_CONFIG) ifeq (,$(findstring DNO_SPEEX,$(FTE_CONFIG_EXTRA))) - USE_SPEEX?=1 + USE_SPEEX?=1 endif ifeq (,$(findstring DNO_OPUS,$(FTE_CONFIG_EXTRA))) - USE_OPUS=1 + USE_OPUS=1 endif ifeq (,$(findstring DNO_BOTLIB,$(FTE_CONFIG_EXTRA))) - USE_BOTLIB=1 + USE_BOTLIB=1 endif ifeq (,$(findstring DNO_VORBISFILE,$(FTE_CONFIG_EXTRA))) - USE_VORBISFILE=1 + USE_VORBISFILE=1 endif ifneq (,$(findstring DLINK_FREETYPE,$(FTE_CONFIG_EXTRA))) - LINK_FREETYPE=1 - LINK_ZLIB=1 - LINK_PNG=1 + LINK_FREETYPE=1 + LINK_ZLIB=1 + LINK_PNG=1 endif ifneq (,$(findstring DLINK_JPEG,$(FTE_CONFIG_EXTRA))) - LINK_JPEG=1 + LINK_JPEG=1 endif ifneq (,$(findstring DLINK_PNG,$(FTE_CONFIG_EXTRA))) - LINK_ZLIB=1 - LINK_PNG=1 + LINK_ZLIB=1 + LINK_PNG=1 endif ifneq (,$(findstring -Os,$(FTE_CONFIG_EXTRA))) - CPUOPTIMIZATIONS+=-Os - BRANDFLAGS:=$(filter-out -O%,$(BRANDFLAGS)) + CPUOPTIMIZATIONS+=-Os + BRANDFLAGS:=$(filter-out -O%,$(BRANDFLAGS)) endif ifneq (,$(findstring DLINK_INTERNAL_BULLET,$(FTE_CONFIG_EXTRA))) - INTERNAL_BULLET=1 #bullet plugin will be built into the exe itself + INTERNAL_BULLET=1 #bullet plugin will be built into the exe itself endif ifeq ($(BITS),64) - CC:=$(CC) -m64 - CXX:=$(CXX) -m64 + CC:=$(CC) -m64 + CXX:=$(CXX) -m64 endif ifeq ($(BITS),32) - CC:=$(CC) -m32 - CXX:=$(CXX) -m32 + CC:=$(CC) -m32 + CXX:=$(CXX) -m32 endif #correct the gcc build when cross compiling @@ -196,7 +196,7 @@ ifneq (,$(findstring win64,$(FTE_TARGET))) endif ifeq ($(FTE_TARGET),win32_sdl) - FTE_TARGET=win32_SDL + FTE_TARGET=win32_SDL endif USER_TARGET:=$(FTE_TARGET) @@ -418,6 +418,14 @@ ifeq ($(FTE_TARGET),linux32) STRIP=strip BITS=32 endif +ifeq ($(FTE_TARGET),linuxx86) + FTE_TARGET=linux + CC=i686-linux-gnu-gcc + PKGCONFIG=i686-linux-gnu-pkg-config + CXX=i686-linux-gnu-g++ + STRIP=i686-linux-gnu-strip + BITS=32 +endif ifeq ($(FTE_TARGET),linuxarmhf) #debian's armhf is armv7, but armv6 works on RPI too. FTE_TARGET=linux @@ -628,15 +636,16 @@ else endif #foo:=$(shell echo ARCH is $(ARCH) 1>&2 ) endif -ARCHLIBS=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH) +ARCHLIBS:=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH) #incase our compiler doesn't support it (mingw) ifeq ($(shell LANG=c $(CC) -rdynamic 2>&1 | grep unrecognized),) DEBUG_CFLAGS+= -rdynamic endif -PKGCONFIG=$(ARCH)-pkg-config +PKGCONFIG?=$(ARCH)-pkg-config ifeq ($(shell which $(PKGCONFIG) 2> /dev/null),) + FFS:=$(shell echo $(PKGCONFIG) not found 1>&2 ) PKGCONFIG=/bin/true #don't end up using eg /usr/include when cross-compiling. makelibs is a valid workaround. endif #try to statically link @@ -922,59 +931,75 @@ SERVERLIBFLAGS=$(COMMONLIBFLAGS) CLIENTLDDEPS=$(COMMONLDDEPS) $(LIBOPUS_LDFLAGS) $(LIBSPEEX_LDFLAGS) $(OGGVORBISLDFLAGS) SERVERLDDEPS=$(COMMONLDDEPS) ifeq (1,$(USE_OPUS)) - LIBOPUS_STATIC=-DOPUS_STATIC - LIBOPUS_LDFLAGS=-lopus - ALL_CFLAGS+=-I/usr/include/opus + LIBOPUS_STATIC=-DOPUS_STATIC + LIBOPUS_LDFLAGS=-lopus + ALL_CFLAGS+=-I/usr/include/opus endif ifeq (1,$(USE_SPEEX)) - LIBSPEEX_STATIC=-DSPEEX_STATIC - LIBSPEEX_LDFLAGS=-lspeex -lspeexdsp + LIBSPEEX_STATIC=-DSPEEX_STATIC + LIBSPEEX_LDFLAGS=-lspeex -lspeexdsp endif ifeq (1,$(USE_VORBISFILE)) - OGGVORBISFILE_STATIC=-DLIBVORBISFILE_STATIC + OGGVORBISFILE_STATIC=-DLIBVORBISFILE_STATIC else - OGGVORBISLDFLAGS= - OGGVORBISFILE_STATIC= + OGGVORBISLDFLAGS= + OGGVORBISFILE_STATIC= endif + +#freetype is annoying. ifeq (1,$(LINK_FREETYPE)) - CLIENTLIBFLAGS+=-DFREETYPE_STATIC - CLIENTLDDEPS+=-lfreetype + CLIENTLIBFLAGS+=-DFREETYPE_STATIC + CLIENTLDDEPS+=$(FREETYPE_LDFLAGS) +endif +ifneq ("$(wildcard $(ARCHLIBS))","") + #makelibs has been used. we know what to use here. + FREETYPE_CFLAGS:= + FREETYPE_LDFLAGS:=-lfreetype +else + #we're using system libraries... lets hope pkg-config knows it and can handle any cross compiles. + FREETYPE_CFLAGS:=$(shell $(PKGCONFIG) freetype2 --cflags --silence-errors) + FREETYPE_LDFLAGS:=$(shell $(PKGCONFIG) freetype2 --libs --silence-errors) + ifeq (,$(FREETYPE_CFLAGS)) + #system freetype headers not installed. don't try to include them! + FREETYPE_CFLAGS:=-DNO_FREETYPE + FREETYPE_LDFLAGS:= + endif endif -FREETYPE_CFLAGS:=$(shell $(PKGCONFIG) freetype --cflags --silence-errors) ALL_CFLAGS+=$(FREETYPE_CFLAGS) + ifeq (1,$(LINK_PNG)) - CLIENTLIBFLAGS+=-DLIBPNG_STATIC - CLIENTLDDEPS+=-lpng + CLIENTLIBFLAGS+=-DLIBPNG_STATIC + CLIENTLDDEPS+=-lpng endif ifeq (1,$(LINK_JPEG)) - CLIENTLIBFLAGS+=-DLIBJPEG_STATIC - CLIENTLDDEPS+=-ljpeg + CLIENTLIBFLAGS+=-DLIBJPEG_STATIC + CLIENTLDDEPS+=-ljpeg endif ifeq (1,$(LINK_ZLIB)) - CLIENTLIBFLAGS+=-DZLIB_STATIC - CLIENTLDDEPS+=-lz + CLIENTLIBFLAGS+=-DZLIB_STATIC + CLIENTLDDEPS+=-lz endif ifeq (1,$(strip $(INTERNAL_BULLET))) - COMMON_OBJS+=com_phys_bullet.o - ALL_CFLAGS+=-I/usr/include/bullet -I$(ARCHLIBS)/bullet3-$(BULLETVER)/src - COMMONLDDEPS+=-lBulletDynamics -lBulletCollision -lLinearMath - LDCC=$(CXX) - MAKELIBS+=libs-$(ARCH)/libBulletDynamics.a + COMMON_OBJS+=com_phys_bullet.o + ALL_CFLAGS+=-I/usr/include/bullet -I$(ARCHLIBS)/bullet3-$(BULLETVER)/src + COMMONLDDEPS+=-lBulletDynamics -lBulletCollision -lLinearMath + LDCC=$(CXX) + MAKELIBS+=libs-$(ARCH)/libBulletDynamics.a endif #the defaults for sdl come first #CC_MACHINE:=$(shell $(CC) -dumpmachine) ifeq ($(FTE_TARGET),SDL2) - SDLCONFIG?=sdl2-config - FTE_FULLTARGET?=sdl2$(BITS) + SDLCONFIG?=sdl2-config + FTE_FULLTARGET?=sdl2$(BITS) endif ifeq ($(FTE_TARGET),SDL1) - SDLCONFIG?=sdl-config - FTE_FULLTARGET?=sdl1$(BITS) + SDLCONFIG?=sdl-config + FTE_FULLTARGET?=sdl1$(BITS) endif ifeq ($(FTE_TARGET),SDL) - FTE_FULLTARGET?=sdl$(BITS) + FTE_FULLTARGET?=sdl$(BITS) endif SDLCONFIG?=sdl-config FTE_FULLTARGET?=sdl$(FTE_TARGET)$(BITS) @@ -2320,9 +2345,9 @@ $(RELEASE_DIR)/httpserver$(BITS)$(EXEPOSTFIX): $(HTTP_OBJECTS) $(CC) -o $@ -Icommon -Iclient -Iqclib -Igl -Iserver -DWEBSERVER -DWEBSVONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DNO_PNG $(HTTP_OBJECTS) httpserver: $(RELEASE_DIR)/httpserver$(BITS)$(EXEPOSTFIX) -IQM_OBJECTS=../iqm/iqm.cpp +IQM_OBJECTS=../iqm/iqm.cpp ../imgtool.c client/image.c ../plugins/models/gltf.c $(RELEASE_DIR)/iqm$(BITS)$(EXEPOSTFIX): $(IQM_OBJECTS) - $(CC) -o $@ $(IQM_OBJECTS) -static -lstdc++ -lm -Os + $(CC) -o $@ $(IQM_OBJECTS) -Icommon -Iclient -Iqclib -Igl -Iserver $(ALL_CFLAGS) $(CLIENTLIBFLAGS) -DIQMTOOL $(BASELDFLAGS) $(CLIENTLDDEPS) -static -lstdc++ -lm -Os iqm-rel: $(RELEASE_DIR)/iqm$(BITS)$(EXEPOSTFIX) iqm: iqm-rel iqmtool: iqm-rel diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 1846bd4f..368bc77e 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -202,9 +202,6 @@ cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat cvar_t cl_dlemptyterminate = CVAR("cl_dlemptyterminate", "1"); -cvar_t host_mapname = CVARAF("mapname", "", - "host_mapname", 0); - #define RULESETADVICE " You should not normally change this cvar from its permissive default, instead impose limits on yourself only through the 'ruleset' cvar." cvar_t ruleset_allow_playercount = CVARD("ruleset_allow_playercount", "1", "Specifies whether teamplay triggers that count nearby players are allowed in the current ruleset."RULESETADVICE); cvar_t ruleset_allow_frj = CVARD("ruleset_allow_frj", "1", "Specifies whether Forward-Rocket-Jump scripts are allowed in the current ruleset. If 0, limits on yaw speed will be imposed so they cannot be scripted."RULESETADVICE); @@ -2064,7 +2061,10 @@ void CL_User_f (void) if (!cl.players[i].userinfovalid) Con_Printf("name: %s\ncolour %i %i\nping: %i\n", cl.players[i].name, cl.players[i].rbottomcolor, cl.players[i].rtopcolor, cl.players[i].ping); else + { InfoBuf_Print (&cl.players[i].userinfo, ""); + Con_Printf("[%u, %u]\n", (unsigned)cl.players[i].userinfo.totalsize, (unsigned)cl.players[i].userinfo.numkeys); + } found = true; } } @@ -3349,7 +3349,7 @@ void CL_ConnectionlessPacket (void) if (candtls && connectinfo.adr.prot == NP_DGRAM && (connectinfo.dtlsupgrade || candtls > 1)) { //c2s getchallenge - //s2c c%u\0DTLS=0 + //s2c c%u\0DTLS=$candtls //c2s dtlsconnect %u //s2c dtlsopened //c2s DTLS(getchallenge) @@ -3360,7 +3360,18 @@ void CL_ConnectionlessPacket (void) //FIXME: do rcon via dtls too, but requires tracking pending rcon packets until the handshake completes. //server says it can do tls. - char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge); + + char *pkt; + //qwfwd proxy routing + char *at; + if ((at = strrchr(cls.servername, '@'))) + { + *at = 0; + pkt = va("%c%c%c%cdtlsconnect %i %s", 255, 255, 255, 255, connectinfo.challenge, cls.servername); + *at = '@'; + } + else + pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge); NET_SendPacket (cls.sockets, strlen(pkt), pkt, &net_from); return; } @@ -4853,8 +4864,6 @@ void CL_Init (void) Cvar_Register (&cl_splitscreen, cl_controlgroup); - Cvar_Register (&host_mapname, "Scripting"); - #ifndef SERVERONLY Cvar_Register (&cl_loopbackprotocol, cl_controlgroup); #endif diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 84a2b141..980991ca 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -126,7 +126,7 @@ typedef struct serverdetailedinfo_s //hold minimum info. typedef struct serverinfo_s { - char name[64]; //hostname. + char name[80]; //hostname. netadr_t adr; char brokerid[64]; //'rtc[s]://adr//brokerid' diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 25ce2718..97e916b5 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -291,7 +291,7 @@ static const char *svc_nqstrings[] = }; #endif -extern cvar_t requiredownloads, mod_precache, cl_standardchat, msg_filter, msg_filter_frags, msg_filter_pickups, cl_countpendingpl, cl_download_mapsrc; +extern cvar_t requiredownloads, mod_precache, snd_precache, cl_standardchat, msg_filter, msg_filter_frags, msg_filter_pickups, cl_countpendingpl, cl_download_mapsrc; int oldparsecountmod; int parsecountmod; double parsecounttime; @@ -1852,6 +1852,15 @@ void CL_RequestNextDownload (void) Mod_LoadModel(cl.model_precache[i], MLV_WARN); } } + if (snd_precache.ival >= 2) + { + int i; + for (i=1 ; iloadstate == SLS_NOTLOADED) + S_LoadSound(cl.sound_precache[i], false); + } + } } } diff --git a/engine/client/image.c b/engine/client/image.c index 286fc3bd..465b74b0 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -2,13 +2,25 @@ #include "shader.h" #include "glquake.h" //we need some of the gl format enums -#if defined(NPFTE) || defined(IMGTOOL) +#ifndef HAVE_CLIENT //#define Con_Printf(f, ...) //hope you're on a littleendian machine #define LittleShort(s) s #define LittleLong(s) s #define LittleFloat(s) s +#define BigFloat(s) SwapFloat(s) +static float SwapFloat (float l) +{ + union {qbyte b[4]; float f;} in, out; + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + return out.f; +} + #undef S_COLOR_BLACK #undef S_COLOR_RED #undef S_COLOR_GREEN @@ -314,7 +326,7 @@ static char *ReadGreyTargaFile (qbyte *data, int flen, tgaheader_t *tgahead, int rows = tgahead->height; flipped = !((tgahead->attribs & 0x20) >> 5); -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (r_dodgytgafiles.value) flipped = true; #endif @@ -457,7 +469,7 @@ void *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_t flipped = !((tgaheader.attribs & 0x20) >> 5); -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (r_dodgytgafiles.value) flipped = true; #endif @@ -2674,7 +2686,7 @@ qbyte *ReadPCXFile(qbyte *buf, int length, int *width, int *height) *width = swidth; *height = sheight; -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (r_dodgypcxfiles.value) palette = host_basepal; else @@ -3386,9 +3398,6 @@ static qbyte *ReadPBMFile(qbyte *buf, size_t len, const char *fname, int *width, } else { -#if defined(NPFTE) || defined(IMGTOOL) - return NULL; -#else r = BZ_Malloc(*width**height*4*sizeof(float)); for(y = 0; y < *height; y++) for(x = 0, fo=(float*)r+(*height-y-1)*4**width; x < *height; x++) @@ -3398,7 +3407,6 @@ static qbyte *ReadPBMFile(qbyte *buf, size_t len, const char *fname, int *width, *fo++ = BigFloat(*fi++); *fo++ = 1; } -#endif } *format = PTI_RGBA32F; } @@ -3414,14 +3422,10 @@ static qbyte *ReadPBMFile(qbyte *buf, size_t len, const char *fname, int *width, } else { -#if defined(NPFTE) || defined(IMGTOOL) - return NULL; -#else r = BZ_Malloc(*width**height*sizeof(float)); for(y = 0; y < *height; y++) for(x = 0, fo=(float*)r+(*height-y-1)**width; x < *height; x++) *fo++ = BigFloat(*fi++); -#endif } *format = PTI_R32F; } @@ -4499,7 +4503,7 @@ static void *ReadEXRFile(qbyte *buf, size_t len, const char *fname, int *outwidt } #endif -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT // saturate function, stolen from jitspoe @@ -7951,7 +7955,7 @@ void *Image_ResampleTexture (uploadfmt_t format, const void *in, int inwidth, in case PTI_BGRX8_SRGB: if (!out) out = BZ_Malloc(((outwidth+3)&~3)*outheight*4); -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (gl_lerpimages.ival) #else if (1) @@ -8053,7 +8057,7 @@ static unsigned int * Image_GenerateNormalMap(qbyte *pixels, unsigned int *nmap, static int Image_GetPicMip(unsigned int flags) { int picmip = 0; -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (flags & IF_NOMIPMAP) picmip += gl_picmip2d.ival; //2d stuff gets its own picmip cvar. else @@ -8120,7 +8124,7 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne if (*scaled_height > sh_config.texture2d_maxsize) *scaled_height = sh_config.texture2d_maxsize; } -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (!(flags & (IF_UIPIC|IF_RENDERTARGET))) { if (gl_max_size.value) @@ -11843,7 +11847,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag //8bit opaque data Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); flags |= IF_NOPICMIP; -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (!r_dodgymiptex.ival && mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight) { //special hack required to preserve the hand-drawn lower mips. unsigned int pixels = @@ -11971,7 +11975,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag unsigned int rgb = d_8to24rgbtable[((qbyte*)rawdata)[i]]; heights[i] = (((rgb>>16)&0xff) + ((rgb>>8)&0xff) + ((rgb>>0)&0xff))/3; } -#if defined(NPFTE) || defined(IMGTOOL) +#ifndef HAVE_CLIENT Image_GenerateNormalMap(heights, rgbadata, imgwidth, imgheight, 4, 0); #else Image_GenerateNormalMap(heights, rgbadata, imgwidth, imgheight, r_shadow_bumpscale_basetexture.value?r_shadow_bumpscale_basetexture.value:4, r_shadow_heightscale_basetexture.value); @@ -11984,7 +11988,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case TF_HEIGHT8: mips->encoding = PTI_RGBA8; rgbadata = BZ_Malloc(imgwidth * imgheight*4); -#if defined(NPFTE) || defined(IMGTOOL) +#ifndef HAVE_CLIENT Image_GenerateNormalMap(rawdata, rgbadata, imgwidth, imgheight, 4, 1); #else Image_GenerateNormalMap(rawdata, rgbadata, imgwidth, imgheight, r_shadow_bumpscale_bumpmap.value, r_shadow_heightscale_bumpmap.value); @@ -12027,7 +12031,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag palettedata = (qbyte*)rawdata + pixels; Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); flags |= IF_NOPICMIP; -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT if (!r_dodgymiptex.ival && mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight) { unsigned int pixels = @@ -12531,7 +12535,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag //writes to rgbdata+format on success void Image_ReadExternalAlpha(qbyte *rgbadata, size_t imgwidth, size_t imgheight, const char *fname, uploadfmt_t *format) { -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT unsigned int alpha_width, alpha_height, p; char aname[MAX_QPATH]; qbyte *alphadata, *srcchan; @@ -12716,7 +12720,7 @@ struct pendingtextureinfo *Image_LoadMipsFromMemory(int flags, const char *iname if ((rgbadata = ReadRawImageFile(filedata, filesize, &imgwidth, &imgheight, &format, false, fname))) { -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT extern cvar_t vid_hardwaregamma; if (!(flags&IF_NOGAMMA) && !vid_hardwaregamma.value) BoostGamma(rgbadata, imgwidth, imgheight, format); @@ -12846,7 +12850,7 @@ void *Image_FlipImage(const void *inbuffer, void *outbuffer, int *inoutwidth, in } return outbuffer; } -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT static int tex_extensions_count; #define tex_extensions_max 15 static struct @@ -14179,7 +14183,7 @@ void Image_Init(void) #endif } -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT wadmutex = Sys_CreateMutex(); memset(imagetablebuckets, 0, sizeof(imagetablebuckets)); Hash_InitTable(&imagetable, sizeof(imagetablebuckets)/sizeof(imagetablebuckets[0]), imagetablebuckets); @@ -14189,7 +14193,7 @@ void Image_Init(void) #endif } -#if !defined(NPFTE) && !defined(IMGTOOL) +#ifdef HAVE_CLIENT // ocrana led functions static int ledcolors[8][3] = { diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 423b1d7a..88e652d6 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1851,7 +1851,7 @@ menucombo_t *skillcombo; menucombo_t *mapcombo; } singleplayerinfo_t; -#ifndef CLIENTONLY +#ifdef HAVE_SERVER static const char *maplist_q1[] = { "start", @@ -1966,7 +1966,6 @@ static const char *maplist_q2[] = "city3", "boss1", "boss2", - NULL }; static const char *mapoptions_q2[] = { @@ -2037,7 +2036,7 @@ qboolean M_Apply_SP_Cheats (union menuoption_s *op,struct emenu_s *menu,int key) break; } -#ifndef CLIENTONLY +#ifdef HAVE_SERVER if ((unsigned int)info->mapcombo->selectedoption < countof(maplist_q1)-1) Cbuf_AddText(va("map %s\n", maplist_q1[info->mapcombo->selectedoption]), RESTRICT_LOCAL); #endif @@ -2050,7 +2049,7 @@ qboolean M_Apply_SP_Cheats (union menuoption_s *op,struct emenu_s *menu,int key) void M_Menu_Singleplayer_Cheats_Quake (void) { - #ifndef CLIENTONLY + #ifdef HAVE_SERVER static const char *skilloptions[] = { "Easy", @@ -2063,7 +2062,6 @@ void M_Menu_Singleplayer_Cheats_Quake (void) int currentskill; int currentmap; extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill; - extern cvar_t host_mapname; #endif singleplayerinfo_t *info; int cursorpositionY; @@ -2073,7 +2071,7 @@ void M_Menu_Singleplayer_Cheats_Quake (void) cursorpositionY = (y + 24); - #ifndef CLIENTONLY + #ifdef HAVE_SERVER if ( !*skill.string ) currentskill = 4; // no skill selected else @@ -2088,7 +2086,7 @@ void M_Menu_Singleplayer_Cheats_Quake (void) MC_AddRedText(menu, 16, 170, y, " Quake Singleplayer Cheats", false); y+=8; MC_AddWhiteText(menu, 16, 170, y, " ^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082 ", false); y+=8; y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8; info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_q1, currentmap); y+=8; MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8; @@ -2100,19 +2098,19 @@ void M_Menu_Singleplayer_Cheats_Quake (void) MC_AddConsoleCommand(menu, 16, 170, y, " Toggle Flymode", "fly\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, " Toggle Noclip", "noclip\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, " Quad Damage", "impulse 255\n"); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddSlider(menu, 16, 170, y, "Gravity", &sv_gravity,0,800,25); y+=8; #endif MC_AddSlider(menu, 16, 170, y, "Forward Speed", &cl_forwardspeed,0,1000,50); y+=8; MC_AddSlider(menu, 16, 170, y, "Side Speed", &cl_sidespeed,0,1000,50); y+=8; MC_AddSlider(menu, 16, 170, y, "Back Speed", &cl_backspeed,0,1000,50); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddSlider(menu, 16, 170, y, "Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8; #endif MC_AddConsoleCommand(menu, 16, 170, y, " Silver & Gold Keys", "impulse 13\nimpulse 14\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "All Weapons & Items", "impulse 9\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "No Enemy Targetting", "notarget\n"); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddConsoleCommand(menu, 16, 170, y, "Restart Map", "restart\n"); y+=8; #else MC_AddConsoleCommand(menu, 16, 170, y, "Suicide", "kill\n"); y+=8; @@ -2175,11 +2173,10 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void) singleplayerq2info_t *info; int cursorpositionY; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER int currentskill; int currentmap; extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill; - extern cvar_t host_mapname; #endif int y; emenu_t *menu = M_Options_Title(&y, sizeof(*info)); @@ -2187,14 +2184,14 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void) cursorpositionY = (y + 24); - #ifndef CLIENTONLY + #ifdef HAVE_SERVER if ( !*skill.string ) currentskill = 3; // no skill selected else currentskill = skill.value; for (currentmap = countof(maplist_q2); currentmap --> 0; ) - if (!strcmp(host_mapname.string, maplist_q2[currentmap])) + if (!Q_strcasecmp(host_mapname.string, maplist_q2[currentmap])) break; /*anything that doesn't match will end up with 0*/ #endif @@ -2202,20 +2199,20 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void) MC_AddRedText(menu, 16, 170, y, "Quake2 Singleplayer Cheats", false); y+=8; MC_AddWhiteText(menu, 16, 170, y, "^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082", false); y+=8; y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8; info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_q2, currentmap); y+=8; MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8; #endif MC_AddConsoleCommand(menu, 16, 170, y, "Toggle Godmode", "god\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Toggle Noclip", "noclip\n"); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddSlider(menu, 16, 170, y, "Gravity", &sv_gravity,0,850,25); y+=8; #endif MC_AddSlider(menu, 16, 170, y, "Forward Speed", &cl_forwardspeed,0,1000,50); y+=8; MC_AddSlider(menu, 16, 170, y, "Side Speed", &cl_sidespeed,0,1000,50); y+=8; MC_AddSlider(menu, 16, 170, y, "Back Speed", &cl_backspeed,0,1000,50); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddSlider(menu, 16, 170, y, "Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8; #endif MC_AddConsoleCommand(menu, 16, 170, y, "Unlimited Ammo", "dmflags 8192\n"); y+=8; @@ -2238,7 +2235,7 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void) MC_AddConsoleCommand(menu, 16, 170, y, "Commander's Head", "give commander's head\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Security Pass", "give security pass\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Airstrike Marker", "give airstrike marker\n"); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddConsoleCommand(menu, 16, 170, y, "Restart Map", va("restart\n")); y+=8; #endif @@ -2256,6 +2253,90 @@ menucombo_t *skillcombo; menucombo_t *mapcombo; } singleplayerh2info_t; +#ifdef HAVE_SERVER +static const char *maplist_h2[] = +{ + "demo1", + "demo2", + "demo3", + "village1", + "village3", + "village2", + "village4", + "village5", + "rider1a", + "meso1", + "meso2", + "meso3", + "meso4", + "meso5", + "meso6", + "meso8", + "meso9", + "egypt1", + "egypt2", + "egypt3", + "egypt4", + "egypt5", + "egypt6", + "egypt7", + "rider2c", + "romeric1", + "romeric2", + "romeric3", + "romeric4", + "romeric5", + "romeric6", + "romeric7", + "castle4", + "castle5", + "cath", + "tower", + "eidolon", +}; +static const char *mapoptions_h2[] = +{ + "demo1 (Blackmarsh: Hub 1 Blackmarsh)", + "demo2 (Barbican: Hub 1 Blackmarsh)", + "demo3 (The Mill: Hub 1 Blackmarsh)", + "village1 (King's Court: Hub 1 Blackmarsh)", + "village3 (Stables: Hub 1 Blackmarsh)", + "village2 (Inner Courtyard: Hub 1 Blackmarsh)", + "village4 (Palance Entrance: Hub 1 Blackmarsh)", + "village5 (The Forgotten Chapel: Hub 1 Blackmarsh)", + "rider1a (Famine's Domain: Hub 1 Blackmarsh)", + "meso1 (Palance of Columns: Hub 2 Mazaera)", + "meso2 (Plaza of the Sun: Hub 2 Mazaera)", + "meso3 (Square of the Stream: Hub 2 Mazaera)", + "meso4 (Tomb of the High Priest: Hub 2 Mazaera)", + "meso5 (Obelisk of the Moon: Hub 2 Mazaera)", + "meso6 (Court of 1000 Warriors: Hub 2 Mazaera)", + "meso8 (Bridge of Stars: Hub 2 Mazaera)", + "meso9 (Well of Souls: Hub 2 Mazaera)", + "egypt1 (Temple of Horus: Hub 3 Thysis)", + "egypt2 (Ancient Tempor of Nefertum: Hub 3 Thysis)", + "egypt3 (Tempor of Nefertum: Hub 3 Thysis)", + "egypt4 (Palace of the Pharaoh: Hub 3 Thysis", + "egypt5 (Pyramid of Anubus: Hub 3 Thysis)", + "egypt6 (Temple of Light: Hub 3 Thysis)", + "egypt7 (Shrine of Naos: Hub 3 Thysis)", + "rider2c (Pestilence's Lair: Hub 3 Thysis)", + "romeric1 (The Hall of Heroes: Hub 4 Septimus)", + "romeric2 (Gardens of Athena: Hub 4 Septimus)", + "romeric3 (Forum of Zeus: Hub 4 Septimus)", + "romeric4 (Baths of Demetrius: Hub 4 Septimus)", + "romeric5 (Temple of Mars: Hub 4 Septimus)", + "romeric6 (Coliseum of War: Hub 4 Septimus)", + "romeric7 (Reflecting Pool: Hub 4 Septimus)", + "castle4 (The Underhalls: Hub 5 Return to Blackmarsh)", + "castle5 (Eidolon's Ordeal: Hub 5 Return to Blackmarsh)", + "cath (Cathedral: Hub 5 Return to Blackmarsh)", + "tower (Tower of the Dark Mage: Hub 5 Return to Blackmarsh)", + "eidolon (Eidolon's Lair: Hub 5 Return to Blackmarsh)", + NULL +}; +#endif + qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int key) { singleplayerh2info_t *info = menu->data; @@ -2279,120 +2360,8 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k break; } - switch(info->mapcombo->selectedoption) - { - case 0: - Cbuf_AddText("map demo1\n", RESTRICT_LOCAL); - break; - case 1: - Cbuf_AddText("map demo2\n", RESTRICT_LOCAL); - break; - case 2: - Cbuf_AddText("map demo3\n", RESTRICT_LOCAL); - break; - case 3: - Cbuf_AddText("map village1\n", RESTRICT_LOCAL); - break; - case 4: - Cbuf_AddText("map village2\n", RESTRICT_LOCAL); - break; - case 5: - Cbuf_AddText("map village3\n", RESTRICT_LOCAL); - break; - case 6: - Cbuf_AddText("map village4\n", RESTRICT_LOCAL); - break; - case 7: - Cbuf_AddText("map village5\n", RESTRICT_LOCAL); - break; - case 8: - Cbuf_AddText("map rider1a\n", RESTRICT_LOCAL); - break; - case 9: - Cbuf_AddText("map meso1\n", RESTRICT_LOCAL); - break; - case 10: - Cbuf_AddText("map meso2\n", RESTRICT_LOCAL); - break; - case 11: - Cbuf_AddText("map meso3\n", RESTRICT_LOCAL); - break; - case 12: - Cbuf_AddText("map meso4\n", RESTRICT_LOCAL); - break; - case 13: - Cbuf_AddText("map meso5\n", RESTRICT_LOCAL); - break; - case 14: - Cbuf_AddText("map meso6\n", RESTRICT_LOCAL); - break; - case 15: - Cbuf_AddText("map meso8\n", RESTRICT_LOCAL); - break; - case 16: - Cbuf_AddText("map meso9\n", RESTRICT_LOCAL); - break; - case 17: - Cbuf_AddText("map egypt1\n", RESTRICT_LOCAL); - break; - case 18: - Cbuf_AddText("map egypt2\n", RESTRICT_LOCAL); - break; - case 19: - Cbuf_AddText("map egypt3\n", RESTRICT_LOCAL); - break; - case 20: - Cbuf_AddText("map egypt4\n", RESTRICT_LOCAL); - break; - case 21: - Cbuf_AddText("map egypt5\n", RESTRICT_LOCAL); - break; - case 22: - Cbuf_AddText("map egypt6\n", RESTRICT_LOCAL); - break; - case 23: - Cbuf_AddText("map egypt7\n", RESTRICT_LOCAL); - break; - case 24: - Cbuf_AddText("map rider2c\n", RESTRICT_LOCAL); - break; - case 25: - Cbuf_AddText("map romeric1\n", RESTRICT_LOCAL); - break; - case 26: - Cbuf_AddText("map romeric2\n", RESTRICT_LOCAL); - break; - case 27: - Cbuf_AddText("map romeric3\n", RESTRICT_LOCAL); - break; - case 28: - Cbuf_AddText("map romeric4\n", RESTRICT_LOCAL); - break; - case 29: - Cbuf_AddText("map romeric5\n", RESTRICT_LOCAL); - break; - case 30: - Cbuf_AddText("map romeric6\n", RESTRICT_LOCAL); - break; - case 31: - Cbuf_AddText("map romeric7\n", RESTRICT_LOCAL); - break; - case 32: - Cbuf_AddText("map castle4\n", RESTRICT_LOCAL); - break; - case 33: - Cbuf_AddText("map castle5\n", RESTRICT_LOCAL); - break; - case 34: - Cbuf_AddText("map cath\n", RESTRICT_LOCAL); - break; - case 35: - Cbuf_AddText("map tower\n", RESTRICT_LOCAL); - break; - case 36: - Cbuf_AddText("map eidolon\n", RESTRICT_LOCAL); - break; - } + if ((unsigned)info->mapcombo->selectedoption < countof(maplist_h2)) + Cbuf_AddText(va("map %s\n", maplist_h2[info->mapcombo->selectedoption]), RESTRICT_LOCAL); M_RemoveMenu(menu); Cbuf_AddText("menu_spcheats\n", RESTRICT_LOCAL); @@ -2402,7 +2371,6 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k void M_Menu_Singleplayer_Cheats_Hexen2 (void) { - static const char *skilloptions[] = { "Easy", @@ -2413,168 +2381,50 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void) NULL }; - static const char *mapoptions[] = - { - "demo1 (Blackmarsh: Hub 1 Blackmarsh)", - "demo2 (Barbican: Hub 1 Blackmarsh)", - "demo3 (The Mill: Hub 1 Blackmarsh)", - "village1 (King's Court: Hub 1 Blackmarsh)", - "village3 (Stables: Hub 1 Blackmarsh)", - "village2 (Inner Courtyard: Hub 1 Blackmarsh)", - "village4 (Palance Entrance: Hub 1 Blackmarsh)", - "village5 (The Forgotten Chapel: Hub 1 Blackmarsh)", - "rider1a (Famine's Domain: Hub 1 Blackmarsh)", - "meso1 (Palance of Columns: Hub 2 Mazaera)", - "meso2 (Plaza of the Sun: Hub 2 Mazaera)", - "meso3 (Square of the Stream: Hub 2 Mazaera)", - "meso4 (Tomb of the High Priest: Hub 2 Mazaera)", - "meso5 (Obelisk of the Moon: Hub 2 Mazaera)", - "meso6 (Court of 1000 Warriors: Hub 2 Mazaera)", - "meso8 (Bridge of Stars: Hub 2 Mazaera)", - "meso9 (Well of Souls: Hub 2 Mazaera)", - "egypt1 (Temple of Horus: Hub 3 Thysis)", - "egypt2 (Ancient Tempor of Nefertum: Hub 3 Thysis)", - "egypt3 (Tempor of Nefertum: Hub 3 Thysis)", - "egypt4 (Palace of the Pharaoh: Hub 3 Thysis", - "egypt5 (Pyramid of Anubus: Hub 3 Thysis)", - "egypt6 (Temple of Light: Hub 3 Thysis)", - "egypt7 (Shrine of Naos: Hub 3 Thysis)", - "rider2c (Pestilence's Lair: Hub 3 Thysis)", - "romeric1 (The Hall of Heroes: Hub 4 Septimus)", - "romeric2 (Gardens of Athena: Hub 4 Septimus)", - "romeric3 (Forum of Zeus: Hub 4 Septimus)", - "romeric4 (Baths of Demetrius: Hub 4 Septimus)", - "romeric5 (Temple of Mars: Hub 4 Septimus)", - "romeric6 (Coliseum of War: Hub 4 Septimus)", - "romeric7 (Reflecting Pool: Hub 4 Septimus)", - "castle4 (The Underhalls: Hub 5 Return to Blackmarsh)", - "castle5 (Eidolon's Ordeal: Hub 5 Return to Blackmarsh)", - "cath (Cathedral: Hub 5 Return to Blackmarsh)", - "tower (Tower of the Dark Mage: Hub 5 Return to Blackmarsh)", - "eidolon (Eidolon's Lair: Hub 5 Return to Blackmarsh)", - NULL - }; - singleplayerh2info_t *info; int cursorpositionY; int currentmap; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER int currentskill; extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill; #endif - extern cvar_t host_mapname; int y; emenu_t *menu = M_Options_Title(&y, sizeof(*info)); info = menu->data; cursorpositionY = (y + 24); - #ifndef CLIENTONLY + #ifdef HAVE_SERVER if ( !*skill.string ) currentskill = 4; // no skill selected else currentskill = skill.value; - #endif - if ( strcmp ( host_mapname.string, "" ) == 0) - currentmap = 0; - else if ( stricmp ( host_mapname.string, "demo1" ) == 0 ) - currentmap = 0; - else if ( stricmp ( host_mapname.string, "demo2" ) == 0 ) - currentmap = 1; - else if ( stricmp ( host_mapname.string, "demo3" ) == 0 ) - currentmap = 2; - else if ( stricmp ( host_mapname.string, "village1" ) == 0 ) - currentmap = 3; - else if ( stricmp ( host_mapname.string, "village2" ) == 0 ) - currentmap = 4; - else if ( stricmp ( host_mapname.string, "village3" ) == 0 ) - currentmap = 5; - else if ( stricmp ( host_mapname.string, "village4" ) == 0 ) - currentmap = 6; - else if ( stricmp ( host_mapname.string, "village5" ) == 0 ) - currentmap = 7; - else if ( stricmp ( host_mapname.string, "rider1a" ) == 0 ) - currentmap = 8; - else if ( stricmp ( host_mapname.string, "meso1" ) == 0 ) - currentmap = 9; - else if ( stricmp ( host_mapname.string, "meso2" ) == 0 ) - currentmap = 10; - else if ( stricmp ( host_mapname.string, "meso3" ) == 0 ) - currentmap = 11; - else if ( stricmp ( host_mapname.string, "meso4" ) == 0 ) - currentmap = 12; - else if ( stricmp ( host_mapname.string, "meso5" ) == 0 ) - currentmap = 13; - else if ( stricmp ( host_mapname.string, "meso6" ) == 0 ) - currentmap = 14; - else if ( stricmp ( host_mapname.string, "meso8" ) == 0 ) - currentmap = 15; - else if ( stricmp ( host_mapname.string, "meso9" ) == 0 ) - currentmap = 16; - else if ( stricmp ( host_mapname.string, "egypt1" ) == 0 ) - currentmap = 17; - else if ( stricmp ( host_mapname.string, "egypt2" ) == 0 ) - currentmap = 18; - else if ( stricmp ( host_mapname.string, "egypt3" ) == 0 ) - currentmap = 19; - else if ( stricmp ( host_mapname.string, "egypt4" ) == 0 ) - currentmap = 20; - else if ( stricmp ( host_mapname.string, "egypt5" ) == 0 ) - currentmap = 21; - else if ( stricmp ( host_mapname.string, "egypt6" ) == 0 ) - currentmap = 22; - else if ( stricmp ( host_mapname.string, "egypt7" ) == 0 ) - currentmap = 23; - else if ( stricmp ( host_mapname.string, "rider2c" ) == 0 ) - currentmap = 24; - else if ( stricmp ( host_mapname.string, "romeric1" ) == 0 ) - currentmap = 25; - else if ( stricmp ( host_mapname.string, "romeric2" ) == 0 ) - currentmap = 26; - else if ( stricmp ( host_mapname.string, "romeric3" ) == 0 ) - currentmap = 27; - else if ( stricmp ( host_mapname.string, "romeric4" ) == 0 ) - currentmap = 28; - else if ( stricmp ( host_mapname.string, "romeric5" ) == 0 ) - currentmap = 29; - else if ( stricmp ( host_mapname.string, "romeric6" ) == 0 ) - currentmap = 30; - else if ( stricmp ( host_mapname.string, "romeric7" ) == 0 ) - currentmap = 31; - else if ( stricmp ( host_mapname.string, "castle4" ) == 0 ) - currentmap = 32; - else if ( stricmp ( host_mapname.string, "castle5" ) == 0 ) - currentmap = 33; - else if ( stricmp ( host_mapname.string, "cath" ) == 0 ) - currentmap = 34; - else if ( stricmp ( host_mapname.string, "tower" ) == 0 ) - currentmap = 35; - else if ( stricmp ( host_mapname.string, "eidolon" ) == 0 ) - currentmap = 36; - else - currentmap = 0; + for (currentmap = countof(maplist_h2); currentmap --> 0; ) + if (!Q_strcasecmp(host_mapname.string, maplist_h2[currentmap])) + break; + #endif MC_AddRedText(menu, 16, 170, y, "Hexen2 Singleplayer Cheats", false); y+=8; MC_AddWhiteText(menu, 16, 170, y, "^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082 ", false); y+=8; y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER info->skillcombo = MC_AddCombo(menu,16,170, y, "Difficulty", skilloptions, currentskill); y+=8; #endif - info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions, currentmap); y+=8; - #ifndef CLIENTONLY + info->mapcombo = MC_AddCombo(menu,16,170, y, "Map", mapoptions_h2, currentmap); y+=8; + #ifdef HAVE_SERVER MC_AddCheckBox(menu, 16, 170, y, "Cheats", &sv_cheats,0); y+=8; #endif MC_AddConsoleCommand(menu, 16, 170, y, "Toggle Godmode", "god\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Toggle Flymode", "fly\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Toggle Noclip", "noclip\n"); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddSlider(menu, 16, 170, y, "Gravity", &sv_gravity,0,800,25); y+=8; #endif MC_AddSlider(menu, 16, 170, y, "Forward Speed", &cl_forwardspeed,0,1000,50); y+=8; MC_AddSlider(menu, 16, 170, y, "Side Speed", &cl_sidespeed,0,1000,50); y+=8; MC_AddSlider(menu, 16, 170, y, "Back Speed", &cl_backspeed,0,1000,50); y+=8; - #ifndef CLIENTONLY + #ifdef HAVE_SERVER MC_AddSlider(menu, 16, 170, y, "Max Movement Speed", &sv_maxspeed,0,1000,50); y+=8; #endif MC_AddConsoleCommand(menu, 16, 170, y, "Sheep Transformation", "impulse 14\n"); y+=8; @@ -2582,6 +2432,7 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void) MC_AddConsoleCommand(menu, 16, 170, y, "Change To Crusader (lvl3+)", "impulse 172\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Change to Necromancer (lvl3+)", "impulse 173\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Change to Assassin (lvl3+)", "impulse 174\n"); y+=8; + //demoness? MC_AddConsoleCommand(menu, 16, 170, y, "Remove Monsters", "impulse 35\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Freeze Monsters", "impulse 36\n"); y+=8; MC_AddConsoleCommand(menu, 16, 170, y, "Unfreeze Monsters", "impulse 37\n"); y+=8; @@ -3240,9 +3091,14 @@ typedef struct int textype; double framechangetime; double skinchangetime; + float pitch; float yaw; + vec3_t cameraorg; + vec2_t mousepos; + qboolean mousedown; float dist; + char modelname[MAX_QPATH]; char forceshader[MAX_QPATH]; @@ -3334,6 +3190,7 @@ static unsigned int tobit(unsigned int bitmask) } static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu_s *m) { + extern qboolean keydown[]; static playerview_t pv; entity_t ent; vec3_t fwd, rgt, up; @@ -3344,6 +3201,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu vec3_t lightpos = {0, 1, 0}; modelview_t *mods = c->dptr; + skinfile_t *skin; if (R2D_Flush) R2D_Flush(); @@ -3374,6 +3232,32 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu AngleVectors(r_refdef.viewangles, fwd, rgt, up); VectorScale(fwd, -mods->dist, r_refdef.vieworg); + if (keydown[K_MOUSE1] && mods->mousedown) + { + mods->pitch += (mousecursor_y-mods->mousepos[1]) * m_pitch.value * sensitivity.value; + mods->yaw -= (mousecursor_x-mods->mousepos[0]) * m_yaw.value * sensitivity.value; + + if (keydown['w'] || keydown['s'] || keydown['a'] || keydown['d']) + { + VectorAdd(mods->cameraorg, r_refdef.vieworg, mods->cameraorg); + mods->dist = 0; + + if (keydown['w']) + VectorMA(mods->cameraorg, host_frametime*cl_forwardspeed.value, fwd, mods->cameraorg); + if (keydown['s']) + VectorMA(mods->cameraorg, host_frametime*-(cl_backspeed.value?cl_backspeed.value:cl_forwardspeed.value), fwd, mods->cameraorg); + if (keydown['a']) + VectorMA(mods->cameraorg, host_frametime*-cl_sidespeed.value, rgt, mods->cameraorg); + if (keydown['d']) + VectorMA(mods->cameraorg, host_frametime*cl_sidespeed.value, rgt, mods->cameraorg); + } + } + mods->mousedown = keydown[K_MOUSE1]; + mods->mousepos[0] = mousecursor_x; + mods->mousepos[1] = mousecursor_y; + + VectorAdd(r_refdef.vieworg, mods->cameraorg, r_refdef.vieworg); + memset(&ent, 0, sizeof(ent)); // ent.angles[1] = realtime*45;//mods->yaw; // ent.angles[0] = realtime*23.4;//mods->pitch; @@ -3388,7 +3272,8 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu return; //panic! ent.scale = max(max(fabs(ent.model->maxs[0]-ent.model->mins[0]), fabs(ent.model->maxs[1]-ent.model->mins[1])), fabs(ent.model->maxs[2]-ent.model->mins[2])); ent.scale = ent.scale?64.0/ent.scale:1; - ent.origin[2] -= (ent.model->maxs[2]-ent.model->mins[2]) * 0.5;// + ent.model->mins[2]; +// ent.scale = 1; + ent.origin[2] -= ent.model->mins[2] + (ent.model->maxs[2]-ent.model->mins[2]) * 0.5; ent.origin[2] *= ent.scale; Vector4Set(ent.shaderRGBAf, 1, 1, 1, 1); VectorSet(ent.glowmod, 1, 1, 1); @@ -3417,10 +3302,15 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime; ent.framestate.g[FS_REG].endbone = 0x7fffffff; ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum)); + skin = Mod_LookupSkin(ent.customskin); ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66; ent.light_range[0] = ent.light_range[1] = ent.light_range[2] = 0.33; +#ifdef HEXEN2 + ent.drawflags = SCALE_ORIGIN_ORIGIN; +#endif + V_ApplyRefdef(); /* { @@ -3683,7 +3573,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu float duration = 0; qboolean loop = false; if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop)) - fname = "Unknown Frame"; + fname = "Unknown Sequence"; Draw_FunString(0, y, va("Frame%i: %s (%i poses, %f of %f secs, %s)", mods->framegroup, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); y+=8; } @@ -3761,7 +3651,10 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu contents, inf->csurface.flags, inf->surfaceid, - inf->geomset>=MAX_GEOMSETS?-1:inf->geomset, inf->geomid, inf->geomset>=MAX_GEOMSETS?" (always)":"", + inf->geomset>=MAX_GEOMSETS?-1:inf->geomset, inf->geomid, + inf->geomset>=MAX_GEOMSETS?" (always)": + ((skin?skin->geomset[inf->geomset]:0)!=inf->geomid)?" (hidden)": + "", inf->numverts, inf->numindexes/3 #ifdef SKELETALMODELS ,inf->numbones @@ -3895,15 +3788,16 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu } static qboolean M_ModelViewerKey(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) { + extern qboolean keydown[]; modelview_t *mods = c->dptr; - if (key == 'w') + if (key == 'w' && !keydown[K_MOUSE1]) { mods->dist *= 0.9; if (mods->dist < 1) mods->dist = 1; } - else if (key == 's') + else if (key == 's' && !keydown[K_MOUSE1]) mods->dist /= 0.9; else if (key == 'm') { diff --git a/engine/client/merged.h b/engine/client/merged.h index 6c0bd97e..09e421b0 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -56,7 +56,7 @@ typedef enum #define FST_BASE 0 //base frames #define FS_REG 1 //regular frames #define FS_COUNT 2 //regular frames -typedef struct { +typedef struct framestate_s { struct framestateregion_s { int frame[FRAME_BLENDS]; float frametime[FRAME_BLENDS]; @@ -443,6 +443,8 @@ typedef struct rendererinfo_s { void (*VID_SetWindowCaption) (const char *msg); +//FIXME: add clipboard stuff... + //FIXME: remove these... char *(*VID_GetRGBInfo) (int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 4345fd58..94fb674e 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -4809,6 +4809,9 @@ static int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, ctx.scale1 /= m; ctx.scale2 /= m; + if (ptype->randsmax!=1) + ctx.bias1 += ptype->texsstride * (rand()%ptype->randsmax); + //inserts decals through a callback. Mod_ClipDecal(ctx.model, ctx.center, ctx.normal, ctx.tangent2, ctx.tangent1, m, ptype->surfflagmask, ptype->surfflagmatch, PScript_AddDecals, &ctx); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 546cdefc..a7c731a6 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -3387,17 +3387,18 @@ void QCBUILTIN PF_cs_setcustomskin (pubprogfuncs_t *prinst, struct globalvars_s const char *skindata = PF_VarString(prinst, 2, pr_globals); if (ent->skinobject > 0) - { Mod_WipeSkin(ent->skinobject, false); - ent->skinobject = 0; - } + ent->skinobject = 0; if (*fname || *skindata) { if (*skindata) ent->skinobject = Mod_ReadSkinFile(fname, skindata); else - ent->skinobject = -(int)Mod_RegisterSkinFile(fname); + ent->skinobject = Mod_RegisterSkinFile(fname); + + if (*fname) + ent->skinobject *= -1;//negative means it doesn't bother refcounting, just leaves it loaded the whole time. } } void QCBUILTIN PF_cs_loadcustomskin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -3410,7 +3411,7 @@ void QCBUILTIN PF_cs_loadcustomskin (pubprogfuncs_t *prinst, struct globalvars_s if (*skindata) G_FLOAT(OFS_RETURN) = Mod_ReadSkinFile(fname, skindata); else - G_FLOAT(OFS_RETURN) = -(int)Mod_RegisterSkinFile(fname); + G_FLOAT(OFS_RETURN) = Mod_RegisterSkinFile(fname); } else G_FLOAT(OFS_RETURN) = 0; @@ -3426,9 +3427,16 @@ void QCBUILTIN PF_cs_applycustomskin (pubprogfuncs_t *prinst, struct globalvars_ csqcedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0); int newskin = G_FLOAT(OFS_PARM1); int oldskin = ent->skinobject; - ent->skinobject = newskin; + skinfile_t *sk; + ent->skinobject = -abs(newskin); if (oldskin > 0) Mod_WipeSkin(oldskin, false); + if (ent->skinobject > 0) + { //add a ref, so it doesn't get forgotten so fast. + sk = Mod_LookupSkin(ent->skinobject); + if (sk) + sk->refcount++; + } } static void QCBUILTIN PF_ReadByte(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index c4d9f585..f89a3fac 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -208,11 +208,16 @@ extern "C" { #endif #endif -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define min(a,b) ((a) < (b) ? (a) : (b)) +#ifdef __cplusplus + #define q_max(a,b) ((a) > (b) ? (a) : (b)) + #define q_min(a,b) ((a) < (b) ? (a) : (b)) +#else + #ifndef max + #define max(a,b) ((a) > (b) ? (a) : (b)) + #define min(a,b) ((a) < (b) ? (a) : (b)) + #endif + #define max3(a,b,c) max(max(a,b),c) #endif -#define max3(a,b,c) max(max(a,b),c) //msvcrt lacks any and all c99 support. #if defined(_WIN32) @@ -328,6 +333,7 @@ extern cvar_t ezcompat_markup; extern cvar_t sys_ticrate; extern cvar_t sys_nostdout; extern cvar_t developer; +extern cvar_t host_mapname; extern cvar_t password; diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 42862efe..844c389f 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -16,6 +16,7 @@ We also have no doppler with WebAudio. "build/openal-soft-1.19.1/Alc/filters/filter.c:25: BiquadFilter_setParams: Assertion `gain > 0.00001f' failed." + SIGABRT bug started with 1.19.1. Not fte's bug. either disable reverb or disable openal. + (happens when reverb properties are changed too fast) AL_OUT_OF_MEMORY shitty openal implementation with too-low limits on number of sources. diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 867ae960..6e37281e 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -80,7 +80,7 @@ cvar_t volume = CVARAFD( "volume", "0.7", /*q3*/"s_volume",CVAR_ARCHIVE, cvar_t nosound = CVARFD( "nosound", "0", CVAR_ARCHIVE, "Disable all sound from the engine. Cannot be overriden by configs or anything if set via the -nosound commandline argument."); -cvar_t precache = CVARAF( "s_precache", "1", +cvar_t snd_precache = CVARAF( "s_precache", "1", "precache", 0); cvar_t loadas8bit = CVARAFD( "s_loadas8bit", "0", "loadas8bit", CVAR_ARCHIVE, @@ -2299,7 +2299,7 @@ void S_Init (void) Cvar_Register(&nosound, "Sound controls"); Cvar_Register(&mastervolume, "Sound controls"); Cvar_Register(&volume, "Sound controls"); - Cvar_Register(&precache, "Sound controls"); + Cvar_Register(&snd_precache, "Sound controls"); Cvar_Register(&loadas8bit, "Sound controls"); Cvar_Register(&snd_loadasstereo, "Sound controls"); Cvar_Register(&bgmvolume, "Sound controls"); @@ -2590,7 +2590,7 @@ sfx_t *S_PrecacheSound2 (const char *name, qboolean syspath) sfx = S_FindName (name, true, syspath); // cache it in - if (precache.ival && sndcardinfo) + if (snd_precache.ival && snd_precache.ival != 2 && sndcardinfo) S_LoadSound (sfx, true); return sfx; diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 2985d1f4..075fe536 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -1267,7 +1267,7 @@ qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refres #endif } -#if !defined(GLQUAKE) && !defined(VKQUAKE) +#if defined(NO_X11) #define SYS_CLIPBOARD_SIZE 256 static char clipboard_buffer[SYS_CLIPBOARD_SIZE] = {0}; diff --git a/engine/client/vid.h b/engine/client/vid.h index ed5c9898..23583aaf 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -47,6 +47,7 @@ typedef struct { qboolean stereo; int srgb; //<0 = gamma-only. 0 = no srgb at all, >0 full srgb, including textures and stuff int bpp; //16, 24(aka 32), 30, and 48 are meaningful + int depthbits; int rate; int wait; //-1 = default, 0 = off, 1 = on, 2 = every other int multisample; //for opengl antialiasing (which requires context stuff) diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index c781b229..4c7d6eee 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -113,7 +113,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif -#ifdef IMGTOOL +#if defined(IMGTOOL) || defined(IQMTOOL) #undef WEBCLIENT #undef LOADERTHREAD #elif defined(MASTERONLY) diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index ef087f80..0cc9c7ef 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -247,7 +247,7 @@ void QDECL Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v, q #ifdef SKELETALMODELS -/*like above, but guess the quat.w*/ +/*like GenMatrixPosQuat4Scale, but guess the quat.w*/ static void GenMatrixPosQuat3Scale(vec3_t const pos, vec3_t const quat3, vec3_t const scale, float result[12]) { vec4_t quat4; @@ -1369,11 +1369,51 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, gali { boneidx_t *fte_restrict bidx = inf->ofs_skel_idx[0]; float *fte_restrict weight = inf->ofs_skel_weight[0]; + const float *morphweights; if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE) meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); - if ((1)) + morphweights = inf->AnimateMorphs?inf->AnimateMorphs(inf, framestate):NULL; + if (morphweights) + { + size_t m,v; + float w; + vecV_t *xyz = alloca(sizeof(*xyz)*inf->numverts), *inxyz; + vec3_t *norm = alloca(sizeof(*norm)*inf->numverts), *innorm; + vec3_t *sdir = alloca(sizeof(*sdir)*inf->numverts), *insdir; + vec3_t *tdir = alloca(sizeof(*tdir)*inf->numverts), *intdir; + memcpy(xyz, inf->ofs_skel_xyz, sizeof(*xyz)*inf->numverts); + memcpy(norm, inf->ofs_skel_norm, sizeof(*norm)*inf->numverts); + memcpy(sdir, inf->ofs_skel_svect, sizeof(*sdir)*inf->numverts); + memcpy(tdir, inf->ofs_skel_tvect, sizeof(*tdir)*inf->numverts); + for (m = 0; m < inf->nummorphs; m++) + { + if (morphweights[m] <= 0) + continue; + inxyz = inf->ofs_skel_xyz + (m+1)*inf->numverts; + innorm = inf->ofs_skel_norm + (m+1)*inf->numverts; + insdir = inf->ofs_skel_svect + (m+1)*inf->numverts; + intdir = inf->ofs_skel_tvect + (m+1)*inf->numverts; + w = morphweights[m]; + for (v = 0; v < inf->numverts; v++) + { + VectorMA(xyz[v], w, inxyz[v], xyz[v]); + VectorMA(norm[v], w, innorm[v], norm[v]); + VectorMA(sdir[v], w, insdir[v], sdir[v]); + VectorMA(tdir[v], w, intdir[v], tdir[v]); + } + } + + //right, now do the bones thing. + Alias_TransformVerticies_VNST(meshcache.usebonepose, inf->numverts, bidx, weight, + xyz[0], mesh->xyz_array[0], + norm[0], mesh->normals_array[0], + sdir[0], mesh->snormals_array[0], + tdir[0], mesh->tnormals_array[0] + ); + } + else if ((1)) Alias_TransformVerticies_VNST(meshcache.usebonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], mesh->xyz_array[0], inf->ofs_skel_norm[0], mesh->normals_array[0], @@ -1388,7 +1428,7 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, gali } #if !defined(SERVERONLY) -static void Alias_BuildSkeletalVerts(float *xyzout, framestate_t *framestate, galiasinfo_t *inf) +static void Alias_BuildSkeletalVerts(float *xyzout, float *normout, framestate_t *framestate, galiasinfo_t *inf) { float buffer[MAX_BONES*12]; float bufferalt[MAX_BONES*12]; @@ -1396,7 +1436,10 @@ static void Alias_BuildSkeletalVerts(float *xyzout, framestate_t *framestate, ga float *fte_restrict weight = inf->ofs_skel_weight[0]; const float *bonepose = Alias_GetBoneInformation(inf, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES); - Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], xyzout); + if (normout) + Alias_TransformVerticies_VN(bonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], xyzout, inf->ofs_skel_norm[0], normout); + else + Alias_TransformVerticies_V(bonepose, inf->numverts, bidx, weight, inf->ofs_skel_xyz[0], xyzout); } #endif @@ -1696,7 +1739,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in usebones = false; else if (inf->ofs_skel_xyz && !inf->ofs_skel_weight) usebones = false; - else if (e->fatness || !inf->ofs_skel_idx || (!inf->mappedbones && inf->numbones > sh_config.max_gpu_bones)) + else if (e->fatness || !inf->ofs_skel_idx || (!inf->mappedbones && inf->numbones > sh_config.max_gpu_bones) || inf->nummorphs) #endif usebones = false; @@ -2108,8 +2151,8 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qbool else if (surfnum != surfaceidx) continue; + normdata = NULL; #ifdef SKELETALMODELS - normdata = mod->ofs_skel_norm; if (mod->numbones) { if (!mod->ofs_skel_idx) @@ -2119,7 +2162,8 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qbool cursurfnum = mod->shares_verts; posedata = alloca(mod->numverts*sizeof(vecV_t)); - Alias_BuildSkeletalVerts((float*)posedata, &ent->framestate, mod); + normdata = normals?alloca(mod->numverts*sizeof(vec3_t)):NULL; + Alias_BuildSkeletalVerts((float*)posedata, (float*)normdata, &ent->framestate, mod); } //else posedata = posedata; } @@ -2131,6 +2175,7 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qbool if (!mod->numanimations) { #ifdef SKELETALMODELS + normdata = mod->ofs_skel_norm; if (mod->ofs_skel_xyz) posedata = mod->ofs_skel_xyz; else @@ -2148,6 +2193,7 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qbool pose = group->poseofs; pose += (int)(ent->framestate.g[FS_REG].frametime[0] * group->rate)%group->numposes; posedata = pose->ofsverts; + normdata = pose->ofsnormals; } #endif @@ -2175,14 +2221,14 @@ void Mod_AddSingleSurface(entity_t *ent, int surfaceidx, shader_t *shader, qbool cl_stris_ExpandVerts(cl_numstrisvert+t->numvert); for (i = 0; i < mod->numverts; i++) { - VectorMA(ent->origin, posedata[i][0], ent->axis[0], tmp); + VectorMA(vec3_origin, posedata[i][0], ent->axis[0], tmp); VectorMA(tmp, posedata[i][1], ent->axis[1], tmp); VectorMA(tmp, posedata[i][2], ent->axis[2], tmp); VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i*2+0]); - VectorMA(tmp, 0.1*normdata[i][0], ent->axis[0], tmp); - VectorMA(tmp, 0.1*normdata[i][1], ent->axis[1], tmp); - VectorMA(tmp, 0.1*normdata[i][2], ent->axis[2], tmp); + VectorMA(tmp, normdata[i][0], ent->axis[0], tmp); + VectorMA(tmp, normdata[i][1], ent->axis[1], tmp); + VectorMA(tmp, normdata[i][2], ent->axis[2], tmp); VectorMA(ent->origin, ent->scale, tmp, cl_strisvertv[t->firstvert+i*2+1]); Vector2Set(cl_strisvertt[t->firstvert+i*2+0], 0.0, 0.0); @@ -3536,7 +3582,7 @@ typedef struct #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) #define FLOODFILL_STEP( off, dx, dy ) \ -{ \ +do{ \ if (pos[off] == fillcolor) \ { \ pos[off] = 255; \ @@ -3544,7 +3590,7 @@ typedef struct inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ } \ else if (pos[off] != 255) fdc = pos[off]; \ -} +}while(0) static void Mod_FloodFillSkin( qbyte *skin, int skinwidth, int skinheight ) { @@ -8448,9 +8494,9 @@ static qboolean QDECL Mod_LoadInterQuakeModel(model_t *mod, void *buffer, size_t static qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *prototype, void**poseofs, galiasanimation_t *gat) { -#define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return false; } -#define MD5ERROR1PARAM(x, y) { Con_Printf(CON_ERROR x "\n", y); return false; } -#define EXPECT(x) buffer = COM_ParseOut(buffer, token, sizeof(token)); if (strcmp(token, x)) MD5ERROR1PARAM("MD5ANIM: expected %s", x); +#define MD5ERROR0PARAM(x) do{ Con_Printf(CON_ERROR x "\n"); return false; }while(0) +#define MD5ERROR1PARAM(x, y) do{ Con_Printf(CON_ERROR x "\n", y); return false; }while(0) +#define EXPECT(x) do{buffer = COM_ParseOut(buffer, token, sizeof(token)); if (strcmp(token, x)) MD5ERROR1PARAM("MD5ANIM: expected %s", x);}while(0) unsigned int i, j; galiasanimation_t grp; @@ -8658,9 +8704,9 @@ static qboolean Mod_ParseMD5Anim(model_t *mod, char *buffer, galiasinfo_t *proto static galiasinfo_t *Mod_ParseMD5MeshModel(model_t *mod, char *buffer, char *modname) { -#define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return NULL; } -#define MD5ERROR1PARAM(x, y) { Con_Printf(CON_ERROR x "\n", y); return NULL; } -#define EXPECT(x) buffer = COM_ParseOut(buffer, token, sizeof(token)); if (strcmp(token, x)) Sys_Error("MD5MESH: expected %s", x); +#define MD5ERROR0PARAM(x) do{ Con_Printf(CON_ERROR x "\n"); return NULL; }while(0) +#define MD5ERROR1PARAM(x, y) do{ Con_Printf(CON_ERROR x "\n", y); return NULL; }while(0) +#define EXPECT(x) do{buffer = COM_ParseOut(buffer, token, sizeof(token)); if (strcmp(token, x)) Sys_Error("MD5MESH: expected %s", x);}while(0) int numjoints = 0; int nummeshes = 0; qboolean foundjoints = false; diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 884a13e7..25895fc8 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -1,6 +1,8 @@ #ifndef COM_MESH_H #define COM_MESH_H +#include "quakedef.h" + #ifdef __cplusplus extern "C" { #endif @@ -177,6 +179,8 @@ typedef struct galiasinfo_s #ifdef SKELETALMODELS boneidx_t *bonemap; //filled in automatically if our mesh has more gpu bones than we can support unsigned int mappedbones; + unsigned int nummorphs; //extra data after the xyz/norm/stvect arrays + const float *(QDECL *AnimateMorphs)(const struct galiasinfo_s *surf, const framestate_t *framestate); float *baseframeofs; /*non-heirachical*/ int numbones; diff --git a/engine/common/common.c b/engine/common/common.c index 3697b324..31abcd04 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -89,22 +89,21 @@ cvar_t developer = CVAR("developer","1"); cvar_t developer = CVARD("developer","0", "Enables the spewing of additional developer/debugging messages. 2 will give even more spam, much of it unwanted."); #endif -cvar_t registered = CVARD("registered","0","Set if quake's pak1.pak is available"); -cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version for server browsers"); -cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers"); -cvar_t gameversion_max = CVARD("gameversion_max","", "gamecode version for server browsers"); -cvar_t fs_gamename = CVARAD("com_fullgamename", NULL, "fs_gamename", "The filesystem is trying to run this game"); -cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers."); -cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers. -cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. +cvar_t registered = CVARD("registered","0","Set if quake's pak1.pak is available"); +cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version for server browsers"); +cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers"); +cvar_t gameversion_max = CVARD("gameversion_max","", "gamecode version for server browsers"); +cvar_t fs_gamename = CVARAD("com_fullgamename", NULL, "fs_gamename", "The filesystem is trying to run this game"); +cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers."); +cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers. +cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. +cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); +cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients."); +cvar_t sys_platform = CVAR("sys_platform", PLATFORM); +cvar_t host_mapname = CVARAFD("mapname", "", "host_mapname", 0, "Cvar that holds the short name of the current map, for scripting type stuff"); #ifdef HAVE_LEGACY -cvar_t ezcompat_markup = CVARD("ezcompat_markup", "1", "Attempt compatibility with ezquake's text markup.0: disabled.\n1: Handle markup ampersand markup.\n2: Handle chevron markup (only in echo commands, for config compat, because its just too unreliable otherwise)."); -#endif -cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); -cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients."); -cvar_t sys_platform = CVAR("sys_platform", PLATFORM); -#ifdef HAVE_LEGACY -cvar_t pm_noround = CVARD("pm_noround", "0", "Disables player prediction snapping, in a way that cannot be reliably predicted but may be needed to avoid map bugs."); +cvar_t ezcompat_markup = CVARD("ezcompat_markup", "1", "Attempt compatibility with ezquake's text markup.0: disabled.\n1: Handle markup ampersand markup.\n2: Handle chevron markup (only in echo commands, for config compat, because its just too unreliable otherwise)."); +cvar_t pm_noround = CVARD("pm_noround", "0", "Disables player prediction snapping, in a way that cannot be reliably predicted but may be needed to avoid map bugs."); #endif qboolean com_modified; // set true if using non-id files @@ -5847,6 +5846,7 @@ void COM_Init (void) #endif COM_InitFilesystem (); + Cvar_Register (&host_mapname, "Scripting"); Cvar_Register (&developer, "Debugging"); Cvar_Register (&sys_platform, "Gamecode"); Cvar_Register (®istered, "Copy protection"); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index f4df427c..08647e0d 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -2258,6 +2258,9 @@ static qboolean CModQ3_LoadSubmodels (model_t *mod, qbyte *mod_base, lump_t *l) } out->firstsurface = LittleLong (in->firstsurface); out->numsurfaces = LittleLong (in->num_surfaces); + + out->firstbrush = LittleLong(in->firstbrush); + out->num_brushes = LittleLong(in->num_brushes); if (!i) { out->headnode = mod->nodes; @@ -2269,9 +2272,6 @@ static qboolean CModQ3_LoadSubmodels (model_t *mod, qbyte *mod_base, lump_t *l) out->headleaf = bleaf; out->headnode = NULL; -// out->firstbrush = LittleLong(in->firstbrush); -// out->num_brushes = LittleLong(in->num_brushes); - bleaf->numleafbrushes = LittleLong ( in->num_brushes ); bleaf->firstleafbrush = prv->numleafbrushes; bleaf->contents = 0; @@ -6362,15 +6362,24 @@ return; CM_RecursiveHullCheck (mod, node->childnum[side^1], midf, p2f, mid, p2); } +#define BIH_USEBIH +//#define BIH_USEBVH struct bihnode_s { //in a bih tree there are two values per node instead of a kd-tree's single midpoint //this allows the two sides to overlap, which prevents the need to chop large objects into multiple leafs //(it also allows gaps in the middle, which can further skip recursion) enum { +#ifdef BIH_USEBIH BIH_X, BIH_Y, BIH_Z, +#endif +#ifdef BIH_USEBVH + BVH_X, + BVH_Y, + BVH_Z, +#endif BIH_GROUP, BIH_BRUSH, BIH_PATCHBRUSH, @@ -6382,11 +6391,21 @@ struct bihnode_s int firstchild; int numchildren; } group; +#ifdef BIH_USEBVH + struct{ + int firstchild; + vec3_t min, max; + float cmin; + float cmax; + } bvhnode; +#endif +#ifdef BIH_USEBIH struct{ int firstchild; float cmin[2]; float cmax[2]; - } node; + } bihnode; +#endif struct bihdata_s{ unsigned int contents; union { @@ -6449,6 +6468,7 @@ static void CM_RecursiveBIHTrace (struct bihtrace_s *fte_restrict tr, const stru CM_RecursiveBIHTrace(tr, node+node->group.firstchild+i, movesubbounds, nodebox); } return; +#ifdef BIH_USEBIH case BIH_X: case BIH_Y: case BIH_Z: @@ -6456,31 +6476,31 @@ static void CM_RecursiveBIHTrace (struct bihtrace_s *fte_restrict tr, const stru struct bihbox_s bounds; struct bihbox_s newbounds; float distnear, distfar, nearfrac, farfrac, min, max; - unsigned int axis = node->type, child; + unsigned int axis = node->type-BIH_X, child, a, s; vec3_t points[2]; if (!tr->totalmove[axis]) { //doesn't move with respect to this axis. don't allow infinities. for (child = 0; child < 2; child++) { //only recurse if we are actually within the child - min = node->node.cmin[child] - tr->expand[axis]; - max = node->node.cmax[child] + tr->expand[axis]; + min = node->bihnode.cmin[child] - tr->expand[axis]; + max = node->bihnode.cmax[child] + tr->expand[axis]; if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) { bounds = *nodebox; bounds.min[axis] = min; bounds.max[axis] = max; - CM_RecursiveBIHTrace(tr, node+node->node.firstchild+child, movesubbounds, &bounds); + CM_RecursiveBIHTrace(tr, node+node->bihnode.firstchild+child, movesubbounds, &bounds); } } } else if (tr->negativedir[axis]) { //trace goes from right to left so favour the right. + bounds = *nodebox; for (child = 2; child-- > 0;) { - bounds = *nodebox; - bounds.min[axis] = node->node.cmin[child] - tr->expand[axis]; - bounds.max[axis] = node->node.cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size + bounds.min[axis] = node->bihnode.cmin[child] - tr->expand[axis]; + bounds.max[axis] = node->bihnode.cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size if (!BoundsIntersect(movesubbounds->min, movesubbounds->max, bounds.min, bounds.max)) continue; @@ -6498,20 +6518,23 @@ static void CM_RecursiveBIHTrace (struct bihtrace_s *fte_restrict tr, const stru farfrac = distfar/tr->totalmove[axis]; VectorMA(tr->startpos, farfrac, tr->totalmove, points[1]); //clip the new movebounds (this is more to clip the other axis too) - newbounds.min[0] = max(points[tr->negativedir[0]][0]-tr->expand[axis], bounds.min[0]); newbounds.max[0] = min(points[!tr->negativedir[0]][0]+tr->expand[axis], bounds.max[0]); - newbounds.min[1] = max(points[tr->negativedir[1]][1]-tr->expand[axis], bounds.min[1]); newbounds.max[1] = min(points[!tr->negativedir[1]][1]+tr->expand[axis], bounds.max[1]); - newbounds.min[2] = max(points[tr->negativedir[2]][2]-tr->expand[axis], bounds.min[2]); newbounds.max[2] = min(points[!tr->negativedir[2]][2]+tr->expand[axis], bounds.max[2]); - CM_RecursiveBIHTrace(tr, node+node->node.firstchild+child, &newbounds, &bounds); + for (a = 0; a < 3; a++) + { + s = points[0][a] > points[1][a]; + newbounds.min[a] = max(movesubbounds->min[a], points[s][a] - tr->expand[a]); + newbounds.max[a] = min(movesubbounds->max[a], points[!s][a] + tr->expand[a]); + } + CM_RecursiveBIHTrace(tr, node+node->bihnode.firstchild+child, &newbounds, &bounds); } } } else { //trace goes from left to right + bounds = *nodebox; for (child = 0; child < 2; child++) { - bounds = *nodebox; - bounds.min[axis] = node->node.cmin[child] - tr->expand[axis]; - bounds.max[axis] = node->node.cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size + bounds.min[axis] = node->bihnode.cmin[child] - tr->expand[axis]; + bounds.max[axis] = node->bihnode.cmax[child] + tr->expand[axis]; //expand the bounds according to the player's size if (!BoundsIntersect(movesubbounds->min, movesubbounds->max, bounds.min, bounds.max)) continue; @@ -6529,15 +6552,143 @@ static void CM_RecursiveBIHTrace (struct bihtrace_s *fte_restrict tr, const stru farfrac = distfar/tr->totalmove[axis]; VectorMA(tr->startpos, farfrac, tr->totalmove, points[1]); //clip the new movebounds (this is more to clip the other axis too) - newbounds.min[0] = max(points[tr->negativedir[0]][0]-tr->expand[axis], bounds.min[0]); newbounds.max[0] = min(points[!tr->negativedir[0]][0]+tr->expand[axis], bounds.max[0]); - newbounds.min[1] = max(points[tr->negativedir[1]][1]-tr->expand[axis], bounds.min[1]); newbounds.max[1] = min(points[!tr->negativedir[1]][1]+tr->expand[axis], bounds.max[1]); - newbounds.min[2] = max(points[tr->negativedir[2]][2]-tr->expand[axis], bounds.min[2]); newbounds.max[2] = min(points[!tr->negativedir[2]][2]+tr->expand[axis], bounds.max[2]); - CM_RecursiveBIHTrace(tr, node+node->node.firstchild+child, &newbounds, &bounds); + for (a = 0; a < 3; a++) + { + s = points[0][a] > points[1][a]; + newbounds.min[a] = max(movesubbounds->min[a], points[s][a] - tr->expand[a]); + newbounds.max[a] = min(movesubbounds->max[a], points[!s][a] + tr->expand[a]); + } + CM_RecursiveBIHTrace(tr, node+node->bihnode.firstchild+child, &newbounds, &bounds); } } } } return; +#endif +#ifdef BIH_USEBVH + case BVH_X: + case BVH_Y: + case BVH_Z: + { + struct bihbox_s bounds; + struct bihbox_s newbounds; + float distnear, distfar, nearfrac, farfrac, min, max; + unsigned int axis = node->type-BVH_X, child, a, s; + vec3_t points[2]; + + if (!tr->totalmove[axis]) + { //doesn't move with respect to this axis. don't allow infinities. + for (child = 0; child < 2; child++) + { //only recurse if we are actually within the child + if (child == 0) + { + min = node->bvhnode.min[axis] - tr->expand[axis]; + max = node->bvhnode.cmax + tr->expand[axis]; + } + else + { + min = node->bvhnode.cmin - tr->expand[axis]; + max = node->bvhnode.max[axis] + tr->expand[axis]; + } + if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + { + VectorCopy(node->bvhnode.min, bounds.min); + VectorCopy(node->bvhnode.max, bounds.max); + bounds.min[axis] = min; + bounds.max[axis] = max; + CM_RecursiveBIHTrace(tr, node+node->bvhnode.firstchild+child, movesubbounds, &bounds); + } + } + } + else if (tr->negativedir[axis]) + { //trace goes from right to left so favour the right. + VectorCopy(node->bvhnode.min, bounds.min); + VectorCopy(node->bvhnode.max, bounds.max); + for (child = 2; child-- > 0;) + { + if (child == 0) + { + bounds.min[axis] = node->bvhnode.min[axis] - tr->expand[axis]; + bounds.max[axis] = node->bvhnode.cmax + tr->expand[axis]; //expand the bounds according to the player's size + } + else + { + bounds.min[axis] = node->bvhnode.cmin - tr->expand[axis]; + bounds.max[axis] = node->bvhnode.max[axis] + tr->expand[axis]; //expand the bounds according to the player's size + } + + if (!BoundsIntersect(movesubbounds->min, movesubbounds->max, bounds.min, bounds.max)) + continue; +// if (movesubbounds->max[axis] < bounds.min[axis]) +// continue; //(clipped) move bounds is outside this child +// if (bounds.max[axis] < movesubbounds->min[axis]) +// continue; //(clipped) move bounds is outside this child + + distnear = bounds.max[axis] - tr->startpos[axis]; + nearfrac = (distnear+DIST_EPSILON)/tr->totalmove[axis]; + if (nearfrac <= trace_truefraction) + { + VectorMA(tr->startpos, nearfrac, tr->totalmove, points[0]); //clip the new movebounds (this is more to clip the other axis too) + distfar = bounds.min[axis] - tr->startpos[axis]; + farfrac = (distfar-DIST_EPSILON)/tr->totalmove[axis]; + VectorMA(tr->startpos, farfrac, tr->totalmove, points[1]); //clip the new movebounds (this is more to clip the other axis too) + + for (a = 0; a < 3; a++) + { + s = points[0][a] > points[1][a]; + newbounds.min[a] = max(movesubbounds->min[a], points[s][a] - tr->expand[a]); + newbounds.max[a] = min(movesubbounds->max[a], points[!s][a] + tr->expand[a]); + } + CM_RecursiveBIHTrace(tr, node+node->bvhnode.firstchild+child, &newbounds, &bounds); + } + } + } + else + { //trace goes from left to right + VectorCopy(node->bvhnode.min, bounds.min); + VectorCopy(node->bvhnode.max, bounds.max); + for (child = 0; child < 2; child++) + { + if (child == 0) + { + bounds.min[axis] = node->bvhnode.min[axis] - tr->expand[axis]; + bounds.max[axis] = node->bvhnode.cmax + tr->expand[axis]; //expand the bounds according to the player's size + } + else + { + bounds.min[axis] = node->bvhnode.cmin - tr->expand[axis]; + bounds.max[axis] = node->bvhnode.max[axis] + tr->expand[axis]; //expand the bounds according to the player's size + } + + if (!BoundsIntersect(movesubbounds->min, movesubbounds->max, bounds.min, bounds.max)) + continue; +// if (movesubbounds->max[axis] < bounds.min[axis]) +// continue; //(clipped) move bounds is outside this child +// if (bounds.max[axis] < movesubbounds->min[axis]) +// continue; //(clipped) move bounds is outside this child + + distnear = bounds.min[axis] - tr->startpos[axis]; + nearfrac = (distnear-DIST_EPSILON)/tr->totalmove[axis]; + if (nearfrac <= trace_truefraction) + { + VectorMA(tr->startpos, nearfrac, tr->totalmove, points[0]); //clip the new movebounds (this is more to clip the other axis too) + distfar = bounds.max[axis] - tr->startpos[axis]; + farfrac = (distfar+DIST_EPSILON)/tr->totalmove[axis]; + VectorMA(tr->startpos, farfrac, tr->totalmove, points[1]); //clip the new movebounds (this is more to clip the other axis too) + + for (a = 0; a < 3; a++) + { + s = points[0][a] > points[1][a]; + newbounds.min[a] = max(movesubbounds->min[a], points[s][a] - tr->expand[a]); + newbounds.max[a] = min(movesubbounds->max[a], points[!s][a] + tr->expand[a]); + } + CM_RecursiveBIHTrace(tr, node+node->bvhnode.firstchild+child, &newbounds, &bounds); + } + } + } + } + return; +#endif } FTE_UNREACHABLE; } @@ -6581,30 +6732,58 @@ static void CM_RecursiveBIHTest (struct bihtrace_s *fte_restrict tr, const struc } } return; +#ifdef BIH_USEBIH case BIH_X: case BIH_Y: case BIH_Z: { //node (x y or z) float min; float max; - int axis = node->type; - min = node->node.cmin[0] - tr->expand[axis]; - max = node->node.cmax[0] + tr->expand[axis]; //expand the bounds according to the player's size + int axis = node->type - BIH_X; + min = node->bihnode.cmin[0] - tr->expand[axis]; + max = node->bihnode.cmax[0] + tr->expand[axis]; //expand the bounds according to the player's size //the point can potentially be within both children, or neither. //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) { - CM_RecursiveBIHTest(tr, node+node->node.firstchild+0); + CM_RecursiveBIHTest(tr, node+node->bihnode.firstchild+0); if (trace_trace.allsolid) return; } - min = node->node.cmin[1] - tr->expand[axis]; - max = node->node.cmax[1] + tr->expand[axis]; + min = node->bihnode.cmin[1] - tr->expand[axis]; + max = node->bihnode.cmax[1] + tr->expand[axis]; if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) - return CM_RecursiveBIHTest(tr, node+node->node.firstchild+1); + return CM_RecursiveBIHTest(tr, node+node->bihnode.firstchild+1); } return; +#endif +#ifdef BIH_USEBVH + case BVH_X: + case BVH_Y: + case BVH_Z: + { //node (x y or z) + float min; float max; + int axis = node->type - BVH_X; + min = node->bvhnode.min[axis] - tr->expand[axis]; + max = node->bvhnode.cmax + tr->expand[axis]; //expand the bounds according to the player's size + + //the point can potentially be within both children, or neither. + //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. + if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + { + CM_RecursiveBIHTest(tr, node+node->bvhnode.firstchild+0); + if (trace_trace.allsolid) + return; + } + + min = node->bvhnode.cmin - tr->expand[axis]; + max = node->bvhnode.max[axis] + tr->expand[axis]; + if (min <= tr->startpos[axis] && tr->startpos[axis] <= max) + return CM_RecursiveBIHTest(tr, node+node->bvhnode.firstchild+1); + } + return; +#endif } FTE_UNREACHABLE; } @@ -6646,23 +6825,46 @@ static unsigned int CM_PointContentsBIH (const struct bihnode_s *fte_restrict no contents |= CM_PointContentsBIH(node+node->group.firstchild+i, p); return contents; } +#ifdef BIH_USEBIH case BIH_X: case BIH_Y: case BIH_Z: { //node (x y or z) unsigned int contents; + unsigned int axis = node->type - BIH_X; //the point can potentially be within both children, or neither. //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. - if (node->node.cmin[0] <= p[node->type] && p[node->type] <= node->node.cmax[0]) - contents = CM_PointContentsBIH(node+node->node.firstchild+0, p); + if (node->bihnode.cmin[0] <= p[axis] && p[axis] <= node->bihnode.cmax[0]) + contents = CM_PointContentsBIH(node+node->bihnode.firstchild+0, p); else contents = 0; - if (node->node.cmin[1] <= p[node->type] && p[node->type] <= node->node.cmax[1]) - contents |= CM_PointContentsBIH(node+node->node.firstchild+1, p); + if (node->bihnode.cmin[1] <= p[axis] && p[axis] <= node->bihnode.cmax[1]) + contents |= CM_PointContentsBIH(node+node->bihnode.firstchild+1, p); return contents; } +#endif +#ifdef BIH_USEBVH + case BVH_X: + case BVH_Y: + case BVH_Z: + { //node (x y or z) + unsigned int contents; + unsigned int axis = node->type - BVH_X; + + //the point can potentially be within both children, or neither. + //it doesn't really matter which order we walk the tree, just be sure to do it efficiently. + if (node->bvhnode.min[axis] <= p[axis] && p[axis] <= node->bvhnode.cmax) + contents = CM_PointContentsBIH(node+node->bvhnode.firstchild+0, p); + else + contents = 0; + + if (node->bvhnode.cmin <= p[axis] && p[axis] <= node->bvhnode.max[axis]) + contents |= CM_PointContentsBIH(node+node->bvhnode.firstchild+1, p); + return contents; + } +#endif } FTE_UNREACHABLE; } @@ -6675,6 +6877,7 @@ struct bihleaf_s struct bihdata_s data; }; +#if defined(BIH_USEBIH) || defined(BIH_USEBVH) static int QDECL CM_SortBIH_X (const void *va, const void *vb) { const struct bihleaf_s *a = va, *b = vb; @@ -6702,6 +6905,7 @@ static int QDECL CM_SortBIH_Z (const void *va, const void *vb) return 0; return am > bm; } +#endif static struct bihbox_s CM_BuildBIHNode (struct bihnode_s *node, struct bihnode_s **freenodes, struct bihleaf_s *leafs, size_t numleafs) { struct bihbox_s bounds; @@ -6720,27 +6924,8 @@ static struct bihbox_s CM_BuildBIHNode (struct bihnode_s *node, struct bihnode_s bounds.max[i] += 1; } } - else if (numleafs < 8) //the leaf just gives the brush pointer. - { - struct bihnode_s *cnodes; - struct bihbox_s cb; - size_t i; - node->type = BIH_GROUP; - - cnodes = *freenodes; - *freenodes += numleafs; - node->group.firstchild = cnodes - node; - node->group.numchildren = numleafs; - - bounds = CM_BuildBIHNode(cnodes+0, freenodes, leafs+0, 1); - for (i = 1; i < numleafs; i++) - { - cb = CM_BuildBIHNode(cnodes+i, freenodes, leafs+i, 1); - AddPointToBounds(cb.min, bounds.min, bounds.max); - AddPointToBounds(cb.max, bounds.min, bounds.max); - } - } - else +#ifdef BIH_USEBIH + else if (numleafs >= 8) //the leaf just gives the brush pointer. { size_t i, j; size_t numleft = numleafs / 2; //this ends up splitting at the median point. @@ -6799,23 +6984,126 @@ static struct bihbox_s CM_BuildBIHNode (struct bihnode_s *node, struct bihnode_s node->type = BIH_Z;*/ } #endif - qsort(leafs, numleafs, sizeof(*leafs), sorts[node->type]); + qsort(leafs, numleafs, sizeof(*leafs), sorts[node->type-BIH_X]); cnodes = *freenodes; *freenodes += 2; - node->node.firstchild = cnodes - node; + node->bihnode.firstchild = cnodes - node; left = CM_BuildBIHNode (cnodes+0, freenodes, leafs, numleft); right = CM_BuildBIHNode (cnodes+1, freenodes, &leafs[numleft], numright); - node->node.cmin[0] = left.min[node->type]; - node->node.cmax[0] = left.max[node->type]; - node->node.cmin[1] = right.min[node->type]; - node->node.cmax[1] = right.max[node->type]; + node->bihnode.cmin[0] = left.min[node->type-BIH_X]; + node->bihnode.cmax[0] = left.max[node->type-BIH_X]; + node->bihnode.cmin[1] = right.min[node->type-BIH_X]; + node->bihnode.cmax[1] = right.max[node->type-BIH_X]; bounds = left; AddPointToBounds(right.min, bounds.min, bounds.max); AddPointToBounds(right.max, bounds.min, bounds.max); } +#endif +#ifdef BIH_USEBVH + else if (numleafs >= 8) //the leaf just gives the brush pointer. + { + size_t i, j; + size_t numleft = numleafs / 2; //this ends up splitting at the median point. + size_t numright = numleafs - numleft; + struct bihbox_s left, right; + struct bihnode_s *cnodes; + static int (QDECL *sorts[3]) (const void *va, const void *vb) = {CM_SortBIH_X, CM_SortBIH_Y, CM_SortBIH_Z}; + VectorCopy(leafs[0].mins, bounds.min); + VectorCopy(leafs[0].maxs, bounds.max); + for (i = 1; i < numleafs; i++) + { + for(j = 0; j < 3; j++) + { + if (bounds.min[j] > leafs[i].mins[j]) + bounds.min[j] = leafs[i].mins[j]; + if (bounds.max[j] < leafs[i].maxs[j]) + bounds.max[j] = leafs[i].maxs[j]; + } + } +#if 1 + { //balanced by counts + vec3_t mid; + int onleft[3], onright[3], weight[3]; + VectorAvg(bounds.max, bounds.min, mid); + VectorClear(onleft); + VectorClear(onright); + for (i = 0; i < numleafs; i++) + { + for (j = 0; j < 3; j++) + { //ignore leafs that split the node. + if (leafs[i].maxs[j] < mid[j]) + onleft[j]++; + if (mid[j] > leafs[i].mins[j]) + onright[j]++; + } + } + for (j = 0; j < 3; j++) + weight[j] = onleft[j]+onright[j] - abs(onleft[j]-onright[j]); + //pick the most balanced. + if (weight[0] > weight[1] && weight[0] > weight[2]) + node->type = BVH_X; + else if (weight[1] > weight[2]) + node->type = BVH_Y; + else + node->type = BVH_Z; + } +#else + { //balanced by volume + vec3_t size; + VectorSubtract(bounds.max, bounds.min, size); + if (size[0] > size[1] && size[0] > size[2]) + node->type = BVH_X; + else if (size[1] > size[2]) + node->type = BVH_Y; + else + node->type = BVH_Z;*/ + } +#endif + qsort(leafs, numleafs, sizeof(*leafs), sorts[node->type-BVH_X]); + + cnodes = *freenodes; + *freenodes += 2; + node->bvhnode.firstchild = cnodes - node; + left = CM_BuildBIHNode (cnodes+0, freenodes, leafs, numleft); + right = CM_BuildBIHNode (cnodes+1, freenodes, &leafs[numleft], numright); + + node->bvhnode.min[0] = min(left.min[0], right.min[0]); + node->bvhnode.min[1] = min(left.min[1], right.min[1]); + node->bvhnode.min[2] = min(left.min[2], right.min[2]); + node->bvhnode.cmax = left.max[node->type-BVH_X]; + node->bvhnode.cmin = right.min[node->type-BVH_X]; + node->bvhnode.max[0] = max(left.max[0], right.max[0]); + node->bvhnode.max[1] = max(left.max[1], right.max[1]); + node->bvhnode.max[2] = max(left.max[2], right.max[2]); + + bounds = left; + AddPointToBounds(right.min, bounds.min, bounds.max); + AddPointToBounds(right.max, bounds.min, bounds.max); + } +#endif + else + { + struct bihnode_s *cnodes; + struct bihbox_s cb; + size_t i; + node->type = BIH_GROUP; + + cnodes = *freenodes; + *freenodes += numleafs; + node->group.firstchild = cnodes - node; + node->group.numchildren = numleafs; + + bounds = CM_BuildBIHNode(cnodes+0, freenodes, leafs+0, 1); + for (i = 1; i < numleafs; i++) + { + cb = CM_BuildBIHNode(cnodes+i, freenodes, leafs+i, 1); + AddPointToBounds(cb.min, bounds.min, bounds.max); + AddPointToBounds(cb.max, bounds.min, bounds.max); + } + } return bounds; } static struct bihnode_s *CM_BuildBIH (model_t *mod, cminfo_t *prv) @@ -6823,15 +7111,20 @@ static struct bihnode_s *CM_BuildBIH (model_t *mod, cminfo_t *prv) size_t numleafs, numnodes, i, j; struct bihnode_s *nodes, *tmpnodes; struct bihleaf_s *leafs, *leaf; - numleafs = prv->numbrushes; + + int firstbrush = prv->cmodels[0].firstbrush; + int numbrushes = prv->cmodels[0].num_brushes; + + + numleafs = numbrushes; for (i = 0; i < prv->numpatches; i++) numleafs += prv->patches[i].numfacets; numnodes = numleafs*2-1; leafs = BZ_Malloc(sizeof(*leafs)*numleafs); nodes = ZG_Malloc(&mod->memgroup, sizeof(*nodes)*numnodes); - for (leaf=leafs, i = 0; i < prv->numbrushes; i++, leaf++) + for (leaf=leafs, i = 0; i < numbrushes; i++, leaf++) { - q2cbrush_t *b = &prv->brushes[i]; + q2cbrush_t *b = &prv->brushes[firstbrush+i]; leaf->type = BIH_BRUSH; leaf->data.contents = b->contents; leaf->data.brush = b; @@ -6993,11 +7286,12 @@ static trace_t CM_BoxTrace (model_t *mod, const vec3_t start, const vec3_t end, } else #endif - if (((cminfo_t*)mod->meshinfo)->bihnodes) + if (!mod->submodelof && ((cminfo_t*)mod->meshinfo)->bihnodes) { cminfo_t *prv = mod->meshinfo; struct bihtrace_s tr; int j; + VectorCopy(trace_mins, tr.size.min); VectorCopy(trace_maxs, tr.size.max); VectorCopy(trace_absmins, tr.bounds.min); diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 09eed62c..89a4c595 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -94,7 +94,7 @@ extern vec3_t vec3_origin; #define Vector4Copy(a,b) do{(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];(b)[3]=(a)[3];}while(0) #define Vector4Scale(in,scale,out) ((out)[0]=(in)[0]*scale,(out)[1]=(in)[1]*scale,(out)[2]=(in)[2]*scale,(out)[3]=(in)[3]*scale) #define Vector4Add(a,b,c) ((c)[0]=(((a[0])+(b[0]))),(c)[1]=(((a[1])+(b[1]))),(c)[2]=(((a[2])+(b[2]))),(c)[3]=(((a[3])+(b[3])))) -#define Vector4Set(r,x,y,z,w) {(r)[0] = x; (r)[1] = y;(r)[2] = z;(r)[3]=w;} +#define Vector4Set(r,x,y,z,w) (r)[0] = x, (r)[1] = y, (r)[2] = z, (r)[3]=w #define Vector4Interpolate(a, bness, b, c) FloatInterpolate((a)[0], bness, (b)[0], (c)[0]),FloatInterpolate((a)[1], bness, (b)[1], (c)[1]),FloatInterpolate((a)[2], bness, (b)[2], (c)[2]),FloatInterpolate((a)[3], bness, (b)[3], (c)[3]) #define Vector4MA(a,s,b,c) do{(c)[0] = (a)[0] + (s)*(b)[0];(c)[1] = (a)[1] + (s)*(b)[1];(c)[2] = (a)[2] + (s)*(b)[2];(c)[3] = (a)[3] + (s)*(b)[3];}while(0) diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 49c84f89..5968fcf8 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -32,7 +32,11 @@ cvar_t pr_brokenfloatconvert = CVAR("pr_brokenfloatconvert", "0"); cvar_t pr_fixbrokenqccarrays = CVARFD("pr_fixbrokenqccarrays", "0", CVAR_LATCH, "As part of its nq/qw/h2/csqc support, FTE remaps QC fields to match an internal order. This is a faster way to handle extended fields. However, some QCCs are buggy and don't report all field defs.\n0: do nothing. QCC must be well behaved.\n1: Duplicate engine fields, remap the ones we can to known offsets. This is sufficient for QCCX/FrikQCC mods that use hardcoded or even occasional calculated offsets (fixes ktpro).\n2: Scan the mod for field accessing instructions, and assume those are the fields (and that they don't alias non-fields). This can be used to work around gmqcc's WTFs (fixes xonotic)."); cvar_t pr_tempstringcount = CVARD("pr_tempstringcount", "", "Obsolete. Set to 16 if you want to recycle+reuse the same 16 tempstring references and break lots of mods."); cvar_t pr_tempstringsize = CVARD("pr_tempstringsize", "4096", "Obsolete"); +#ifdef MULTITHREAD +cvar_t pr_gc_threaded = CVARD("pr_gc_threaded", "1", "Says whether to use a separate thread for tempstring garbage collections. This avoids main-thread stalls but at the expense of more memory usage."); +#else cvar_t pr_gc_threaded = CVARD("pr_gc_threaded", "0", "Says whether to use a separate thread for tempstring garbage collections. This avoids main-thread stalls but at the expense of more memory usage."); +#endif cvar_t pr_sourcedir = CVARD("pr_sourcedir", "src", "Subdirectory where your qc source is located. Used by the internal compiler and qc debugging functionality."); cvar_t pr_enable_uriget = CVARD("pr_enable_uriget", "1", "Allows gamecode to make direct http requests"); cvar_t pr_enable_profiling = CVARD("pr_enable_profiling", "0", "Enables profiling support. Will run more slowly. Change the map and then use the profile_ssqc/profile_csqc commands to see the results."); @@ -2103,8 +2107,8 @@ qboolean QC_FixFileName(const char *name, const char **result, const char **fall void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { const char *name = PR_GetStringOfs(prinst, OFS_PARM0); - int fmode = G_FLOAT(OFS_PARM1); - int fsize = G_FLOAT(OFS_PARM2); + int fmode = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):-1; + int fsize = (prinst->callargc>2)?G_FLOAT(OFS_PARM2):0; const char *fallbackread; int i; size_t insize; @@ -2122,6 +2126,28 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals return; } + if (fmode < 0 && (!strncmp(name, "tcp://", 6) || !strncmp(name, "tls://", 6))) + { + G_FLOAT(OFS_RETURN) = -1; + Q_strncpyz(pf_fopen_files[i].name, name, sizeof(pf_fopen_files[i].name)); + pf_fopen_files[i].accessmode = FRIK_FILE_STREAM; + pf_fopen_files[i].bufferlen = 0; + pf_fopen_files[i].data = NULL; + pf_fopen_files[i].len = 0; + pf_fopen_files[i].ofs = 0; + pf_fopen_files[i].prinst = prinst; + + pf_fopen_files[i].file = FS_OpenTCP(name, 0, true); + if (pf_fopen_files[i].file) + G_FLOAT(OFS_RETURN) = i + FIRST_QC_FILE_INDEX; + else + { + G_FLOAT(OFS_RETURN) = -1; + memset(&pf_fopen_files[i], 0, sizeof(pf_fopen_files[i])); + } + return; + } + if (!QC_FixFileName(name, &name, &fallbackread)) { Con_Printf("qcfopen(\"%s\"): Access denied\n", name); @@ -2270,6 +2296,7 @@ void PF_fclose_i (int fnum) pf_fopen_files[fnum].prinst->AddressableFree(pf_fopen_files[fnum].prinst, pf_fopen_files[fnum].data); break; + case FRIK_FILE_STREAM: case FRIK_FILE_READ_DELAY: VFS_CLOSE(pf_fopen_files[fnum].file); break; @@ -2342,6 +2369,14 @@ void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals return; //this just isn't ours. } + if (pf_fopen_files[fnum].accessmode == FRIK_FILE_STREAM) + { + if (VFS_GETS(pf_fopen_files[fnum].file, pr_string_temp, sizeof(pr_string_temp))) + RETURN_TSTRING(pr_string_temp); + else + G_INT(OFS_RETURN) = 0; //EOF + return; + } if (pf_fopen_files[fnum].accessmode == FRIK_FILE_READ_DELAY) { //on first read, convert into a regular file. pf_fopen_files[fnum].accessmode = FRIK_FILE_READ; @@ -2460,6 +2495,9 @@ static int PF_fwrite_internal (pubprogfuncs_t *prinst, int fnum, const char *msg return 0; //this just isn't ours. } + if (pf_fopen_files[fnum].accessmode == FRIK_FILE_STREAM) + return VFS_WRITE(pf_fopen_files[fnum].file, msg, len); + if (pf_fopen_files[fnum].ofs + len < pf_fopen_files[fnum].ofs) { PF_Warningf(prinst, "PF_fwrite: size overflow\n"); @@ -2504,6 +2542,8 @@ static int PF_fread_internal (pubprogfuncs_t *prinst, int fnum, char *buf, size_ return 0; //this just isn't ours. } + if (pf_fopen_files[fnum].accessmode == FRIK_FILE_STREAM) + return VFS_READ(pf_fopen_files[fnum].file, buf, len); if (pf_fopen_files[fnum].accessmode == FRIK_FILE_READ_DELAY) { //on first read, convert into a regular file. pf_fopen_files[fnum].accessmode = FRIK_FILE_READ; @@ -2584,10 +2624,29 @@ void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals return; //this just isn't ours. } - G_INT(OFS_RETURN) = pf_fopen_files[fnum].ofs; - if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0) + if (pf_fopen_files[fnum].accessmode == FRIK_FILE_READ_DELAY) + { //on first read, convert into a regular file. + pf_fopen_files[fnum].accessmode = FRIK_FILE_READ; + pf_fopen_files[fnum].data = BZ_Malloc(pf_fopen_files[fnum].len+1); + pf_fopen_files[fnum].data[pf_fopen_files[fnum].len] = 0; + pf_fopen_files[fnum].len = pf_fopen_files[fnum].bufferlen = VFS_READ(pf_fopen_files[fnum].file, pf_fopen_files[fnum].data, pf_fopen_files[fnum].len); + VFS_CLOSE(pf_fopen_files[fnum].file); + pf_fopen_files[fnum].file = NULL; + } + + if (pf_fopen_files[fnum].file) { - pf_fopen_files[fnum].ofs = G_INT(OFS_PARM1); + G_INT(OFS_RETURN) = VFS_TELL(pf_fopen_files[fnum].file); + if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0) + VFS_SEEK(pf_fopen_files[fnum].file, G_INT(OFS_PARM1)); + } + else + { + G_INT(OFS_RETURN) = pf_fopen_files[fnum].ofs; + if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0) + { + pf_fopen_files[fnum].ofs = G_INT(OFS_PARM1); + } } } void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -2610,12 +2669,31 @@ void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals return; //this just isn't ours. } - G_INT(OFS_RETURN) = pf_fopen_files[fnum].len; - if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0) + if (pf_fopen_files[fnum].accessmode == FRIK_FILE_READ_DELAY) + { //on first read, convert into a regular file. + pf_fopen_files[fnum].accessmode = FRIK_FILE_READ; + pf_fopen_files[fnum].data = BZ_Malloc(pf_fopen_files[fnum].len+1); + pf_fopen_files[fnum].data[pf_fopen_files[fnum].len] = 0; + pf_fopen_files[fnum].len = pf_fopen_files[fnum].bufferlen = VFS_READ(pf_fopen_files[fnum].file, pf_fopen_files[fnum].data, pf_fopen_files[fnum].len); + VFS_CLOSE(pf_fopen_files[fnum].file); + pf_fopen_files[fnum].file = NULL; + } + + if (pf_fopen_files[fnum].file) { - size_t newlen = G_INT(OFS_PARM1); - PF_fresizebuffer_internal(&pf_fopen_files[fnum], newlen); - pf_fopen_files[fnum].len = min(pf_fopen_files[fnum].bufferlen, newlen); + G_INT(OFS_RETURN) = VFS_GETLEN(pf_fopen_files[fnum].file); + if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0) + PF_Warningf(prinst, "PF_fsize: truncation/extension is not supported for stream file types\n"); + } + else + { + G_INT(OFS_RETURN) = pf_fopen_files[fnum].len; + if (prinst->callargc>1 && G_INT(OFS_PARM1) >= 0) + { + size_t newlen = G_INT(OFS_PARM1); + PF_fresizebuffer_internal(&pf_fopen_files[fnum], newlen); + pf_fopen_files[fnum].len = min(pf_fopen_files[fnum].bufferlen, newlen); + } } } @@ -2630,6 +2708,7 @@ void PF_fcloseall (pubprogfuncs_t *prinst) switch(pf_fopen_files[i].accessmode) { + case FRIK_FILE_STREAM: case FRIK_FILE_APPEND: case FRIK_FILE_WRITE: case FRIK_FILE_MMAP_RW: @@ -3924,7 +4003,6 @@ void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_global ((int *)pr_globals)[OFS_RETURN] = prinst->AllocTempString(prinst, &buf, len); if (buf) { - len = 0; for (i = 0; i < prinst->callargc; i++) { memcpy(buf, s[i], l[i]); diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index ed2e9dc5..e8e773db 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -749,6 +749,7 @@ typedef enum VF_SKYROOM_CAMERA = 222, VF_PIXELPSCALE = 223, //[dpi_x, dpi_y, dpi_y/dpi_x] VF_PROJECTIONOFFSET = 224, //allows for off-axis projections. + //WARNING: update fteqcc when new entries are added. VF_DP_CLEARSCREEN = 201, // weird behaviour that disables a whole load of things. @@ -789,6 +790,7 @@ typedef enum #define FRIK_FILE_MMAP_RW 6 /*fgets returns a pointer. file is written upon close. memory is not guarenteed to be released.*/ #define FRIK_FILE_READ_DELAY (7) /*internal special mode where the file is not read until the first read. this avoids extra slowness with xonotic (where it uses fopen to see if (large) binary file exists, resulting in large binary files getting decompressed repeatedly then discarded without reading)*/ +#define FRIK_FILE_STREAM (8) /*access goes via the vfs, we don't need to track the read/write info here*/ #define MASK_DELTA 1 #define MASK_STDVIEWMODEL 2 diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 2098014b..fd1fb897 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -2073,10 +2073,12 @@ static void BE_ApplyUniforms(program_t *prog, struct programpermu_s *perm) case SP_M_ENTBONES_MAT3X4: case SP_M_ENTBONES_PACKED: + case SP_M_ENTBONES_MAT4: case SP_E_VLSCALE: case SP_E_ORIGIN: case SP_E_GLOWMOD: case SP_M_INVVIEWPROJECTION: + case SP_M_INVMODELVIEW: case SP_M_INVMODELVIEWPROJECTION: case SP_SOURCESIZE: case SP_S_COLOUR: @@ -2090,11 +2092,18 @@ static void BE_ApplyUniforms(program_t *prog, struct programpermu_s *perm) case SP_RENDERTEXTURESCALE: case SP_FIRSTIMMEDIATE: - case SP_CONSTI: - case SP_CONSTF: + case SP_CONST1I: + case SP_CONST2I: + case SP_CONST3I: + case SP_CONST4I: + case SP_CONST1F: + case SP_CONST2F: + case SP_CONST3F: + case SP_CONST4F: case SP_CVARI: case SP_CVARF: case SP_CVAR3F: + case SP_CVAR4F: case SP_TEXTURE: case SP_BAD: Con_Printf("shader property %i not implemented\n", pp->type); diff --git a/engine/d3d/d3d_shader.c b/engine/d3d/d3d_shader.c index 21dbaf0f..2f250919 100644 --- a/engine/d3d/d3d_shader.c +++ b/engine/d3d/d3d_shader.c @@ -397,7 +397,7 @@ static int D3D9Shader_FindUniform(union programhandle_u *h, int type, const char return -1; } -static void D3D9Shader_ProgAutoFields(program_t *prog, struct programpermu_s *pp, cvar_t **cvarrefs, char **cvarnames, int *cvartypes) +static void D3D9Shader_ProgAutoFields(program_t *prog, struct programpermu_s *pp, char **cvarnames, int *cvartypes) { unsigned int i; int uniformloc; @@ -434,10 +434,14 @@ static void D3D9Shader_ProgAutoFields(program_t *prog, struct programpermu_s *pp for (i = 0; cvarnames[i]; i++) { - if (!cvarrefs[i]) + cvar_t *cvarref; + if (cvartypes[i] < SP_CVARI) + continue; + cvarref = Cvar_FindVar(cvarnames[i]); + if (!cvarref) continue; //just directly sets uniforms. can't cope with cvars dynamically changing. - cvarrefs[i]->flags |= CVAR_SHADERSYSTEM; + cvarref->flags |= CVAR_SHADERSYSTEM; Q_snprintfz(tmpbuffer, sizeof(tmpbuffer), "cvar_%s", cvarnames[i]); uniformloc = D3D9Shader_FindUniform(&pp->h, 1, tmpbuffer); @@ -445,22 +449,22 @@ static void D3D9Shader_ProgAutoFields(program_t *prog, struct programpermu_s *pp { if (cvartypes[i] == SP_CVARI) { - int v[4] = {cvarrefs[i]->ival, 0, 0, 0}; + int v[4] = {cvarref->ival, 0, 0, 0}; IDirect3DDevice9_SetVertexShaderConstantI(pD3DDev9, 0, v, 1); } else - IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, 0, cvarrefs[i]->vec4, 1); + IDirect3DDevice9_SetVertexShaderConstantF(pD3DDev9, 0, cvarref->vec4, 1); } uniformloc = D3D9Shader_FindUniform(&pp->h, 2, tmpbuffer); if (uniformloc != -1) { if (cvartypes[i] == SP_CVARI) { - int v[4] = {cvarrefs[i]->ival, 0, 0, 0}; + int v[4] = {cvarref->ival, 0, 0, 0}; IDirect3DDevice9_SetPixelShaderConstantI(pD3DDev9, 0, v, 1); } else - IDirect3DDevice9_SetPixelShaderConstantF(pD3DDev9, 0, cvarrefs[i]->vec4, 1); + IDirect3DDevice9_SetPixelShaderConstantF(pD3DDev9, 0, cvarref->vec4, 1); } } diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 5afed7cf..c62ad71d 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -520,7 +520,12 @@ static qboolean initD3D9Device(HWND hWnd, rendererstate_t *info, unsigned int de d3dpp.Windowed = !info->fullscreen; d3dpp.EnableAutoDepthStencil = true; - d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//D3DFMT_D16; + if (info->depthbits==16) + d3dpp.AutoDepthStencilFormat = D3DFMT_D16; + else if (info->depthbits==32) + d3dpp.AutoDepthStencilFormat = D3DFMT_D32; + else + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; if (info->fullscreen) { diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 5b17e79a..1b14799d 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -73,6 +73,7 @@ IDXGIOutput *d3dscreen; ID3D11RenderTargetView *fb_backbuffer; ID3D11DepthStencilView *fb_backdepthstencil; +static DXGI_FORMAT depthformat; void *d3d11mod; static unsigned int d3d11multisample_count, d3d11multisample_quality; @@ -661,7 +662,7 @@ static qboolean resetd3dbackbuffer(int width, int height) t2ddesc.Height = height; t2ddesc.MipLevels = 1; t2ddesc.ArraySize = 1; - t2ddesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + t2ddesc.Format = depthformat; t2ddesc.SampleDesc.Count = d3d11multisample_count; t2ddesc.SampleDesc.Quality = d3d11multisample_quality; t2ddesc.Usage = D3D11_USAGE_DEFAULT; @@ -723,6 +724,13 @@ static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) modestate = MS_FULLSCREEN; + if (info->depthbits == 16) + depthformat = DXGI_FORMAT_D16_UNORM; + else if (info->depthbits == 32) + depthformat = DXGI_FORMAT_D32_FLOAT; + else + depthformat = DXGI_FORMAT_D24_UNORM_S8_UINT; + //fill scd scd.Width = info->width; scd.Height = info->height; @@ -798,6 +806,13 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA else drivertype = adapt?D3D_DRIVER_TYPE_UNKNOWN:D3D_DRIVER_TYPE_HARDWARE; + if (info->depthbits == 16) + depthformat = DXGI_FORMAT_D16_UNORM; + else if (info->depthbits == 32) + depthformat = DXGI_FORMAT_D32_FLOAT; + else + depthformat = DXGI_FORMAT_D24_UNORM_S8_UINT; + //for stereo support, we would have to rewrite all of this in a way that would make us dependant upon windows 8 or 7+platform update, which would exclude vista. scd.BufferDesc.Width = info->width; scd.BufferDesc.Height = info->height; diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index 1dffc4e8..e92ded1b 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -555,7 +555,7 @@ static qboolean initD3D8Device(HWND hWnd, rendererstate_t *info, unsigned int de d3dpp.Windowed = !info->fullscreen; d3dpp.EnableAutoDepthStencil = true; - d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//D3DFMT_D16; + d3dpp.AutoDepthStencilFormat = (info->depthbits==16)?D3DFMT_D16:D3DFMT_D24S8;; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; if (info->bpp == 16) d3dpp.BackBufferFormat = D3DFMT_R5G6B5; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 25c43f3d..ddc3de02 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -3520,6 +3520,13 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu qglUniformMatrix4fvARB(ph, 1, false, inv); } break; + case SP_M_INVMODELVIEW: + { + float inv[9]; + Matrix3x4_InvertTo3x3(shaderstate.modelviewmatrix, inv); + qglUniformMatrix3fvARB(ph, 1, false, inv); + } + break; case SP_M_MODEL: qglUniformMatrix4fvARB(ph, 1, false, shaderstate.modelmatrix); break; @@ -3820,12 +3827,21 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu case SP_E_TIME: qglUniform1fARB(ph, shaderstate.curtime); break; - case SP_CONSTI: + case SP_CONST1I: case SP_TEXTURE: - qglUniform1iARB(ph, p->ival); + qglUniform1iARB(ph, p->ival[0]); break; - case SP_CONSTF: - qglUniform1fARB(ph, p->fval); + case SP_CONST1F: + qglUniform1fARB(ph, p->fval[0]); + break; + case SP_CONST2F: + qglUniform3fARB(ph, p->fval[0], p->fval[1], 0); + break; + case SP_CONST3F: + qglUniform3fARB(ph, p->fval[0], p->fval[1], p->fval[2]); + break; + case SP_CONST4F: + qglUniform4fARB(ph, p->fval[0], p->fval[1], p->fval[2], p->fval[3]); break; case SP_CVARI: qglUniform1iARB(ph, ((cvar_t*)p->pval)->ival); @@ -3834,17 +3850,10 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu qglUniform1fARB(ph, ((cvar_t*)p->pval)->value); break; case SP_CVAR3F: - { - cvar_t *var = (cvar_t*)p->pval; - char *vs = var->string; - vs = COM_Parse(vs); - param4[0] = atof(com_token); - vs = COM_Parse(vs); - param4[1] = atof(com_token); - vs = COM_Parse(vs); - param4[2] = atof(com_token); - qglUniform3fvARB(ph, 1, param4); - } + qglUniform3fvARB(ph, 1, ((cvar_t*)p->pval)->vec4); + break; + case SP_CVAR4F: + qglUniform3fvARB(ph, 1, ((cvar_t*)p->pval)->vec4); break; default: @@ -3912,7 +3921,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas BE_SendPassBlendDepthMask(pass->shaderbits); #ifndef GLSLONLY - if (!p->nofixedcompat) + if (p->calcgens) { GenerateColourMods(pass); for (i = 0; i < pass->numMergedPasses; i++) @@ -3920,11 +3929,6 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas Shader_BindTextureForPass(i, pass+i); BE_GeneratePassTC(pass+i, i); } - for (; i < shaderstate.lastpasstmus; i++) - { - GL_LazyBind(i, 0, r_nulltex); - } - shaderstate.lastpasstmus = pass->numMergedPasses; } else #endif @@ -3933,21 +3937,22 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas { Shader_BindTextureForPass(i, pass+i); } -#if MAXRLIGHTMAPS > 1 - if (perm & PERMUTATION_LIGHTSTYLES) - { - GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[1]>=0?lightmap[shaderstate.curbatch->lightmap[1]]->lightmap_texture:r_nulltex); - GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[2]>=0?lightmap[shaderstate.curbatch->lightmap[2]]->lightmap_texture:r_nulltex); - GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[3]>=0?lightmap[shaderstate.curbatch->lightmap[3]]->lightmap_texture:r_nulltex); - GL_LazyBind(i++, GL_TEXTURE_2D, (shaderstate.curbatch->lightmap[1]>=0&&lightmap[shaderstate.curbatch->lightmap[1]]->hasdeluxe)?lightmap[shaderstate.curbatch->lightmap[1]+1]->lightmap_texture:missing_texture_normal); - GL_LazyBind(i++, GL_TEXTURE_2D, (shaderstate.curbatch->lightmap[2]>=0&&lightmap[shaderstate.curbatch->lightmap[2]]->hasdeluxe)?lightmap[shaderstate.curbatch->lightmap[2]+1]->lightmap_texture:missing_texture_normal); - GL_LazyBind(i++, GL_TEXTURE_2D, (shaderstate.curbatch->lightmap[3]>=0&&lightmap[shaderstate.curbatch->lightmap[3]]->hasdeluxe)?lightmap[shaderstate.curbatch->lightmap[3]+1]->lightmap_texture:missing_texture_normal); - } -#endif - while (shaderstate.lastpasstmus > i) - GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex); - shaderstate.lastpasstmus = i; //in case it was already lower } +#if MAXRLIGHTMAPS > 1 + if (perm & PERMUTATION_LIGHTSTYLES) + { + GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[1]>=0?lightmap[shaderstate.curbatch->lightmap[1]]->lightmap_texture:r_nulltex); + GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[2]>=0?lightmap[shaderstate.curbatch->lightmap[2]]->lightmap_texture:r_nulltex); + GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[3]>=0?lightmap[shaderstate.curbatch->lightmap[3]]->lightmap_texture:r_nulltex); + GL_LazyBind(i++, GL_TEXTURE_2D, (shaderstate.curbatch->lightmap[1]>=0&&lightmap[shaderstate.curbatch->lightmap[1]]->hasdeluxe)?lightmap[shaderstate.curbatch->lightmap[1]+1]->lightmap_texture:missing_texture_normal); + GL_LazyBind(i++, GL_TEXTURE_2D, (shaderstate.curbatch->lightmap[2]>=0&&lightmap[shaderstate.curbatch->lightmap[2]]->hasdeluxe)?lightmap[shaderstate.curbatch->lightmap[2]+1]->lightmap_texture:missing_texture_normal); + GL_LazyBind(i++, GL_TEXTURE_2D, (shaderstate.curbatch->lightmap[3]>=0&&lightmap[shaderstate.curbatch->lightmap[3]]->hasdeluxe)?lightmap[shaderstate.curbatch->lightmap[3]+1]->lightmap_texture:missing_texture_normal); + } +#endif + while (shaderstate.lastpasstmus > i) + GL_LazyBind(--shaderstate.lastpasstmus, 0, r_nulltex); + shaderstate.lastpasstmus = i; + BE_EnableShaderAttributes(permu->attrmask, shaderstate.sourcevbo->vao); BE_SubmitMeshChain(permu->h.glsl.usetesselation); } diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index ced8245a..c104a563 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -2280,7 +2280,7 @@ void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmw 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) + Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1); cl_numstrisvert++; } } @@ -2314,22 +2314,22 @@ void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmw { VectorSet(cl_strisvertv[cl_numstrisvert], mins[0], mins[1], w->maxheight); - Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1) + Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1); Vector2Set(cl_strisvertt[cl_numstrisvert], mins[0]/64, mins[1]/64); cl_numstrisvert++; VectorSet(cl_strisvertv[cl_numstrisvert], mins[0], maxs[1], w->maxheight); - Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1) + Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1); Vector2Set(cl_strisvertt[cl_numstrisvert], mins[0]/64, maxs[1]/64); cl_numstrisvert++; VectorSet(cl_strisvertv[cl_numstrisvert], maxs[0], maxs[1], w->maxheight); - Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1) + Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1); Vector2Set(cl_strisvertt[cl_numstrisvert], maxs[0]/64, maxs[1]/64); cl_numstrisvert++; VectorSet(cl_strisvertv[cl_numstrisvert], maxs[0], mins[1], w->maxheight); - Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1) + Vector4Set(cl_strisvertc[cl_numstrisvert], 1,1,1,1); Vector2Set(cl_strisvertt[cl_numstrisvert], maxs[0]/64, mins[1]/64); cl_numstrisvert++; } @@ -7813,7 +7813,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); scale[1] = atof(token); } - else rot = 0; + else rot = 0, scale[0] = 1, scale[1] = 1; //hexen2 has some extra junk that is useless - some 'light' value, but its never used and should normally be -1. //quake2/3 on the other hand has 3 different args. Contents SurfaceFlags SurfaceValue. diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 2a423c9f..a9bbae25 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -5815,6 +5815,11 @@ static void * Mod_LoadSpriteGroup (model_t *mod, void * pin, void *pend, msprite pingroup = (dspritegroup_t *)pin; numframes = LittleLong (pingroup->numframes); + if (numframes <= 0) + { + Con_Printf (CON_ERROR "Mod_LoadSpriteGroup: invalid frame count\n"); + return NULL; + } pspritegroup = ZG_Malloc(&mod->memgroup, sizeof (mspritegroup_t) + (numframes - 1) * sizeof (pspritegroup->frames[0])); diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index ef4ed9ab..ee01e5c2 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -56,6 +56,8 @@ typedef enum { #ifdef FTE_TARGET_WEB #define MAX_BONES 256 +#elif defined(IQMTOOL) +#define MAX_BONES 8192 #else #define MAX_BONES 256 //Note: there's lots of bone data allocated on the stack, so don't bump recklessly. #endif diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 4876b857..7a041d02 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -79,11 +79,11 @@ cvar_t r_detailtextures; #define MAX_TOKEN_CHARS sizeof(com_token) -char *COM_ParseExt (char **data_p, qboolean nl, qboolean comma) +char *COM_ParseExt (const char **data_p, qboolean nl, qboolean comma) { int c; int len; - char *data; + const char *data; COM_AssertMainThread("COM_ParseExt"); @@ -124,7 +124,7 @@ skipwhite: // skip /* comments if (c == '/' && data[1] == '*') { - char *start = data; + const char *start = data; data+=2; for(;data[0];) { @@ -225,7 +225,7 @@ typedef struct shaderparsestate_s { shader_t *s; //the shader we're parsing shaderpass_t *pass; //the pass we're currently parsing - char *ptr; //the src file pointer we're at + const char *ptr; //the src file pointer we're at char *sourcename; //the name of the shader file being read (or '') const char *forcedshader; @@ -255,7 +255,7 @@ typedef struct shaderparsestate_s typedef struct shaderkey_s { char *keyword; - void (*func)( parsestate_t *ps, char **ptr ); + void (*func)( parsestate_t *ps, const char **ptr ); char *prefix; } shaderkey_t; typedef struct shadercachefile_s { @@ -285,17 +285,17 @@ void *shader_active_hash_mem; //static char r_skyboxname[MAX_QPATH]; //static float r_skyheight; -static char *Shader_Skip(const char *file, const char *shadername, char *ptr); -static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, char *token); -static void Shader_ParseFunc(parsestate_t *ps, const char *functype, char **args, shaderfunc_t *func); +static const char *Shader_Skip(const char *file, const char *shadername, const char *ptr); +static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, const char *token); +static void Shader_ParseFunc(parsestate_t *ps, const char *functype, const char **args, shaderfunc_t *func); static void Shader_MakeCache(const char *path, unsigned int parseflags); -static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, size_t *offset, shadercachefile_t **sourcefile); -static void Shader_ReadShader(parsestate_t *ps, char *shadersource, shadercachefile_t *sourcefile); -static qboolean Shader_ParseShader(parsestate_t *ps, char *parsename); +static qboolean Shader_LocateSource(const char *name, const char **buf, size_t *bufsize, size_t *offset, shadercachefile_t **sourcefile); +static void Shader_ReadShader(parsestate_t *ps, const char *shadersource, shadercachefile_t *sourcefile); +static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename); //=========================================================================== -static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) +static qboolean Shader_EvaluateCondition(shader_t *shader, const char **ptr) { char *token; cvar_t *cv; @@ -441,7 +441,7 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr) return conditiontrue; } -static char *Shader_ParseExactString(char **ptr) +static char *Shader_ParseExactString(const char **ptr) { char *token; @@ -454,7 +454,7 @@ static char *Shader_ParseExactString(char **ptr) return token; } -static char *Shader_ParseString(char **ptr) +static char *Shader_ParseString(const char **ptr) { char *token; @@ -471,7 +471,7 @@ static char *Shader_ParseString(char **ptr) return token; } -static char *Shader_ParseSensString(char **ptr) +static char *Shader_ParseSensString(const char **ptr) { char *token; @@ -485,7 +485,7 @@ static char *Shader_ParseSensString(char **ptr) return token; } -static float Shader_ParseFloat(shader_t *shader, char **ptr, float defaultval) +static float Shader_ParseFloat(shader_t *shader, const char **ptr, float defaultval) { char *token; if (!ptr || !(*ptr)) @@ -518,9 +518,9 @@ static float Shader_ParseFloat(shader_t *shader, char **ptr, float defaultval) return atof(token); } -static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v) +static void Shader_ParseVector(shader_t *shader, const char **ptr, vec3_t v) { - char *scratch; + const char *scratch; char *token; qboolean bracket; qboolean fromcvar = false; @@ -541,7 +541,7 @@ static void Shader_ParseVector(shader_t *shader, char **ptr, vec3_t v) ptr = &scratch; scratch = var->string; - token = Shader_ParseString( ptr); + token = Shader_ParseString(ptr); fromcvar = true; } if (!Q_stricmp (token, "(")) @@ -666,7 +666,7 @@ qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *ima return allokay; } -static void Shader_ParseFunc (parsestate_t *ps, const char *functype, char **ptr, shaderfunc_t *func) +static void Shader_ParseFunc (parsestate_t *ps, const char *functype, const char **ptr, shaderfunc_t *func) { shader_t *shader = ps->s; char *token; @@ -889,7 +889,7 @@ static texid_t Shader_FindImage (parsestate_t *parsestate, char *name, int flags /****************** shader keyword functions ************************/ -static void Shader_Cull (parsestate_t *ps, char **ptr) +static void Shader_Cull (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; char *token; @@ -907,26 +907,26 @@ static void Shader_Cull (parsestate_t *ps, char **ptr) } } -static void Shader_NoMipMaps (parsestate_t *ps, char **ptr) +static void Shader_NoMipMaps (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->flags |= (SHADER_NOMIPMAPS|SHADER_NOPICMIP); } -static void Shader_Affine (parsestate_t *ps, char **ptr) +static void Shader_Affine (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->flags |= SBITS_AFFINE; } -static void Shader_NoPicMip (parsestate_t *ps, char **ptr) +static void Shader_NoPicMip (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->flags |= SHADER_NOPICMIP; } -static void Shader_DeformVertexes (parsestate_t *ps, char **ptr) +static void Shader_DeformVertexes (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; char *token; @@ -986,7 +986,7 @@ static void Shader_DeformVertexes (parsestate_t *ps, char **ptr) shader->numdeforms++; } -static void Shader_ClutterParms(parsestate_t *ps, char **ptr) +static void Shader_ClutterParms(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; struct shader_clutter_s *clut; @@ -1006,7 +1006,7 @@ static void Shader_ClutterParms(parsestate_t *ps, char **ptr) shader->clutter = clut; } -static void Shader_SkyParms(parsestate_t *ps, char **ptr) +static void Shader_SkyParms(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; skydome_t *skydome; @@ -1033,7 +1033,7 @@ static void Shader_SkyParms(parsestate_t *ps, char **ptr) shader->sort = SHADER_SORT_SKY; } -static void Shader_FogParms (parsestate_t *ps, char **ptr) +static void Shader_FogParms (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; float div; @@ -1062,7 +1062,7 @@ static void Shader_FogParms (parsestate_t *ps, char **ptr) shader->flags |= SHADER_NODLIGHT|SHADER_NOSHADOWS; } -static void Shader_SurfaceParm (parsestate_t *ps, char **ptr) +static void Shader_SurfaceParm (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; char *token; @@ -1104,7 +1104,7 @@ static void Shader_SurfaceParm (parsestate_t *ps, char **ptr) Con_DLPrintf(2, "Shader %s, Unknown surface parm \"%s\"\n", ps->s->name, token); //note that there are game-specific names used to override mod surfaceflags+contents } -static void Shader_Sort (parsestate_t *ps, char **ptr) +static void Shader_Sort (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; char *token; @@ -1148,19 +1148,19 @@ static void Shader_Sort (parsestate_t *ps, char **ptr) } } -static void Shader_Deferredlight (parsestate_t *ps, char **ptr) +static void Shader_Deferredlight (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->sort = SHADER_SORT_DEFERREDLIGHT; } -static void Shader_Portal (parsestate_t *ps, char **ptr) +static void Shader_Portal (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->sort = SHADER_SORT_PORTAL; } -static void Shader_PolygonOffset (parsestate_t *ps, char **ptr) +static void Shader_PolygonOffset (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; float m = Shader_ParseFloat(shader, ptr, 1); @@ -1170,15 +1170,16 @@ static void Shader_PolygonOffset (parsestate_t *ps, char **ptr) shader->flags |= SHADER_POLYGONOFFSET; //some backends might be lazy and only allow simple values. } -static void Shader_EntityMergable (parsestate_t *ps, char **ptr) +static void Shader_EntityMergable (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->flags |= SHADER_ENTITY_MERGABLE; } #if defined(GLQUAKE) || defined(D3DQUAKE) -static qboolean Shader_ParseProgramCvar(char *script, cvar_t **cvarrefs, char **cvarnames, int *cvartypes, int cvartype) +static qboolean Shader_ParseProgramCvar(char *script, char **cvarnames, int *cvartypes, int cvartype) { + cvar_t *ref; char body[MAX_QPATH]; char *out; char *namestart; @@ -1205,10 +1206,94 @@ static qboolean Shader_ParseProgramCvar(char *script, cvar_t **cvarrefs, char ** while (out < com_token+countof(body)-1 && *script != '\n' && !(script[0] == '/' && script[1] == '/')) *out++ = *script++; *out++ = 0; - cvarrefs[0] = Cvar_Get(cvarnames[0], body, 0, "GLSL Variables"); + ref = Cvar_Get(cvarnames[0], body, 0, "GLSL Variables"); } else - cvarrefs[0] = Cvar_Get(cvarnames[0], "", 0, "GLSL Variables"); + ref = Cvar_Get(cvarnames[0], "", 0, "GLSL Variables"); + if (!ref) + { + Z_Free(cvarnames[0]); + return false; + } + return true; +} +static qboolean Shader_ParseSemantic(const char *script, const char *shadername, char **cvarnames, int *cvartypes) +{ + int s; + const char *namestart, *nameend; + while (*script == ' ' || *script == '\t') + script++; + namestart = script; + while ((*script >= 'A' && *script <= 'Z') || (*script >= 'a' && *script <= 'z') || (*script >= '0' && *script <= '9') || *script == '_') + script++; + nameend = script; + if (*script == ' ' || *script == '\t') + { + while (*script == ' ' || *script == '\t') + script++; + while ((*script >= 'A' && *script <= 'Z') || (*script >= 'a' && *script <= 'z') || (*script >= '0' && *script <= '9') || *script == '_') + script++; + } + else + return false; + + cvarnames[0] = Z_Malloc(script - namestart + 1); + memcpy(cvarnames[0], namestart, script - namestart); + cvarnames[0][script - namestart] = 0; + + cvarnames[0][nameend-namestart] = 0; + nameend = &cvarnames[0][nameend-namestart]+1; + + for (s = 0; shader_unif_names[s].name; s++) + { + if (!strcmp(shader_unif_names[s].name, nameend)) + { + cvartypes[0] = shader_unif_names[s].ptype; + return true; + } + } + Con_Printf("%s: semantic %s not found\n", shadername, nameend); + Z_Free(cvarnames[0]); + return false; +} +static qboolean Shader_ParseProgramConst(char *script, char **cvarnames, int *cvartypes, int cvartype, unsigned short *numsamplers) +{ + char *namestart; + char *nameend; + while (*script == ' ' || *script == '\t') + script++; + namestart = script; + while ((*script >= 'A' && *script <= 'Z') || (*script >= 'a' && *script <= 'z') || (*script >= '0' && *script <= '9') || *script == '_') + script++; + nameend = script; + if (*script == ' ' || *script == '\t') + { + while (*script != '\n') + script++; + } + + cvartypes[0] = cvartype; + cvarnames[0] = Z_Malloc(script - namestart + 1); + memcpy(cvarnames[0], namestart, script - namestart); + cvarnames[0][script - namestart] = 0; + + //not a cvar. data is baked weirdly into the name. + if (nameend < script) + { + cvarnames[0][nameend-namestart] = '='; + + if (numsamplers) + { //this is a !!constt + //make sure we know the max sampler id needed... + unsigned short s; + nameend = &cvarnames[0][nameend-namestart]+1; + while (*nameend == ' ' || *nameend == '\t') + nameend++; + s = atoi(nameend)+1; + if (*numsamplers < s) + *numsamplers = s; + } + } return true; } #endif @@ -1341,7 +1426,6 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p) if (!fail && sh_config.pProgAutoFields) { - cvar_t *cvarrefs[64]; char *cvarnames[64+1]; int cvartypes[64]; @@ -1353,10 +1437,9 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p) cvarnames[i] = cvardata+sizeof(int); size -= sizeof(int)+strlen(cvarnames[i])+1; cvardata += sizeof(int)+strlen(cvarnames[i])+1; - cvarrefs[i] = Cvar_FindVar(cvarnames[i]); } cvarnames[i] = NULL; //no more - sh_config.pProgAutoFields(prog, pp, cvarrefs, cvarnames, cvartypes); + sh_config.pProgAutoFields(prog, pp, cvarnames, cvartypes); } if (fail) { @@ -1417,7 +1500,6 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip int p; char *end; - cvar_t *cvarrefs[64]; char *cvarnames[64]; int cvartypes[64]; size_t cvarcount = 0, i; @@ -1455,7 +1537,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip prog->name = Z_StrDup(name); prog->geom = false; prog->tess = false; - prog->nofixedcompat = true; + prog->calcgens = false; prog->numsamplers = 0; prog->defaulttextures = 0; for(;;) @@ -1464,9 +1546,14 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip script++; if (!strncmp(script, "!!fixed", 7)) { - prog->nofixedcompat = false; + prog->calcgens = true; script += 7; } + else if (!strncmp(script, "!!explicit", 10)) + { + prog->explicitsyms = true; + script += 10; + } else if (!strncmp(script, "!!geom", 6)) { prog->geom = true; @@ -1663,20 +1750,41 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip } script = end; } - else if (!strncmp(script, "!!cvarf", 7)) + else if (!strncmp(script, "!!cvarf", 7) || !strncmp(script, "!!cvari", 7) || !strncmp(script, "!!cvarv", 7) || !strncmp(script, "!!cvar3f", 8) || !strncmp(script, "!!cvar4f", 8)) { + int type; + if (script[6]=='f') type = SP_CVARF; + else if (script[6]=='i') type = SP_CVARI; + else if (script[6]=='v') type = SP_CVAR3F; + else if (script[6]=='3') type = SP_CVAR3F; + else if (script[6]=='4') type = SP_CVAR4F; + else break; if (cvarcount != sizeof(cvarnames)/sizeof(cvarnames[0])) - cvarcount += Shader_ParseProgramCvar(script+7, &cvarrefs[cvarcount], &cvarnames[cvarcount], &cvartypes[cvarcount], SP_CVARF); + cvarcount += Shader_ParseProgramCvar(script+8, &cvarnames[cvarcount], &cvartypes[cvarcount], type); } - else if (!strncmp(script, "!!cvari", 7)) + else if ( !strncmp(script, "!!semantic", 10)) { if (cvarcount != sizeof(cvarnames)/sizeof(cvarnames[0])) - cvarcount += Shader_ParseProgramCvar(script+7, &cvarrefs[cvarcount], &cvarnames[cvarcount], &cvartypes[cvarcount], SP_CVARI); + cvarcount += Shader_ParseSemantic(script+10, name, &cvarnames[cvarcount], &cvartypes[cvarcount]); } - else if (!strncmp(script, "!!cvarv", 7)) + else if ( !strncmp(script, "!!const1f", 9) || + !strncmp(script, "!!const2f", 9) || + !strncmp(script, "!!const3f", 9) || + !strncmp(script, "!!const4f", 9) || + !strncmp(script, "!!constt", 8)) { + int type; + if (script[8] == 'f') + type = SP_CONST1F + (script[7]-'1'); + else if (script[8] == 'i') + type = SP_CONST1I + (script[7]-'1'); + else if (script[7] == 't') + type = SP_TEXTURE; + else + break; + if (cvarcount != sizeof(cvarnames)/sizeof(cvarnames[0])) - cvarcount += Shader_ParseProgramCvar(script+7, &cvarrefs[cvarcount], &cvarnames[cvarcount], &cvartypes[cvarcount], SP_CVAR3F); + cvarcount += Shader_ParseProgramConst(script+9, &cvarnames[cvarcount], &cvartypes[cvarcount], type, (type==SP_TEXTURE)?&prog->numsamplers:NULL); } else if (!strncmp(script, "!!arg", 5)) { //compat with our vulkan glsl, generate (specialisation) constants from #args @@ -1850,7 +1958,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip if (!end) end = start + strlen(start); if (end-start == 7 && !Q_strncasecmp(start, "usemods", 7)) - prog->nofixedcompat = false; + prog->calcgens = true; if (end-start == 4 && !Q_strncasecmp(start, "tess", 4)) prog->tess |= cantess; @@ -1881,13 +1989,10 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip offset = 0; for (i = 0; i < cvarcount && offset < sizeof(prescript); i++) { - if (cvarrefs[i]) - { - memcpy(prescript+offset, &cvartypes[i], sizeof(int)); - offset+=4; - Q_strlcatfz(prescript, &offset, sizeof(prescript), "%s", cvarnames[i]); - offset++; - } + memcpy(prescript+offset, &cvartypes[i], sizeof(int)); + offset+=4; + Q_strlcatfz(prescript, &offset, sizeof(prescript), "%s", cvarnames[i]); + offset++; } prog->cvardata = Z_Malloc(offset); prog->cvardatasize = offset; @@ -2176,8 +2281,10 @@ struct shader_field_names_s shader_unif_names[] = /**/{"m_modelviewprojection", SP_M_MODELVIEWPROJECTION},//fancy mvp matrix. probably has degraded precision. {"m_bones_packed", SP_M_ENTBONES_PACKED}, //bone matrix array. should normally be read via sys/skeletal.h {"m_bones_mat3x4", SP_M_ENTBONES_MAT3X4}, //bone matrix array. should normally be read via sys/skeletal.h + {"m_bones_mat4", SP_M_ENTBONES_MAT4}, //bone matrix array. should normally be read via sys/skeletal.h {"m_invviewprojection", SP_M_INVVIEWPROJECTION},//inverted vp matrix {"m_invmodelviewprojection",SP_M_INVMODELVIEWPROJECTION},//inverted mvp matrix. + {"m_invmodelview", SP_M_INVMODELVIEW},//inverted mv matrix. /**///m_modelinv /*viewer properties*/ @@ -2220,10 +2327,10 @@ struct shader_field_names_s shader_unif_names[] = {NULL} }; -static char *Shader_ParseBody(char *debugname, char **ptr) +static char *Shader_ParseBody(char *debugname, const char **ptr) { char *body; - char *start, *end; + const char *start, *end; end = *ptr; while (*end == ' ' || *end == '\t' || *end == '\r') @@ -2264,7 +2371,7 @@ static char *Shader_ParseBody(char *debugname, char **ptr) return NULL; } -static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr, int qrtype) +static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, const char **ptr, int qrtype) { /*accepts: program @@ -2328,45 +2435,45 @@ static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **p } } -static void Shader_GLSLProgramName (parsestate_t *ps, char **ptr) +static void Shader_GLSLProgramName (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; Shader_SLProgramName(shader,pass,ptr,QR_OPENGL); } -static void Shader_ProgramName (parsestate_t *ps, char **ptr) +static void Shader_ProgramName (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; Shader_SLProgramName(shader,pass,ptr,qrenderer); } -static void Shader_HLSL9ProgramName (parsestate_t *ps, char **ptr) +static void Shader_HLSL9ProgramName (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; Shader_SLProgramName(shader,pass,ptr,QR_DIRECT3D9); } -static void Shader_HLSL11ProgramName (parsestate_t *ps, char **ptr) +static void Shader_HLSL11ProgramName (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; Shader_SLProgramName(shader,pass,ptr,QR_DIRECT3D11); } -static void Shader_ReflectCube(parsestate_t *ps, char **ptr) +static void Shader_ReflectCube(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_TEXTYPE_CUBE); ps->s->defaulttextures->reflectcube = Shader_FindImage(ps, token, flags); } -static void Shader_ReflectMask(parsestate_t *ps, char **ptr) +static void Shader_ReflectMask(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); ps->s->defaulttextures->reflectmask = Shader_FindImage(ps, token, flags); } -static void Shader_DiffuseMap(parsestate_t *ps, char **ptr) +static void Shader_DiffuseMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); @@ -2374,44 +2481,44 @@ static void Shader_DiffuseMap(parsestate_t *ps, char **ptr) Q_strncpyz(ps->s->defaulttextures->mapname, token, sizeof(ps->s->defaulttextures->mapname)); } -static void Shader_SpecularMap(parsestate_t *ps, char **ptr) +static void Shader_SpecularMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); ps->s->defaulttextures->specular = Shader_FindImage(ps, token, flags); } -static void Shader_NormalMap(parsestate_t *ps, char **ptr) +static void Shader_NormalMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_TRYBUMP|IF_NOSRGB); ps->s->defaulttextures->bump = Shader_FindImage(ps, token, flags); } -static void Shader_FullbrightMap(parsestate_t *ps, char **ptr) +static void Shader_FullbrightMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); ps->s->defaulttextures->fullbright = Shader_FindImage(ps, token, flags); } -static void Shader_UpperMap(parsestate_t *ps, char **ptr) +static void Shader_UpperMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); ps->s->defaulttextures->upperoverlay = Shader_FindImage(ps, token, flags); } -static void Shader_LowerMap(parsestate_t *ps, char **ptr) +static void Shader_LowerMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, 0); ps->s->defaulttextures->loweroverlay = Shader_FindImage(ps, token, flags); } -static void Shader_DisplacementMap(parsestate_t *ps, char **ptr) +static void Shader_DisplacementMap(parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString(ptr); unsigned int flags = Shader_SetImageFlags (ps, ps->pass, &token, IF_NOSRGB); ps->s->defaulttextures->displacement = Shader_FindImage(ps, token, flags); } -static void Shaderpass_QF_Material(parsestate_t *ps, char **ptr) +static void Shaderpass_QF_Material(parsestate_t *ps, const char **ptr) { //qf_material BASETEXTURE NORMALMAP SPECULARMAP unsigned int flags; char *progname = "defaultwall"; @@ -2463,25 +2570,25 @@ static void Shaderpass_QF_Material(parsestate_t *ps, char **ptr) static qboolean Shaderpass_MapGen (parsestate_t *ps, shaderpass_t *pass, char *tname); -static void Shader_Translucent(parsestate_t *ps, char **ptr) +static void Shader_Translucent(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->flags |= SHADER_BLEND; } -static void Shader_PortalFBOScale(parsestate_t *ps, char **ptr) +static void Shader_PortalFBOScale(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->portalfboscale = Shader_ParseFloat(shader, ptr, 0); shader->portalfboscale = max(shader->portalfboscale, 0); } -static void Shader_DP_Camera(parsestate_t *ps, char **ptr) +static void Shader_DP_Camera(parsestate_t *ps, const char **ptr) { ps->s->sort = SHADER_SORT_PORTAL; ps->dpwatertype |= 4; } -static void Shader_DP_Water(parsestate_t *ps, char **ptr) +static void Shader_DP_Water(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; ps->parseflags |= SPF_PROGRAMIFY; @@ -2495,7 +2602,7 @@ static void Shader_DP_Water(parsestate_t *ps, char **ptr) Shader_ParseVector(shader, ptr, ps->reflectcolour); ps->wateralpha = Shader_ParseFloat(shader, ptr, 0); } -static void Shader_DP_Reflect(parsestate_t *ps, char **ptr) +static void Shader_DP_Reflect(parsestate_t *ps, const char **ptr) { ps->parseflags |= SPF_PROGRAMIFY; @@ -2505,7 +2612,7 @@ static void Shader_DP_Reflect(parsestate_t *ps, char **ptr) ps->reflectfactor = Shader_ParseFloat(ps->s, ptr, 0); Shader_ParseVector(ps->s, ptr, ps->reflectcolour); } -static void Shader_DP_Refract(parsestate_t *ps, char **ptr) +static void Shader_DP_Refract(parsestate_t *ps, const char **ptr) { ps->parseflags |= SPF_PROGRAMIFY; @@ -2514,7 +2621,7 @@ static void Shader_DP_Refract(parsestate_t *ps, char **ptr) Shader_ParseVector(ps->s, ptr, ps->refractcolour); } -static void Shader_DP_OffsetMapping(parsestate_t *ps, char **ptr) +static void Shader_DP_OffsetMapping(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; char *token = Shader_ParseString(ptr); @@ -2537,16 +2644,16 @@ static void Shader_DP_OffsetMapping(parsestate_t *ps, char **ptr) else if (!strcmp(token, "match16")) ps->offsetmappingbias = 1.0 - (1.0/65535) * Shader_ParseFloat(shader, ptr, 32768); } -static void Shader_DP_GlossScale(parsestate_t *ps, char **ptr) +static void Shader_DP_GlossScale(parsestate_t *ps, const char **ptr) { ps->specularvalscale = Shader_ParseFloat(ps->s, ptr, 0); } -static void Shader_DP_GlossExponent(parsestate_t *ps, char **ptr) +static void Shader_DP_GlossExponent(parsestate_t *ps, const char **ptr) { ps->specularexpscale = Shader_ParseFloat(ps->s, ptr, 0); } -static void Shader_FactorBase(parsestate_t *ps, char **ptr) +static void Shader_FactorBase(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->factors[MATERIAL_FACTOR_BASE][0] = Shader_ParseFloat(shader, ptr, 1); @@ -2554,7 +2661,7 @@ static void Shader_FactorBase(parsestate_t *ps, char **ptr) shader->factors[MATERIAL_FACTOR_BASE][2] = Shader_ParseFloat(shader, ptr, 1); shader->factors[MATERIAL_FACTOR_BASE][3] = Shader_ParseFloat(shader, ptr, 1); } -static void Shader_FactorSpec(parsestate_t *ps, char **ptr) +static void Shader_FactorSpec(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->factors[MATERIAL_FACTOR_SPEC][0] = Shader_ParseFloat(shader, ptr, 1); @@ -2562,7 +2669,7 @@ static void Shader_FactorSpec(parsestate_t *ps, char **ptr) shader->factors[MATERIAL_FACTOR_SPEC][2] = Shader_ParseFloat(shader, ptr, 1); shader->factors[MATERIAL_FACTOR_SPEC][3] = Shader_ParseFloat(shader, ptr, 1); } -static void Shader_FactorEmit(parsestate_t *ps, char **ptr) +static void Shader_FactorEmit(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->factors[MATERIAL_FACTOR_EMIT][0] = Shader_ParseFloat(shader, ptr, 1); @@ -2571,7 +2678,7 @@ static void Shader_FactorEmit(parsestate_t *ps, char **ptr) shader->factors[MATERIAL_FACTOR_EMIT][3] = Shader_ParseFloat(shader, ptr, 1); } -static void Shader_BEMode(parsestate_t *ps, char **ptr) +static void Shader_BEMode(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; char subname[1024]; @@ -2949,7 +3056,7 @@ shaderpass_t *Shaderpass_DefineMap(parsestate_t *ps, shaderpass_t *pass) return pass; } -static void Shaderpass_Map (parsestate_t *ps, char **ptr) +static void Shaderpass_Map (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -2989,7 +3096,7 @@ static void Shaderpass_Map (parsestate_t *ps, char **ptr) } } -static void Shaderpass_AnimMap_Flag (parsestate_t *ps, char **ptr, unsigned int flags) +static void Shaderpass_AnimMap_Flag (parsestate_t *ps, const char **ptr, unsigned int flags) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3047,16 +3154,16 @@ static void Shaderpass_AnimMap_Flag (parsestate_t *ps, char **ptr, unsigned int } } } -static void Shaderpass_AnimMap (parsestate_t *ps, char **ptr) +static void Shaderpass_AnimMap (parsestate_t *ps, const char **ptr) { Shaderpass_AnimMap_Flag(ps, ptr, 0); } -static void Shaderpass_QF_AnimClampMap (parsestate_t *ps, char **ptr) +static void Shaderpass_QF_AnimClampMap (parsestate_t *ps, const char **ptr) { Shaderpass_AnimMap_Flag(ps, ptr, IF_CLAMP); } -static void Shaderpass_ClampMap (parsestate_t *ps, char **ptr) +static void Shaderpass_ClampMap (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; int flags; @@ -3096,7 +3203,7 @@ static void Shaderpass_ClampMap (parsestate_t *ps, char **ptr) } } -static void Shaderpass_VideoMap (parsestate_t *ps, char **ptr) +static void Shaderpass_VideoMap (parsestate_t *ps, const char **ptr) { char *token = Shader_ParseSensString (ptr); @@ -3131,38 +3238,38 @@ static void Shaderpass_VideoMap (parsestate_t *ps, char **ptr) #endif } -static void Shaderpass_RTCW_Map_16bit (parsestate_t *ps, char **ptr) +static void Shaderpass_RTCW_Map_16bit (parsestate_t *ps, const char **ptr) { if (!gl_load24bit.ival) //urm, not sure if suitable choice of cvar Shaderpass_Map(ps, ptr); } -static void Shaderpass_RTCW_Map_32bit (parsestate_t *ps, char **ptr) +static void Shaderpass_RTCW_Map_32bit (parsestate_t *ps, const char **ptr) { if (gl_load24bit.ival) Shaderpass_Map(ps, ptr); } -static void Shaderpass_RTCW_Map_s3tc (parsestate_t *ps, char **ptr) +static void Shaderpass_RTCW_Map_s3tc (parsestate_t *ps, const char **ptr) { if (sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival) Shaderpass_Map(ps, ptr); } -static void Shaderpass_RTCW_Map_nos3tc (parsestate_t *ps, char **ptr) +static void Shaderpass_RTCW_Map_nos3tc (parsestate_t *ps, const char **ptr) { if (!(sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival)) Shaderpass_Map(ps, ptr); } -static void Shaderpass_RTCW_AnimMap_s3tc (parsestate_t *ps, char **ptr) +static void Shaderpass_RTCW_AnimMap_s3tc (parsestate_t *ps, const char **ptr) { if ((sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival)) Shaderpass_AnimMap(ps, ptr); } -static void Shaderpass_RTCW_AnimMap_nos3tc (parsestate_t *ps, char **ptr) +static void Shaderpass_RTCW_AnimMap_nos3tc (parsestate_t *ps, const char **ptr) { if (!(sh_config.texfmt[PTI_BC3_RGBA] && gl_compress.ival)) Shaderpass_AnimMap(ps, ptr); } -static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr, int qrtype) +static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, const char **ptr, int qrtype) { /*accepts: program @@ -3204,14 +3311,14 @@ static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, char else pass->prog = Shader_FindGeneric(Shader_ParseExactString(ptr), qrtype); } -static void Shaderpass_ProgramName (parsestate_t *ps, char **ptr) +static void Shaderpass_ProgramName (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; Shaderpass_SLProgramName(shader,pass,ptr,qrenderer); } -static void Shaderpass_RGBGen (parsestate_t *ps, char **ptr) +static void Shaderpass_RGBGen (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3269,7 +3376,7 @@ static void Shaderpass_RGBGen (parsestate_t *ps, char **ptr) pass->rgbgen = RGB_GEN_BOTTOMCOLOR; } -static void Shaderpass_AlphaGen (parsestate_t *ps, char **ptr) +static void Shaderpass_AlphaGen (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3309,7 +3416,7 @@ static void Shaderpass_AlphaGen (parsestate_t *ps, char **ptr) pass->alphagen_func.args[0] = fabs(Shader_ParseFloat(shader, ptr, 0)); } } -static void Shaderpass_AlphaShift (parsestate_t *ps, char **ptr) +static void Shaderpass_AlphaShift (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3394,7 +3501,7 @@ static int Shader_BlendFactor(char *name, qboolean dstnotsrc) return factor; } -static void Shaderpass_BlendFunc (parsestate_t *ps, char **ptr) +static void Shaderpass_BlendFunc (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; char *token; @@ -3431,7 +3538,7 @@ static void Shaderpass_BlendFunc (parsestate_t *ps, char **ptr) } } -static void Shaderpass_AlphaFunc (parsestate_t *ps, char **ptr) +static void Shaderpass_AlphaFunc (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; char *token; @@ -3453,7 +3560,7 @@ static void Shaderpass_AlphaFunc (parsestate_t *ps, char **ptr) } } -static void Shaderpass_DepthFunc (parsestate_t *ps, char **ptr) +static void Shaderpass_DepthFunc (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; char *token; @@ -3481,7 +3588,7 @@ static void Shaderpass_DepthFunc (parsestate_t *ps, char **ptr) Con_DPrintf("Invalid depth func %s\n", token); } -static void Shaderpass_DepthWrite (parsestate_t *ps, char **ptr) +static void Shaderpass_DepthWrite (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3489,7 +3596,7 @@ static void Shaderpass_DepthWrite (parsestate_t *ps, char **ptr) pass->shaderbits |= SBITS_MISC_DEPTHWRITE; } -static void Shaderpass_NoDepthTest (parsestate_t *ps, char **ptr) +static void Shaderpass_NoDepthTest (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3497,13 +3604,13 @@ static void Shaderpass_NoDepthTest (parsestate_t *ps, char **ptr) pass->shaderbits |= SBITS_MISC_NODEPTHTEST; } -static void Shaderpass_NoDepth (parsestate_t *ps, char **ptr) +static void Shaderpass_NoDepth (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shader->flags |= SHADER_DEPTHWRITE; } -static void Shaderpass_TcMod (parsestate_t *ps, char **ptr) +static void Shaderpass_TcMod (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3581,7 +3688,7 @@ static void Shaderpass_TcMod (parsestate_t *ps, char **ptr) pass->numtcmods++; } -static void Shaderpass_Scale (parsestate_t *ps, char **ptr) +static void Shaderpass_Scale (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3621,7 +3728,7 @@ static void Shaderpass_Scale (parsestate_t *ps, char **ptr) pass->numtcmods++; } -static void Shaderpass_Scroll (parsestate_t *ps, char **ptr) +static void Shaderpass_Scroll (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3659,7 +3766,7 @@ static void Shaderpass_Scroll (parsestate_t *ps, char **ptr) } -static void Shaderpass_TcGen (parsestate_t *ps, char **ptr) +static void Shaderpass_TcGen (parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3689,85 +3796,85 @@ static void Shaderpass_TcGen (parsestate_t *ps, char **ptr) pass->tcgen = TC_GEN_SKYBOX; } } -static void Shaderpass_EnvMap (parsestate_t *ps, char **ptr) +static void Shaderpass_EnvMap (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->tcgen = TC_GEN_ENVIRONMENT; } -static void Shaderpass_Detail (parsestate_t *ps, char **ptr) +static void Shaderpass_Detail (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->flags |= SHADER_PASS_DETAIL; } -static void Shaderpass_AlphaMask (parsestate_t *ps, char **ptr) +static void Shaderpass_AlphaMask (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->shaderbits &= ~SBITS_ATEST_BITS; pass->shaderbits |= SBITS_ATEST_GE128; } -static void Shaderpass_NoLightMap (parsestate_t *ps, char **ptr) +static void Shaderpass_NoLightMap (parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->rgbgen = RGB_GEN_IDENTITY; } -static void Shaderpass_Red(parsestate_t *ps, char **ptr) +static void Shaderpass_Red(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; pass->rgbgen = RGB_GEN_CONST; pass->rgbgen_func.args[0] = Shader_ParseFloat(shader, ptr, 0); } -static void Shaderpass_Green(parsestate_t *ps, char **ptr) +static void Shaderpass_Green(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; pass->rgbgen = RGB_GEN_CONST; pass->rgbgen_func.args[1] = Shader_ParseFloat(shader, ptr, 0); } -static void Shaderpass_Blue(parsestate_t *ps, char **ptr) +static void Shaderpass_Blue(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; pass->rgbgen = RGB_GEN_CONST; pass->rgbgen_func.args[2] = Shader_ParseFloat(shader, ptr, 0); } -static void Shaderpass_Alpha(parsestate_t *ps, char **ptr) +static void Shaderpass_Alpha(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; pass->alphagen = ALPHA_GEN_CONST; pass->alphagen_func.args[0] = Shader_ParseFloat(shader, ptr, 0); } -static void Shaderpass_MaskColor(parsestate_t *ps, char **ptr) +static void Shaderpass_MaskColor(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->shaderbits |= SBITS_MASK_RED|SBITS_MASK_GREEN|SBITS_MASK_BLUE; } -static void Shaderpass_MaskRed(parsestate_t *ps, char **ptr) +static void Shaderpass_MaskRed(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->shaderbits |= SBITS_MASK_RED; } -static void Shaderpass_MaskGreen(parsestate_t *ps, char **ptr) +static void Shaderpass_MaskGreen(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->shaderbits |= SBITS_MASK_GREEN; } -static void Shaderpass_MaskBlue(parsestate_t *ps, char **ptr) +static void Shaderpass_MaskBlue(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->shaderbits |= SBITS_MASK_BLUE; } -static void Shaderpass_MaskAlpha(parsestate_t *ps, char **ptr) +static void Shaderpass_MaskAlpha(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; pass->shaderbits |= SBITS_MASK_ALPHA; } -static void Shaderpass_AlphaTest(parsestate_t *ps, char **ptr) +static void Shaderpass_AlphaTest(parsestate_t *ps, const char **ptr) { shader_t *shader = ps->s; shaderpass_t *pass = ps->pass; @@ -3776,7 +3883,7 @@ static void Shaderpass_AlphaTest(parsestate_t *ps, char **ptr) else Con_Printf("unsupported alphatest value\n"); } -static void Shaderpass_TexGen(parsestate_t *ps, char **ptr) +static void Shaderpass_TexGen(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; char *token = Shader_ParseString(ptr); @@ -3798,7 +3905,7 @@ static void Shaderpass_TexGen(parsestate_t *ps, char **ptr) Con_Printf("texgen token not understood\n"); } } -static void Shaderpass_CubeMap(parsestate_t *ps, char **ptr) +static void Shaderpass_CubeMap(parsestate_t *ps, const char **ptr) { shaderpass_t *pass = ps->pass; char *token = Shader_ParseString(ptr); @@ -4052,7 +4159,8 @@ void Shader_FlushCache(void) static void Shader_MakeCache(const char *path, unsigned int parseflags) { unsigned int key; - char *buf, *ptr, *token; + const char *buf, *ptr; + char *token; shadercache_t *cache; shadercachefile_t *cachefile, *filelink = NULL; qofs_t size; @@ -4107,7 +4215,7 @@ static void Shader_MakeCache(const char *path, unsigned int parseflags) ptr+=1; //blank line with mac or unix ending else if (ptr[0] == '/' && ptr[1] == '/') { - char *e = strchr(ptr, '\n'); + const char *e = strchr(ptr, '\n'); if (e) e++; else @@ -4178,7 +4286,7 @@ static void Shader_MakeCache(const char *path, unsigned int parseflags) } while ( ptr ); } -static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, size_t *offset, shadercachefile_t **sourcefile) +static qboolean Shader_LocateSource(const char *name, const char **buf, size_t *bufsize, size_t *offset, shadercachefile_t **sourcefile) { unsigned int key; shadercache_t *cache; @@ -4203,7 +4311,7 @@ static qboolean Shader_LocateSource(char *name, char **buf, size_t *bufsize, siz return false; } -static char *Shader_Skip(const char *file, const char *shadername, char *ptr) +static const char *Shader_Skip(const char *file, const char *shadername, const char *ptr) { char *tok; int brace_count; @@ -4225,7 +4333,7 @@ static char *Shader_Skip(const char *file, const char *shadername, char *ptr) if ( !tok[0] ) { - Con_Printf("%s: unexpected EOF parsing %s\n", file, shadername); + Con_Printf(CON_WARNING"%s: unexpected EOF parsing %s\n", file, shadername); return NULL; } @@ -4495,8 +4603,9 @@ struct scondinfo_s #define COND_ALLOWELSE 4 #define COND_TAKEN 8 }; -static qboolean Shader_Conditional_Read(shader_t *shader, struct scondinfo_s *cond, char *token, char **ptr) +static qboolean Shader_Conditional_Read(parsestate_t *ps, struct scondinfo_s *cond, const char *token, const char **ptr) { + shader_t *shader = ps->s; if (!Q_stricmp(token, "if")) { if (cond->depth+1 == countof(cond->level)) @@ -4534,7 +4643,7 @@ static qboolean Shader_Conditional_Read(shader_t *shader, struct scondinfo_s *co } else { - Con_Printf("unexpected elif statement in shader %s\n", shader->name); + Con_Printf(CON_WARNING"unexpected elif statement in shader %s\n", shader->name); *ptr += strlen(*ptr); } } @@ -4560,7 +4669,7 @@ static qboolean Shader_Conditional_Read(shader_t *shader, struct scondinfo_s *co } else { - Con_Printf("unexpected else statement in shader %s\n", shader->name); + Con_Printf(CON_WARNING"unexpected else statement in shader %s\n", shader->name); *ptr += strlen(*ptr); } } @@ -4582,7 +4691,7 @@ static qboolean Shader_Conditional_Read(shader_t *shader, struct scondinfo_s *co void Shader_Readpass (parsestate_t *ps) { shader_t *shader = ps->s; - char *token; + const char *token; shaderpass_t *pass; static shader_t dummy; struct scondinfo_s cond = {0}; @@ -4625,12 +4734,12 @@ void Shader_Readpass (parsestate_t *ps) { continue; } - else if (!Shader_Conditional_Read(shader, &cond, token, &ps->ptr)) + else if (!Shader_Conditional_Read(ps, &cond, token, &ps->ptr)) { if ( token[0] == '}' ) break; else if (token[0] == '{') - Con_Printf("unexpected indentation in %s\n", shader->name); + Con_Printf(CON_WARNING"%s: unexpected indentation in %s\n", ps->sourcename, shader->name); else if ( Shader_Parsetok (ps, shaderpasskeys, token) ) break; } @@ -4736,10 +4845,10 @@ void Shader_Readpass (parsestate_t *ps) } //we've read the first token, now make sense of it and any args -static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, char *token) +static qboolean Shader_Parsetok(parsestate_t *ps, shaderkey_t *keys, const char *token) { shaderkey_t *key; - char *prefix; + const char *prefix; qboolean toolchainprefix = false; if (*token == '_') @@ -7013,7 +7122,7 @@ static qboolean Shader_ReadShaderTerms(parsestate_t *ps, struct scondinfo_s *con if ( !token[0] ) return true; - else if (!Shader_Conditional_Read(ps->s, cond, token, &ps->ptr)) + else if (!Shader_Conditional_Read(ps, cond, token, &ps->ptr)) { int i; for (i = 0; shadermacros[i].name; i++) @@ -7022,7 +7131,7 @@ static qboolean Shader_ReadShaderTerms(parsestate_t *ps, struct scondinfo_s *con { #define SHADER_MACRO_ARGS 8 int argn = 0; - char *oldptr; + const char *oldptr; char arg[SHADER_MACRO_ARGS][256]; char tmp[4096], *out, *in; //parse args until the end of the line @@ -7087,7 +7196,7 @@ static qboolean Shader_ReadShaderTerms(parsestate_t *ps, struct scondinfo_s *con } //loads a shader string into an existing shader object, and finalises it and stuff -static void Shader_ReadShader(parsestate_t *ps, char *shadersource, shadercachefile_t *sourcefile) +static void Shader_ReadShader(parsestate_t *ps, const char *shadersource, shadercachefile_t *sourcefile) { struct scondinfo_s cond = {0}; char **savebody = ps->saveshaderbody; @@ -7141,12 +7250,12 @@ static void Shader_ReadShader(parsestate_t *ps, char *shadersource, shadercachef } } -static qboolean Shader_ParseShader(parsestate_t *ps, char *parsename) +static qboolean Shader_ParseShader(parsestate_t *ps, const char *parsename) { size_t offset = 0, length; - char *buf = NULL; + const char *buf = NULL; shadercachefile_t *sourcefile = NULL; - char *file; + const char *file; const char *token; if (!strchr(parsename, ':')) @@ -7189,7 +7298,7 @@ static qboolean Shader_ParseShader(parsestate_t *ps, char *parsename) token = COM_ParseExt (&file, true, true); if ( !file || token[0] != '{' ) { - FS_FreeFile(buf); + FS_FreeFile((char*)buf); return false; } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 92b99606..1f485785 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -2462,6 +2462,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, int lighttype, vec3_t axis[3], qbyte *lvi fmt = PTI_DEPTH24_8; else fmt = PTI_DEPTH16; + (void)fmt; if (lighttype & (LSHADER_SPOT|LSHADER_ORTHO)) { //spotlights only face forwards. which is side 4. which is annoying. diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index cbd2cc9c..c069eb54 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -116,6 +116,7 @@ FTEPFNGLBINDATTRIBLOCATIONARBPROC qglBindAttribLocationARB; FTEPFNGLGETATTRIBLOCATIONARBPROC qglGetAttribLocationARB; FTEPFNGLGETUNIFORMLOCATIONARBPROC qglGetUniformLocationARB; FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix4fvARB; +FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix3fvARB; FTEPFNGLUNIFORM4FARBPROC qglUniform4fARB; FTEPFNGLUNIFORM4FVARBPROC qglUniform4fvARB; FTEPFNGLUNIFORM3FARBPROC qglUniform3fARB; @@ -1050,6 +1051,7 @@ static qboolean GL_CheckExtensions (void *(*getglfunction) (char *name)) qglGetAttribLocationARB = (void *)getglext("glGetAttribLocation"); qglGetUniformLocationARB = (void *)getglext("glGetUniformLocation"); qglUniformMatrix4fvARB = (void *)getglext("glUniformMatrix4fv"); + qglUniformMatrix3fvARB = (void *)getglext("glUniformMatrix3fv"); qglUniformMatrix3x4fv = (void *)getglext("glUniformMatrix3x4fv"); qglUniformMatrix4x3fv = (void *)getglext("glUniformMatrix4x3fv"); qglUniform4fARB = (void *)getglext("glUniform4f"); @@ -1103,6 +1105,7 @@ static qboolean GL_CheckExtensions (void *(*getglfunction) (char *name)) qglDisableVertexAttribArray = (void *)getglext("glDisableVertexAttribArrayARB"); qglGetUniformLocationARB = (void *)getglext("glGetUniformLocationARB"); qglUniformMatrix4fvARB = (void *)getglext("glUniformMatrix4fvARB"); + qglUniformMatrix3fvARB = (void *)getglext("glUniformMatrix3fvARB"); qglUniformMatrix3x4fv = (void *)getglext("glUniformMatrix3x4fvARB"); qglUniformMatrix4x3fv = (void *)getglext("glUniformMatrix4x3fvARB"); qglUniform4fARB = (void *)getglext("glUniform4fARB"); @@ -1399,7 +1402,9 @@ static const char *glsl_hdrs[] = "#define SPECULAR_BASE_POW 32.0\n" "#define SPECULAR_BASE_MUL 1.0\n" "#endif\n" - "#define FTE_SPECULAR_EXPONENT (SPECULAR_BASE_POW*float(SPECEXP))\n" + "#ifndef FTE_SPECULAR_EXPONENT\n" + "#define FTE_SPECULAR_EXPONENT (SPECULAR_BASE_POW*float(SPECEXP))\n" + "#endif\n" "#ifndef SPECMUL\n" "#define SPECMUL 1.0\n" "#endif\n" @@ -1513,6 +1518,7 @@ static const char *glsl_hdrs[] = "#endif\n" "uniform mat4 m_invviewprojection;" "uniform mat4 m_invmodelviewprojection;" + "uniform mat3 m_invmodelview;" /*viewer properties*/ "uniform vec3 v_eyepos;" @@ -2313,7 +2319,7 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int ); } - if (prog) + if (prog && !prog->explicitsyms) { //for compat with our vulkan processor, which injects samplers in order to control layouts. const char *defaultsamplernames[] = { @@ -2403,41 +2409,44 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int ); } - if (gl_config_nofixedfunc) + if (!prog->explicitsyms) { - GLSlang_GenerateInternal(&glsl, - "attribute vec3 v_position1;\n" - "#ifdef FRAMEBLEND\n" - "attribute vec3 v_position2;\n" - "uniform vec2 e_vblend;\n" - "#define v_position ((v_position1*e_vblend.x)+(v_position2*e_vblend.y))\n" - "#else\n" - "#define v_position v_position1\n" - "#endif\n" - "uniform mat4 m_modelviewprojection;\n" + if (gl_config_nofixedfunc) + { + GLSlang_GenerateInternal(&glsl, + "attribute vec3 v_position1;\n" + "#ifdef FRAMEBLEND\n" + "attribute vec3 v_position2;\n" + "uniform vec2 e_vblend;\n" + "#define v_position ((v_position1*e_vblend.x)+(v_position2*e_vblend.y))\n" + "#else\n" + "#define v_position v_position1\n" + "#endif\n" + "uniform mat4 m_modelviewprojection;\n" #if 1//def FTE_TARGET_WEB - //IE is buggy - "vec4 ftetransform() { return m_modelviewprojection * vec4(v_position, 1.0); }\n" + //IE is buggy + "vec4 ftetransform() { return m_modelviewprojection * vec4(v_position, 1.0); }\n" #else - "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" + "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" #endif - ); - } - else - { - GLSlang_GenerateInternal(&glsl, - "#ifdef FRAMEBLEND\n" - "attribute vec3 v_position2;\n" - "uniform vec2 e_vblend;\n" - "#define v_position (gl_Vertex.xyz*e_vblend.x+v_position2*e_vblend.y)\n" - "uniform mat4 m_modelviewprojection;\n" - "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" - "#else\n" - "#define v_position gl_Vertex.xyz\n" - "uniform mat4 m_modelviewprojection;\n" - "#define ftetransform ftransform\n" - "#endif\n" - ); + ); + } + else + { + GLSlang_GenerateInternal(&glsl, + "#ifdef FRAMEBLEND\n" + "attribute vec3 v_position2;\n" + "uniform vec2 e_vblend;\n" + "#define v_position (gl_Vertex.xyz*e_vblend.x+v_position2*e_vblend.y)\n" + "uniform mat4 m_modelviewprojection;\n" + "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" + "#else\n" + "#define v_position gl_Vertex.xyz\n" + "uniform mat4 m_modelviewprojection;\n" + "#define ftetransform ftransform\n" + "#endif\n" + ); + } } break; @@ -2626,8 +2635,9 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL return shader; } -GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLhandleARB cont, GLhandleARB eval, GLhandleARB geom, GLhandleARB frag) +GLhandleARB GLSlang_CreateProgramObject (program_t *prog, const char *name, GLhandleARB vert, GLhandleARB cont, GLhandleARB eval, GLhandleARB geom, GLhandleARB frag) { + int i; GLhandleARB program; program = qglCreateProgramObjectARB(); @@ -2637,36 +2647,16 @@ GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLh if (eval) qglAttachObjectARB(program, eval); if (frag) qglAttachObjectARB(program, frag); - qglBindAttribLocationARB(program, VATTR_VERTEX1, "v_position1"); - qglBindAttribLocationARB(program, VATTR_COLOUR, "v_colour"); - qglBindAttribLocationARB(program, VATTR_TEXCOORD, "v_texcoord"); - qglBindAttribLocationARB(program, VATTR_LMCOORD, "v_lmcoord"); - qglBindAttribLocationARB(program, VATTR_NORMALS, "v_normal"); - qglBindAttribLocationARB(program, VATTR_SNORMALS, "v_svector"); - qglBindAttribLocationARB(program, VATTR_TNORMALS, "v_tvector"); - qglBindAttribLocationARB(program, VATTR_VERTEX2, "v_position2"); - - //the following MAY not be valid in gles2. - if (gl_config.maxattribs > VATTR_BONENUMS) - qglBindAttribLocationARB(program, VATTR_BONENUMS, "v_bone"); - if (gl_config.maxattribs > VATTR_BONEWEIGHTS) - qglBindAttribLocationARB(program, VATTR_BONEWEIGHTS, "v_weight"); -#if MAXRLIGHTMAPS > 1 - if (gl_config.maxattribs > VATTR_COLOUR2) - qglBindAttribLocationARB(program, VATTR_COLOUR2, "v_colour2"); - if (gl_config.maxattribs > VATTR_COLOUR3) - qglBindAttribLocationARB(program, VATTR_COLOUR3, "v_colour3"); - if (gl_config.maxattribs > VATTR_COLOUR4) - qglBindAttribLocationARB(program, VATTR_COLOUR4, "v_colour4"); -#endif -#if MAXRLIGHTMAPS > 1 - if (gl_config.maxattribs > VATTR_LMCOORD2) - qglBindAttribLocationARB(program, VATTR_LMCOORD2, "v_lmcoord2"); - if (gl_config.maxattribs > VATTR_LMCOORD3) - qglBindAttribLocationARB(program, VATTR_LMCOORD3, "v_lmcoord3"); - if (gl_config.maxattribs > VATTR_LMCOORD4) - qglBindAttribLocationARB(program, VATTR_LMCOORD4, "v_lmcoord4"); -#endif + for (i = 0; shader_attr_names[i].name; i++) + { + if (gl_config.maxattribs > shader_attr_names[i].ptype) + { + if (prog->explicitsyms) + qglBindAttribLocationARB(program, shader_attr_names[i].ptype, va("fte_%s", shader_attr_names[i].name)); + else + qglBindAttribLocationARB(program, shader_attr_names[i].ptype, shader_attr_names[i].name); + } + } qglLinkProgramARB(program); return program; @@ -2762,7 +2752,7 @@ union programhandle_u GLSlang_CreateProgram(program_t *prog, const char *name, i if (!vs || !fs) ret.glsl.handle = 0; else - ret.glsl.handle = GLSlang_CreateProgramObject(name, vs, cs, es, gs, fs); + ret.glsl.handle = GLSlang_CreateProgramObject(prog, name, vs, cs, es, gs, fs); //delete ignores 0s. if (vs) qglDeleteShaderObject_(vs); if (gs) qglDeleteShaderObject_(gs); @@ -2890,9 +2880,9 @@ static void GLSlang_DeleteProg(program_t *prog) } } -static void GLSlang_ProgAutoFields(program_t *prog, struct programpermu_s *pp, cvar_t **cvars, char **cvarnames, int *cvartypes) +static void GLSlang_ProgAutoFields(program_t *prog, struct programpermu_s *pp, char **cvarnames, int *cvartypes) { - unsigned int i; + unsigned int i,j; int uniformloc; char tmpname[128]; int maxparms = 0; @@ -2901,7 +2891,10 @@ static void GLSlang_ProgAutoFields(program_t *prog, struct programpermu_s *pp, c GLSlang_UseProgram(pp->h.glsl.handle); for (i = 0; shader_attr_names[i].name; i++) { - uniformloc = qglGetAttribLocationARB(pp->h.glsl.handle, shader_attr_names[i].name); + if (prog->explicitsyms) + uniformloc = qglGetAttribLocationARB(pp->h.glsl.handle, va("fte_%s", shader_attr_names[i].name)); + else + uniformloc = qglGetAttribLocationARB(pp->h.glsl.handle, shader_attr_names[i].name); if (uniformloc != -1) { if (shader_attr_names[i].ptype != uniformloc) @@ -2937,22 +2930,53 @@ static void GLSlang_ProgAutoFields(program_t *prog, struct programpermu_s *pp, c /*FIXME: enumerate cvars automatically instead*/ for (i = 0; cvarnames[i]; i++) { - if (!cvars[i]) - continue; - - Q_snprintfz(tmpname, sizeof(tmpname), "cvar_%s", cvarnames[i]); - uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); - if (uniformloc >= 0) + if (cvartypes[i] <= SP_CONST4F) { - if (pp->numparms >= maxparms) + char *t; + Q_snprintfz(tmpname, sizeof(tmpname), "%s", cvarnames[i]); + t = strchr(tmpname, '='); + if (t) *t++=0; + uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); + if (uniformloc >= 0) { - maxparms = pp->numparms?pp->numparms * 2:8; - pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); + if (pp->numparms >= maxparms) + { + maxparms = pp->numparms?pp->numparms * 2:8; + pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); + } + pp->parm[pp->numparms].type = cvartypes[i]; + for(j = 0; j < 4; j++) + { + t = COM_Parse(t); + if (cvartypes[i] >= SP_CONST1F && cvartypes[i] <= SP_CONST4F) + pp->parm[pp->numparms].fval[j] = atoi(com_token); + else + pp->parm[pp->numparms].ival[j] = atoi(com_token); + } + pp->parm[pp->numparms].handle = uniformloc; + pp->numparms++; + } + } + else + { + cvar_t *ref = Cvar_FindVar(cvarnames[i]); + if (!ref) + continue; //shouldn't happen... + + Q_snprintfz(tmpname, sizeof(tmpname), "cvar_%s", cvarnames[i]); + uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, tmpname); + if (uniformloc >= 0) + { + if (pp->numparms >= maxparms) + { + maxparms = pp->numparms?pp->numparms * 2:8; + pp->parm = BZ_Realloc(pp->parm, sizeof(*pp->parm) * maxparms); + } + pp->parm[pp->numparms].type = cvartypes[i]; + pp->parm[pp->numparms].pval = ref; + pp->parm[pp->numparms].handle = uniformloc; + pp->numparms++; } - pp->parm[pp->numparms].type = cvartypes[i]; - pp->parm[pp->numparms].pval = cvars[i]; - pp->parm[pp->numparms].handle = uniformloc; - pp->numparms++; } } @@ -3417,9 +3441,6 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglTexCoord1f = (void *)getglcore("glTexCoord1f"); qglTexCoord2f = (void *)getglcore("glTexCoord2f"); qglTexCoord2fv = (void *)getglcore("glTexCoord2fv"); - qglTexEnvf = (void *)getglcore("glTexEnvf"); - qglTexEnvfv = (void *)getglcore("glTexEnvfv"); - qglTexEnvi = (void *)getglcore("glTexEnvi"); qglTexGeni = (void *)getglcore("glTexGeni"); qglTexGenfv = (void *)getglcore("glTexGenfv"); qglTranslatef = (void *)getglcore("glTranslatef"); @@ -3442,6 +3463,12 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name)) qglEndList = (void*)getglcore("glEndList"); qglCallList = (void*)getglcore("glCallList"); } + if (!gl_config.gles || (gl_config.gles && gl_config.glversion<2)) + { + qglTexEnvf = (void *)getglcore("glTexEnvf"); + qglTexEnvfv = (void *)getglcore("glTexEnvfv"); + qglTexEnvi = (void *)getglcore("glTexEnvi"); + } if (!qglColor4fv) qglColor4fv = GL_Color4fv_Emul; //can be missing in gles1 #endif diff --git a/engine/gl/gl_videgl.c b/engine/gl/gl_videgl.c index c2ade6a1..87edf5ad 100644 --- a/engine/gl/gl_videgl.c +++ b/engine/gl/gl_videgl.c @@ -303,7 +303,7 @@ qboolean EGL_InitDisplay (rendererstate_t *info, int eglplat, void *ndpy, EGLNat // EGL_SAMPLES, info->multisample, // EGL_STENCIL_SIZE, 8, EGL_ALPHA_MASK_SIZE, 0, - EGL_DEPTH_SIZE, 16, + EGL_DEPTH_SIZE, info->depthbits?info->depthbits:16, EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, EGL_BLUE_SIZE, 1, diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 6171a366..44ebb125 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -2005,7 +2005,7 @@ static GLXFBConfig GLX_GetFBConfig(rendererstate_t *info) } } //attrib[n++] = GLX_ALPHA_SIZE; attrib[n++] = GLX_DONT_CARE; - attrib[n++] = GLX_DEPTH_SIZE; attrib[n++] = 16; + attrib[n++] = GLX_DEPTH_SIZE; attrib[n++] = info->depthbits?info->depthbits:16; attrib[n++] = GLX_STENCIL_SIZE; attrib[n++] = (i&16)?0:4; if (!(i&8)) diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 55250557..078908fd 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -2379,7 +2379,7 @@ static BOOL CheckForcePixelFormat(rendererstate_t *info) } } // iAttribute[iAttributes++] = WGL_ALPHA_BITS_ARB; iAttribute[iAttributes++] = 2; - iAttribute[iAttributes++] = WGL_DEPTH_BITS_ARB; iAttribute[iAttributes++] = 16; + iAttribute[iAttributes++] = WGL_DEPTH_BITS_ARB; iAttribute[iAttributes++] = info->depthbits?info->depthbits:16; iAttribute[iAttributes++] = WGL_STENCIL_BITS_ARB; iAttribute[iAttributes++] = 8; iAttribute[iAttributes++] = WGL_DOUBLE_BUFFER_ARB; iAttribute[iAttributes++] = GL_TRUE; iAttribute[iAttributes++] = WGL_STEREO_ARB; iAttribute[iAttributes++] = info->stereo; diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index c429aab8..829de89b 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -611,6 +611,7 @@ void R_NetGraph (void); #define qglGetAttribLocationARB glGetAttribLocation #define qglGetUniformLocationARB glGetUniformLocation #define qglUniformMatrix4fvARB glUniformMatrix4fv +#define qglUniformMatrix3fvARB glUniformMatrix3fv #define qglUniform4fARB glUniform4f #define qglUniform4fvARB glUniform4fv #define qglUniform3fARB glUniform3f @@ -707,6 +708,7 @@ extern FTEPFNGLBINDATTRIBLOCATIONARBPROC qglBindAttribLocationARB; extern FTEPFNGLGETATTRIBLOCATIONARBPROC qglGetAttribLocationARB; extern FTEPFNGLGETUNIFORMLOCATIONARBPROC qglGetUniformLocationARB; extern FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix4fvARB; +extern FTEPFNGLUNIFORMMATRIXPROC qglUniformMatrix3fvARB; extern FTEPFNGLUNIFORM4FARBPROC qglUniform4fARB; extern FTEPFNGLUNIFORM4FVARBPROC qglUniform4fvARB; extern FTEPFNGLUNIFORM3FARBPROC qglUniform3fARB; diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 4d4100c0..3b5739c0 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -445,6 +445,7 @@ typedef struct { SP_M_ENTBONES_PACKED, SP_M_ENTBONES_MAT3X4, + SP_M_ENTBONES_MAT4, SP_M_VIEW, SP_M_MODEL, SP_M_MODELVIEW, @@ -452,6 +453,7 @@ typedef struct { SP_M_MODELVIEWPROJECTION, SP_M_INVVIEWPROJECTION, SP_M_INVMODELVIEWPROJECTION, + SP_M_INVMODELVIEW, SP_RENDERTEXTURESCALE, /*multiplier for currentrender->texcoord*/ SP_SOURCESIZE, /*size of $sourcecolour*/ @@ -470,17 +472,24 @@ typedef struct { //things that are set immediatly SP_FIRSTIMMEDIATE, //never set - SP_CONSTI, - SP_CONSTF, + SP_TEXTURE, + SP_CONST1I, + SP_CONST2I, + SP_CONST3I, + SP_CONST4I, + SP_CONST1F, + SP_CONST2F, + SP_CONST3F, + SP_CONST4F, SP_CVARI, SP_CVARF, SP_CVAR3F, - SP_TEXTURE + SP_CVAR4F, } type; union { - int ival; - float fval; + int ival[4]; + float fval[4]; void *pval; }; unsigned int handle; @@ -532,10 +541,11 @@ typedef struct programshared_s { char *name; int refs; - unsigned nofixedcompat:1; - unsigned tess:2; - unsigned geom:1; - unsigned warned:1; //one of the permutations of this shader has already been warned about. don't warn about all of them because that's potentially spammy. + unsigned calcgens:1; //calculate legacy rgb/alpha/tc gens + unsigned explicitsyms:1; //avoid defining symbol names that'll conflict with other glsl (any fte-specific names must have an fte_ prefix) + unsigned tess:1; //has a tessellation control+evaluation shader + unsigned geom:1; //has a geometry shader + unsigned warned:1; //one of the permutations of this shader has already been warned about. don't warn about all of them because that's potentially spammy. unsigned short numsamplers; //shader system can strip any passes above this unsigned int defaulttextures; //diffuse etc @@ -821,7 +831,7 @@ typedef struct qboolean (*pLoadBlob) (program_t *prog, unsigned int permu, vfsfile_t *blobfile); qboolean (*pCreateProgram) (program_t *prog, struct programpermu_s *permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile); qboolean (*pValidateProgram)(program_t *prog, struct programpermu_s *permu, qboolean noerrors, vfsfile_t *blobfile); - void (*pProgAutoFields) (program_t *prog, struct programpermu_s *permu, cvar_t **cvars, char **cvarnames, int *cvartypes); + void (*pProgAutoFields) (program_t *prog, struct programpermu_s *permu, char **cvarnames, int *cvartypes); } sh_config_t; extern sh_config_t sh_config; #endif diff --git a/engine/qclib/Makefile b/engine/qclib/Makefile index 36b61bb3..c3e8cf68 100644 --- a/engine/qclib/Makefile +++ b/engine/qclib/Makefile @@ -78,6 +78,9 @@ qccguistuff.o: qccguistuff.c qcc.h packager.o: qccguistuff.c qcc.h $(DO_CC) +%.o: %.c + $(DO_CC) + qcc_gtk.o: qcc_gtk.c qcc.h $(DO_CC) `pkg-config --cflags gtk+-2.0` @@ -91,15 +94,18 @@ clean: qcvm.so: $(QCC_OBJS) $(VM_OBJS) $(COMMON_OBJS) $(CC) $(BASE_CFLAGS) -o $@ -O3 $(BASE_LDFLAGS) $(QCC_OBJS) $(VM_OBJS) $(COMMON_OBJS) -shared - +qcvm.a: $(QCC_OBJS) $(VM_OBJS) $(COMMON_OBJS) + ar r $@ $^ test.o: test.c $(DO_CC) -testapp.bin: qcvm.so test.o - $(CC) $(BASE_CFLAGS) -o testapp.bin -O3 $(BASE_LDFLAGS) qcvm.so test.o +testapp.bin: test.o qcvm.a + $(CC) $(BASE_CFLAGS) $(CFLAGS) -o testapp.bin -O3 $(BASE_LDFLAGS) $^ -lm -lz tests: testapp.bin + @echo Running Tests... @$(foreach a,$(wildcard tests/*.src), echo TEST: $a; rm progs.dat; ./testapp.bin progs.dat -srcfile $a; echo; echo) + @echo Tests run. -.PHONY: tests \ No newline at end of file +.PHONY: tests diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index 9638eea3..32e0796f 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -1681,7 +1681,11 @@ static void PDECL PR_Shutdown(pubprogfuncs_t *ppf) #endif #if defined(QCLIBDLL_EXPORTS) -__declspec(dllexport) + #ifdef _WIN32 + __declspec(dllexport) + #else + __attribute__((visibility("default"))) + #endif #endif pubprogfuncs_t * PDECL InitProgs(progexterns_t *ext) { @@ -1698,7 +1702,7 @@ pubprogfuncs_t * PDECL InitProgs(progexterns_t *ext) #undef memalloc #undef pr_progstate #undef pr_argc - funcs = ext->memalloc(sizeof(progfuncs_t)); + funcs = (ext->memalloc?ext->memalloc:qclib_malloc)(sizeof(progfuncs_t)); memcpy(&funcs->funcs, &deffuncs, sizeof(pubprogfuncs_t)); memset(&funcs->inst, 0, sizeof(funcs->inst)); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index 6afe1371..2624d638 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -182,7 +182,7 @@ struct pubprogfuncs_s void (PDECL *AddSharedVar) (pubprogfuncs_t *progfuncs, int start, int size); void (PDECL *AddSharedFieldVar) (pubprogfuncs_t *progfuncs, int num, char *relstringtable); char *(PDECL *RemoveProgsString) (pubprogfuncs_t *progfuncs, string_t str); - pbool (PDECL *GetFunctionInfo) (pubprogfuncs_t *progfuncs, func_t func, int *argcount, qbyte **argsizes, int *builtinnum, char *funcname, size_t funcnamesize); //queries the interesting info from a function def + pbool (PDECL *GetFunctionInfo) (pubprogfuncs_t *progfuncs, func_t func, int *argcount, unsigned char **argsizes, int *builtinnum, char *funcname, size_t funcnamesize); //queries the interesting info from a function def void (PDECL *GenerateStatementString) (pubprogfuncs_t *progfuncs, int statementnum, char *out, int outlen); //disassembles a specific statement. for debugging reports. fdef_t *(PDECL *FieldInfo) (pubprogfuncs_t *progfuncs, unsigned int *count); char *(PDECL *UglyValueString) (pubprogfuncs_t *progfuncs, etype_t type, union eval_s *val); @@ -249,7 +249,11 @@ typedef struct progexterns_s { } progparms_t, progexterns_t; #if defined(QCLIBDLL_EXPORTS) -__declspec(dllexport) + #ifdef _WIN32 + __declspec(dllexport) + #else + __attribute__((visibility("default"))) + #endif #endif pubprogfuncs_t * PDECL InitProgs(progparms_t *ext); diff --git a/engine/qclib/test.c b/engine/qclib/test.c index bee386ae..23360856 100644 --- a/engine/qclib/test.c +++ b/engine/qclib/test.c @@ -14,7 +14,7 @@ #include #include - +enum{false,true}; //builtins and builtin management. @@ -53,7 +53,7 @@ char *va(char *format, ...) return string; } -void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, char *s, int firstarg, char *outbuf, int outbuflen) +void QCBUILTIN PF_sprintf_internal (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals, const char *s, int firstarg, char *outbuf, int outbuflen) { const char *s0; char *o = outbuf, *end = outbuf + outbuflen, *err; @@ -394,7 +394,7 @@ void PF_printf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void PF_spawn (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { struct edict_s *ed; - ed = ED_Alloc(prinst); + ed = ED_Alloc(prinst, false, 0); pr_globals = PR_globals(prinst, PR_CURRENT); RETURN_EDICT(prinst, ed); } @@ -435,8 +435,9 @@ int Sys_Printf(char *s, ...) #include //copy file into buffer. note that the buffer will have been sized to fit the file (obtained via FileSize) -unsigned char *Sys_ReadFile (char *fname, void *buffer, int buflen) +void *PDECL Sys_ReadFile(const char *fname, unsigned char *(PDECL *buf_get)(void *ctx, size_t len), void *buf_ctx, size_t *out_size, pbool issourcefile) { + void *buffer; int len; FILE *f; if (!strncmp(fname, "src/", 4)) @@ -446,15 +447,17 @@ unsigned char *Sys_ReadFile (char *fname, void *buffer, int buflen) return NULL; fseek(f, 0, SEEK_END); len = ftell(f); - if (buflen < len) - return NULL; + + buffer = buf_get(buf_ctx, len); fseek(f, 0, SEEK_SET); fread(buffer, 1, len, f); fclose(f); + + *out_size = len; return buffer; } //Finds the size of a file. -int Sys_FileSize (char *fname) +int Sys_FileSize (const char *fname) { int len; FILE *f; @@ -469,7 +472,7 @@ int Sys_FileSize (char *fname) return len; } //Writes a file. -pbool Sys_WriteFile (char *fname, void *data, int len) +pbool Sys_WriteFile (const char *fname, void *data, int len) { FILE *f; f = fopen(fname, "wb"); @@ -480,7 +483,7 @@ pbool Sys_WriteFile (char *fname, void *data, int len) return 1; } -void runtest(char *progsname) +void runtest(const char *progsname) { pubprogfuncs_t *pf; func_t func; @@ -499,9 +502,9 @@ void runtest(char *progsname) ext.globalbuiltins = builtins; pf = InitProgs(&ext); - pf->Configure(pf, 1024*1024, 1); //memory quantity of 1mb. Maximum progs loadable into the instance of 1 + pf->Configure(pf, 1024*1024, 1, false); //memory quantity of 1mb. Maximum progs loadable into the instance of 1 //If you support multiple progs types, you should tell the VM the offsets here, via RegisterFieldVar - pn = pf->LoadProgs(pf, progsname, 0, NULL, 0); //load the progs, don't care about the crc, and use those builtins. + pn = pf->LoadProgs(pf, progsname); //load the progs. if (pn < 0) printf("test: Failed to load progs \"%s\"\n", progsname); else @@ -519,13 +522,12 @@ void runtest(char *progsname) else pf->ExecuteProgram(pf, func); //call the function } - pf->CloseProgs(pf); + pf->Shutdown(pf); } - //Run a compiler and nothing else. //Note that this could be done with an autocompile of PR_COMPILEALWAYS. -void compile(int argc, char **argv) +void compile(int argc, const char **argv) { pubprogfuncs_t *pf; @@ -564,13 +566,15 @@ void compile(int argc, char **argv) while(pf->ContinueCompile(pf) == 1) ; } + else + printf("compilation failed to start\n"); } else printf("no compiler in this qcvm build\n"); - pf->CloseProgs(pf); + pf->Shutdown(pf); } -int main(int argc, char **argv) +int main(int argc, const char **argv) { if (argc < 2) { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 02102268..38006237 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -2600,6 +2600,19 @@ void QC_Clear(void) =============================================================================== */ +static void PR_ConsoleCommand_f(void) +{ + char cmd[2048]; + Q_snprintfz(cmd, sizeof(cmd), "%s %s", Cmd_Argv(0), Cmd_Args()); + PR_ConsoleCmd(cmd); +} +static void QCBUILTIN PF_sv_registercommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + const char *str = PF_VarString(prinst, 0, pr_globals); + if (!Cmd_Exists(str)) + Cmd_AddCommand(str, PR_ConsoleCommand_f); +} + static void SV_Effect(vec3_t org, int mdlidx, int startframe, int endframe, int framerate) { @@ -5173,6 +5186,12 @@ void QCBUILTIN PF_WriteByte (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo qbyte val = PF_Write_BoundForNetwork(prinst, 0, G_FLOAT(OFS_PARM1), 255); if (dest == MSG_CSQC) { //csqc buffers are always written. + if (!csqcmsgbuffer.maxsize) + { + PR_StackTrace(prinst, false); + prinst->parms->Abort ("MSG_CSQC outside of SendEntity method"); + } + MSG_WriteByte(&csqcmsgbuffer, val); return; } @@ -10442,8 +10461,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"error", PF_Fixme, 0, 0, 0, 2, D("void(string err,...)", "Fatal error that will trigger a crash-to-console that users will actually notice.")}, {"objerror", PF_Fixme, 0, 0, 0, 3, D("void(string err,...)", "For some reason this has been redefined as non-fatal, and as it won't force the user to look at the console it'll generally be ignored completely so really what's the point? Other than as a convoluted way to remove(self) that is.")}, {"print", PF_Fixme, 0, 0, 0, 4, D("void(string text,...)", "Hello, world. Shoves junk on the console. Hopefully people will bother to read it, maybe.")}, - {"bprint", PF_Fixme, 0, 0, 0, 5, "void(string text,...)"}, - {"msprint", PF_Fixme, 0, 0, 0, 6, "void(float clientnum, string text,...)"}, + {"bprint", PF_Fixme, 0, 0, 0, 5, "DEP void(string text,...)"}, + {"msprint", PF_Fixme, 0, 0, 0, 6, "DEP void(float clientnum, string text,...)"}, {"cprint", PF_Fixme, 0, 0, 0, 7, D("void(string text,...)", "Tries to show the given message in the centre of the screen, assuming that its not obscured by menus. Oh hey look, you're calling it in menuqc!")}, {"normalize", PF_Fixme, 0, 0, 0, 8, "vector(vector)"}, {"vlen", PF_Fixme, 0, 0, 0, 9, "float(vector)"}, @@ -10493,8 +10512,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"strcat", PF_Fixme, 0, 0, 0, 53, "string(string, optional string, optional string, optional string, optional string, optional string, optional string, optional string)"}, {"substring", PF_Fixme, 0, 0, 0, 54, "string(string s, float start, float length)"}, {"stov", PF_Fixme, 0, 0, 0, 55, "vector(string)"}, - {"strzone", PF_Fixme, 0, 0, 0, 56, D("string(string)", "Exists in FTE for compat only, no different from strcat.")}, - {"strunzone", PF_Fixme, 0, 0, 0, 57, D("void(string)", "Exists in FTE for compat only, does nothing.")}, + {"strzone", PF_Fixme, 0, 0, 0, 56, D("FTEDEP(\"Redundant\") string(string)", "Exists in FTE for compat only, no different from strcat.")}, + {"strunzone", PF_Fixme, 0, 0, 0, 57, D("FTEDEP(\"Redundant\") void(string)", "Exists in FTE for compat only, does nothing.")}, {"tokenize", PF_Fixme, 0, 0, 0, 58, D("float(string)", "Splits up the given string into its different components (what constitutes a token separator is not well defined and has been hacked about with over the years so have fun with that), returning the number of tokens that were found. Call argv(0 through ret-1) to retrieve each individual token. Take care to not use this recursively.")}, {"argv", PF_Fixme, 0, 0, 0, 59, D("string(float)", "Returns one of the tokens found via tokenize (and equivelent builtins).")}, {"isserver", PF_Fixme, 0, 0, 0, 60, D("float()", "Returns true if the local engine is running a server, and thus cvars and localcmds are shared with said server.")}, @@ -10518,11 +10537,11 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"etof", PF_Fixme, 0, 0, 0, 79, "float(entity)"}, {"ftoe", PF_Fixme, 0, 0, 0, 80, "entity(float)"}, {"validstring", PF_Fixme, 0, 0, 0, 81, D("float(string)", "Returns true if str isn't null. In case 'if [not](str)' was configured to test for empty instead of null.")}, - {"altstr_count", PF_Fixme, 0, 0, 0, 82, D("float(string str)", "Reports how many single-quotes there were in the string, divided by 2.")}, - {"altstr_prepare", PF_Fixme, 0, 0, 0, 83, D("string(string str)", "Adds markup to escape only single-quotes. Does not add any.")}, - {"altstr_get", PF_Fixme, 0, 0, 0, 84, D("string(string str, float num)", "Gets the Nth single-quoted token in the input.")}, - {"altstr_set", PF_Fixme, 0, 0, 0, 85, D("string(string str, float num, string setval)", "Changes the Nth single-quoted token. The setval argument must not contain any single-quotes (use altstr_prepare to ensure this).")}, - {"altstr_ins", PF_Fixme, 0, 0, 0, 86, D("string(string str, float num, string set)", NULL), true}, + {"altstr_count", PF_Fixme, 0, 0, 0, 82, D("DEP float(string str)", "Reports how many single-quotes there were in the string, divided by 2.")}, + {"altstr_prepare", PF_Fixme, 0, 0, 0, 83, D("DEP string(string str)", "Adds markup to escape only single-quotes. Does not add any.")}, + {"altstr_get", PF_Fixme, 0, 0, 0, 84, D("DEP string(string str, float num)", "Gets the Nth single-quoted token in the input.")}, + {"altstr_set", PF_Fixme, 0, 0, 0, 85, D("DEP string(string str, float num, string setval)", "Changes the Nth single-quoted token. The setval argument must not contain any single-quotes (use altstr_prepare to ensure this).")}, + {"altstr_ins", PF_Fixme, 0, 0, 0, 86, D("DEP string(string str, float num, string set)", NULL), true}, {"findflags", PF_Fixme, 0, 0, 0, 87, "entity(entity start, .float field, float match)"}, {"findchainflags", PF_Fixme, 0, 0, 0, 88, "entity(.float field, float match)"}, {"cvar_defstring", PF_Fixme, 0, 0, 0, 89, "string(string name)"}, @@ -10538,7 +10557,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"setorigin", PF_setorigin, 2, 2, 2, 0, D("void(entity e, vector o)","Changes e's origin to be equal to o. Also relinks collision state (as well as setting absmin+absmax), which is required after changing .solid")}, {"setmodel", PF_setmodel, 3, 3, 3, 0, D("void(entity e, string m)","Looks up m in the model precache list, and sets both e.model and e.modelindex to match. BSP models will set e.mins and e.maxs accordingly, other models depend upon the value of sv_gameplayfix_setmodelrealbox - for compatibility you should always call setsize after all pickups or non-bsp models. Also relinks collision state.")}, {"setsize", PF_setsize, 4, 4, 4, 0, D("void(entity e, vector min, vector max)", "Sets the e's mins and maxs fields. Also relinks collision state, which sets absmin and absmax too.")}, - {"qtest_setabssize",PF_setsize, 5, 0, 0, 0, D("void(entity e, vector min, vector max)", "qtest"), true}, + {"qtest_setabssize",PF_setsize, 5, 0, 0, 0, D("DEP void(entity e, vector min, vector max)", "qtest"), true}, {"breakpoint", PF_break, 6, 6, 6, 0, D("void()", "Trigger a debugging event. FTE will break into the qc debugger. Other engines may crash with a debug execption.")}, {"random", PF_random, 7, 7, 7, 0, D("float()", "Returns a random value between 0 and 1. Be warned, this builtin can return 1 in most engines, which can break arrays.")}, {"sound", PF_sound, 8, 8, 8, 0, D("void(entity e, float chan, string samp, float vol, float atten, optional float speedpct, optional float flags, optional float timeofs)", "Starts a sound centered upon the given entity.\nchan is the entity sound channel to use, channel 0 will allow you to mix many samples at once, others will replace the old sample\n'samp' must have been precached first\nif specified, 'speedpct' should normally be around 100 (or =0), 200 for double speed or 50 for half speed.\nIf flags is specified, the reliable flag in the channels argument is used for additional channels. Flags should be made from SOUNDFLAG_* constants\ntimeofs should be negative in order to provide a delay before the sound actually starts.")}, @@ -10585,7 +10604,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"rint", PF_rint, 36, 36, 36, 0, D("float(float)", "Rounds the given float up or down to the closest integeral value. X.5 rounds away from 0")}, {"floor", PF_floor, 37, 37, 37, 0, D("float(float)", "Rounds the given float downwards, even when negative.")}, {"ceil", PF_ceil, 38, 38, 38, 0, D("float(float)", "Rounds the given float upwards, even when negative.")}, - {"qtest_canreach", PF_Ignore, 39, 0, 0, 0, "float(vector v)"}, // QTest builtin called in effectless statement + {"qtest_canreach", PF_Ignore, 39, 0, 0, 0, "DEP float(vector v)"}, // QTest builtin called in effectless statement {"checkbottom", PF_checkbottom, 40, 40, 40, 0, D("float(entity ent)", "Expensive checks to ensure that the entity is actually sitting on something solid, returns true if it is.")}, {"pointcontents", PF_pointcontents, 41, 41, 41, 0, D("float(vector pos)", "Checks the given point to see what is there. Returns one of the SOLID_* constants. Just because a spot is empty does not mean that the player can stand there due to the size of the player - use tracebox for such tests.")}, // {"qtest_stopsound", NULL, 42}, // defined QTest builtin that is never called @@ -10656,20 +10675,20 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"logfrag", PF_logfrag, 0, 79, 0, 79, "void(entity killer, entity killee)"}, //79 // Tomaz - QuakeC String Manipulation Begin - {"tq_zone", PF_strzone, 0, 0, 0, 79, D("string(string s)",NULL), true}, //79 - {"tq_unzone", PF_strunzone, 0, 0, 0, 80, D("void(string s)",NULL), true}, //80 - {"tq_stof", PF_stof, 0, 0, 0, 81, D("float(string s)",NULL), true}, //81 - {"tq_strcat", PF_strcat, 0, 0, 0, 82, D("string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true}, //82 - {"tq_substring", PF_substring, 0, 0, 0, 83, D("string(string str, float start, float len)",NULL), true}, //83 - {"tq_stof", PF_stof, 0, 0, 0, 84, D("float(string s)",NULL), true}, //84 - {"tq_stov", PF_stov, 0, 0, 0, 85, D("vector(string s)",NULL), true}, //85 + {"tq_zone", PF_strzone, 0, 0, 0, 79, D("DEP string(string s)",NULL), true}, //79 + {"tq_unzone", PF_strunzone, 0, 0, 0, 80, D("DEP void(string s)",NULL), true}, //80 + {"tq_stof", PF_stof, 0, 0, 0, 81, D("DEP float(string s)",NULL), true}, //81 + {"tq_strcat", PF_strcat, 0, 0, 0, 82, D("DEP string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true}, //82 + {"tq_substring", PF_substring, 0, 0, 0, 83, D("DEP string(string str, float start, float len)",NULL), true}, //83 + {"tq_stof", PF_stof, 0, 0, 0, 84, D("DEP float(string s)",NULL), true}, //84 + {"tq_stov", PF_stov, 0, 0, 0, 85, D("DEP vector(string s)",NULL), true}, //85 // Tomaz - QuakeC String Manipulation End // Tomaz - QuakeC File System Begin (new mods use frik_file instead) - {"tq_fopen", PF_fopen, 0, 0, 0, 86, D("filestream(string filename, float mode)",NULL), true},// (QSG_FILE) - {"tq_fclose", PF_fclose, 0, 0, 0, 87, D("void(filestream fhandle)",NULL), true},// (QSG_FILE) - {"tq_fgets", PF_fgets, 0, 0, 0, 88, D("string(filestream fhandle)",NULL), true},// (QSG_FILE) - {"tq_fputs", PF_fputs, 0, 0, 0, 89, D("void(filestream fhandle, string s)",NULL), true},// (QSG_FILE) + {"tq_fopen", PF_fopen, 0, 0, 0, 86, D("DEP filestream(string filename, float mode)",NULL), true},// (QSG_FILE) + {"tq_fclose", PF_fclose, 0, 0, 0, 87, D("DEP void(filestream fhandle)",NULL), true},// (QSG_FILE) + {"tq_fgets", PF_fgets, 0, 0, 0, 88, D("DEP string(filestream fhandle)",NULL), true},// (QSG_FILE) + {"tq_fputs", PF_fputs, 0, 0, 0, 89, D("DEP void(filestream fhandle, string s)",NULL), true},// (QSG_FILE) // Tomaz - QuakeC File System End {"infokey", PF_infokey_s, 0, 80, 0, 80, D("string(entity e, string key)", "If e is world, returns the field 'key' from either the serverinfo or the localinfo. If e is a player, returns the value of 'key' from the player's userinfo string. There are a few special exceptions, like 'ip' which is not technically part of the userinfo.")}, //80 @@ -10681,36 +10700,36 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs #ifdef HAVE_LEGACY //mvdsv (don't require ebfs usage in qw) - {"executecommand", PF_ExecuteCommand, 0, 0, 0, 83, D("void()","Attempt to flush the localcmd buffer NOW. This is unsafe, as many events might cause the map to be purged while still executing qc code."), true}, - {"mvdtokenize", PF_tokenize_console,0, 0, 0, 84, D("void(string str)",NULL), true}, - {"mvdargc", PF_ArgC, 0, 0, 0, 85, D("float()",NULL), true}, - {"mvdargv", PF_ArgV, 0, 0, 0, 86, D("string(float num)",NULL), true}, + {"executecommand", PF_ExecuteCommand, 0, 0, 0, 83, D("DEP void()","Attempt to flush the localcmd buffer NOW. This is unsafe, as many events might cause the map to be purged while still executing qc code."), true}, + {"mvdtokenize", PF_tokenize_console,0, 0, 0, 84, D("DEP void(string str)",NULL), true}, + {"mvdargc", PF_ArgC, 0, 0, 0, 85, D("DEP float()",NULL), true}, + {"mvdargv", PF_ArgV, 0, 0, 0, 86, D("DEP string(float num)",NULL), true}, //mvd commands //some of these are a little iffy. //we support them for mvdsv compatability but some of them look very hacky. //these ones are not honoured with numbers, but can be used via the proper means. - {"teamfield", PF_teamfield, 0, 0, 0, 87, D("void(.string teamfield)",NULL), true}, - {"substr", PF_substr, 0, 0, 0, 88, D("string(string str, float start, float len)","Returns the theDoes not work on tempstrings nor zoned strings."), true}, - {"mvdstrcat", PF_strcat, 0, 0, 0, 89, D("string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true}, - {"mvdstrlen", PF_strlen, 0, 0, 0, 90, D("float(string s)",NULL), true}, - {"str2byte", PF_str2byte, 0, 0, 0, 91, D("float(string str)","Returns the value of the first byte of the given string."), true}, - {"str2short", PF_str2short, 0, 0, 0, 92, D("float(string str)","Returns the value of the first two bytes of the given string, treated as a short."), true}, - {"mvdnewstr", PF_mvdsv_newstring, 0, 0, 0, 93, D("string(string s, optional float bufsize)","Allocs a copy of the string. If bufsize is longer than the string then there will be extra space available on the end. The resulting string can then be modified freely."), true}, - {"mvdfreestr", PF_mvdsv_freestring,0, 0, 0, 94, D("void(string s)","Frees memory allocated by mvdnewstr."), true}, - {"conprint", PF_conprint, 0, 0, 0, 95, D("void(string s, ...)","Prints the string(s) onto the local console, bypassing redirects."), true}, - {"readcmd", PF_readcmd, 0, 0, 0, 0/*96*/, D("string(string str)","Executes the given command NOW. This is unsafe, as many events might cause the map to be purged while still executing qc code, so be careful about the commands you try reading, and avoid aliases."), true}, - {"mvdstrcpy", PF_MVDSV_strcpy, 0, 0, 0, 97, D("void(string dst, string src)",NULL), true}, - {"strstr", PF_strstr, 0, 0, 0, 98, D("string(string str, string sub)",NULL), true}, - {"mvdstrncpy", PF_MVDSV_strncpy, 0, 0, 0, 99, D("void(string dst, string src, float count)",NULL), true}, - {"logtext", PF_logtext, 0, 0, 0, 100, D("void(string name, float console, string text)",NULL), true}, - {"mvdcalltimeofday",PF_calltimeofday, 0, 0, 0, 102, D("void()",NULL), true}, + {"teamfield", PF_teamfield, 0, 0, 0, 87, D("DEP void(.string teamfield)",NULL), true}, + {"substr", PF_substr, 0, 0, 0, 88, D("DEP string(string str, float start, float len)","Returns the theDoes not work on tempstrings nor zoned strings."), true}, + {"mvdstrcat", PF_strcat, 0, 0, 0, 89, D("DEP string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)",NULL), true}, + {"mvdstrlen", PF_strlen, 0, 0, 0, 90, D("DEP float(string s)",NULL), true}, + {"str2byte", PF_str2byte, 0, 0, 0, 91, D("DEP float(string str)","Returns the value of the first byte of the given string."), true}, + {"str2short", PF_str2short, 0, 0, 0, 92, D("DEP float(string str)","Returns the value of the first two bytes of the given string, treated as a short."), true}, + {"mvdnewstr", PF_mvdsv_newstring, 0, 0, 0, 93, D("DEP string(string s, optional float bufsize)","Allocs a copy of the string. If bufsize is longer than the string then there will be extra space available on the end. The resulting string can then be modified freely."), true}, + {"mvdfreestr", PF_mvdsv_freestring,0, 0, 0, 94, D("DEP void(string s)","Frees memory allocated by mvdnewstr."), true}, + {"conprint", PF_conprint, 0, 0, 0, 95, D("DEP void(string s, ...)","Prints the string(s) onto the local console, bypassing redirects."), true}, + {"readcmd", PF_readcmd, 0, 0, 0, 0/*96*/, D("DEP string(string str)","Executes the given command NOW. This is unsafe, as many events might cause the map to be purged while still executing qc code, so be careful about the commands you try reading, and avoid aliases."), true}, + {"mvdstrcpy", PF_MVDSV_strcpy, 0, 0, 0, 97, D("DEP void(string dst, string src)",NULL), true}, + {"strstr", PF_strstr, 0, 0, 0, 98, D("DEP string(string str, string sub)",NULL), true}, + {"mvdstrncpy", PF_MVDSV_strncpy, 0, 0, 0, 99, D("DEP void(string dst, string src, float count)",NULL), true}, + {"logtext", PF_logtext, 0, 0, 0, 100, D("DEP void(string name, float console, string text)",NULL), true}, + {"mvdcalltimeofday",PF_calltimeofday, 0, 0, 0, 102, D("__deprecated(\"Use strftime\") void()",NULL), true}, #ifdef MVD_RECORDING - {"forcedemoframe", PF_forcedemoframe, 0, 0, 0, 103, D("void(float now)",NULL), true}, + {"forcedemoframe", PF_forcedemoframe, 0, 0, 0, 103, D("DEP void(float now)",NULL), true}, #endif //end of mvdsv #endif - {"redirectcmd", PF_redirectcmd, 0, 0, 0, 101, D("void(entity to, string str)","Executes a single console command, and sends the text generated by it to the specified player. The command will be executed at the end of the frame once QC is no longer running - you may wish to pre/postfix it with 'echo'.")}, + {"redirectcmd", PF_redirectcmd, 0, 0, 0, 101, D("DEP void(entity to, string str)","Executes a single console command, and sends the text generated by it to the specified player. The command will be executed at the end of the frame once QC is no longer running - you may wish to pre/postfix it with 'echo'.")}, {"getlightstyle", PF_getlightstyle, 0, 0, 0, 0, D("string(float style, optional __out vector rgb)", "Obtains the light style string for the given style.")}, {"getlightstylergb",PF_getlightstylergb,0, 0, 0, 0, D("vector(float style)", "Obtains the current rgb value of the specified light style. In csqc, this is correct with regard to the current frame, while ssqc gives no guarentees about time and ignores client cvars. Note: use getlight if you want the actual light value at a point.")}, @@ -10769,7 +10788,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"bound", PF_bound, 0, 0, 0, 96, D("float(float minimum, float val, float maximum)", "Returns val, unless minimum is higher, or maximum is less.")},// (DP_QC_MINMAXBOUND) {"pow", PF_pow, 0, 0, 0, 97, "float(float value, float exp)"}, {"logarithm", PF_Logarithm, 0, 0, 0, 0, D("float(float v, optional float base)", "Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by.")}, - {"tj_cvar_string", PF_cvar_string, 0, 0, 0, 97, D("string(string cvarname)",NULL), true}, //telejano + {"tj_cvar_string", PF_cvar_string, 0, 0, 0, 97, D("DEP string(string cvarname)",NULL), true}, //telejano //DP_QC_FINDFLOAT {"findfloat", PF_FindFloat, 0, 0, 0, 98, D("#define findentity findfloat\nentity(entity start, .__variant fld, __variant match)", "Equivelent to the find builtin, but instead of comparing strings contents, this builtin compares the raw values. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value.\nworld is returned when there are no more entities.")}, // #98 (DP_QC_FINDFLOAT) @@ -10777,17 +10796,17 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"checkbuiltin", PF_checkbuiltin, 0, 0, 0, 0, D("float(__variant funcref)", "Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. Warning, if two different engines map different builtins to the same number, then this function will not tell you which will be called, only that it won't crash (the exception being #0, which are remapped as available).")}, {"builtin_find", PF_builtinsupported,100, 100, 0, 100, D("float(string builtinname)", "Looks to see if the named builtin is valid, and returns the builtin number it exists at.")}, // #100 //per builtin system. {"anglemod", PF_anglemod, 0, 0, 0, 102, "float(float value)"}, - {"qsg_cvar_string", PF_cvar_string, 0, 0, 0, 103, D("string(string cvarname)","An old/legacy equivelent of more recent/common builtins in order to read a cvar's string value."), true}, + {"qsg_cvar_string", PF_cvar_string, 0, 0, 0, 103, D("DEP string(string cvarname)","An old/legacy equivelent of more recent/common builtins in order to read a cvar's string value."), true}, //TEI_SHOWLMP2 - {"showpic", PF_ShowPic, 0, 0, 0, 104, "void(string slot, string picname, float x, float y, float zone, optional entity player)"}, - {"hidepic", PF_HidePic, 0, 0, 0, 105, "void(string slot, optional entity player)"}, - {"movepic", PF_MovePic, 0, 0, 0, 106, "void(string slot, float x, float y, float zone, optional entity player)"}, - {"changepic", PF_ChangePic, 0, 0, 0, 107, "void(string slot, string picname, optional entity player)"}, - {"showpicent", PF_ShowPic, 0, 0, 0, 108, D("void(string slot, entity player)",NULL), true}, - {"hidepicent", PF_HidePic, 0, 0, 0, 109, D("void(string slot, entity player)",NULL), true}, -// {"movepicent", PF_MovePic, 0, 0, 0, 110, "void(string slot, float x, float y, float zone, entity player)", true}, -// {"changepicent", PF_ChangePic, 0, 0, 0, 111, "void(string slot, string picname, entity player)", true}, + {"showpic", PF_ShowPic, 0, 0, 0, 104, "DEP_CSQC void(string slot, string picname, float x, float y, float zone, optional entity player)"}, + {"hidepic", PF_HidePic, 0, 0, 0, 105, "DEP_CSQC void(string slot, optional entity player)"}, + {"movepic", PF_MovePic, 0, 0, 0, 106, "DEP_CSQC void(string slot, float x, float y, float zone, optional entity player)"}, + {"changepic", PF_ChangePic, 0, 0, 0, 107, "DEP_CSQC void(string slot, string picname, optional entity player)"}, + {"showpicent", PF_ShowPic, 0, 0, 0, 108, D("DEP_CSQC void(string slot, entity player)",NULL), true}, + {"hidepicent", PF_HidePic, 0, 0, 0, 109, D("DEP_CSQC void(string slot, entity player)",NULL), true}, +// {"movepicent", PF_MovePic, 0, 0, 0, 110, "DEP_CSQC void(string slot, float x, float y, float zone, entity player)", true}, +// {"changepicent", PF_ChangePic, 0, 0, 0, 111, "DEP_CSQC void(string slot, string picname, entity player)", true}, //End TEU_SHOWLMP2 //frik file @@ -10804,8 +10823,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"substring", PF_substring, 0, 0, 0, 116, "string(string s, float start, float length)"}, // (FRIK_FILE) {"stov", PF_stov, 0, 0, 0, 117, "vector(string s)"}, // (FRIK_FILE) #ifdef QCGC - {"strzone", PF_strzone, 0, 0, 0, 118, D("string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods.")}, // (FRIK_FILE) - {"strunzone", PF_strunzone, 0, 0, 0, 119, D("void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing.")}, // (FRIK_FILE) + {"strzone", PF_strzone, 0, 0, 0, 118, D("FTEDEP(\"Redundant\") string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods.")}, // (FRIK_FILE) + {"strunzone", PF_strunzone, 0, 0, 0, 119, D("FTEDEP(\"Redundant\") void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing.")}, // (FRIK_FILE) #else {"strzone", PF_strzone, 0, 0, 0, 118, D("string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope).")}, // (FRIK_FILE) {"strunzone", PF_strunzone, 0, 0, 0, 119, D("void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game.")}, // (FRIK_FILE) @@ -10830,7 +10849,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"addprogs", PF_addprogs, 0, 0, 0, 202, D("float(string progsname)", "Loads an additional .dat file into the current qcvm. The returned handle can be used with any of the externcall/externset/externvalue builtins.\nThere are cvars that allow progs to be loaded automatically.")}, {"externvalue", PF_externvalue, 0, 0, 0, 203, D("__variant(float prnum, string varname)", "Reads a global in the named progs by the name of that global.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")}, {"externset", PF_externset, 0, 0, 0, 204, D("void(float prnum, __variant newval, string varname)", "Sets a global in the named progs by name.\nprnum=0 is the 'default' or 'main' progs.\nprnum=-1 means current progs.\nprnum=-2 will scan through the active progs and will use the first it finds.")}, - {"externrefcall", PF_externrefcall, 0, 0, 0, 205, D("__variant(float prnum, void() func, ...)","Calls a function between progs by its reference. No longer needed as direct function calls now switch progs context automatically, and have done for a long time. There is no remaining merit for this function."), true}, + {"externrefcall", PF_externrefcall, 0, 0, 0, 205, D("__deprecated(\"Redundant\") __variant(float prnum, void() func, ...)","Calls a function between progs by its reference. No longer needed as direct function calls now switch progs context automatically, and have done for a long time. There is no remaining merit for this function."), true}, {"instr", PF_instr, 0, 0, 0, 206, D("float(string input, string token)", "Returns substring(input, strstrpos(input, token), -1), or the null string if token was not found in input. You're probably better off using strstrpos."), true}, {"openportal", PF_OpenPortal, 0, 0, 0, 207, D("void(entity portal, float state)", "Opens or closes the portals associated with a door or some such on q2 or q3 maps. On Q2BSPs, the entity should be the 'func_areaportal' entity - its style field will say which portal to open. On Q3BSPs, the entity is the door itself, the portal will be determined by the two areas found from a preceding setorigin call.")}, @@ -10875,7 +10894,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"strtrim", PF_strtrim, 0, 0, 0, 0, D("string(string s)", "Trims the whitespace from the start+end of the string.")}, //FTE_CALLTIMEOFDAY - {"calltimeofday", PF_calltimeofday, 0, 0, 0, 231, D("void()", "Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv.\ntimeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue)\nThe strftime builtin is more versatile and less weird.")}, + {"calltimeofday", PF_calltimeofday, 0, 0, 0, 231, D("__deprecated(\"Use strftime.\") void()", "Asks the engine to instantly call the qc's 'timeofday' function, before returning. For compatibility with mvdsv.\ntimeofday should have the prototype: void(float secs, float mins, float hour, float day, float mon, float year, string strvalue)\nThe strftime builtin is more versatile and less weird.")}, //EXT_CSQC {"clientstat", PF_clientstat, 0, 0, 0, 232, D("void(float num, float type, .__variant fld)", "Specifies what data to use in order to send various stats, in a client-specific way.\n'num' should be a value between 32 and 127, other values are reserved.\n'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY.\nfld must be a reference to the field used, each player will be sent only their own copy of these fields.")}, //EXT_CSQC @@ -11052,6 +11071,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"r_readimage", PF_Fixme, 0, 0, 0, 0, D("int*(string filename, __out int width, __out int height)", "Reads and decodes an image from disk, providing raw R8G8B8A8 pixel data. Should not be used for dds or ktx etc formats. Returns __NULL__ if the image could not be read for any reason. Use memfree to free the data once you're done with it.")}, {"drawgetimagesize",PF_Fixme, 0, 0, 0, 318, D("#define draw_getimagesize drawgetimagesize\nvector(string picname)", "Returns the dimensions of the named image. Images specified with .lmp should give the original .lmp's dimensions even if texture replacements use a different resolution. WARNING: this function may be slow if used without or directly after its initial precache_pic.")},// (EXT_CSQC) {"freepic", PF_Fixme, 0, 0, 0, 319, D("void(string name)", "Tells the engine that the image is no longer needed. The image will appear to be new the next time its needed.")},// (EXT_CSQC) + {"spriteframe", PF_Fixme, 0, 0, 0, 0, D("string(string modelname, int frame, float frametime)", "Obtains a suitable shader name to draw a sprite's shader via drawpic/R_BeginPolygon/etc, instead of needing to create a scene.")}, //320 {"drawcharacter", PF_Fixme, 0, 0, 0, 320, D("float(vector position, float character, vector size, vector rgb, float alpha, optional float drawflag)", "Draw the given quake character at the given position.\nIf flag&4, the function will consider the char to be a unicode char instead (or display as a ? if outside the 32-127 range).\nsize should normally be something like '8 8 0'.\nrgb should normally be '1 1 1'\nalpha normally 1.\nSoftware engines may assume the named defaults.\nNote that ALL text may be rescaled on the X axis due to variable width fonts. The X axis may even be ignored completely.")},// (EXT_CSQC, [EXT_CSQC_???]) {"drawrawstring", PF_Fixme, 0, 0, 0, 321, D("float(vector position, string text, vector size, vector rgb, float alpha, optional float drawflag)", "Draws the specified string without using any markup at all, even in engines that support it.\nIf UTF-8 is globally enabled in the engine, then that encoding is used (without additional markup), otherwise it is raw quake chars.\nSoftware engines may assume a size of '8 8 0', rgb='1 1 1', alpha=1, flag&3=0, but it is not an error to draw out of the screen.")},// (EXT_CSQC, [EXT_CSQC_???]) @@ -11086,9 +11106,9 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"keynumtostring", PF_Fixme, 0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (EXT_CSQC) - {"keynumtostring_csqc",PF_Fixme,0, 0, 0, 340, D("string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (found in menuqc) + {"keynumtostring_csqc",PF_Fixme,0, 0, 0, 340, D("DEP string(float keynum)", "Returns a hunam-readable name for the given keycode, as a tempstring.")},// (found in menuqc) {"stringtokeynum", PF_Fixme, 0, 0, 0, 341, D("float(string keyname)", "Looks up the key name in the same way that the bind command would, returning the keycode for that key.")},// (EXT_CSQC) - {"stringtokeynum_csqc", PF_Fixme,0, 0, 0, 341, D("float(string keyname)", "Looks up the key name in the same way that the bind command would, returning the keycode for that key.")},// (found in menuqc) + {"stringtokeynum_csqc", PF_Fixme,0, 0, 0, 341, D("DEP float(string keyname)", "Looks up the key name in the same way that the bind command would, returning the keycode for that key.")},// (found in menuqc) {"getkeybind", PF_Fixme, 0, 0, 0, 342, D("string(float keynum)", "Returns the current binding for the given key (returning only the command executed when no modifiers are pressed).")},// (EXT_CSQC) {"setcursormode", PF_Fixme, 0, 0, 0, 343, D("void(float usecursor, optional string cursorimage, optional vector hotspot, optional float scale)", "Pass TRUE if you want the engine to release the mouse cursor (absolute input events + touchscreen mode). Pass FALSE if you want the engine to grab the cursor (relative input events + standard looking). If the image name is specified, the engine will use that image for a cursor (use an empty string to clear it again), in a way that will not conflict with the console. Images specified this way will be hardware accelerated, if supported by the platform/port.")}, @@ -11115,7 +11135,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"isserver", PF_Fixme, 0, 0, 0, 350, D("float()", "Returns non-zero whenever the local console can directly affect the server (ie: listen servers or single-player). Compat note: DP returns 0 for single-player.")},//(EXT_CSQC) {"SetListener", PF_Fixme, 0, 0, 0, 351, D("void(vector origin, vector forward, vector right, vector up, optional float reverbtype)", "Sets the position of the view, as far as the audio subsystem is concerned. This should be called once per CSQC_UpdateView as it will otherwise revert to default. For reverbtype, see setup_reverb or treat as 'underwater'.")},// (EXT_CSQC) {"setup_reverb", PF_Fixme, 0, 0, 0, 0, D("typedef struct {\n\tfloat flDensity;\n\tfloat flDiffusion;\n\tfloat flGain;\n\tfloat flGainHF;\n\tfloat flGainLF;\n\tfloat flDecayTime;\n\tfloat flDecayHFRatio;\n\tfloat flDecayLFRatio;\n\tfloat flReflectionsGain;\n\tfloat flReflectionsDelay;\n\tvector flReflectionsPan;\n\tfloat flLateReverbGain;\n\tfloat flLateReverbDelay;\n\tvector flLateReverbPan;\n\tfloat flEchoTime;\n\tfloat flEchoDepth;\n\tfloat flModulationTime;\n\tfloat flModulationDepth;\n\tfloat flAirAbsorptionGainHF;\n\tfloat flHFReference;\n\tfloat flLFReference;\n\tfloat flRoomRolloffFactor;\n\tint iDecayHFLimit;\n} reverbinfo_t;\nvoid(float reverbslot, reverbinfo_t *reverbinfo, int sizeofreverinfo_t)", "Reconfigures a reverb slot for weird effects. Slot 0 is reserved for no effects. Slot 1 is reserved for underwater effects. Reserved slots will be reinitialised on snd_restart, but can otherwise be changed. These reverb slots can be activated with SetListener. Note that reverb will currently only work when using OpenAL.")}, - {"registercommand", PF_Fixme, 0, 0, 0, 352, D("void(string cmdname)", "Register the given console command, for easy console use.\nConsole commands that are later used will invoke CSQC_ConsoleCommand.")},//(EXT_CSQC) + {"registercommand", PF_sv_registercommand,0,0, 0, 352, D("void(string cmdname)", "Register the given console command, for easy console use.\nConsole commands that are later used will invoke CSQC_ConsoleCommand/m_consolecommand/ConsoleCmd according to module.")},//(EXT_CSQC) {"wasfreed", PF_WasFreed,0, 0, 0, 353, D("float(entity ent)", "Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust.")},//(EXT_CSQC) (should be availabe on server too) {"serverkey", PF_sv_serverkeystring,0,0, 0, 354, D("string(string key)", "Look up a key in the server's public serverinfo string. If the key contains binary data then it will be truncated at the first null.")},// {"serverkeyfloat", PF_sv_serverkeyfloat,0,0, 0, 0, D("float(string key, optional float assumevalue)", "Version of serverkey that returns the value as a float (which avoids tempstrings).")},// @@ -11182,7 +11202,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs //DP_QC_COPYENTITY {"copyentity", PF_copyentity, 0, 0, 0, 400, D("entity(entity from, optional entity to)", "Copies all fields from one entity to another.")},// (DP_QC_COPYENTITY) //DP_SV_SETCOLOR - {"setcolors", PF_setcolors, 0, 0, 0, 401, D("void(entity ent, float colours)", "Changes a player's colours. The bits 0-3 are the lower/trouser colour, bits 4-7 are the upper/shirt colours.")},//DP_SV_SETCOLOR + {"setcolors", PF_setcolors, 0, 0, 0, 401, D("__deprecated(\"No RGB support.\") void(entity ent, float colours)", "Changes a player's colours. The bits 0-3 are the lower/trouser colour, bits 4-7 are the upper/shirt colours.")},//DP_SV_SETCOLOR //DP_QC_FINDCHAIN {"findchain", PF_findchain, 0, 0, 0, 402, "entity(.string field, string match, optional .entity chainfield)"},// (DP_QC_FINDCHAIN) //DP_QC_FINDCHAINFLOAT @@ -11337,7 +11357,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"cin_getstate", PF_Fixme, 0, 0, 0, 0, D("float(string id)", NULL)}, {"cin_restart", PF_Fixme, 0, 0, 0, 0, D("void(string file)", NULL)}, - {"crc16", PF_crc16, 0, 0, 0, 494, "float(float caseinsensitive, string s, ...)"},//DP_QC_CRC16 + {"crc16", PF_crc16, 0, 0, 0, 494, "__deprecated(\"Use digest_hex\") float(float caseinsensitive, string s, ...)"},//DP_QC_CRC16 {"cvar_type", PF_cvar_type, 0, 0, 0, 495, "float(string name)"},//DP_QC_CVAR_TYPE {"numentityfields", PF_numentityfields, 0, 0, 0, 496, D("float()", "Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3).")},//DP_QC_ENTITYDATA {"findentityfield", PF_findentityfield, 0, 0, 0, 0, D("float(string fieldname)", "Find a field index by name.")}, @@ -11367,8 +11387,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"buf_cvarlist", PF_buf_cvarlist, 0, 0, 0, 517, "void(strbuf strbuf, string pattern, string antipattern)"}, {"cvar_description",PF_cvar_description,0, 0, 0, 518, D("string(string cvarname)", "Retrieves the description of a cvar, which might be useful for tooltips or help files. This may still not be useful.")}, {"gettime", PF_gettime, 0, 0, 0, 519, "float(optional float timetype)"}, - {"keynumtostring_omgwtf",PF_Fixme, 0, 0, 0, 520, "string(float keynum)"}, //excessive third version in dp's csqc. - {"findkeysforcommand",PF_Fixme, 0, 0, 0, 521, D("string(string command, optional float bindmap)", "Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE.")}, + {"keynumtostring_omgwtf",PF_Fixme, 0, 0, 0, 520, "DEP string(float keynum)"}, //excessive third version in dp's csqc. + {"findkeysforcommand",PF_Fixme, 0, 0, 0, 521, D("__deprecated(\"Does not support modifiers\") string(string command, optional float bindmap)", "Returns a list of keycodes that perform the given console command in a format that can only be parsed via tokenize (NOT tokenize_console). This only and always returns two values - if only one key is actually bound, -1 will be returned. The bindmap argument is listed for compatibility with dp-specific defs, but is ignored in FTE.")}, {"findkeysforcommandex",PF_Fixme, 0, 0, 0, 0, D("string(string command, optional float bindmap)", "Returns a list of key bindings in keyname format instead of keynums. Use tokenize to parse. This list may contain modifiers. May return large numbers of keys.")}, // {"initparticlespawner",PF_Fixme, 0, 0, 0, 522, D("void(float max_themes)","")}, // {"resetparticle", PF_Fixme, 0, 0, 0, 523, D("void()","")}, @@ -11413,8 +11433,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"writetofile", PF_writetofile, 0, 0, 0, 606, D("void(filestream fh, entity e)", "Writes an entity's fields to the named frik_file file handle.")}, {"isfunction", PF_isfunction, 0, 0, 0, 607, D("float(string s)", "Returns true if the named function exists and can be called with the callfunction builtin.")}, {"getresolution", PF_Fixme, 0, 0, 0, 608, D("vector(float vidmode, optional float forfullscreen)", "Supposed to query the driver for supported video modes. FTE does not query drivers in this way, nor would it trust drivers anyway.")}, - {"keynumtostring_menu",PF_Fixme, 0, 0, 0, 609, "string(float keynum)"}, //third copy of this builtin in dp's csqc. - {"findkeysforcommand_dp",PF_Fixme, 0, 0, 0, 610, "string(string command, optional float bindmap)"}, + {"keynumtostring_menu",PF_Fixme, 0, 0, 0, 609, "DEP string(float keynum)"}, //third copy of this builtin in dp's csqc. + {"findkeysforcommand_dp",PF_Fixme, 0, 0, 0, 610, "DEP string(string command, optional float bindmap)"}, {"keynumtostring", PF_Fixme, 0, 0, 0, 609, D("string(float keynum)", "Converts a qscancode key number into a mostly-human-readable name, matching the bind command.")}, //normal name is for menuqc standard. {"findkeysforcommand",PF_Fixme, 0, 0, 0, 610, "string(string command, optional float bindmap)"}, {"gethostcachevalue",PF_Fixme, 0, 0, 0, 611, "float(float type)"}, @@ -11442,18 +11462,18 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"setkeybind", PF_Fixme, 0, 0, 0, 630, "float(float key, string bind, optional float bindmap, optional float modifier)"}, {"getbindmaps", PF_Fixme, 0, 0, 0, 631, "vector()"}, {"setbindmaps", PF_Fixme, 0, 0, 0, 632, "float(vector bm)"}, - {"crypto_getkeyfp", PF_Fixme, 0, 0, 0, 633, "string(string addr)" STUB}, - {"crypto_getidfp", PF_Fixme, 0, 0, 0, 634, "string(string addr)" STUB}, - {"crypto_getencryptlevel",PF_Fixme, 0, 0, 0, 635, "string(string addr)" STUB}, - {"crypto_getmykeyfp",PF_Fixme, 0, 0, 0, 636, "string(string addr)" STUB}, - {"crypto_getmyidfp",PF_Fixme, 0, 0, 0, 637, "string(float addr)" STUB}, + {"crypto_getkeyfp", PF_Fixme, 0, 0, 0, 633, "DEP string(string addr)" STUB}, + {"crypto_getidfp", PF_Fixme, 0, 0, 0, 634, "DEP string(string addr)" STUB}, + {"crypto_getencryptlevel",PF_Fixme, 0, 0, 0, 635, "DEP string(string addr)" STUB}, + {"crypto_getmykeyfp",PF_Fixme, 0, 0, 0, 636, "DEP string(string addr)" STUB}, + {"crypto_getmyidfp",PF_Fixme, 0, 0, 0, 637, "DEP string(float addr)" STUB}, // {"CL_RotateMoves", PF_Fixme, 0, 0, 0, 638, D("void(vector anglechange)", "Rewrites the input log history to rotate all unacknowledged frames according to the angle delta specified.")}, {"digest_hex", PF_digest_hex, 0, 0, 0, 639, "string(string digest, string data, ...)"}, {"digest_ptr", PF_digest_ptr, 0, 0, 0, 0, D("string(string digest, void *data, int length)", "Calculates the digest of a single contiguous block of memory (including nulls) using the specified hash function.")}, - {"V_CalcRefdef", PF_Fixme, 0, 0, 0, 640, "void(entity e, float flags)" STUB}, - {"crypto_getmyidstatus",PF_Fixme, 0, 0, 0, 641, "float(float i)" STUB}, - {"coverage", PF_Fixme, 0, 0, 0, 642, "void()" STUB}, - {"crypto_getidstatus",PF_Fixme, 0, 0, 0, 643, "float(string addr)" STUB}, + {"V_CalcRefdef", PF_Fixme, 0, 0, 0, 640, "DEP void(entity e, float flags)" STUB}, + {"crypto_getmyidstatus",PF_Fixme, 0, 0, 0, 641, "DEP float(float i)" STUB}, + {"coverage", PF_Fixme, 0, 0, 0, 642, "DEP void()" STUB}, + {"crypto_getidstatus",PF_Fixme, 0, 0, 0, 643, "DEP float(string addr)" STUB}, //end dp extras //wrath extras... @@ -11462,10 +11482,10 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"fremove", PF_fremove, 0, 0, 0, 652, D("float(string fname)", "Deletes the named file - path is relative to data/ subdir, like fopen's FILE_WRITE. Returns 0 on success.")}, {"fexists", PF_fexists, 0, 0, 0, 653, D("float(string fname)", "Use whichpack instead. Returns true if it exists inside the default writable path.")}, {"rmtree", PF_rmtree, 0, 0, 0, 654, D("float(string path)", "Dangerous, but sandboxed to data/")}, - {"walkmovedist", PF_walkmovedist, 0, 0, 0, 655, D("float(float yaw, float dist, optional float settraceglobals)", "Attempt to walk the entity at a given angle for a given distance.\nif settraceglobals is set, the trace_* globals will be set, showing the results of the movement.\nThis function will trigger touch events."), true}, + {"walkmovedist", PF_walkmovedist, 0, 0, 0, 655, D("DEP float(float yaw, float dist, optional float settraceglobals)", "Attempt to walk the entity at a given angle for a given distance.\nif settraceglobals is set, the trace_* globals will be set, showing the results of the movement.\nThis function will trigger touch events."), true}, //end wrath extras - {"getrmqeffectsversion",PF_Ignore, 0, 0, 0, 666, "float()" STUB}, + {"getrmqeffectsversion",PF_Ignore, 0, 0, 0, 666, "DEP float()" STUB}, //don't exceed sizeof(pr_builtin)/sizeof(pr_builtin[0]) (currently 1024) without modifing the size of pr_builtin {NULL} @@ -12176,6 +12196,18 @@ void PR_DumpPlatform_f(void) // {"button15", ".float", QW|NQ}, // {"button16", ".float", QW|NQ}, +#undef comfieldfloatdep +#undef comfieldintdep +#undef comfieldvectordep +#undef comfieldentitydep +#undef comfieldstringdep +#define comfieldfloatdep(name,desc,depreason) {#name, "__deprecated(\""depreason"\") .float", FL, D(desc)}, +#define comfieldintdep(name,desc,depreason) {#name, "__deprecated(\""depreason"\") .int", FL, D(desc)}, +#define comfieldvectordep(name,desc,depreason) {#name, "__deprecated(\""depreason"\") .vector", FL, D(desc)}, +#define comfieldentitydep(name,desc,depreason) {#name, "__deprecated(\""depreason"\") .entity", FL, D(desc)}, +#define comfieldstringdep(name,desc,depreason) {#name, "__deprecated(\""depreason"\") .string", FL, D(desc)}, +//function types can bake their deprecation reason into their type string. + #define comfieldfloat(name,desc) {#name, ".float", FL, D(desc)}, #define comfieldint(name,desc) {#name, ".int", FL, D(desc)}, #define comfieldvector(name,desc) {#name, ".vector", FL, D(desc)}, @@ -12212,7 +12244,7 @@ void PR_DumpPlatform_f(void) {"SV_ShouldPause", "float(float newstatus)", QW|NQ, "Called to give the qc a change to block pause/unpause requests. Return false for the pause request to be ignored. newstatus is 1 if the user is trying to pause the game. For the duration of the call, self will be set to the player who tried to pause, or to world if it was triggered by a server-side event."}, {"SV_RunClientCommand", "void()", QW|NQ, "Called each time a player movement packet was received from a client. Self is set to the player entity which should be updated, while the input_* globals specify the various properties stored within the input packet. The contents of this function should be somewaht identical to the equivelent function in CSQC, or prediction misses will occur. If you're feeling lazy, you can simply call 'runstandardplayerphysics' after modifying the inputs."}, {"SV_AddDebugPolygons", "void()", QW|NQ, "Called each video frame. This is the only place where ssqc is allowed to call the R_BeginPolygon/R_PolygonVertex/R_EndPolygon builtins. This is exclusively for debugging, and will break in anything but single player as it will not be called if the engine is not running both a client and a server."}, - {"SV_PlayerPhysics", "void()", QW|NQ, "Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful."}, + {"SV_PlayerPhysics", "DEP_CSQC void()", QW|NQ, "Compatibility method to tweak player input that does not reliably work with prediction (prediction WILL break). Mods that care about prediction should use SV_RunClientCommand instead. If pr_no_playerphysics is set to 1, this function will never be called, which will either fix prediction or completely break player movement depending on whether the feature was even useful."}, {"EndFrame", "void()", QW|NQ, "Called after non-player entities have been run at the end of the physics frame. Player physics is performed out of order and can/will still occur between EndFrame and BeginFrame."}, {"SV_CheckRejectConnection","string(string addr, string uinfo, string features) ", QW|NQ, "Called to give the mod a chance to ignore connection requests based upon client protocol support or other properties. Use infoget to read the uinfo and features arguments."}, #ifdef HEXEN2 @@ -12262,9 +12294,10 @@ void PR_DumpPlatform_f(void) {"m_shutdown", "void()", MENU}, {"m_draw", "void(vector screensize)", MENU, "Provides the menuqc with a chance to draw. Will be called even if the menu does not have focus, so be sure to avoid that. COMPAT: screensize is not provided in DP."}, {"m_drawloading", "void(vector screensize, float opaque)", MENU, "Additional drawing function to draw loading screens. If opaque is set, then this function must ensure that the entire screen is overdrawn (even if just by a black drawfill)."}, + {"Menu_RendererRestarted", "void(string rendererdescription)", MENU, "Called by the engine after the video was restarted. This serves to notify the MenuQC that any render targets that it may have cached were purged, and will need to be regenerated."}, {"Menu_InputEvent", "float(float evtype, float scanx, float chary, float devid)", MENU, "If present, this is called instead of m_keydown and m_keyup\nCalled whenever a key is pressed, the mouse is moved, etc. evtype will be one of the IE_* constants. The other arguments vary depending on the evtype. Key presses are not guarenteed to have both scan and unichar values set at the same time."}, - {"m_keydown", "void(float scan, float chr)", MENU}, - {"m_keyup", "void(float scan, float chr)", MENU}, + {"m_keydown", "__deprecated(\"Use Menu_InputEvent\") void(float scan, float chr)", MENU}, + {"m_keyup", "__deprecated(\"Use Menu_InputEvent\") void(float scan, float chr)", MENU}, {"m_toggle", "void(float wantmode)", MENU}, {"m_consolecommand", "float(string cmd)", MENU}, @@ -12284,7 +12317,7 @@ void PR_DumpPlatform_f(void) {"TRUE", "const float", ALL, NULL, 1}, {"FALSE", "const float", ALL, "File not found...", 0}, - {"M_PI", "const float", ALL, NULL, M_PI}, + {"M_PI", "const float", ALL, "Mathematica Pi constant.", M_PI}, {"MOVETYPE_NONE", "const float", QW|NQ|CS, NULL, MOVETYPE_NONE}, {"MOVETYPE_WALK", "const float", QW|NQ|CS, NULL, MOVETYPE_WALK}, @@ -12309,8 +12342,8 @@ void PR_DumpPlatform_f(void) {"SOLID_BBOX", "const float", QW|NQ|CS, NULL, SOLID_BBOX}, {"SOLID_SLIDEBOX", "const float", QW|NQ|CS, NULL, SOLID_SLIDEBOX}, {"SOLID_BSP", "const float", QW|NQ|CS, D("Does not collide against other SOLID_BSP entities. Normally paired with MOVETYPE_PUSH."), SOLID_BSP}, - {"SOLID_CORPSE", "const float", QW|NQ|CS, D("Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .solid value to SOLID_BBOX or so, perform the traceline, then revert the player's .solid value."), SOLID_CORPSE}, - {"SOLID_LADDER", "const float", QW|NQ|CS, D("Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead."), SOLID_LADDER}, + {"SOLID_CORPSE", "const float", QW|NQ|CS, D("Non-solid to SOLID_SLIDEBOX or other SOLID_CORPSE entities. For hitscan weapons to hit corpses, change the player's .hitcontentsmaski value to include CONTENTBIT_CORPSE, perform the traceline, then revert the player's .solid value."), SOLID_CORPSE}, + {"SOLID_LADDER", "__deprecated(\"Obsoleted by .skin=CONTENTS_LADDER\") const float", QW|NQ|CS, D("Obsolete and may be removed at some point. Use skin=CONTENT_LADDER and solid_bsp or solid_trigger instead."), SOLID_LADDER}, {"SOLID_PORTAL", "const float", QW|NQ|CS, D("CSG subtraction volume combined with entity transformations on impact."), SOLID_PORTAL}, {"SOLID_BSPTRIGGER", "const float", QW|NQ|CS, D("For complex-shaped trigger volumes, instead of being a pure aabb."), SOLID_BSPTRIGGER}, {"SOLID_PHYSICS_BOX", "const float", QW|NQ|CS, NULL, SOLID_PHYSICS_BOX}, @@ -12396,12 +12429,12 @@ void PR_DumpPlatform_f(void) {"CONTENTBIT_LAVA", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_LAVA)"i"}, {"CONTENTBIT_SLIME", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_SLIME)"i"}, {"CONTENTBIT_WATER", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_WATER)"i"}, - {"CONTENTBIT_FTELADDER", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_LADDER)"i"}, + {"CONTENTBIT_FTELADDER", "const int", QW|NQ|CS, D("Content bit used for .skin=CONTENT_LADDER entities."), 0,STRINGIFY(FTECONTENTS_LADDER)"i"}, {"CONTENTBIT_PLAYERCLIP", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_PLAYERCLIP)"i"}, {"CONTENTBIT_MONSTERCLIP", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_MONSTERCLIP)"i"}, - {"CONTENTBIT_BODY", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_BODY)"i"}, - {"CONTENTBIT_CORPSE", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_CORPSE)"i"}, - {"CONTENTBIT_Q2LADDER", "const int", QW|NQ|CS, D("Content bit specific to q2bsp"), 0,STRINGIFY(Q2CONTENTS_LADDER)"i"}, + {"CONTENTBIT_BODY", "const int", QW|NQ|CS, D("Content bit that indicates collisions against SOLID_BBOX/SOLID_SLIDEBOX entities."), 0,STRINGIFY(FTECONTENTS_BODY)"i"}, + {"CONTENTBIT_CORPSE", "const int", QW|NQ|CS, D("Content bit that indicates collisions against SOLID_CORPSE entities."), 0,STRINGIFY(FTECONTENTS_CORPSE)"i"}, + {"CONTENTBIT_Q2LADDER", "const int", QW|NQ|CS, D("Content bit specific to q2bsp (conflicts with q3bsp contents so use with caution)."), 0,STRINGIFY(Q2CONTENTS_LADDER)"i"}, {"CONTENTBIT_SKY", "const int", QW|NQ|CS, D("Content bit somewhat specific to q1bsp (aliases to NODROP in q3bsp), but you should probably check surfaceflags&SURF_SKY as well for q2+q3bsp too."), 0,STRINGIFY(FTECONTENTS_SKY)"i"}, {"CONTENTBITS_POINTSOLID", "const int", QW|NQ|CS, D("Bits that traceline would normally consider solid"), 0,"CONTENTBIT_SOLID|"STRINGIFY(Q2CONTENTS_WINDOW)"i|CONTENTBIT_BODY"}, {"CONTENTBITS_BOXSOLID", "const int", QW|NQ|CS, D("Bits that tracebox would normally consider solid"), 0,"CONTENTBIT_SOLID|"STRINGIFY(Q2CONTENTS_WINDOW)"i|CONTENTBIT_BODY|CONTENTBIT_PLAYERCLIP"}, @@ -12440,9 +12473,12 @@ void PR_DumpPlatform_f(void) {"SVC_CGAMEPACKET", "const float", QW|NQ, D("Direct ssqc->csqc message. Must only be multicast. The data triggers a CSQC_Parse_Event call in the csqc for the csqc to read the contents. The server *may* insert length information for clients connected via proxies which are not able to cope with custom csqc payloads. This should only ever be used in conjunction with the MSG_MULTICAST destination."), svcfte_cgamepacket}, #ifdef HAVE_LEGACY - {"MSG_BROADCAST", "const float", QW|NQ, D("The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family."), MSG_BROADCAST}, - {"MSG_ONE", "const float", QW|NQ, D("The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client."), MSG_ONE}, - {"MSG_ALL", "const float", QW|NQ, D("The byte(s) will be reliably sent to all players."), MSG_ALL}, + {"MSG_BROADCAST", "const float", NQ, D("The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family."), MSG_BROADCAST}, + {"MSG_ONE", "const float", NQ, D("The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client."), MSG_ONE}, + {"MSG_ALL", "const float", NQ, D("The byte(s) will be reliably sent to all players."), MSG_ALL}, + {"MSG_BROADCAST", "__deprecated(\"Use MSG_MULTICAST+multicast(MULTICAST_*)\") const float", QW, D("The byte(s) will be unreliably sent to all players. MSG_ constants are valid arguments to the Write* builtin family."), MSG_BROADCAST}, + {"MSG_ONE", "__deprecated(\"Use MSG_MULTICAST+multicast(MULTICAST_ONE_R)\") const float", QW, D("The byte(s) will be reliably sent to the player specified in the msg_entity global. WARNING: in quakeworld servers without network preparsing enabled, this can result in illegible server messages (due to individual reliable messages being split between multiple backbuffers/packets). NQ has larger reliable buffers which avoids this issue, but still kicks the client."), MSG_ONE}, + {"MSG_ALL", "__deprecated(\"Use MSG_MULTICAST+multicast(MULTICAST_ALL)\") const float", QW, D("The byte(s) will be reliably sent to all players."), MSG_ALL}, {"MSG_INIT", "const float", QW|NQ, D("The byte(s) will be written into the signon buffer. Clients will see these messages when they connect later. This buffer is only flushed on map changes, so spamming it _WILL_ result in overflows."), MSG_INIT}, #endif {"MSG_MULTICAST", "const float", QW|NQ, D("The byte(s) will be written into the multicast buffer for more selective sending. Messages sent this way will never be split across packets, and using this for csqc-only messages will not break protocol translation."), MSG_MULTICAST}, @@ -12567,7 +12603,7 @@ void PR_DumpPlatform_f(void) {"EF_DIMLIGHT", "const float", QW|NQ|CS, NULL, EF_DIMLIGHT}, {"EF_FLAG1", "const float", QW , NULL, QWEF_FLAG1}, {"EF_FLAG2", "const float", QW , NULL, QWEF_FLAG2}, - {"EF_NODRAW", "const float", NQ|CS, NULL, NQEF_NODRAW}, + {"EF_NODRAW", "const float", NQ|CS, D("Disables drawing of the model. Does NOT work on QW players."), NQEF_NODRAW}, {"EF_ADDITIVE", "const float", QW|NQ|CS, D("The entity will be drawn with an additive blend. This is NOT supported on players in any quakeworld engine."), NQEF_ADDITIVE}, {"EF_BLUE", "const float", QW|NQ|CS, D("A blue glow"), EF_BLUE}, {"EF_RED", "const float", QW|NQ|CS, D("A red glow"), EF_RED}, @@ -12588,15 +12624,15 @@ void PR_DumpPlatform_f(void) {"MF_TRACER3", "const float", QW|NQ|CS, D("AKA: purple vore trail"), EF_MF_TRACER3>>24}, - {"SL_ORG_TL", "const float", QW|NQ, D("Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen"), SL_ORG_TL}, - {"SL_ORG_TR", "const float", QW|NQ, NULL, SL_ORG_TR}, - {"SL_ORG_BL", "const float", QW|NQ, NULL, SL_ORG_BL}, - {"SL_ORG_BR", "const float", QW|NQ, NULL, SL_ORG_BR}, - {"SL_ORG_MM", "const float", QW|NQ, NULL, SL_ORG_MM}, - {"SL_ORG_TM", "const float", QW|NQ, NULL, SL_ORG_TM}, - {"SL_ORG_BM", "const float", QW|NQ, NULL, SL_ORG_BM}, - {"SL_ORG_ML", "const float", QW|NQ, NULL, SL_ORG_ML}, - {"SL_ORG_MR", "const float", QW|NQ, NULL, SL_ORG_MR}, + {"SL_ORG_TL", "DEP_CSQC const float", QW|NQ, D("Used with showpic etc, specifies that the x+y values are relative to the top-left of the screen"), SL_ORG_TL}, + {"SL_ORG_TR", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_TR}, + {"SL_ORG_BL", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_BL}, + {"SL_ORG_BR", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_BR}, + {"SL_ORG_MM", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_MM}, + {"SL_ORG_TM", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_TM}, + {"SL_ORG_BM", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_BM}, + {"SL_ORG_ML", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_ML}, + {"SL_ORG_MR", "DEP_CSQC const float", QW|NQ, NULL, SL_ORG_MR}, {"PFLAGS_NOSHADOW", "const float", QW|NQ|CS, D("Associated RT lights attached will not cast shadows, making them significantly faster to draw."), PFLAGS_NOSHADOW}, {"PFLAGS_CORONA", "const float", QW|NQ|CS, D("Enables support of coronas on the associated rtlights."), PFLAGS_CORONA}, @@ -12957,7 +12993,7 @@ void PR_DumpPlatform_f(void) if ((targ&ALL) == H2) { if (targ&FTE) - VFS_PRINTF(f, "#pragma target FTEH2\n"); + VFS_PRINTF(f, "#pragma target FTEH2\n#define FTEDEP DEP\n"); else VFS_PRINTF(f, "#pragma target H2\n"); } @@ -12965,7 +13001,7 @@ void PR_DumpPlatform_f(void) #endif { if (targ&FTE) - VFS_PRINTF(f, "#pragma target FTE\n"); + VFS_PRINTF(f, "#pragma target FTE\n#define FTEDEP DEP\n"); } if ((targ&ALL) == CS) VFS_PRINTF(f, "#ifndef CSQC\n" @@ -13013,6 +13049,25 @@ void PR_DumpPlatform_f(void) ); + if (targ&(NQ|QW|H2)) + { + VFS_PRINTF(f, "#if defined(CSQC) || defined(MENU)\n" + "#define DEP_CSQC DEP\n" + "#else\n" + "#define DEP_CSQC __deprecated(\"Use CSQC for this\")\n" + "#endif\n" + ); + } + else + VFS_PRINTF(f, "#define DEP_CSQC DEP\n"); + VFS_PRINTF(f, "#ifndef DEP\n" + " #define DEP __deprecated //predefine this if you want to avoid our deprecation warnings.\n" + "#endif\n" + "#ifndef FTEDEP\n" + " #define FTEDEP //for symbols deprecated in FTE that may still be useful/required for other engines\n" + "#endif\n"); + + for (i = 0; i < QSG_Extensions_count; i++) { if (!QSG_Extensions[i].name || *QSG_Extensions[i].name == '?' || *QSG_Extensions[i].name == '_') @@ -13458,6 +13513,9 @@ void PR_DumpPlatform_f(void) "};\n"); VFS_PRINTF(f, "#endif\n"); + VFS_PRINTF(f, "#undef DEP_CSQC\n"); + VFS_PRINTF(f, "#undef FTEDEP\n"); + VFS_PRINTF(f, "#undef DEP\n"); VFS_PRINTF(f, "#pragma noref 0\n"); VFS_CLOSE(f); diff --git a/engine/server/progdefs.h b/engine/server/progdefs.h index 57fbf8f8..761977d5 100644 --- a/engine/server/progdefs.h +++ b/engine/server/progdefs.h @@ -119,8 +119,10 @@ typedef struct nqglobalvars_s #ifndef HAVE_LEGACY #define comfieldfloat_legacy(n,desc) +#define comfieldfloatdep_legacy(n,desc,depreason) #else #define comfieldfloat_legacy comfieldfloat +#define comfieldfloatdep_legacy comfieldfloatdep #endif @@ -237,10 +239,10 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldentity(movechain,"This is a linked list of entities which will be moved whenever this entity moves, logically they are attached to this entity.")/*hexen2*/\ comfieldfunction(chainmoved, ".void()","Called when the entity is moved as a result of being part of another entity's .movechain")/*hexen2*/\ comfieldfunction(contentstransition, ".void(float old, float new)","This function is called when the entity moves between water and air. If specified, default splash sounds will be disabled allowing you to provide your own.")/*ENTITYCONTENTSTRANSITION*/\ - comfieldfloat(dimension_solid,"This is the bitmask of dimensions which the entity is solid within.")/*EXT_DIMENSION_PHYSICS*/\ + comfieldfloat(dimension_solid,"This is the bitmask of dimensions which the entity is solid within. This is not networked, instead csqc traces impacting ssqc entities assumes the ssqc entity to have a dimension_solid of 1.")/*EXT_DIMENSION_PHYSICS*/\ comfieldfloat(dimension_hit,"This is the bitmask of dimensions which the entity will be blocked by. If other.dimension_solid & self.dimension_hit, our traces will impact and not proceed. If its false, the traces will NOT impact, allowing self to pass straight through.")/*EXT_DIMENSION_PHYSICS*/\ /*comfieldfloat_legacy(hitcontentsmask,"Traces performed for this entity will impact against surfaces that match this contents mask.")*/ \ - comfieldint(hitcontentsmaski,"Traces performed for this entity will impact against surfaces that match this contents mask.")\ + comfieldint(hitcontentsmaski,"Traces performed for this entity will impact against surfaces that match this contents mask (CONTENTBITS_* constants).")\ comfieldfloat_legacy(dphitcontentsmask, "Some crappy field that inefficiently requires translating to the native contents flags. Ditch the 'dp', do it properly.")\ comfieldfloat(scale,"Multiplier that resizes the entity. 1 is normal sized, 2 is double sized. scale 0 is remapped to 1. In SSQC, this is limited to 1/16th precision, with a maximum just shy of 16.")/*DP_ENT_SCALE*/\ comfieldfloat(fatness,"How many QuakeUnits to push the entity's verticies along their normals by.")/*FTE_PEXT_FATNESS*/\ @@ -250,13 +252,13 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldfloat(basebone,"The base* frame animations are equivelent to their non-base versions, except that they only affect bone numbers below the 'basebone' value. This means that the base* animation can affect the legs of a skeletal model independantly of the normal animation fields affecting the torso area. For more complex animation than this, use skeletal objects.") /*FTE_QC_BASEFRAME*/\ comfieldfloat(baseframe,"See basebone") /*FTE_QC_BASEFRAME*/\ comfieldfunction(customphysics,".void()", "Called once each physics frame, overriding the entity's .movetype field and associated logic. You'll probably want to use tracebox to move it through the world. Be sure to call .think as appropriate.")\ - comfieldentity(tag_entity,NULL)\ - comfieldfloat(tag_index,NULL)\ + comfieldentity(tag_entity,"Specifies which entity this entity's origin+angles is 'attached' to.")\ + comfieldfloat(tag_index,"Specifies the tag or bone on the parent entity that we're attached to. If this is -1 then the entity is instead a q3-like camera portal, with the tag_entity saying the entity to display for. If tag_entity is world then this is a q3-like portal surface marker with a separate camera (with a tag_entity referring to the portal surface).")\ comfieldfloat(skeletonindex,"This object serves as a container for the skeletal bone states used to override the animation data.") /*FTE_CSQC_SKELETONOBJECTS*/\ comfieldvector(colormod,"Provides a colour tint for the entity (does not affect fullbrights).")\ comfieldvector(glowmod,"Scaler for an entity's fullbright textures.")\ comfieldvector(gravitydir,"Specifies the direction in which gravity acts. Must be normalised. '0 0 0' also means down. Use '0 0 1' if you want the player to be able to run on ceilings.")\ - comfieldfunction(camera_transform,".vector(vector org, vector ang)", "Provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc.")\ + comfieldfunction(camera_transform,".vector(vector org, vector ang)", "A callback that provides portal transform information for portal surfaces attached to this entity. Also used to open up pvs in ssqc.")\ comfieldfloat(pmove_flags,NULL)/*EXT_CSQC_1*/\ comfieldfloat(geomtype,NULL)/*DP_...PHYSICS*/\ comfieldfloat(friction,NULL)/*DP_...PHYSICS*/\ @@ -268,7 +270,7 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldfloat(idealpitch,NULL)/*DP_QC_CHANGEPITCH (inconsistant naming)*/\ comfieldfloat(pitch_speed,NULL)/*DP_QC_CHANGEPITCH*/\ comextqcfieldshexen2 \ - comfieldvector(color,"This affects the colour of realtime lights that were enabled via the pflags field.")/*Hexen2 has a .float color, the warnings should be benign*/ \ + comfieldvector(color,"This affects the colour of realtime lights that were enabled via the pflags field.")/*Hexen2 has a .float color, the warnings should be benign but does mean updated hexen2 mods may need to use color_x for map compat*/ \ comfieldfloat(light_lev,"This is the radius of an entity's light. This is not normally used by the engine, but is used for realtime lights (ones that are enabled with the pflags field).")\ comfieldfloat(style,"Used by the light util to decide how an entity's light should animate. On an entity with pflags set, this also affects realtime lights.")\ comfieldfloat(pflags,"Realtime lighting flags") @@ -289,10 +291,10 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldentity(view2,"defines a second viewpoint, typically displayed in a corner of the screen (also punches open pvs).")/*FTE_PEXT_VIEW2*/\ comfieldvector(movement,"These are the directions that the player is currently trying to move in (ie: which +forward/+moveright/+moveup etc buttons they have held), expressed relative to that player's angles. Order is forward, right, up.")\ comfieldfloat(vw_index,"This acts as a second modelindex, using the same frames etc.")\ - comfieldentity(nodrawtoclient,"This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game.")\ - comfieldentity(drawonlytoclient,"This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game.")\ - comfieldentity(viewmodelforclient,"This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model.")/*DP_ENT_VIEWMODEL*/\ - comfieldentity(exteriormodeltoclient,"This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity.")\ + comfieldentitydep(nodrawtoclient,"This entity will not be sent to the player named by this field. They will be invisible and not emit dlights/particles. Does not work in MVD-recorded game.", "Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.")\ + comfieldentitydep(drawonlytoclient,"This entity will be sent *only* to the player named by this field. To other players they will be invisible and not emit dlights/particles. Does not work in MVD-recorded game.", "Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.")\ + comfieldentitydep(viewmodelforclient,"This entity will be sent only to the player named by this field, and this entity will be attached to the player's view as an additional weapon model.", "Redundant. Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.")/*DP_ENT_VIEWMODEL*/\ + comfieldentitydep(exteriormodeltoclient,"This entity will be invisible to the player named by this field, except in mirrors or mirror-like surfaces, where it will be visible as normal. It may still cast shadows as normal, and generate lights+particles, depending on client settings. Does not affect how other players see the entity.", "Cannot be recorded in MVDs, nor work properly with splitscreen. Use CSQC instead.")\ svextqcfield_clientcamera\ comfieldfloat(glow_size,"Some outdated particle trail thing.")\ comfieldfloat(glow_color,"Some outdated particle trail thing.")\ @@ -301,20 +303,20 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldfloat(emiteffectnum,"This should be set to the result of particleeffectnum, in order to continually spawn particles in the direction that this entity faces.")/*DP_ENT_TRAILEFFECTNUM*/\ /*comfieldfloat(baseframe,"Specifies the current frame(group) to use for the lower (numerically) bones of a skeletal model. The basebone field specifies the bone where the regular frame field takes over.")*/ /*FTESS_QC_BASEFRAME*/\ /*comfieldfloat(basebone,"Specifies the bone at which the baseframe* fields stop being effective.")*/ /*FTE_SSQC_BASEFRAME*/\ - 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*/\ + comfieldfloatdep(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.", "Does not work with MVDs nor splitscreen.")/*EXT_DIMENSION_VISIBLE*/\ + comfieldfloatdep(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.", "Does not work with MVDs nor splitscreen.")/*EXT_DIMENSION_VISIBLE*/\ + comfieldfloatdep(dimension_ghost,"If this entity is visible only within these dimensions, it will become transparent, as if a ghost.", "Does not work with MVDs nor splitscreen.")/*EXT_DIMENSION_GHOST*/\ + comfieldfloatdep(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.", "Does not work with MVDs nor splitscreen.")/*EXT_DIMENSION_GHOST*/\ comfieldfunction(SendEntity, ".float(entity playerent, float changedflags)","Called by the engine whenever an entity needs to be (re)sent to a client's csprogs, either because SendFlags was set or because data was lost. Must write its data to the MSG_ENTITY buffer. Will be called at the engine's leasure.")/*EXT_CSQC*/\ comfieldfloat(SendFlags,"Indicates that something in the entity has been changed, and that it needs to be updated to all players that can see it. The engine will clear it at some point, with the cleared bits appearing in the 'changedflags' argument of the SendEntity method.")/*EXT_CSQC_1 (one of the DP guys came up with it)*/\ - comfieldfloat_legacy(Version,"Obsolete, set a SendFlags bit instead.")/*EXT_CSQC (obsolete)*/\ - comfieldfloat_legacy(clientcolors,NULL)\ + comfieldfloatdep_legacy(Version,"Obsolete", "Use SendFlags instead.")/*EXT_CSQC (obsolete)*/\ + comfieldfloatdep_legacy(clientcolors,NULL, "Doesn't support RGB player colours.")\ comfieldfloat_legacy(viewzoom,NULL)/*DP_VIEWZOOM, stats*/\ comfieldfloat_legacy(items2,NULL) /*added in quake 1.09 (for hipnotic). legacy because of stats*/\ svextqcfieldshexen2 \ comfieldfloat(pvsflags,"Reconfigures when the entity is visible to clients")/*EXT_CSQC_1*/\ comfieldfloat(uniquespawnid,"Incremented by 1 whenever the entity is respawned. Persists across remove calls, for when the two-second grace period is insufficient.")/*FTE_ENT_UNIQUESPAWNID*/\ - comfieldfunction(customizeentityforclient, ".float()","Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see.") + comfieldfunction(customizeentityforclient, "DEP_CSQC .float()","Called just before an entity is sent to a client (non-csqc protocol). This gives you a chance to tailor 'self' according to what 'other' should see.") #ifdef HALFLIFEMODELS #define HALFLIFEMODEL_FIELDS \ @@ -363,6 +365,10 @@ and the extension fields are added on the end and can have extra vm-specific stu comfieldfloat(drawmask, "Matces the bitmask passed to the addentities builtin, to easily submit entities to the renderer. Not otherwise meaningful.") /*So that the qc can specify all rockets at once or all bannanas at once*/ \ comfieldfunction(predraw, ".float()","Called as part of the addentities builtin. Returns one of the PREDRAW_ constants. This gives you a chance to interpolate or animate entities as desired.") /*If present, is called just before it's drawn.*/ + +#define comfieldentitydep(nam,desc,depreason) comfieldentity(nam,desc) +#define comfieldfloatdep(nam,desc,depreason) comfieldfloat(nam,desc) + typedef struct stdentvars_s //standard = standard for qw { #define comfieldfloat(sharedname,desc) float sharedname; diff --git a/engine/server/server.h b/engine/server/server.h index 2301bff2..501b5777 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -739,6 +739,9 @@ typedef struct client_s laggedpacket_t *laggedpacket; laggedpacket_t *laggedpacket_last; + size_t lastseen_count; + float *lastseen_time; //timer for cullentities_trace, so we can get away with fewer traces per test + #ifdef VM_Q1 int hideentity; qboolean hideplayers; diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 944c8244..db86e900 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -827,9 +827,7 @@ void SV_Map_f (void) Cvar_ApplyLatches(CVAR_LATCH); - gametype = Cvar_Get("mapname", "", CVAR_LATCH|CVAR_SERVERINFO, "Q3 compatability"); - gametype->flags |= CVAR_SERVERINFO; - Cvar_ForceSet(gametype, level); + host_mapname.flags |= CVAR_SERVERINFO; gametype = Cvar_Get("g_gametype", "", CVAR_LATCH|CVAR_SERVERINFO, "Q3 compatability"); // gametype->callback = gtcallback; @@ -845,6 +843,8 @@ void SV_Map_f (void) } #endif + Cvar_ForceSet(&host_mapname, level); + #ifdef HAVE_CLIENT Menu_PopAll(); #endif @@ -2538,6 +2538,7 @@ void SV_User_f (void) int clnum=-1; unsigned int u; char buf[256]; + extern cvar_t sv_userinfo_bytelimit, sv_userinfo_keylimit; static const char *pext1names[32] = { "setview", "scale", "lightstylecol", "trans", "view2", "builletens", "accuratetimings", "sounddbl", "fatness", "hlbsp", "bullet", "hullsize", "modeldbl", "entitydbl", "entitydbl2", "floatcoords", "OLD vweap", "q2bsp", "q3bsp", "colormod", "splitscreen", "hexen2", "spawnstatic2", "customtempeffects", @@ -2558,6 +2559,7 @@ void SV_User_f (void) while((cl = SV_GetClientForString(Cmd_Argv(1), &clnum))) { InfoBuf_Print (&cl->userinfo, " "); + Con_Printf("[%u/%i, %u/%i]\n", (unsigned)cl->userinfo.totalsize, sv_userinfo_bytelimit.ival, (unsigned)cl->userinfo.numkeys, sv_userinfo_keylimit.ival); switch(cl->protocol) { case SCP_BAD: diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 8e9c1f21..19c2e940 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -2370,39 +2370,79 @@ void SV_WritePlayerToClient(sizebuf_t *msg, clstate_t *ent) #endif -qboolean Cull_Traceline(pvscamera_t *cameras, edict_t *seen) +qboolean Cull_Traceline(float *timestamp, pvscamera_t *cameras, edict_t *seen) { int i; trace_t tr; - vec3_t end; + vec3_t end, amin, size; int c; if (seen->v->solid == SOLID_BSP) - return false; //bsp ents are never culled this way + return false; //bsp ents are never culled this way (typically far too large to care, often with large parts inside walls) - //stage 1: check against their origin - for (c = 0; c < cameras->numents; c++) + if (timestamp) { - tr.fraction = 1; - if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, NULLFRAMESTATE, NULL, cameras->org[c], seen->v->origin, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) - return false; //wasn't blocked - } + int tests; + float delay; - //stage 2: check against their bbox - for (c = 0; c < cameras->numents; c++) - { - for (i = 0; i < 8; i++) + //temporal cache + //we still need to fire some traces every frame (monte-carlo style), but we don't need to be so desperate as it'll stay visible for a while anyway. + + if (seen->entnum <= sv.allocated_client_slots) + tests = 8, delay = 0.2; + else + tests = 2, delay = 1.0; + + VectorAdd(seen->v->origin, seen->v->mins, amin); + VectorSubtract(seen->v->maxs, seen->v->mins, size); + + 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 < tests; i++) + { + end[0] = amin[0] + frandom()*size[0]; + end[1] = amin[1] + frandom()*size[1]; + end[2] = amin[2] + frandom()*size[2]; + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, NULLFRAMESTATE, NULL, cameras->org[c], end, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) + { + *timestamp = sv.time + delay; + return false; //this trace went through, so don't cull + } + } + } + + if (*timestamp >= sv.time) + return false; + return true; + } + else + { + //stage 1: check against their origin + for (c = 0; c < cameras->numents; c++) + { tr.fraction = 1; - if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, NULLFRAMESTATE, NULL, cameras->org[c], end, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) - return false; //this trace went through, so don't cull + if (!sv.world.worldmodel->funcs.NativeTrace (sv.world.worldmodel, 1, NULLFRAMESTATE, NULL, cameras->org[c], seen->v->origin, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) + return false; //wasn't blocked + } + + //stage 2: check against their bbox + for (c = 0; c < cameras->numents; c++) + { + 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, NULLFRAMESTATE, NULL, cameras->org[c], end, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID, &tr)) + return false; //this trace went through, so don't cull + } } } + //not visible return true; } @@ -2710,7 +2750,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t * if (!((int)clent->xv->dimension_see & ((int)ent->xv->dimension_seen | (int)ent->xv->dimension_ghost))) continue; //not in this dimension - sorry... if (cameras && (sv_cullplayers_trace.value || sv_cullentities_trace.value)) - if (Cull_Traceline(cameras, ent)) + if (Cull_Traceline(NULL, cameras, ent)) continue; } @@ -3622,6 +3662,9 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t limit = e+1; } + if (sv_cullentities_trace.ival && client->lastseen_count < limit) + Z_ReallocElements((void**)&client->lastseen_time, &client->lastseen_count, limit, sizeof(client->lastseen_time)); + for ( ; ev->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(cameras, tracecullent)) + if (Cull_Traceline(e < client->lastseen_count?&client->lastseen_time[e]:NULL, cameras, tracecullent)) continue; } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 705b297b..bed139ed 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -117,7 +117,7 @@ static void QDECL SV_Public_Callback(struct cvar_s *var, char *oldvalue) strtol(name, &e, 0); if (*name&&e==name) //failed to read any number out of it. { - FTENET_AddToCollection(svs.sockets, var->name, va("/%s", name), NA_INVALID, NP_RTC_TLS); + FTENET_AddToCollection(svs.sockets, var->name, va("/%s", (*name == '/')?name+1:name), NA_INVALID, NP_RTC_TLS); var->value = var->ival = 2; //so other stuff sees us as holepunched. } else if (var->ival == 2) @@ -3907,7 +3907,9 @@ qboolean SV_ConnectionlessPacket (void) #ifdef HAVE_DTLS if (net_from.prot == NP_DGRAM && (net_enable_dtls.ival /*|| !*net_enable_dtls.ival*/)) { - if (SV_ChallengePasses(atoi(Cmd_Argv(1)))) + if (*Cmd_Argv(2)) + SV_RejectMessage (SCP_QUAKEWORLD, "Proxying not enabled.\n"); //server would be expected to getchallenge+dtlsconnect the target server (or respond with a no-dtls challenge response...) + else if (SV_ChallengePasses(atoi(Cmd_Argv(1)))) { char *banreason = SV_BannedReason(&net_from); if (banreason) diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 039efd3e..073f0ef1 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2104,30 +2104,34 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) #ifdef HEXEN2 void WPhys_MoveChain(world_t *w, wedict_t *ent, wedict_t *movechain, float *initial_origin, float *initial_angle) { - qboolean callfunc; - if ((callfunc=DotProduct(ent->v->origin, initial_origin)) || DotProduct(ent->v->angles, initial_angle)) + qboolean orgchanged; + vec3_t moveorg, moveang; + VectorSubtract(ent->v->origin, initial_origin, moveorg); + VectorSubtract(ent->v->angles, initial_angle, moveang); + if ((orgchanged=DotProduct(moveorg,moveorg)) || DotProduct(moveang,moveang)) { - vec3_t moveang, moveorg; int i; - VectorSubtract(ent->v->angles, initial_angle, moveang); - VectorSubtract(ent->v->origin, initial_origin, moveorg); - - for(i=16;i && movechain != w->edicts && !ED_ISFREE(movechain);i--, movechain = PROG_TO_WEDICT(w->progs, movechain->xv->movechain)) + for(i=16; i && movechain != w->edicts && !ED_ISFREE(movechain); i--, movechain = PROG_TO_WEDICT(w->progs, movechain->xv->movechain)) { if ((int)movechain->v->flags & FL_MOVECHAIN_ANGLE) VectorAdd(movechain->v->angles, moveang, movechain->v->angles); //FIXME: axial only - VectorAdd(movechain->v->origin, moveorg, movechain->v->origin); - - if (movechain->xv->chainmoved && callfunc) + if (orgchanged) { - *w->g.self = EDICT_TO_PROG(w->progs, movechain); - *w->g.other = EDICT_TO_PROG(w->progs, ent); + VectorAdd(movechain->v->origin, moveorg, movechain->v->origin); + World_LinkEdict(w, movechain, false); + + //chainmoved is called only for origin changes, not angle ones, apparently. + if (movechain->xv->chainmoved) + { + *w->g.self = EDICT_TO_PROG(w->progs, movechain); + *w->g.other = EDICT_TO_PROG(w->progs, ent); #ifdef VM_Q1 - if (svs.gametype == GT_Q1QVM && w == &sv.world) - Q1QVM_ChainMoved(); - else + if (svs.gametype == GT_Q1QVM && w == &sv.world) + Q1QVM_ChainMoved(); + else #endif - PR_ExecuteProgram(w->progs, movechain->xv->chainmoved); + PR_ExecuteProgram(w->progs, movechain->xv->chainmoved); + } } } } @@ -2164,9 +2168,10 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) } else #endif + { if (svs.clients[ent->entnum-1].state < cs_spawned) - return; // unconnected slot - + return; // unconnected slot + } if (svs.clients[ent->entnum-1].protocol == SCP_BAD) svent->v->fixangle = FIXANGLE_NO; //bots never get fixangle cleared otherwise diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index c7b3ce01..a209c6e8 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -710,9 +710,11 @@ static void Friendly_Crash_Handler(int sig, siginfo_t *info, void *vcontext) #if defined(__i386__) //x86 signals don't leave the stack in a clean state, so replace the signal handler with the real crash address, and hide this function - ucontext_t *uc = vcontext; - array[1] = (void*)uc->uc_mcontext.gregs[REG_EIP]; - firstframe = 1; + { + ucontext_t *uc = vcontext; + array[1] = (void*)uc->uc_mcontext.gregs[REG_EIP]; + firstframe = 1; + } #elif defined(__amd64__) //amd64 is sane enough, but this function and the libc signal handler are on the stack, and should be ignored. firstframe = 2; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 8fbc153b..7ed5c77c 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1071,16 +1071,18 @@ void SV_SendClientPrespawnInfo(client_t *client) } else if (client->prespawn_idx == 2) { + static const char *prioritykeys[] = {"*", "fpd", "teamplay", "deathmatch", "maxfps", NULL}; //make sure these are in there. + static const char *ignorekeys[] = {"mapname"/*here for q3, useless for qw*/, NULL}; if (!ISNQCLIENT(client) || (client->fteprotocolextensions2 & PEXT2_PREDINFO)) { //nq does not normally get serverinfo sent to it. - i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, NULL, NULL, &client->infosync, &svs.info); + i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), prioritykeys, ignorekeys, NULL, &client->infosync, &svs.info); Info_SetValueForStarKey(buffer, "*z_ext", va("%i", client->zquake_extensions), sizeof(buffer)); //should already be in there, so this should only ever make it shorter. ClientReliableWrite_Begin(client, svc_stufftext, 20 + i); ClientReliableWrite_String (client, va("fullserverinfo \"%s\"\n", buffer) ); } else if (sv.csqcdebug) { - i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, NULL, NULL, &client->infosync, &svs.info); + i = InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), prioritykeys, ignorekeys, NULL, &client->infosync, &svs.info); ClientReliableWrite_Begin(client, svc_stufftext, 22 + i); ClientReliableWrite_String (client, va("//fullserverinfo \"%s\"\n", buffer) ); } @@ -5130,7 +5132,7 @@ void Cmd_Fly_f (void) } } -#ifdef SUBSERVERS +#if defined(_DEBUG) && defined(SUBSERVERS) void Cmd_SSV_Transfer_f(void) { char *dest = Cmd_Argv(1); @@ -6247,7 +6249,7 @@ ucmd_t ucmds[] = {"fly", Cmd_Fly_f}, {"notarget", Cmd_Notarget_f}, {"setpos", Cmd_SetPos_f}, -#ifdef SUBSERVERS +#if defined(_DEBUG) && defined(SUBSERVERS) {"ssvtransfer", Cmd_SSV_Transfer_f},//transfer the player to a different map/server {"ssvsay", Cmd_SSV_AllSay_f}, //says realm-wide {"ssvjoin", Cmd_SSV_Join_f}, //transfer the player to a different map/server diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 09771247..85a4970b 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -1058,7 +1058,6 @@ qboolean VK_LoadGLSL(program_t *prog, struct programpermu_s *permu, int ver, con if (permu->permutation) //FIXME... return false; - prog->nofixedcompat = false; // prog->supportedpermutations = 0; prog->cvardata = NULL; prog->cvardatasize = 0; @@ -1101,7 +1100,6 @@ qboolean VK_LoadBlob(program_t *prog, void *blobdata, const char *name) prog->vert = vert; prog->frag = frag; - prog->nofixedcompat = true; prog->numsamplers = blob->numtextures; prog->defaulttextures = blob->defaulttextures; prog->supportedpermutations = blob->permutations; diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 7bba345c..d0631413 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -5058,11 +5058,22 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre sh_config.pValidateProgram = NULL; sh_config.pProgAutoFields = NULL; - if (sh_config.texfmt[PTI_DEPTH24]) + if (info->depthbits == 16 && sh_config.texfmt[PTI_DEPTH16]) + vk.depthformat = VK_FORMAT_D16_UNORM; + else if (info->depthbits == 32 && sh_config.texfmt[PTI_DEPTH32]) + vk.depthformat = VK_FORMAT_D32_SFLOAT; +// else if (info->depthbits == 32 && sh_config.texfmt[PTI_DEPTH32_8]) +// vk.depthformat = VK_FORMAT_D32_SFLOAT_S8_UINT; + else if (info->depthbits == 24 && sh_config.texfmt[PTI_DEPTH24_8]) + vk.depthformat = VK_FORMAT_D24_UNORM_S8_UINT; + else if (info->depthbits == 24 && sh_config.texfmt[PTI_DEPTH24]) + vk.depthformat = VK_FORMAT_X8_D24_UNORM_PACK32; + + else if (sh_config.texfmt[PTI_DEPTH24]) vk.depthformat = VK_FORMAT_X8_D24_UNORM_PACK32; else if (sh_config.texfmt[PTI_DEPTH24_8]) vk.depthformat = VK_FORMAT_D24_UNORM_S8_UINT; - else if (sh_config.texfmt[PTI_DEPTH32]) //nvidia recommend to de-prioritise 32bit (float) depth. + else if (sh_config.texfmt[PTI_DEPTH32]) //nvidia: "Don’t use 32-bit floating point depth formats, due to the performance cost, unless improved precision is actually required" vk.depthformat = VK_FORMAT_D32_SFLOAT; else //16bit depth is guarenteed in vulkan vk.depthformat = VK_FORMAT_D16_UNORM;