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); Q_snprintfz(name, sizeof(name), "textures/bmodels/simple_%s_%i.tga", basename, ent->skinnum);
else else
Q_snprintfz(name, sizeof(name), "textures/models/simple_%s_%i.tga", basename, ent->skinnum); 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); 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) if (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)
cls.netchan.qportsize = 1; cls.netchan.qportsize = 1;
} }
cls.netchan.fragmentsize = connectinfo.mtu; cls.netchan.pext_fragmentation = connectinfo.mtu?true:false;
if (connectinfo.mtu >= 64) if (connectinfo.mtu >= 64)
{
cls.netchan.mtu = connectinfo.mtu;
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf); cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
}
else
cls.netchan.mtu = MAX_QWMSGLEN;
#ifdef HUFFNETWORK #ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc); cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.compresscrc);
#else #else
@ -6396,7 +6401,12 @@ void Host_FinishLoading(void)
FS_ChangeGame(NULL, true, true); FS_ChangeGame(NULL, true, true);
if (waitingformanifest) if (waitingformanifest)
{
#ifdef MULTITHREAD
Sys_Sleep(0.1);
#endif
return; return;
}
Con_History_Load(); Con_History_Load();
@ -6437,7 +6447,12 @@ void Host_FinishLoading(void)
} }
if (PM_IsApplying(true)) if (PM_IsApplying(true))
{
#ifdef MULTITHREAD
Sys_Sleep(0.1);
#endif
return; return;
}
//android may find that it has no renderer at various points. //android may find that it has no renderer at various points.
if (r_forceheadless) 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. 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. //any file-conflicts prevent the package from being installable.
//this is mostly for pak1.pak //this is mostly for pak1.pak
for (dep = package->deps; dep; dep = dep->next) 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)) if (*p->title && strcmp(p->title, p->name))
{ {
Q_strncatz(buf, " ", sizeof(buf)); 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) if (*p->version)
{ {
@ -2745,7 +2754,6 @@ qboolean PM_CanInstall(const char *packagename)
void PM_Command_f(void) void PM_Command_f(void)
{ {
size_t i;
package_t *p; package_t *p;
const char *act = Cmd_Argv(1); const char *act = Cmd_Argv(1);
const char *key; const char *key;
@ -2878,6 +2886,7 @@ void PM_Command_f(void)
} }
Con_Printf("<end of list>\n"); Con_Printf("<end of list>\n");
} }
#ifdef WEBCLIENT
else if (!strcmp(act, "sources") || !strcmp(act, "addsource")) else if (!strcmp(act, "sources") || !strcmp(act, "addsource"))
{ {
if (Cmd_Argc() == 2) if (Cmd_Argc() == 2)
@ -2890,6 +2899,7 @@ void PM_Command_f(void)
else else
PM_AddSubList(Cmd_Argv(2), "", true, true); PM_AddSubList(Cmd_Argv(2), "", true, true);
} }
#endif
else if (!strcmp(act, "remsource")) else if (!strcmp(act, "remsource"))
PM_RemSubList(Cmd_Argv(2)); PM_RemSubList(Cmd_Argv(2));
else if (!strcmp(act, "apply")) else if (!strcmp(act, "apply"))
@ -2908,8 +2918,10 @@ void PM_Command_f(void)
{ {
PM_RevertChanges(); PM_RevertChanges();
} }
#ifdef WEBCLIENT
else if (!strcmp(act, "update")) else if (!strcmp(act, "update"))
{ //flush package cache, make a new request. { //flush package cache, make a new request.
int i;
for (i = 0; i < numdownloadablelists; i++) for (i = 0; i < numdownloadablelists; i++)
downloadablelist[i].received = 0; downloadablelist[i].received = 0;
} }
@ -2924,6 +2936,7 @@ void PM_Command_f(void)
else else
Con_Printf("Already using latest versions of all packages\n"); 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")) else if (!strcmp(act, "add") || !strcmp(act, "get") || !strcmp(act, "install") || !strcmp(act, "enable"))
{ //FIXME: make sure this updates. { //FIXME: make sure this updates.
int arg = 2; int arg = 2;
@ -2938,6 +2951,7 @@ void PM_Command_f(void)
} }
PM_PrintChanges(); PM_PrintChanges();
} }
#ifdef WEBCLIENT
else if (!strcmp(act, "reinstall")) else if (!strcmp(act, "reinstall"))
{ //fixme: favour the current verson. { //fixme: favour the current verson.
int arg = 2; int arg = 2;
@ -2955,6 +2969,7 @@ void PM_Command_f(void)
} }
PM_PrintChanges(); PM_PrintChanges();
} }
#endif
else if (!strcmp(act, "disable") || !strcmp(act, "rem") || !strcmp(act, "remove")) else if (!strcmp(act, "disable") || !strcmp(act, "rem") || !strcmp(act, "remove"))
{ {
int arg = 2; 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_USERMARKED:
case DPF_MARKED: case DPF_MARKED:
p->flags |= DPF_PURGE; p->flags |= DPF_PURGE;
#ifdef WEBCLIENT
//now: re-get despite already having it. //now: re-get despite already having it.
if ((p->flags & DPF_CORRUPT) || ((p->flags & DPF_PRESENT) && !PM_PurgeOnDisable(p))) 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. break; //only makes sense if we already have a cached copy that we're not going to use.
#endif
//fallthrough //fallthrough
case DPF_USERMARKED|DPF_PURGE: case DPF_USERMARKED|DPF_PURGE:
case DPF_AUTOMARKED|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; dlmenu_t *info = m->data;
int i, y; int i, y;
package_t *p; 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; menuoption_t *si;
menubutton_t *b, *d; menubutton_t *b, *d;
#ifdef WEBCLIENT
unsigned int downloads=0;
menucustom_t *c; menucustom_t *c;
#endif
if (info->downloadablessequence != downloadablessequence || !info->populated) if (info->downloadablessequence != downloadablessequence || !info->populated)
{ {

View file

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

View file

@ -306,15 +306,15 @@ static void S_Info(void);
static void S_Shutdown_f(void); static void S_Shutdown_f(void);
*/ */
static cvar_t s_al_debug = CVAR("s_al_debug", "0"); static cvar_t s_al_debug = CVARD("s_al_debug", "0", "Enables periodic checks for OpenAL errors.");
static cvar_t s_al_use_reverb = CVAR("s_al_use_reverb", "1"); 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_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_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 = CVARFC("s_al_dopplerfactor", "1.0",0,OnChangeALSettings); 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 = CVARFC("s_al_distancemodel", "2",0,OnChangeALSettings); 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_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_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 = CVAR("s_al_velocityscale", "1"); 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 static cvar_t s_al_static_listener = CVAR("s_al_static_listener", "0"); //cheat
extern cvar_t snd_doppler; 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_dopplerfactor, SOUNDVARS);
Cvar_Register(&s_al_distancemodel, SOUNDVARS); Cvar_Register(&s_al_distancemodel, SOUNDVARS);
Cvar_Register(&s_al_reference_distance, 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_velocityscale, SOUNDVARS);
Cvar_Register(&s_al_static_listener, SOUNDVARS); Cvar_Register(&s_al_static_listener, SOUNDVARS);
Cvar_Register(&s_al_speedofsound, 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__) #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 //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*)((ucontext_t*)vcontext)->uc_mcontext.gregs[REG_EIP];
array[1] = (void*)uc->uc_mcontext.gregs[REG_EIP];
firstframe = 1; firstframe = 1;
#elif defined(__amd64__) #elif defined(__amd64__)
//amd64 is sane enough, but this function and the libc signal handler are on the stack, and should be ignored. //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 #endif
TL_InitLanguages(parms.binarydir); TL_InitLanguages(parms.binarydir);
if (!isatty(STDIN_FILENO)) 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). 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 else

View file

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

View file

@ -52,7 +52,8 @@ typedef struct
#endif #endif
qboolean loop; qboolean loop;
int numposes; int numposes;
float rate; //float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1]
float rate; //average framerate of animation.
#ifdef NONSKELETALMODELS #ifdef NONSKELETALMODELS
galiaspose_t *poseofs; galiaspose_t *poseofs;
#endif #endif
@ -219,7 +220,7 @@ typedef struct modplugfuncs_s
void (QDECL *UnRegisterModelFormat)(int idx); void (QDECL *UnRegisterModelFormat)(int idx);
void (QDECL *UnRegisterAllModelFormats)(void); 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 *ConcatTransforms) (const float in1[3][4], const float in2[3][4], float out[3][4]);
void (QDECL *M3x4_Invert) (const float *in1, float *out); 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_SERVERINFO_STRING 1024 //standard quake has 512 here.
#define MAX_LOCALINFO_STRING 32768 #define MAX_LOCALINFO_STRING 32768
#ifdef HAVE_LEGACY
#define legacyval(_legval,_newval) _legval
#else
#define legacyval(_legval,_newval) _newval
#endif
#ifdef HAVE_CLIENT #ifdef HAVE_CLIENT
#define cls_state cls.state #define cls_state cls.state
#else #else
@ -448,7 +455,7 @@ struct cache_user_s;
extern char com_gamepath[MAX_OSPATH]; extern char com_gamepath[MAX_OSPATH];
extern char com_homepath[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; //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. //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 HAVE_WINSSPI //on windows
#define FTPSERVER //sv_ftp cvar. #define FTPSERVER //sv_ftp cvar.
#define WEBCLIENT //uri_get+any internal downloads etc #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 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 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. #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_WATCHED (1<<22) //report any attempts to change this cvar.
#define CVAR_VIDEOLATCH (1<<23) #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_LATCHMASK (CVAR_LATCH|CVAR_RENDERERLATCH|CVAR_SERVEROVERRIDE|CVAR_CHEAT|CVAR_SEMICHEAT) //you're only allowed one of these.
#define CVAR_NEEDDEFAULT CVAR_CHEAT #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 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_gamepath[MAX_OSPATH]; //c:\games\quake
char com_homepath[MAX_OSPATH]; //c:\users\foo\my docs\fte\quake char com_homepath[MAX_OSPATH]; //c:\users\foo\my docs\fte\quake
qboolean com_homepathenabled; qboolean com_homepathenabled;
qboolean com_homepathusable; //com_homepath is safe, even if not enabled. 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_dups;
int fs_hash_files; int fs_hash_files;
@ -737,7 +738,7 @@ static void COM_Path_f (void)
Con_Printf("pubgamedirfile: \"%s\"\n", pubgamedirfile); Con_Printf("pubgamedirfile: \"%s\"\n", pubgamedirfile);
Con_Printf("com_gamepath: \"%s\"\n", com_gamepath); 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_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) if (fs_manifest)
FS_Manifest_Print(fs_manifest); FS_Manifest_Print(fs_manifest);
return; return;
@ -1915,6 +1916,9 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela
fs_accessed_time = realtime; fs_accessed_time = realtime;
if (fs_readonly && *mode == 'w')
return NULL;
if (relativeto == FS_SYSTEM) if (relativeto == FS_SYSTEM)
return VFSOS_Open(filename, mode); return VFSOS_Open(filename, mode);
@ -1937,9 +1941,21 @@ 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. //if there can only be one file (eg: write access) find out where it is.
switch (relativeto) 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; vfs = NULL;
//FIXME: go via a searchpath, because then the fscache can be selectively updated
if (com_homepathenabled) if (com_homepathenabled)
{
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)) if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_homepath, gamedirfile, filename))
return NULL; return NULL;
@ -1947,7 +1963,19 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela
COM_CreatePath(fullname); COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode); vfs = VFSOS_Open(fullname, mode);
} }
}
if (!vfs && *gamedirfile) if (!vfs && *gamedirfile)
{
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)) if (!try_snprintf(fullname, sizeof(fullname), "%s%s/%s", com_gamepath, gamedirfile, filename))
return NULL; return NULL;
@ -1955,6 +1983,7 @@ vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_rela
COM_CreatePath(fullname); COM_CreatePath(fullname);
vfs = VFSOS_Open(fullname, mode); vfs = VFSOS_Open(fullname, mode);
} }
}
if (vfs || !(*mode == 'w' || *mode == 'a')) if (vfs || !(*mode == 'w' || *mode == 'a'))
return vfs; return vfs;
//fall through //fall through
@ -2793,7 +2822,7 @@ Sets com_gamedir, adds the directory to the head of the path,
then loads and adds pak1.pak pak2.pak ... 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; unsigned int keptflags;
searchpath_t *search; searchpath_t *search;
@ -2808,7 +2837,7 @@ static void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, c
if (!Q_strcasecmp(search->logicalpath, dir)) if (!Q_strcasecmp(search->logicalpath, dir))
{ {
search->flags |= flags & SPF_WRITABLE; 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) if (!handle)
handle = VFSOS_OpenPath(NULL, NULL, dir, dir, ""); 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 //if syspath, something like c:\quake\baseq2
@ -3698,7 +3740,6 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
searchpath_t *next; searchpath_t *next;
int i; int i;
int orderkey; int orderkey;
char syspath[MAX_OSPATH];
COM_AssertMainThread("FS_ReloadPackFilesFlags"); COM_AssertMainThread("FS_ReloadPackFilesFlags");
COM_WorkerFullSync(); COM_WorkerFullSync();
@ -3715,6 +3756,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
com_searchpaths = NULL; com_searchpaths = NULL;
com_purepaths = NULL; com_purepaths = NULL;
com_base_searchpaths = NULL; com_base_searchpaths = NULL;
gameonly_gamedir = gameonly_homedir = NULL;
i = COM_CheckParm ("-basepack"); i = COM_CheckParm ("-basepack");
while (i && i < com_argc-1) while (i && i < com_argc-1)
@ -3777,23 +3819,11 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
else if (*dir == '*') else if (*dir == '*')
{ {
//paths with a leading * are private, and not announced to clients that ask what the current gamedir is. //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, reloadflags, SPF_EXPLICIT|SPF_PRIVATE|SPF_WRITABLE);
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);
}
} }
else else
{ {
Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, dir); FS_AddGameDirectory(&oldpaths, dir, reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
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);
}
} }
} }
} }
@ -3823,9 +3853,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
} }
else else
{ {
FS_AddGameDirectory(&oldpaths, dir, va("%s%s", com_gamepath, dir), reloadflags, SPF_EXPLICIT|(com_homepathenabled?0:SPF_WRITABLE)); FS_AddGameDirectory(&oldpaths, dir, reloadflags, SPF_EXPLICIT|SPF_WRITABLE);
if (com_homepathenabled)
FS_AddGameDirectory(&oldpaths, dir, va("%s%s", com_homepath, 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 //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. //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 //new installs use $XDG_DATA_HOME/#HOMESUBDIR/ instead
char *ev = getenv("FTEHOME"); char *ev = getenv("FTEHOME");
if (ev && *ev) 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 *PollChanges)(searchpathfuncs_t *handle); //returns true if there were changes
qboolean (QDECL *FileStat)(searchpathfuncs_t *handle, flocation_t *loc, time_t *mtime); 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 *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 //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_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_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_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_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). #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); 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; sp->AddFileHash = AddFileHash;
Sys_EnumerateFiles(sp->rootpath, "*", FSSTDIO_RebuildFSHash, AddFileHash, handle); 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) static unsigned int QDECL FSSTDIO_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult)
{ {
stdiopath_t *sp = (void*)handle; 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 // 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 #ifdef ANDROID
{ {
@ -378,6 +403,7 @@ searchpathfuncs_t *QDECL FSSTDIO_OpenPath(vfsfile_t *mustbenull, searchpathfuncs
np->pub.OpenVFS = FSSTDIO_OpenVFS; np->pub.OpenVFS = FSSTDIO_OpenVFS;
np->pub.PollChanges = FSSTDIO_PollChanges; np->pub.PollChanges = FSSTDIO_PollChanges;
np->pub.FileStat = FSSTDIO_FileStat; np->pub.FileStat = FSSTDIO_FileStat;
np->pub.CreateFile = FSSTDIO_CreateLoc;
return &np->pub; return &np->pub;
} }

View file

@ -522,6 +522,30 @@ static void QDECL VFSW32_BuildHash(searchpathfuncs_t *handle, int hashdepth, voi
wp->hashdepth = hashdepth; wp->hashdepth = hashdepth;
Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, AddFileHash, handle); 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> #include <errno.h>
static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult) static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t *loc, const char *filename, void *hashedresult)
{ {
@ -545,7 +569,8 @@ static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t
*/ */
// check a file in the directory tree // 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) 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); snprintf (syspath, sizeof(syspath)-1, "%s/%s", wp->rootpath, filename);
return Sys_remove(syspath); 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) 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; np->pub.FileStat = VFSW32_FileStat;
#undef CreateFile //stoopid windows.h
np->pub.CreateFile = VFSW32_CreateLoc;
np->pub.RenameFile = VFSW32_RenameFile; np->pub.RenameFile = VFSW32_RenameFile;
np->pub.RemoveFile = VFSW32_RemoveFile; np->pub.RemoveFile = VFSW32_RemoveFile;
np->pub.MkDir = VFSW32_MkDir;
return &np->pub; return &np->pub;
} }

View file

@ -313,7 +313,8 @@ typedef struct
{ {
struct struct
{ {
int cp[2]; unsigned short cp[2];
unsigned short fixedres[2];
} patch; } patch;
struct struct
{ {
@ -527,7 +528,7 @@ static int Patch_FlatnessTest( float maxflat2, const float *point0, const float
Patch_GetFlatness 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; int i, p, u, v;
float maxflat2 = maxflat * maxflat; float maxflat2 = maxflat * maxflat;
@ -579,7 +580,7 @@ static void Patch_Evaluate_QuadricBezier( float t, const vec_t *point0, const ve
Patch_Evaluate 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 num_patches[2], num_tess[2];
int index[3], dstpitch, i, u, v, x, y; 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 * 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 step[2], size[2], flat[2];
int i, j, k ,u, v; 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++; checkout[facenum] = prv->numpatches++;
//gcc warns without this cast //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->contents |= patch->surface->c.value;
leaf->numleafpatches++; leaf->numleafpatches++;
@ -2554,8 +2555,12 @@ static qboolean CModRBSP_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l)
if (out->facetype == MST_PATCH) if (out->facetype == MST_PATCH)
{ {
out->patch.cp[0] = LittleLong ( in->patchwidth ); unsigned int w = LittleLong ( in->patchwidth );
out->patch.cp[1] = LittleLong ( in->patchheight ); 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 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) 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; float subdivlevel;
patch_cp[0] = patchwidth; patch_cp[0] = patchwidth&0xffff;
patch_cp[1] = patchheight; patch_cp[1] = patchheight&0xffff;
if (patch_cp[0] <= 0 || patch_cp[1] <= 0 ) 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) 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; 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; index_t *indexes;
float subdivlevel; float subdivlevel;
int sty; int sty;
patch_cp[0] = patchwidth; patch_cp[0] = patchwidth&0xffff;
patch_cp[1] = patchheight; patch_cp[1] = patchheight&0xffff;
if (patch_cp[0] <= 0 || patch_cp[1] <= 0 ) 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 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 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 #endif
qboolean pext_fragmentation; //fte's packet fragmentation extension, to avoid issues with low mtus.
struct netprim_s netprim; struct netprim_s netprim;
int fragmentsize; int mtu; //the path mtu, if known
int dupe; int dupe; //how many times to dupe packets
float last_received; // for timeouts float last_received; // for timeouts

View file

@ -716,7 +716,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
// write the packet header // write the packet header
send.data = send_buf; send.data = send_buf;
send.maxsize = MAX_QWMSGLEN + PACKET_HEADER; send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER;
send.cursize = 0; send.cursize = 0;
w1 = chan->outgoing_sequence | (send_reliable<<31); w1 = chan->outgoing_sequence | (send_reliable<<31);
@ -738,9 +738,9 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
} }
#endif #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; send.maxsize = MAX_OVERALLMSGLEN + PACKET_HEADER;
MSG_WriteShort(&send, 0); 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 // copy the reliable message to the packet first
if (send_reliable) 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); SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
chan->last_reliable_sequence = chan->outgoing_sequence; 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) if (chan->compresstable)
{ {
//int oldsize = send.cursize; //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); // Con_Printf("%i becomes %i\n", oldsize, send.cursize);
// Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8); // 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*/ 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++) for (i = -1; i < chan->dupe && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address); e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
send.cursize += send.cursize * i; 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); Con_Printf("Reducing MSS to %i\n", chan->mtu);
chan->fragmentsize -= 10; chan->mtu -= 10;
} }
} }
else else
{ { //fte's fragmentaton protocol
int offset = 0, no; int offset = 0, no;
qboolean more; 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*/ /*send the additional parts, adding new headers within the previous packet*/
do do
{ {
no = offset + chan->fragmentsize - hsz; no = offset + chan->mtu - hsz;
if (no < send.cursize-hsz) if (no < send.cursize-hsz)
{ {
no &= ~7; 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++) for (i = -1; i < chan->dupe && e == NETERR_SENT; i++)
{ {
e = NET_SendPacket (chan->sock, (no - offset) + hsz, send.data + offset, &chan->remote_address); 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; chan->mtu -= 16;
Con_Printf("Reducing MSS to %i\n", chan->fragmentsize); Con_Printf("Reducing MSS to %i\n", chan->mtu);
no = offset; no = offset;
more = true; more = true;
break; break;
@ -917,7 +931,7 @@ qboolean Netchan_Process (netchan_t *chan)
MSG_ReadShort (); MSG_ReadShort ();
#endif #endif
if (chan->fragmentsize) if (chan->pext_fragmentation)
offset = (unsigned short)MSG_ReadShort(); offset = (unsigned short)MSG_ReadShort();
else else
offset = 0; offset = 0;

View file

@ -101,9 +101,9 @@ FTE_ALIGN(4) qbyte net_message_buffer[MAX_OVERALLMSGLEN];
#define HAVE_NATPMP #define HAVE_NATPMP
#endif #endif
#if defined(HAVE_SERVER) || defined(MASTERONLY) //#if !defined(HAVE_SERVER) && !defined(MASTERONLY)
#define HAVE_HTTPSV // #undef HAVE_HTTPSV
#endif //#endif
void NET_GetLocalAddress (int socket, netadr_t *out); void NET_GetLocalAddress (int socket, netadr_t *out);
//int TCP_OpenListenSocket (const char *localip, int port); //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) #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."); 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 #endif
#ifdef HAVE_HTTPSV
#ifdef SV_MASTER #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."); 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 #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_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."); 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
#endif
#if defined(HAVE_DTLS) && defined(HAVE_SERVER) #if defined(HAVE_DTLS) && defined(HAVE_SERVER)
static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue) 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_UNKNOWN, //waiting to see what they send us.
TCPC_QIZMO, //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length. TCPC_QIZMO, //'qizmo\n' handshake, followed by packets prefixed with a 16bit packet length.
#ifdef HAVE_HTTPSV
TCPC_WEBSOCKETU, //utf-8 encoded data. TCPC_WEBSOCKETU, //utf-8 encoded data.
TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary') TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary')
TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake 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_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_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. 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); return FTENET_TCPConnect_HTTPResponse(st, arg, acceptsgzip);
} }
} }
#endif
#ifdef HAVE_SSL #if defined(HAVE_SSL) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV))
static int QDECL TLSPromoteRead (struct vfsfile_s *file, void *buffer, int bytestoread) static int QDECL TLSPromoteRead (struct vfsfile_s *file, void *buffer, int bytestoread)
{ {
if (bytestoread > net_message.cursize) if (bytestoread > net_message.cursize)
@ -4730,7 +4732,6 @@ static int QDECL TLSPromoteRead (struct vfsfile_s *file, void *buffer, int bytes
return bytestoread; return bytestoread;
} }
#endif #endif
#endif
void FTENET_TCPConnect_PrintStatus(ftenet_generic_connection_t *gcon) void FTENET_TCPConnect_PrintStatus(ftenet_generic_connection_t *gcon)
{ {
ftenet_tcpconnect_connection_t *con = (ftenet_tcpconnect_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: case TCPC_QIZMO:
Con_Printf("qizmo %s\n", adr); Con_Printf("qizmo %s\n", adr);
break; break;
#ifdef HAVE_HTTPSV
case TCPC_WEBSOCKETU: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB: case TCPC_WEBSOCKETB:
case TCPC_WEBSOCKETNQ: case TCPC_WEBSOCKETNQ:
Con_Printf("websocket %s\n", adr); Con_Printf("websocket %s\n", adr);
break; break;
#ifdef HAVE_HTTPSV
case TCPC_HTTPCLIENT: case TCPC_HTTPCLIENT:
Con_Printf("http %s\n", adr); Con_Printf("http %s\n", adr);
break; break;
@ -5011,13 +5012,12 @@ closesvstream:
net_from = st->remoteaddr; net_from = st->remoteaddr;
return true; return true;
#ifdef HAVE_HTTPSV
case TCPC_WEBSOCKETU: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB: case TCPC_WEBSOCKETB:
case TCPC_WEBSOCKETNQ: case TCPC_WEBSOCKETNQ:
#ifdef HAVE_HTTPSV
case TCPC_WEBRTC_HOST: case TCPC_WEBRTC_HOST:
case TCPC_WEBRTC_CLIENT: case TCPC_WEBRTC_CLIENT:
#endif
while (st->inlen >= 2) while (st->inlen >= 2)
{ {
unsigned short ctrl = ((unsigned char*)st->inbuffer)[0]<<8 | ((unsigned char*)st->inbuffer)[1]; 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)); Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
} }
#ifdef HAVE_HTTPSV
#ifdef SUPPORT_RTC_ICE #ifdef SUPPORT_RTC_ICE
if (st->clienttype == TCPC_WEBRTC_CLIENT && !*st->webrtc.resource) if (st->clienttype == TCPC_WEBRTC_CLIENT && !*st->webrtc.resource)
{ //this is a client that's corrected directly to us via webrtc. { //this is a client that's corrected directly to us via webrtc.
@ -5203,7 +5202,6 @@ closesvstream:
net_message.cursize = 0; net_message.cursize = 0;
} }
else else
#endif
#ifdef NQPROT #ifdef NQPROT
if (st->clienttype == TCPC_WEBSOCKETNQ) if (st->clienttype == TCPC_WEBSOCKETNQ)
{ //hack in an 8-byte header { //hack in an 8-byte header
@ -5248,6 +5246,7 @@ closesvstream:
} }
} }
break; 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 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_connection_t *con = (ftenet_tcpconnect_connection_t*)gcon;
ftenet_tcpconnect_stream_t *st; ftenet_tcpconnect_stream_t *st;
@ -5333,6 +5331,7 @@ neterr_t FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len
} }
} }
break; break;
#ifdef HAVE_HTTPSV
case TCPC_WEBSOCKETNQ: case TCPC_WEBSOCKETNQ:
if (length < 8 || ((char*)data)[0] & 0x80) if (length < 8 || ((char*)data)[0] & 0x80)
break; break;
@ -5344,10 +5343,13 @@ neterr_t FTENET_TCPConnect_SendPacket(ftenet_generic_connection_t *gcon, int len
//fallthrough //fallthrough
case TCPC_WEBSOCKETU: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB: case TCPC_WEBSOCKETB:
e = FTENET_TCPConnect_WebSocket_Splurge(st, (st->clienttype==TCPC_WEBSOCKETU)?1:2, data, length); {
neterr_t e = FTENET_TCPConnect_WebSocket_Splurge(st, (st->clienttype==TCPC_WEBSOCKETU)?1:2, data, length);
if (e != NETERR_SENT) if (e != NETERR_SENT)
return e; return e;
}
break; break;
#endif
default: default:
break; break;
} }
@ -7877,10 +7879,12 @@ void NET_Init (void)
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
Cvar_Register(&net_enable_tls, "networking"); Cvar_Register(&net_enable_tls, "networking");
#endif #endif
#ifdef HAVE_HTTPSV
Cvar_Register(&net_enable_http, "networking"); Cvar_Register(&net_enable_http, "networking");
Cvar_Register(&net_enable_websockets, "networking"); Cvar_Register(&net_enable_websockets, "networking");
Cvar_Register(&net_enable_webrtcbroker, "networking"); Cvar_Register(&net_enable_webrtcbroker, "networking");
#endif #endif
#endif

View file

@ -125,7 +125,7 @@ void Plug_RegisterBuiltin(char *name, Plug_Builtin_t bi, int flags)
} }
//got an empty number. //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].name = name;
plugbuiltins[newnum].func = bi; plugbuiltins[newnum].func = bi;
plugbuiltins[newnum].flags = flags; 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 //make sure we're fully synced, so that workers can't mess up
Cvar_Set(Cvar_FindVar("worker_count"), "0"); Cvar_Set(Cvar_FindVar("worker_count"), "0");
COM_WorkerFullSync(); COM_WorkerFullSync();
#ifdef WEBCLIENT
DL_DeThread(); DL_DeThread();
#endif
#ifdef SQL #ifdef SQL
SQL_KillServers(); //FIXME: this is bad... SQL_KillServers(); //FIXME: this is bad...
#endif #endif

View file

@ -52,11 +52,11 @@ qbyte sentinalkey;
#define TAGLESS 1 #define TAGLESS 1
int zmemtotal; size_t zmemtotal;
int zmemdelta; size_t zmemdelta;
typedef struct memheader_s { typedef struct memheader_s {
int size; size_t size;
int tag; int tag;
} memheader_t; } memheader_t;
@ -108,13 +108,13 @@ static void Z_DumpTree(void)
} }
#endif #endif
void *VARGS Z_TagMalloc(int size, int tag) void *Z_TagMalloc(size_t size, int tag)
{ {
zone_t *zone; zone_t *zone;
zone = (zone_t *)malloc(size + sizeof(zone_t)); zone = (zone_t *)malloc(size + sizeof(zone_t));
if (!zone) 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)); Q_memset(zone, 0, size + sizeof(zone_t));
zone->mh.tag = tag; zone->mh.tag = tag;
zone->mh.size = size; zone->mh.size = size;
@ -184,7 +184,7 @@ void *Z_MallocNamed(int size, char *file, int line)
return mem; return mem;
} }
#else #else
void *ZF_Malloc(int size) void *ZF_Malloc(size_t size)
{ {
#ifdef ANDROID #ifdef ANDROID
void *ret = NULL; void *ret = NULL;
@ -202,11 +202,11 @@ void *ZF_Malloc(int size)
return calloc(size, 1); return calloc(size, 1);
#endif #endif
} }
void *Z_Malloc(int size) void *Z_Malloc(size_t size)
{ {
void *mem = ZF_Malloc(size); void *mem = ZF_Malloc(size);
if (!mem) 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; return mem;
} }
@ -423,7 +423,7 @@ void *BZF_MallocNamed(int size, const char *file, int line) //BZ_MallocNamed but
return mem; return mem;
} }
#else #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; void *mem;
mem = malloc(size); mem = malloc(size);
@ -446,11 +446,11 @@ void *BZ_MallocNamed(int size, const char *file, int line) //BZ_MallocNamed but
return mem; return mem;
} }
#else #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); void *mem = BZF_Malloc(size);
if (!mem) 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; return mem;
} }
@ -472,17 +472,17 @@ void *BZ_ReallocNamed(void *data, int newsize, const char *file, int line)
return mem; return mem;
} }
#else #else
void *BZF_Realloc(void *data, int newsize) void *BZF_Realloc(void *data, size_t newsize)
{ {
return realloc(data, 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); void *mem = BZF_Realloc(data, newsize);
if (!mem) 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; 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 *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) void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line)
#else #else
void *QDECL ZG_Malloc(zonegroup_t *ctx, int size) void *QDECL ZG_Malloc(zonegroup_t *ctx, size_t size)
#endif #endif
{ {
zonegroupblock_t *newm; zonegroupblock_t *newm;
@ -590,7 +590,7 @@ void Hunk_TempFree(void)
//allocates without clearing previous temp. //allocates without clearing previous temp.
//safer than my hack that fuh moaned about... //safer than my hack that fuh moaned about...
void *Hunk_TempAllocMore (int size) void *Hunk_TempAllocMore (size_t size)
{ {
void *buf; void *buf;
@ -624,7 +624,7 @@ void *Hunk_TempAllocMore (int size)
} }
void *Hunk_TempAlloc (int size) void *Hunk_TempAlloc (size_t size)
{ {
Hunk_TempFree(); Hunk_TempFree();
@ -657,8 +657,8 @@ void Cache_Flush(void)
static void Hunk_Print_f (void) static void Hunk_Print_f (void)
{ {
Con_Printf("Z Delta: %iKB\n", zmemdelta/1024); zmemdelta = 0; Con_Printf("Z Delta: %"PRIuSIZE"KB\n", zmemdelta/1024); zmemdelta = 0;
Con_Printf("Z Total: %iKB\n", zmemtotal/1024); 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 //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. //we don't track reallocs either.

View file

@ -87,12 +87,12 @@ void Memory_Init (void);
void Memory_DeInit(void); void Memory_DeInit(void);
void VARGS Z_Free (void *ptr); void VARGS Z_Free (void *ptr);
void *Z_Malloc (int size); // returns 0 filled memory void *Z_Malloc (size_t size); // returns 0 filled memory
void *ZF_Malloc (int size); // allowed to fail void *ZF_Malloc (size_t size); // allowed to fail
void *Z_MallocNamed (int size, char *file, int line); // returns 0 filled memory void *Z_MallocNamed (size_t size, char *file, int line); // returns 0 filled memory
void *ZF_MallocNamed (int size, char *file, int line); // allowed to fail void *ZF_MallocNamed (size_t size, char *file, int line); // allowed to fail
//#define Z_Malloc(x) Z_MallocNamed2(x, __FILE__, __LINE__ ) //#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_TagFree(void *ptr);
void VARGS Z_FreeTags(int tag); void VARGS Z_FreeTags(int tag);
qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize); //returns false on error 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. //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) //(this is a nicer name for malloc)
void *BZ_Malloc(int size); void *BZ_Malloc(size_t size);
void *BZF_Malloc(int size); void *BZF_Malloc(size_t size);
void *BZ_MallocNamed (int size, const char *file, int line); // returns 0 filled memory void *BZ_MallocNamed (size_t size, const char *file, int line); // returns 0 filled memory
void *BZF_MallocNamed (int size, const char *file, int line); // allowed to fail void *BZF_MallocNamed (size_t size, const char *file, int line); // allowed to fail
void *BZ_Realloc(void *ptr, int size); void *BZ_Realloc(void *ptr, size_t size);
void *BZ_ReallocNamed(void *data, int newsize, const char *file, int line); void *BZ_ReallocNamed(void *data, size_t newsize, const char *file, int line);
void *BZF_Realloc(void *data, int newsize); void *BZF_Realloc(void *data, size_t newsize);
void *BZF_ReallocNamed(void *data, int newsize, const char *file, int line); void *BZF_ReallocNamed(void *data, size_t newsize, const char *file, int line);
void BZ_Free(void *ptr); void BZ_Free(void *ptr);
//ctx should start off as void*ctx=NULL //ctx should start off as void*ctx=NULL
@ -117,8 +117,8 @@ typedef struct zonegroup_s
void *first; void *first;
int bytes; int bytes;
} zonegroup_t; } zonegroup_t;
void *QDECL ZG_Malloc(zonegroup_t *ctx, int size); void *QDECL ZG_Malloc(zonegroup_t *ctx, size_t size);
void *ZG_MallocNamed(zonegroup_t *ctx, int size, char *file, int line); void *ZG_MallocNamed(zonegroup_t *ctx, size_t size, char *file, int line);
void ZG_FreeGroup(zonegroup_t *ctx); void ZG_FreeGroup(zonegroup_t *ctx);
#ifdef USE_MSVCRT_DEBUG #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_AllocName (int size, char *name);
*/ */
void *Hunk_TempAlloc (int size); void *Hunk_TempAlloc (size_t size);
void *Hunk_TempAllocMore (int size); //Don't clear old temp void *Hunk_TempAllocMore (size_t size); //Don't clear old temp
/* /*
typedef struct cache_user_s 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_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 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 exec touch.cfg

View file

@ -4725,6 +4725,20 @@ static void DrawMeshes(void)
p = &shaderstate.curshader->passes[passno]; p = &shaderstate.curshader->passes[passno];
passno += p->numMergedPasses; 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 = 0;
emumode = (p->shaderbits & SBITS_ATEST_BITS) >> SBITS_ATEST_SHIFT; emumode = (p->shaderbits & SBITS_ATEST_BITS) >> SBITS_ATEST_SHIFT;

View file

@ -135,11 +135,11 @@ void GL_SetupFormats(void)
if (gl_config_gles) if (gl_config_gles)
{ {
//pre-3 gles doesn't support sized formats, and only a limited number of them too //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_RGB8, 0, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE, tc_rgb);
glfmtc(PTI_RGBA8, GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, tc_rgba8); glfmtc(PTI_RGBA8, 0, 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_L8A8, 0, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
glfmt(PTI_L8, GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE); glfmt(PTI_L8, 0, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
// glfmt(PTI_RGBA8, GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE); // glfmt(PTI_A8, 0, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
if (!gl_config.webgl_ie) if (!gl_config.webgl_ie)
{ //these should work on all gles2+webgl1 devices, but microsoft doesn't give a shit. { //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_BASE_LEVEL, 0);
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, nummips-1); 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_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_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_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 enum
{ {
@ -81,7 +85,7 @@ void validatelinks2(link_t *firstnode, link_t *panic)
#ifndef SERVERONLY #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 void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b);
static qboolean Terr_Collect(heightmap_t *hm); static qboolean Terr_Collect(heightmap_t *hm);
#endif #endif
@ -1933,6 +1937,18 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
if (!s || s->loadstate < TSLS_LOADING2) if (!s || s->loadstate < TSLS_LOADING2)
return; 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); validatelinks(&hm->recycle);
RemoveLink(&s->recycle); RemoveLink(&s->recycle);
@ -1965,13 +1981,19 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
if (qrenderer == QR_OPENGL) if (qrenderer == QR_OPENGL)
{ {
if (qglDeleteBuffersARB) if (qglDeleteBuffersARB)
{
if (s->vbo.coord.gl.vbo)
{ {
qglDeleteBuffersARB(1, &s->vbo.coord.gl.vbo); qglDeleteBuffersARB(1, &s->vbo.coord.gl.vbo);
s->vbo.coord.gl.vbo = 0; s->vbo.coord.gl.vbo = 0;
}
if (s->vbo.indicies.gl.vbo)
{
qglDeleteBuffersARB(1, &s->vbo.indicies.gl.vbo); qglDeleteBuffersARB(1, &s->vbo.indicies.gl.vbo);
s->vbo.indicies.gl.vbo = 0; s->vbo.indicies.gl.vbo = 0;
} }
} }
}
else else
#endif #endif
{ {
@ -2123,8 +2145,6 @@ validatelinks(&hm->recycle);
} }
else else
{ {
c->section[sx+sy*MAXSECTIONS] = NULL;
validatelinks(&hm->recycle); validatelinks(&hm->recycle);
Terr_DestroySection(hm, s, lightmapreusable); Terr_DestroySection(hm, s, lightmapreusable);
validatelinks(&hm->recycle); validatelinks(&hm->recycle);
@ -2999,7 +3019,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
// hm->beinglazy = false; // hm->beinglazy = false;
if (hm->relight) if (hm->relight)
ted_dorelight(hm); ted_dorelight(m, hm);
if (e->model == cl.worldmodel && hm->skyshader) 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); 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 #if 0
float z = 0;
norm[0] = 0; norm[0] = 0;
norm[1] = 0; norm[1] = 0;
norm[2] = 1; norm[2] = 1;
@ -3322,6 +3343,7 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
vec3_t d1, d2; vec3_t d1, d2;
const float wbias = CHUNKBIAS * hm->sectionsize; const float wbias = CHUNKBIAS * hm->sectionsize;
hmsection_t *s; hmsection_t *s;
float z;
norm[0] = 0; norm[0] = 0;
norm[1] = 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; sx = (org[0]+wbias)/hm->sectionsize;
sy = (org[1]+wbias)/hm->sectionsize; sy = (org[1]+wbias)/hm->sectionsize;
if (sx < hm->firstsegx || sy < hm->firstsegy) if (sx < hm->firstsegx || sy < hm->firstsegy)
return; return hm->defaultgroundheight;
if (sx >= hm->maxsegx || sy >= hm->maxsegy) if (sx >= hm->maxsegx || sy >= hm->maxsegy)
return; return hm->defaultgroundheight;
s = Terr_GetSection(hm, sx, sy, TGS_TRYLOAD); s = Terr_GetSection(hm, sx, sy, TGS_TRYLOAD);
if (!s) if (!s)
return; return hm->defaultgroundheight;
x = (org[0]+wbias - (sx*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; x = (org[0]+wbias - (sx*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize;
y = (org[1]+wbias - (sy*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; 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[0] = 0;
d2[1] = (hm->sectionsize / SECTHEIGHTSIZE); d2[1] = (hm->sectionsize / SECTHEIGHTSIZE);
d2[2] = (s->heights[(sx+1)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+1)+(sy+0)*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 else
{ //the 0,0 triangle { //the 0,0 triangle
@ -3366,13 +3392,19 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm)
d2[0] = 0; d2[0] = 0;
d2[1] = (hm->sectionsize / SECTHEIGHTSIZE); d2[1] = (hm->sectionsize / SECTHEIGHTSIZE);
d2[2] = (s->heights[(sx+0)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+0)+(sy+0)*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(d1);
VectorNormalize(d2); VectorNormalize(d2);
CrossProduct(d1, d2, norm); CrossProduct(d1, d2, norm);
VectorNormalize(norm); VectorNormalize(norm);
#endif #endif
return z;
} }
typedef struct { 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); qboolean ret = Heightmap_Trace(model, hulloverride, framestate, mataxis, start, end, mins, maxs, capsule, against, trace);
if (!trace->startsolid) if (!trace->startsolid)
{ { //FIXME: this code should not be needed.
trace_t testtrace; trace_t testtrace;
Heightmap_Trace(model, hulloverride, framestate, mataxis, trace->endpos, trace->endpos, mins, maxs, capsule, against, &testtrace); Heightmap_Trace(model, hulloverride, framestate, mataxis, trace->endpos, trace->endpos, mins, maxs, capsule, against, &testtrace);
if (testtrace.startsolid) if (testtrace.startsolid)
{ { //yup, we're bugged.
Con_DPrintf("Trace became solid\n"); Con_DPrintf("Trace became solid\n");
trace->fraction = 0; trace->fraction = 0;
VectorCopy(start, trace->endpos); 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; 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); unsigned char *lm = Terr_GetLightmap(hm->relight, 0, true);
int x, y; int x, y, k;
#define EXPAND 2 #define EXPAND 2
vec3_t surfnorms[(SECTTEXSIZE+EXPAND*2)*(SECTTEXSIZE+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]; // float scaletab[EXPAND*2*EXPAND*2];
vec3_t ldir = {0.4, 0.7, 2}; vec3_t ldir;
hmsection_t *s = hm->relight; hmsection_t *s = hm->relight;
float ambient, diffuse;
trace_t trace;
s->flags &= ~TSF_RELIGHT; s->flags &= ~TSF_RELIGHT;
hm->relight = NULL; hm->relight = NULL;
if (s->lightmap < 0) if (s->lightmap < 0)
return; return;
ambient = 255*mod_terrain_ambient.value;
diffuse = 255-ambient;
for (y = -EXPAND; y < SECTTEXSIZE+EXPAND; y++) for (y = -EXPAND; y < SECTTEXSIZE+EXPAND; y++)
for (x = -EXPAND; x < SECTTEXSIZE+EXPAND; x++) for (x = -EXPAND; x < SECTTEXSIZE+EXPAND; x++)
{ {
vec3_t pos; k = x+EXPAND + (y+EXPAND)*(SECTTEXSIZE+EXPAND*2);
pos[0] = hm->relightmin[0] + (x*hm->sectionsize/(SECTTEXSIZE-1)); surfpoint[k][0] = hm->relightmin[0] + (x*hm->sectionsize/(SECTTEXSIZE-1));
pos[1] = hm->relightmin[1] + (y*hm->sectionsize/(SECTTEXSIZE-1)); surfpoint[k][1] = hm->relightmin[1] + (y*hm->sectionsize/(SECTTEXSIZE-1));
pos[2] = 0; surfpoint[k][2] = Heightmap_Normal(s->hmmod, surfpoint[k], surfnorms[k])+0.1;
Heightmap_Normal(s->hmmod, pos, surfnorms[x+EXPAND + (y+EXPAND)*(SECTTEXSIZE+EXPAND*2)]);
} }
VectorNormalize(ldir); VectorNormalize2(mod_terrain_sundir.vec4, ldir);
for (y = 0; y < SECTTEXSIZE; y++, lm += (HMLMSTRIDE-SECTTEXSIZE)*4) for (y = 0; y < SECTTEXSIZE; y++, lm += (HMLMSTRIDE-SECTTEXSIZE)*4)
for (x = 0; x < SECTTEXSIZE; x++, lm += 4) for (x = 0; x < SECTTEXSIZE; x++, lm += 4)
@ -4415,10 +4452,18 @@ static void ted_dorelight(heightmap_t *hm)
d = DotProduct(ldir, norm); d = DotProduct(ldir, norm);
if (d < 0) if (d < 0)
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[0] = norm[0]*127 + 128;
// lm[1] = norm[1]*127 + 128; // lm[1] = norm[1]*127 + 128;
// lm[2] = norm[2]*127 + 128; // lm[2] = norm[2]*127 + 128;
lm[3] = 127 + d*128; lm[3] = ambient + d*diffuse;
} }
lightmap[s->lightmap]->modified = true; 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); 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", hasrgba?"WS":"2",
br->patch->tex?br->patch->tex->shadername:"", br->patch->tex?br->patch->tex->shadername:"",
0.0/*xoffset*/, br->patch->xpoints/*width*/,
0.0/*yoffset*/, br->patch->ypoints/*height*/,
0.0/*rotation*/, 0.0/*rotation*/,
1.0/*xscale*/, 1.0/*xscale*/,
1.0/*yscale*/); 1.0/*yscale*/);
@ -7480,9 +7525,10 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
continue; 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; 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 qboolean parsergba = !strcmp(token, "patchDefWS"); //fancy alternative with rgba colours per control point
if (numplanes || patch_tex) 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); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;} if (strcmp(token, "(")) {Con_Printf(CON_ERROR "%s: invalid patch\n", mod->name);return false;}
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); 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); 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); 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);*/ /*rotation = atof(token);*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
/*xscale = atof(token);*/ /*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); patch_v[y][x].tc[1] = atof(token);
if (parsergba) 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); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
patch_v[y][x].rgba[0] = atof(token); patch_v[y][x].rgba[0] = atof(token);
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); 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 #ifndef SERVERONLY
#if 0 //not yet ready
struct ted_import_s struct ted_import_s
{ {
int x, y; size_t x, y;
int width; size_t width;
int height; size_t height;
unsigned short *data; unsigned short *data;
}; };
//static void ted_itterate(heightmap_t *hm, int distribution, float *pos, float radius, float strength, int steps, //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; struct ted_import_s *ctx = vctx;
unsigned int y = idx/SECTHEIGHTSIZE; unsigned int y = idx/SECTHEIGHTSIZE;
unsigned int x = idx%SECTHEIGHTSIZE; unsigned int x = idx%SECTHEIGHTSIZE;
x += s->sx*(SECTHEIGHTSIZE-1) - ctx->x; x += s->sx*(SECTHEIGHTSIZE-1) - ctx->x;
y += s->sy*(SECTHEIGHTSIZE-1) - ctx->y; 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; return;
s->flags |= TSF_NOTIFY|TSF_EDITED|TSF_DIRTY|TSF_RELIGHT; s->flags |= TSF_NOTIFY|TSF_EDITED|TSF_DIRTY|TSF_RELIGHT;
s->heights[idx] = ctx->data[x + y*ctx->width] * (8192.0/(1<<16)); 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; model_t *mod;
struct ted_import_s ctx; struct ted_import_s ctx;
const char *mapname = Cmd_Argv(1); const char *mapname = Cmd_Argv(1);
const char *filename;
size_t fsize; size_t fsize;
heightmap_t *hm; heightmap_t *hm;
vec3_t pos = {0}; vec3_t pos = {0};
@ -8025,16 +8085,142 @@ void Mod_Terrain_Import_f(void)
return; return;
fsize = 0; 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.width = ctx.height = sqrt(fsize/2);
ctx.x = 0; ctx.x = 0;
ctx.y = 0; ctx.y = 0;
pos[0] += hm->sectionsize * CHUNKBIAS; pos[0] += hm->sectionsize * CHUNKBIAS;
pos[1] += hm->sectionsize * CHUNKBIAS; pos[1] += hm->sectionsize * CHUNKBIAS;
if (fsize == ctx.width*ctx.height*2) 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); 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) 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_save", Mod_Terrain_Save_f);
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f); Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
#ifndef SERVERONLY #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_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."); 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 #endif
Mod_RegisterModelFormatText(NULL, "FTE Heightmap Map (hmp)", "terrain", Terr_LoadTerrainModel); 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; size_t n, pn = 0;
char defines[8192]; char defines[8192];
size_t offset; size_t offset;
qboolean fail = false;
extern cvar_t gl_specular, gl_specular_power; 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; 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)) 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. //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 //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)) if (!fail && sh_config.pValidateProgram && !sh_config.pValidateProgram(prog, pp, prog->warned, NULL))
prog->warned = true; prog->warned = fail = true;
if (sh_config.pProgAutoFields) if (!fail && sh_config.pProgAutoFields)
{ {
cvar_t *cvarrefs[64]; cvar_t *cvarrefs[64];
char *cvarnames[64+1]; char *cvarnames[64+1];
@ -1320,9 +1321,52 @@ struct programpermu_s *Shader_LoadPermutation(program_t *prog, unsigned int p)
cvarnames[i] = NULL; //no more cvarnames[i] = NULL; //no more
sh_config.pProgAutoFields(prog, pp, cvarrefs, cvarnames, cvartypes); sh_config.pProgAutoFields(prog, pp, cvarrefs, cvarnames, cvartypes);
} }
if (fail)
{
Z_Free(pp);
return NULL;
}
return pp; 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) static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *script, int qrtype, int ver, char *blobfilename)
{ {
#if defined(GLQUAKE) || defined(D3DQUAKE) #if defined(GLQUAKE) || defined(D3DQUAKE)
@ -1412,15 +1456,16 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
if (*token == '=' || *token == '!') if (*token == '=' || *token == '!')
{ {
len = strlen(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; ignore = true;
continue; continue;
} }
else if (ignore) else if (ignore)
continue; continue;
#ifdef HAVE_LEGACY #if 1//def HAVE_LEGACY
else if (!strncmp(token, "deluxmap", 8)) else if (!strncmp(token, "deluxmap", 8))
{ //FIXME: remove this some time. { //FIXME: remove this some time.
Con_DPrintf("Outdated texture name \"%s\" in program \"%s\"\n", token, name);
token = va("deluxemap%s",token+8); token = va("deluxemap%s",token+8);
} }
#endif #endif
@ -1470,7 +1515,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
prog->numsamplers = i; prog->numsamplers = i;
} }
else else
Con_Printf("Unknown texture name in %s\n", name); Con_Printf("Unknown texture name \"%s\" in program \"%s\"\n", token, name);
} }
} }
} }
@ -1667,6 +1712,7 @@ 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') if (!strncmp(permutations[p].name, script, end - script) && permutations[p].name[end-script] == '\0')
{ {
if (Shader_PermutationEnabled(permutations[p].bitmask))
nopermutation &= ~permutations[p].bitmask; nopermutation &= ~permutations[p].bitmask;
break; break;
} }
@ -1738,10 +1784,10 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
nopermutation |= PERMUTATION_SKELETAL; nopermutation |= PERMUTATION_SKELETAL;
//multiple lightmaps is kinda hacky. if any are set, all must be. //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)))) if (prog->defaulttextures & ((1u<<(ALTLIGHTMAPSAMP+0)) | (1u<<(ALTLIGHTMAPSAMP+1)) | (1u<<(ALTLIGHTMAPSAMP+2))))
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)))) if (prog->defaulttextures & ((1u<<(ALTDELUXMAPSAMP+0)) | (1u<<(ALTDELUXMAPSAMP+1)) | (1u<<(ALTDELUXMAPSAMP+2))))
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++) for (i = 0; i < gl_num_extensions; i++)
if (!strcmp(qglGetStringi(GL_EXTENSIONS, i), extname)) if (!strcmp(qglGetStringi(GL_EXTENSIONS, i), extname))
{ {
Con_DPrintf("Detected GL extension %s\n", extname); Con_DPrintf("GL: Found %s\n", extname);
return true; 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 "#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n" "#define sampler2DShadow sampler2D\n"
"#elif defined(GL_ES)\n" "#elif defined(GL_ES)\n"
"#if __VERSION__ < 300\n"
"#extension GL_EXT_shadow_samplers : require\n"
"#endif\n"
"precision lowp sampler2DShadow;\n" //gah "precision lowp sampler2DShadow;\n" //gah
"#endif\n" "#endif\n"
#endif #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. //must support skeletal and 2-way vertex blending or Bad Things Will Happen.
//the vertex shader is responsible for calculating lighting values. //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" "#define affine noperspective\n"
"#else\n" "#else\n"
"#define affine\n" "#define affine\n"
@ -5599,11 +5599,17 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"!!permu REFLECTCUBEMASK\n" "!!permu REFLECTCUBEMASK\n"
"!!cvarf r_glsl_offsetmapping_scale\n" "!!cvarf r_glsl_offsetmapping_scale\n"
"!!cvardf r_tessellation_level=5\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. //diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
"!!samps =EIGHTBIT paletted 1 specular diffuse\n" "!!samps =EIGHTBIT paletted 1\n"
"!!samps lightmap deluxemap\n" "!!samps =SPECULAR specular\n"
"!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3\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" "#if defined(ORM) || defined(SG)\n"
"#define PBR\n" "#define PBR\n"
@ -5960,7 +5966,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#else\n" "#else\n"
//now we have our diffuse+specular terms, modulate by lightmap values. //now we have our diffuse+specular terms, modulate by lightmap values.
"col.rgb *= lightmaps.rgb;\n" "col.rgb *= lightmaps.rgb;\n"
//add on the fullbright //add on the fullbright
"#ifdef FULLBRIGHT\n" "#ifdef FULLBRIGHT\n"
"col.rgb += texture2D(s_fullbright, tc).rgb;\n" "col.rgb += texture2D(s_fullbright, tc).rgb;\n"
@ -10603,10 +10608,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
#endif #endif
#ifdef GLQUAKE #ifdef GLQUAKE
{QR_OPENGL, 110, "terrain", {QR_OPENGL, 110, "terrain",
"!!ver 100 300\n"
"!!permu FOG\n" "!!permu FOG\n"
//t0-t3 are the diffusemaps, t4 is the blend factors //RTLIGHT (+PCF,CUBE,SPOT,etc)
"!!samps 4\n" "!!samps tr=0 tg=1 tb=2 tx=3 //the four texturemaps\n"
"!!samps mix=4\n" "!!samps mix=4 //how the ground is blended\n"
"!!samps =PCF shadowmap\n" "!!samps =PCF shadowmap\n"
"!!samps =CUBE projectionmap\n" "!!samps =CUBE projectionmap\n"
@ -10703,10 +10709,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec4 r;\n" "vec4 r;\n"
"vec4 m = texture2D(s_mix, lm);\n" "vec4 m = texture2D(s_mix, lm);\n"
"r = texture2D(s_t0, tc)*m.r;\n" "r = texture2D(s_tr, tc)*m.r;\n"
"r += texture2D(s_t1, tc)*m.g;\n" "r += texture2D(s_tg, tc)*m.g;\n"
"r += texture2D(s_t2, tc)*m.b;\n" "r += texture2D(s_tb, tc)*m.b;\n"
"r += texture2D(s_t3, tc)*(1.0 - (m.r + m.g + 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. //vertex colours provide a scaler that applies even through rtlights.
"r *= vc;\n" "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); 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); 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*/ /*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; unsigned int i;
edictrun_t *e; 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if (pnum < 0) 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; 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; // progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if (((edictrun_t *)ed)->ereftype != ER_ENTITY) 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); 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; 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; 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
unsigned int i; unsigned int i;
@ -795,7 +795,7 @@ eval_t *PDECL PR_FindGlobal(pubprogfuncs_t *ppf, const char *globname, progsnum_
return NULL; 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
int i; int i;
@ -816,7 +816,7 @@ char *PDECL PR_VarString (pubprogfuncs_t *ppf, int first)
return out; 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
fdef_t *var; 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]); 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
if ((unsigned)progs >= (unsigned)prinst.maxedicts) 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); 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; // progfuncs_t *progfuncs = (progfuncs_t*)ppf;
return EDICT_TO_PROG(progfuncs, ed); 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); 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. //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) if (!str)
*fld = 0; *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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
char *ret; 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
tempstr_t **ntable; tempstr_t **ntable;
@ -1319,7 +1319,7 @@ static void PR_FreeAllTemps (progfuncs_t *progfuncs)
prinst.numtempstrings = 0; prinst.numtempstrings = 0;
prinst.nexttempstring = 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; progfuncs_t *progfuncs = (progfuncs_t*)ppf;
struct progstate_s *ps; 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); static void PDECL RegisterBuiltin(pubprogfuncs_t *progfncs, const char *name, builtin_t func);
pubprogfuncs_t deffuncs = { static pubprogfuncs_t deffuncs = {
PROGSTRUCT_VERSION, PROGSTRUCT_VERSION,
PR_CloseProgs, PR_CloseProgs,
PR_Configure, PR_Configure,
@ -1510,11 +1510,11 @@ static void PDECL qclib_free(void *ptr)
#endif #endif
//defs incase following structure is not passed. //defs incase following structure is not passed.
struct edict_s *safesv_edicts; static struct edict_s *safesv_edicts;
int safesv_num_edicts; static int safesv_num_edicts;
double safetime=0; static double safetime=0;
progexterns_t defexterns = { static progexterns_t defexterns = {
PROGSTRUCT_VERSION, PROGSTRUCT_VERSION,
NULL, //char *(*ReadFile) (char *fname, void *buffer, int len); 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.")}, {"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, 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.")}, {"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. //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_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.")}, {"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.")}, {"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.")}, {"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.")}, {"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 #ifdef Q3SERVER
q3singleplayer = !strcmp(Cmd_Argv(0), "spmap"); q3singleplayer = !strcmp(Cmd_Argv(0), "spmap");
#endif #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 #ifdef SAVEDGAMES
newunit = flushparms || (!strcmp(Cmd_Argv(0), "changelevel") && !startspot); newunit = flushparms || (!strcmp(Cmd_Argv(0), "changelevel") && !startspot);
q2savetos0 = !strcmp(Cmd_Argv(0), "gamemap") && !isDedicated; //q2 q2savetos0 = !strcmp(Cmd_Argv(0), "gamemap") && !isDedicated; //q2
@ -1910,7 +1913,10 @@ static void SV_Status_f (void)
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
extern cvar_t net_enable_tls; extern cvar_t net_enable_tls;
#endif #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 #endif
#ifdef NQPROT #ifdef NQPROT
extern cvar_t sv_listen_nq, sv_listen_dp; extern cvar_t sv_listen_nq, sv_listen_dp;
@ -1990,12 +1996,14 @@ static void SV_Status_f (void)
if (net_enable_tls.ival) if (net_enable_tls.ival)
Con_Printf(" TLS"); Con_Printf(" TLS");
#endif #endif
#ifdef HAVE_HTTPSV
if (net_enable_http.ival) if (net_enable_http.ival)
Con_Printf(" HTTP"); Con_Printf(" HTTP");
if (net_enable_webrtcbroker.ival) if (net_enable_webrtcbroker.ival)
Con_Printf(" WebRTC"); Con_Printf(" WebRTC");
if (net_enable_websockets.ival) if (net_enable_websockets.ival)
Con_Printf(" WS"); Con_Printf(" WS");
#endif
if (net_enable_qizmo.ival) if (net_enable_qizmo.ival)
Con_Printf(" QZ"); Con_Printf(" QZ");
if (net_enable_qtv.ival) if (net_enable_qtv.ival)

View file

@ -3140,13 +3140,27 @@ client_t *SVC_DirectConnect(void)
else else
#endif #endif
newcl->netchan.compresstable = NULL; 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 (mtu >= 64)
{ //if we support application fragmenting, then we can send massive reliables without too much issue { //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); 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. 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; newcl->protocol = protocol;
#ifdef NQPROT #ifdef NQPROT

View file

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

View file

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

View file

@ -987,12 +987,12 @@ void SV_SendClientPrespawnInfo(client_t *client)
return; 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. //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; 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) if (maxsize < 500)
maxsize = 500; maxsize = 500;
} }
@ -1933,7 +1933,6 @@ void SVQW_Spawn_f (void)
// when that is completed, a begin command will be issued // when that is completed, a begin command will be issued
ClientReliableWrite_Begin (host_client, svc_stufftext, 8); ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
ClientReliableWrite_String (host_client, "skins\n" ); ClientReliableWrite_String (host_client, "skins\n" );
} }
/* /*
@ -7733,6 +7732,8 @@ void SV_ReadQCRequest(void)
done: done:
args[i] = 0; args[i] = 0;
rname = MSG_ReadString(); 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) if (i)
fname = va("CSEv_%s_%s", rname, args); 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). 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); rname = va("Cmd_%s", rname);
f = PR_FindFunction(svprogfuncs, rname, PR_ANY); f = PR_FindFunction(svprogfuncs, rname, PR_ANY);
if (f) 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 #endif
if (host_client->drop) 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); 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) qboolean SVQ2_InitGameProgs(void)
{ {
extern cvar_t maxclients; extern cvar_t maxclients;
@ -862,7 +866,7 @@ qboolean SVQ2_InitGameProgs(void)
import.WriteDir = PFQ2_WriteDir; import.WriteDir = PFQ2_WriteDir;
import.WriteAngle = PFQ2_WriteAngle; import.WriteAngle = PFQ2_WriteAngle;
import.TagMalloc = Z_TagMalloc; import.TagMalloc = ZQ2_TagMalloc;
import.TagFree = Z_TagFree; import.TagFree = Z_TagFree;
import.FreeTags = Z_FreeTags; import.FreeTags = Z_FreeTags;

View file

@ -30,7 +30,7 @@
//must support skeletal and 2-way vertex blending or Bad Things Will Happen. //must support skeletal and 2-way vertex blending or Bad Things Will Happen.
//the vertex shader is responsible for calculating lighting values. //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 #define affine noperspective
#else #else
#define affine #define affine

View file

@ -9,11 +9,17 @@
!!permu REFLECTCUBEMASK !!permu REFLECTCUBEMASK
!!cvarf r_glsl_offsetmapping_scale !!cvarf r_glsl_offsetmapping_scale
!!cvardf r_tessellation_level=5 !!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. //diffuse gives us alpha, and prevents dlight from bugging out when there's no diffuse.
!!samps =EIGHTBIT paletted 1 specular diffuse !!samps =EIGHTBIT paletted 1
!!samps lightmap deluxemap !!samps =SPECULAR specular
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3 deluxemap deluxemap1 deluxemap2 deluxemap3 !!samps lightmap
!!samps =LIGHTSTYLED lightmap1 lightmap2 lightmap3
!!samps =DELUXE deluxmap
!!samps =LIGHTSTYLED =DELUXE deluxemap1 deluxemap2 deluxemap3
#if defined(ORM) || defined(SG) #if defined(ORM) || defined(SG)
#define PBR #define PBR
@ -370,7 +376,6 @@ void main ()
#else #else
//now we have our diffuse+specular terms, modulate by lightmap values. //now we have our diffuse+specular terms, modulate by lightmap values.
col.rgb *= lightmaps.rgb; col.rgb *= lightmaps.rgb;
//add on the fullbright //add on the fullbright
#ifdef FULLBRIGHT #ifdef FULLBRIGHT
col.rgb += texture2D(s_fullbright, tc).rgb; col.rgb += texture2D(s_fullbright, tc).rgb;

View file

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