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
This commit is contained in:
Spoike 2020-06-12 23:29:58 +00:00
parent a37f70e5f0
commit 5aa11ddbb1
54 changed files with 1715 additions and 985 deletions

View File

@ -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

View File

@ -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

View File

@ -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'

View File

@ -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 ; i<MAX_PRECACHE_SOUNDS ; i++)
{
if (cl.sound_precache[i] && cl.sound_precache[i]->loadstate == SLS_NOTLOADED)
S_LoadSound(cl.sound_precache[i], false);
}
}
}
}

View File

@ -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] =
{

View File

@ -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')
{

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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};

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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 (&registered, "Copy protection");

View File

@ -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);

View File

@ -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)

View File

@ -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]);

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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.

View File

@ -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]));

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -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

View File

@ -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,

View File

@ -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))

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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
.PHONY: tests

View File

@ -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));

View File

@ -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);

View File

@ -14,7 +14,7 @@
#include <string.h>
#include <stdarg.h>
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 <stdio.h>
//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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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 ( ; e<limit ; e++)
{
ent = EDICT_NUM_PB(svprogfuncs, e);
@ -3782,7 +3825,7 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t
if (cameras && tracecullent && !((unsigned int)ent->v->effects & (EF_DIMLIGHT|EF_BLUE|EF_RED|EF_BRIGHTLIGHT|EF_BRIGHTFIELD|EF_NODEPTHTEST)))
{ //more expensive culling
if ((e <= sv.allocated_client_slots && sv_cullplayers_trace.value) || sv_cullentities_trace.value)
if (Cull_Traceline(cameras, tracecullent))
if (Cull_Traceline(e < client->lastseen_count?&client->lastseen_time[e]:NULL, cameras, tracecullent))
continue;
}

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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: "Dont 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;