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:
parent
e82dd608a6
commit
d248ce223f
53 changed files with 1389 additions and 724 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
;
|
||||
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
300
engine/common/sys_win_threads.c
Normal file
300
engine/common/sys_win_threads.c
Normal 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
|
|
@ -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)))
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -33963,6 +33963,10 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\sys_win_threads.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\translate.c"
|
||||
>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include "sqlite3.h"
|
||||
#endif
|
||||
|
||||
dllhandle_t *mysqlhandle;
|
||||
|
||||
#define SQL_CONNECT_STRUCTPARAMS 2
|
||||
#define SQL_CONNECT_PARAMS 4
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue