diff --git a/engine/Makefile b/engine/Makefile index e949d495f..bc411a459 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -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 diff --git a/engine/client/cd_win.c b/engine/client/cd_win.c index b03e10593..ea54c53e3 100644 --- a/engine/client/cd_win.c +++ b/engine/client/cd_win.c @@ -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); -} diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 09637a795..aa0c2b34b 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -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 diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 4f79df662..b56946d9f 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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) { diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 72e495227..3f2af9d1d 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -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; } diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 282e27e49..134db190f 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -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 ; icount ; 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 (); } diff --git a/engine/client/client.h b/engine/client/client.h index 54b11e474..3d5171651 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -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); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index 4ff900ff5..ca77232f0 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -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); } diff --git a/engine/client/r_partset.c b/engine/client/r_partset.c index d5e5f2311..15eba20b7 100644 --- a/engine/client/r_partset.c +++ b/engine/client/r_partset.c @@ -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" ; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 3f6d5cc8d..f210b0958 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -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 (); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a78b072bc..aa2c81fd6 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -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; diff --git a/engine/client/snd_directx.c b/engine/client/snd_directx.c index 3d770abb5..e239b5a89 100644 --- a/engine/client/snd_directx.c +++ b/engine/client/snd_directx.c @@ -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 diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 7a87fdd14..e08b8119e 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -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; diff --git a/engine/client/sys_morphos.c b/engine/client/sys_morphos.c index ba58b6c05..69c31a13c 100755 --- a/engine/client/sys_morphos.c +++ b/engine/client/sys_morphos.c @@ -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; } diff --git a/engine/client/sys_plugfte.c b/engine/client/sys_plugfte.c index 3d4693004..38bd97b89 100644 --- a/engine/client/sys_plugfte.c +++ b/engine/client/sys_plugfte.c @@ -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; } diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index 10ecb0eb5..7d9be63b5 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -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); diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 860500484..0456029c4 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -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); diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 9fd7563d6..f5e053a0f 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -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 diff --git a/engine/common/mathlib.c b/engine/common/mathlib.c index 4b0e7ee93..261fd74ac 100644 --- a/engine/common/mathlib.c +++ b/engine/common/mathlib.c @@ -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]; diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 8199221f7..da292c426 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -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); diff --git a/engine/common/protocol.h b/engine/common/protocol.h index ed9be53da..efcc180b3 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -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 diff --git a/engine/common/sys.h b/engine/common/sys.h index 8ea99f8d3..457bb1ee0 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -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); diff --git a/engine/common/sys_win_threads.c b/engine/common/sys_win_threads.c new file mode 100644 index 000000000..f74052e0e --- /dev/null +++ b/engine/common/sys_win_threads.c @@ -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 +#include + +#include +#include + +#ifdef MULTITHREAD +#include +#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 diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 3f66b1587..b0cbc13db 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -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))) diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index eaefdebf9..f201abb8d 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -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))) diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 717a0e1ac..7323dae14 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -33963,6 +33963,10 @@ /> + + diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 7ebd57379..15a9be978 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.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<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<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<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; diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 9b794db33..9b1f05340 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -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 - hm = sv.world.worldmodel->terrain; - if (!hm) //its not terrain. + if (!sv.world.worldmodel) + return false; + hm = sv.world.worldmodel->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)); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 40d3778d4..961158e27 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -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) { diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 079c8a1e2..09e135337 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -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 diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 72d059336..71a8b6e39 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -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 diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index f1a2a8873..42b77513c 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -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) diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 7e60200ec..78df2069e 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -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); diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 30860256e..fe4a5bf22 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -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"); diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 7314d05fe..d2f9f2bdf 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -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); diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 9049b05f6..679e2df35 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -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; diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index a11ab8f8e..f6adfd2be 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -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 diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 1a5005b9d..79daa7a34 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -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 diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index d2d130c24..67f3d77c8 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -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; diff --git a/engine/partcfgs/h2part.cfg b/engine/partcfgs/h2part.cfg index cfc871b43..6f5460894 100644 --- a/engine/partcfgs/h2part.cfg +++ b/engine/partcfgs/h2part.cfg @@ -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 +} diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 29d2e04bb..3da8d44be 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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) diff --git a/engine/server/progs.h b/engine/server/progs.h index ce09a542b..7aa1b5288 100644 --- a/engine/server/progs.h +++ b/engine/server/progs.h @@ -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); diff --git a/engine/server/q2game.h b/engine/server/q2game.h index c877722ae..26848056d 100644 --- a/engine/server/q2game.h +++ b/engine/server/q2game.h @@ -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; diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 9e0b5f485..7b054c701 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -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 diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 43955664e..1c3162083 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -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)); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 2430e6f93..5941fe84b 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -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(); diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index ada08ec2c..c04661c65 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -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) diff --git a/engine/server/sv_sql.c b/engine/server/sv_sql.c index ee6b3d952..87c068b4b 100644 --- a/engine/server/sv_sql.c +++ b/engine/server/sv_sql.c @@ -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 diff --git a/engine/server/sv_sql.h b/engine/server/sv_sql.h index b1c9f2a52..55d3b70d5 100644 --- a/engine/server/sv_sql.h +++ b/engine/server/sv_sql.h @@ -12,8 +12,6 @@ #include "sqlite3.h" #endif -dllhandle_t *mysqlhandle; - #define SQL_CONNECT_STRUCTPARAMS 2 #define SQL_CONNECT_PARAMS 4 @@ -104,4 +102,4 @@ extern cvar_t sql_defaultdb; #define SQLCVAROPTIONS "SQL Defaults" -#endif \ No newline at end of file +#endif diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index da1e06b60..f15a6c1e9 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -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; diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index 4fda6e8e0..927cee678 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -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; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 43d2f833b..5ffc7bed3 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -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 diff --git a/engine/sw/sw_rast.c b/engine/sw/sw_rast.c index f66c05b3d..cfd7d1c1d 100644 --- a/engine/sw/sw_rast.c +++ b/engine/sw/sw_rast.c @@ -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; }