added support for persistent particle effects in hexen2.

tweaked shutdown of sql to not make sql unusable after 'disconnect' on a listen server, fixed a couple of mem leaks.
audio no longer starts up twice in windows.
removed specular permutation. its either globally active or globally inactive.
Use oblique near-plane clipping instead of a clipplane, fixing our rtlighting+water warping.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4156 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2012-11-29 13:37:48 +00:00
parent e82dd608a6
commit d248ce223f
53 changed files with 1389 additions and 724 deletions

View file

@ -558,7 +558,8 @@ SERVERONLY_OBJS = \
WINDOWSSERVERONLY_OBJS = \
svmodel.o \
sv_sys_win.o
sv_sys_win.o \
sys_win_threads.o
COMMON_OBJS = \
gl_alias.o \
@ -776,7 +777,7 @@ ifeq ($(FTE_TARGET),vc)
SV_LDFLAGS=/subsystem:console
M_EXE_NAME=../fteqw.exe
MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o resources.o
MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o resources.o
M_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS)
MB_DIR=m_vc
M_LDFLAGS=$(GLLDFLAGS) libs/jpeg.lib libs/libpng.lib libs/zlib.lib uuid.lib gdi32.lib ole32.lib /subsystem:windows
@ -811,7 +812,7 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),)
SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(BOTLIB_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START)
GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o $(LTO_END) resources.o $(LTO_START)
GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(LTO_END) resources.o $(LTO_START)
GL_EXE_NAME=../fteglqw$(BITS).exe
GLCL_EXE_NAME=../fteglqwcl$(BITS).exe
GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32
@ -819,7 +820,7 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),)
GLB_DIR=gl_mgw$(BITS)
GLCL_DIR=glcl_mgw$(BITS)
NPFTECL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_npfte.o sys_axfte.o sys_plugfte.o $(LTO_END) npplug.o ../../ftequake/npapi.def $(LTO_START)
NPFTECL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o sys_npfte.o sys_axfte.o sys_plugfte.o $(LTO_END) npplug.o ../../ftequake/npapi.def $(LTO_START)
NPFTE_DLL_NAME=../npfte$(BITS).dll
NPFTECL_DLL_NAME=../npftecl$(BITS).dll
NPFTE_LDFLAGS=-Wl,--enable-stdcall-fixup $(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -loleaut32 -luuid -lstdc++ -shared
@ -827,7 +828,7 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),)
NPFTEB_DIR=npfte_mgw$(BITS)
NPFTECL_DIR=npqtvcl_mgw$(BITS)
MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o $(LTO_END) resources.o $(LTO_START)
MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) fs_win32.o gl_vidnt.o snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(LTO_END) resources.o $(LTO_START)
M_EXE_NAME=../fteqw$(BITS).exe
MCL_EXE_NAME=../fteqwcl$(BITS).exe
M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32
@ -835,7 +836,7 @@ ifeq ($(shell echo $(FTE_TARGET)|grep -E -v "win(32|64)$$"),)
MB_DIR=m_mgw$(BITS)
MCL_DIR=mcl_mgw$(BITS)
D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o $(D3DGL_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START)
D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_win.o snd_directx.o cd_win.o in_win.o sys_win.o sys_win_threads.o $(D3DGL_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START)
D3D_EXE_NAME=../fted3dqw$(BITS).exe
D3DCL_EXE_NAME=../fted3dclqw$(BITS).exe
D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32

View file

@ -34,35 +34,29 @@ static qboolean cdValid = false;
static qboolean playing = false;
static qboolean wasPlaying = false;
static qboolean initialized = false;
static qboolean initializefailed = false;
static qboolean enabled = false;
static qboolean playLooping = false;
static qbyte remap[100];
static qbyte playTrack;
static qbyte maxTrack;
UINT wDeviceID;
static UINT wDeviceID;
static void CDAudio_Eject(void)
static void BGMVolume_Callback(struct cvar_s *var, char *oldvalue)
{
DWORD dwReturn;
int cdvolume;
dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD_PTR)NULL);
if (dwReturn)
Con_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", (int)dwReturn);
if (!enabled)
return;
cdvolume = atof(oldvalue);
if (cdvolume && !var->ival)
CDAudio_Pause ();
else if (!cdvolume && var->ival)
CDAudio_Resume ();
}
static void CDAudio_CloseDoor(void)
{
DWORD dwReturn;
dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD_PTR)NULL);
if (dwReturn)
Con_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", (int)dwReturn);
}
static int CDAudio_GetAudioDiskInfo(void)
{
DWORD dwReturn;
@ -103,6 +97,89 @@ static int CDAudio_GetAudioDiskInfo(void)
return 0;
}
static qboolean CDAudio_Startup(void)
{
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;
MCI_SET_PARMS mciSetParms;
int n;
if (initializefailed)
return false;
if (!bgmvolume.value)
return false;
if (initialized)
return true;
mciOpenParms.lpstrDeviceType = "cdaudio";
dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD_PTR) (LPVOID) &mciOpenParms);
if (dwReturn)
{
Con_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", (int)dwReturn);
initializefailed = true;
return 0;
}
wDeviceID = mciOpenParms.wDeviceID;
// Set the time format to track/minute/second/frame (TMSF).
mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &mciSetParms);
if (dwReturn)
{
Con_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", (int)dwReturn);
mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD_PTR)NULL);
initializefailed = true;
return 0;
}
for (n = 0; n < 100; n++)
remap[n] = n;
initialized = true;
enabled = true;
if (CDAudio_GetAudioDiskInfo())
{
Con_Printf("CDAudio_Init: No CD in player.\n");
cdValid = false;
enabled = false;
}
Cvar_Hook(&bgmvolume, BGMVolume_Callback);
return true;
}
void CDAudio_Shutdown(void)
{
if (initialized)
{
Cvar_Unhook(&bgmvolume);
CDAudio_Stop();
if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)NULL))
Con_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
}
initialized = false;
}
static void CDAudio_Eject(void)
{
DWORD dwReturn;
dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD_PTR)NULL);
if (dwReturn)
Con_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", (int)dwReturn);
}
static void CDAudio_CloseDoor(void)
{
DWORD dwReturn;
dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD_PTR)NULL);
if (dwReturn)
Con_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", (int)dwReturn);
}
void CDAudio_Play(int track, qboolean looping)
{
@ -133,7 +210,7 @@ void CDAudio_Play(int track, qboolean looping)
}
}
if (!initialized)
if (!CDAudio_Startup())
return;
track = remap[track];
@ -292,7 +369,7 @@ static void CD_f (void)
}
if (!initialized)
if (!CDAudio_Startup())
{
Con_Printf("No cd drive detected\n");
return;
@ -426,21 +503,6 @@ LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return 0;
}
void BGMVolume_Callback(struct cvar_s *var, char *oldvalue)
{
int cdvolume;
if (!enabled)
return;
cdvolume = atof(oldvalue);
if (cdvolume && !var->ival)
CDAudio_Pause ();
else if (!cdvolume && var->ival)
CDAudio_Resume ();
}
void CDAudio_Update(void)
{
@ -449,11 +511,6 @@ void CDAudio_Update(void)
int CDAudio_Init(void)
{
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;
MCI_SET_PARMS mciSetParms;
int n;
Cmd_AddCommand ("cd", CD_f);
#if 0 // QW
@ -461,53 +518,10 @@ int CDAudio_Init(void)
return -1;
#endif
if (COM_CheckParm("-nocdaudio"))
return -1;
mciOpenParms.lpstrDeviceType = "cdaudio";
dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD_PTR) (LPVOID) &mciOpenParms);
if (dwReturn)
{
Con_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", (int)dwReturn);
return -1;
}
wDeviceID = mciOpenParms.wDeviceID;
// Set the time format to track/minute/second/frame (TMSF).
mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &mciSetParms);
if (dwReturn)
{
Con_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", (int)dwReturn);
mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD_PTR)NULL);
return -1;
}
for (n = 0; n < 100; n++)
remap[n] = n;
initialized = true;
enabled = true;
if (CDAudio_GetAudioDiskInfo())
{
Con_Printf("CDAudio_Init: No CD in player.\n");
cdValid = false;
enabled = false;
}
Cvar_Hook(&bgmvolume, BGMVolume_Callback);
// Con_Printf("CD Audio Initialized\n");
initializefailed = true;
else
initializefailed = false;
return 0;
}
void CDAudio_Shutdown(void)
{
if (!initialized)
return;
CDAudio_Stop();
if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)NULL))
Con_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
Cvar_Unhook(&bgmvolume);
}

View file

@ -1234,7 +1234,7 @@ void CL_UseIndepPhysics(qboolean allow)
indeplock = Sys_CreateMutex();
runningindepphys = true;
indepthread = Sys_CreateThread(CL_IndepPhysicsThread, NULL, THREADP_HIGHEST, 8192);
indepthread = Sys_CreateThread("indepphys", CL_IndepPhysicsThread, NULL, THREADP_HIGHEST, 8192);
allowindepphys = true;
}
else

View file

@ -2893,21 +2893,21 @@ void CL_DownloadSize_f(void)
if (!strcmp(size, "e"))
{
Con_Printf("Download of \"%s\" failed. Not found.\n", rname);
CL_DownloadFailed(rname);
CL_DownloadFailed(rname, false);
}
else if (!strcmp(size, "p"))
{
if (stricmp(cls.downloadremotename, rname))
{
Con_Printf("Download of \"%s\" failed. Not allowed.\n", rname);
CL_DownloadFailed(rname);
CL_DownloadFailed(rname, false);
}
}
else if (!strcmp(size, "r"))
{
redirection = Cmd_Argv(3);
dl = CL_DownloadFailed(rname);
dl = CL_DownloadFailed(rname, false);
if (cl_download_redirection.ival)
{
@ -3012,7 +3012,7 @@ void CL_Windows_f (void)
#ifndef CLIENTONLY
void CL_ServerInfo_f(void)
{
if (!sv.state && cls.state)
if (!sv.state && cls.state && Cmd_Argc() < 2)
{
if (cls.demoplayback || cls.protocol != CP_QUAKEWORLD)
{

View file

@ -438,7 +438,7 @@ qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags)
#ifdef PEXT_PK3DOWNLOADS
| PEXT_PK3DOWNLOADS
#endif
)))
)) && !(dl->flags & DLLF_TEMPORARY))
{
CL_SendClientCommand(true, "dlsize \"%s\"", dl->rname);
}
@ -508,7 +508,7 @@ void CL_DisenqueDownload(char *filename)
void CL_WebDownloadFinished(struct dl_download *dl)
{
if (dl->status == DL_FAILED)
CL_DownloadFailed(dl->url);
CL_DownloadFailed(dl->url, false);
else if (dl->status == DL_FINISHED)
{
if (dl->file)
@ -519,11 +519,12 @@ void CL_WebDownloadFinished(struct dl_download *dl)
}
#endif
void CL_SendDownloadStartRequest(char *filename, char *localname)
void CL_SendDownloadStartRequest(char *filename, char *localname, unsigned int flags)
{
strcpy (cls.downloadremotename, filename);
strcpy (cls.downloadlocalname, localname);
Con_TPrintf (TL_DOWNLOADINGFILE, cls.downloadlocalname);
if (!(flags & DLLF_TEMPORARY))
Con_TPrintf (TL_DOWNLOADINGFILE, cls.downloadlocalname);
// download to a temp name, and only rename
// to the real name when done, so if interrupted
@ -537,7 +538,7 @@ void CL_SendDownloadStartRequest(char *filename, char *localname)
cls.downloadmethod = DL_HTTP;
cls.downloadpercent = 0;
if (!HTTP_CL_Get(cls.downloadremotename, cls.downloadtempname, CL_WebDownloadFinished))
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, false);
}
else
#endif
@ -569,7 +570,15 @@ void CL_DownloadFinished(void)
// rename the temp file to it's final name
if (tempname)
{
if (strcmp(tempname, filename))
#ifdef TERRAIN
if (!strncmp(tempname, "temp/", 5) && Terr_DownloadedSection(tempname))
{
FS_Remove(tempname, FS_GAME);
return;
}
else
#endif
if (strcmp(tempname, filename))
{
if (!strncmp(tempname,"package/",8))
{
@ -1379,7 +1388,7 @@ void CL_RequestNextDownload (void)
{
if ((fl & DLLF_OVERWRITE) || !CL_CheckFile (dl->localname))
{
CL_SendDownloadStartRequest(dl->rname, dl->localname);
CL_SendDownloadStartRequest(dl->rname, dl->localname, fl);
return;
}
else
@ -1555,7 +1564,7 @@ char *ZLibDownloadDecode(int *messagesize, char *input, int finalsize)
}
#endif
downloadlist_t *CL_DownloadFailed(char *name)
downloadlist_t *CL_DownloadFailed(char *name, qboolean cancel)
{
//add this to our failed list. (so we don't try downloading it again...)
downloadlist_t *failed, **link, *dl;
@ -1565,7 +1574,8 @@ downloadlist_t *CL_DownloadFailed(char *name)
Q_strncpyz(failed->rname, name, sizeof(failed->rname));
//if this is what we're currently downloading, close it up now.
if (!stricmp(cls.downloadremotename, name) || !*name)
//don't do this if we're just marking the file as unavailable for download.
if (cancel && (!stricmp(cls.downloadremotename, name) || !*name))
{
cls.downloadmethod = DL_NONE;
@ -1657,7 +1667,7 @@ void CL_ParseChunkedDownload(void)
Con_Printf("Couldn't find file \"%s\" on the server\n", svname);
cls.downloadmethod = DL_NONE;
CL_DownloadFailed(svname);
CL_DownloadFailed(svname, true);
CL_RequestNextDownload();
return;
@ -1701,7 +1711,7 @@ void CL_ParseChunkedDownload(void)
if (!cls.downloadqw)
{
CL_DownloadFailed(svname);
CL_DownloadFailed(svname, true);
return;
}
@ -1848,7 +1858,7 @@ void CL_ParseDownload (void)
VFS_CLOSE (cls.downloadqw);
cls.downloadqw = NULL;
}
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
CL_CheckOrEnqueDownloadFile(name, localname, DLLF_IGNOREFAILED);
return;
}
@ -1879,7 +1889,7 @@ void CL_ParseDownload (void)
cls.downloadqw = NULL;
}
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
return;
}
@ -1902,7 +1912,7 @@ void CL_ParseDownload (void)
{
msg_readcount += size;
Con_TPrintf (TL_FAILEDTOOPEN, cls.downloadtempname);
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
CL_RequestNextDownload ();
return;
}
@ -2051,7 +2061,7 @@ void CLDP_ParseDownloadBegin(char *s)
}
}
else
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
cls.downloadstarttime = Sys_DoubleTime();
}
@ -2086,7 +2096,7 @@ void CLDP_ParseDownloadFinished(char *s)
else
{
Con_Printf("Download failed: unable to check CRC of download\n");
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
return;
}
@ -2094,13 +2104,13 @@ void CLDP_ParseDownloadFinished(char *s)
if (size != atoi(Cmd_Argv(1)))
{
Con_Printf("Download failed: wrong file size\n");
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
return;
}
if (runningcrc != atoi(Cmd_Argv(2)))
{
Con_Printf("Download failed: wrong crc\n");
CL_DownloadFailed(cls.downloadremotename);
CL_DownloadFailed(cls.downloadremotename, true);
return;
}

View file

@ -1638,17 +1638,122 @@ typedef struct {
vec3_t dlightcfade;
} clcustomtents_t;
clcustomtents_t customtenttype[255]; //network based.
void CL_ParseCustomTEnt(void)
typedef struct custtentinst_s
{
int count;
struct custtentinst_s *next;
clcustomtents_t *type;
int id;
vec3_t pos;
vec3_t pos2;
vec3_t dir;
int count;
} custtentinst_t;
custtentinst_t *activepcusttents;
void CL_SpawnCustomTEnd(custtentinst_t *info)
{
clcustomtents_t *t = info->type;
qboolean failed;
if (t->netstyle & CTE_ISBEAM)
{
if (t->netstyle & (CTE_CUSTOMVELOCITY|CTE_CUSTOMDIRECTION))
{
vec3_t org;
int i, j;
//FIXME: pvs cull
if (t->particleeffecttype != -1)
{
for (i=0 ; i<info->count ; i++)
{
for (j=0 ; j<3 ; j++)
{
org[j] = info->pos[j] + (info->pos2[j] - info->pos[j])*frandom();
}
P_RunParticleEffectType(org, info->dir, 1, t->particleeffecttype);
}
}
}
else
failed = P_ParticleTrail(info->pos, info->pos2, t->particleeffecttype, 0, NULL);
}
else
{
if (t->netstyle & CTE_CUSTOMVELOCITY|CTE_CUSTOMDIRECTION)
failed = P_RunParticleEffectType(info->pos, info->dir, info->count, t->particleeffecttype);
else
failed = P_RunParticleEffectType(info->pos, NULL, info->count, t->particleeffecttype);
}
if (failed)
Con_DPrintf("Failed to create effect %s\n", t->name);
if (t->netstyle & CTE_STAINS)
{ //added at pos2 - end of trail
R_AddStain(info->pos2, t->stain[0], t->stain[1], t->stain[2], 40);
}
if (t->netstyle & CTE_GLOWS)
{ //added at pos1 firer's end.
dlight_t *dl;
dl = CL_AllocDlight (0);
VectorCopy (info->pos, dl->origin);
dl->radius = t->dlightradius*4;
dl->die = cl.time + t->dlighttime;
dl->decay = t->radius/t->dlighttime;
dl->color[0] = t->dlightrgb[0];
dl->color[1] = t->dlightrgb[1];
dl->color[2] = t->dlightrgb[2];
if (t->netstyle & CTE_CHANNELFADE)
{
dl->channelfade[0] = t->dlightcfade[0];
dl->channelfade[1] = t->dlightcfade[1];
dl->channelfade[2] = t->dlightcfade[2];
}
/*
if (dl->color[0] < 0)
dl->channelfade[0] = 0;
else
dl->channelfade[0] = dl->color[0]/t->dlighttime;
if (dl->color[1] < 0)
dl->channelfade[1] = 0;
else
dl->channelfade[1] = dl->color[0]/t->dlighttime;
if (dl->color[2] < 0)
dl->channelfade[2] = 0;
else
dl->channelfade[2] = dl->color[0]/t->dlighttime;
*/
}
}
void CL_RunPCustomTEnts(void)
{
custtentinst_t *ef;
static float lasttime;
float since = cl.time - lasttime;
if (since < 0)
lasttime = cl.time;
else if (since < 1/60.0)
return;
lasttime = cl.time;
for (ef = activepcusttents; ef; ef = ef->next)
{
CL_SpawnCustomTEnd(ef);
}
}
clcustomtents_t customtenttype[255]; //network based.
void CL_ParseCustomTEnt(void)
{
char *str;
clcustomtents_t *t;
int type = MSG_ReadByte();
qboolean failed;
custtentinst_t info;
if (type == 255) //255 is register
{
@ -1692,93 +1797,97 @@ void CL_ParseCustomTEnt(void)
t = &customtenttype[type];
if (t->netstyle & CTE_ISBEAM)
info.type = t;
if (t->netstyle & CTE_PERSISTANT)
{
MSG_ReadPos (pos);
MSG_ReadPos (pos2);
failed = P_ParticleTrail(pos, pos2, t->particleeffecttype, 0, NULL);
info.id = MSG_ReadShort();
}
else
info.id = 0;
if (info.id & 0x8000)
{
VectorClear(info.pos);
VectorClear(info.pos2);
info.count = 0;
VectorClear(info.dir);
}
else
{
MSG_ReadPos (pos);
VectorCopy(pos, pos2);
MSG_ReadPos (info.pos);
if (t->netstyle & CTE_ISBEAM)
MSG_ReadPos (info.pos2);
else
VectorCopy(info.pos, info.pos2);
if (t->netstyle & CTE_CUSTOMCOUNT)
count = MSG_ReadByte();
info.count = MSG_ReadByte();
else
count = 1;
info.count = 1;
if (t->netstyle & CTE_CUSTOMVELOCITY)
{
dir[0] = MSG_ReadCoord();
dir[1] = MSG_ReadCoord();
dir[2] = MSG_ReadCoord();
failed = P_RunParticleEffectType(pos, dir, count, t->particleeffecttype);
info.dir[0] = MSG_ReadCoord();
info.dir[1] = MSG_ReadCoord();
info.dir[2] = MSG_ReadCoord();
}
else if (t->netstyle & CTE_CUSTOMDIRECTION)
MSG_ReadDir (info.dir);
else
VectorClear(info.dir);
}
if (t->netstyle & CTE_PERSISTANT)
{
if (info.id & 0x8000)
{
MSG_ReadDir (dir);
failed = P_RunParticleEffectType(pos, dir, count, t->particleeffecttype);
custtentinst_t **link, *o;
for (link = &activepcusttents; *link; )
{
o = *link;
if (o->id == info.id)
{
*link = o->next;
Z_Free(o);
}
else
link = &(*link)->next;
}
}
else failed = P_RunParticleEffectType(pos, NULL, count, t->particleeffecttype);
}
if (failed)
Con_DPrintf("Failed to create effect %s\n", t->name);
if (t->netstyle & CTE_STAINS)
{ //added at pos2 - end of trail
R_AddStain(pos2, t->stain[0], t->stain[1], t->stain[2], 40);
}
if (t->netstyle & CTE_GLOWS)
{ //added at pos1 firer's end.
dlight_t *dl;
dl = CL_AllocDlight (0);
VectorCopy (pos, dl->origin);
dl->radius = t->dlightradius*4;
dl->die = cl.time + t->dlighttime;
dl->decay = t->radius/t->dlighttime;
dl->color[0] = t->dlightrgb[0];
dl->color[1] = t->dlightrgb[1];
dl->color[2] = t->dlightrgb[2];
if (t->netstyle & CTE_CHANNELFADE)
else
{
dl->channelfade[0] = t->dlightcfade[0];
dl->channelfade[1] = t->dlightcfade[1];
dl->channelfade[2] = t->dlightcfade[2];
//heap fragmentation is going to suck here.
custtentinst_t *n = Z_Malloc(sizeof(*n));
info.next = activepcusttents;
*n = info;
activepcusttents = n;
}
/*
if (dl->color[0] < 0)
dl->channelfade[0] = 0;
else
dl->channelfade[0] = dl->color[0]/t->dlighttime;
if (dl->color[1] < 0)
dl->channelfade[1] = 0;
else
dl->channelfade[1] = dl->color[0]/t->dlighttime;
if (dl->color[2] < 0)
dl->channelfade[2] = 0;
else
dl->channelfade[2] = dl->color[0]/t->dlighttime;
*/
}
else
CL_SpawnCustomTEnd(&info);
}
void CL_RefreshCustomTEnts(void)
{
int i;
for (i = 0; i < sizeof(customtenttype)/sizeof(customtenttype[0]); i++)
customtenttype[i].particleeffecttype = P_FindParticleType(customtenttype[i].name);
customtenttype[i].particleeffecttype = (!*customtenttype[i].name)?-1:P_FindParticleType(customtenttype[i].name);
}
void CL_ClearCustomTEnts(void)
{
int i;
custtentinst_t *p;
while(activepcusttents)
{
p = activepcusttents;
activepcusttents = p->next;
Z_Free(p);
}
for (i = 0; i < sizeof(customtenttype)/sizeof(customtenttype[0]); i++)
{
*customtenttype[i].name = 0;
customtenttype[i].particleeffecttype = -1;
}
}
int CL_TranslateParticleFromServer(int sveffect)
@ -3210,4 +3319,5 @@ void CL_UpdateTEnts (void)
{
CL_UpdateBeams ();
CL_UpdateExplosions ();
CL_RunPCustomTEnts ();
}

View file

@ -448,6 +448,7 @@ typedef struct downloadlist_s {
#define DLLF_SIZEUNKNOWN 8 //download's size isn't known
#define DLLF_IGNOREFAILED 16 //
#define DLLF_NONGAME 32 //means the requested download filename+localname is gamedir explicit (so id1/foo.txt is distinct from qw/foo.txt)
#define DLLF_TEMPORARY 64 //download it, but don't actually save it (DLLF_OVERWRITE doesn't actually overwrite, but does ignore any local files)
struct downloadlist_s *next;
} downloadlist_t;
@ -974,7 +975,7 @@ void CL_NewTranslation (int slot);
qboolean CL_CheckOrEnqueDownloadFile (char *filename, char *localname, unsigned int flags);
qboolean CL_EnqueDownload(char *filename, char *localname, unsigned int flags);
downloadlist_t *CL_DownloadFailed(char *name);
downloadlist_t *CL_DownloadFailed(char *name, qboolean cancel);
int CL_DownloadRate(void);
void CL_GetDownloadSizes(unsigned int *filecount, unsigned int *totalsize, qboolean *somesizesunknown);
qboolean CL_ParseOOBDownload(void);

View file

@ -2194,6 +2194,8 @@ static void PScript_Shutdown (void)
while (numparticletypes > 0)
{
numparticletypes--;
if (part_type[numparticletypes].models)
BZ_Free(part_type[numparticletypes].models);
if (part_type[numparticletypes].ramp)
BZ_Free(part_type[numparticletypes].ramp);
}

View file

@ -2400,6 +2400,42 @@ char *particle_set_h2part =
"rotationspeed 425\n"
"}\n"
"r_part ce_fountain\n"
"{\n"
"texture \"particles/fteparticlefont.tga\"\n"
"tcoords 1 1 63 63 256 2 64\n"
"count 1\n"
"scale 10\n"
"rotationspeed -64 64\n"
"scalefactor 1\n"
"die 1\n"
"alpha 0.2\n"
"rgb 128 128 128\n"
"rgbdelta 0 -32 -32\n"
"blend add\n"
"spawnvel 100\n"
"veladd 1\n"
"gravity 800\n"
"}\n"
"r_part ce_snow\n"
"{\n"
"texture \"particles/fteparticlefont.tga\"\n"
"tcoords 1 1 63 63 256 2 64\n"
"count 1\n"
"scale 30\n"
"scaledelta -10\n"
"rotationspeed -64 64\n"
"scalefactor 1\n"
"die 1\n"
"alpha 0.2\n"
"rgb 255 255 255\n"
"rgbdelta 0 -32 -32\n"
"friction 1\n"
"blend add\n"
"veladd 1\n"
"gravity 200\n"
"}\n"
;

View file

@ -2296,7 +2296,7 @@ void Surf_DrawWorld (void)
if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
{
// CL_LinkStaticEntities(entvis);
CL_LinkStaticEntities(entvis);
TRACE(("dbg: calling R_DrawParticles\n"));
if (!r_refdef.recurse)
P_DrawParticles ();

View file

@ -979,6 +979,9 @@ void R_ShutdownRenderer(void)
COM_FlushTempoaryPacks();
W_Shutdown();
if (h2playertranslations)
BZ_Free(h2playertranslations);
h2playertranslations = NULL;
if (host_basepal)
BZ_Free(host_basepal);
host_basepal = NULL;

View file

@ -923,7 +923,7 @@ int DSOUND_InitCard (soundcardinfo_t *sc, int cardnum)
#ifdef MULTITHREAD
sc->selfpainting = true;
sc->thread = Sys_CreateThread(DSOUND_Thread, sc, THREADP_HIGHEST, 0);
sc->thread = Sys_CreateThread("dsoundmixer", DSOUND_Thread, sc, THREADP_HIGHEST, 0);
if (!sc->thread)
sc->selfpainting = false; /*oh well*/
#endif

View file

@ -760,7 +760,7 @@ void Sys_SaveClipboard(char *text) {
/* Thread creation calls */
typedef void *(*pfunction_t)(void *);
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize)
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
pthread_t *thread;
pthread_attr_t attr;

View file

@ -484,7 +484,7 @@ qboolean Sys_RandomBytes(qbyte *string, int len)
#ifdef MULTITHREAD
/* Everything here is stubbed because I don't know MorphOS */
/* Thread creation calls */
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize) { return NULL; }
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize) { return NULL; }
void Sys_WaitOnThread(void *thread) {}
/* Mutex calls */
void *Sys_CreateMutex(void) { return NULL; }

View file

@ -858,7 +858,7 @@ qboolean Plug_StartContext(struct context *ctx)
activecontext = ctx;
if (!ctx->mutex)
ctx->mutex = Sys_CreateMutex();
ctx->thread = Sys_CreateThread(Plug_PluginThread, ctx, THREADP_NORMAL, 0);
ctx->thread = Sys_CreateThread("pluginctx", Plug_PluginThread, ctx, THREADP_NORMAL, 0);
return true;
}

View file

@ -592,7 +592,7 @@ void Sys_SaveClipboard(char *text)
#ifdef MULTITHREAD
/* Thread creation calls */
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize)
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
// SDL threads do not support setting thread stack size
return (void *)SDL_CreateThread(func, args);

View file

@ -2255,266 +2255,6 @@ qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refres
return true;
}
#ifdef MULTITHREAD
/* Thread creation calls */
typedef struct threadwrap_s
{
int (*func)(void *);
void *args;
} threadwrap_t;
// the thread call is wrapped so we don't need WINAPI everywhere
unsigned WINAPI threadwrapper(void *args)
{
threadwrap_t tw;
tw.func = ((threadwrap_t *)args)->func;
tw.args = ((threadwrap_t *)args)->args;
free(args);
#ifdef CATCHCRASH
__try
{
#endif
tw.func(tw.args);
#ifdef CATCHCRASH
}
__except (CrashExceptionHandler(GetExceptionCode(), GetExceptionInformation()))
{
return 1;
}
#endif
#ifndef WIN32CRTDLL
_endthreadex(0);
#endif
return 0;
}
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize)
{
threadwrap_t *tw = (threadwrap_t *)malloc(sizeof(threadwrap_t));
HANDLE handle;
if (!tw)
return NULL;
if (stacksize)
stacksize += 128; // wrapper overhead, also prevent default stack size
tw->func = func;
tw->args = args;
#ifdef WIN32CRTDLL
handle = (HANDLE)CreateThread(NULL, stacksize, &threadwrapper, (void *)tw, 0, NULL);
#else
handle = (HANDLE)_beginthreadex(NULL, stacksize, &threadwrapper, (void *)tw, 0, NULL);
#endif
if (!handle)
{
free(tw);
return NULL;
}
return (void *)handle;
}
void Sys_WaitOnThread(void *thread)
{
while (WaitForSingleObject((HANDLE)thread, 10) == WAIT_TIMEOUT)
{
/*keep responding to window messages*/
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
DispatchMessage(&msg);
}
CloseHandle((HANDLE)thread);
}
/* Mutex calls */
void *Sys_CreateMutex(void)
{
return (void *)CreateMutex(NULL, 0, NULL);
}
qboolean Sys_TryLockMutex(void *mutex)
{
return WaitForSingleObject(mutex, 0) == WAIT_OBJECT_0;
}
qboolean Sys_LockMutex(void *mutex)
{
#if 0//def _DEBUG
/*in debug builds, trigger a debug break if we sit on a mutex for longer than 20 secs*/
if (WaitForSingleObject(mutex, 20000) == WAIT_OBJECT_0)
return true;
OutputDebugString("Warning: Suspected mutex deadlock\n");
DebugBreak();
return false;
#else
return WaitForSingleObject(mutex, INFINITE) == WAIT_OBJECT_0;
#endif
}
qboolean Sys_UnlockMutex(void *mutex)
{
return !!ReleaseMutex(mutex);
}
void Sys_DestroyMutex(void *mutex)
{
CloseHandle(mutex);
}
/* Conditional wait calls */
/*
TODO: Windows Vista has condition variables as documented here:
http://msdn.microsoft.com/en-us/library/ms682052(VS.85).aspx
Note this uses Slim Reader/Writer locks (Vista+ exclusive)
or critical sections.
The condition variable implementation is based on the libSDL implementation.
This code could probably be made more efficient with the use of events or
different mechanisms but for now the main concern is a correct and
complete solution.
*/
typedef struct condvar_s
{
int waiting;
int signals;
CRITICAL_SECTION countlock;
CRITICAL_SECTION mainlock;
HANDLE wait_sem;
HANDLE wait_done;
} condvar_t;
void *Sys_CreateConditional(void)
{
condvar_t *cv;
cv = (condvar_t *)malloc(sizeof(condvar_t));
if (!cv)
return NULL;
cv->waiting = 0;
cv->signals = 0;
InitializeCriticalSection (&cv->mainlock);
InitializeCriticalSection (&cv->countlock);
cv->wait_sem = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
cv->wait_done = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
if (cv->wait_sem && cv->wait_done)
return (void *)cv;
// something failed so deallocate everything
if (cv->wait_done)
CloseHandle(cv->wait_done);
if (cv->wait_sem)
CloseHandle(cv->wait_sem);
DeleteCriticalSection(&cv->countlock);
DeleteCriticalSection(&cv->mainlock);
free(cv);
return NULL;
}
qboolean Sys_LockConditional(void *condv)
{
EnterCriticalSection(&((condvar_t *)condv)->mainlock);
return true;
}
qboolean Sys_UnlockConditional(void *condv)
{
LeaveCriticalSection(&((condvar_t *)condv)->mainlock);
return true;
}
qboolean Sys_ConditionWait(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
qboolean success;
// increase count for non-signaled waiting threads
EnterCriticalSection(&cv->countlock);
cv->waiting++;
LeaveCriticalSection(&cv->countlock);
LeaveCriticalSection(&cv->mainlock); // unlock as per condition variable definition
// wait on a signal
success = (WaitForSingleObject(cv->wait_sem, INFINITE) != WAIT_FAILED);
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
EnterCriticalSection(&cv->countlock);
if (cv->signals > 0)
{
ReleaseSemaphore(cv->wait_done, cv->signals, NULL);
cv->signals = 0;
}
cv->waiting--;
LeaveCriticalSection(&cv->countlock);
EnterCriticalSection(&cv->mainlock); // lock as per condition variable definition
return success;
}
qboolean Sys_ConditionSignal(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
// if there are non-signaled waiting threads, we signal one and wait on the response
EnterCriticalSection(&cv->countlock);
if (cv->waiting > cv->signals)
{
cv->signals++;
ReleaseSemaphore(cv->wait_sem, 1, NULL);
LeaveCriticalSection(&cv->countlock);
WaitForSingleObject(cv->wait_done, INFINITE);
}
else
LeaveCriticalSection(&cv->countlock);
return true;
}
qboolean Sys_ConditionBroadcast(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
// if there are non-signaled waiting threads, we signal all of them and wait on all the responses back
EnterCriticalSection(&cv->countlock);
if (cv->waiting > cv->signals)
{
int i, num_waiting;
num_waiting = (cv->waiting - cv->signals);
cv->signals = cv->waiting;
ReleaseSemaphore(cv->wait_sem, num_waiting, NULL);
LeaveCriticalSection(&cv->countlock);
// there's no call to wait for the same object multiple times so we need to loop through
// and burn up the semaphore count
for (i = 0; i < num_waiting; i++)
WaitForSingleObject(cv->wait_done, INFINITE);
}
else
LeaveCriticalSection(&cv->countlock);
return true;
}
void Sys_DestroyConditional(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
CloseHandle(cv->wait_done);
CloseHandle(cv->wait_sem);
DeleteCriticalSection(&cv->countlock);
DeleteCriticalSection(&cv->mainlock);
free(cv);
}
#endif
void Sys_Sleep (double seconds)
{
Sleep(seconds * 1000);

View file

@ -1132,7 +1132,8 @@ qboolean Cvar_Command (int level)
if (v->flags & CVAR_NOSET)
{
Con_Printf ("Cvar %s may not be set via the console\n", v->name);
if (cl_warncmd.value || developer.value)
Con_Printf ("Cvar %s may not be set via the console\n", v->name);
return true;
}
#ifndef SERVERONLY

View file

@ -941,6 +941,15 @@ void Matrix4x4_CM_Transform4(const float *matrix, const float *vector, float *pr
product[3] = matrix[3]*vector[0] + matrix[7]*vector[1] + matrix[11]*vector[2] + matrix[15]*vector[3];
}
//ignore the entire right+bottom row/column of the 4*4 matrix
void Matrix4x4_CM_Transform3x3(const float *matrix, const float *vector, float *product)
{
product[0] = matrix[0]*vector[0] + matrix[4]*vector[1] + matrix[8]*vector[2];
product[1] = matrix[1]*vector[0] + matrix[5]*vector[1] + matrix[9]*vector[2];
product[2] = matrix[2]*vector[0] + matrix[6]*vector[1] + matrix[10]*vector[2];
}
//disregard the extra bit of the matrix
void Matrix4x4_CM_Transform3(const float *matrix, const float *vector, float *product)
{
product[0] = matrix[0]*vector[0] + matrix[4]*vector[1] + matrix[8]*vector[2] + matrix[12];

View file

@ -64,6 +64,7 @@ extern vec3_t vec3_origin;
#define FloatInterpolate(a, bness, b, c) ((c) = (a) + (b - a)*bness)
#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3])
#define VectorSubtract(a,b,c) do{(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}while(0)
#define VectorAdd(a,b,c) do{(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}while(0)
#define VectorCopy(a,b) do{(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}while(0)
@ -156,6 +157,7 @@ void Matrix4_CreateFromQuakeEntity (float *matrix, float x, float y, float z, f
void Matrix4_Multiply (const float *a, const float *b, float *out);
void Matrix3x4_Multiply(const float *a, const float *b, float *out);
qboolean Matrix4x4_CM_Project (const vec3_t in, vec3_t out, const vec3_t viewangles, const vec3_t vieworg, float fovx, float fovy);
void Matrix4x4_CM_Transform3x3(const float *matrix, const float *vector, float *product);
void Matrix4x4_CM_Transform3 (const float *matrix, const float *vector, float *product);
void Matrix4x4_CM_Transform4 (const float *matrix, const float *vector, float *product);
void Matrix4x4_CM_Transform34(const float *matrix, const vec3_t vector, vec4_t product);

View file

@ -752,6 +752,7 @@ enum {
#define CTE_GLOWS 8
#define CTE_CHANNELFADE 16
#define CTE_CUSTOMVELOCITY 32
#define CTE_PERSISTANT 64
#define CTE_ISBEAM 128
//FTE's version of TEI_SHOWLMP2

View file

@ -90,7 +90,7 @@ void Sys_Vibrate(int count);
qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refreshrate);
#ifdef MULTITHREAD
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize);
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize);
void Sys_WaitOnThread(void *thread);
void Sys_DetachThread(void *thread);

View file

@ -0,0 +1,300 @@
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "quakedef.h"
#include <sys/types.h>
#include <sys/timeb.h>
#include <winsock.h>
#include <conio.h>
#ifdef MULTITHREAD
#include <process.h>
#endif
#ifdef MULTITHREAD
/* Thread creation calls */
typedef struct threadwrap_s
{
void (*func)(void *);
void *args;
} threadwrap_t;
// the thread call is wrapped so we don't need WINAPI everywhere
DWORD WINAPI threadwrapper(void *args)
{
threadwrap_t tw;
tw.func = ((threadwrap_t *)args)->func;
tw.args = ((threadwrap_t *)args)->args;
free(args);
tw.func(tw.args);
#ifndef WIN32CRTDLL
_endthreadex(0);
#endif
return 0;
}
#ifdef _DEBUG
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void SetThreadName(DWORD dwThreadID, char *threadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
#endif
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
threadwrap_t *tw = (threadwrap_t *)malloc(sizeof(threadwrap_t));
HANDLE handle;
DWORD tid;
if (!tw)
return NULL;
stacksize += 128; // wrapper overhead, also prevent default stack size
tw->func = func;
tw->args = args;
#ifdef WIN32CRTDLL
handle = (HANDLE)CreateThread(NULL, stacksize, &threadwrapper, (void *)tw, 0, &tid);
#else
handle = (HANDLE)_beginthreadex(NULL, stacksize, &threadwrapper, (void *)tw, 0, &tid);
#endif
if (!handle)
{
free(tw);
return NULL;
}
#ifdef _DEBUG
SetThreadName(tid, name);
#endif
return (void *)handle;
}
void Sys_DetachThread(void *thread)
{
CloseHandle((HANDLE)thread);
}
void Sys_WaitOnThread(void *thread)
{
WaitForSingleObject((HANDLE)thread, INFINITE);
CloseHandle((HANDLE)thread);
}
/* Mutex calls */
void *Sys_CreateMutex(void)
{
return (void *)CreateMutex(NULL, 0, NULL);
}
qboolean Sys_TryLockMutex(void *mutex)
{
return WaitForSingleObject(mutex, 0) == WAIT_OBJECT_0;
}
qboolean Sys_LockMutex(void *mutex)
{
return WaitForSingleObject(mutex, INFINITE) == WAIT_OBJECT_0;
}
qboolean Sys_UnlockMutex(void *mutex)
{
return !!ReleaseMutex(mutex);
}
void Sys_DestroyMutex(void *mutex)
{
CloseHandle(mutex);
}
/* Conditional wait calls */
/*
TODO: Windows Vista has condition variables as documented here:
http://msdn.microsoft.com/en-us/library/ms682052(VS.85).aspx
Note this uses Slim Reader/Writer locks (Vista+ exclusive)
or critical sections.
The condition variable implementation is based on the libSDL implementation.
This code could probably be made more efficient with the use of events or
different mechanisms but for now the main concern is a correct and
complete solution.
*/
typedef struct condvar_s
{
int waiting;
int signals;
CRITICAL_SECTION countlock;
CRITICAL_SECTION mainlock;
HANDLE wait_sem;
HANDLE wait_done;
} condvar_t;
void *Sys_CreateConditional(void)
{
condvar_t *cv;
cv = (condvar_t *)malloc(sizeof(condvar_t));
if (!cv)
return NULL;
cv->waiting = 0;
cv->signals = 0;
InitializeCriticalSection (&cv->mainlock);
InitializeCriticalSection (&cv->countlock);
cv->wait_sem = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
cv->wait_done = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
if (cv->wait_sem && cv->wait_done)
return (void *)cv;
// something failed so deallocate everything
if (cv->wait_done)
CloseHandle(cv->wait_done);
if (cv->wait_sem)
CloseHandle(cv->wait_sem);
DeleteCriticalSection(&cv->countlock);
DeleteCriticalSection(&cv->mainlock);
free(cv);
return NULL;
}
qboolean Sys_LockConditional(void *condv)
{
EnterCriticalSection(&((condvar_t *)condv)->mainlock);
return true;
}
qboolean Sys_UnlockConditional(void *condv)
{
LeaveCriticalSection(&((condvar_t *)condv)->mainlock);
return true;
}
qboolean Sys_ConditionWait(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
qboolean success;
// increase count for non-signaled waiting threads
EnterCriticalSection(&cv->countlock);
cv->waiting++;
LeaveCriticalSection(&cv->countlock);
LeaveCriticalSection(&cv->mainlock); // unlock as per condition variable definition
// wait on a signal
success = (WaitForSingleObject(cv->wait_sem, INFINITE) != WAIT_FAILED);
// update waiting count and alert signaling thread that we're done to avoid the deadlock condition
EnterCriticalSection(&cv->countlock);
if (cv->signals > 0)
{
ReleaseSemaphore(cv->wait_done, cv->signals, NULL);
cv->signals = 0;
}
cv->waiting--;
LeaveCriticalSection(&cv->countlock);
EnterCriticalSection(&cv->mainlock); // lock as per condition variable definition
return success;
}
qboolean Sys_ConditionSignal(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
// if there are non-signaled waiting threads, we signal one and wait on the response
EnterCriticalSection(&cv->countlock);
if (cv->waiting > cv->signals)
{
cv->signals++;
ReleaseSemaphore(cv->wait_sem, 1, NULL);
LeaveCriticalSection(&cv->countlock);
WaitForSingleObject(cv->wait_done, INFINITE);
}
else
LeaveCriticalSection(&cv->countlock);
return true;
}
qboolean Sys_ConditionBroadcast(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
// if there are non-signaled waiting threads, we signal all of them and wait on all the responses back
EnterCriticalSection(&cv->countlock);
if (cv->waiting > cv->signals)
{
int i, num_waiting;
num_waiting = (cv->waiting - cv->signals);
cv->signals = cv->waiting;
ReleaseSemaphore(cv->wait_sem, num_waiting, NULL);
LeaveCriticalSection(&cv->countlock);
// there's no call to wait for the same object multiple times so we need to loop through
// and burn up the semaphore count
for (i = 0; i < num_waiting; i++)
WaitForSingleObject(cv->wait_done, INFINITE);
}
else
LeaveCriticalSection(&cv->countlock);
return true;
}
void Sys_DestroyConditional(void *condv)
{
condvar_t *cv = (condvar_t *)condv;
CloseHandle(cv->wait_done);
CloseHandle(cv->wait_sem);
DeleteCriticalSection(&cv->countlock);
DeleteCriticalSection(&cv->mainlock);
free(cv);
}
#endif

View file

@ -1560,8 +1560,6 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertcount, unsigned i
if (TEXVALID(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].handle.hlsl.vert)
perm |= PERMUTATION_BUMPMAP;
if (TEXVALID(shaderstate.curtexnums->specular) && p->permu[perm|PERMUTATION_SPECULAR].handle.hlsl.vert)
perm |= PERMUTATION_SPECULAR;
if (TEXVALID(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].handle.hlsl.vert)
perm |= PERMUTATION_FULLBRIGHT;
if (p->permu[perm|PERMUTATION_UPPERLOWER].handle.hlsl.vert && (TEXVALID(shaderstate.curtexnums->upperoverlay) || TEXVALID(shaderstate.curtexnums->loweroverlay)))

View file

@ -1768,8 +1768,6 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertcount, unsigned i
if (TEXVALID(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].handle.hlsl.vert)
perm |= PERMUTATION_BUMPMAP;
if (TEXVALID(shaderstate.curtexnums->specular) && p->permu[perm|PERMUTATION_SPECULAR].handle.hlsl.vert)
perm |= PERMUTATION_SPECULAR;
if (TEXVALID(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].handle.hlsl.vert)
perm |= PERMUTATION_FULLBRIGHT;
if (p->permu[perm|PERMUTATION_UPPERLOWER].handle.hlsl.vert && (TEXVALID(shaderstate.curtexnums->upperoverlay) || TEXVALID(shaderstate.curtexnums->loweroverlay)))

View file

@ -33963,6 +33963,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\common\sys_win_threads.c"
>
</File>
<File
RelativePath="..\common\translate.c"
>

View file

@ -6,7 +6,7 @@ void DumpGLState(void);
#ifdef GLQUAKE
#define r_refract_fboival 0
#define r_refract_fboival 1
#include "glquake.h"
#include "shader.h"
@ -136,6 +136,8 @@ struct {
texid_t tex_normals;
texid_t tex_diffuse;
int fbo_diffuse;
int rb_depth;
int rb_stencil;
texid_t tex_sourcecol; /*this is used by $sourcecolour tgen*/
texid_t tex_sourcedepth;
int fbo_depthless;
@ -194,6 +196,7 @@ struct {
texid_t fogtexture;
texid_t normalisationcubemap;
float fogfar;
float depthrange;
batch_t **mbatches; //model batches (ie: not world)
};
@ -625,19 +628,31 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend
break;
case VATTR_NORMALS:
if (!shaderstate.sourcevbo->normals.gl.addr)
break;
{
shaderstate.sha_attr &= ~(1u<<i);
qglDisableVertexAttribArray(i);
continue;
}
GL_SelectVBO(shaderstate.sourcevbo->normals.gl.vbo);
qglVertexAttribPointer(VATTR_NORMALS, 3, GL_FLOAT, GL_FALSE, sizeof(vec3_t), shaderstate.sourcevbo->normals.gl.addr);
break;
case VATTR_SNORMALS:
if (!shaderstate.sourcevbo->svector.gl.addr)
break;
{
shaderstate.sha_attr &= ~(1u<<i);
qglDisableVertexAttribArray(i);
continue;
}
GL_SelectVBO(shaderstate.sourcevbo->svector.gl.vbo);
qglVertexAttribPointer(VATTR_SNORMALS, 3, GL_FLOAT, GL_FALSE, sizeof(vec3_t), shaderstate.sourcevbo->svector.gl.addr);
break;
case VATTR_TNORMALS:
if (!shaderstate.sourcevbo->tvector.gl.addr)
break;
{
shaderstate.sha_attr &= ~(1u<<i);
qglDisableVertexAttribArray(i);
continue;
}
GL_SelectVBO(shaderstate.sourcevbo->tvector.gl.vbo);
qglVertexAttribPointer(VATTR_TNORMALS, 3, GL_FLOAT, GL_FALSE, sizeof(vec3_t), shaderstate.sourcevbo->tvector.gl.addr);
break;
@ -780,7 +795,7 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
shaderstate.sourcevbo = &shaderstate.dummyvbo;
shaderstate.dummyvbo.indicies.gl.vbo = ibo;
if (gl_config.nofixedfunc)
if (shaderstate.allblackshader)
{
GL_SelectProgram(shaderstate.allblackshader);
@ -2981,8 +2996,6 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas
perm |= PERMUTATION_FRAMEBLEND;
if (TEXVALID(shaderstate.curtexnums->bump) && p->permu[perm|PERMUTATION_BUMPMAP].handle.glsl)
perm |= PERMUTATION_BUMPMAP;
if (/*TEXVALID(shaderstate.curtexnums->specular) &&*/ p->permu[perm|PERMUTATION_SPECULAR].handle.glsl)
perm |= PERMUTATION_SPECULAR;
if (TEXVALID(shaderstate.curtexnums->fullbright) && p->permu[perm|PERMUTATION_FULLBRIGHT].handle.glsl)
perm |= PERMUTATION_FULLBRIGHT;
if ((TEXVALID(shaderstate.curtexnums->loweroverlay) || TEXVALID(shaderstate.curtexnums->upperoverlay)) && p->permu[perm|PERMUTATION_UPPERLOWER].handle.glsl)
@ -3188,25 +3201,25 @@ void GLBE_SelectMode(backendmode_t mode)
void GLBE_SelectEntity(entity_t *ent)
{
if (shaderstate.curentity->flags & Q2RF_DEPTHHACK)
{
if (qglDepthRange)
qglDepthRange (gldepthmin, gldepthmax);
else if (qglDepthRangef)
qglDepthRangef (gldepthmin, gldepthmax);
}
float nd;
shaderstate.curentity = ent;
currententity = ent;
R_RotateForEntity(shaderstate.modelmatrix, shaderstate.modelviewmatrix, shaderstate.curentity, shaderstate.curentity->model);
Matrix4_Invert(shaderstate.modelmatrix, shaderstate.modelmatrixinv);
if (qglLoadMatrixf)
qglLoadMatrixf(shaderstate.modelviewmatrix);
if (shaderstate.curentity->flags & Q2RF_DEPTHHACK)
nd = 0.3;
else
nd = 1;
if (shaderstate.depthrange != nd)
{
shaderstate.depthrange = nd;
if (qglDepthRange)
qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
qglDepthRange (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
else if (qglDepthRangef)
qglDepthRangef (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
qglDepthRangef (gldepthmin, gldepthmin + shaderstate.depthrange*(gldepthmax-gldepthmin));
}
shaderstate.lastuniform = 0;
@ -3918,8 +3931,8 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
qglViewport (0, 0, vid.pixelwidth/2, vid.pixelheight/2);
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.pixelwidth/2;
r_refdef.vrect.height = vid.pixelheight/2;
r_refdef.vrect.width = vid.width/2;
r_refdef.vrect.height = vid.height/2;
GL_ForceDepthWritable();
qglClearColor(0, 0, 0, 0);
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -3950,8 +3963,8 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
orect = r_refdef.vrect;
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.pixelwidth/2;
r_refdef.vrect.height = vid.pixelheight/2;
r_refdef.vrect.width = vid.width/2;
r_refdef.vrect.height = vid.height/2;
GL_ForceDepthWritable();
qglClearColor(0, 0, 0, 0);
@ -3983,8 +3996,8 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist)
orect = r_refdef.vrect;
r_refdef.vrect.x = 0;
r_refdef.vrect.y = 0;
r_refdef.vrect.width = vid.pixelwidth/2;
r_refdef.vrect.height = vid.pixelheight/2;
r_refdef.vrect.width = vid.width/2;
r_refdef.vrect.height = vid.height/2;
qglClearColor(0, 0, 0, 0);
qglClear(GL_COLOR_BUFFER_BIT);
@ -4116,17 +4129,26 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
{
if (!shaderstate.fbo_diffuse)
{
int drb;
qglGenFramebuffersEXT(1, &shaderstate.fbo_diffuse);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shaderstate.fbo_diffuse);
//create an unnamed depth buffer
qglGenRenderbuffersEXT(1, &drb);
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, drb);
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth/2, vid.pixelheight/2);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, drb);
// qglDeleteRenderbuffersEXT(1, &drb);
qglGenRenderbuffersEXT(1, &shaderstate.rb_depth);
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, shaderstate.rb_depth);
if (gl_config.ext_packed_depth_stencil)
{
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, vid.pixelwidth/2, vid.pixelheight/2);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth);
}
else
{
qglGenRenderbuffersEXT(1, &shaderstate.rb_stencil);
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, vid.pixelwidth/2, vid.pixelheight/2);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_stencil);
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB, vid.pixelwidth/2, vid.pixelheight/2);
}
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, shaderstate.rb_depth);
qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
qglReadBuffer(GL_NONE);
@ -4286,6 +4308,8 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
RSpeedLocals();
shaderstate.mbatches = batches;
shaderstate.depthrange = 0;
TRACE(("GLBE_DrawWorld: %i %p\n", drawworld, vis));
if (!r_refdef.recurse)
@ -4323,6 +4347,12 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis)
qglDeleteFramebuffersEXT(1, &shaderstate.fbo_diffuse);
shaderstate.fbo_diffuse = 0;
}
if (shaderstate.rb_depth)
qglDeleteRenderbuffersEXT(1, &shaderstate.rb_depth);
shaderstate.rb_depth = 0;
if (shaderstate.rb_stencil)
qglDeleteRenderbuffersEXT(1, &shaderstate.rb_stencil);
shaderstate.rb_stencil = 0;
shaderstate.oldwidth = vid.pixelwidth;
shaderstate.oldheight = vid.pixelheight;

View file

@ -58,11 +58,12 @@ enum
TSF_HASCOLOURS = 1u<<1,
//these flags should not be found on disk
TSF_NOTIFY = 1u<<28, //modified on server, waiting for clients to be told about the change.
TSF_RELIGHT = 1u<<29, //height edited, needs relighting.
TSF_DIRTY = 1u<<30, //its heightmap has changed, the mesh needs rebuilding
TSF_EDITED = 1u<<31 //says it needs to be written if saved
#define TSF_INTERNAL (TSF_RELIGHT|TSF_DIRTY|TSF_EDITED)
#define TSF_INTERNAL (TSF_RELIGHT|TSF_DIRTY|TSF_EDITED|TSF_NOTIFY)
};
typedef struct
@ -278,9 +279,71 @@ static char *Terr_TempDiskSectionName(heightmap_t *hm, int sx, int sy)
sy &= CHUNKLIMIT-1;
return va("temp/%s/sect_%03x_%03x.hms", hm->path, sx, sy);
}
static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy)
static int dehex_e(int i, qboolean *error)
{
if (i >= '0' && i <= '9')
return (i-'0');
else if (i >= 'A' && i <= 'F')
return (i-'A'+10);
else if (i >= 'a' && i <= 'f')
return (i-'a'+10);
else
*error = true;
return 0;
}
static qboolean Terr_IsSectionFName(heightmap_t *hm, char *fname, int *sx, int *sy)
{
int l;
qboolean error = false;
*sx = 0xdeafbeef; //something clearly invalid
*sy = 0xdeafbeef;
//not this model...
if (!hm)
return false;
//expect the first 5 chars to be maps/ or temp/
fname += 5;
l = strlen(hm->path);
if (strncmp(fname, hm->path, l) || fname[l] != '/')
return false;
fname += l+1;
//fname now has a fixed length.
if (strlen(fname) != 16)
return false;
if (strncmp(fname, "sect_", 5) || fname[8] != '_' || (strcmp(fname+12, ".hms") && strcmp(fname+12, ".tmp")))
return false;
*sx = 0;
*sx += dehex_e(fname[5], &error)<<8;
*sx += dehex_e(fname[6], &error)<<4;
*sx += dehex_e(fname[7], &error)<<0;
*sy = 0;
*sy += dehex_e(fname[9], &error)<<8;
*sy += dehex_e(fname[10], &error)<<4;
*sy += dehex_e(fname[11], &error)<<0;
*sx += CHUNKBIAS;
*sy += CHUNKBIAS;
if ((unsigned)*sx >= CHUNKLIMIT)
*sx -= CHUNKLIMIT;
if ((unsigned)*sy >= CHUNKLIMIT)
*sy -= CHUNKLIMIT;
//make sure its a valid section index.
if ((unsigned)*sx >= CHUNKLIMIT)
return false;
if ((unsigned)*sy >= CHUNKLIMIT)
return false;
return true;
}
static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, dsection_t *ds, unsigned int dslen)
{
dsection_t *ds = NULL;
int i;
#ifndef SERVERONLY
dsmesh_t *dm;
@ -289,34 +352,13 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in
#endif
void *ptr;
if (mod_terrain_networked.ival)
{
#ifndef CLIENTONLY
if (hm != sv.world.worldmodel->terrain)
#endif
return NULL;
}
/*queue the file for download if we don't have it yet*/
if (FS_LoadFile(Terr_DiskSectionName(hm, sx, sy), (void**)&ds) < 0
#ifndef CLIENTONLY
&& !sv.state
#endif
)
{
#ifndef SERVERONLY
CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, sx, sy), NULL, 0);
#endif
return NULL;
}
if (ds)
{
if (ds->magic != SECTION_MAGIC)
return NULL;
if (ds->ver != SECTION_VER)
{
FS_FreeFile(ds);
//generate a new one if the version doesn't match
ds = NULL;
}
}
@ -373,10 +415,14 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in
Q_strncpyz(s->texname[2], ds->texname[2], sizeof(s->texname[2]));
Q_strncpyz(s->texname[3], ds->texname[3], sizeof(s->texname[3]));
CL_CheckOrEnqueDownloadFile(s->texname[0], NULL, 0);
CL_CheckOrEnqueDownloadFile(s->texname[1], NULL, 0);
CL_CheckOrEnqueDownloadFile(s->texname[2], NULL, 0);
CL_CheckOrEnqueDownloadFile(s->texname[3], NULL, 0);
if (*s->texname[0])
CL_CheckOrEnqueDownloadFile(s->texname[0], NULL, 0);
if (*s->texname[1])
CL_CheckOrEnqueDownloadFile(s->texname[1], NULL, 0);
if (*s->texname[2])
CL_CheckOrEnqueDownloadFile(s->texname[2], NULL, 0);
if (*s->texname[3])
CL_CheckOrEnqueDownloadFile(s->texname[3], NULL, 0);
/*load in the mixture/lighting*/
if (s->lightmap >= 0)
@ -450,7 +496,6 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in
s->ents[i].shaderRGBAf[3] = 1;
}
#endif
FS_FreeFile(ds);
}
else
{
@ -572,6 +617,92 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in
return s;
}
#ifndef SERVERONLY
qboolean Terr_DownloadedSection(char *fname)
{
int len;
void *fileptr;
int x, y;
heightmap_t *hm;
if (!cl.worldmodel)
return false;
hm = cl.worldmodel->terrain;
if (Terr_IsSectionFName(hm, fname, &x, &y))
{
len = FS_LoadFile(fname, &fileptr);
if (len < 0)
fileptr = NULL;
{
int cx = x / MAXSECTIONS;
int cy = y / MAXSECTIONS;
int sx = x & (MAXSECTIONS-1);
int sy = y & (MAXSECTIONS-1);
hmcluster_t *cluster = hm->cluster[cx + cy*MAXSECTIONS];
if (!cluster)
{
cluster = malloc(sizeof(*cluster));
if (cluster)
{
memset(cluster, 0, sizeof(*cluster));
hm->cluster[cx + cy*MAXSECTIONS] = cluster;
}
}
if (cluster)
cluster->section[sx + sy*MAXSECTIONS] = Terr_ReadSection(hm, cluster->section[sx + sy*MAXSECTIONS], x, y, fileptr, len);
}
if (fileptr)
FS_FreeFile(fileptr);
return true;
}
return false;
}
#endif
static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy)
{
hmsection_t *sect;
void *diskimage;
int len;
#ifndef SERVERONLY
//when using networked terrain, the client will never load a section from disk, but only loading it from the server
if (mod_terrain_networked.ival && !sv.state)
{
//try to download it now...
if (!cl.downloadlist)
CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, sx, sy), Terr_TempDiskSectionName(hm, sx, sy), DLLF_OVERWRITE|DLLF_TEMPORARY);
return NULL;
}
#endif
diskimage = NULL;
len = FS_LoadFile(Terr_DiskSectionName(hm, sx, sy), (void**)&diskimage);
/*queue the file for download if we don't have it yet*/
if (len < 0)
{
#ifndef CLIENTONLY
if (!sv.state) //server ignores any load errors, and will load a dummy section.
#endif
{
#ifndef SERVERONLY
if (!cl.downloadlist)
CL_CheckOrEnqueDownloadFile(Terr_DiskSectionName(hm, sx, sy), NULL, 0);
#endif
return NULL;
}
}
sect = Terr_ReadSection(hm, s, sx, sy, diskimage, len);
if (diskimage)
FS_FreeFile(diskimage);
return sect;
}
//doesn't clear edited/dirty flags or anything
static qboolean Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, char *fname)
{
@ -758,17 +889,11 @@ qboolean Terrain_LocateSection(char *name, flocation_t *loc)
//reject if its not in maps
if (strncmp(name, "maps/", 5))
return false;
//or too short
if (nlen < 17+5)
return false;
//reject if its not a section...
if (strncmp(name+nlen - 17, "/sect_", 6) || strcmp(name+nlen - 4, ".hms"))
return false;
//FIXME: find the right map instead
if (!sv.world.worldmodel)
return false;
hm = sv.world.worldmodel->terrain;
if (!hm) //its not terrain.
if (!Terr_IsSectionFName(hm, name, &x, &y))
return false;
x = dehex(name[nlen-17+ 6])<<8;
@ -1367,6 +1492,144 @@ void Terr_RebuildMesh(hmsection_t *s, int x, int y)
#endif
}
struct tdibctx
{
heightmap_t *hm;
int vx;
int vy;
entity_t *ent;
batch_t **batches;
};
void Terr_DrawInBounds(struct tdibctx *ctx, int x, int y, int w, int h)
{
vec3_t mins, maxs;
hmsection_t *s;
mesh_t *mesh;
int i;
batch_t *b;
heightmap_t *hm = ctx->hm;
if (w == 1 && h == 1)
{
mins[0] = (x+0 - CHUNKBIAS)*hm->sectionsize;
maxs[0] = (x+w - CHUNKBIAS)*hm->sectionsize;
mins[1] = (y+0 - CHUNKBIAS)*hm->sectionsize;
maxs[1] = (y+h - CHUNKBIAS)*hm->sectionsize;
mins[2] = -999999;
maxs[2] = 999999;
if (R_CullBox(mins, maxs))
return;
s = Terr_GetSection(hm, x, y, true);
if (!s)
return;
if (s->lightmap < 0)
Terr_LoadSection(hm, s, x, y);
if (s->flags & TSF_RELIGHT)
{
if (!hm->relight)
{
hm->relight = s;
hm->relightidx = 0;
hm->relightmin[0] = mins[0];
hm->relightmin[1] = mins[1];
}
}
mesh = &s->mesh;
if (s->flags & TSF_DIRTY)
{
s->flags &= ~TSF_DIRTY;
Terr_RebuildMesh(s, x, y);
}
//chuck out any batches for models in this section
for (i = 0; i < s->numents; i++)
{
if (s->ents[i].model && s->ents[i].model->type == mod_alias)
{
R_GAlias_GenerateBatches(&s->ents[i], ctx->batches);
}
}
if (s->flags & TSF_HASWATER)
{
mins[2] = s->waterheight;
maxs[2] = s->waterheight;
if (!R_CullBox(mins, maxs))
{
Terr_DrawTerrainWater(hm, mins, maxs, s->waterheight, 1, 1, 1, 1);
}
}
mins[2] = s->minh;
maxs[2] = s->maxh;
// if (!BoundsIntersect(mins, maxs, r_refdef.vieworg, r_refdef.vieworg))
if (R_CullBox(mins, maxs))
return;
b = BE_GetTempBatch();
if (!b)
return;
b->ent = ctx->ent;
b->shader = hm->shader;
b->flags = 0;
b->mesh = &s->amesh;
b->mesh[0] = mesh;
b->meshes = 1;
b->buildmeshes = NULL;
b->skin = &s->textures;
b->texture = NULL;
b->vbo = NULL;//&s->vbo;
b->lightmap[0] = s->lightmap;
b->lightmap[1] = -1;
b->lightmap[2] = -1;
b->lightmap[3] = -1;
b->next = ctx->batches[b->shader->sort];
ctx->batches[b->shader->sort] = b;
}
else if (w && h)
{
//divide and conquer, radiating outwards from the view.
if (w > h)
{
i = x + w;
w = x + w/2;
if (ctx->vx >= w)
{
Terr_DrawInBounds(ctx, w, y, i-w, h);
Terr_DrawInBounds(ctx, x, y, w-x, h);
}
else
{
Terr_DrawInBounds(ctx, x, y, w-x, h);
Terr_DrawInBounds(ctx, w, y, i-w, h);
}
}
else
{
i = y + h;
h = y + h/2;
if (ctx->vy >= h)
{
Terr_DrawInBounds(ctx, x, h, w, i-h);
Terr_DrawInBounds(ctx, x, y, w, h-y);
}
else
{
Terr_DrawInBounds(ctx, x, y, w, h-y);
Terr_DrawInBounds(ctx, x, h, w, i-h);
}
}
}
}
void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
{
//a 512*512 heightmap
@ -1382,6 +1645,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
batch_t *b;
hmsection_t *s;
int bounds[4];
struct tdibctx tdibctx;
if (hm->relight)
ted_dorelight(hm);
@ -1448,6 +1712,14 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
bounds[3] = hm->maxsegy;
}
tdibctx.hm = hm;
tdibctx.batches = batches;
tdibctx.ent = e;
tdibctx.vx = (r_refdef.vieworg[0] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
tdibctx.vy = (r_refdef.vieworg[1] + CHUNKBIAS*hm->sectionsize) / hm->sectionsize;
Terr_DrawInBounds(&tdibctx, bounds[0], bounds[2], bounds[1]-bounds[0], bounds[3]-bounds[2]);
/*
for (x = bounds[0]; x < bounds[1]; x++)
{
mins[0] = (x+0 - CHUNKBIAS)*hm->sectionsize;
@ -1530,6 +1802,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e)
batches[b->shader->sort] = b;
}
}
*/
}
typedef struct fragmentdecal_s fragmentdecal_t;
@ -2307,7 +2580,7 @@ static void ted_sethole(void *ctx, hmsection_t *s, int idx, float wx, float wy,
bit = mask;
else
bit = 0;
s->flags |= TSF_DIRTY|TSF_EDITED;
s->flags |= TSF_NOTIFY|TSF_DIRTY|TSF_EDITED;
s->holes = (s->holes & ~mask) | bit;
}
static void ted_heighttally(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w)
@ -2318,7 +2591,7 @@ static void ted_heighttally(void *ctx, hmsection_t *s, int idx, float wx, float
}
static void ted_heightsmooth(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w)
{
s->flags |= TSF_DIRTY|TSF_EDITED|TSF_RELIGHT;
s->flags |= TSF_NOTIFY|TSF_DIRTY|TSF_EDITED|TSF_RELIGHT;
/*interpolate the terrain towards a certain value*/
if (IS_NAN(s->heights[idx]))
@ -2328,13 +2601,13 @@ static void ted_heightsmooth(void *ctx, hmsection_t *s, int idx, float wx, float
}
static void ted_heightraise(void *ctx, hmsection_t *s, int idx, float wx, float wy, float strength)
{
s->flags |= TSF_DIRTY|TSF_EDITED|TSF_RELIGHT;
s->flags |= TSF_NOTIFY|TSF_DIRTY|TSF_EDITED|TSF_RELIGHT;
/*raise the terrain*/
s->heights[idx] += strength;
}
static void ted_heightset(void *ctx, hmsection_t *s, int idx, float wx, float wy, float strength)
{
s->flags |= TSF_DIRTY|TSF_EDITED|TSF_RELIGHT;
s->flags |= TSF_NOTIFY|TSF_DIRTY|TSF_EDITED|TSF_RELIGHT;
/*set the terrain to a specific value*/
s->heights[idx] = *(float*)ctx;
}
@ -2342,6 +2615,8 @@ static void ted_heightset(void *ctx, hmsection_t *s, int idx, float wx, float wy
static void ted_mixconcentrate(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w)
{
unsigned char *lm = ted_getlightmap(s, idx);
s->flags |= TSF_NOTIFY|TSF_EDITED;
/*concentrate the lightmap values to a single channel*/
if (lm[0] > lm[1] && lm[0] > lm[2] && lm[0] > (255-(lm[0]+lm[1]+lm[2])))
{
@ -2374,6 +2649,9 @@ static void ted_mixnoise(void *ctx, hmsection_t *s, int idx, float wx, float wy,
unsigned char *lm = ted_getlightmap(s, idx);
vec4_t v;
float sc;
s->flags |= TSF_NOTIFY|TSF_EDITED;
/*randomize the lightmap somewhat (you'll probably want to concentrate it a bit after)*/
v[0] = (rand()&255);
v[1] = (rand()&255);
@ -2396,6 +2674,8 @@ static void ted_mixpaint(void *ctx, hmsection_t *s, int idx, float wx, float wy,
if (w > 1)
w = 1;
s->flags |= TSF_NOTIFY|TSF_EDITED;
for (t = 0; t < 4; t++)
{
if (!strncmp(s->texname[t], texname, sizeof(s->texname[t])-1))
@ -2487,6 +2767,8 @@ static void ted_mixset(void *ctx, hmsection_t *s, int idx, float wx, float wy, f
unsigned char *lm = ted_getlightmap(s, idx);
if (w > 1)
w = 1;
s->flags |= TSF_NOTIFY|TSF_EDITED;
lm[2] = lm[2]*(1-w) + (255*((float*)ctx)[0]*(w));
lm[1] = lm[1]*(1-w) + (255*((float*)ctx)[1]*(w));
lm[0] = lm[0]*(1-w) + (255*((float*)ctx)[2]*(w));
@ -2507,7 +2789,7 @@ static void ted_tint(void *ctx, hmsection_t *s, int idx, float wx, float wy, flo
float *newval = ctx;
if (w > 1)
w = 1;
s->flags |= TSF_DIRTY|TSF_EDITED|TSF_HASCOLOURS; /*dirty because of the vbo*/
s->flags |= TSF_NOTIFY|TSF_DIRTY|TSF_EDITED|TSF_HASCOLOURS; /*dirty because of the vbo*/
col[0] = col[0]*(1-w) + (newval[0]*(w));
col[1] = col[1]*(1-w) + (newval[1]*(w));
col[2] = col[2]*(1-w) + (newval[2]*(w));

View file

@ -278,7 +278,7 @@ void RMod_Think (void)
relightthreads = sizeof(relightthread)/sizeof(relightthread[0]);
wantrelight = true;
for (i = 0; i < relightthreads; i++)
relightthread[i] = Sys_CreateThread(RelightThread, lightmodel, THREADP_NORMAL, 0);
relightthread[i] = Sys_CreateThread("relight", RelightThread, lightmodel, THREADP_NORMAL, 0);
}
if (relitsurface < lightmodel->numsurfaces)
{

View file

@ -1030,6 +1030,7 @@ qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axi
unsigned int Heightmap_PointContents(model_t *model, vec3_t axis[3], vec3_t org);
struct fragmentdecal_s;
void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model);
qboolean Terr_DownloadedSection(char *fname);
#endif

View file

@ -567,13 +567,8 @@ void R_RenderScene (void)
RQ_BeginFrame();
if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
{
TRACE(("dbg: calling R_DrawWorld\n"));
Surf_DrawWorld (); // adds static entities to the list
}
else
BE_DrawWorld(false, NULL);
TRACE(("dbg: calling Surf_DrawWorld\n"));
Surf_DrawWorld (); // adds static entities to the list
S_ExtraUpdate (); // don't let sound get messed up if going slow
@ -732,10 +727,49 @@ static void TransformDir(vec3_t in, vec3_t planea[3], vec3_t viewa[3], vec3_t re
VectorMA(result, d, viewa[i], result);
}
}
static float sgn(float a)
{
if (a > 0.0F) return (1.0F);
if (a < 0.0F) return (-1.0F);
return (0.0F);
}
void R_ObliqueNearClip(mplane_t *wplane)
{
float f;
vec4_t q, c;
vec3_t ping, pong;
vec4_t vplane;
//convert world plane into view space
Matrix4x4_CM_Transform3x3(r_refdef.m_view, wplane->normal, vplane);
VectorScale(wplane->normal, wplane->dist, ping);
Matrix4x4_CM_Transform3(r_refdef.m_view, ping, pong);
vplane[3] = -DotProduct(pong, vplane);
// Calculate the clip-space corner point opposite the clipping plane
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
// transform it into camera space by multiplying it
// by the inverse of the projection matrix
q[0] = (sgn(vplane[0]) + r_refdef.m_projection[8]) / r_refdef.m_projection[0];
q[1] = (sgn(vplane[1]) + r_refdef.m_projection[9]) / r_refdef.m_projection[5];
q[2] = -1.0F;
q[3] = (1.0F + r_refdef.m_projection[10]) / r_refdef.m_projection[14];
// Calculate the scaled plane vector
f = 2.0F / DotProduct4(vplane, q);
Vector4Scale(vplane, f, c);
// Replace the third row of the projection matrix
r_refdef.m_projection[2] = c[0];
r_refdef.m_projection[6] = c[1];
r_refdef.m_projection[10] = c[2] + 1.0F;
r_refdef.m_projection[14] = c[3];
}
void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype)
{
entity_t *view;
GLdouble glplane[4];
// GLdouble glplane[4];
plane_t plane;
refdef_t oldrefdef;
mesh_t *mesh = batch->mesh[batch->firstmesh];
@ -892,22 +926,23 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype)
/*FIXME: can we get away with stenciling the screen?*/
/*Add to frustum culling instead of clip planes?*/
if (qglClipPlane)
{
glplane[0] = -plane.normal[0];
glplane[1] = -plane.normal[1];
glplane[2] = -plane.normal[2];
glplane[3] = plane.dist;
qglClipPlane(GL_CLIP_PLANE0, glplane);
qglEnable(GL_CLIP_PLANE0);
}
// if (qglClipPlane)
// {
// glplane[0] = -plane.normal[0];
// glplane[1] = -plane.normal[1];
// glplane[2] = -plane.normal[2];
// glplane[3] = plane.dist;
// qglClipPlane(GL_CLIP_PLANE0, glplane);
// qglEnable(GL_CLIP_PLANE0);
// }
frustum[4].normal[0] = plane.normal[0];
frustum[4].normal[1] = plane.normal[1];
frustum[4].normal[2] = plane.normal[2];
frustum[4].dist = plane.dist + 0.01;
R_ObliqueNearClip(&frustum[4]);
R_RenderScene();
if (qglClipPlane)
qglDisable(GL_CLIP_PLANE0);
// if (qglClipPlane)
// qglDisable(GL_CLIP_PLANE0);
for (sort = 0; sort < SHADER_SORT_COUNT; sort++)
for (batch = blist[sort]; batch; batch = batch->next)
@ -963,10 +998,6 @@ void R_Clear (void)
gldepthmax = 1;
gldepthfunc=GL_LEQUAL;
}
if (qglDepthRange)
qglDepthRange (gldepthmin, gldepthmax);
else if (qglDepthRangef)
qglDepthRangef (gldepthmin, gldepthmax);
}
#if 0

View file

@ -834,7 +834,6 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
static char *permutationname[] =
{
"#define BUMP\n",
"#define SPECULAR\n",
"#define FULLBRIGHT\n",
"#define UPPERLOWER\n",
"#define DELUXE\n",
@ -854,6 +853,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
int cvartypes[64];
int cvarcount = 0;
qboolean onefailed = false;
extern cvar_t gl_specular;
if (qrenderer != qrtype)
{
@ -983,6 +983,8 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
permutationdefines[pn++] = "#define RELIEFMAPPING\n";
}
}
if (gl_specular.value)
permutationdefines[pn++] = "#define SPECULAR\n";
permutationdefines[pn++] = NULL;
if (0)

View file

@ -2654,37 +2654,6 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis)
qglDisable(GL_DEPTH_CLAMP_ARB);
//end stencil writing.
/*stencil writing probably changed the vertex pointer, and our backend caches it*/
// PPL_RevertToKnownState();
#if 0 //draw the stencil stuff to the red channel
qglMatrixMode(GL_PROJECTION);
qglPushMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPushMatrix();
GL_Set2D();
{
qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
qglStencilFunc(GL_GREATER, sref, ~0);
R2D_ConsoleBackground(vid.height);
qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
qglStencilFunc(GL_LESS, sref, ~0);
R2D_ConsoleBackground(vid.height);
qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
qglStencilFunc(GL_EQUAL, sref, ~0);
R2D_ConsoleBackground(vid.height);
}
qglMatrixMode(GL_PROJECTION);
qglPopMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPopMatrix();
#endif
BE_SelectMode(BEM_LIGHT);
Sh_DrawEntLighting(dl, colour);
qglDisable(GL_STENCIL_TEST);

View file

@ -541,6 +541,8 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
gl_config.ext_texture_filter_anisotropic = 0;
gl_config.ext_packed_depth_stencil = GL_CheckExtension("GL_EXT_packed_depth_stencil");
if (GL_CheckExtension("GL_EXT_texture_filter_anisotropic"))
{
qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_config.ext_texture_filter_anisotropic);
@ -616,7 +618,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
qglStencilOpSeparateATI = NULL;
qglActiveStencilFaceEXT = NULL;
if (gl_config.gles && gl_config.glversion >= 2)
if ((gl_config.gles && gl_config.glversion >= 2) || gl_config.glversion >= 3) //theoretically that should be a 2 not 3.
qglStencilOpSeparateATI = (void *) getglext("glStencilOpSeparate");
else if (GL_CheckExtension("GL_ATI_separate_stencil"))
qglStencilOpSeparateATI = (void *) getglext("glStencilOpSeparateATI");

View file

@ -2145,8 +2145,6 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
vid_canalttab = true;
S_Restart_f();
Cvar_Hook(&_vid_wait_override, VID_Wait_Override_Callback);
Cvar_Hook(&vid_wndalpha, VID_WndAlpha_Override_Callback);

View file

@ -197,6 +197,7 @@ typedef struct {
qboolean arb_shader_objects;
qboolean ext_framebuffer_objects;
qboolean ext_stencil_wrap;
qboolean ext_packed_depth_stencil;
qboolean arb_depth_clamp;
int ext_texture_filter_anisotropic;
} gl_config_t;

View file

@ -123,6 +123,10 @@ extern qlpMTex2FUNC qglMultiTexCoord2fARB;
#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
#endif
#ifndef GL_EXT_packed_depth_stencil
#define GL_DEPTH24_STENCIL8_EXT 0x88F0
#endif
#ifndef GL_ARB_shadow
#define GL_ARB_shadow
#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C
@ -690,8 +694,6 @@ typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
#endif
#ifndef GL_VERSION_3_0
#define GL_MAJOR_VERSION 0x821B
#define GL_MINOR_VERSION 0x821C

View file

@ -262,15 +262,14 @@ typedef struct
enum{
PERMUTATION_GENERIC = 0,
PERMUTATION_BUMPMAP = 1,
PERMUTATION_SPECULAR = 2,
PERMUTATION_FULLBRIGHT = 4,
PERMUTATION_UPPERLOWER = 8,
PERMUTATION_DELUXE = 16,
PERMUTATION_SKELETAL = 32,
PERMUTATION_FOG = 64,
PERMUTATION_FRAMEBLEND = 128,
PERMUTATION_LIGHTSTYLES = 256,
PERMUTATIONS = 512
PERMUTATION_FULLBRIGHT = 2,
PERMUTATION_UPPERLOWER = 4,
PERMUTATION_DELUXE = 8,
PERMUTATION_SKELETAL = 16,
PERMUTATION_FOG = 32,
PERMUTATION_FRAMEBLEND = 64,
PERMUTATION_LIGHTSTYLES = 128,
PERMUTATIONS = 256
};
enum shaderattribs_e

View file

@ -516,7 +516,7 @@ qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyF
dl->file = file;
dl->notify = NotifyFunction;
dl->threadctx = Sys_CreateThread(DL_Thread_Work, dl, THREADP_NORMAL, 0);
dl->threadctx = Sys_CreateThread("download", DL_Thread_Work, dl, THREADP_NORMAL, 0);
if (!dl->threadctx)
return false;

View file

@ -526,3 +526,39 @@ r_part ce_chunk_bone
rotationspeed 425
}
r_part ce_fountain
{
texture "particles/fteparticlefont.tga"
tcoords 1 1 63 63 256 2 64
count 1
scale 10
rotationspeed -64 64
scalefactor 1
die 1
alpha 0.2
rgb 128 128 128
rgbdelta 0 -32 -32
blend add
spawnvel 100
veladd 1
gravity 800
}
r_part ce_snow
{
texture "particles/fteparticlefont.tga"
tcoords 1 1 63 63 256 2 64
count 1
scale 30
scaledelta -10
rotationspeed -64 64
scalefactor 1
die 1
alpha 0.2
rgb 255 255 255
rgbdelta 0 -32 -32
friction 1
blend add
veladd 1
gravity 200
}

View file

@ -591,10 +591,6 @@ void PR_Deinit(void)
World_ODE_End(&sv.world);
#endif
#ifdef SQL
SQL_DeInit();
#endif
PRSV_ClearThreads();
if (svprogfuncs)
{
@ -610,6 +606,11 @@ void PR_Deinit(void)
sv.strings.lightstyles[i] = NULL;
}
}
#ifdef SQL
SQL_KillServers();
#endif
#ifdef TEXTEDITOR
Editor_ProgsKilled(svprogfuncs);
#endif
@ -622,6 +623,13 @@ void PR_Deinit(void)
SpectatorDisconnect = 0;
}
void PR_Shutdown(void)
{
PR_Deinit();
#ifdef SQL
SQL_DeInit();
#endif
}
#define QW_PROGHEADER_CRC 54730
#define NQ_PROGHEADER_CRC 5927
@ -2061,46 +2069,59 @@ static int SV_CustomTEnt_Register(char *effectname, int nettype, float *stain_rg
return i;
}
static void SV_CustomTEnt_Spawn(int index, float *org, float *org2, int count, float *dir)
static int SV_CustomTEnt_Spawn(int index, float *org, float *org2, int count, float *dir)
{
static int persist_id;
int type;
multicast_t mct = MULTICAST_PVS;
if (index < 0 || index >= 255)
return;
return -1;
type = sv.customtents[index].netstyle;
MSG_WriteByte(&sv.multicast, svcfte_customtempent);
MSG_WriteByte(&sv.multicast, index);
if (type & CTE_PERSISTANT)
{
persist_id++;
if (persist_id >= 0x8000)
persist_id = 1;
if (sv.state == ss_loading)
mct = MULTICAST_INIT;
else
mct = MULTICAST_ALL;
MSG_WriteShort(&sv.multicast, persist_id);
}
MSG_WriteCoord(&sv.multicast, org[0]);
MSG_WriteCoord(&sv.multicast, org[1]);
MSG_WriteCoord(&sv.multicast, org[2]);
type = sv.customtents[index].netstyle;
if (type & CTE_ISBEAM)
{
MSG_WriteCoord(&sv.multicast, org2[0]);
MSG_WriteCoord(&sv.multicast, org2[1]);
MSG_WriteCoord(&sv.multicast, org2[2]);
}
else
if (type & CTE_CUSTOMCOUNT)
{
if (type & CTE_CUSTOMCOUNT)
{
MSG_WriteByte(&sv.multicast, count);
}
if (type & CTE_CUSTOMVELOCITY)
{
MSG_WriteCoord(&sv.multicast, dir[0]);
MSG_WriteCoord(&sv.multicast, dir[1]);
MSG_WriteCoord(&sv.multicast, dir[2]);
}
else if (type & CTE_CUSTOMDIRECTION)
{
vec3_t norm;
VectorNormalize2(dir, norm);
MSG_WriteDir(&sv.multicast, norm);
}
MSG_WriteByte(&sv.multicast, count);
}
if (type & CTE_CUSTOMVELOCITY)
{
MSG_WriteCoord(&sv.multicast, dir[0]);
MSG_WriteCoord(&sv.multicast, dir[1]);
MSG_WriteCoord(&sv.multicast, dir[2]);
}
else if (type & CTE_CUSTOMDIRECTION)
{
vec3_t norm;
VectorNormalize2(dir, norm);
MSG_WriteDir(&sv.multicast, norm);
}
SV_MulticastProtExt (org, MULTICAST_PVS, pr_global_struct->dimension_send, PEXT_CUSTOMTEMPEFFECTS, 0); //now send the new multicast to all that will.
SV_MulticastProtExt (org, mct, pr_global_struct->dimension_send, PEXT_CUSTOMTEMPEFFECTS, 0); //now send the new multicast to all that will.
return persist_id;
}
@ -5441,6 +5462,8 @@ void PF_sqlopenquery (progfuncs_t *prinst, struct globalvars_s *pr_globals)
qother = pr_global_struct->other;
qotherid = PROG_TO_EDICT(prinst, qother)->xv->uniquespawnid;
Con_DPrintf("SQL Query: %s\n", querystr);
G_FLOAT(OFS_RETURN) = SQL_NewQuery(server, callfunc, querytype, qself, qselfid, qother, qotherid, querystr);
return;
}
@ -6763,11 +6786,10 @@ void SV_RegisterH2CustomTents(void)
if (progstype == PROG_H2)
{
// ce_rain
// ce_fountain
h2customtents[ce_rain] = SV_CustomTEnt_Register("ce_rain", CTE_PERSISTANT|CTE_CUSTOMVELOCITY|CTE_ISBEAM|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_fountain] = SV_CustomTEnt_Register("ce_fountain", CTE_PERSISTANT|CTE_CUSTOMVELOCITY|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_quake] = SV_CustomTEnt_Register("ce_quake", 0, NULL, 0, NULL, 0, 0, NULL);
// ce_white_smoke
// ce_white_smoke (special)
h2customtents[ce_bluespark] = SV_CustomTEnt_Register("ce_bluespark", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_yellowspark] = SV_CustomTEnt_Register("ce_yellowspark", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_sm_circle_exp] = SV_CustomTEnt_Register("ce_sm_circle_exp", 0, NULL, 0, NULL, 0, 0, NULL);
@ -6783,8 +6805,8 @@ void SV_RegisterH2CustomTents(void)
h2customtents[ce_floor_explosion] = SV_CustomTEnt_Register("ce_floor_explosion", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_rider_death] = SV_CustomTEnt_Register("ce_rider_death", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_blue_explosion] = SV_CustomTEnt_Register("ce_blue_explosion", 0, NULL, 0, NULL, 0, 0, NULL);
// ce_green_smoke
// ce_grey_smoke
// ce_green_smoke (special)
// ce_grey_smoke (special)
h2customtents[ce_red_smoke] = SV_CustomTEnt_Register("ce_red_smoke", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_slow_white_smoke] = SV_CustomTEnt_Register("ce_slow_white_smoke", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_redspark] = SV_CustomTEnt_Register("ce_redspark", 0, NULL, 0, NULL, 0, 0, NULL);
@ -6798,7 +6820,7 @@ void SV_RegisterH2CustomTents(void)
h2customtents[ce_xbow_explosion] = SV_CustomTEnt_Register("ce_xbow_explosion", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_new_explosion] = SV_CustomTEnt_Register("ce_new_explosion", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_magic_missile_explosion] = SV_CustomTEnt_Register("ce_magic_missile_explosion", 0, NULL, 0, NULL, 0, 0, NULL);
// ce_ghost
h2customtents[ce_ghost] = SV_CustomTEnt_Register("ce_ghost", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_bone_explosion] = SV_CustomTEnt_Register("ce_bone_explosion", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_redcloud] = SV_CustomTEnt_Register("ce_redcloud", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_teleporterpuffs] = SV_CustomTEnt_Register("ce_teleporterpuffs", 0, NULL, 0, NULL, 0, 0, NULL);
@ -6806,7 +6828,7 @@ void SV_RegisterH2CustomTents(void)
h2customtents[ce_boneshard] = SV_CustomTEnt_Register("ce_boneshard", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_boneshrapnel] = SV_CustomTEnt_Register("ce_boneshrapnel", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_flamestream] = SV_CustomTEnt_Register("ce_flamestream", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL);
// ce_snow,
h2customtents[ce_snow] = SV_CustomTEnt_Register("ce_snow", CTE_PERSISTANT|CTE_CUSTOMVELOCITY|CTE_ISBEAM|CTE_CUSTOMCOUNT, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_gravitywell] = SV_CustomTEnt_Register("ce_gravitywell", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_bldrn_expl] = SV_CustomTEnt_Register("ce_bldrn_expl", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_acid_muzzfl] = SV_CustomTEnt_Register("ce_acid_muzzfl", CTE_CUSTOMVELOCITY, NULL, 0, NULL, 0, 0, NULL);
@ -6818,7 +6840,7 @@ void SV_RegisterH2CustomTents(void)
h2customtents[ce_acid_splat] = SV_CustomTEnt_Register("ce_acid_splat", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_acid_expl] = SV_CustomTEnt_Register("ce_acid_expl", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_fboom] = SV_CustomTEnt_Register("ce_fboom", 0, NULL, 0, NULL, 0, 0, NULL);
// ce_chunk
// ce_chunk (special)
h2customtents[ce_bomb] = SV_CustomTEnt_Register("ce_bomb", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_brn_bounce] = SV_CustomTEnt_Register("ce_brn_bounce", 0, NULL, 0, NULL, 0, 0, NULL);
h2customtents[ce_lshock] = SV_CustomTEnt_Register("ce_lshock", 0, NULL, 0, NULL, 0, 0, NULL);
@ -6870,9 +6892,10 @@ void SV_RegisterH2CustomTents(void)
}
static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
// float *min, *max, *angle, *size;
// float colour, wait, radius, frame, framelength, duration;
// int flags, type, skin;
float *min, *max, *angle, *size;
float colour;
// float wait, radius, frame, framelength, duration;
// int flags, skin;
int type;
float *org, *dir;
int count;
@ -6883,40 +6906,50 @@ static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s
{
case ce_rain:
/*this effect is meant to be persistant (endeffect is never used)*/
//min = G_VECTOR(OFS_PARM1);
//max = G_VECTOR(OFS_PARM2);
//size = G_VECTOR(OFS_PARM3);
//dir = G_VECTOR(OFS_PARM4);
//colour = G_FLOAT(OFS_PARM5);
//count = G_FLOAT(OFS_PARM6);
min = G_VECTOR(OFS_PARM1);
max = G_VECTOR(OFS_PARM2);
size = G_VECTOR(OFS_PARM3);
dir = G_VECTOR(OFS_PARM4);
colour = G_FLOAT(OFS_PARM5);
count = G_FLOAT(OFS_PARM6);
//wait = G_FLOAT(OFS_PARM7);
/*FIXME: not spawned - this persistant effect is created by a map object, all attributes are custom.*/
Con_Printf("FTE-H2 FIXME: ce_rain not supported!\n");
if (colour == 0 && size == 0)
SV_CustomTEnt_Spawn(h2customtents[efnum], min, max, count, dir);
else
Con_Printf("FTE-H2 FIXME: ce_rain not supported!\n");
return;
break;
case ce_snow:
/*this effect is meant to be persistant (endeffect is never used)*/
//min = G_VECTOR(OFS_PARM1);
//max = G_VECTOR(OFS_PARM2);
min = G_VECTOR(OFS_PARM1);
max = G_VECTOR(OFS_PARM2);
//flags = G_FLOAT(OFS_PARM3);
//dir = G_VECTOR(OFS_PARM4);
//count = G_FLOAT(OFS_PARM5);
/*FIXME: not spawned - this persistant effect is created by a map object (might be delay-spawned), all attributes are custom.*/
Con_Printf("FTE-H2 FIXME: ce_snow not supported!\n");
dir = G_VECTOR(OFS_PARM4);
count = G_FLOAT(OFS_PARM5);
/*FIXME: we ignore any happy/fluffy/mixed snow types*/
SV_CustomTEnt_Spawn(h2customtents[efnum], min, max, count, dir);
// Con_Printf("FTE-H2 FIXME: ce_snow not supported!\n");
return;
break;
case ce_fountain:
/*this effect is meant to be persistant (endeffect is never used)*/
//org = G_VECTOR(OFS_PARM1);
//angle = G_VECTOR(OFS_PARM2);
//dir = G_VECTOR(OFS_PARM3);
//colour = G_FLOAT(OFS_PARM4);
//count = G_FLOAT(OFS_PARM5);
org = G_VECTOR(OFS_PARM1);
angle = G_VECTOR(OFS_PARM2);
dir = G_VECTOR(OFS_PARM3);
colour = G_FLOAT(OFS_PARM4);
count = G_FLOAT(OFS_PARM5);
/*FIXME: not spawned - this persistant effect is created by a map object, all attributes are custom.*/
Con_Printf("FTE-H2 FIXME: ce_fountain not supported!\n");
if (colour == 407)
{
dir[2] *= 2;
SV_CustomTEnt_Spawn(h2customtents[efnum], org, NULL, count, dir);
}
else
Con_Printf("FTE-H2 FIXME: ce_fountain not supported!\n");
return;
break;
case ce_quake:
/*this effect is meant to be persistant*/
org = G_VECTOR(OFS_PARM1);
@ -6924,7 +6957,7 @@ static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s
if (h2customtents[efnum] != -1)
{
SV_CustomTEnt_Spawn(h2customtents[efnum], org, NULL, 1, NULL);
G_FLOAT(OFS_RETURN) = SV_CustomTEnt_Spawn(h2customtents[efnum], org, NULL, 1, NULL);
return;
}
break;
@ -7077,7 +7110,7 @@ static void QCBUILTIN PF_h2starteffect(progfuncs_t *prinst, struct globalvars_s
/*FIXME: meant to be persistant until removed*/
if (h2customtents[efnum] != -1)
{
SV_CustomTEnt_Spawn(h2customtents[efnum], org, NULL, 1, dir);
G_FLOAT(OFS_RETURN) = SV_CustomTEnt_Spawn(h2customtents[efnum], org, NULL, 1, dir);
return;
}
break;
@ -7228,10 +7261,11 @@ static void QCBUILTIN PF_CustomTEnt(progfuncs_t *prinst, struct globalvars_s *pr
{
int type;
int arg;
float *org = G_VECTOR(OFS_PARM1);
float *org;
multicast_t mcd = MULTICAST_PVS;
if (sv.multicast.cursize)
SV_MulticastProtExt (org, MULTICAST_PVS, pr_global_struct->dimension_send, 0, PEXT_CUSTOMTEMPEFFECTS); //do a multicast with the current buffer to all players who won't get the new effect.
SV_MulticastProtExt (vec3_origin, MULTICAST_ALL, pr_global_struct->dimension_send, 0, PEXT_CUSTOMTEMPEFFECTS); //do a multicast with the current buffer to all players who won't get the new effect.
type = G_FLOAT(OFS_PARM0);
if (type < 0 || type >= 255)
@ -7239,12 +7273,29 @@ static void QCBUILTIN PF_CustomTEnt(progfuncs_t *prinst, struct globalvars_s *pr
MSG_WriteByte(&sv.multicast, svcfte_customtempent);
MSG_WriteByte(&sv.multicast, type);
type = sv.customtents[type].netstyle;
arg = 1;
if (type & CTE_PERSISTANT)
{
int id = G_EDICTNUM(prinst, OFS_PARM0+arg*3);
arg++;
mcd = MULTICAST_ALL_R;
if (arg == *prinst->callargc)
{
MSG_WriteShort(&sv.multicast, id | 0x8000);
SV_MulticastProtExt (vec3_origin, mcd, pr_global_struct->dimension_send, PEXT_CUSTOMTEMPEFFECTS, 0); //now send the new multicast to all that will.
return;
}
MSG_WriteShort(&sv.multicast, id);
}
org = G_VECTOR(OFS_PARM0+arg*3);
MSG_WriteCoord(&sv.multicast, org[0]);
MSG_WriteCoord(&sv.multicast, org[1]);
MSG_WriteCoord(&sv.multicast, org[2]);
type = sv.customtents[type].netstyle;
arg = 2;
if (type & CTE_ISBEAM)
{
MSG_WriteCoord(&sv.multicast, G_VECTOR(OFS_PARM0+arg*3)[0]);
@ -7278,7 +7329,7 @@ static void QCBUILTIN PF_CustomTEnt(progfuncs_t *prinst, struct globalvars_s *pr
if (arg != *prinst->callargc)
Con_Printf("PF_CusromTEnt: bad number of arguments for particle type\n");
SV_MulticastProtExt (org, MULTICAST_PVS, pr_global_struct->dimension_send, PEXT_CUSTOMTEMPEFFECTS, 0); //now send the new multicast to all that will.
SV_MulticastProtExt (org, mcd, pr_global_struct->dimension_send, PEXT_CUSTOMTEMPEFFECTS, 0); //now send the new multicast to all that will.
}
//float(string effectname) particleeffectnum (EXT_CSQC)

View file

@ -29,7 +29,8 @@ struct edict_s;
void SVQ1_CvarChanged(cvar_t *var);
#define NewGetEdictFieldValue GetEdictFieldValue
void Q_SetProgsParms(qboolean forcompiler);
void PR_Deinit(void);
void PR_Deinit(void); //server shutting down
void PR_Shutdown(void); //server quitting
void PR_LoadGlabalStruct(void);
void Q_InitProgs(void);
void PR_RegisterFields(void);

View file

@ -30,7 +30,8 @@ typedef enum multicast_e
MULTICAST_PVS_R,
MULTICAST_ONE,
MULTICAST_ONE_R
MULTICAST_ONE_R,
MULTICAST_INIT
} multicast_t;
extern float pm_q2stepheight;

View file

@ -2210,7 +2210,8 @@ void SV_InitOperatorCommands (void)
Cmd_AddCommand ("pin_delete", SV_Pin_Delete_f);
Cmd_AddCommand ("pin_add", SV_Pin_Add_f);
cl_warncmd.value = 1;
if (isDedicated)
cl_warncmd.value = 1;
}
#endif

View file

@ -676,9 +676,7 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us
Mod_ClearAll ();
Hunk_FreeToLowMark (host_hunklevel);
#ifdef USEODE
World_ODE_End(&sv.world);
#endif
PR_Deinit();
// wipe the entire per-level structure
memset (&sv, 0, sizeof(sv));

View file

@ -253,7 +253,7 @@ void SV_Shutdown (void)
sv_fraglogfile = NULL;
}
PR_Deinit();
PR_Shutdown();
#ifdef USEODE
World_ODE_Shutdown();
#endif
@ -274,6 +274,7 @@ void SV_Shutdown (void)
sv_staticentities = NULL;
}
T_FreeStrings();
SV_GibFilterPurge();

View file

@ -510,6 +510,16 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
qboolean reliable;
int pnum = 0;
if (to == MULTICAST_INIT)
{
//we only have one signon buffer. make sure you don't put non-identical protocols in the buffer
SV_FlushSignon();
SZ_Write (&sv.signon, sv.multicast.data, sv.multicast.cursize);
//and send to players that are already on
to = MULTICAST_ALL_R;
}
// to = MULTICAST_ALL;
#ifdef Q2BSPS
if (sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3)

View file

@ -59,6 +59,7 @@ static dllfunction_t mysqlfuncs[] =
{(void*)&qmysql_thread_safe, "mysql_thread_safe"},
{NULL}
};
dllhandle_t *mysqlhandle;
#endif
#ifdef USE_SQLITE
@ -93,6 +94,7 @@ static dllfunction_t sqlitefuncs[] =
{(void*)&qsqlite3_finalize, "sqlite3_finalize"},
{NULL}
};
dllhandle_t *sqlitehandle;
#endif
cvar_t sql_driver = SCVARF("sv_sql_driver", "mysql", CVAR_NOUNSAFEEXPAND);
@ -184,6 +186,7 @@ int sql_serverworker(void *sref)
const char *error = NULL;
int tinit = -1, i;
qboolean needlock = false;
qboolean allokay = true;
switch(server->driver)
{
@ -240,9 +243,9 @@ int sql_serverworker(void *sref)
}
if (error)
server->active = false;
allokay = false;
while (server->active)
while (allokay)
{
Sys_LockConditional(server->requestcondv);
if (!server->requests) // this is needed for thread startup and to catch any "lost" changes
@ -260,7 +263,11 @@ int sql_serverworker(void *sref)
void *res = NULL;
if (!(qreq = SQL_PullRequest(server, needlock)))
{
if (!server->active)
allokay = false;
break;
}
// pullrequest makes sure our condition is unlocked but we'll need
// a lock next round
@ -329,6 +336,7 @@ int sql_serverworker(void *sref)
int rowspace;
qboolean keeplooping = true;
Sys_Printf("processing %s\n", statementstring);
// qsqlite3_mutex_enter(server->sqlite->mutex);
// while(*statementstring)
// {
@ -383,6 +391,15 @@ int sql_serverworker(void *sref)
qres->eof = true; //this one was the ender.
break;
}
else
{
Sys_Printf("sqlite error code %i: %s\n", rc, statementstring);
keeplooping = false;
qres->eof = true; //this one was the ender.
if (!qres->columns)
qres->columns = -1;
break;
}
rc = qsqlite3_step(pStmt);
}
@ -421,6 +438,7 @@ int sql_serverworker(void *sref)
}
}
}
server->active = false;
switch(server->driver)
{
@ -792,7 +810,7 @@ int SQL_NewServer(char *driver, char **paramstr)
return -1;
}
server->thread = Sys_CreateThread(sql_serverworker, (void *)server, THREADP_NORMAL, 1024);
server->thread = Sys_CreateThread("sqlworker", sql_serverworker, (void *)server, THREADP_NORMAL, 1024);
if (!server->thread)
{
@ -1170,7 +1188,7 @@ void SQL_KillServers(void)
void SQL_DeInit(void)
{
sqlavailable = false;
sqlavailable = 0;
SQL_KillServers();
@ -1180,6 +1198,9 @@ void SQL_DeInit(void)
Sys_CloseLibrary(mysqlhandle);
#endif
#ifdef USE_SQLITE
Sys_CloseLibrary(sqlitehandle);
#endif
}
#endif

View file

@ -12,8 +12,6 @@
#include "sqlite3.h"
#endif
dllhandle_t *mysqlhandle;
#define SQL_CONNECT_STRUCTPARAMS 2
#define SQL_CONNECT_PARAMS 4

View file

@ -915,7 +915,7 @@ void Sys_ServerActivity(void)
/* Thread creation calls */
typedef void *(*pfunction_t)(void *);
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize)
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
pthread_t *thread;
pthread_attr_t attr;

View file

@ -1444,7 +1444,7 @@ DWORD WINAPI threadwrapper(void *args)
return 0;
}
void *Sys_CreateThread(int (*func)(void *), void *args, int priority, int stacksize)
void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority, int stacksize)
{
threadwrap_t *tw = (threadwrap_t *)malloc(sizeof(threadwrap_t));
HANDLE handle;

View file

@ -1173,9 +1173,9 @@ SV_PreSpawn_f
enum
{
PRESPAWN_MAPCHECK=0,
PRESPAWN_CUSTOMTENTS,
PRESPAWN_SIGNON_BUF,
PRESPAWN_SPAWNSTATIC,
PRESPAWN_CUSTOMTENTS,
PRESPAWN_BASELINES,
PRESPAWN_DONE
};
@ -1266,6 +1266,49 @@ void SVQW_PreSpawn_f (void)
edict_t *ent;
svcustomtents_t *ctent;
if (ps_type == PRESPAWN_CUSTOMTENTS)
{
while (host_client->netchan.message.cursize < (host_client->netchan.message.maxsize/2))
{
if (ps_idx >= 255)
{
ps_type++;
ps_idx = 0;
break;
}
ctent = &sv.customtents[ps_idx];
if (*ctent->particleeffecttype)
{
if (host_client->fteprotocolextensions & PEXT_CUSTOMTEMPEFFECTS)
{
MSG_WriteByte(&host_client->netchan.message, svcfte_customtempent);
MSG_WriteByte(&host_client->netchan.message, 255);
MSG_WriteByte(&host_client->netchan.message, ps_idx);
MSG_WriteByte(&host_client->netchan.message, ctent->netstyle);
MSG_WriteString(&host_client->netchan.message, ctent->particleeffecttype);
if (ctent->netstyle & CTE_STAINS)
{
MSG_WriteChar(&host_client->netchan.message, ctent->stain[0]);
MSG_WriteChar(&host_client->netchan.message, ctent->stain[0]);
MSG_WriteChar(&host_client->netchan.message, ctent->stain[0]);
MSG_WriteByte(&host_client->netchan.message, ctent->radius);
}
if (ctent->netstyle & CTE_GLOWS)
{
MSG_WriteByte(&host_client->netchan.message, ctent->dlightrgb[0]);
MSG_WriteByte(&host_client->netchan.message, ctent->dlightrgb[1]);
MSG_WriteByte(&host_client->netchan.message, ctent->dlightrgb[2]);
MSG_WriteByte(&host_client->netchan.message, ctent->dlightradius);
MSG_WriteByte(&host_client->netchan.message, ctent->dlighttime);
}
}
}
ps_idx++;
}
}
if (ps_type == PRESPAWN_SIGNON_BUF)
{
while (host_client->netchan.message.cursize < (host_client->netchan.message.maxsize/2))
@ -1340,49 +1383,6 @@ void SVQW_PreSpawn_f (void)
}
}
if (ps_type == PRESPAWN_CUSTOMTENTS)
{
while (host_client->netchan.message.cursize < (host_client->netchan.message.maxsize/2))
{
if (ps_idx >= 255)
{
ps_type++;
ps_idx = 0;
break;
}
ctent = &sv.customtents[ps_idx];
if (*ctent->particleeffecttype)
{
if (host_client->fteprotocolextensions & PEXT_CUSTOMTEMPEFFECTS)
{
MSG_WriteByte(&host_client->netchan.message, svcfte_customtempent);
MSG_WriteByte(&host_client->netchan.message, 255);
MSG_WriteByte(&host_client->netchan.message, ps_idx);
MSG_WriteByte(&host_client->netchan.message, ctent->netstyle);
MSG_WriteString(&host_client->netchan.message, ctent->particleeffecttype);
if (ctent->netstyle & CTE_STAINS)
{
MSG_WriteChar(&host_client->netchan.message, ctent->stain[0]);
MSG_WriteChar(&host_client->netchan.message, ctent->stain[0]);
MSG_WriteChar(&host_client->netchan.message, ctent->stain[0]);
MSG_WriteByte(&host_client->netchan.message, ctent->radius);
}
if (ctent->netstyle & CTE_GLOWS)
{
MSG_WriteByte(&host_client->netchan.message, ctent->dlightrgb[0]);
MSG_WriteByte(&host_client->netchan.message, ctent->dlightrgb[1]);
MSG_WriteByte(&host_client->netchan.message, ctent->dlightrgb[2]);
MSG_WriteByte(&host_client->netchan.message, ctent->dlightradius);
MSG_WriteByte(&host_client->netchan.message, ctent->dlighttime);
}
}
}
ps_idx++;
}
}
if (ps_type == PRESPAWN_BASELINES)
{
while (host_client->netchan.message.cursize < (host_client->netchan.message.maxsize/2)) //baselines

View file

@ -703,7 +703,7 @@ void SWRast_CreateThreadPool(struct workqueue_s *wq, int numthreads)
{
t = &wq->swthreads[i];
t->threadnum = i;
t->thread = Sys_CreateThread(WT_Main, t, THREADP_NORMAL, 0);
t->thread = Sys_CreateThread("swrast", WT_Main, t, THREADP_NORMAL, 0);
if (!t->thread)
break;
}