1
0
Fork 0
forked from fte/fteqw

Optimised the textures of defaultwall with fast preset.

Fix simpleitems transparency in gles2.
Fix a couple of GL errors in gles2 (including some fixed function stuff that could result in segfaults).
Dynamically adjust MTU values with legacy qw clients too.
Added some small sleeps while waiting for downloads (this fixes insanely slow valgrind startups but might make non-valgrind start a smidge slower).
Fix title metadata in the updates system.
Clean up some issues for when WEBCLIENT is not defined.
HAVE_HTTPSV also disables websocket connections, to completely avoid any http strings anywhere, in the hope that it reduces virus scanner false positives.
Fix presets initial option, again.
Writing files to FS_GAMEONLY no longer purges the entire fscache, which should give a speedup in certain situations.
Added some new cvars to control heightmap lightmap generation.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5461 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-05-23 15:11:32 +00:00
parent b3050121cf
commit 3c5518afa8
41 changed files with 735 additions and 279 deletions

View file

@ -4195,7 +4195,7 @@ void CL_LinkPacketEntities (void)
Q_snprintfz(name, sizeof(name), "textures/bmodels/simple_%s_%i.tga", basename, ent->skinnum);
else
Q_snprintfz(name, sizeof(name), "textures/models/simple_%s_%i.tga", basename, ent->skinnum);
model->simpleskin[ent->skinnum] = R_RegisterShader(name, 0, va("{\nnomipmaps\nprogram defaultsprite\nsurfaceparm noshadows\nsurfaceparm nodlight\nsort seethrough\n{\nmap \"%s\"\nalphafunc ge128\n}\n}\n", name));
model->simpleskin[ent->skinnum] = R_RegisterShader(name, 0, va("{\nnomipmaps\nprogram defaultsprite#MASK=0.5\nsurfaceparm noshadows\nsurfaceparm nodlight\nsort seethrough\n{\nmap \"%s\"\nalphafunc ge128\n}\n}\n", name));
}
VectorCopy(le->angles, angles);

View file

@ -3493,9 +3493,14 @@ client_connect: //fixme: make function
if (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)
cls.netchan.qportsize = 1;
}
cls.netchan.fragmentsize = connectinfo.mtu;
cls.netchan.pext_fragmentation = connectinfo.mtu?true:false;
if (connectinfo.mtu >= 64)
{
cls.netchan.mtu = connectinfo.mtu;
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
}
else
cls.netchan.mtu = MAX_QWMSGLEN;
#ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc);
#else
@ -6396,7 +6401,12 @@ void Host_FinishLoading(void)
FS_ChangeGame(NULL, true, true);
if (waitingformanifest)
{
#ifdef MULTITHREAD
Sys_Sleep(0.1);
#endif
return;
}
Con_History_Load();
@ -6437,7 +6447,12 @@ void Host_FinishLoading(void)
}
if (PM_IsApplying(true))
{
#ifdef MULTITHREAD
Sys_Sleep(0.1);
#endif
return;
}
//android may find that it has no renderer at various points.
if (r_forceheadless)

View file

@ -1390,6 +1390,15 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag)
return; //looks like its already picked. marking it again will do no harm.
}
#ifndef WEBCLIENT
//can't mark for download if we cannot download.
if (!(package->flags & DPF_PRESENT))
{ //though we can at least unmark it for deletion...
package->flags &= ~DPF_PURGE;
return;
}
#endif
//any file-conflicts prevent the package from being installable.
//this is mostly for pak1.pak
for (dep = package->deps; dep; dep = dep->next)
@ -1881,7 +1890,7 @@ static void PM_WriteInstalledPackages(void)
if (*p->title && strcmp(p->title, p->name))
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("title=%s", p->version), buf, sizeof(buf));
COM_QuotedConcat(va("title=%s", p->title), buf, sizeof(buf));
}
if (*p->version)
{
@ -2745,7 +2754,6 @@ qboolean PM_CanInstall(const char *packagename)
void PM_Command_f(void)
{
size_t i;
package_t *p;
const char *act = Cmd_Argv(1);
const char *key;
@ -2878,6 +2886,7 @@ void PM_Command_f(void)
}
Con_Printf("<end of list>\n");
}
#ifdef WEBCLIENT
else if (!strcmp(act, "sources") || !strcmp(act, "addsource"))
{
if (Cmd_Argc() == 2)
@ -2890,6 +2899,7 @@ void PM_Command_f(void)
else
PM_AddSubList(Cmd_Argv(2), "", true, true);
}
#endif
else if (!strcmp(act, "remsource"))
PM_RemSubList(Cmd_Argv(2));
else if (!strcmp(act, "apply"))
@ -2908,8 +2918,10 @@ void PM_Command_f(void)
{
PM_RevertChanges();
}
#ifdef WEBCLIENT
else if (!strcmp(act, "update"))
{ //flush package cache, make a new request.
int i;
for (i = 0; i < numdownloadablelists; i++)
downloadablelist[i].received = 0;
}
@ -2924,6 +2936,7 @@ void PM_Command_f(void)
else
Con_Printf("Already using latest versions of all packages\n");
}
#endif
else if (!strcmp(act, "add") || !strcmp(act, "get") || !strcmp(act, "install") || !strcmp(act, "enable"))
{ //FIXME: make sure this updates.
int arg = 2;
@ -2938,6 +2951,7 @@ void PM_Command_f(void)
}
PM_PrintChanges();
}
#ifdef WEBCLIENT
else if (!strcmp(act, "reinstall"))
{ //fixme: favour the current verson.
int arg = 2;
@ -2955,6 +2969,7 @@ void PM_Command_f(void)
}
PM_PrintChanges();
}
#endif
else if (!strcmp(act, "disable") || !strcmp(act, "rem") || !strcmp(act, "remove"))
{
int arg = 2;
@ -3234,9 +3249,11 @@ static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsig
case DPF_USERMARKED:
case DPF_MARKED:
p->flags |= DPF_PURGE;
#ifdef WEBCLIENT
//now: re-get despite already having it.
if ((p->flags & DPF_CORRUPT) || ((p->flags & DPF_PRESENT) && !PM_PurgeOnDisable(p)))
break; //only makes sense if we already have a cached copy that we're not going to use.
#endif
//fallthrough
case DPF_USERMARKED|DPF_PURGE:
case DPF_AUTOMARKED|DPF_PURGE:
@ -3444,10 +3461,13 @@ static void MD_Download_UpdateStatus(struct menu_s *m)
dlmenu_t *info = m->data;
int i, y;
package_t *p;
unsigned int totalpackages=0, selectedpackages=0, addpackages=0, rempackages=0, downloads=0;
unsigned int totalpackages=0, selectedpackages=0, addpackages=0, rempackages=0;
menuoption_t *si;
menubutton_t *b, *d;
#ifdef WEBCLIENT
unsigned int downloads=0;
menucustom_t *c;
#endif
if (info->downloadablessequence != downloadablessequence || !info->populated)
{

View file

@ -1062,6 +1062,7 @@ void M_Menu_Preset_f (void)
item = 6; //fast
else
item = 7; //simple
item++; //the autosave option
item -= bias;
while (item --> 0)
menu->selecteditem = menu->selecteditem->common.next;

View file

@ -306,15 +306,15 @@ static void S_Info(void);
static void S_Shutdown_f(void);
*/
static cvar_t s_al_debug = CVAR("s_al_debug", "0");
static cvar_t s_al_use_reverb = CVAR("s_al_use_reverb", "1");
static cvar_t s_al_debug = CVARD("s_al_debug", "0", "Enables periodic checks for OpenAL errors.");
static cvar_t s_al_use_reverb = CVARD("s_al_use_reverb", "1", "Controls whether reverb effects will be used. Set to 0 to block them. Reverb requires gamecode to configure the reverb properties, other than underwater.");
static cvar_t s_al_max_distance = CVARFC("s_al_max_distance", "1000",0,OnChangeALSettings);
static cvar_t s_al_speedofsound = CVARFC("s_al_speedofsound", "343.3",0,OnChangeALSettings);
static cvar_t s_al_dopplerfactor = CVARFC("s_al_dopplerfactor", "1.0",0,OnChangeALSettings);
static cvar_t s_al_distancemodel = CVARFC("s_al_distancemodel", "2",0,OnChangeALSettings);
static cvar_t s_al_rolloff_factor = CVAR("s_al_rolloff_factor", "1");
static cvar_t s_al_reference_distance = CVAR("s_al_reference_distance", "120");
static cvar_t s_al_velocityscale = CVAR("s_al_velocityscale", "1");
static cvar_t s_al_speedofsound = CVARFCD("s_al_speedofsound", "343.3",0,OnChangeALSettings, "Configures the speed of sound, in game units per second. This affects doppler.");
static cvar_t s_al_dopplerfactor = CVARFCD("s_al_dopplerfactor", "1.0",0,OnChangeALSettings, "Multiplies the strength of doppler effects.");
static cvar_t s_al_distancemodel = CVARFCD("s_al_distancemodel", legacyval("2","0"),0,OnChangeALSettings, "Controls how sounds fade with distance.\n0: Inverse (most realistic)\n1: Inverse Clamped\n2: Linear (Quake-like)\n3: Linear Clamped\n4: Exponential\n5: Exponential Clamped\n6: None");
//static cvar_t s_al_rolloff_factor = CVAR("s_al_rolloff_factor", "1");
static cvar_t s_al_reference_distance = CVARD("s_al_reference_distance", "120", "This is the distance at which the sound is audiable with standard volume in the inverse distance models. Nearer sounds will be louder than the original sample.");
static cvar_t s_al_velocityscale = CVARD("s_al_velocityscale", "1", "Rescales velocity values, before doppler can be calculated.");
static cvar_t s_al_static_listener = CVAR("s_al_static_listener", "0"); //cheat
extern cvar_t snd_doppler;
@ -503,7 +503,7 @@ static void QDECL OpenAL_CvarInit(void)
Cvar_Register(&s_al_dopplerfactor, SOUNDVARS);
Cvar_Register(&s_al_distancemodel, SOUNDVARS);
Cvar_Register(&s_al_reference_distance, SOUNDVARS);
Cvar_Register(&s_al_rolloff_factor, SOUNDVARS);
// Cvar_Register(&s_al_rolloff_factor, SOUNDVARS);
Cvar_Register(&s_al_velocityscale, SOUNDVARS);
Cvar_Register(&s_al_static_listener, SOUNDVARS);
Cvar_Register(&s_al_speedofsound, SOUNDVARS);

View file

@ -802,8 +802,7 @@ 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];
array[1] = (void*)((ucontext_t*)vcontext)->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.
@ -995,7 +994,6 @@ int main (int c, const char **v)
#endif
TL_InitLanguages(parms.binarydir);
if (!isatty(STDIN_FILENO))
noconinput = !isPlugin; //don't read the stdin if its probably screwed (running in qtcreator seems to pipe stdout to stdin in an attempt to screw everything up).
else

View file

@ -3362,10 +3362,15 @@ static void *Q1MDL_LoadFrameGroup (galiasinfo_t *galias, dmdl_t *pq1inmodel, mod
galias->numanimations++;
intervals = (daliasinterval_t *)(ingroup+1);
sinter = LittleFloat(intervals->interval);
if (sinter <= 0)
sinter = 0.1;
frame->rate = 1/sinter;
if (frame->numposes == 0)
frame->rate = 10;
else
{
sinter = LittleFloat(intervals->interval);
if (sinter <= 0)
sinter = 0.1;
frame->rate = 1/sinter;
}
pinframe = (dtrivertx_t *)(intervals+frame->numposes);
for (k = 0; k < frame->numposes; k++)

View file

@ -52,7 +52,8 @@ typedef struct
#endif
qboolean loop;
int numposes;
float rate;
//float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1]
float rate; //average framerate of animation.
#ifdef NONSKELETALMODELS
galiaspose_t *poseofs;
#endif
@ -219,7 +220,7 @@ typedef struct modplugfuncs_s
void (QDECL *UnRegisterModelFormat)(int idx);
void (QDECL *UnRegisterAllModelFormats)(void);
void *(QDECL *ZG_Malloc)(zonegroup_t *ctx, int size); //ctx=&mod->memgroup and the data will be freed when the model is freed.
void *(QDECL *ZG_Malloc)(zonegroup_t *ctx, size_t size); //ctx=&mod->memgroup and the data will be freed when the model is freed.
void (QDECL *ConcatTransforms) (const float in1[3][4], const float in2[3][4], float out[3][4]);
void (QDECL *M3x4_Invert) (const float *in1, float *out);

View file

@ -131,6 +131,13 @@ typedef enum {false, true} qboolean;
#define MAX_SERVERINFO_STRING 1024 //standard quake has 512 here.
#define MAX_LOCALINFO_STRING 32768
#ifdef HAVE_LEGACY
#define legacyval(_legval,_newval) _legval
#else
#define legacyval(_legval,_newval) _newval
#endif
#ifdef HAVE_CLIENT
#define cls_state cls.state
#else
@ -448,7 +455,7 @@ struct cache_user_s;
extern char com_gamepath[MAX_OSPATH];
extern char com_homepath[MAX_OSPATH];
extern char com_configdir[MAX_OSPATH]; //dir to put cfg_save configs in
//extern char com_configdir[MAX_OSPATH]; //dir to put cfg_save configs in
//extern char *com_basedir;
//qofs_Make is used to 'construct' a variable of qofs_t type. this is so the code can merge two 32bit ints on old systems and use a long long type internally without generating warnings about bit shifts when qofs_t is only 32bit instead.

View file

@ -137,6 +137,7 @@
#define HAVE_WINSSPI //on windows
#define FTPSERVER //sv_ftp cvar.
#define WEBCLIENT //uri_get+any internal downloads etc
#define HAVE_HTTPSV //net_enable_http/websocket
#define TCPCONNECT //support for playing over tcp sockets, instead of just udp. compatible with qizmo.
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.

View file

@ -144,7 +144,7 @@ typedef struct cvar_group_s
#define CVAR_WATCHED (1<<22) //report any attempts to change this cvar.
#define CVAR_VIDEOLATCH (1<<23)
#define CVAR_LASTFLAG CVAR_SHADERSYSTEM
#define CVAR_LASTFLAG CVAR_VIDEOLATCH
#define CVAR_LATCHMASK (CVAR_LATCH|CVAR_RENDERERLATCH|CVAR_SERVEROVERRIDE|CVAR_CHEAT|CVAR_SEMICHEAT) //you're only allowed one of these.
#define CVAR_NEEDDEFAULT CVAR_CHEAT

View file

@ -172,14 +172,15 @@ char gamedirfile[MAX_OSPATH];
char pubgamedirfile[MAX_OSPATH]; //like gamedirfile, but not set to the fte-only paths
searchpath_t *gameonly_homedir;
searchpath_t *gameonly_gamedir;
char com_gamepath[MAX_OSPATH]; //c:\games\quake
char com_homepath[MAX_OSPATH]; //c:\users\foo\my docs\fte\quake
qboolean com_homepathenabled;
qboolean com_homepathusable; //com_homepath is safe, even if not enabled.
char com_configdir[MAX_OSPATH]; //homedir/fte/configs
//char com_configdir[MAX_OSPATH]; //homedir/fte/configs
int fs_hash_dups;
int fs_hash_files;
@ -737,7 +738,7 @@ static void COM_Path_f (void)
Con_Printf("pubgamedirfile: \"%s\"\n", pubgamedirfile);
Con_Printf("com_gamepath: \"%s\"\n", com_gamepath);
Con_Printf("com_homepath: \"%s\" (enabled: %s, usable: %s)\n", com_homepath, com_homepathenabled?"yes":"no", com_homepathusable?"yes":"no");
Con_Printf("com_configdir: \"%s\"\n", com_configdir);
// Con_Printf("com_configdir: \"%s\"\n", com_configdir);
if (fs_manifest)
FS_Manifest_Print(fs_manifest);
return;
@ -1915,6 +1916,9 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela
fs_accessed_time = realtime;
if (fs_readonly && *mode == 'w')
return NULL;
if (relativeto == FS_SYSTEM)
return VFSOS_Open(filename, mode);
@ -1937,23 +1941,48 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela
//if there can only be one file (eg: write access) find out where it is.
switch (relativeto)
{
case FS_GAMEONLY: //OS access only, no paks
case FS_GAMEONLY: //OS access only, no paks. Used for (re)writing files.
vfs = NULL;
//FIXME: go via a searchpath, because then the fscache can be selectively updated
if (com_homepathenabled)
{
if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_homepath, gamedirfile, filename))
return NULL;
if (*mode == 'w')
COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode);
if (gameonly_homedir)
{
if ((*mode == 'w')
? gameonly_homedir->handle->CreateFile(gameonly_homedir->handle, &loc, filename)
: gameonly_homedir->handle->FindFile (gameonly_homedir->handle, &loc, filename, NULL))
vfs = gameonly_homedir->handle->OpenVFS (gameonly_homedir->handle, &loc, mode);
else
vfs = NULL;
}
else
{
if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_homepath, gamedirfile, filename))
return NULL;
if (*mode == 'w')
COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode);
}
}
if (!vfs && *gamedirfile)
{
if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_gamepath, gamedirfile, filename))
return NULL;
if (*mode == 'w')
COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode);
if (gameonly_gamedir)
{
if ((*mode == 'w')
? gameonly_gamedir->handle->CreateFile(gameonly_gamedir->handle, &loc, filename)
: gameonly_gamedir->handle->FindFile (gameonly_gamedir->handle, &loc, filename, NULL))
vfs = gameonly_gamedir->handle->OpenVFS (gameonly_gamedir->handle, &loc, mode);
else
vfs = NULL;
}
else
{
if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_gamepath, gamedirfile, filename))
return NULL;
if (*mode == 'w')
COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode);
}
}
if (vfs || !(*mode == 'w' || *mode == 'a'))
return vfs;
@ -2793,7 +2822,7 @@ Sets com_gamedir, adds the directory to the head of the path,
then loads and adds pak1.pak pak2.pak ...
================
*/
static void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, const char *dir, unsigned int loadstuff, unsigned int flags)
static searchpath_t *FS_AddSingleGameDirectory (searchpath_t **oldpaths, const char *puredir, const char *dir, unsigned int loadstuff, unsigned int flags)
{
unsigned int keptflags;
searchpath_t *search;
@ -2808,7 +2837,7 @@ static void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, c
if (!Q_strcasecmp(search->logicalpath, dir))
{
search->flags |= flags & SPF_WRITABLE;
return; //already loaded (base paths?)
return search; //already loaded (base paths?)
}
}
@ -2831,7 +2860,20 @@ static void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, c
if (!handle)
handle = VFSOS_OpenPath(NULL, NULL, dir, dir, "");
FS_AddPathHandle(oldpaths, puredir, dir, handle, "", flags|keptflags, loadstuff);
return FS_AddPathHandle(oldpaths, puredir, dir, handle, "", flags|keptflags, loadstuff);
}
static void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, unsigned int loadstuff, unsigned int flags)
{
char syspath[MAX_OSPATH];
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, puredir);
gameonly_gamedir = FS_AddSingleGameDirectory(oldpaths, puredir, syspath, loadstuff, flags&~(com_homepathenabled?SPF_WRITABLE:0u));
if (com_homepathenabled)
{
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, puredir);
gameonly_homedir = FS_AddSingleGameDirectory(oldpaths, puredir, syspath, loadstuff, flags);
}
else
gameonly_homedir = NULL;
}
//if syspath, something like c:\quake\baseq2
@ -3698,7 +3740,6 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
searchpath_t *next;
int i;
int orderkey;
char syspath[MAX_OSPATH];
COM_AssertMainThread("FS_ReloadPackFilesFlags");
COM_WorkerFullSync();
@ -3715,6 +3756,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
com_searchpaths = NULL;
com_purepaths = NULL;
com_base_searchpaths = NULL;
gameonly_gamedir = gameonly_homedir = NULL;
i = COM_CheckParm ("-basepack");
while (i && i < com_argc-1)
@ -3777,23 +3819,11 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
else if (*dir == '*')
{
//paths with a leading * are private, and not announced to clients that ask what the current gamedir is.
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, dir+1);
FS_AddGameDirectory(&oldpaths, dir+1, syspath, reloadflags, SPF_EXPLICIT|SPF_PRIVATE|(com_homepathenabled?0:SPF_WRITABLE));
if (com_homepathenabled)
{
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, dir+1);
FS_AddGameDirectory(&oldpaths, dir+1, syspath, reloadflags, SPF_EXPLICIT|SPF_PRIVATE|SPF_WRITABLE);
}
FS_AddGameDirectory(&oldpaths, dir+1, reloadflags, SPF_EXPLICIT|SPF_PRIVATE|SPF_WRITABLE);
}
else
{
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, dir);
FS_AddGameDirectory(&oldpaths, dir, syspath, reloadflags, SPF_EXPLICIT|(com_homepathenabled?0:SPF_WRITABLE));
if (com_homepathenabled)
{
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, dir);
FS_AddGameDirectory(&oldpaths, dir, syspath, reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
}
FS_AddGameDirectory(&oldpaths, dir, reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
}
}
}
@ -3823,9 +3853,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
}
else
{
FS_AddGameDirectory(&oldpaths, dir, va("%s%s", com_gamepath, dir), reloadflags, SPF_EXPLICIT|(com_homepathenabled?0:SPF_WRITABLE));
if (com_homepathenabled)
FS_AddGameDirectory(&oldpaths, dir, va("%s%s", com_homepath, dir), reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
FS_AddGameDirectory(&oldpaths, dir, reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
}
}
}
@ -6330,7 +6358,6 @@ static void COM_InitHomedir(ftemanifest_t *man)
//but if it doesn't exist then we use $XDG_DATA_HOME/.fte instead
//we used to use $HOME/.#HOMESUBDIR/ but this is now only used if it actually exists AND the new path doesn't.
//new installs use $XDG_DATA_HOME/#HOMESUBDIR/ instead
char *ev = getenv("FTEHOME");
if (ev && *ev)
{

View file

@ -49,9 +49,9 @@ struct searchpathfuncs_s
qboolean (QDECL *PollChanges)(searchpathfuncs_t *handle); //returns true if there were changes
qboolean (QDECL *FileStat)(searchpathfuncs_t *handle, flocation_t *loc, time_t *mtime);
qboolean (QDECL *RenameFile)(searchpathfuncs_t *handle, const char *oldname, const char *newname); //returns true on success, false if source doesn't exist, or if dest does.
qboolean (QDECL *CreateFile)(searchpathfuncs_t *handle, flocation_t *loc, const char *filename); //like FindFile, but returns a usable loc even if the file does not exist yet (may also create requisite directories too)
qboolean (QDECL *RenameFile)(searchpathfuncs_t *handle, const char *oldname, const char *newname); //returns true on success, false if source doesn't exist, or if dest does (cached locs may refer to either new or old name).
qboolean (QDECL *RemoveFile)(searchpathfuncs_t *handle, const char *filename); //returns true on success, false if it wasn't found or is readonly.
qboolean (QDECL *MkDir)(searchpathfuncs_t *handle, const char *filename); //is this really needed?
};
//searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc); //returns a handle to a new pak/path
@ -87,7 +87,7 @@ int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man),
#define SPF_TEMPORARY 4 //a map-specific path, purged at map change.
#define SPF_EXPLICIT 8 //a root gamedir (bumps depth on gamedir depth checks).
#define SPF_UNTRUSTED 16 //has been downloaded from somewhere. configs inside it should never be execed with local access rights.
#define SPF_PRIVATE 32 //private to the client. ie: the fte dir.
#define SPF_PRIVATE 32 //private to the client. ie: the fte dir. name is not networked.
#define SPF_WRITABLE 64 //safe to write here. lots of weird rules etc.
#define SPF_BASEPATH 128 //part of the basegames, and not the mod gamedir(s).
qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags);

View file

@ -271,6 +271,30 @@ static void QDECL FSSTDIO_BuildHash(searchpathfuncs_t *handle, int depth, void (
sp->AddFileHash = AddFileHash;
Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, AddFileHash, handle);
}
static unsigned int QDECL FSSTDIO_CreateLoc(searchpathfuncs_t *handle, flocation_t *loc, const char *filename)
{
stdiopath_t *sp = (void*)handle;
char *ofs;
loc->len = 0;
loc->offset = 0;
loc->fhandle = handle;
if ((unsigned int)snprintf(loc->rawname, sizeof(loc->rawname), "%s/%s", sp->rootpath, filename) > sizeof(loc->rawname)-1)
return FF_NOTFOUND; //too long...
for (ofs = loc->rawname+1 ; *ofs ; ofs++)
{
if (*ofs == '/')
{ // create the directory
*ofs = 0;
Sys_mkdir (loc->rawname);
*ofs = '/';
}
}
return FF_FOUND;
}
static unsigned int QDECL FSSTDIO_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult)
{
stdiopath_t *sp = (void*)handle;
@ -289,7 +313,8 @@ static unsigned int QDECL FSSTDIO_FLocate(searchpathfuncs_t *handle, flocation_t
*/
// check a file in the directory tree
snprintf (netpath, sizeof(netpath)-1, "%s/%s", sp->rootpath, filename);
if ((unsigned int)snprintf (netpath, sizeof(netpath), "%s/%s", sp->rootpath, filename) > sizeof(netpath)-1)
return FF_NOTFOUND;
#ifdef ANDROID
{
@ -378,6 +403,7 @@ searchpathfuncs_t *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, searchpathfuncs
np->pub.OpenVFS = FSSTDIO_OpenVFS;
np->pub.PollChanges = FSSTDIO_PollChanges;
np->pub.FileStat = FSSTDIO_FileStat;
np->pub.CreateFile = FSSTDIO_CreateLoc;
return &np->pub;
}

View file

@ -522,6 +522,30 @@ static void QDECL VFSW32_BuildHash(searchpathfuncs_t *handle, int hashdepth, voi
wp->hashdepth = hashdepth;
Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, AddFileHash, handle);
}
static unsigned int QDECL VFSW32_CreateLoc(searchpathfuncs_t *handle, flocation_t *loc, const char *filename)
{
vfsw32path_t *wp = (void*)handle;
char *ofs;
loc->len = 0;
loc->offset = 0;
loc->fhandle = handle;
loc->rawname[sizeof(loc->rawname)-1] = 0;
if ((unsigned int)snprintf (loc->rawname, sizeof(loc->rawname), "%s/%s", wp->rootpath, filename) > sizeof(loc->rawname)-1)
return FF_NOTFOUND;
for (ofs = loc->rawname+1 ; *ofs ; ofs++)
{
if (*ofs == '/')
{ // create the directory
*ofs = 0;
Sys_mkdir (loc->rawname);
*ofs = '/';
}
}
return FF_FOUND;
}
#include <errno.h>
static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult)
{
@ -545,7 +569,8 @@ static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t
*/
// check a file in the directory tree
snprintf (netpath, sizeof(netpath)-1, "%s/%s", wp->rootpath, filename);
if ((unsigned int)snprintf (netpath, sizeof(netpath), "%s/%s", wp->rootpath, filename) > sizeof(loc->rawname)-1)
return FF_NOTFOUND;
if (!WinNT)
{
@ -634,16 +659,6 @@ static qboolean QDECL VFSW32_RemoveFile(searchpathfuncs_t *handle, const char *f
snprintf (syspath, sizeof(syspath)-1, "%s/%s", wp->rootpath, filename);
return Sys_remove(syspath);
}
static qboolean QDECL VFSW32_MkDir(searchpathfuncs_t *handle, const char *filename)
{
vfsw32path_t *wp = (vfsw32path_t*)handle;
char syspath[MAX_OSPATH];
if (fs_readonly)
return false;
snprintf (syspath, sizeof(syspath)-1, "%s/%s", wp->rootpath, filename);
Sys_mkdir(syspath);
return true;
}
searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix)
{
@ -675,9 +690,10 @@ searchpathfuncs_t *QDECL VFSW32_OpenPath(vfsfile_t *mustbenull, searchpathfuncs_
np->pub.FileStat = VFSW32_FileStat;
#undef CreateFile //stoopid windows.h
np->pub.CreateFile = VFSW32_CreateLoc;
np->pub.RenameFile = VFSW32_RenameFile;
np->pub.RemoveFile = VFSW32_RemoveFile;
np->pub.MkDir = VFSW32_MkDir;
return &np->pub;
}

View file

@ -313,7 +313,8 @@ typedef struct
{
struct
{
int cp[2];
unsigned short cp[2];
unsigned short fixedres[2];
} patch;
struct
{
@ -527,7 +528,7 @@ static int Patch_FlatnessTest( float maxflat2, const float *point0, const float
Patch_GetFlatness
===============
*/
static void Patch_GetFlatness( float maxflat, const float *points, int comp, const int *patch_cp, int *flat )
static void Patch_GetFlatness( float maxflat, const float *points, int comp, const unsigned short *patch_cp, int *flat )
{
int i, p, u, v;
float maxflat2 = maxflat * maxflat;
@ -579,7 +580,7 @@ static void Patch_Evaluate_QuadricBezier( float t, const vec_t *point0, const ve
Patch_Evaluate
===============
*/
static void Patch_Evaluate( const vec_t *p, const int *numcp, const int *tess, vec_t *dest, int comp )
static void Patch_Evaluate( const vec_t *p, const unsigned short *numcp, const int *tess, vec_t *dest, int comp )
{
int num_patches[2], num_tess[2];
int index[3], dstpitch, i, u, v, x, y;
@ -850,7 +851,7 @@ static int CM_CreateFacetFromPoints(q2cbrush_t *facet, vec3_t *verts, int numver
/*
* CM_CreatePatch
*/
static void CM_CreatePatch(model_t *loadmodel, q3cpatch_t *patch, q2mapsurface_t *shaderref, const vec_t *verts, const int *patch_cp )
static void CM_CreatePatch(model_t *loadmodel, q3cpatch_t *patch, q2mapsurface_t *shaderref, const vec_t *verts, const unsigned short *patch_cp, const unsigned short *patch_subdiv)
{
int step[2], size[2], flat[2];
int i, j, k ,u, v;
@ -1088,7 +1089,7 @@ static qboolean CM_CreatePatchForFace (model_t *loadmodel, cminfo_t *prv, mleaf_
checkout[facenum] = prv->numpatches++;
//gcc warns without this cast
CM_CreatePatch (loadmodel, patch, surf, (const vec_t *)(prv->verts + face->firstvert), face->patch.cp );
CM_CreatePatch (loadmodel, patch, surf, (const vec_t *)(prv->verts + face->firstvert), face->patch.cp, face->patch.fixedres );
}
leaf->contents |= patch->surface->c.value;
leaf->numleafpatches++;
@ -2554,8 +2555,12 @@ static qboolean CModRBSP_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l)
if (out->facetype == MST_PATCH)
{
out->patch.cp[0] = LittleLong ( in->patchwidth );
out->patch.cp[1] = LittleLong ( in->patchheight );
unsigned int w = LittleLong ( in->patchwidth );
unsigned int h = LittleLong ( in->patchheight );
out->patch.cp[0] = w&0xffff;
out->patch.cp[1] = h&0xffff;
out->patch.fixedres[0]=w>>16;
out->patch.fixedres[1]=h>>16;
}
else
{
@ -2658,11 +2663,12 @@ static index_t tempIndexesArray[MAX_ARRAY_VERTS*6];
static void GL_SizePatch(mesh_t *mesh, int patchwidth, int patchheight, int numverts, int firstvert, cminfo_t *prv)
{
int patch_cp[2], step[2], size[2], flat[2];
unsigned short patch_cp[2];
int step[2], size[2], flat[2];
float subdivlevel;
patch_cp[0] = patchwidth;
patch_cp[1] = patchheight;
patch_cp[0] = patchwidth&0xffff;
patch_cp[1] = patchheight&0xffff;
if (patch_cp[0] <= 0 || patch_cp[1] <= 0 )
{
@ -2692,13 +2698,14 @@ static void GL_SizePatch(mesh_t *mesh, int patchwidth, int patchheight, int numv
static void GL_CreateMeshForPatch (model_t *mod, mesh_t *mesh, int patchwidth, int patchheight, int numverts, int firstvert)
{
cminfo_t *prv = (cminfo_t*)mod->meshinfo;
int numindexes, patch_cp[2], step[2], size[2], flat[2], i, u, v, p;
int numindexes, step[2], size[2], flat[2], i, u, v, p;
unsigned short patch_cp[2];
index_t *indexes;
float subdivlevel;
int sty;
patch_cp[0] = patchwidth;
patch_cp[1] = patchheight;
patch_cp[0] = patchwidth&0xffff;
patch_cp[1] = patchheight&0xffff;
if (patch_cp[0] <= 0 || patch_cp[1] <= 0 )
{

View file

@ -209,9 +209,10 @@ typedef struct
float nqreliable_resendtime;//force nqreliable_allowed, thereby forcing a resend of anything n
qbyte nqunreliableonly; //nq can't cope with certain reliables some times. if 2, we have a reliable that result in a block (that should be sent). if 1, we are blocking. if 0, we can send reliables freely. if 3, then we just want to ignore clc_moves
#endif
qboolean pext_fragmentation; //fte's packet fragmentation extension, to avoid issues with low mtus.
struct netprim_s netprim;
int fragmentsize;
int dupe;
int mtu; //the path mtu, if known
int dupe; //how many times to dupe packets
float last_received; // for timeouts

View file

@ -692,7 +692,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->message.overflowed)
{
chan->fatal_error = true;
Con_TPrintf ("%s:Outgoing message overflow\n"
Con_TPrintf ("%s: Outgoing message overflow\n"
, NET_AdrToString (remote_adr, sizeof(remote_adr), &chan->remote_address));
return 0;
}
@ -716,7 +716,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
// write the packet header
send.data = send_buf;
send.maxsize = MAX_QWMSGLEN + PACKET_HEADER;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER;
send.cursize = 0;
w1 = chan->outgoing_sequence | (send_reliable<<31);
@ -738,9 +738,9 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
}
#endif
if (chan->fragmentsize)
if (chan->pext_fragmentation)
{
//allow the max size to be bigger
//allow the max size to be bigger, sending everything available
send.maxsize = MAX_OVERALLMSGLEN + PACKET_HEADER;
MSG_WriteShort(&send, 0);
}
@ -748,6 +748,17 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
// copy the reliable message to the packet first
if (send_reliable)
{
if (send.maxsize - send.cursize < chan->reliable_length)
{
if (!chan->fatal_error)
{
chan->fatal_error = true;
Con_TPrintf ("%s: Path MTU is lower than %u\n"
, NET_AdrToString (remote_adr, sizeof(remote_adr), &chan->remote_address), chan->reliable_length);
}
chan->outgoing_sequence--;
return 0;
}
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
chan->last_reliable_sequence = chan->outgoing_sequence;
}
@ -765,7 +776,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->compresstable)
{
//int oldsize = send.cursize;
Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->fragmentsize?2:0));
Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->pext_fragmentation?2:0));
// Con_Printf("%i becomes %i\n", oldsize, send.cursize);
// Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8);
}
@ -779,20 +790,23 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
{
int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/
if ((!chan->fragmentsize))// || send.cursize < ((chan->fragmentsize - hsz)&~7))
{
if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7))
{ //vanilla sends
for (i = -1; i < chan->dupe && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
send.cursize += send.cursize * i;
if (e == NETERR_MTU && chan->fragmentsize > 560)
//ipv4 'guarentees' mtu sizes of at least 560ish.
//our reliable/backbuf messages are limited to 1024 bytes.
//this means that large reliables may be unsendable.
if (e == NETERR_MTU && chan->mtu > 560)
{
Con_Printf("Reducing MSS to %i\n", chan->fragmentsize);
chan->fragmentsize -= 10;
Con_Printf("Reducing MSS to %i\n", chan->mtu);
chan->mtu -= 10;
}
}
else
{
{ //fte's fragmentaton protocol
int offset = 0, no;
qboolean more;
@ -801,7 +815,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
/*send the additional parts, adding new headers within the previous packet*/
do
{
no = offset + chan->fragmentsize - hsz;
no = offset + chan->mtu - hsz;
if (no < send.cursize-hsz)
{
no &= ~7;
@ -831,10 +845,10 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
for (i = -1; i < chan->dupe && e == NETERR_SENT; i++)
{
e = NET_SendPacket (chan->sock, (no - offset) + hsz, send.data + offset, &chan->remote_address);
if (e == NETERR_MTU && !offset && chan->fragmentsize > 560)
if (e == NETERR_MTU && !offset && chan->mtu > 560)
{
chan->fragmentsize -= 16;
Con_Printf("Reducing MSS to %i\n", chan->fragmentsize);
chan->mtu -= 16;
Con_Printf("Reducing MSS to %i\n", chan->mtu);
no = offset;
more = true;
break;
@ -917,7 +931,7 @@ qboolean Netchan_Process (netchan_t *chan)
MSG_ReadShort ();
#endif
if (chan->fragmentsize)
if (chan->pext_fragmentation)
offset = (unsigned short)MSG_ReadShort();
else
offset = 0;

View file

@ -101,9 +101,9 @@ FTE_ALIGN(4) qbyte net_message_buffer[MAX_OVERALLMSGLEN];
#define HAVE_NATPMP
#endif
#if defined(HAVE_SERVER) || defined(MASTERONLY)
#define HAVE_HTTPSV
#endif
//#if !defined(HAVE_SERVER) && !defined(MASTERONLY)
// #undef HAVE_HTTPSV
//#endif
void NET_GetLocalAddress (int socket, netadr_t *out);
//int TCP_OpenListenSocket (const char *localip, int port);
@ -127,6 +127,7 @@ cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxie
#if defined(HAVE_SSL)
cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port.");
#endif
#ifdef HAVE_HTTPSV
#ifdef SV_MASTER
cvar_t net_enable_http = CVARD("net_enable_http", "1", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay.");
#else
@ -135,6 +136,7 @@ cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp port
cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients.");
cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections.");
#endif
#endif
#if defined(HAVE_DTLS) && defined(HAVE_SERVER)
static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue)
{
@ -3693,10 +3695,10 @@ typedef struct ftenet_tcpconnect_stream_s {
{
TCPC_UNKNOWN, //waiting to see what they send us.
TCPC_QIZMO, //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length.
#ifdef HAVE_HTTPSV
TCPC_WEBSOCKETU, //utf-8 encoded data.
TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary')
TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake
#ifdef HAVE_HTTPSV
TCPC_HTTPCLIENT, //we're sending a file to this victim.
TCPC_WEBRTC_CLIENT, //for brokering webrtc connections, doesn't carry any actual game data itself.
TCPC_WEBRTC_HOST //for brokering webrtc connections, doesn't carry any actual game data itself.
@ -4718,8 +4720,8 @@ qboolean FTENET_TCP_ParseHTTPRequest(ftenet_tcpconnect_connection_t *con, ftenet
return FTENET_TCPConnect_HTTPResponse(st, arg, acceptsgzip);
}
}
#ifdef HAVE_SSL
#endif
#if defined(HAVE_SSL) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV))
static int QDECL TLSPromoteRead (struct vfsfile_s *file, void *buffer, int bytestoread)
{
if (bytestoread > net_message.cursize)
@ -4730,7 +4732,6 @@ static int QDECL TLSPromoteRead (struct vfsfile_s *file, void *buffer, int bytes
return bytestoread;
}
#endif
#endif
void FTENET_TCPConnect_PrintStatus(ftenet_generic_connection_t *gcon)
{
ftenet_tcpconnect_connection_t *con = (ftenet_tcpconnect_connection_t*)gcon;
@ -4749,12 +4750,12 @@ void FTENET_TCPConnect_PrintStatus(ftenet_generic_connection_t *gcon)
case TCPC_QIZMO:
Con_Printf("qizmo %s\n", adr);
break;
#ifdef HAVE_HTTPSV
case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB:
case TCPC_WEBSOCKETNQ:
Con_Printf("websocket %s\n", adr);
break;
#ifdef HAVE_HTTPSV
case TCPC_HTTPCLIENT:
Con_Printf("http %s\n", adr);
break;
@ -5011,13 +5012,12 @@ closesvstream:
net_from = st->remoteaddr;
return true;
#ifdef HAVE_HTTPSV
case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB:
case TCPC_WEBSOCKETNQ:
#ifdef HAVE_HTTPSV
case TCPC_WEBRTC_HOST:
case TCPC_WEBRTC_CLIENT:
#endif
while (st->inlen >= 2)
{
unsigned short ctrl = ((unsigned char*)st->inbuffer)[0]<<8 | ((unsigned char*)st->inbuffer)[1];
@ -5164,7 +5164,6 @@ closesvstream:
Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream;
}
#ifdef HAVE_HTTPSV
#ifdef SUPPORT_RTC_ICE
if (st->clienttype == TCPC_WEBRTC_CLIENT && !*st->webrtc.resource)
{ //this is a client that's corrected directly to us via webrtc.
@ -5203,7 +5202,6 @@ closesvstream:
net_message.cursize = 0;
}
else
#endif
#ifdef NQPROT
if (st->clienttype == TCPC_WEBSOCKETNQ)
{ //hack in an 8-byte header
@ -5248,6 +5246,7 @@ closesvstream:
}
}
break;
#endif
}
}
@ -5298,7 +5297,6 @@ closesvstream:
neterr_t FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int length, const void *data, netadr_t *to)
{
neterr_t e;
ftenet_tcpconnect_connection_t *con = (ftenet_tcpconnect_connection_t*)gcon;
ftenet_tcpconnect_stream_t *st;
@ -5333,6 +5331,7 @@ neterr_t FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len
}
}
break;
#ifdef HAVE_HTTPSV
case TCPC_WEBSOCKETNQ:
if (length < 8 || ((char*)data)[0] & 0x80)
break;
@ -5344,10 +5343,13 @@ neterr_t FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len
//fallthrough
case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB:
e = FTENET_TCPConnect_WebSocket_Splurge(st, (st->clienttype==TCPC_WEBSOCKETU)?1:2, data, length);
if (e != NETERR_SENT)
return e;
{
neterr_t e = FTENET_TCPConnect_WebSocket_Splurge(st, (st->clienttype==TCPC_WEBSOCKETU)?1:2, data, length);
if (e != NETERR_SENT)
return e;
}
break;
#endif
default:
break;
}
@ -7877,10 +7879,12 @@ void NET_Init (void)
#if defined(HAVE_SSL)
Cvar_Register(&net_enable_tls, "networking");
#endif
#ifdef HAVE_HTTPSV
Cvar_Register(&net_enable_http, "networking");
Cvar_Register(&net_enable_websockets, "networking");
Cvar_Register(&net_enable_webrtcbroker, "networking");
#endif
#endif

View file

@ -125,7 +125,7 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags)
}
//got an empty number.
Con_DPrintf("%s: %i\n", name, newnum);
Con_DLPrintf(2, "%s: %i\n", name, newnum);
plugbuiltins[newnum].name = name;
plugbuiltins[newnum].func = bi;
plugbuiltins[newnum].flags = flags;

View file

@ -364,7 +364,9 @@ pubsubserver_t *Sys_ForkServer(void)
//make sure we're fully synced, so that workers can't mess up
Cvar_Set(Cvar_FindVar("worker_count"), "0");
COM_WorkerFullSync();
#ifdef WEBCLIENT
DL_DeThread();
#endif
#ifdef SQL
SQL_KillServers(); //FIXME: this is bad...
#endif

View file

@ -52,11 +52,11 @@ qbyte sentinalkey;
#define TAGLESS 1
int zmemtotal;
int zmemdelta;
size_t zmemtotal;
size_t zmemdelta;
typedef struct memheader_s {
int size;
size_t size;
int tag;
} memheader_t;
@ -108,13 +108,13 @@ static void Z_DumpTree(void)
}
#endif
void *VARGS Z_TagMalloc(int size, int tag)
void *Z_TagMalloc(size_t size, int tag)
{
zone_t *zone;
zone = (zone_t *)malloc(size + sizeof(zone_t));
if (!zone)
Sys_Error("Z_Malloc: Failed on allocation of %i bytes", size);
Sys_Error("Z_Malloc: Failed on allocation of %"PRIuSIZE" bytes", size);
Q_memset(zone, 0, size + sizeof(zone_t));
zone->mh.tag = tag;
zone->mh.size = size;
@ -184,7 +184,7 @@ void *Z_MallocNamed(int size, char *file, int line)
return mem;
}
#else
void *ZF_Malloc(int size)
void *ZF_Malloc(size_t size)
{
#ifdef ANDROID
void *ret = NULL;
@ -202,11 +202,11 @@ void *ZF_Malloc(int size)
return calloc(size, 1);
#endif
}
void *Z_Malloc(int size)
void *Z_Malloc(size_t size)
{
void *mem = ZF_Malloc(size);
if (!mem)
Sys_Error("Z_Malloc: Failed on allocation of %i bytes", size);
Sys_Error("Z_Malloc: Failed on allocation of %"PRIuSIZE" bytes", size);
return mem;
}
@ -423,7 +423,7 @@ void *BZF_MallocNamed(int size, const char *file, int line) //BZ_MallocNamed but
return mem;
}
#else
void *BZF_Malloc(int size) //BZ_Malloc but allowed to fail - like straight malloc.
void *BZF_Malloc(size_t size) //BZ_Malloc but allowed to fail - like straight malloc.
{
void *mem;
mem = malloc(size);
@ -446,11 +446,11 @@ void *BZ_MallocNamed(int size, const char *file, int line) //BZ_MallocNamed but
return mem;
}
#else
void *BZ_Malloc(int size) //Doesn't clear. The expectation is a large file, rather than sensitive data structures.
void *BZ_Malloc(size_t size) //Doesn't clear. The expectation is a large file, rather than sensitive data structures.
{
void *mem = BZF_Malloc(size);
if (!mem)
Sys_Error("BZ_Malloc: Failed on allocation of %i bytes", size);
Sys_Error("BZ_Malloc: Failed on allocation of %"PRIuSIZE" bytes", size);
return mem;
}
@ -472,17 +472,17 @@ void *BZ_ReallocNamed(void *data, int newsize, const char *file, int line)
return mem;
}
#else
void *BZF_Realloc(void *data, int newsize)
void *BZF_Realloc(void *data, size_t newsize)
{
return realloc(data, newsize);
}
void *BZ_Realloc(void *data, int newsize)
void *BZ_Realloc(void *data, size_t newsize)
{
void *mem = BZF_Realloc(data, newsize);
if (!mem)
Sys_Error("BZ_Realloc: Failed on reallocation of %i bytes", newsize);
Sys_Error("BZ_Realloc: Failed on reallocation of %"PRIuSIZE" bytes", newsize);
return mem;
}
@ -508,7 +508,7 @@ typedef struct zonegroupblock_s
void *QDECL ZG_Malloc(zonegroup_t *ctx, int size){return ZG_MallocNamed(ctx, size, "ZG_Malloc", size);}
void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line)
#else
void *QDECL ZG_Malloc(zonegroup_t *ctx, int size)
void *QDECL ZG_Malloc(zonegroup_t *ctx, size_t size)
#endif
{
zonegroupblock_t *newm;
@ -590,7 +590,7 @@ void Hunk_TempFree(void)
//allocates without clearing previous temp.
//safer than my hack that fuh moaned about...
void *Hunk_TempAllocMore (int size)
void *Hunk_TempAllocMore (size_t size)
{
void *buf;
@ -624,7 +624,7 @@ void *Hunk_TempAllocMore (int size)
}
void *Hunk_TempAlloc (int size)
void *Hunk_TempAlloc (size_t size)
{
Hunk_TempFree();
@ -657,8 +657,8 @@ void Cache_Flush(void)
static void Hunk_Print_f (void)
{
Con_Printf("Z Delta: %iKB\n", zmemdelta/1024); zmemdelta = 0;
Con_Printf("Z Total: %iKB\n", zmemtotal/1024);
Con_Printf("Z Delta: %"PRIuSIZE"KB\n", zmemdelta/1024); zmemdelta = 0;
Con_Printf("Z Total: %"PRIuSIZE"KB\n", zmemtotal/1024);
//note: Zone memory isn't tracked reliably. we don't track the mem that is freed, so it'll just climb and climb
//we don't track reallocs either.

View file

@ -87,12 +87,12 @@ void Memory_Init (void);
void Memory_DeInit(void);
void VARGS Z_Free (void *ptr);
void *Z_Malloc (int size); // returns 0 filled memory
void *ZF_Malloc (int size); // allowed to fail
void *Z_MallocNamed (int size, char *file, int line); // returns 0 filled memory
void *ZF_MallocNamed (int size, char *file, int line); // allowed to fail
void *Z_Malloc (size_t size); // returns 0 filled memory
void *ZF_Malloc (size_t size); // allowed to fail
void *Z_MallocNamed (size_t size, char *file, int line); // returns 0 filled memory
void *ZF_MallocNamed (size_t size, char *file, int line); // allowed to fail
//#define Z_Malloc(x) Z_MallocNamed2(x, __FILE__, __LINE__ )
void *VARGS Z_TagMalloc (int size, int tag);
void *Z_TagMalloc (size_t size, int tag);
void VARGS Z_TagFree(void *ptr);
void VARGS Z_FreeTags(int tag);
qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize); //returns false on error
@ -101,14 +101,14 @@ qboolean ZF_ReallocElementsNamed(void **ptr, size_t *elements, size_t newelement
//Big Zone: allowed to fail, doesn't clear. The expectation is a large file, rather than sensitive data structures.
//(this is a nicer name for malloc)
void *BZ_Malloc(int size);
void *BZF_Malloc(int size);
void *BZ_MallocNamed (int size, const char *file, int line); // returns 0 filled memory
void *BZF_MallocNamed (int size, const char *file, int line); // allowed to fail
void *BZ_Realloc(void *ptr, int size);
void *BZ_ReallocNamed(void *data, int newsize, const char *file, int line);
void *BZF_Realloc(void *data, int newsize);
void *BZF_ReallocNamed(void *data, int newsize, const char *file, int line);
void *BZ_Malloc(size_t size);
void *BZF_Malloc(size_t size);
void *BZ_MallocNamed (size_t size, const char *file, int line); // returns 0 filled memory
void *BZF_MallocNamed (size_t size, const char *file, int line); // allowed to fail
void *BZ_Realloc(void *ptr, size_t size);
void *BZ_ReallocNamed(void *data, size_t newsize, const char *file, int line);
void *BZF_Realloc(void *data, size_t newsize);
void *BZF_ReallocNamed(void *data, size_t newsize, const char *file, int line);
void BZ_Free(void *ptr);
//ctx should start off as void*ctx=NULL
@ -117,8 +117,8 @@ typedef struct zonegroup_s
void *first;
int bytes;
} zonegroup_t;
void *QDECL ZG_Malloc(zonegroup_t *ctx, int size);
void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line);
void *QDECL ZG_Malloc(zonegroup_t *ctx, size_t size);
void *ZG_MallocNamed(zonegroup_t *ctx, size_t size, char *file, int line);
void ZG_FreeGroup(zonegroup_t *ctx);
#ifdef USE_MSVCRT_DEBUG
@ -141,8 +141,8 @@ void *Hunk_Alloc (int size); // returns 0 filled memory
void *Hunk_AllocName (int size, char *name);
*/
void *Hunk_TempAlloc (int size);
void *Hunk_TempAllocMore (int size); //Don't clear old temp
void *Hunk_TempAlloc (size_t size);
void *Hunk_TempAllocMore (size_t size); //Don't clear old temp
/*
typedef struct cache_user_s

View file

@ -15,4 +15,5 @@ vid_conwidth "0" //make something up based upon aspect ratio
vid_conheight "300" //not using autoscale as it can make the menu unusable.
vid_conautoscale "0" // Text/Menu size. 2 is the default. 4 is bigger
scr_consize 0.4 //android's onscreen keyboard can take up over half the screen (and we don't know exactly where it is).
exec touch.cfg

View file

@ -4725,6 +4725,20 @@ static void DrawMeshes(void)
p = &shaderstate.curshader->passes[passno];
passno += p->numMergedPasses;
if (p->prog)
{
shaderstate.pendingcolourvbo = shaderstate.sourcevbo->colours[0].gl.vbo;
shaderstate.pendingcolourpointer = shaderstate.sourcevbo->colours[0].gl.addr;
shaderstate.colourarraytype = shaderstate.sourcevbo->colours_bytes?GL_UNSIGNED_BYTE:GL_FLOAT;
shaderstate.pendingtexcoordparts[0] = 2;
shaderstate.pendingtexcoordvbo[0] = shaderstate.sourcevbo->texcoord.gl.vbo;
shaderstate.pendingtexcoordpointer[0] = shaderstate.sourcevbo->texcoord.gl.addr;
BE_RenderMeshProgram(shaderstate.curshader, p, p->prog);
continue;
}
emumode = 0;
emumode = (p->shaderbits & SBITS_ATEST_BITS) >> SBITS_ATEST_SHIFT;

View file

@ -135,11 +135,11 @@ void GL_SetupFormats(void)
if (gl_config_gles)
{
//pre-3 gles doesn't support sized formats, and only a limited number of them too
glfmtc(PTI_RGB8, GL_RGB, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tc_rgb);
glfmtc(PTI_RGBA8, GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8);
glfmt(PTI_L8A8, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
glfmt(PTI_L8, GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
// glfmt(PTI_RGBA8, GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
glfmtc(PTI_RGB8, 0, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tc_rgb);
glfmtc(PTI_RGBA8, 0, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8);
glfmt(PTI_L8A8, 0, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
glfmt(PTI_L8, 0, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
// glfmt(PTI_A8, 0, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
if (!gl_config.webgl_ie)
{ //these should work on all gles2+webgl1 devices, but microsoft doesn't give a shit.
@ -754,7 +754,6 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
{
qglTexParameteri(targ, GL_TEXTURE_BASE_LEVEL, 0);
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, nummips-1);
qglTexParameteri(targ, GL_TEXTURE_LOD_BIAS, 0);
}
}
}

View file

@ -24,6 +24,10 @@ struct patchvert_s
cvar_t mod_terrain_networked = CVARD("mod_terrain_networked", "0", "Terrain edits are networked. Clients will download sections on demand, and servers will notify clients of changes.");
cvar_t mod_terrain_defaulttexture = CVARD("mod_terrain_defaulttexture", "", "Newly created terrain tiles will use this texture. This should generally be updated by the terrain editor.");
cvar_t mod_terrain_savever = CVARD("mod_terrain_savever", "", "Which terrain section version to write if terrain was edited.");
cvar_t mod_terrain_sundir = CVARD("mod_terrain_sundir", "0.4 0.7 2", "The direction of the sun (vector will be normalised).");
cvar_t mod_terrain_ambient = CVARD("mod_terrain_ambient", "0.5", "Proportion of ambient light.");
cvar_t mod_terrain_shadows = CVARD("mod_terrain_shadows", "0", "Cast rays to determine whether parts of the terrain should be in shadow.");
cvar_t mod_terrain_shadow_dist = CVARD("mod_terrain_shadow_dist", "2048", "How far rays should be cast in order to look for occlusing geometry.");
enum
{
@ -81,7 +85,7 @@ void validatelinks2(link_t *firstnode, link_t *panic)
#ifndef SERVERONLY
static void ted_dorelight(heightmap_t *hm);
static void ted_dorelight(model_t *m, heightmap_t *hm);
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b);
static qboolean Terr_Collect(heightmap_t *hm);
#endif
@ -1933,6 +1937,18 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
if (!s || s->loadstate < TSLS_LOADING2)
return;
{
int cx = s->sx/MAXSECTIONS;
int cy = s->sy/MAXSECTIONS;
hmcluster_t *c = hm->cluster[cx + cy*MAXCLUSTERS];
int sx = s->sx & (MAXSECTIONS-1);
int sy = s->sy & (MAXSECTIONS-1);
if (c->section[sx+sy*MAXSECTIONS] != s)
Sys_Error("Section %i,%i already destroyed...\n", s->sx, s->sy);
c->section[sx+sy*MAXSECTIONS] = NULL;
}
validatelinks(&hm->recycle);
RemoveLink(&s->recycle);
@ -1966,10 +1982,16 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
{
if (qglDeleteBuffersARB)
{
qglDeleteBuffersARB(1, &s->vbo.coord.gl.vbo);
s->vbo.coord.gl.vbo = 0;
qglDeleteBuffersARB(1, &s->vbo.indicies.gl.vbo);
s->vbo.indicies.gl.vbo = 0;
if (s->vbo.coord.gl.vbo)
{
qglDeleteBuffersARB(1, &s->vbo.coord.gl.vbo);
s->vbo.coord.gl.vbo = 0;
}
if (s->vbo.indicies.gl.vbo)
{
qglDeleteBuffersARB(1, &s->vbo.indicies.gl.vbo);
s->vbo.indicies.gl.vbo = 0;
}
}
}
else
@ -2123,8 +2145,6 @@ validatelinks(&hm->recycle);
}
else
{
c->section[sx+sy*MAXSECTIONS] = NULL;
validatelinks(&hm->recycle);
Terr_DestroySection(hm, s, lightmapreusable);
validatelinks(&hm->recycle);
@ -2999,7 +3019,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
// hm->beinglazy = false;
if (hm->relight)
ted_dorelight(hm);
ted_dorelight(m, hm);
if (e->model == cl.worldmodel && hm->skyshader)
{
@ -3310,9 +3330,10 @@ unsigned int Heightmap_NativeBoxContents(model_t *model, int hulloverride, frame
return Heightmap_PointContentsHM(hm, mins[2], org);
}
void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
float Heightmap_Normal(heightmap_t *hm, vec2_t org, vec3_t norm) //returns the z
{
#if 0
float z = 0;
norm[0] = 0;
norm[1] = 0;
norm[2] = 1;
@ -3322,6 +3343,7 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
vec3_t d1, d2;
const float wbias = CHUNKBIAS * hm->sectionsize;
hmsection_t *s;
float z;
norm[0] = 0;
norm[1] = 0;
@ -3330,12 +3352,12 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
sx = (org[0]+wbias)/hm->sectionsize;
sy = (org[1]+wbias)/hm->sectionsize;
if (sx < hm->firstsegx || sy < hm->firstsegy)
return;
return hm->defaultgroundheight;
if (sx >= hm->maxsegx || sy >= hm->maxsegy)
return;
return hm->defaultgroundheight;
s = Terr_GetSection(hm, sx, sy, TGS_TRYLOAD);
if (!s)
return;
return hm->defaultgroundheight;
x = (org[0]+wbias - (sx*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize;
y = (org[1]+wbias - (sy*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize;
@ -3354,6 +3376,10 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
d2[0] = 0;
d2[1] = (hm->sectionsize / SECTHEIGHTSIZE);
d2[2] = (s->heights[(sx+1)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+1)+(sy+0)*SECTHEIGHTSIZE]);
z = (s->heights[(sx+0)+(sy+1)*SECTHEIGHTSIZE]*(1-y) +
s->heights[(sx+1)+(sy+1)*SECTHEIGHTSIZE]*(x+y-1) +
s->heights[(sx+1)+(sy+0)*SECTHEIGHTSIZE]*(1-x));
}
else
{ //the 0,0 triangle
@ -3366,13 +3392,19 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
d2[0] = 0;
d2[1] = (hm->sectionsize / SECTHEIGHTSIZE);
d2[2] = (s->heights[(sx+0)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+0)+(sy+0)*SECTHEIGHTSIZE]);
z = (s->heights[(sx+0)+(sy+1)*SECTHEIGHTSIZE]*(y) +
s->heights[(sx+1)+(sy+0)*SECTHEIGHTSIZE]*(x) +
s->heights[(sx+0)+(sy+0)*SECTHEIGHTSIZE]*(1-y-x));
}
VectorNormalize(d1);
VectorNormalize(d2);
CrossProduct(d1, d2, norm);
VectorNormalize(norm);
#endif
return z;
}
typedef struct {
@ -4244,11 +4276,11 @@ qboolean Heightmap_Trace_Test(struct model_s *model, int hulloverride, framestat
qboolean ret = Heightmap_Trace(model, hulloverride, framestate, mataxis, start, end, mins, maxs, capsule, against, trace);
if (!trace->startsolid)
{
{ //FIXME: this code should not be needed.
trace_t testtrace;
Heightmap_Trace(model, hulloverride, framestate, mataxis, trace->endpos, trace->endpos, mins, maxs, capsule, against, &testtrace);
if (testtrace.startsolid)
{
{ //yup, we're bugged.
Con_DPrintf("Trace became solid\n");
trace->fraction = 0;
VectorCopy(start, trace->endpos);
@ -4370,32 +4402,37 @@ static unsigned char *QDECL Terr_GetLightmap(hmsection_t *s, int idx, qboolean e
}
return lightmap[s->lightmap]->lightmaps + ((s->lmy+y) * HMLMSTRIDE + (s->lmx+x)) * lightmap[s->lightmap]->pixbytes;
}
static void ted_dorelight(heightmap_t *hm)
static void ted_dorelight(model_t *m, heightmap_t *hm)
{
unsigned char *lm = Terr_GetLightmap(hm->relight, 0, true);
int x, y;
int x, y, k;
#define EXPAND 2
vec3_t surfnorms[(SECTTEXSIZE+EXPAND*2)*(SECTTEXSIZE+EXPAND*2)];
vec3_t surfpoint[(SECTTEXSIZE+EXPAND*2)*(SECTTEXSIZE+EXPAND*2)];
// float scaletab[EXPAND*2*EXPAND*2];
vec3_t ldir = {0.4, 0.7, 2};
vec3_t ldir;
hmsection_t *s = hm->relight;
float ambient, diffuse;
trace_t trace;
s->flags &= ~TSF_RELIGHT;
hm->relight = NULL;
if (s->lightmap < 0)
return;
ambient = 255*mod_terrain_ambient.value;
diffuse = 255-ambient;
for (y = -EXPAND; y < SECTTEXSIZE+EXPAND; y++)
for (x = -EXPAND; x < SECTTEXSIZE+EXPAND; x++)
{
vec3_t pos;
pos[0] = hm->relightmin[0] + (x*hm->sectionsize/(SECTTEXSIZE-1));
pos[1] = hm->relightmin[1] + (y*hm->sectionsize/(SECTTEXSIZE-1));
pos[2] = 0;
Heightmap_Normal(s->hmmod, pos, surfnorms[x+EXPAND + (y+EXPAND)*(SECTTEXSIZE+EXPAND*2)]);
k = x+EXPAND + (y+EXPAND)*(SECTTEXSIZE+EXPAND*2);
surfpoint[k][0] = hm->relightmin[0] + (x*hm->sectionsize/(SECTTEXSIZE-1));
surfpoint[k][1] = hm->relightmin[1] + (y*hm->sectionsize/(SECTTEXSIZE-1));
surfpoint[k][2] = Heightmap_Normal(s->hmmod, surfpoint[k], surfnorms[k])+0.1;
}
VectorNormalize(ldir);
VectorNormalize2(mod_terrain_sundir.vec4, ldir);
for (y = 0; y < SECTTEXSIZE; y++, lm += (HMLMSTRIDE-SECTTEXSIZE)*4)
for (x = 0; x < SECTTEXSIZE; x++, lm += 4)
@ -4415,10 +4452,18 @@ static void ted_dorelight(heightmap_t *hm)
d = DotProduct(ldir, norm);
if (d < 0)
d = 0;
else if (mod_terrain_shadows.ival)
{
float *point = surfpoint[x+EXPAND + (y+EXPAND)*(SECTTEXSIZE+EXPAND*2)];
vec3_t sun;
VectorMA(point, mod_terrain_shadow_dist.value, ldir, sun);
if (m->funcs.NativeTrace(m, 0, NULL, NULL, point, sun, vec3_origin, vec3_origin, false, FTECONTENTS_SOLID|FTECONTENTS_BODY, &trace))
d = 0;
}
// lm[0] = norm[0]*127 + 128;
// lm[1] = norm[1]*127 + 128;
// lm[2] = norm[2]*127 + 128;
lm[3] = 127 + d*128;
lm[3] = ambient + d*diffuse;
}
lightmap[s->lightmap]->modified = true;
@ -7102,11 +7147,11 @@ void Terr_WriteBrushInfo(vfsfile_t *file, brushes_t *br)
}
hasrgba = (y < br->patch->ypoints*br->patch->xpoints);
VFS_PRINTF(file, "\n\tpatchDef%s\n\t{\n\t\t\"%s\"\n\t\t( %.9g %.9g %.9g %.9g %.9g )\n\t\t(\n",
VFS_PRINTF(file, "\n\tpatchDef%s\n\t{\n\t\t\"%s\"\n\t\t( %u %u %.9g %.9g %.9g )\n\t\t(\n",
hasrgba?"WS":"2",
br->patch->tex?br->patch->tex->shadername:"",
0.0/*xoffset*/,
0.0/*yoffset*/,
br->patch->xpoints/*width*/,
br->patch->ypoints/*height*/,
0.0/*rotation*/,
1.0/*xscale*/,
1.0/*yscale*/);
@ -7480,9 +7525,10 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
continue;
}
}
else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDefWS")))
else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDef3") || !strcmp(token, "patchDefWS")))
{
int x, y;
qboolean patchdef3 = !strcmp(token, "patchDef3"); //fancy alternative with rgba colours per control point
qboolean parsergba = !strcmp(token, "patchDefWS"); //fancy alternative with rgba colours per control point
if (numplanes || patch_tex)
{
@ -7498,10 +7544,17 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*xoffset = atof(token);*/
/*patch_w = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*yoffset = atof(token);*/
/*patch_h = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (patchdef3)
{
/*xsubdiv = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*ysubdiv = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
}
/*rotation = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*xscale = atof(token);*/
@ -7532,7 +7585,12 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
patch_v[y][x].tc[1] = atof(token);
if (parsergba)
{
{ //the following four lines are stupid.
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (strcmp(token, ")")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
patch_v[y][x].rgba[0] = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
@ -7981,31 +8039,33 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force)
}
#ifndef SERVERONLY
#if 0 //not yet ready
struct ted_import_s
{
int x, y;
int width;
int height;
size_t x, y;
size_t width;
size_t height;
unsigned short *data;
};
//static void ted_itterate(heightmap_t *hm, int distribution, float *pos, float radius, float strength, int steps,
void ted_import_heights(void *vctx, hmsection_t *s, int idx, float wx, float wy, float strength)
static void ted_import_heights_r16(void *vctx, hmsection_t *s, int idx, float wx, float wy, float strength)
{
struct ted_import_s *ctx = vctx;
unsigned int y = idx/SECTHEIGHTSIZE;
unsigned int x = idx%SECTHEIGHTSIZE;
x += s->sx*(SECTHEIGHTSIZE-1) - ctx->x;
y += s->sy*(SECTHEIGHTSIZE-1) - ctx->y;
if (x < 0 || x >= ctx->width || y < 0 || y >= ctx->height)
if (x >= ctx->width || y >= ctx->height)
return;
s->flags |= TSF_NOTIFY|TSF_EDITED|TSF_DIRTY|TSF_RELIGHT;
s->heights[idx] = ctx->data[x + y*ctx->width] * (8192.0/(1<<16));
}
void Mod_Terrain_Import_f(void)
static void Mod_Terrain_Import_f(void)
{
model_t *mod;
struct ted_import_s ctx;
const char *mapname = Cmd_Argv(1);
const char *filename;
size_t fsize;
heightmap_t *hm;
vec3_t pos = {0};
@ -8025,16 +8085,142 @@ void Mod_Terrain_Import_f(void)
return;
fsize = 0;
ctx.data = (void*)FS_LoadMallocFile("quake8km/height8km.r16", &fsize);
filename = va("maps/%s.r16", mapname);
ctx.data = (void*)FS_LoadMallocFile(filename, &fsize);
if (!ctx.data)
{
Con_Printf("Unable to read %s\n", filename);
return;
}
ctx.width = ctx.height = sqrt(fsize/2);
ctx.x = 0;
ctx.y = 0;
pos[0] += hm->sectionsize * CHUNKBIAS;
pos[1] += hm->sectionsize * CHUNKBIAS;
if (fsize == ctx.width*ctx.height*2)
ted_itterate(hm, tid_flat, pos, max(ctx.width, ctx.height), 1, SECTHEIGHTSIZE, ted_import_heights, &ctx);
ted_itterate(hm, tid_flat, pos, max(ctx.width, ctx.height), 1, SECTHEIGHTSIZE, ted_import_heights_r16, &ctx);
FS_FreeFile(ctx.data);
}
static void Mod_Terrain_Export_f(void)
{
model_t *mod;
struct ted_import_s ctx;
char mapname[MAX_QPATH];
const char *filename;
heightmap_t *hm;
size_t w, h;
size_t tx, ty;
size_t sx, sy;
unsigned int outtilex=0,outtiley=0;
qboolean populated;
if (Cmd_IsInsecure())
{
Con_Printf("Please use this command via the console\n");
return;
}
if (*Cmd_Argv(1))
mod = NULL;//Mod_FindName(va("maps/%s", mapname));
else
mod = cl.worldmodel;
if (!mod || mod->type == mod_dummy)
return;
hm = mod->terrain;
if (!hm)
return;
COM_StripExtension(mod->name, mapname, sizeof(mapname));
ctx.x = hm->firstsegx * (SECTHEIGHTSIZE-1);
w = (hm->maxsegx-hm->firstsegx) * (SECTHEIGHTSIZE-1) + 1;
while(w)
{
ctx.width = w;
if (ctx.width > 2048+1)
ctx.width = 2048;
outtiley = 0;
ctx.y = hm->firstsegy * (SECTHEIGHTSIZE-1);
h = (hm->maxsegy-hm->firstsegy) * (SECTHEIGHTSIZE-1) + 1;
while(h)
{
ctx.height = h;
if (ctx.height > 2048+1)
ctx.height = 2048;
populated = false;
ctx.data = Z_Malloc(ctx.width*ctx.height*2);
for (sy = ctx.y/(SECTHEIGHTSIZE-1); sy < (ctx.y+ctx.height + SECTHEIGHTSIZE-3)/(SECTHEIGHTSIZE-1); sy++)
for (sx = ctx.x/(SECTHEIGHTSIZE-1); sx < (ctx.x+ctx.width + SECTHEIGHTSIZE-3)/(SECTHEIGHTSIZE-1); sx++)
{
hmsection_t *s = Terr_GetSection(hm, sx, sy, TGS_WAITLOAD|TGS_ANYSTATE);
if (s->loadstate == TSLS_FAILED)
{ //we're doing this weirdly so we can destroy sections as we go.
Terr_DestroySection(hm, s, true);
s = NULL;
}
if (s)
{
populated = true;
for (ty = 0; ty < SECTHEIGHTSIZE; ty++)
{
size_t y = sy*(SECTHEIGHTSIZE-1)+ty - ctx.y;
if (y >= ctx.height)
continue;
for (tx = 0; tx < SECTHEIGHTSIZE; tx++)
{
size_t x = sx*(SECTHEIGHTSIZE-1)+tx - ctx.x;
if (x >= ctx.width)
continue;
ctx.data[x + y*ctx.width] = s->heights[tx+y*SECTHEIGHTSIZE] / (8192.0/(1<<16));
}
}
if (!(s->flags & TSF_EDITED))
Terr_DestroySection(hm, s, true);
}
else
{
for (ty = 0; ty < SECTHEIGHTSIZE; ty++)
{
size_t y = sy*(SECTHEIGHTSIZE-1)+ty - ctx.y;
if (y >= ctx.height)
continue;
for (tx = 0; tx < SECTHEIGHTSIZE; tx++)
{
size_t x = sx*(SECTHEIGHTSIZE-1)+tx - ctx.x;
if (x >= ctx.width)
continue;
ctx.data[x + y*ctx.width] = hm->defaultgroundheight / (8192.0/(1<<16));
}
}
}
}
filename = va("%s/x%u_y%u.r16", mapname, outtilex, outtiley);
if (populated)
{
if (FS_WriteFile(filename, ctx.data, ctx.width*ctx.height*2, FS_GAMEONLY))
{
char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf("Wrote %s\n", sysname);
}
else
Con_Printf("Unable to write %s\n", filename);
}
else
Con_Printf("Skipping unpopulated %s\n", filename);
Z_Free(ctx.data);
outtiley++;
ctx.y += ctx.height;
h -= ctx.height;
}
outtilex++;
ctx.x += ctx.width;
w -= ctx.width;
}
}
#endif
void Mod_Terrain_Create_f(void)
{
@ -8279,9 +8465,15 @@ void Terr_Init(void)
Cmd_AddCommand("mod_terrain_save", Mod_Terrain_Save_f);
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
#ifndef SERVERONLY
Cmd_AddCommandD("mod_terrain_import", Mod_Terrain_Import_f, "Import a raw heightmap");
// Cmd_AddCommandD("mod_terrain_export", Mod_Terrain_Export_f, "Export a raw heightmap");
// Cmd_AddCommandD("mod_terrain_import", Mod_Terrain_Import_f, "Import a raw heightmap");
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);
Cmd_AddCommandD("mod_terrain_convert", Mod_Terrain_Convert_f, "mod_terrain_convert [mapname] [texkill]\nConvert a terrain to the current format. If texkill is specified, only tiles with the named texture will be converted, and tiles with that texture will be stripped. This is a slow operation.");
Cvar_Register(&mod_terrain_sundir, "Terrain");
Cvar_Register(&mod_terrain_ambient, "Terrain");
Cvar_Register(&mod_terrain_shadows, "Terrain");
Cvar_Register(&mod_terrain_shadow_dist, "Terrain");
#endif
Mod_RegisterModelFormatText(NULL, "FTE Heightmap Map (hmp)", "terrain", Terr_LoadTerrainModel);

View file

@ -1256,6 +1256,7 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p)
size_t n, pn = 0;
char defines[8192];
size_t offset;
qboolean fail = false;
extern cvar_t gl_specular, gl_specular_power;
@ -1294,14 +1295,14 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p)
permutationdefines[pn++] = NULL;
if (!sh_config.pCreateProgram(prog, pp, prog->shaderver, permutationdefines, prog->shadertext, prog->tess?prog->shadertext:NULL, prog->tess?prog->shadertext:NULL, prog->geom?prog->shadertext:NULL, prog->shadertext, prog->warned, NULL))
prog->warned = true;
prog->warned = fail = true;
//extra loop to validate the programs actually linked properly.
//delaying it like this gives certain threaded drivers a chance to compile them all while we're messing around with other junk
if (sh_config.pValidateProgram && !sh_config.pValidateProgram(prog, pp, prog->warned, NULL))
prog->warned = true;
if (!fail && sh_config.pValidateProgram && !sh_config.pValidateProgram(prog, pp, prog->warned, NULL))
prog->warned = fail = true;
if (sh_config.pProgAutoFields)
if (!fail && sh_config.pProgAutoFields)
{
cvar_t *cvarrefs[64];
char *cvarnames[64+1];
@ -1320,9 +1321,52 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p)
cvarnames[i] = NULL; //no more
sh_config.pProgAutoFields(prog, pp, cvarrefs, cvarnames, cvartypes);
}
if (fail)
{
Z_Free(pp);
return NULL;
}
return pp;
}
qboolean Shader_PermutationEnabled(unsigned int bit)
{
if (bit == PERMUTATION_REFLECTCUBEMASK)
return gl_load24bit.ival;
if (bit == PERMUTATION_BUMPMAP)
return r_loadbumpmapping;
return true;
}
qboolean Com_PermuOrFloatArgument(const char *shadername, char *arg, size_t arglen, float def)
{
extern cvar_t gl_specular;
size_t p;
//load-time-only permutations...
if (arglen == 8 && !strncmp("SPECULAR", arg, arglen) && gl_specular.value)
return true;
if ((arglen==5||arglen==6) && !strncmp("DELUXE", arg, arglen) && r_deluxemapping && Shader_PermutationEnabled(PERMUTATION_BUMPMAP))
return true;
if (arglen == 13 && !strncmp("OFFSETMAPPING", arg, arglen) && r_glsl_offsetmapping.ival)
return true;
if (arglen == 13 && !strncmp("RELIEFMAPPING", arg, arglen) && r_glsl_offsetmapping.ival && r_glsl_offsetmapping_reliefmapping.ival)
return true;
//real permutations
if (arglen == 5 && (!strncmp("UPPER", arg, arglen)||!strncmp("LOWER", arg, arglen)) && Shader_PermutationEnabled(PERMUTATION_BIT_UPPERLOWER))
return true;
for (p = 0; p < countof(permutations); p++)
{
if (arglen == strlen(permutations[p].name) && !strncmp(permutations[p].name, arg, arglen))
{
if (Shader_PermutationEnabled(permutations[p].bitmask))
return true;
break;
}
}
return Com_FloatArgument(shadername, arg, arglen, def) != 0;
}
static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *script, int qrtype, int ver, char *blobfilename)
{
#if defined(GLQUAKE) || defined(D3DQUAKE)
@ -1412,15 +1456,16 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
if (*token == '=' || *token == '!')
{
len = strlen(token);
if (*token == (Com_FloatArgument(name, token+1, len-1, 0)?'!':'='))
if (*token == (Com_PermuOrFloatArgument(name, token+1, len-1, 0)?'!':'='))
ignore = true;
continue;
}
else if (ignore)
continue;
#ifdef HAVE_LEGACY
#if 1//def HAVE_LEGACY
else if (!strncmp(token, "deluxmap", 8))
{ //FIXME: remove this some time.
Con_DPrintf("Outdated texture name \"%s\" in program \"%s\"\n", token, name);
token = va("deluxemap%s",token+8);
}
#endif
@ -1470,7 +1515,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
prog->numsamplers = i;
}
else
Con_Printf("Unknown texture name in %s\n", name);
Con_Printf("Unknown texture name \"%s\" in program \"%s\"\n", token, name);
}
}
}
@ -1667,7 +1712,8 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
{
if (!strncmp(permutations[p].name, script, end - script) && permutations[p].name[end-script] == '\0')
{
nopermutation &= ~permutations[p].bitmask;
if (Shader_PermutationEnabled(permutations[p].bitmask))
nopermutation &= ~permutations[p].bitmask;
break;
}
}
@ -1738,10 +1784,10 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
nopermutation |= PERMUTATION_SKELETAL;
//multiple lightmaps is kinda hacky. if any are set, all must be.
#define ALTLIGHTMAPSAMP 13
#define ALTLIGHTMAPSAMP 14
if (prog->defaulttextures & ((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2))))
prog->defaulttextures |=((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2)));
#define ALTDELUXMAPSAMP 16
#define ALTDELUXMAPSAMP 17
if (prog->defaulttextures & ((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2))))
prog->defaulttextures |=((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2)));

View file

@ -420,7 +420,7 @@ qboolean GL_CheckExtension(char *extname)
for (i = 0; i < gl_num_extensions; i++)
if (!strcmp(qglGetStringi(GL_EXTENSIONS, i), extname))
{
Con_DPrintf("Detected GL extension %s\n", extname);
Con_DPrintf("GL: Found %s\n", extname);
return true;
}
}
@ -2280,6 +2280,9 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
"#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#elif defined(GL_ES)\n"
"#if __VERSION__ < 300\n"
"#extension GL_EXT_shadow_samplers : require\n"
"#endif\n"
"precision lowp sampler2DShadow;\n" //gah
"#endif\n"
#endif

View file

@ -2975,7 +2975,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
//must support skeletal and 2-way vertex blending or Bad Things Will Happen.
//the vertex shader is responsible for calculating lighting values.
"#if gl_affinemodels==1 && __VERSION__ >= 130\n"
"#if gl_affinemodels==1 && __VERSION__ >= 130 && !defined(GL_ES)\n"
"#define affine noperspective\n"
"#else\n"
"#define affine\n"
@ -5599,11 +5599,17 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"!!permu REFLECTCUBEMASK\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvardf r_tessellation_level=5\n"
"!!samps !EIGHTBIT diffuse specular normalmap fullbright reflectmask reflectcube\n"
"!!samps diffuse\n"
"!!samps !EIGHTBIT =FULLBRIGHT fullbright\n"
"!!samps !EIGHTBIT =BUMP normalmap\n"
"!!samps !EIGHTBIT =REFLECTCUBEMASK reflectmask reflectcube\n"
//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
"!!samps =EIGHTBIT paletted 1 specular diffuse\n"
"!!samps lightmap deluxemap\n"
"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3\n"
"!!samps =EIGHTBIT paletted 1\n"
"!!samps =SPECULAR specular\n"
"!!samps lightmap\n"
"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3\n"
"!!samps =DELUXE deluxmap\n"
"!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3\n"
"#if defined(ORM) || defined(SG)\n"
"#define PBR\n"
@ -5960,7 +5966,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#else\n"
//now we have our diffuse+specular terms, modulate by lightmap values.
"col.rgb *= lightmaps.rgb;\n"
//add on the fullbright
"#ifdef FULLBRIGHT\n"
"col.rgb += texture2D(s_fullbright, tc).rgb;\n"
@ -10603,10 +10608,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "terrain",
"!!ver 100 300\n"
"!!permu FOG\n"
//t0-t3 are the diffusemaps, t4 is the blend factors
"!!samps 4\n"
"!!samps mix=4\n"
//RTLIGHT (+PCF,CUBE,SPOT,etc)
"!!samps tr=0 tg=1 tb=2 tx=3 //the four texturemaps\n"
"!!samps mix=4 //how the ground is blended\n"
"!!samps =PCF shadowmap\n"
"!!samps =CUBE projectionmap\n"
@ -10703,10 +10709,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec4 r;\n"
"vec4 m = texture2D(s_mix, lm);\n"
"r = texture2D(s_t0, tc)*m.r;\n"
"r += texture2D(s_t1, tc)*m.g;\n"
"r += texture2D(s_t2, tc)*m.b;\n"
"r += texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b));\n"
"r = texture2D(s_tr, tc)*m.r;\n"
"r += texture2D(s_tg, tc)*m.g;\n"
"r += texture2D(s_tb, tc)*m.b;\n"
"r += texture2D(s_tx, tc)*(1.0 - (m.r + m.g + m.b));\n"
"r.rgb *= 1.0/r.a; //fancy maths, so low alpha values give other textures a greater focus\n"
//vertex colours provide a scaler that applies even through rtlights.
"r *= vc;\n"

View file

@ -23,7 +23,7 @@ void *PRHunkAlloc(progfuncs_t *progfuncs, int ammount, const char *name)
return ((char *)mem)+sizeof(prmemb_t);
}
void *PDECL QC_HunkAlloc(pubprogfuncs_t *ppf, int ammount, char *name)
static void *PDECL QC_HunkAlloc(pubprogfuncs_t *ppf, int ammount, char *name)
{
return PRHunkAlloc((progfuncs_t*)ppf, ammount, name);
}
@ -48,7 +48,7 @@ void PRHunkFree(progfuncs_t *progfuncs, int mark)
}
/*if we ran out of memory, the vm can allocate a new block, but doing so requires fixing up all sorts of pointers*/
void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int oldlen)
static void PRAddressableRelocate(progfuncs_t *progfuncs, char *oldb, char *newb, int oldlen)
{
unsigned int i;
edictrun_t *e;
@ -583,7 +583,7 @@ static void PDECL PR_Configure (pubprogfuncs_t *ppf, size_t addressable_size, in
struct globalvars_s *PDECL PR_globals (pubprogfuncs_t *ppf, progsnum_t pnum)
static struct globalvars_s *PDECL PR_globals (pubprogfuncs_t *ppf, progsnum_t pnum)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if (pnum < 0)
@ -598,7 +598,7 @@ struct globalvars_s *PDECL PR_globals (pubprogfuncs_t *ppf, progsnum_t pnum)
return (struct globalvars_s *)pr_progstate[pnum].globals;
}
struct entvars_s *PDECL PR_entvars (pubprogfuncs_t *ppf, struct edict_s *ed)
static struct entvars_s *PDECL PR_entvars (pubprogfuncs_t *ppf, struct edict_s *ed)
{
// progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if (((edictrun_t *)ed)->ereftype != ER_ENTITY)
@ -607,7 +607,7 @@ struct entvars_s *PDECL PR_entvars (pubprogfuncs_t *ppf, struct edict_s *ed)
return (struct entvars_s *)edvars(ed);
}
pbool PDECL PR_GetFunctionInfo(pubprogfuncs_t *ppf, func_t func, int *args, int *builtinnum, char *funcname, size_t funcnamesize)
static pbool PDECL PR_GetFunctionInfo(pubprogfuncs_t *ppf, func_t func, int *args, int *builtinnum, char *funcname, size_t funcnamesize)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
@ -697,7 +697,7 @@ func_t PDECL PR_FindFunc(pubprogfuncs_t *ppf, const char *funcname, progsnum_t p
return 0;
}
void PDECL QC_FindPrefixedGlobals(pubprogfuncs_t *ppf, int pnum, char *prefix, void (PDECL *found) (pubprogfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type, void *ctx), void *ctx)
static void PDECL QC_FindPrefixedGlobals(pubprogfuncs_t *ppf, int pnum, char *prefix, void (PDECL *found) (pubprogfuncs_t *progfuncs, char *name, union eval_s *val, etype_t type, void *ctx), void *ctx)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
unsigned int i;
@ -795,7 +795,7 @@ eval_t *PDECL PR_FindGlobal(pubprogfuncs_t *ppf, const char *globname, progsnum_
return NULL;
}
char *PDECL PR_VarString (pubprogfuncs_t *ppf, int first)
static char *PDECL PR_VarString (pubprogfuncs_t *ppf, int first)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
int i;
@ -816,7 +816,7 @@ char *PDECL PR_VarString (pubprogfuncs_t *ppf, int first)
return out;
}
int PDECL PR_QueryField (pubprogfuncs_t *ppf, unsigned int fieldoffset, etype_t *type, char const**name, evalc_t *fieldcache)
static int PDECL PR_QueryField (pubprogfuncs_t *ppf, unsigned int fieldoffset, etype_t *type, char const**name, evalc_t *fieldcache)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
fdef_t *var;
@ -868,7 +868,7 @@ eval_t *PDECL QC_GetEdictFieldValue(pubprogfuncs_t *ppf, struct edict_s *ed, con
return (eval_t *) &(((int*)(((edictrun_t*)ed)->fields))[cache->ofs32->ofs]);
}
struct edict_s *PDECL ProgsToEdict (pubprogfuncs_t *ppf, int progs)
static struct edict_s *PDECL ProgsToEdict (pubprogfuncs_t *ppf, int progs)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if ((unsigned)progs >= (unsigned)prinst.maxedicts)
@ -883,7 +883,7 @@ struct edict_s *PDECL ProgsToEdict (pubprogfuncs_t *ppf, int progs)
}
return (struct edict_s *)PROG_TO_EDICT_PB(progfuncs.inst, progs);
}
int PDECL EdictToProgs (pubprogfuncs_t *ppf, struct edict_s *ed)
static int PDECL EdictToProgs (pubprogfuncs_t *ppf, struct edict_s *ed)
{
// progfuncs_t *progfuncs = (progfuncs_t*)ppf;
return EDICT_TO_PROG(progfuncs, ed);
@ -935,7 +935,7 @@ string_t PDECL PR_StringToProgs (pubprogfuncs_t *ppf, const char *str)
return (string_t)((unsigned int)i | STRING_STATIC);
}
//if ed is null, fld points to a global. if str_is_static, then s doesn't need its own memory allocated.
void PDECL PR_SetStringField(pubprogfuncs_t *progfuncs, struct edict_s *ed, string_t *fld, const char *str, pbool str_is_static)
static void PDECL PR_SetStringField(pubprogfuncs_t *progfuncs, struct edict_s *ed, string_t *fld, const char *str, pbool str_is_static)
{
if (!str)
*fld = 0;
@ -951,7 +951,7 @@ void PDECL PR_SetStringField(pubprogfuncs_t *progfuncs, struct edict_s *ed, stri
}
}
char *PDECL PR_RemoveProgsString (pubprogfuncs_t *ppf, string_t str)
static char *PDECL PR_RemoveProgsString (pubprogfuncs_t *ppf, string_t str)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
char *ret;
@ -1110,7 +1110,7 @@ void QCBUILTIN PF_memsetval (pubprogfuncs_t *inst, struct globalvars_s *globals)
}
string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
static string_t PDECL PR_AllocTempStringLen (pubprogfuncs_t *ppf, char **str, unsigned int len)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
tempstr_t **ntable;
@ -1319,7 +1319,7 @@ static void PR_FreeAllTemps (progfuncs_t *progfuncs)
prinst.numtempstrings = 0;
prinst.nexttempstring = 0;
}
pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles)
static pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
struct progstate_s *ps;
@ -1391,7 +1391,7 @@ static void PDECL PR_CloseProgs(pubprogfuncs_t *ppf);
static void PDECL RegisterBuiltin(pubprogfuncs_t *progfncs, const char *name, builtin_t func);
pubprogfuncs_t deffuncs = {
static pubprogfuncs_t deffuncs = {
PROGSTRUCT_VERSION,
PR_CloseProgs,
PR_Configure,
@ -1510,11 +1510,11 @@ static void PDECL qclib_free(void *ptr)
#endif
//defs incase following structure is not passed.
struct edict_s *safesv_edicts;
int safesv_num_edicts;
double safetime=0;
static struct edict_s *safesv_edicts;
static int safesv_num_edicts;
static double safetime=0;
progexterns_t defexterns = {
static progexterns_t defexterns = {
PROGSTRUCT_VERSION,
NULL, //char *(*ReadFile) (char *fname, void *buffer, int len);

View file

@ -10451,9 +10451,14 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"bprint", PF_bprint, 0, 23, 0, 0, D("void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)", "QW: Concatenates all string arguments, and prints the messsage on the console of only all clients who's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument.")},
{"sprint", PF_sprint, 24, 0, 24, 0, D("void(entity client, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)", "NQ: Concatenates all string arguments, and prints the messsage on the named client's console")},
{"sprint", PF_sprint, 0, 24, 0, 0, D("void(entity client, float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6)", "QW: Concatenates all string arguments, and prints the messsage on the named client's console, but only if that client's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument.")},
#ifdef HAVE_LEGACY
//these have subtly different behaviour, and are implemented using different internal builtins, which is a bit weird in the extensions file. documentation is documentation.
{"dprint", PF_dprint, 25, 0, 25, 0, D("void(string s, ...)", "NQ: Prints the given message on the server's console, but only if the developer cvar is set. Arguments will be concatenated into a single message.")},
{"dprint", PF_print, 0, 25, 0, 0, D("void(string s, ...)", "QW: Unconditionally prints the given message on the server's console. Arguments will be concatenated into a single message.")},
#else
//going forward, we have print and dprint
{"dprint", PF_dprint, 25, 25, 25, 0, D("void(string s, ...)", "NQ: Prints the given message on the server's console, but only if the developer cvar is set. Arguments will be concatenated into a single message.")},
#endif
{"ftos", PF_ftos, 26, 26, 26, 0, D("string(float val)", "Returns a tempstring containing a representation of the given float. Precision depends upon engine.")},
{"vtos", PF_vtos, 27, 27, 27, 0, D("string(vector val)", "Returns a tempstring containing a representation of the given vector. Precision depends upon engine.")},
{"coredump", PF_coredump, 28, 28, 28, 0, D("void()", "Writes out a coredump. This contains stack, globals, and field info for all ents. This can be handy for debugging.")},

View file

@ -565,7 +565,10 @@ void SV_Map_f (void)
#ifdef Q3SERVER
q3singleplayer = !strcmp(Cmd_Argv(0), "spmap");
#endif
flushparms = !strcmp(Cmd_Argv(0), "map") || !strcmp(Cmd_Argv(0), "spmap");
if ((svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) && progstype == PROG_QW)
flushparms = !strcmp(Cmd_Argv(0), "spmap"); //quakeworld's map command preserves spawnparms.
else
flushparms = !strcmp(Cmd_Argv(0), "map") || !strcmp(Cmd_Argv(0), "spmap"); //[sp]map flushes in nq+h2+q2+etc
#ifdef SAVEDGAMES
newunit = flushparms || (!strcmp(Cmd_Argv(0), "changelevel") && !startspot);
q2savetos0 = !strcmp(Cmd_Argv(0), "gamemap") && !isDedicated; //q2
@ -1910,7 +1913,10 @@ static void SV_Status_f (void)
#if defined(HAVE_SSL)
extern cvar_t net_enable_tls;
#endif
extern cvar_t net_enable_http, net_enable_webrtcbroker, net_enable_websockets, net_enable_qizmo, net_enable_qtv;
#ifdef HAVE_HTTPSV
extern cvar_t net_enable_http, net_enable_webrtcbroker, net_enable_websockets;
#endif
extern cvar_t net_enable_qizmo, net_enable_qtv;
#endif
#ifdef NQPROT
extern cvar_t sv_listen_nq, sv_listen_dp;
@ -1990,12 +1996,14 @@ static void SV_Status_f (void)
if (net_enable_tls.ival)
Con_Printf(" TLS");
#endif
#ifdef HAVE_HTTPSV
if (net_enable_http.ival)
Con_Printf(" HTTP");
if (net_enable_webrtcbroker.ival)
Con_Printf(" WebRTC");
if (net_enable_websockets.ival)
Con_Printf(" WS");
#endif
if (net_enable_qizmo.ival)
Con_Printf(" QZ");
if (net_enable_qtv.ival)

View file

@ -3140,13 +3140,27 @@ client_t *SVC_DirectConnect(void)
else
#endif
newcl->netchan.compresstable = NULL;
newcl->netchan.pext_fragmentation = mtu?true:false;
//this is the upper bound of the mtu, if its too high we'll get EMSGSIZE and we'll reduce it.
//however, if it drops below newcl->netchan.message.maxsize then we'll start to see undeliverable reliables, which means dropped clients.
newcl->netchan.mtu = MAX_DATAGRAM; //vanilla qw clients are assumed to have an mtu of this size.
if (mtu >= 64)
{ //if we support application fragmenting, then we can send massive reliables without too much issue
newcl->netchan.fragmentsize = mtu;
newcl->netchan.mtu = mtu;
newcl->netchan.message.maxsize = sizeof(newcl->netchan.message_buf);
}
else //otherwise we can't fragment the packets, and the only way to honour the mtu is to send less data. yay for more round-trips.
newcl->netchan.message.maxsize = min(newcl->netchan.message.maxsize, max(net_mtu.ival, 512));
{
mtu = atoi(Info_ValueForKey (userinfo[0], "mtu"));
if (mtu)
newcl->netchan.mtu = mtu; //locked mtu size, because not everyone has a working connection (we need icmp would-fragment responses for mtu detection)
else //if its not set then use some 'safe' fallback.
mtu = MAX_BACKBUFLEN; //MAX_BACKBUFLEN of 1200 is < ipv6 required segment size so should always work for reliables.
//enforce some boundaries
mtu = bound(512-8, mtu, sizeof(newcl->netchan.message_buf));
newcl->netchan.message.maxsize = mtu;
}
Con_DLPrintf(2, "MTU size: %i - %i\n", newcl->netchan.message.maxsize, newcl->netchan.mtu);
newcl->protocol = protocol;
#ifdef NQPROT

View file

@ -35,7 +35,7 @@ void ClientReliableCheckBlock(client_t *cl, int maxsize)
memset(&cl->backbuf, 0, sizeof(cl->backbuf));
cl->backbuf.allowoverflow = true;
cl->backbuf.data = cl->backbuf_data[0];
cl->backbuf.maxsize = sizeof(cl->backbuf_data[0]);
cl->backbuf.maxsize = min(cl->netchan.message.maxsize, sizeof(cl->backbuf_data[0]));
cl->backbuf_size[0] = 0;
cl->num_backbuf++;
}
@ -54,7 +54,7 @@ void ClientReliableCheckBlock(client_t *cl, int maxsize)
memset(&cl->backbuf, 0, sizeof(cl->backbuf));
cl->backbuf.allowoverflow = true;
cl->backbuf.data = cl->backbuf_data[cl->num_backbuf];
cl->backbuf.maxsize = sizeof(cl->backbuf_data[cl->num_backbuf]);
cl->backbuf.maxsize = min(cl->netchan.message.maxsize, sizeof(cl->backbuf_data[cl->num_backbuf]));
cl->backbuf_size[cl->num_backbuf] = 0;
cl->num_backbuf++;
}

View file

@ -2573,13 +2573,15 @@ qboolean SV_SendClientDatagram (client_t *client)
client->edict->v->goalentity = 0;
}
if (client->netchan.fragmentsize)
if (client->netchan.pext_fragmentation)
{
if (client->netchan.remote_address.type == NA_LOOPBACK)
clientlimit = countof(buf); //biiiig...
else
clientlimit = client->netchan.fragmentsize; //try not to overflow
clientlimit = client->netchan.mtu; //try not to overflow
}
else if (client->netchan.mtu)
clientlimit = client->netchan.mtu;
else if (client->protocol == SCP_NETQUAKE)
clientlimit = MAX_NQDATAGRAM; //vanilla client is limited.
else
@ -3411,7 +3413,7 @@ void SV_SendClientMessages (void)
memset(&c->backbuf, 0, sizeof(c->backbuf));
c->backbuf.data = c->backbuf_data[c->num_backbuf - 1];
c->backbuf.cursize = c->backbuf_size[c->num_backbuf - 1];
c->backbuf.maxsize = sizeof(c->backbuf_data[c->num_backbuf - 1]);
c->backbuf.maxsize = min(c->netchan.message.maxsize, sizeof(c->backbuf_data[c->num_backbuf-1]));
}
}
}
@ -3526,6 +3528,9 @@ void SV_SendClientMessages (void)
c->datagram.cursize = 0;
}
c->lastoutgoingphysicstime = sv.world.physicstime;
if (c->netchan.fatal_error)
c->drop = true;
}
#ifdef MVD_RECORDING
if (sv.mvdrecording)

View file

@ -987,12 +987,12 @@ void SV_SendClientPrespawnInfo(client_t *client)
return;
}
//just because we CAN generate huge messages doesn't meant that we should.
//just because we CAN generate huge messages doesn't mean that we should.
//try to keep packets within reasonable sizes so that we don't trigger insane burst+packetloss on map changes.
maxsize = client->netchan.message.maxsize/2;
if (client->netchan.fragmentsize && maxsize > client->netchan.fragmentsize-200)
if (client->netchan.mtu && maxsize > client->netchan.mtu-200)
{
maxsize = client->netchan.fragmentsize-200;
maxsize = client->netchan.mtu-200;
if (maxsize < 500)
maxsize = 500;
}
@ -1933,7 +1933,6 @@ void SVQW_Spawn_f (void)
// when that is completed, a begin command will be issued
ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
ClientReliableWrite_String (host_client, "skins\n" );
}
/*
@ -7733,6 +7732,8 @@ void SV_ReadQCRequest(void)
done:
args[i] = 0;
rname = MSG_ReadString();
//We used to use Cmd_foo_args, but that conflicts with a zquake extension and would cause [e]zquake mods that use it to be remotely exploitable (mostly crashes from uninitialised args though).
//Instead, we've switched to some more weird prefix that's much less likly to conflict.
if (i)
fname = va("CSEv_%s_%s", rname, args);
else if (strchr(rname, '_')) //this is awkward, as not forcing an underscore would allow people to mis-call things with lingering data (the alternative is to block underscores entirely).
@ -7749,7 +7750,10 @@ done:
rname = va("Cmd_%s", rname);
f = PR_FindFunction(svprogfuncs, rname, PR_ANY);
if (f)
SV_ClientPrintf(host_client, PRINT_HIGH, "the name \"%s\" is deprecated\n", rname);
{
SV_ClientPrintf(host_client, PRINT_HIGH, "\"%s\" is no longer supported.\n", rname);
f = 0;
}
}
#endif
if (host_client->drop)

View file

@ -809,6 +809,10 @@ static void QDECL PFQ2_SetAreaPortalState(unsigned int p, qboolean s)
CMQ2_SetAreaPortalState(sv.world.worldmodel, p, s);
}
static void *VARGS ZQ2_TagMalloc(int size, int tag)
{
return Z_TagMalloc(size, tag);
}
qboolean SVQ2_InitGameProgs(void)
{
extern cvar_t maxclients;
@ -862,7 +866,7 @@ qboolean SVQ2_InitGameProgs(void)
import.WriteDir = PFQ2_WriteDir;
import.WriteAngle = PFQ2_WriteAngle;
import.TagMalloc = Z_TagMalloc;
import.TagMalloc = ZQ2_TagMalloc;
import.TagFree = Z_TagFree;
import.FreeTags = Z_FreeTags;

View file

@ -30,7 +30,7 @@
//must support skeletal and 2-way vertex blending or Bad Things Will Happen.
//the vertex shader is responsible for calculating lighting values.
#if gl_affinemodels==1 && __VERSION__ >= 130
#if gl_affinemodels==1 && __VERSION__ >= 130 && !defined(GL_ES)
#define affine noperspective
#else
#define affine

View file

@ -9,11 +9,17 @@
!!permu REFLECTCUBEMASK
!!cvarf r_glsl_offsetmapping_scale
!!cvardf r_tessellation_level=5
!!samps !EIGHTBIT diffuse specular normalmap fullbright reflectmask reflectcube
!!samps diffuse
!!samps !EIGHTBIT =FULLBRIGHT fullbright
!!samps !EIGHTBIT =BUMP normalmap
!!samps !EIGHTBIT =REFLECTCUBEMASK reflectmask reflectcube
//diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
!!samps =EIGHTBIT paletted 1 specular diffuse
!!samps lightmap deluxemap
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3
!!samps =EIGHTBIT paletted 1
!!samps =SPECULAR specular
!!samps lightmap
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3
!!samps =DELUXE deluxmap
!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3
#if defined(ORM) || defined(SG)
#define PBR
@ -299,7 +305,7 @@ void main ()
vec3 deluxe = (texture2D(s_deluxemap, lm0).rgb-0.5);
#ifdef BUMPMODELSPACE
deluxe = normalize(deluxe*invsurface);
#else
#else
deluxe = normalize(deluxe);
lightmaps *= 2.0 / max(0.25, deluxe.z); //counter the darkening from deluxemaps
#endif
@ -370,7 +376,6 @@ void main ()
#else
//now we have our diffuse+specular terms, modulate by lightmap values.
col.rgb *= lightmaps.rgb;
//add on the fullbright
#ifdef FULLBRIGHT
col.rgb += texture2D(s_fullbright, tc).rgb;

View file

@ -1,7 +1,8 @@
!!ver 100 300
!!permu FOG
//t0-t3 are the diffusemaps, t4 is the blend factors
!!samps 4
!!samps mix=4
//RTLIGHT (+PCF,CUBE,SPOT,etc)
!!samps tr=0 tg=1 tb=2 tx=3 //the four texturemaps
!!samps mix=4 //how the ground is blended
!!samps =PCF shadowmap
!!samps =CUBE projectionmap
@ -98,10 +99,12 @@ void main (void)
vec4 r;
vec4 m = texture2D(s_mix, lm);
r = texture2D(s_t0, tc)*m.r;
r += texture2D(s_t1, tc)*m.g;
r += texture2D(s_t2, tc)*m.b;
r += texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b));
r = texture2D(s_tr, tc)*m.r;
r += texture2D(s_tg, tc)*m.g;
r += texture2D(s_tb, tc)*m.b;
r += texture2D(s_tx, tc)*(1.0 - (m.r + m.g + m.b));
r.rgb *= 1.0/r.a; //fancy maths, so low alpha values give other textures a greater focus
//vertex colours provide a scaler that applies even through rtlights.
r *= vc;