diff --git a/engine/client/cd_linux.c b/engine/client/cd_linux.c index 3f74d1a36..1ebecae79 100644 --- a/engine/client/cd_linux.c +++ b/engine/client/cd_linux.c @@ -40,22 +40,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include -static qboolean cdValid = false; -static qboolean playing = false; -static qboolean wasPlaying = false; -static qboolean initialized = false; -static qboolean enabled = true; -static qboolean playLooping = false; -static qbyte remap[100]; -static qbyte playTrack; -static qbyte maxTrack; - static int cdfile = -1; static char cd_dev[64] = "/dev/cdrom"; static void CDAudio_Eject(void) { - if (cdfile == -1 || !enabled) + if (cdfile == -1) return; // no cd init'd if ( ioctl(cdfile, CDROMEJECT) == -1 ) @@ -65,7 +55,7 @@ static void CDAudio_Eject(void) static void CDAudio_CloseDoor(void) { - if (cdfile == -1 || !enabled) + if (cdfile == -1) return; // no cd init'd if ( ioctl(cdfile, CDROMCLOSETRAY) == -1 ) @@ -76,7 +66,8 @@ static int CDAudio_GetAudioDiskInfo(void) { struct cdrom_tochdr tochdr; - cdValid = false; + if (cdfile == -1) + return -1; if ( ioctl(cdfile, CDROMREADTOCHDR, &tochdr) == -1 ) { @@ -90,10 +81,7 @@ static int CDAudio_GetAudioDiskInfo(void) return -1; } - cdValid = true; - maxTrack = tochdr.cdth_trk1; - - return 0; + return tochdr.cdth_trk1; } @@ -102,23 +90,8 @@ void CDAudio_Play(int track, qboolean looping) struct cdrom_tocentry entry; struct cdrom_ti ti; - if (cdfile == -1 || !enabled) + if (cdfile == -1) return; - - if (!cdValid) - { - CDAudio_GetAudioDiskInfo(); - if (!cdValid) - return; - } - - track = remap[track]; - - if (track < 1 || track > maxTrack) - { - Con_DPrintf("CDAudio: Bad track number %u.\n", track); - return; - } // don't try to play a non-audio track entry.cdte_track = track; @@ -134,13 +107,6 @@ void CDAudio_Play(int track, qboolean looping) return; } - if (playing) - { - if (playTrack == track) - return; - CDAudio_Stop(); - } - ti.cdti_trk0 = track; ti.cdti_trk1 = track; ti.cdti_ind0 = 1; @@ -155,10 +121,6 @@ void CDAudio_Play(int track, qboolean looping) if ( ioctl(cdfile, CDROMRESUME) == -1 ) Con_DPrintf("ioctl cdromresume failed\n"); - playLooping = looping; - playTrack = track; - playing = true; - if (!bgmvolume.value) CDAudio_Pause (); } @@ -166,181 +128,30 @@ void CDAudio_Play(int track, qboolean looping) void CDAudio_Stop(void) { - if (cdfile == -1 || !enabled) - return; - - if (!playing) + if (cdfile == -1) return; if ( ioctl(cdfile, CDROMSTOP) == -1 ) Con_DPrintf("ioctl cdromstop failed (%d)\n", errno); - - wasPlaying = false; - playing = false; } void CDAudio_Pause(void) { - if (cdfile == -1 || !enabled) - return; - - if (!playing) + if (cdfile == -1) return; if ( ioctl(cdfile, CDROMPAUSE) == -1 ) Con_DPrintf("ioctl cdrompause failed\n"); - - wasPlaying = playing; - playing = false; } void CDAudio_Resume(void) { - if (cdfile == -1 || !enabled) - return; - - if (!cdValid) - return; - - if (!wasPlaying) + if (cdfile == -1) return; if ( ioctl(cdfile, CDROMRESUME) == -1 ) Con_DPrintf("ioctl cdromresume failed\n"); - playing = true; -} - -static void CD_f (void) -{ - char *command; - int ret; - int n; - - if (Cmd_Argc() < 2) - return; - - command = Cmd_Argv (1); - - if (Q_strcasecmp(command, "on") == 0) - { - enabled = true; - return; - } - - if (Q_strcasecmp(command, "off") == 0) - { - if (playing) - CDAudio_Stop(); - enabled = false; - return; - } - - if (Q_strcasecmp(command, "reset") == 0) - { - enabled = true; - if (playing) - CDAudio_Stop(); - for (n = 0; n < 100; n++) - remap[n] = n; - CDAudio_GetAudioDiskInfo(); - return; - } - - if (Q_strcasecmp(command, "remap") == 0) - { - ret = Cmd_Argc() - 2; - if (ret <= 0) - { - for (n = 1; n < 100; n++) - if (remap[n] != n) - Con_Printf(" %u -> %u\n", n, remap[n]); - return; - } - for (n = 1; n <= ret; n++) - remap[n] = Q_atoi(Cmd_Argv (n+1)); - return; - } - - if (Q_strcasecmp(command, "close") == 0) - { - CDAudio_CloseDoor(); - return; - } - - if (!cdValid) - { - CDAudio_GetAudioDiskInfo(); - if (!cdValid) - { - Con_Printf("No CD in player.\n"); - return; - } - } - - if (Q_strcasecmp(command, "play") == 0) - { - CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), false); - return; - } - - if (Q_strcasecmp(command, "loop") == 0) - { - CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), true); - return; - } - - if (Q_strcasecmp(command, "stop") == 0) - { - CDAudio_Stop(); - return; - } - - if (Q_strcasecmp(command, "pause") == 0) - { - CDAudio_Pause(); - return; - } - - if (Q_strcasecmp(command, "resume") == 0) - { - CDAudio_Resume(); - return; - } - - if (Q_strcasecmp(command, "eject") == 0) - { - if (playing) - CDAudio_Stop(); - CDAudio_Eject(); - cdValid = false; - return; - } - - if (Q_strcasecmp(command, "info") == 0) - { - Con_Printf("%u tracks\n", maxTrack); - if (playing) - Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); - else if (wasPlaying) - Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack); - return; - } -} - -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) @@ -348,19 +159,19 @@ void CDAudio_Update(void) struct cdrom_subchnl subchnl; static time_t lastchk; - if (!enabled) - return; - - if (playing && lastchk < time(NULL)) { - lastchk = time(NULL) + 2; //two seconds between chks + if (playing && lastchk < time(NULL)) + { + lastchk = time(NULL) + 2; //two seconds between checks subchnl.cdsc_format = CDROM_MSF; - if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) { + if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1 ) + { Con_DPrintf("ioctl cdromsubchnl failed\n"); playing = false; return; } if (subchnl.cdsc_audiostatus != CDROM_AUDIO_PLAY && - subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) { + subchnl.cdsc_audiostatus != CDROM_AUDIO_PAUSED) + { playing = false; if (playLooping) CDAudio_Play(playTrack, true); @@ -368,57 +179,43 @@ void CDAudio_Update(void) } } -int CDAudio_Init(void) +qboolean CDAudio_Startup(void) { int i; -#if 0 - if (cls.state == ca_dedicated) - return -1; -#endif + if (cdfile != -1) + return true; - if (COM_CheckParm("-nocdaudio")) - return -1; + if (!bgmvolume.value) + return false; - if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) { + if ((i = COM_CheckParm("-cddev")) != 0 && i < com_argc - 1) + { Q_strncpyz(cd_dev, com_argv[i + 1], sizeof(cd_dev)); cd_dev[sizeof(cd_dev) - 1] = 0; } - if ((cdfile = open(cd_dev, O_RDONLY)) == -1) { + if ((cdfile = open(cd_dev, O_RDONLY)) == -1) + { Con_Printf("CDAudio_Init: open of \"%s\" failed (%i)\n", cd_dev, errno); cdfile = -1; - return -1; + return false; } - for (i = 0; i < 100; i++) - remap[i] = i; - initialized = true; - enabled = true; + return true; +} - if (CDAudio_GetAudioDiskInfo()) - { - Con_Printf("CDAudio_Init: No CD in player.\n"); - cdValid = false; - } - - Cmd_AddCommand ("cd", CD_f); - - Cvar_Hook(&bgmvolume, BGMVolume_Callback); - - Con_Printf("CD Audio Initialized\n"); - - return 0; +void CDAudio_Init(void) +{ } void CDAudio_Shutdown(void) { - if (!initialized) + if (cdfile == -1) return; CDAudio_Stop(); close(cdfile); cdfile = -1; - Cvar_Unhook(&bgmvolume); } #endif diff --git a/engine/client/cd_null.c b/engine/client/cd_null.c index 55ce00605..9a906f2ef 100644 --- a/engine/client/cd_null.c +++ b/engine/client/cd_null.c @@ -17,12 +17,11 @@ void CDAudio_Update(void) { } -int CDAudio_Init(void) +void CDAudio_Init(void) { - return -1; } -void CDAudio_Play(int track, qboolean looping) +void CDAudio_Play(int track) { } @@ -37,3 +36,21 @@ void CDAudio_Pause(void) void CDAudio_Resume(void) { } + +void CDAudio_Eject(void) +{ +} + +void CDAudio_CloseDoor(void) +{ +} + +int CDAudio_GetAudioDiskInfo(void) +{ + return -2; +} + +int CDAudio_Startup(void) +{ + return -2; +} \ No newline at end of file diff --git a/engine/client/cd_sdl.c b/engine/client/cd_sdl.c index fd35edc8e..79032cdb8 100644 --- a/engine/client/cd_sdl.c +++ b/engine/client/cd_sdl.c @@ -4,91 +4,48 @@ extern cvar_t bgmvolume; -static qboolean cdValid = false; -static qboolean playing = false; -static qboolean wasPlaying = false; static qboolean initialized = false; -static qboolean enabled = false; -static qboolean playLooping = false; -static qbyte remap[100]; -static qbyte playTrack; -static qbyte maxTrack; static SDL_CD *cddevice; -static void CDAudio_Eject(void) +void CDAudio_Eject(void) { if (SDL_CDEject(cddevice)) Con_DPrintf("SDL_CDEject failed\n"); } -static void CDAudio_CloseDoor(void) +void CDAudio_CloseDoor(void) { Con_Printf("SDL does not support this\n"); } -static int CDAudio_GetAudioDiskInfo(void) +int CDAudio_GetAudioDiskInfo(void) { - cdValid = false; - switch (SDL_CDStatus(cddevice)) { case CD_ERROR: Con_Printf("SDL_CDStatus returned error\n"); + return -1; case CD_TRAYEMPTY: - cdValid = false; - return 1; + return 0; default: break; } - - cdValid = true; - maxTrack = cddevice->numtracks; - - return 0; + return cddevice->numtracks; } -void CDAudio_Play(int track, qboolean looping) +void CDAudio_Play(int track) { - if (!enabled) - return; - - if (!cdValid) - { - CDAudio_GetAudioDiskInfo(); - if (!cdValid) - return; - } - - track = remap[track]; - - if (track < 1 || track > maxTrack) - { - Con_DPrintf("CDAudio: Bad track number %u.\n", track); - return; - } - - if (playing) - { - if (playTrack == track) - return; - CDAudio_Stop(); - } - - if (SDL_CDPlayTracks(cddevice, track, 0, track+1, 0)) + if (SDL_CDPlayTracks(cddevice, track, 0, 1, 0)) { Con_Printf("CDAudio: track %i is not audio\n", track); return; } - playLooping = looping; - playTrack = track; - playing = true; - if (!bgmvolume.value) CDAudio_Pause (); @@ -98,225 +55,25 @@ void CDAudio_Play(int track, qboolean looping) void CDAudio_Stop(void) { - if (!enabled) - return; - - if (!playing) - return; - if (SDL_CDStop(cddevice)) Con_DPrintf("CDAudio: SDL_CDStop failed"); - - wasPlaying = false; - playing = false; } void CDAudio_Pause(void) { - if (!enabled) - return; - - if (!playing) - return; - if (SDL_CDPause(cddevice)) Con_DPrintf("CDAudio: SDL_CDPause failed"); - - wasPlaying = playing; - playing = false; } void CDAudio_Resume(void) { - if (!enabled) - return; - - if (!cdValid) - return; - - if (!wasPlaying) - return; - if (SDL_CDResume(cddevice)) { Con_DPrintf("CDAudio: SDL_CDResume failed\n"); return; } - playing = true; -} - - -static void CD_f (void) -{ - char *command; - int ret; - int n; - - if (!initialized) - return; - - if (Cmd_Argc() < 2) - return; - - command = Cmd_Argv (1); - - if (Q_strcasecmp(command, "on") == 0) - { - enabled = true; - return; - } - - if (Q_strcasecmp(command, "off") == 0) - { - if (playing) - CDAudio_Stop(); - enabled = false; - return; - } - - if (Q_strcasecmp(command, "reset") == 0) - { - enabled = true; - if (playing) - CDAudio_Stop(); - for (n = 0; n < 100; n++) - remap[n] = n; - CDAudio_GetAudioDiskInfo(); - return; - } - - if (Q_strcasecmp(command, "remap") == 0) - { - ret = Cmd_Argc() - 2; - if (ret <= 0) - { - for (n = 1; n < 100; n++) - if (remap[n] != n) - Con_Printf(" %u -> %u\n", n, remap[n]); - return; - } - for (n = 1; n <= ret; n++) - remap[n] = Q_atoi(Cmd_Argv (n+1)); - return; - } - - if (Q_strcasecmp(command, "close") == 0) - { - CDAudio_CloseDoor(); - return; - } - - if (Q_strcasecmp(command, "play") == 0) - { - CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), false); - return; - } - - if (Q_strcasecmp(command, "eject") == 0) - { - if (playing) - CDAudio_Stop(); - CDAudio_Eject(); - cdValid = false; - return; - } - - if (!cdValid) - { - CDAudio_GetAudioDiskInfo(); - if (!cdValid) - { - Con_Printf("No CD in player.\n"); - return; - } - } - - if (Q_strcasecmp(command, "loop") == 0) - { - CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), true); - return; - } - - if (Q_strcasecmp(command, "stop") == 0) - { - CDAudio_Stop(); - return; - } - - if (Q_strcasecmp(command, "pause") == 0) - { - CDAudio_Pause(); - return; - } - - if (Q_strcasecmp(command, "resume") == 0) - { - CDAudio_Resume(); - return; - } - - if (Q_strcasecmp(command, "info") == 0) - { - Con_Printf("%u tracks\n", maxTrack); - if (playing) - Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); - else if (wasPlaying) - Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack); - return; - } -} - -/* -LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (lParam != wDeviceID) - return 1; - - switch (wParam) - { - case MCI_NOTIFY_SUCCESSFUL: - if (playing) - { - playing = false; - if (playLooping) - CDAudio_Play(playTrack, true); - } - break; - - case MCI_NOTIFY_ABORTED: - case MCI_NOTIFY_SUPERSEDED: - break; - - case MCI_NOTIFY_FAILURE: - Con_DPrintf("MCI_NOTIFY_FAILURE\n"); - CDAudio_Stop (); - cdValid = false; - break; - - default: - Con_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam); - return 1; - } - - 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) @@ -324,53 +81,36 @@ void CDAudio_Update(void) } -int CDAudio_Init(void) +void CDAudio_Init(void) { - int n; +} -#if 0 // QW - if (cls.state == ca_dedicated) - return -1; -#endif - if (COM_CheckParm("-nocdaudio")) - return -1; +qboolean CDAudio_Startup(void) +{ + if (initialized) + return !!cddevice; + if (!bgmvolume.value) + return false; + initialized = true; SDL_InitSubSystem(SDL_INIT_CDROM|SDL_INIT_NOPARACHUTE); if(!SDL_CDNumDrives()) { Con_DPrintf("CDAudio_Init: No CD drives\n"); - return -1; + return false; } cddevice = SDL_CDOpen(0); if (!cddevice) { Con_Printf("CDAudio_Init: SDL_CDOpen failed\n"); - return -1; + return false; } - 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; - } - - Cmd_AddCommand ("cd", CD_f); - - Cvar_Hook(&bgmvolume, BGMVolume_Callback); -// Con_Printf("CD Audio Initialized\n"); - - return 0; + return true; } - void CDAudio_Shutdown(void) { if (!initialized) @@ -380,6 +120,4 @@ void CDAudio_Shutdown(void) SDL_CDClose(cddevice); cddevice = NULL; initialized = false; - - Cvar_Unhook(&bgmvolume); } diff --git a/engine/client/cd_win.c b/engine/client/cd_win.c index ea54c53e3..b7d7da2fc 100644 --- a/engine/client/cd_win.c +++ b/engine/client/cd_win.c @@ -30,43 +30,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern HWND mainwindow; extern cvar_t bgmvolume; -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; +static qboolean initialized; +static qboolean initializefailed; +static DWORD resumeend; +static qboolean pollneeded; //workaround for windows vista/7 bug, where notification simply does not work for end of tracks. static UINT wDeviceID; -static 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 (); -} -static int CDAudio_GetAudioDiskInfo(void) +int CDAudio_GetAudioDiskInfo(void) { DWORD dwReturn; - MCI_STATUS_PARMS mciStatusParms; + static MCI_STATUS_PARMS mciStatusParms; + + if (!CDAudio_Startup()) + return -1; - cdValid = false; if (!initialized) return -1; mciStatusParms.dwItem = MCI_STATUS_READY; + mciStatusParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR) (LPVOID) &mciStatusParms); if (dwReturn) { @@ -80,6 +63,7 @@ static int CDAudio_GetAudioDiskInfo(void) } mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + mciStatusParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR) (LPVOID) &mciStatusParms); if (dwReturn) { @@ -92,28 +76,22 @@ static int CDAudio_GetAudioDiskInfo(void) return -1; } - cdValid = true; - maxTrack = mciStatusParms.dwReturn; - - return 0; + return mciStatusParms.dwReturn; } -static qboolean CDAudio_Startup(void) +qboolean CDAudio_Startup(void) { DWORD dwReturn; - MCI_OPEN_PARMS mciOpenParms; - MCI_SET_PARMS mciSetParms; - int n; + static MCI_OPEN_PARMS mciOpenParms; + static MCI_SET_PARMS mciSetParms; if (initializefailed) return false; - if (!bgmvolume.value) - return false; - if (initialized) return true; mciOpenParms.lpstrDeviceType = "cdaudio"; + mciOpenParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD_PTR) (LPVOID) &mciOpenParms); if (dwReturn) { @@ -123,8 +101,9 @@ static qboolean CDAudio_Startup(void) } wDeviceID = mciOpenParms.wDeviceID; - // Set the time format to track/minute/second/frame (TMSF). - mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF; + // Set the time format to frames. vista+ simply cannot come with converting to/from seconds, or something (notifies don't work, status stays playing, position stops updating at about 3 frames from the end of the track). + mciSetParms.dwTimeFormat = MCI_FORMAT_MSF; + mciSetParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)(LPVOID) &mciSetParms); if (dwReturn) { @@ -134,26 +113,19 @@ static qboolean CDAudio_Startup(void) return 0; } - for (n = 0; n < 100; n++) - remap[n] = n; initialized = true; - enabled = true; - if (CDAudio_GetAudioDiskInfo()) + if (CDAudio_GetAudioDiskInfo() <= 0) { 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"); @@ -162,7 +134,7 @@ void CDAudio_Shutdown(void) initialized = false; } -static void CDAudio_Eject(void) +void CDAudio_Eject(void) { DWORD dwReturn; @@ -171,8 +143,7 @@ static void CDAudio_Eject(void) Con_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", (int)dwReturn); } - -static void CDAudio_CloseDoor(void) +void CDAudio_CloseDoor(void) { DWORD dwReturn; @@ -181,41 +152,42 @@ static void CDAudio_CloseDoor(void) Con_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", (int)dwReturn); } -void CDAudio_Play(int track, qboolean looping) +//try to add time values sensibly because: +//a) microsoft api SUCKS and does not directly support frames. +//b) microsoft buggily stops 3 frames short of the end of the track if we use tmsf... +//c) frames added together will break things +//d) we can subtract an offset so we can actually detect when its reached the end of a track +//e) we need to do frames so we don't break if some track is exactly a multiple of a second long +DWORD MSFToFrames(DWORD base) +{ + int m = MCI_MSF_MINUTE(base); + int s = MCI_MSF_SECOND(base); + int f = MCI_MSF_FRAME(base); + + s += m*60; + f += 75*s; //75 frames per second. + return f; +} +DWORD FramesToMSF(DWORD in) +{ + DWORD m, s, f; + f = in % 75; + in /= 75; + s = in % 60; + in /= 60; + m = in; + + return MCI_MAKE_MSF(m, s, f); +} + +void CDAudio_Play(int track) { DWORD dwReturn; - MCI_PLAY_PARMS mciPlayParms; - MCI_STATUS_PARMS mciStatusParms; + static MCI_PLAY_PARMS mciPlayParms; + static MCI_STATUS_PARMS mciStatusParms; + DWORD trackstartposition; -#ifndef NOMEDIA - if (Media_FakeTrack(track, looping)) - { - if (playing) - CDAudio_Stop(); - return; - } -#endif - - if (!enabled) - { - return; - } - - if (!cdValid) - { - CDAudio_GetAudioDiskInfo(); - if (!cdValid) - { - return; - } - } - - if (!CDAudio_Startup()) - return; - - track = remap[track]; - - if (track < 1 || track > maxTrack) + if (track < 1) { Con_DPrintf("CDAudio: Bad track number %u.\n", track); return; @@ -224,6 +196,7 @@ void CDAudio_Play(int track, qboolean looping) // don't try to play a non-audio track mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK; mciStatusParms.dwTrack = track; + mciStatusParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR) (LPVOID) &mciStatusParms); if (dwReturn) { @@ -236,9 +209,22 @@ void CDAudio_Play(int track, qboolean looping) return; } + // get the start of the track to be played + mciStatusParms.dwItem = MCI_STATUS_POSITION; + mciStatusParms.dwTrack = track; + mciStatusParms.dwCallback = (DWORD_PTR)mainwindow; + dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR) (LPVOID) &mciStatusParms); + if (dwReturn) + { + Con_DPrintf("MCI_STATUS failed (%i)\n", (int)dwReturn); + return; + } + trackstartposition = mciStatusParms.dwReturn; + // get the length of the track to be played mciStatusParms.dwItem = MCI_STATUS_LENGTH; mciStatusParms.dwTrack = track; + mciStatusParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR) (LPVOID) &mciStatusParms); if (dwReturn) { @@ -246,15 +232,9 @@ void CDAudio_Play(int track, qboolean looping) return; } - if (playing) - { - if (playTrack == track) - return; - CDAudio_Stop(); - } - - mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0); - mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track; + //set up to play from start to start+length + mciPlayParms.dwFrom = trackstartposition; + mciPlayParms.dwTo = resumeend = FramesToMSF(MSFToFrames(trackstartposition) + MSFToFrames(mciStatusParms.dwReturn) - 8); //-8 to avoid microsoft's potential fuck ups mciPlayParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD_PTR)(LPVOID) &mciPlayParms); if (dwReturn) @@ -263,9 +243,7 @@ void CDAudio_Play(int track, qboolean looping) return; } - playLooping = looping; - playTrack = track; - playing = true; + pollneeded = true; if (!bgmvolume.value) CDAudio_Pause (); @@ -278,61 +256,38 @@ void CDAudio_Stop(void) { DWORD dwReturn; - if (!enabled) - return; - - if (!playing) - return; + pollneeded = false; dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD_PTR)NULL); if (dwReturn) Con_DPrintf("MCI_STOP failed (%i)", (int)dwReturn); - - wasPlaying = false; - playing = false; } void CDAudio_Pause(void) { DWORD dwReturn; - MCI_GENERIC_PARMS mciGenericParms; - - if (!enabled) - return; - - if (!playing) - return; + static MCI_GENERIC_PARMS mciGenericParms; mciGenericParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD_PTR)(LPVOID) &mciGenericParms); if (dwReturn) Con_DPrintf("MCI_PAUSE failed (%i)", (int)dwReturn); - wasPlaying = playing; - playing = false; + pollneeded = false; } void CDAudio_Resume(void) { DWORD dwReturn; - MCI_PLAY_PARMS mciPlayParms; - - if (!enabled) - return; - - if (!cdValid) - return; - - if (!wasPlaying) - return; + static MCI_PLAY_PARMS mciPlayParms; if (!bgmvolume.value) return; - mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0); - mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0); + mciPlayParms.dwFrom = resumeend; + mciPlayParms.dwTo = resumeend; mciPlayParms.dwCallback = (DWORD_PTR)mainwindow; dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD_PTR)(LPVOID) &mciPlayParms); if (dwReturn) @@ -340,133 +295,8 @@ void CDAudio_Resume(void) Con_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", (int)dwReturn); return; } - playing = true; -} - -static void CD_f (void) -{ - char *command; - int ret; - int n; - - if (Cmd_Argc() < 2) - return; - - command = Cmd_Argv (1); - - - if (Q_strcasecmp(command, "play") == 0) - { - CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), false); - return; - } - - if (Q_strcasecmp(command, "loop") == 0) - { - CDAudio_Play((qbyte)Q_atoi(Cmd_Argv (2)), true); - return; - } - - - if (!CDAudio_Startup()) - { - Con_Printf("No cd drive detected\n"); - return; - } - - if (Q_strcasecmp(command, "on") == 0) - { - enabled = true; - return; - } - - if (Q_strcasecmp(command, "off") == 0) - { - if (playing) - CDAudio_Stop(); - enabled = false; - return; - } - - if (Q_strcasecmp(command, "reset") == 0) - { - enabled = true; - if (playing) - CDAudio_Stop(); - for (n = 0; n < 100; n++) - remap[n] = n; - CDAudio_GetAudioDiskInfo(); - return; - } - - if (Q_strcasecmp(command, "remap") == 0) - { - ret = Cmd_Argc() - 2; - if (ret <= 0) - { - for (n = 1; n < 100; n++) - if (remap[n] != n) - Con_Printf(" %u -> %u\n", n, remap[n]); - return; - } - for (n = 1; n <= ret; n++) - remap[n] = Q_atoi(Cmd_Argv (n+1)); - return; - } - - if (Q_strcasecmp(command, "close") == 0) - { - CDAudio_CloseDoor(); - return; - } - - if (!cdValid) - { - CDAudio_GetAudioDiskInfo(); - if (!cdValid) - { - Con_Printf("No CD in player.\n"); - return; - } - } - - if (Q_strcasecmp(command, "stop") == 0) - { - CDAudio_Stop(); - return; - } - - if (Q_strcasecmp(command, "pause") == 0) - { - CDAudio_Pause(); - return; - } - - if (Q_strcasecmp(command, "resume") == 0) - { - CDAudio_Resume(); - return; - } - - if (Q_strcasecmp(command, "eject") == 0) - { - if (playing) - CDAudio_Stop(); - CDAudio_Eject(); - cdValid = false; - return; - } - - if (Q_strcasecmp(command, "info") == 0) - { - Con_Printf("%u tracks\n", maxTrack); - if (playing) - Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); - else if (wasPlaying) - Con_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack); - return; - } + pollneeded = true; } LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -477,12 +307,8 @@ LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) switch (wParam) { case MCI_NOTIFY_SUCCESSFUL: - if (playing) - { - playing = false; - if (playLooping) - CDAudio_Play(playTrack, true); - } + pollneeded = false; + Media_EndedTrack(); break; case MCI_NOTIFY_ABORTED: @@ -492,7 +318,8 @@ LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case MCI_NOTIFY_FAILURE: Con_DPrintf("MCI_NOTIFY_FAILURE\n"); CDAudio_Stop (); - cdValid = false; + CDAudio_Shutdown(); +// Media_EndedTrack(); break; default: @@ -505,23 +332,34 @@ LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) void CDAudio_Update(void) { - + //workaround for vista bug where MCI_NOTIFY does not work to signal the end of the track. + if (pollneeded) + { + MCI_STATUS_PARMS mciStatusParms; + mciStatusParms.dwCallback = (DWORD_PTR)mainwindow; + mciStatusParms.dwItem = MCI_STATUS_POSITION; + mciStatusParms.dwReturn = resumeend; + mciStatusParms.dwTrack = 0; + if (0 == mciSendCommand(wDeviceID, MCI_STATUS, MCI_WAIT|MCI_STATUS_ITEM, (DWORD_PTR)&mciStatusParms)) + { + unsigned int c, f; + int cm = MCI_MSF_MINUTE(mciStatusParms.dwReturn); + int cs = MCI_MSF_SECOND(mciStatusParms.dwReturn); + int cf = MCI_MSF_FRAME(mciStatusParms.dwReturn); + int fm = MCI_MSF_MINUTE(resumeend); + int fs = MCI_MSF_SECOND(resumeend); + int ff = MCI_MSF_FRAME(resumeend); + c = cf | (cs<<8) | (cm<<16); + f = ff | (fs<<8) | (fm<<16); + if (c >= f) + { + pollneeded = false; + Media_EndedTrack(); + } + } + } } - -int CDAudio_Init(void) +void CDAudio_Init(void) { - Cmd_AddCommand ("cd", CD_f); - -#if 0 // QW - if (cls.state == ca_dedicated) - return -1; -#endif - if (COM_CheckParm("-nocdaudio")) - initializefailed = true; - else - initializefailed = false; - - return 0; } - diff --git a/engine/client/cdaudio.h b/engine/client/cdaudio.h index e7224e4ad..9c7f4133b 100644 --- a/engine/client/cdaudio.h +++ b/engine/client/cdaudio.h @@ -18,11 +18,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -int CDAudio_Init(void); -void CDAudio_Play(int track, qboolean looping); +void CDAudio_Init(void); +qboolean CDAudio_Startup(void); //called when the cd isn't currently valid. returns if its valid or not. +int CDAudio_GetAudioDiskInfo(void);//returns number of tracks available, or 0 if the cd is not valid. +void CDAudio_Play(int track); void CDAudio_Stop(void); void CDAudio_Pause(void); void CDAudio_Resume(void); +void CDAudio_Eject(void); +void CDAudio_CloseDoor(void); void CDAudio_Shutdown(void); void CDAudio_Update(void); diff --git a/engine/client/cl_cam.c b/engine/client/cl_cam.c index 22cd3f054..f6a543ae9 100644 --- a/engine/client/cl_cam.c +++ b/engine/client/cl_cam.c @@ -468,21 +468,28 @@ void Cam_Track(playerview_t *pv, usercmd_t *cmd) if (cl_chasecam.value || scr_chatmode == 2) { + float *neworg; +// float *newang; + if (pv->nolocalplayer) + neworg = cl.lerpents[pv->viewentity].origin; + else + neworg = player->origin; + if (scr_chatmode != 2) pv->cam_lastviewtime = realtime; - VectorCopy(player->viewangles, pv->viewangles); - if (memcmp(player->origin, &self->origin, sizeof(player->origin)) != 0) +// VectorCopy(newang, pv->viewangles); + if (memcmp(neworg, &self->origin, sizeof(vec3_t)) != 0) { if (!cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_tmove); - MSG_WriteCoord (&cls.netchan.message, player->origin[0]); - MSG_WriteCoord (&cls.netchan.message, player->origin[1]); - MSG_WriteCoord (&cls.netchan.message, player->origin[2]); + MSG_WriteCoord (&cls.netchan.message, neworg[0]); + MSG_WriteCoord (&cls.netchan.message, neworg[1]); + MSG_WriteCoord (&cls.netchan.message, neworg[2]); } // move there locally immediately - VectorCopy(player->origin, self->origin); + VectorCopy(neworg, self->origin); } self->weaponframe = player->weaponframe; diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index 3b4390a3e..e17629e2e 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -533,7 +533,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_UPDATESCREEN: //force a buffer swap cos loading won't refresh it soon. - if (key_dest != key_console) + if (!Key_Dest_Has(kdm_console)) scr_con_current = 0; SCR_UpdateScreen(); break; diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 6bc77ab36..08f3dde84 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -454,7 +454,8 @@ qboolean CL_GetDemoMessage (void) cls.td_startframe = host_framecount; //force the console up, we're done loading. - key_dest = key_game; + Key_Dest_Remove(kdm_console); + Key_Dest_Remove(kdm_menu); scr_con_current = 0; } @@ -588,7 +589,7 @@ readnext: cls.td_startframe = host_framecount; //force the console up, we're done loading. - key_dest = key_game; + Key_Dest_Remove(kdm_console); scr_con_current = 0; } if (cls.td_startframe == host_framecount+1) @@ -1910,7 +1911,7 @@ void CL_QTVPoll (void) if (!sourcesmenu) { m_state = m_complex; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); sourcesmenu = M_CreateMenu(0); MC_AddPicture(sourcesmenu, 16, 4, 32, 144, "gfx/qplaque.lmp"); diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 213a3197d..370b2aa93 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -129,9 +129,11 @@ static void CL_ClearDlight(dlight_t *dl, int key) dl->color[2] = 1; dl->corona = bound(0, r_flashblend.value * 0.25, 1); dl->coronascale = bound(0, r_flashblendscale.value, 1); +#ifdef RTLIGHTS dl->lightcolourscales[0] = r_shadow_realtime_dlight_ambient.value; dl->lightcolourscales[1] = r_shadow_realtime_dlight_diffuse.value; dl->lightcolourscales[2] = r_shadow_realtime_dlight_specular.value; +#endif // if (r_shadow_realtime_dlight_shadowmap.value) // dl->flags |= LFLAG_SHADOWMAP; } @@ -722,7 +724,6 @@ void CLFTE_ParseEntities(void) unsigned int newnum, oldnum; int oldindex; qboolean isvalid = false; - entity_state_t *e; qboolean removeflag; int inputframe = cls.netchan.incoming_sequence; @@ -4500,6 +4501,12 @@ void CL_LinkViewModel(void) if (r_refdef.playerview->stats[STAT_HEALTH] <= 0) return; + if (cl.intermission) + return; + + if (pv->stats[STAT_WEAPON] <= 0 || pv->stats[STAT_WEAPON] >= MAX_MODELS) + return; + if (r_drawviewmodel.value > 0 && r_drawviewmodel.value < 1) alpha = r_drawviewmodel.value; else @@ -4515,10 +4522,6 @@ void CL_LinkViewModel(void) V_ClearEntity(&ent); - ent.model = r_refdef.playerview->viewent.model; - if (!ent.model) - return; - #ifdef PEXT_SCALE ent.scale = 1; #endif @@ -4540,11 +4543,15 @@ void CL_LinkViewModel(void) ent.flags |= Q2RF_TRANSLUCENT; } + ent.model = cl.model_precache[pv->stats[STAT_WEAPON]]; + if (!ent.model) + return; + #ifdef HLCLIENT if (!CLHL_AnimateViewEntity(&ent)) #endif { - ent.framestate.g[FS_REG].frame[0] = pv->viewent.framestate.g[FS_REG].frame[0]; + ent.framestate.g[FS_REG].frame[0] = pv->stats[STAT_WEAPONFRAME]; ent.framestate.g[FS_REG].frame[1] = pv->oldframe; if (ent.framestate.g[FS_REG].frame[0] != pv->prevframe) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index c77580cbe..936793f89 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -630,11 +630,11 @@ void CL_CheckForResend (void) char data[2048]; double t1, t2; int contype = 0; - unsigned int pext1, pext2; #ifndef CLIENTONLY if (!cls.state && sv.state) { + unsigned int pext1, pext2; pext1 = 0; pext2 = 0; Q_strncpyz (cls.servername, "internalserver", sizeof(cls.servername)); @@ -3849,10 +3849,11 @@ int nopacketcount; void SNDDMA_SetUnderWater(qboolean underwater); double Host_Frame (double time) { + static double time0 = 0; static double time1 = 0; static double time2 = 0; static double time3 = 0; - int pass1, pass2, pass3; + int pass0, pass1, pass2, pass3; // float fps; double newrealtime; static double spare; @@ -3906,8 +3907,8 @@ double Host_Frame (double time) #ifdef VM_UI UI_MenuState() != 0 || #endif - key_dest == key_menu || - key_dest == key_editor || + Key_Dest_Has(kdm_menu) || + Key_Dest_Has(kdm_editor) || cl.paused; // TODO: check if minimized or unfocused @@ -4048,6 +4049,9 @@ double Host_Frame (double time) RSpeedEnd(RSPEED_PROTOCOL); + if (host_speeds.ival) + time0 = Sys_DoubleTime (); + #ifndef CLIENTONLY if (sv.state) { @@ -4106,12 +4110,13 @@ double Host_Frame (double time) if (host_speeds.ival) { - pass1 = (time1 - time3)*1000; + pass0 = (time0 - time3)*1000000; time3 = Sys_DoubleTime (); - pass2 = (time2 - time1)*1000; - pass3 = (time3 - time2)*1000; - Con_TPrintf (TLC_HOSTSPEEDSOUTPUT, - pass1+pass2+pass3, pass1, pass2, pass3); + pass1 = (time1 - time0)*1000000; + pass2 = (time2 - time1)*1000000; + pass3 = (time3 - time2)*1000000; + Con_Printf ("%4i tot %4i idle %4i server %4i gfx %4i snd\n", + pass0+pass1+pass2+pass3, pass0, pass1, pass2, pass3); } @@ -4307,7 +4312,7 @@ void CL_ExecInitialConfigs(char *resetcommand) //if the renderer is already up and running, be prepared to reload content to match the new conback/font/etc if (qrenderer != QR_NONE) Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL); - if (key_dest == key_menu) + if (Key_Dest_Has(kdm_menu)) Cbuf_AddText ("closemenu\ntogglemenu\n", RESTRICT_LOCAL); //make sure the menu has the right content loaded. Cbuf_Execute (); //if the server initialisation causes a problem, give it a place to abort to diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 4042d3cf6..5a73a4a72 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3290,6 +3290,7 @@ void CL_ParseModellist (qboolean lots) int nummodels; char *str; int n; + int vwplayerindex = -1; // precache models and note certain default indexes if (lots) @@ -3311,6 +3312,8 @@ void CL_ParseModellist (qboolean lots) cl_spikeindex = nummodels; if (!strcmp(cl.model_name[nummodels],"progs/player.mdl")) cl_playerindex = nummodels; + if (*cl.model_name_vwep[0] && !strcmp(cl.model_name[nummodels],cl.model_name_vwep[0]) && cl_playerindex == -1) + cl_playerindex = nummodels; if (!strcmp(cl.model_name[nummodels],"progs/h_player.mdl")) cl_h_playerindex = nummodels; if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl")) @@ -3457,7 +3460,7 @@ void CLQ2_ParseConfigString (void) else if (i == Q2CS_CDTRACK) { // if (cl.refresh_prepped) - CDAudio_Play (atoi(s), true); + Media_NumberedTrack (atoi(s), atoi(s)); } else if (i >= Q2CS_MODELS && i < Q2CS_MODELS+Q2MAX_MODELS) { @@ -5698,7 +5701,7 @@ void CLQW_ParseServerMessage (void) case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); - CDAudio_Play ((qbyte)cl.cdtrack, true); + Media_NumberedTrack ((qbyte)cl.cdtrack, (qbyte)cl.cdtrack); break; case svc_intermission: @@ -6350,7 +6353,7 @@ void CLNQ_ParseServerMessage (void) cl.cdtrack = MSG_ReadByte (); MSG_ReadByte (); - CDAudio_Play ((qbyte)cl.cdtrack, true); + Media_NumberedTrack ((qbyte)cl.cdtrack, (qbyte)cl.cdtrack); break; case svc_setview: diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index ba26d62f3..900616102 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -27,19 +27,19 @@ qintptr_t VARGS Plug_Menu_Control(void *offset, quintptr_t mask, const qintptr_t Plug_Menu_Event(3, 0); menuplug = NULL; currentplug = oldplug; - key_dest = key_game; + Key_Dest_Remove(kdm_menu); } if (VM_LONG(arg[0]) != 1) return 1; //give us menu control menuplug = currentplug; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_plugin; return 1; case 2: //weather it's us or not. return currentplug == menuplug && m_state == m_plugin; case 3: //weather a menu is active - return key_dest == key_menu; + return !!Key_Dest_Has(kdm_menu); default: return 0; } @@ -561,7 +561,7 @@ void Plug_Client_Close(plugin_t *plug) if (menuplug == plug) { menuplug = NULL; - key_dest = key_game; + Key_Dest_Remove(kdm_menu); } if (protocolclientplugin == plug) { diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 3430d3be6..df229a71b 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -32,7 +32,7 @@ extern usercmd_t independantphysics[MAX_SPLITS]; #ifdef Q2CLIENT #define MAX_PARSE_ENTITIES 1024 -extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; +extern entity_state_t clq2_parse_entities[MAX_PARSE_ENTITIES]; char *Get_Q2ConfigString(int i); @@ -113,7 +113,7 @@ void CLQ2_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t en for (i=0 ; isolid) continue; @@ -202,7 +202,7 @@ int VARGS CLQ2_PMpointcontents (vec3_t point) for (i=0 ; isolid != 31) // special value for bmodel continue; @@ -726,6 +726,8 @@ static void CL_EntStateToPlayerState(player_state_t *plstate, entity_state_t *st plstate->pm_type = pmtype; VectorCopy(state->origin, plstate->origin); VectorScale(state->u.q1.velocity, 1/8.0, plstate->velocity); + VectorCopy(state->angles, plstate->viewangles); + plstate->viewangles[0] *= -3; a[0] = ((-192-state->u.q1.gravitydir[0])/256.0f) * 360; a[1] = (state->u.q1.gravitydir[1]/256.0f) * 360; @@ -1126,11 +1128,13 @@ Con_DPrintf("%i:%f %f %i:%f (%f)\n", fromframe, fromtime, simtime, toframe, toti pv->simorg[i] = (1-f)*fromstate->origin[i] + f*tostate->origin[i]; pv->simvel[i] = (1-f)*fromstate->velocity[i] + f*tostate->velocity[i]; -/* if (cl.spectator && Cam_TrackNum(vnum) >= 0) - pv->simangles[i] = LerpAngles16(from->playerstate[pnum].command.angles[i], to->playerstate[pnum].command.angles[i], f) * (360.0/65535); - else if (cls.demoplayback == DPB_QUAKEWORLD) - pv->simangles[i] = LerpAngles16(cmdfrom->cmd[vnum].angles[i], cmdto->cmd[vnum].angles[i], f) * (360.0/65535); -*/ } + + if (pv->viewentity != pv->playernum+1) + { + pv->simangles[i] = LerpAngles360(fromstate->viewangles[i], tostate->viewangles[i], f);// * (360.0/65535); +// pv->viewangles[i] = LerpAngles16(fromstate->command.angles[i], tostate->command.angles[i], f) * (360.0/65535); + } + } } CL_CatagorizePosition(pv); @@ -1140,8 +1144,11 @@ Con_DPrintf("%i:%f %f %i:%f (%f)\n", fromframe, fromtime, simtime, toframe, toti { //keep the entity tracking the prediction position, so mirrors don't go all weird VectorCopy(tostate->origin, le->origin); - VectorScale(pv->simangles, 1, le->angles); - le->angles[0] *= -0.333; + if (pv->stats[STAT_HEALTH] > 0) + { + VectorScale(pv->simangles, 1, le->angles); + le->angles[0] *= -0.333; + } } // if (cls.demoplayback) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 7ffd9a3a9..e690b159a 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -64,6 +64,7 @@ void RSpeedShow(void) RSpNames[RSPEED_FINISH] = "glFinish"; + memset(RQntNames, 0, sizeof(RQntNames)); RQntNames[RQUANT_MSECS] = "Microseconds"; RQntNames[RQUANT_EPOLYS] = "Entity Polys"; RQntNames[RQUANT_WPOLYS] = "World Polys"; @@ -72,24 +73,33 @@ void RSpeedShow(void) RQntNames[RQUANT_WORLDBATCHES] = "World Batches"; RQntNames[RQUANT_ENTBATCHES] = "Ent Batches"; RQntNames[RQUANT_SHADOWFACES] = "Shadow Faces"; - RQntNames[RQUANT_SHADOWEDGES] = "Shadow edges"; + RQntNames[RQUANT_SHADOWEDGES] = "Shadow Edges"; + RQntNames[RQUANT_SHADOWSIDES] = "Shadowmap Sides"; RQntNames[RQUANT_LITFACES] = "Lit faces"; + RQntNames[RQUANT_RTLIGHT_DRAWN] = "Lights Drawn"; + RQntNames[RQUANT_RTLIGHT_CULL_FRUSTUM] = "Lights offscreen"; + RQntNames[RQUANT_RTLIGHT_CULL_PVS] = "Lights PVS Culled"; + RQntNames[RQUANT_RTLIGHT_CULL_SCISSOR] = "Lights Scissored"; + if (r_speeds.ival > 1) { for (i = 0; i < RSPEED_MAX; i++) { - s = va("%i %-20s", samplerspeeds[i], RSpNames[i]); + s = va("%g %-20s", samplerspeeds[i]/100.0, RSpNames[i]); Draw_FunString(vid.width-strlen(s)*8, i*8, s); } } for (i = 0; i < RQUANT_MAX; i++) { - s = va("%i %-20s", samplerquant[i], RQntNames[i]); + s = va("%g %-20s", samplerquant[i]/100.0, RQntNames[i]); + Draw_FunString(vid.width-strlen(s)*8, (i+RSPEED_MAX)*8, s); + } + if (r_speeds.ival > 1) + { + s = va("%f %-20s", 100000000.0f/(samplerspeeds[RSPEED_TOTALREFRESH]+samplerspeeds[RSPEED_FINISH]), "Framerate"); Draw_FunString(vid.width-strlen(s)*8, (i+RSPEED_MAX)*8, s); } - s = va("%f %-20s", 100000000.0f/samplerspeeds[RSPEED_TOTALREFRESH], "Framerate"); - Draw_FunString(vid.width-strlen(s)*8, (i+RSPEED_MAX)*8, s); if (++framecount>=100) { @@ -161,7 +171,6 @@ int scr_chatmode; extern cvar_t scr_chatmodecvar; -int mouseusedforgui; float mousecursor_x, mousecursor_y; float mousemove_x, mousemove_y; @@ -550,7 +559,7 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font) void SCR_CheckDrawCenterString (void) { -extern qboolean sb_showscores; + extern qboolean sb_showscores; int pnum; cprint_t *p; vrect_t rect; @@ -564,7 +573,7 @@ extern qboolean sb_showscores; p->time_off -= host_frametime; - if (key_dest != key_game) //don't let progs guis/centerprints interfere with the game menu + if (Key_Dest_Has(~kdm_game)) //don't let progs guis/centerprints interfere with the game menu continue; if (sb_showscores) //this was annoying @@ -1296,7 +1305,7 @@ void SCR_DrawPause (void) if (!cl.paused) return; - if (key_dest == key_menu) + if (Key_Dest_Has(kdm_menu)) return; pic = R2D_SafeCachePic ("gfx/pause.lmp"); @@ -1586,7 +1595,7 @@ void SCR_ImageName (char *mapname) GL_BeginRendering (); SCR_DrawLoading(); SCR_SetUpToDrawConsole(); - if (key_dest == key_console || !*levelshotname) + if (Key_Dest_Has(kdm_console) || !*levelshotname) SCR_DrawConsole(!!*levelshotname); GL_EndRendering(); scr_drawloading = false; @@ -1622,24 +1631,27 @@ void SCR_SetUpToDrawConsole (void) //android has an onscreen imm that we don't want to obscure fullscreenpercent = scr_consize.value; #endif - if ((key_dest == key_console || key_dest == key_game) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload)) + if ((!Key_Dest_Has(~(kdm_console|kdm_game))) && (!cl.sendprespawn && cl.worldmodel && cl.worldmodel->needload)) { - key_dest = key_console; + //force console to fullscreen if we're loading stuff + Key_Dest_Add(kdm_console); scr_conlines = scr_con_current = vid.height * fullscreenpercent; } - else if ((key_dest == key_console || key_dest == key_game) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false)) + else if ((!Key_Dest_Has(~(kdm_console|kdm_game))) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active && !Media_PlayingFullScreen() && !CSQC_UnconnectedOkay(false)) { + //go fullscreen if we're not doing anything #ifdef VM_UI - if (key_dest == key_game && (UI_MenuState() || UI_OpenMenu())) + if (UI_MenuState() || UI_OpenMenu()) ; else #endif if (cls.state < ca_demostart) - key_dest = key_console; + Key_Dest_Add(kdm_console); scr_con_current = scr_conlines = vid.height * fullscreenpercent; } - else if (key_dest == key_console || scr_chatmode) + else if (Key_Dest_Has(kdm_console) || scr_chatmode) { + //go half-screen if we're meant to have the console visible scr_conlines = vid.height*scr_consize.value; // half screen if (scr_conlines < 32) scr_conlines = 32; //prevent total loss of console. @@ -1690,7 +1702,7 @@ void SCR_DrawConsole (qboolean noback) } else { - if (key_dest == key_game || key_dest == key_message) + if (!Key_Dest_Has(kdm_console|kdm_menu)) Con_DrawNotify (); // only draw notify in game } } @@ -2125,6 +2137,7 @@ void SCR_TileClear (void) // The 2d refresh stuff. void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) { + qboolean consolefocused = !!Key_Dest_Has(kdm_console); RSpeedMark(); R2D_ImageColours(1, 1, 1, 1); @@ -2183,7 +2196,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) Editor_Draw(); #endif - if (key_dest != key_console) + //if the console is not focused, show it scrolling back up behind the menu + if (!consolefocused) SCR_DrawConsole (false); M_Draw (uimenu); @@ -2191,7 +2205,8 @@ void SCR_DrawTwoDimensional(int uimenu, qboolean nohud) MP_Draw(); #endif - if (key_dest == key_console) + //but if the console IS focused, then always show it infront. + if (consolefocused) SCR_DrawConsole (false); if (Key_MouseShouldBeFree()) diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 3062b7c5f..bdb04f469 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -955,7 +955,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con Key_ClearStates(); break; case UI_KEY_GETCATCHER: - if (key_dest == key_console) + if (Key_Dest_Has(kdm_console)) VM_LONG(ret) = keycatcher | 1; else VM_LONG(ret) = keycatcher; @@ -1414,8 +1414,6 @@ void UI_DrawMenu(void) if (uivm) { VM_Call(uivm, UI_REFRESH, (int)(realtime * 1000)); - if (keycatcher&2 && key_dest != key_console) - key_dest = key_game; } } @@ -1461,7 +1459,7 @@ void UI_Reset(void) int UI_MenuState(void) { - if (key_dest == key_menu) + if (Key_Dest_Has(kdm_menu)) { return false; } @@ -1589,7 +1587,6 @@ qboolean UI_OpenMenu(void) VM_Call(uivm, UI_SET_ACTIVE_MENU, 2); else VM_Call(uivm, UI_SET_ACTIVE_MENU, 1); - key_dest = key_game; return true; } return false; diff --git a/engine/client/clhl_game.c b/engine/client/clhl_game.c index 0339402b2..b43e1db1a 100644 --- a/engine/client/clhl_game.c +++ b/engine/client/clhl_game.c @@ -1460,7 +1460,7 @@ int CLHL_ParseGamePacket(void) case svc_cdtrack: cl.cdtrack = MSG_ReadByte(); MSG_ReadByte(); - CDAudio_Play ((qbyte)cl.cdtrack, true); + CDAudio_Play ((qbyte)cl.cdtrack, (qbyte)cl.cdtrack); break; case 35: //svc_weaponanimation: diff --git a/engine/client/client.h b/engine/client/client.h index d85a4eec3..bdb1ca77f 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -271,7 +271,9 @@ typedef struct dlight_s float minlight; // don't add when contributing less float color[3]; float channelfade[3]; +#ifdef RTLIGHTS vec3_t lightcolourscales; //ambient, diffuse, specular +#endif float corona; float coronascale; @@ -570,7 +572,9 @@ struct playerview_s CAM_TRACK = 1 } cam_auto; // - entity_t viewent; // is this not utterly redundant yet? + vec3_t vw_axis[3]; //weapons should be positioned relative to this + vec3_t vw_origin; //weapons should be positioned relative to this +// entity_t viewent; // is this not utterly redundant yet? struct model_s *oldmodel; float lerptime; float frameduration; @@ -1297,6 +1301,7 @@ extern qboolean care_f_modified; void CLQ2_ParseTEnt (void); void CLQ2_AddEntities (void); void CLQ2_ParseBaseline (void); +void CLQ2_ClearParticleState(void); void CLQ2_ParseFrame (void); void CLQ2_RunMuzzleFlash2 (int ent, int flash_number); int CLQ2_RegisterTEntModels (void); @@ -1370,7 +1375,9 @@ struct cin_s *Media_StartCin(char *name); texid_tf Media_UpdateForShader(cin_t *cin); void Media_ShutdownCin(cin_t *cin); qboolean Media_FakeTrack(int i, qboolean loop); -qboolean Media_BackgroundTrack(char *track, char *looptrack); +qboolean Media_BackgroundTrack(char *initialtrack, char *looptrack); +void Media_NumberedTrack(int initialtrack, int looptrack); +void Media_EndedTrack(void); //cd is no longer running, media code needs to pick a new track (cd track or faketrack) #endif //these accept NULL for cin to mean the current fullscreen video diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index 12f1bc2ac..a84c5ea11 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -107,8 +107,8 @@ void CLQ2_BlasterTrail2(vec3_t oldorg, vec3_t neworg){}; #define MAX_PARSE_ENTITIES 1024 -q2centity_t cl_entities[MAX_Q2EDICTS]; -entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; +static q2centity_t cl_entities[MAX_Q2EDICTS]; +entity_state_t clq2_parse_entities[MAX_PARSE_ENTITIES]; void Q2S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs); void CL_SmokeAndFlash(vec3_t origin); @@ -629,6 +629,15 @@ void CLQ2_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int to->solid = MSG_ReadShort (); } +void CLQ2_ClearParticleState(void) +{ + int i; + for (i = 0; i < MAX_Q2EDICTS; i++) + { + P_DelinkTrailstate(&cl_entities[i].trailstate); + } +} + /* ================== CL_DeltaEntity @@ -637,14 +646,14 @@ Parses deltas from the given base and adds the resulting entity to the current frame ================== */ -void CLQ2_DeltaEntity (q2frame_t *frame, int newnum, entity_state_t *old, int bits) +static void CLQ2_DeltaEntity (q2frame_t *frame, int newnum, entity_state_t *old, int bits) { q2centity_t *ent; entity_state_t *state; ent = &cl_entities[newnum]; - state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)]; + state = &clq2_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)]; cl.parse_entities++; frame->num_entities++; @@ -700,7 +709,7 @@ An svc_packetentities has just been parsed, deal with the rest of the data stream. ================== */ -void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) +static void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) { int newnum; int bits; @@ -722,7 +731,7 @@ void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) oldnum = 99999; else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &clq2_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } } @@ -751,7 +760,7 @@ void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) oldnum = 99999; else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &clq2_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } } @@ -769,7 +778,7 @@ void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) oldnum = 99999; else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &clq2_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } continue; @@ -787,7 +796,7 @@ void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) oldnum = 99999; else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &clq2_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } continue; @@ -816,7 +825,7 @@ void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) oldnum = 99999; else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &clq2_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } } @@ -974,7 +983,7 @@ void CLQ2_FireEntityEvents (q2frame_t *frame) for (pnum = 0 ; pnumnum_entities ; pnum++) { num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1); - s1 = &cl_parse_entities[num]; + s1 = &clq2_parse_entities[num]; if (s1->u.q2.event) CLQ2_EntityEvent (s1); @@ -1191,7 +1200,7 @@ void CLQ2_AddPacketEntities (q2frame_t *frame) for (pnum = 0 ; pnumnum_entities ; pnum++) { - s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)]; + s1 = &clq2_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)]; cent = &cl_entities[s1->number]; @@ -1744,9 +1753,9 @@ CL_AddViewWeapon void CLQ2_AddViewWeapon (q2player_state_t *ps, q2player_state_t *ops) { entity_t gun; // view model - entity_t *view; extern cvar_t cl_gunx, cl_guny, cl_gunz; extern cvar_t cl_gunanglex, cl_gunangley, cl_gunanglez; + playerview_t *pv = &cl.playerview[0]; // allow the gun to be completely removed if (!r_drawviewmodel.value) @@ -1760,10 +1769,9 @@ void CLQ2_AddViewWeapon (q2player_state_t *ps, q2player_state_t *ops) return; //generate root matrix.. - view = &cl.playerview[0].viewent; - VectorCopy(cl.playerview[0].simorg, view->origin); - AngleVectors(cl.playerview[0].simangles, view->axis[0], view->axis[1], view->axis[2]); - VectorInverse(view->axis[1]); + VectorCopy(cl.playerview[0].simorg, pv->vw_origin); + AngleVectors(cl.playerview[0].simangles, pv->vw_axis[0], pv->vw_axis[1], pv->vw_axis[2]); + VectorInverse(pv->vw_axis[1]); memset (&gun, 0, sizeof(gun)); diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index 75b7ec0fd..27a453f6b 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -914,7 +914,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) cmd->upmove = 100; cmd->buttons &= ~2; } - if (key_dest != key_game || (keycatcher&3)) + if (Key_Dest_Has(~kdm_game) || (keycatcher&3)) cmd->buttons |= 2; //add in the 'at console' button cl.outframes[cl.movesequence&Q3UPDATE_MASK].cmd[0] = *cmd; diff --git a/engine/client/console.c b/engine/client/console.c index 85dc752b8..88ed8ec7d 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -437,22 +437,17 @@ void Con_ToggleConsole_Force(void) SCR_EndLoadingPlaque(); Key_ClearTyping (); - if (key_dest == key_console) - { - if (m_state) - key_dest = key_menu; - else - key_dest = key_game; - } + if (Key_Dest_Has(kdm_console)) + Key_Dest_Remove(kdm_console); else - key_dest = key_console; + Key_Dest_Add(kdm_console); } void Con_ToggleConsole_f (void) { #ifdef CSQC_DAT - if (key_dest == key_game && CSQC_ConsoleCommand("toggleconsole")) + if (!(key_dest_mask & kdm_editor) && CSQC_ConsoleCommand("toggleconsole")) { - key_dest = key_game; + Key_Dest_Remove(kdm_console); return; } #endif @@ -460,24 +455,6 @@ void Con_ToggleConsole_f (void) Con_ToggleConsole_Force(); } -/* -================ -Con_ToggleChat_f -================ -*/ -void Con_ToggleChat_f (void) -{ - Key_ClearTyping (); - - if (key_dest == key_console) - { - if (cls.state == ca_active) - key_dest = key_game; - } - else - key_dest = key_console; -} - void Con_ClearCon(console_t *con) { conline_t *t; @@ -551,7 +528,8 @@ Con_MessageMode_f void Con_MessageMode_f (void) { chat_team = false; - key_dest = key_message; + Key_Dest_Add(kdm_message); + Key_Dest_Remove(kdm_console); } /* @@ -562,12 +540,13 @@ Con_MessageMode2_f void Con_MessageMode2_f (void) { chat_team = true; - key_dest = key_message; + Key_Dest_Add(kdm_message); + Key_Dest_Remove(kdm_console); } void Con_ForceActiveNow(void) { - key_dest = key_console; + Key_Dest_Add(kdm_console); scr_conlines = scr_con_current = vid.height; } @@ -604,7 +583,6 @@ void Con_Init (void) Cvar_Register (&con_separatechat, "Console controls"); Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); - Cmd_AddCommand ("togglechat", Con_ToggleChat_f); Cmd_AddCommand ("messagemode", Con_MessageMode_f); Cmd_AddCommand ("messagemode2", Con_MessageMode2_f); Cmd_AddCommand ("clear", Con_Clear_f); @@ -1255,7 +1233,7 @@ void Con_DrawNotify (void) Con_DrawNotifyOne(con); } - if (key_dest == key_message) + if (Key_Dest_Has(kdm_message)) { int x, y; conchar_t *starts[8]; @@ -1798,7 +1776,7 @@ void Con_DrawConsole (int lines, qboolean noback) y -= Font_CharHeight(); haveprogress = Con_DrawProgress(x, ex - x, y) != y; - y = Con_DrawInput (con_current, key_dest == key_console, x, ex - x, y, selactive, selsx, selex, selsy, seley); + y = Con_DrawInput (con_current, Key_Dest_Has(kdm_console), x, ex - x, y, selactive, selsx, selex, selsy, seley); l = con_current->display; @@ -1826,7 +1804,7 @@ void Con_DrawOneConsole(console_t *con, struct font_s *font, float fx, float fy, Font_BeginString(font, fx, fy, &x, &y); Font_BeginString(font, fx+fsx, fy+fsy, &sx, &sy); - if (con == con_current && key_dest == key_console) + if (con == con_current && Key_Dest_Has(kdm_console)) { selactive = false; //don't change selections if this is the main console and we're looking at the console, because that main console has focus instead anyway. selsx = selsy = selex = seley = 0; @@ -1972,6 +1950,7 @@ Con_NotifyBox void Con_NotifyBox (char *text) { double t1, t2; + qboolean hadconsole; // during startup for sound / cd warnings Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); @@ -1982,7 +1961,8 @@ void Con_NotifyBox (char *text) Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); key_count = -2; // wait for a key down and up - key_dest = key_console; + hadconsole = !!Key_Dest_Has(kdm_console); + Key_Dest_Add(kdm_console); do { @@ -1994,5 +1974,7 @@ void Con_NotifyBox (char *text) } while (key_count < 0); Con_Printf ("\n"); - key_dest = key_game; + + if (!hadconsole) + Key_Dest_Remove(kdm_console); } diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index e8e9f52de..7db037bb1 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -336,6 +336,8 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum) } else { + mousecursor_x += mx; + mousecursor_y += my; #ifdef VM_UI if (UI_MousePosition(mx, my)) { @@ -347,7 +349,7 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum) if (mouse->type == M_TOUCH) { - if (m_strafeonright.ival && mouse->downpos[0] > vid.pixelwidth/2 && movements != NULL && (key_dest == key_game)) + if (m_strafeonright.ival && mouse->downpos[0] > vid.pixelwidth/2 && movements != NULL && !Key_Dest_Has(kdm_game)) { //if they're strafing, calculate the speed to move at based upon their displacement if (mouse->down) @@ -386,6 +388,13 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum) } else { + //if game is not focused, kill any mouse look + if (Key_Dest_Has(~kdm_game)) + { + mx = 0; + my = 0; + } + if (mx || my) if (CSQC_MouseMove(mx, my, mouse->qdeviceid)) { diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index 02870cd8d..21b3f2e04 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -36,30 +36,6 @@ void IN_DeactivateMouse(void) SDL_WM_GrabInput(SDL_GRAB_OFF); } -void IN_UpdateGrabs(int fullscreen, int activeapp) -{ - if (!vid_isfullscreen) - { - if (!_windowed_mouse.value) - { - if (mouseactive) - { - IN_DeactivateMouse (); - } - } - else - { - if ((key_dest == key_game||mouseusedforgui) && ActiveApp) - IN_ActivateMouse (); - else if (!(key_dest == key_game || mouseusedforgui) || !ActiveApp) - IN_DeactivateMouse (); - } - } -} - - - - #define tenoh 0,0,0,0,0, 0,0,0,0,0 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh #define hundredoh fiftyoh, fiftyoh diff --git a/engine/client/keys.c b/engine/client/keys.c index 810978d70..f5a7f1dfc 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -39,7 +39,9 @@ int key_lastpress; int edit_line=0; int history_line=0; -keydest_t key_dest; +unsigned int key_dest_mask; +qboolean key_dest_console; +unsigned int key_dest_absolutemouse; int key_count; // incremented every key event @@ -1299,7 +1301,7 @@ void Key_Message (int key, int unicode) CL_Say(chat_team, ""); } - key_dest = key_game; + Key_Dest_Remove(kdm_message); chat_bufferlen = 0; chat_buffer[0] = 0; return; @@ -1307,7 +1309,7 @@ void Key_Message (int key, int unicode) if (key == K_ESCAPE) { - key_dest = key_game; + Key_Dest_Remove(kdm_message); chat_bufferlen = 0; chat_buffer[0] = 0; return; @@ -1689,6 +1691,9 @@ void Key_Init (void) key_lines[i][0] = ']'; } key_linepos = 1; + + key_dest_mask = kdm_game; + key_dest_absolutemouse = kdm_console | kdm_editor; // // init ascii characters in console mode @@ -1783,20 +1788,17 @@ qboolean Key_MouseShouldBeFree(void) //if true, the input code is expected to return mouse cursor positions rather than deltas extern cvar_t cl_prydoncursor; - extern int mouseusedforgui; - if (mouseusedforgui) //I don't like this + if (key_dest_absolutemouse & key_dest_mask) return true; // if (!ActiveApp) // return true; - if (key_dest == key_menu) + if (Key_Dest_Has(kdm_menu)) { if (m_state == m_complex || m_state == m_plugin /*|| m_state == m_menu_dat*/) return true; } - if (key_dest == key_console || key_dest == key_editor) - return true; #ifdef VM_UI if (UI_MenuState()) @@ -1876,7 +1878,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) } } - if (keydown[k] && (key_dest != key_console && key_dest != key_message)) + if (keydown[k] && !Key_Dest_Has(~kdm_game)) { deltaused[k][keystate] = true; @@ -1940,8 +1942,8 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) } //yes, csqc is allowed to steal the escape key. - if (key != '`' && (!down || key != K_ESCAPE || (key_dest == key_game && !shift_down))) - if (key_dest == key_game && !Media_PlayingFullScreen()) + if (key != '`' && (!down || key != K_ESCAPE || (!Key_Dest_Has(~kdm_game) && !shift_down))) + if (!Key_Dest_Has(~kdm_game) && !Media_PlayingFullScreen()) { #ifdef CSQC_DAT if (CSQC_KeyPress(key, unicode, down, devid)) //give csqc a chance to handle it. @@ -1960,7 +1962,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) { #ifdef VM_UI #ifdef TEXTEDITOR - if (key_dest == key_game) + if (!Key_Dest_Has(~kdm_game)) #endif { if (down && Media_PlayingFullScreen()) @@ -1974,50 +1976,35 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) #endif if (!down) - { - if (key_dest == key_menu) - M_Keyup (key, unicode); return; - } - switch (key_dest) + + if (Key_Dest_Has(kdm_console)) { - case key_message: - Key_Message (key, unicode); - break; - case key_menu: - M_Keydown (key, unicode); - break; -#ifdef TEXTEDITOR - case key_editor: + if (cls.state || Key_Dest_Has(~(kdm_console|kdm_game))) + Key_Dest_Remove(kdm_console); + else + M_ToggleMenu_f (); + } + else if (Key_Dest_Has(kdm_editor)) Editor_Key (key, unicode); - break; -#endif - case key_game: + else if (Key_Dest_Has(kdm_menu)) + M_Keydown (key, unicode); + else if (Key_Dest_Has(kdm_message)) + Key_Dest_Remove(kdm_message); + else + { if (Media_PlayingFullScreen()) { Media_StopFilm(true); - break; + if (!cls.state) + M_ToggleMenu_f (); } - case key_console: - if (cls.state && key_dest == key_console) - key_dest = key_game; else M_ToggleMenu_f (); - break; - default: - Sys_Error ("Bad key_dest"); } return; } -#ifndef NOMEDIA - if (key_dest == key_game && Media_PlayingFullScreen()) - { - Media_Send_KeyEvent(NULL, key, unicode, down?0:1); - return; - } -#endif - // // key up events only generate commands if the game key binding is // a button command (leading + sign). These will occur even in console mode, @@ -2027,19 +2014,16 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) // if (!down) { - switch (key_dest) + if (Key_Dest_Has(kdm_console)) { - case key_menu: - M_Keyup (key, unicode); - break; - case key_console: con_current->mousecursor[0] = mousecursor_x; con_current->mousecursor[1] = mousecursor_y; Key_ConsoleRelease(con_current, key, unicode); - break; - default: - break; } + if (Key_Dest_Has(kdm_menu)) + M_Keyup (key, unicode); + if (Media_PlayingFullScreen()) + Media_Send_KeyEvent(NULL, key, unicode, down?0:1); if (!deltaused[key][keystate]) //this wasn't down, so don't make it leave down state. return; @@ -2077,7 +2061,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) // // during demo playback, most keys bring up the main menu // - if (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV && down && conkey && key != K_TAB && key_dest == key_game) + if (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV && down && conkey && key != K_TAB && !Key_Dest_Has(~kdm_game)) { M_ToggleMenu_f (); return; @@ -2088,90 +2072,76 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) // #ifdef VM_UI if (key != '`' && key != '~') - if (key_dest == key_game || !down) + if (!Key_Dest_Has(~kdm_game) || !down) { if (UI_KeyPress(key, unicode, down) && down) //UI is allowed to take these keydowns. Keyups are always maintained. return; } #endif - if (key && ((key_dest == key_menu && menubound[key]) - || (key_dest == key_console && !conkey) - || (key_dest == key_game && ( cls.state == ca_active || (!conkey) ) ) )) + + if (conkey && Key_Dest_Has(kdm_console)) { - /*don't auto-repeat binds as it breaks too many scripts*/ - if (key_repeats[key] > 1) - return; - - deltaused[key][keystate] = true; - - if (devid) - Q_snprintfz (p, sizeof(p), "p %i ", devid+1); - else - *p = 0; - - if (key == K_RALT) //simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead. - key = K_ALT; - if (key == K_RCTRL) //simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead. - key = K_CTRL; - if (key == K_RSHIFT)//simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead. - key = K_SHIFT; - - kb = keybindings[key][keystate]; - if (kb) - { - if (kb[0] == '+') - { // button commands add keynum as a parm - Q_snprintfz (cmd, sizeof(cmd), "+%s%s %i\n", p, kb+1, key+oldstate*256); - Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); - } - else - { - if (*p)Cbuf_AddText (p, bindcmdlevel[key][keystate]); - Cbuf_AddText (kb, bindcmdlevel[key][keystate]); - Cbuf_AddText ("\n", bindcmdlevel[key][keystate]); - } - } - - return; - } - - if (!down) - { - switch (key_dest) - { - case key_menu: - M_Keyup (key, unicode); - break; - default: - break; - } - return; // other systems only care about key down events - } - - switch (key_dest) - { - case key_message: - Key_Message (key, unicode); - break; - case key_menu: - M_Keydown (key, unicode); - break; -#ifdef TEXTEDITOR - case key_editor: - Editor_Key (key, unicode); - break; -#endif - case key_game: - case key_console: - if ((key && unicode) || key == K_ENTER || key == K_KP_ENTER || key == K_TAB) - key_dest = key_console; con_current->mousecursor[0] = mousecursor_x; con_current->mousecursor[1] = mousecursor_y; Key_Console (con_current, unicode, key); - break; - default: - Sys_Error ("Bad key_dest"); + return; + } + if (Key_Dest_Has(kdm_editor)) + { + Editor_Key (key, unicode); + return; + } + if (Key_Dest_Has(kdm_menu)) + { + M_Keydown (key, unicode); + return; + } + if (Key_Dest_Has(kdm_message)) + { + Key_Message (key, unicode); + return; + } + if (Media_PlayingFullScreen()) + { + Media_Send_KeyEvent(NULL, key, unicode, down?0:1); + return; + } + + //anything else is a key binding. + + /*don't auto-repeat binds as it breaks too many scripts*/ + if (key_repeats[key] > 1) + return; + + deltaused[key][keystate] = true; + + if (devid) + Q_snprintfz (p, sizeof(p), "p %i ", devid+1); + else + *p = 0; + + if (key == K_RALT) //simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead. + key = K_ALT; + if (key == K_RCTRL) //simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead. + key = K_CTRL; + if (key == K_RSHIFT)//simulate a singular alt for binds. really though, this code should translate to csqc/menu keycodes and back to resolve the weirdness instead. + key = K_SHIFT; + + kb = keybindings[key][keystate]; + if (kb) + { + if (kb[0] == '+') + { // button commands add keynum as a parm + Q_snprintfz (cmd, sizeof(cmd), "+%s%s %i\n", p, kb+1, key+oldstate*256); + Cbuf_AddText (cmd, bindcmdlevel[key][keystate]); + } + else + { + if (*p)Cbuf_AddText (p, bindcmdlevel[key][keystate]); + Cbuf_AddText (kb, bindcmdlevel[key][keystate]); + Cbuf_AddText ("\n", bindcmdlevel[key][keystate]); + } } } diff --git a/engine/client/keys.h b/engine/client/keys.h index c5e3580bb..cdbbc06fd 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -170,9 +170,23 @@ K_MAX = 256 #define K_CTRL K_LCTRL #define K_ALT K_LALT -typedef enum {key_game, key_console, key_message, key_menu, key_editor} keydest_t; +typedef enum //highest has priority +{ + kdm_game = 1u<<0, //should always be set + kdm_message = 1u<<1, + kdm_menu = 1u<<2, + kdm_editor = 1u<<3, + kdm_console = 1u<<4, +} keydestmask_t; -extern keydest_t key_dest; +//unsigned int Key_Dest_Get(void); //returns highest priority destination +#define Key_Dest_Add(kdm) (key_dest_mask |= (kdm)) +#define Key_Dest_Remove(kdm) (key_dest_mask &= ~(kdm)) +#define Key_Dest_Has(kdm) (key_dest_mask & (kdm)) +#define Key_Dest_Toggle(kdm) do {if (key_dest_mask & kdm) Key_Dest_Remove(kdm); else Key_Dest_Add(kdm);}while(0) + +extern unsigned int key_dest_absolutemouse; //if the active key dest bit is set, the mouse is absolute. +extern unsigned int key_dest_mask; extern char *keybindings[K_MAX][8]; extern int key_repeats[K_MAX]; extern int key_count; // incremented every key event diff --git a/engine/client/m_download.c b/engine/client/m_download.c index f52704a97..50897cb31 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -764,7 +764,7 @@ void Menu_DownloadStuff_f (void) menu_t *menu; dlmenu_t *info; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(dlmenu_t)); diff --git a/engine/client/m_items.c b/engine/client/m_items.c index f71db73f7..1dc3f24de 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -1526,7 +1526,7 @@ void M_Complex_Draw(void) if (!firstmenu) { - key_dest = key_game; + Key_Dest_Remove(kdm_menu); m_state = m_none; return; } @@ -1853,7 +1853,7 @@ qboolean MC_Main_Key (int key, menu_t *menu) //here purly to restart demos. if (key == K_ESCAPE) { extern int m_save_demonum; - key_dest = key_game; + Key_Dest_Remove(kdm_menu); m_state = m_none; cls.demonum = m_save_demonum; if (cls.demonum != -1 && !cls.demoplayback && cls.state == ca_disconnected && COM_CheckParm("-demos")) @@ -1912,7 +1912,7 @@ void M_Menu_Main_f (void) if (R2D_SafeCachePic("pics/m_main_game")) { m_state = m_complex; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); mainm = M_CreateMenu(0); mainm->key = MC_Main_Key; @@ -1963,7 +1963,7 @@ void M_Menu_Main_f (void) else if (mgt == MGT_HEXEN2) { m_state = m_complex; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); mainm = M_CreateMenu(0); mainm->key = MC_Main_Key; @@ -2003,7 +2003,7 @@ void M_Menu_Main_f (void) else if (QBigFontWorks()) { m_state = m_complex; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); mainm = M_CreateMenu(0); p = R2D_SafeCachePic("gfx/ttl_main.lmp"); @@ -2037,7 +2037,7 @@ void M_Menu_Main_f (void) else { m_state = m_complex; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); mainm = M_CreateMenu(0); p = R2D_SafeCachePic("gfx/ttl_main.lmp"); diff --git a/engine/client/m_master.c b/engine/client/m_master.c index 26aa102b0..09c8a0b87 100644 --- a/engine/client/m_master.c +++ b/engine/client/m_master.c @@ -592,7 +592,7 @@ void M_Menu_ServerList2_f(void) return; } - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(serverlist_t)); @@ -761,7 +761,7 @@ void M_QuickConnect_f(void) menucustom_t *cust; menu_t *menu; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; MasterInfo_Refresh(); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index d3d237b22..00b20d204 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -28,8 +28,8 @@ HWND hwnd_winamp; qboolean Media_EvaluateNextTrack(void); typedef struct mediatrack_s{ - char filename[128]; - char nicename[128]; + char filename[MAX_QPATH]; + char nicename[MAX_QPATH]; int length; struct mediatrack_s *next; } mediatrack_t; @@ -212,69 +212,150 @@ qboolean Media_EvaluateNextTrack(void) return true; } +static char cdloopingtrack[MAX_QPATH]; +static qboolean fakecdactive; + +#define REMAPPED_TRACKS 100 +static struct +{ + char fname[MAX_QPATH]; +} cdremap[REMAPPED_TRACKS]; +static qboolean cdenabled; +static int cdplayingtrack; //currently playing cd track (becomes 0 when paused) +static int cdpausedtrack; //currently paused cd track +static int cdnumtracks; //maximum cd track we can play. + //flushes music channel on all soundcards, and the tracks that arn't decoded yet. void Media_Clear (void) { + //make sure we're not playing any cd music. + if (cdplayingtrack || cdpausedtrack) + { + cdplayingtrack = 0; + cdpausedtrack = 0; + CDAudio_Stop(); + } + + Q_strncpyz(currenttrack.filename, "", sizeof(currenttrack.filename)); + fakecdactive = false; + media_playing = false; + S_Music_Clear(NULL); } -qboolean fakecdactive; //fake cd tracks. qboolean Media_BackgroundTrack(char *track, char *looptrack) { - char *ext[] = { + unsigned int tracknum; + static char *path[] = + { + "music/", + "sound/cdtracks/", + "", + NULL + }; + static char *ext[] = + { "", ".ogg", #ifdef WINAVI ".mp3", #endif ".wav", - NULL}; - + NULL + }; + char *trackend; char trackname[MAX_QPATH]; - int i; - if (!track || !*track) + int ie, ip; + qboolean found = false; + + if (!track || !*track) //ignore calls if the primary track is invalid. whatever is already playing will continue to play. return false; - if (!looptrack || !*looptrack) + if (!looptrack || !*looptrack) //null or empty looptrack loops using the primary track, for compat with q3. looptrack = track; - for(i = 0; ext[i]; i++) - { - Q_snprintfz(trackname, sizeof(name), "%s%s", track, ext[i]); - if (COM_FCheckExists(trackname)) - { - Media_Clear(); - strcpy(currenttrack.filename, trackname); - fakecdactive = true; - media_playing = true; - return true; - } + + //check if its a proper number (0123456789 without any other weird stuff. if so, we can use fake track paths or actual cd tracks) + tracknum = strtoul(track, &trackend, 0); + if (*trackend) + tracknum = 0; + if (tracknum > 0 && tracknum < REMAPPED_TRACKS && *cdremap[tracknum].fname) + { //remap the track if its remapped. + track = cdremap[tracknum].fname; + tracknum = strtoul(track, &trackend, 0); + if (*trackend) + tracknum = 0; } - return false; -} -qboolean Media_FakeTrack(int i, qboolean loop) -{ - char trackname[512]; - qboolean found; - - if (i > 0 && i <= 999) + if (!strcmp(looptrack, "-")) //- for the looptrack argument can be used to prevent looping. + looptrack = ""; + for(ip = 0; path[ip] && !found; ip++) { - found = false; - if (!found && i <= 99) + if (tracknum) { - sprintf(trackname, "music/track%02i", i); - if (Media_BackgroundTrack(trackname, loop?trackname:NULL)) - return true; + if (tracknum <= 999) + { + for(ie = 0; ext[ie] && !found; ie++) + { + Q_snprintfz(trackname, sizeof(trackname), "%strack%03i%s", path[ip], tracknum, ext[ie]); + found = COM_FCheckExists(trackname); + } + } + if (tracknum <= 99) + { + for(ie = 0; ext[ie] && !found; ie++) + { + Q_snprintfz(trackname, sizeof(trackname), "%strack%02i%s", path[ip], tracknum, ext[ie]); + found = COM_FCheckExists(trackname); + } + } } + if (!found) { - sprintf(trackname, "sound/cdtracks/track%03i", i); - if (Media_BackgroundTrack(trackname, loop?trackname:NULL)) - return true; + for(ie = 0; ext[ie] && !found; ie++) + { + Q_snprintfz(trackname, sizeof(trackname), "%s%s%s", path[ip], track, ext[ie]); + found = COM_FCheckExists(trackname); + } } } - fakecdactive = false; + if (found) + { + Q_strncpyz(cdloopingtrack, looptrack, sizeof(cdloopingtrack)); + + Media_Clear(); + Q_strncpyz(currenttrack.filename, trackname, sizeof(currenttrack.filename)); + fakecdactive = true; + media_playing = true; + return true; + } + + if (tracknum && cdenabled) + { + Q_strncpyz(cdloopingtrack, looptrack, sizeof(cdloopingtrack)); + + //couldn't do a faketrack, resort to actual cd tracks, if we're allowed + if (!CDAudio_Startup()) + return false; + if (cdnumtracks <= 0) + cdnumtracks = CDAudio_GetAudioDiskInfo(); + + if (tracknum > cdnumtracks) + { + Con_DPrintf("CDAudio: Bad track number %u.\n", tracknum); + return false; //can't play that, sorry. its not an available track + } + + if (cdplayingtrack == tracknum) + return true; //already playing, don't need to do anything + + Media_Clear(); + cdpausedtrack = 0; + cdplayingtrack = tracknum; + CDAudio_Play(tracknum); + return true; + } return false; } @@ -287,6 +368,168 @@ void Media_NamedTrack_f(void) Media_BackgroundTrack(Cmd_Argv(1), Cmd_Argv(1)); } +void Media_SetPauseTrack(qboolean paused) +{ + if (paused) + { + cdpausedtrack = cdplayingtrack; + cdplayingtrack = 0; + CDAudio_Pause(); + } + else + { + cdplayingtrack = cdpausedtrack; + cdpausedtrack = 0; + CDAudio_Resume(); + } +} + +void Media_NumberedTrack(int initialtrack, int looptrack) +{ + char *init = initialtrack?va("%i", initialtrack):NULL; + char *loop = looptrack?va("%i", looptrack):NULL; + + Media_BackgroundTrack(init, loop); +} + +void Media_EndedTrack(void) +{ + cdplayingtrack = 0; + cdpausedtrack = 0; + + if (cdloopingtrack) + Media_BackgroundTrack(cdloopingtrack, cdloopingtrack); +} + +void CD_f (void) +{ + char *command; + int ret; + int n; + + if (Cmd_Argc() < 2) + return; + + command = Cmd_Argv (1); + + if (Q_strcasecmp(command, "play") == 0) + { + Media_BackgroundTrack(Cmd_Argv(2), "-"); + return; + } + + if (Q_strcasecmp(command, "loop") == 0) + { + Media_BackgroundTrack(Cmd_Argv(2), NULL); + return; + } + + if (Q_strcasecmp(command, "remap") == 0) + { + ret = Cmd_Argc() - 2; + if (ret <= 0) + { + for (n = 1; n < REMAPPED_TRACKS; n++) + if (*cdremap[n].fname) + Con_Printf(" %u -> %s\n", n, cdremap[n].fname); + return; + } + for (n = 1; n <= ret; n++) + Q_strncpyz(cdremap[n].fname, Cmd_Argv (n+1), sizeof(cdremap[n].fname)); + return; + } + + if (!bgmvolume.ival) + { + Con_Printf("Background music is disabled. %s is 0\n", bgmvolume.name); + return; + } + + if (!CDAudio_Startup()) + { + Con_Printf("No cd drive detected\n"); + return; + } + + if (Q_strcasecmp(command, "on") == 0) + { + cdenabled = true; + return; + } + + if (Q_strcasecmp(command, "off") == 0) + { + if (cdplayingtrack || cdpausedtrack) + CDAudio_Stop(); + cdenabled = false; + return; + } + + if (Q_strcasecmp(command, "reset") == 0) + { + cdenabled = true; + if (cdplayingtrack || cdpausedtrack) + CDAudio_Stop(); + for (n = 0; n < REMAPPED_TRACKS; n++) + strcpy(cdremap[n].fname, ""); + cdnumtracks = CDAudio_GetAudioDiskInfo(); + return; + } + + if (Q_strcasecmp(command, "close") == 0) + { + CDAudio_CloseDoor(); + return; + } + + if (cdnumtracks <= 0) + { + cdnumtracks = CDAudio_GetAudioDiskInfo(); + if (cdnumtracks < 0) + { + Con_Printf("No CD in player.\n"); + return; + } + } + + if (Q_strcasecmp(command, "stop") == 0) + { + CDAudio_Stop(); + return; + } + + if (Q_strcasecmp(command, "pause") == 0) + { + Media_SetPauseTrack(true); + return; + } + + if (Q_strcasecmp(command, "resume") == 0) + { + Media_SetPauseTrack(false); + return; + } + + if (Q_strcasecmp(command, "eject") == 0) + { + if (cdplayingtrack || cdpausedtrack) + CDAudio_Stop(); + CDAudio_Eject(); + cdnumtracks = -1; + return; + } + + if (Q_strcasecmp(command, "info") == 0) + { + Con_Printf("%u tracks\n", cdnumtracks); + if (cdplayingtrack > 0) + Con_Printf("Currently %s track %u\n", cdloopingtrack ? "looping" : "playing", cdplayingtrack); + else if (cdpausedtrack > 0) + Con_Printf("Paused %s track %u\n", cdloopingtrack ? "looping" : "playing", cdpausedtrack); + return; + } +} + //actually, this func just flushes and states that it should be playing. the ambientsound func actually changes the track. void Media_Next_f (void) { @@ -310,8 +553,9 @@ void Media_Next_f (void) -void M_Menu_Media_f (void) { - key_dest = key_menu; +void M_Menu_Media_f (void) +{ + Key_Dest_Add(kdm_menu); m_state = m_media; } @@ -575,7 +819,7 @@ void M_Media_Key (int key) mediatrack_t *newtrack; newtrack = Z_Malloc(sizeof(mediatrack_t)); Q_strncpyz(newtrack->filename, media_iofilename, sizeof(newtrack->filename)); - Q_strncpyz(newtrack->nicename, COM_SkipPath(media_iofilename), sizeof(newtrack->filename)); + Q_strncpyz(newtrack->nicename, COM_SkipPath(media_iofilename), sizeof(newtrack->nicename)); newtrack->length = 0; newtrack->next = tracks; tracks = newtrack; @@ -715,7 +959,7 @@ void Media_LoadTrackNames (char *listname) else #endif Q_strncpyz(newtrack->filename, filename, sizeof(newtrack->filename)); - Q_strncpyz(newtrack->nicename, trackname, sizeof(newtrack->filename)); + Q_strncpyz(newtrack->nicename, trackname, sizeof(newtrack->nicename)); newtrack->length = atoi(len); newtrack->next = tracks; tracks = newtrack; @@ -739,7 +983,7 @@ void Media_LoadTrackNames (char *listname) newtrack = Z_Malloc(sizeof(mediatrack_t)); Q_strncpyz(newtrack->filename, filename, sizeof(newtrack->filename)); - Q_strncpyz(newtrack->nicename, COM_SkipPath(trackname), sizeof(newtrack->filename)); + Q_strncpyz(newtrack->nicename, COM_SkipPath(trackname), sizeof(newtrack->nicename)); newtrack->length = 0; newtrack->next = tracks; tracks = newtrack; @@ -764,6 +1008,9 @@ char *Media_NextTrack(int musicchannelnum) if (bgmvolume.value <= 0 || !media_playing) return NULL; + if (!fakecdactive) + Media_EndedTrack(); + if (!loadedtracknames) Media_LoadTrackNames("sound/media.m3u"); if (!tracks && !fakecdactive) @@ -774,6 +1021,7 @@ char *Media_NextTrack(int musicchannelnum) media_playing = false; return NULL; } + fakecdactive = false; // if (cursndcard == sndcardinfo) //figure out the next track (primary sound card, we could actually get different tracks on different cards (and unfortunatly do)) // { @@ -2288,12 +2536,12 @@ qboolean Media_PlayFilm(char *name, qboolean enqueue) CDAudio_Stop(); SCR_EndLoadingPlaque(); - if (key_dest == key_menu) + if (Key_Dest_Has(kdm_menu)) { - key_dest = key_game; + Key_Dest_Remove(kdm_menu); m_state = m_none; } - if (key_dest != key_console) + if (!Key_Dest_Has(kdm_console)) scr_con_current=0; return true; } @@ -2841,7 +3089,7 @@ qboolean Media_PausedDemo (void) //capturedemo doesn't record any frames when the console is visible //but that's okay, as we don't load any demo frames either. if ((cls.demoplayback && Media_Capturing()) || capturepaused) - if (key_dest != key_game || scr_con_current > 0 || !cl.validsequence || capturepaused) + if (Key_Dest_Has(~kdm_game) || scr_con_current > 0 || !cl.validsequence || capturepaused) return true; return false; @@ -3172,7 +3420,7 @@ void Media_RecordDemo_f(void) Cmd_ShiftArgs(1, false); Media_RecordFilm_f(); scr_con_current=0; - key_dest = key_game; + Key_Dest_Remove(kdm_console|kdm_menu); if (currentcapture_funcs) recordingdemo = true; @@ -3891,6 +4139,13 @@ void Media_Init(void) Cmd_AddCommand("music_next", Media_Next_f); Cmd_AddCommand("music", Media_NamedTrack_f); + Cmd_AddCommand("cd", CD_f); + cdenabled = false; + if (COM_CheckParm("-nocdaudio")) + cdenabled = false; + if (COM_CheckParm("-cdaudio")) + cdenabled = true; + #if defined(GLQUAKE) Cmd_AddCommand("capture", Media_RecordFilm_f); Cmd_AddCommand("capturedemo", Media_RecordDemo_f); diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c index 8f0d43ab6..80543b5c3 100644 --- a/engine/client/m_multi.c +++ b/engine/client/m_multi.c @@ -17,7 +17,7 @@ void M_Menu_MultiPlayer_f (void) int mgt; p = NULL; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; mgt = M_GameType(); @@ -340,7 +340,7 @@ void M_Menu_Setup_f (void) mpic_t *p; menucustom_t *cu; m_state = m_complex; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); menu = M_CreateMenu(sizeof(setupmenu_t)); info = menu->data; @@ -388,7 +388,7 @@ void M_Menu_Setup_f (void) return; } - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(setupmenu_t)); @@ -573,7 +573,7 @@ void M_Menu_GameOptions_f (void) int mgt; int players; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(newmultimenu_t)); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 54055afa2..639c58968 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -9,7 +9,7 @@ menu_t *M_Options_Title(int *y, int infosize) struct menu_s *menu; *y = 32; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(infosize); @@ -215,7 +215,7 @@ void M_Menu_Audio_Speakers_f (void) audiomenuinfo_t *info; menu_t *menu; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(audiomenuinfo_t)); @@ -1074,6 +1074,8 @@ void M_Menu_Lighting_f (void) int y; menu_t *menu = M_Options_Title(&y, sizeof(lightingmenuinfo_t)); + +#ifdef RTLIGHTS int lightselect, dlightselect; if (r_shadow_realtime_world.ival) @@ -1105,6 +1107,7 @@ void M_Menu_Lighting_f (void) dlightselect = 1; else dlightselect = 0; +#endif { lightingmenuinfo_t *info = menu->data; @@ -1112,10 +1115,13 @@ void M_Menu_Lighting_f (void) { MB_REDTEXT("Lighting Options", false), MB_TEXT("\x80\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x82", false), +#ifdef RTLIGHTS MB_COMBORETURN("Lighting Mode", lightingopts, lightselect, info->lightcombo, "Selects method used for world lighting. Realtime lighting requires appropriate realtime lighting files for maps."), MB_COMBORETURN("Dynamic Lighting Mode", dlightopts, dlightselect, info->dlightcombo, "Selects method used for dynamic lighting such as explosion lights and muzzle flashes."), + MB_CHECKBOXCVARTIP("Soft Shadows", r_shadow_shadowmapping, 0, "Enables softer shadows instead of course-edged pixelated shadows."), MB_CMD("Apply Lighting", M_VideoApplyShadowLighting, "Applies set lighting modes and restarts video."), MB_SPACING(4), +#endif MB_COMBOCVAR("LIT Loading", r_loadlits, loadlitopts, loadlitvalues, "Determines if the engine should use external colored lighting for maps. The generated setting will cause the engine to generate colored lighting for maps that don't have the associated data."), MB_CHECKBOXCVAR("Lightstyle Lerp", r_lightstylesmooth, 0), MB_SPACING(4), diff --git a/engine/client/m_script.c b/engine/client/m_script.c index ffc4b2ceb..b0167d408 100644 --- a/engine/client/m_script.c +++ b/engine/client/m_script.c @@ -43,8 +43,7 @@ void M_MenuS_Script_f (void) //create a menu. extern menu_t *currentmenu; menu_t *oldmenu; char *alias = Cmd_Argv(1); -// if (key_dest != key_console) - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; selectitem = 0; diff --git a/engine/client/m_single.c b/engine/client/m_single.c index 834a3ac1e..753bb2cec 100644 --- a/engine/client/m_single.c +++ b/engine/client/m_single.c @@ -72,7 +72,7 @@ void M_Menu_Save_f (void) if (cl.intermission) return; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(loadsavemenuinfo_t)); @@ -96,7 +96,7 @@ void M_Menu_Load_f (void) menu_t *menu; int i; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(loadsavemenuinfo_t)); @@ -130,7 +130,7 @@ void M_Menu_SinglePlayer_f (void) mpic_t *p; #endif - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; #ifdef CLIENTONLY @@ -721,7 +721,7 @@ void M_Menu_Demos_f (void) demomenu_t *info; menu_t *menu; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(demomenu_t)); @@ -759,7 +759,7 @@ void M_Menu_MediaFiles_f (void) demomenu_t *info; menu_t *menu; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(sizeof(demomenu_t)); diff --git a/engine/client/menu.c b/engine/client/menu.c index 253b1d0ee..63beb1c57 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -177,10 +177,10 @@ int m_save_demonum; void M_CloseMenu_f (void) { - if (key_dest != key_menu) + if (!Key_Dest_Has(kdm_menu)) return; M_RemoveAllMenus(); - key_dest = key_game; + Key_Dest_Remove(kdm_menu); m_state = m_none; } /* @@ -192,15 +192,14 @@ void M_ToggleMenu_f (void) { if (m_state) { - key_dest = key_menu; + Key_Dest_Add(kdm_menu); return; } #ifdef CSQC_DAT if (CSQC_ConsoleCommand("togglemenu")) { - if (key_dest == key_console) - key_dest = key_game; + Key_Dest_Remove(kdm_console); return; } #endif @@ -213,13 +212,14 @@ void M_ToggleMenu_f (void) return; #endif - if (key_dest == key_menu) + //it IS a toggle, so close the menu if its already active + if (Key_Dest_Has(kdm_menu)) { - key_dest = key_game; + Key_Dest_Remove(kdm_menu); m_state = m_none; return; } - if (key_dest == key_console) + if (Key_Dest_Has(kdm_console)) { if (cls.state != ca_active) M_Menu_Main_f(); @@ -364,7 +364,7 @@ void M_Menu_Keys_f (void) int mgt; extern cvar_t cl_splitscreen, cl_forcesplitclient; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; menu = M_CreateMenu(0); @@ -511,7 +511,7 @@ int helppagemin; void M_Menu_Help_f (void) { - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_help; help_page = 0; @@ -619,7 +619,7 @@ void M_Menu_Prompt (void (*callback)(void *, int), void *ctx, char *m1, char *m2 promptmenu_t *m; char *t; - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; m = (promptmenu_t*)M_CreateMenuInfront(sizeof(*m) - sizeof(m->m) + strlen(m1)+strlen(m2)+strlen(m3)+strlen(optionyes)+strlen(optionyes)+strlen(optioncancel)+6); @@ -827,7 +827,7 @@ qboolean MC_Quit_Key (int key, menu_t *menu) case 'Y': case 'y': M_RemoveMenu(menu); - key_dest = key_console; + Key_Dest_Add(kdm_console); CL_Disconnect (); Sys_Quit (); break; @@ -910,7 +910,7 @@ void M_Menu_Quit_f (void) Sys_Quit (); break; case 2: - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; quitmenu = M_CreateMenuInfront(0); @@ -928,7 +928,7 @@ void M_Menu_Quit_f (void) MC_AddBox (quitmenu, 56, 76, 25, 5); break; case 1: - key_dest = key_menu; + Key_Dest_Add(kdm_menu); m_state = m_complex; quitmenu = M_CreateMenuInfront(0); @@ -1166,7 +1166,7 @@ void M_Draw (int uimenu) { M_RemoveAllMenus(); } - if (key_dest != key_menu) + if (!Key_Dest_Has(kdm_menu)) { m_state = m_none; return; @@ -1225,7 +1225,7 @@ void M_Keydown (int key, int unicode) switch (m_state) { case m_none: - key_dest = key_console; + Key_Dest_Remove(kdm_menu); return; case m_help: diff --git a/engine/client/merged.h b/engine/client/merged.h index 0906788df..7905d74c9 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -266,8 +266,6 @@ typedef enum backendmode_e BEM_DEPTHNORM, //all opaque stuff drawn using 'depthnorm' shader BEM_FOG, //drawing a fog volume BEM_LIGHT, //we have a valid light - BEM_SMAPLIGHTSPOT, //we have a spot light using a shadowmap - BEM_SMAPLIGHT //we have a light using a shadowmap } backendmode_t; typedef struct rendererinfo_s { @@ -322,7 +320,7 @@ typedef struct rendererinfo_s { //Uploads all modified lightmaps void (*BE_UploadAllLightmaps)(void); void (*BE_SelectEntity)(struct entity_s *ent); - void (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour); + qboolean (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour, unsigned int lmode); void (*BE_Scissor)(srect_t *rect); /*check to see if an ent should be drawn for the selected light*/ qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model); diff --git a/engine/client/p_script.c b/engine/client/p_script.c index da828f121..e49ff6091 100644 --- a/engine/client/p_script.c +++ b/engine/client/p_script.c @@ -637,8 +637,8 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "}\n" ; break; - case BM_INVMOD: - namepostfix = "_invmod"; + case BM_INVMODA: + namepostfix = "_invmoda"; defaultshader = "{\n" "program defaultsprite\n" @@ -653,6 +653,22 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) "}\n" ; break; + case BM_INVMODC: + namepostfix = "_invmodc"; + defaultshader = + "{\n" + "program defaultsprite\n" + "nomipmaps\n" + "{\n" + "map $diffuse\n" + "blendfunc GL_ZERO GL_ONE_MINUS_SRC_COLOR\n" + "rgbgen vertex\n" + "alphagen vertex\n" + "}\n" + "polygonoffset\n" + "}\n" + ; + break; case BM_SUBTRACT: namepostfix = "_sub"; defaultshader = @@ -718,21 +734,95 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) } } +static void P_ResetToDefaults(part_type_t *ptype) +{ + particle_t *parts; + skytris_t *st; + part_type_t *torun; + char tnamebuf[sizeof(ptype->name)]; + + // go with a lazy clear of list.. mark everything as DEAD and let + // the beam rendering handle removing nodes + beamseg_t *beamsegs = ptype->beams; + while (beamsegs) + { + beamsegs->flags |= BS_DEAD; + beamsegs = beamsegs->next; + } + + // forget any particles before its wiped + while (ptype->particles) + { + parts = ptype->particles->next; + ptype->particles->next = free_particles; + free_particles = ptype->particles; + ptype->particles = parts; + } + + // if we're in the runstate loop through and remove from linked list + if (ptype->state & PS_INRUNLIST) + { + if (part_run_list == ptype) + part_run_list = part_run_list->nexttorun; + else + { + for (torun = part_run_list; torun != NULL; torun = torun->nexttorun) + { + if (torun->nexttorun == ptype) + torun->nexttorun = torun->nexttorun->nexttorun; + } + } + } + + //some things need to be preserved before we clear everything. + beamsegs = ptype->beams; + st = ptype->skytris; + strcpy(tnamebuf, ptype->name); + + //free uneeded info + if (ptype->ramp) + BZ_Free(ptype->ramp); + if (ptype->models) + BZ_Free(ptype->models); + + //reset everything we're too lazy to specifically set + memset(ptype, 0, sizeof(*ptype)); + + //now set any non-0 defaults. + + ptype->beams = beamsegs; + ptype->skytris = st; + strcpy(ptype->name, tnamebuf); + ptype->assoc=P_INVALID; + ptype->inwater = P_INVALID; + ptype->cliptype = P_INVALID; + ptype->emit = P_INVALID; + ptype->alpha = 1; + ptype->alphachange = 1; + ptype->clipbounce = 0.8; + ptype->colorindex = -1; + ptype->rotationstartmin = -M_PI; //start with a random angle + ptype->rotationstartrand = M_PI-ptype->rotationstartmin; + ptype->spawnchance = 1; + ptype->dl_time = 5000; + VectorSet(ptype->dl_rgb, 1, 1, 1); + + ptype->randsmax = 1; + ptype->s2 = 1; + ptype->t2 = 1; +} + //Uses FTE's multiline console stuff. //This is the function that loads the effect descriptions (via console). static void P_ParticleEffect_f(void) { char *var, *value; char *buf; - particle_t *parts; - beamseg_t *beamsegs; - skytris_t *st; qboolean settype = false; qboolean setalphadelta = false; qboolean setbeamlen = false; - part_type_t *ptype, *torun; - char tnamebuf[sizeof(ptype->name)]; + part_type_t *ptype; int pnum, assoc; char *config = part_parsenamespace; @@ -841,67 +931,7 @@ static void P_ParticleEffect_f(void) pnum = ptype-part_type; - st = ptype->skytris; - if (ptype->ramp) - BZ_Free(ptype->ramp); - if (ptype->models) - BZ_Free(ptype->models); - - while (ptype->particles) // empty particle list - { - parts = ptype->particles->next; - ptype->particles->next = free_particles; - free_particles = ptype->particles; - ptype->particles = parts; - } - - // go with a lazy clear of list.. mark everything as DEAD and let - // the beam rendering handle removing nodes - beamsegs = ptype->beams; - while (beamsegs) - { - beamsegs->flags |= BS_DEAD; - beamsegs = beamsegs->next; - } - - beamsegs = ptype->beams; - - // if we're in the runstate loop through and remove from linked list - if (ptype->state & PS_INRUNLIST) - { - if (part_run_list == ptype) - part_run_list = part_run_list->nexttorun; - else - { - for (torun = part_run_list; torun != NULL; torun = torun->nexttorun) - { - if (torun->nexttorun == ptype) - torun->nexttorun = torun->nexttorun->nexttorun; - } - } - } - - strcpy(tnamebuf, ptype->name); - memset(ptype, 0, sizeof(*ptype)); -// ptype->particles = parts; - ptype->beams = beamsegs; - ptype->skytris = st; - strcpy(ptype->name, tnamebuf); - ptype->assoc=P_INVALID; - ptype->inwater = P_INVALID; - ptype->cliptype = P_INVALID; - ptype->emit = P_INVALID; - ptype->alpha = 1; - ptype->alphachange = 1; - ptype->clipbounce = 0.8; - ptype->colorindex = -1; - ptype->rotationstartmin = -M_PI; //start with a random angle - ptype->rotationstartrand = M_PI-ptype->rotationstartmin; - ptype->spawnchance = 1; - - ptype->randsmax = 1; - ptype->s2 = 1; - ptype->t2 = 1; + P_ResetToDefaults(ptype); while(1) { @@ -1229,8 +1259,10 @@ static void P_ParticleEffect_f(void) ptype->looks.blendmode = BM_ADD; else if (!strcmp(value, "subtract")) ptype->looks.blendmode = BM_SUBTRACT; - else if (!strcmp(value, "invmod")) - ptype->looks.blendmode = BM_INVMOD; + else if (!strcmp(value, "invmoda") || !strcmp(value, "invmod")) + ptype->looks.blendmode = BM_INVMODA; + else if (!strcmp(value, "invmodc")) + ptype->looks.blendmode = BM_INVMODC; else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor")) ptype->looks.blendmode = BM_BLENDCOLOUR; else @@ -1959,6 +1991,7 @@ static void P_ImportEffectInfo_f(void) break; } } + // P_ResetToDefaults(ptype); ptype->loaded = part_parseweak?1:2; ptype->scale = 1; ptype->alpha = 0; @@ -1969,7 +2002,6 @@ static void P_ImportEffectInfo_f(void) ptype->rgb[0] = 1; ptype->rgb[1] = 1; ptype->rgb[2] = 1; - ptype->colorindex = -1; ptype->spawnmode = SM_BOX; @@ -1980,6 +2012,8 @@ static void P_ImportEffectInfo_f(void) ptype->looks.type = PT_NORMAL; ptype->looks.blendmode = BM_BLEND; ptype->looks.stretch = 1; + + ptype->dl_time = 100; } else if (!ptype) { @@ -1995,12 +2029,12 @@ static void P_ImportEffectInfo_f(void) if (!strcmp(arg[1], "decal") || !strcmp(arg[1], "cdecal")) { ptype->looks.type = PT_CDECAL; - ptype->looks.blendmode = BM_INVMOD; + ptype->looks.blendmode = BM_INVMODC; } else if (!strcmp(arg[1], "udecal")) { ptype->looks.type = PT_UDECAL; - ptype->looks.blendmode = BM_INVMOD; + ptype->looks.blendmode = BM_INVMODC; } else if (!strcmp(arg[1], "alphastatic")) { @@ -2020,6 +2054,7 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[1], "spark")) { ptype->looks.type = PT_TEXTUREDSPARK; + ptype->looks.blendmode = BM_ADD; } else if (!strcmp(arg[1], "bubble")) { @@ -2029,7 +2064,7 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[1], "blood")) { ptype->looks.type = PT_NORMAL; - ptype->looks.blendmode = BM_INVMOD; + ptype->looks.blendmode = BM_INVMODC; ptype->gravity = 800*1; } else if (!strcmp(arg[1], "beam")) @@ -2142,7 +2177,7 @@ static void P_ImportEffectInfo_f(void) else if (!strcmp(arg[0], "blend") && args == 2) { if (!strcmp(arg[1], "invmod")) - ptype->looks.blendmode = BM_INVMOD; + ptype->looks.blendmode = BM_INVMODC; else if (!strcmp(arg[1], "alpha")) ptype->looks.blendmode = BM_BLEND; else if (!strcmp(arg[1], "add")) @@ -2152,15 +2187,15 @@ static void P_ImportEffectInfo_f(void) } else if (!strcmp(arg[0], "orientation") && args == 2) { -// if (!strcmp(arg[1], "billboard")) -// ; -// else if (!strcmp(arg[1], "spark")) -// ; -// else if (!strcmp(arg[1], "oriented")) -// ; -// else if (!strcmp(arg[1], "beam")) -// ; -// else + if (!strcmp(arg[1], "billboard")) + ptype->looks.type = PT_NORMAL; + else if (!strcmp(arg[1], "spark")) + ptype->looks.type = PT_TEXTUREDSPARK; + else if (!strcmp(arg[1], "oriented")) //FIXME: not sure this points the right way. also, its double-sided in dp. + ptype->looks.type = PT_UDECAL; + else if (!strcmp(arg[1], "beam")) + ptype->looks.type = PT_BEAM; + else Con_Printf("effectinfo 'orientation %s' not supported\n", arg[1]); } else if (!strcmp(arg[0], "lightradius") && args == 2) diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 15401bca6..e2e458704 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -122,10 +122,13 @@ extern sfx_t *cl_sfx_r_exp3; globalfunction(parse_tempentity, "CSQC_Parse_TempEntity");/*EXT_CSQC_ABSOLUTLY_VILE*/ \ \ /*These are pointers to the csqc's globals.*/ \ - globalfloat(svtime, "time"); /*float Written before entering most qc functions*/ \ - globalfloat(frametime, "frametime"); /*float Written before entering most qc functions*/ \ - globalfloat(gamespeed, "gamespeed"); /*float Written before entering most qc functions*/ \ - globalfloat(cltime, "cltime"); /*float Written before entering most qc functions*/ \ + globalfloat(simtime, "time"); /*float The simulation(aka: smoothed server) time, speed drifts based upon latency*/ \ + globalfloat(frametime, "frametime"); /*float Client render frame interval*/ \ + globalfloat(gamespeed, "gamespeed"); /*float Multiplier for real time -> simulation time*/ \ + globalfloat(cltime, "cltime"); /*float Clientside map uptime indepent of gamespeed, latency, and the server in general*/ \ + globalfloat(netnewtime, "servertime"); /*float Server time of latest inbound network frame*/ \ + globalfloat(netoldtime, "serverprevtime"); /*float Server time of previous inbound network frame */ \ + globalfloat(netdeltatime, "serverdeltatime"); /*float new-old */ \ globalfloat(physics_mode, "physics_mode"); /*float Written before entering most qc functions*/ \ globalentity(self, "self"); /*entity Written before entering most qc functions*/ \ globalentity(other, "other"); /*entity Written before entering most qc functions*/ \ @@ -263,8 +266,8 @@ static void CSQC_FindGlobals(void) #undef globalstring #undef globalfunction - if (csqcg.svtime) - *csqcg.svtime = cl.servertime; + if (csqcg.simtime) + *csqcg.simtime = cl.servertime; if (csqcg.cltime) *csqcg.cltime = cl.time; @@ -276,7 +279,7 @@ static void CSQC_FindGlobals(void) csqc_world.g.physics_mode = csqcg.physics_mode; csqc_world.g.frametime = csqcg.frametime; csqc_world.g.newmis = (int*)PR_FindGlobal(csqcprogs, "newmis", 0, NULL); - csqc_world.g.time = csqcg.svtime; + csqc_world.g.time = csqcg.simtime; csqc_world.g.v_forward = csqcg.forward; csqc_world.g.v_right = csqcg.right; csqc_world.g.v_up = csqcg.up; @@ -468,8 +471,8 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t out->g[FST_BASE].lerpfrac = in->xv->baselerpfrac; if (rflags & CSQCRF_FRAMETIMESARESTARTTIMES) { - out->g[FST_BASE].frametime[0] = *csqcg.svtime - in->xv->baseframe1time; - out->g[FST_BASE].frametime[1] = *csqcg.svtime - in->xv->baseframe2time; + out->g[FST_BASE].frametime[0] = *csqcg.simtime - in->xv->baseframe1time; + out->g[FST_BASE].frametime[1] = *csqcg.simtime - in->xv->baseframe2time; } else { @@ -484,8 +487,8 @@ static void cs_getframestate(csqcedict_t *in, unsigned int rflags, framestate_t out->g[FS_REG].lerpfrac = in->xv->lerpfrac; if (rflags & CSQCRF_FRAMETIMESARESTARTTIMES) { - out->g[FS_REG].frametime[0] = *csqcg.svtime - in->xv->frame1time; - out->g[FS_REG].frametime[1] = *csqcg.svtime - in->xv->frame2time; + out->g[FS_REG].frametime[0] = *csqcg.simtime - in->xv->frame1time; + out->g[FS_REG].frametime[1] = *csqcg.simtime - in->xv->frame2time; } else { @@ -969,9 +972,12 @@ static void QCBUILTIN PF_R_AddEntityMask(pubprogfuncs_t *prinst, struct globalva ent = (void*)EDICT_NUM(prinst, e); if (ent->isfree) continue; - WPhys_RunThink (&csqc_world, (wedict_t*)ent); - if (ent->isfree) - continue; + if (ent->v->think) + { + WPhys_RunThink (&csqc_world, (wedict_t*)ent); + if (ent->isfree) + continue; + } if (ent->xv->predraw) { *csqcg.self = EDICT_TO_PROG(prinst, (void*)ent); @@ -1574,15 +1580,19 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars static void QCBUILTIN PF_cs_getstati(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int stnum = G_FLOAT(OFS_PARM0); - G_INT(OFS_RETURN) = csqc_playerview->stats[stnum]; + if (stnum >= 128) + G_FLOAT(OFS_RETURN) = csqc_playerview->statsf[stnum]; + else + G_INT(OFS_RETURN) = csqc_playerview->stats[stnum]; } static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ //convert an int stat into a qc float. +{ //read a numeric stat into a qc float. + //if bits offsets are specified, reads explicitly the integer version of the stat, allowing high bits to be read for items2/serverflags. the float stat should have the same value, just with lower precision as a float can't hold a 32bit value. maybe we should just use doubles. int stnum = G_FLOAT(OFS_PARM0); - int val = csqc_playerview->stats[stnum]; if (prinst->callargc > 1) { + int val = csqc_playerview->stats[stnum]; int first, count; first = G_FLOAT(OFS_PARM1); if (prinst->callargc > 2) @@ -2080,7 +2090,7 @@ static void QCBUILTIN PF_cs_setsensativityscaler (pubprogfuncs_t *prinst, struct static void QCBUILTIN PF_cs_pointparticles (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - int effectnum = G_FLOAT(OFS_PARM0)-1; + int effectnum = G_FLOAT(OFS_PARM0); float *org = G_VECTOR(OFS_PARM1); float *vel = G_VECTOR(OFS_PARM2); float count = G_FLOAT(OFS_PARM3); @@ -2108,7 +2118,7 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa } else { - efnum = G_FLOAT(OFS_PARM0)-1; + efnum = G_FLOAT(OFS_PARM0); ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM1); } efnum = CL_TranslateParticleFromServer(efnum); @@ -2119,6 +2129,9 @@ static void QCBUILTIN PF_cs_trailparticles (pubprogfuncs_t *prinst, struct globa pe->ParticleTrail(start, end, efnum, -ent->entnum, &ent->trailstate); } +//0 for error, non-0 for success. +//>0 match server +//<0 are client-only. static void QCBUILTIN PF_cs_particleeffectnum (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { int i; @@ -2133,7 +2146,7 @@ static void QCBUILTIN PF_cs_particleeffectnum (pubprogfuncs_t *prinst, struct gl return; } } - //use the server's index first. + //then look for an existing client id for (i = 1; i < MAX_CSPARTICLESPRE && cl.particle_csname[i]; i++) { if (!strcmp(cl.particle_csname[i], effectname)) @@ -2149,16 +2162,12 @@ static void QCBUILTIN PF_cs_particleeffectnum (pubprogfuncs_t *prinst, struct gl cl.particle_csprecache[i] = 1+P_FindParticleType(effectname); if (cl.particle_csprecache[i]) cl.particle_csname[i] = strdup(effectname); + G_FLOAT(OFS_RETURN) = -i; } - if (csqc_isdarkplaces) - { - //keep the effectinfo synced between server and client. - G_FLOAT(OFS_RETURN) = COM_Effectinfo_ForName(effectname); - } - else - { - G_FLOAT(OFS_RETURN) = pe->FindParticleType(effectname)+1; - } + G_FLOAT(OFS_RETURN) = 0; + + //if we're using dp network protocols, we should use the effectinfo.txt file as a lookup table instead. + //G_FLOAT(OFS_RETURN) = COM_Effectinfo_ForName(effectname); } static void QCBUILTIN PF_cs_particleeffectquery (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -3600,9 +3609,6 @@ static void CS_ConsoleCommand_f(void) static void QCBUILTIN PF_cs_registercommand (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { char *str = PF_VarString(prinst, 0, pr_globals); - if (!strcmp(str, "+showscores") || !strcmp(str, "-showscores") || - !strcmp(str, "+showteamscores") || !strcmp(str, "-showteamscores")) - return; if (!Cmd_Exists(str)) Cmd_AddCommand(str, CS_ConsoleCommand_f); } @@ -4372,6 +4378,7 @@ static struct { {"pow", PF_pow, 97}, // #97 float(float value) pow (DP_QC_SINCOSSQRTPOW) {"findfloat", PF_FindFloat, 98}, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT) {"checkextension", PF_checkextension, 99}, // #99 float(string extname) checkextension (EXT_CSQC) + {"anglemod", PF_anglemod, 102}, //110 {"fopen", PF_fopen, 110}, // #110 float(string strname, float accessmode) fopen (FRIK_FILE) @@ -4965,7 +4972,7 @@ void CSQC_Event_Touch(world_t *w, wedict_t *s, wedict_t *o) *csqcg.self = EDICT_TO_PROG(w->progs, (edict_t*)s); *csqcg.other = EDICT_TO_PROG(w->progs, (edict_t*)o); - *csqcg.svtime = w->physicstime; + *csqcg.simtime = w->physicstime; PR_ExecuteProgram (w->progs, s->v->touch); @@ -4977,7 +4984,7 @@ void CSQC_Event_Think(world_t *w, wedict_t *s) { *csqcg.self = EDICT_TO_PROG(w->progs, (edict_t*)s); *csqcg.other = EDICT_TO_PROG(w->progs, (edict_t*)w->edicts); - *csqcg.svtime = w->physicstime; + *csqcg.simtime = w->physicstime; PR_ExecuteProgram (w->progs, s->v->think); } @@ -5007,7 +5014,7 @@ qboolean CSQC_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldwaterty { void *pr_globals = PR_globals(w->progs, PR_CURRENT); *csqcg.self = EDICT_TO_PROG(w->progs, ent); - *csqcg.svtime = w->physicstime; + *csqcg.simtime = w->physicstime; G_FLOAT(OFS_PARM0) = oldwatertype; G_FLOAT(OFS_PARM1) = newwatertype; PR_ExecuteProgram (w->progs, ent->xv->contentstransition); @@ -5028,10 +5035,9 @@ void CSQC_World_GetFrameState(world_t *w, wedict_t *win, framestate_t *out) void CSQC_Shutdown(void) { - extern int mouseusedforgui; if (csqcprogs) { - mouseusedforgui = false; + key_dest_absolutemouse &= ~kdm_game; CSQC_ForgetThreads(); PR_ResetFonts(true); PR_Common_Shutdown(csqcprogs, false); @@ -5290,6 +5296,7 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks csqcprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); csqcprogparms.user = &csqc_world; + csqc_world.keydestmask = kdm_game; csqctime = Sys_DoubleTime(); if (!csqcprogs) @@ -5325,7 +5332,10 @@ qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checks else { if (PR_LoadProgs(csqcprogs, "csprogs.dat", 52195, NULL, 0) >= 0) + { + csqc_isdarkplaces = true; loaded = true; + } else if (PR_LoadProgs(csqcprogs, "csprogs.dat", 0, NULL, 0) >= 0) loaded = true; else @@ -5696,7 +5706,11 @@ qboolean CSQC_DrawView(void) if (csqcg.frametime) *csqcg.frametime = host_frametime; - if (!csqc_isdarkplaces) + if (csqc_isdarkplaces) + { + csqc_world.physicstime = cl.servertime; + } + else { while(1) { @@ -5762,8 +5776,18 @@ qboolean CSQC_DrawView(void) if (csqcg.cltime) *csqcg.cltime = realtime; - if (csqcg.svtime) - *csqcg.svtime = cl.servertime; + if (csqcg.simtime) + *csqcg.simtime = cl.servertime; + + if (cl.currentpackentities && cl.previouspackentities) + { + if (csqcg.netnewtime) + *csqcg.netnewtime = cl.currentpackentities->servertime; + if (csqcg.netoldtime) + *csqcg.netoldtime = cl.previouspackentities->servertime; + if (csqcg.netdeltatime) + *csqcg.netdeltatime = cl.currentpackentities->servertime - cl.previouspackentities->servertime; + } CSQC_RunThreads(); //wake up any qc threads @@ -6064,7 +6088,7 @@ qboolean CSQC_CenterPrint(int lplayernum, char *cmd) (((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, cmd)); PR_ExecuteProgram (csqcprogs, csqcg.parse_centerprint); - return G_FLOAT(OFS_RETURN); + return G_FLOAT(OFS_RETURN) || csqc_isdarkplaces; } void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd) @@ -6074,8 +6098,8 @@ void CSQC_Input_Frame(int lplayernum, usercmd_t *cmd) CSQC_ChangeLocalPlayer(lplayernum); - if (csqcg.svtime) - *csqcg.svtime = cl.servertime; + if (csqcg.simtime) + *csqcg.simtime = cl.servertime; if (csqcg.cltime) *csqcg.cltime = cl.time; @@ -6168,11 +6192,18 @@ void CSQC_ParseEntities(void) pr_globals = PR_globals(csqcprogs, PR_CURRENT); CL_CalcClientTime(); - if (csqcg.svtime) //estimated server time - *csqcg.svtime = cl.servertime; + if (csqcg.simtime) //estimated server time + *csqcg.simtime = cl.servertime; if (csqcg.cltime) //smooth client time. *csqcg.cltime = cl.time; + if (csqcg.netnewtime) + *csqcg.netnewtime = cl.gametime; + if (csqcg.netoldtime) + *csqcg.netoldtime = cl.oldgametime; + if (csqcg.netdeltatime) + *csqcg.netdeltatime = cl.gametime - cl.oldgametime; + if (csqcg.clientcommandframe) *csqcg.clientcommandframe = cl.movesequence; if (csqcg.servercommandframe) diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 131d645d7..09738bd03 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -77,17 +77,11 @@ struct { struct font_s *font[4]; } fontslot[FONT_SLOTS]; -static struct font_s *PR_CL_ChooseFont(pubprogfuncs_t *prinst, float szx, float szy) +static struct font_s *PR_CL_ChooseFont(world_t *world, float szx, float szy) { int fontidx = 0; //default by default... - world_t *world = prinst->parms->user; struct font_s *font = font_conchar; - if (world->g.drawfontscale) - { - szx *= world->g.drawfontscale[0]; - szy *= world->g.drawfontscale[1]; - } if (world->g.drawfont) { fontidx = *world->g.drawfont; @@ -111,8 +105,13 @@ static struct font_s *PR_CL_ChooseFont(pubprogfuncs_t *prinst, float szx, float } void PR_CL_BeginString(pubprogfuncs_t *prinst, float vx, float vy, float szx, float szy, float *px, float *py) { - struct font_s *font = PR_CL_ChooseFont(prinst, szx, szy); - + world_t *world = prinst->parms->user; + struct font_s *font = PR_CL_ChooseFont(world, szx, szy); + if (world->g.drawfontscale && (world->g.drawfontscale[0] || world->g.drawfontscale[1])) + { + szx *= world->g.drawfontscale[0]; + szy *= world->g.drawfontscale[1]; + } Font_BeginScaledString(font, vx, vy, szx, szy, px, py); } int PR_findnamedfont(char *name, qboolean isslotname) @@ -449,7 +448,7 @@ void QCBUILTIN PF_CL_drawcharacter (pubprogfuncs_t *prinst, struct globalvars_s //float drawrawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455; void QCBUILTIN PF_CL_drawrawstring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ +{ float *pos = G_VECTOR(OFS_PARM0); char *text = PR_GetStringOfs(prinst, OFS_PARM1); float *size = G_VECTOR(OFS_PARM2); @@ -567,8 +566,10 @@ void QCBUILTIN PF_CL_drawgetimagesize (pubprogfuncs_t *prinst, struct globalvars void QCBUILTIN PF_cl_getmousepos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { float *ret = G_VECTOR(OFS_RETURN); + world_t *world = prinst->parms->user; + unsigned int target = world->keydestmask; - if (Key_MouseShouldBeFree()) + if (key_dest_absolutemouse & target) { ret[0] = mousecursor_x; ret[1] = mousecursor_y; @@ -656,10 +657,17 @@ void QCBUILTIN PF_SubConDraw (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl float *size = G_VECTOR(OFS_PARM2); float fontsize = G_FLOAT(OFS_PARM3); console_t *con = Con_FindConsole(conname); + world_t *world = prinst->parms->user; if (!con) return; - Con_DrawOneConsole(con, PR_CL_ChooseFont(prinst, fontsize, fontsize), pos[0], pos[1], size[0], size[1]); + if (world->g.drawfontscale) + { +// szx *= world->g.drawfontscale[0]; + fontsize *= world->g.drawfontscale[1]; + } + + Con_DrawOneConsole(con, PR_CL_ChooseFont(world, fontsize, fontsize), pos[0], pos[1], size[0], size[1]); } qboolean Key_Console (console_t *con, unsigned int unicode, int key); void Key_ConsoleRelease (console_t *con, unsigned int unicode, int key); @@ -690,7 +698,7 @@ void QCBUILTIN PF_SubConInput (pubprogfuncs_t *prinst, struct globalvars_s *pr_g break; case CSIE_MOUSEABS: //x, y - if (con == con_current && key_dest == key_console) + if (con == con_current && (key_dest_mask & kdm_console)) break; //no interfering with the main console! con->mousecursor[0] = pa; con->mousecursor[1] = pb; @@ -932,16 +940,21 @@ void QCBUILTIN PF_cl_setkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr { case 0: // key_game - key_dest = ((cls.state == ca_active)?key_game:key_console); + if (!(cls.state == ca_active)) + Key_Dest_Add(kdm_console); + Key_Dest_Remove(kdm_menu); + Key_Dest_Remove(kdm_message); break; case 2: // key_menu - key_dest = key_menu; m_state = m_menu_dat; + Key_Dest_Remove(kdm_message); + Key_Dest_Add(kdm_menu); break; case 1: // key_message - // key_dest = key_message + //Key_Dest_Remove(kdm_menu); + //Key_Dest_Add(kdm_message); // break; default: PR_BIError (prinst, "PF_setkeydest: wrong destination %i !\n",(int)G_FLOAT(OFS_PARM0)); @@ -950,37 +963,31 @@ void QCBUILTIN PF_cl_setkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr //float getkeydest(void) = #602; void QCBUILTIN PF_cl_getkeydest (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - switch(key_dest) + if (Key_Dest_Has(kdm_menu)) { - case key_game: - G_FLOAT(OFS_RETURN) = 0; - break; - case key_menu: if (m_state == m_menu_dat) G_FLOAT(OFS_RETURN) = 2; else G_FLOAT(OFS_RETURN) = 3; - break; - case 1: - // key_message - // key_dest = key_message - // break; - default: - G_FLOAT(OFS_RETURN) = 3; } +// else if (Key_Dest_Has(kdm_message)) +// G_FLOAT(OFS_RETURN) = 1; + else + G_FLOAT(OFS_RETURN) = 0; } //void setmousetarget(float trg) = #603; void QCBUILTIN PF_cl_setmousetarget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - extern int mouseusedforgui; + world_t *world = prinst->parms->user; + unsigned int target = world->keydestmask; switch ((int)G_FLOAT(OFS_PARM0)) { - case 1: //1 is delta-based. - mouseusedforgui = false; + case 1: //1 is delta-based (mt_menu). + key_dest_absolutemouse &= ~target; break; - case 2: //2 is absolute. - mouseusedforgui = true; + case 2: //2 is absolute (mt_client). + key_dest_absolutemouse |= target; break; default: PR_BIError(prinst, "PF_setmousetarget: not a valid destination\n"); @@ -990,8 +997,9 @@ void QCBUILTIN PF_cl_setmousetarget (pubprogfuncs_t *prinst, struct globalvars_s //float getmousetarget(void) = #604; void QCBUILTIN PF_cl_getmousetarget (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { - extern int mouseusedforgui; - G_FLOAT(OFS_RETURN) = mouseusedforgui?2:1; + world_t *world = prinst->parms->user; + unsigned int target = world->keydestmask; + G_FLOAT(OFS_RETURN) = (key_dest_absolutemouse&target)?2:1; } static void QCBUILTIN PF_Remove_ (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -1655,7 +1663,6 @@ jmp_buf mp_abort; void MP_Shutdown (void) { - extern int mouseusedforgui; func_t temp; if (!menu_world.progs) return; @@ -1683,10 +1690,10 @@ void MP_Shutdown (void) Master_ClearMasks(); #endif - key_dest = key_game; + Key_Dest_Remove(kdm_menu); m_state = 0; - mouseusedforgui = false; + key_dest_absolutemouse &= ~kdm_menu; } void *VARGS PR_CB_Malloc(int size); //these functions should be tracked by the library reliably, so there should be no need to track them ourselves. @@ -1787,6 +1794,7 @@ qboolean MP_Init (void) menuprogparms.useeditor = NULL;//sorry... QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); menuprogparms.useeditor = QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms); menuprogparms.user = &menu_world; + menu_world.keydestmask = kdm_menu; menutime = Sys_DoubleTime(); if (!menu_world.progs) diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 2fcaf7e81..886f03648 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -492,8 +492,6 @@ void R2D_ConsoleBackground (int firstline, int lastline, qboolean forceopaque) { float a; int w, h; - if (!conback) - return; w = vid.width; h = vid.height; @@ -515,7 +513,13 @@ void R2D_ConsoleBackground (int firstline, int lastline, qboolean forceopaque) h>>=1; w>>=1; } - if (a >= 1) + if (!conback) + { + R2D_ImageColours(0, 0, 0, a); + R2D_FillBlock(0, lastline-(int)vid.height, w, h); + R2D_ImageColours(1, 1, 1, 1); + } + else if (a >= 1) { R2D_ImageColours(1, 1, 1, 1); R2D_ScalePic(0, lastline-(int)vid.height, w, h, conback); @@ -579,7 +583,7 @@ void R2D_TileClear (float x, float y, float w, float h) void R2D_Conback_Callback(struct cvar_s *var, char *oldvalue) { - if (qrenderer == QR_NONE) + if (qrenderer == QR_NONE || !strcmp(var->string, "none")) { conback = NULL; return; diff --git a/engine/client/r_part.c b/engine/client/r_part.c index 6b2c7ef6c..41c547323 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -92,6 +92,9 @@ void R_ParticleSystem_Callback(struct cvar_s *var, char *oldvalue) { CL_ClearTEntParticleState(); CL_ClearLerpEntsParticleState(); +#ifdef Q2CLIENT + CLQ2_ClearParticleState(); +#endif pe->ShutdownParticles(); } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 96d4b2aa6..417c18da0 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -630,7 +630,7 @@ static void Surf_BuildDeluxMap (msurface_t *surf, qbyte *dest) { deluxmap = surf->samples - currentmodel->lightdata + currentmodel->deluxdata; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -649,7 +649,7 @@ static void Surf_BuildDeluxMap (msurface_t *surf, qbyte *dest) { deluxmap = (surf->samples - currentmodel->lightdata)*3 + currentmodel->deluxdata; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -911,7 +911,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, blocklights[i] = t; } - for (maps = 0 ; maps < MAXLIGHTMAPS ; maps++) + for (maps = 0 ; maps < MAXQ1LIGHTMAPS ; maps++) { surf->cached_light[maps] = -1-ambient; surf->cached_colour[maps] = 0xff; @@ -978,7 +978,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, } else if (currentmodel->engineflags & MDLF_RGBLIGHTING) //rgb { - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -1014,7 +1014,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, } } else - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -1116,7 +1116,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, if (lightmap) { if (currentmodel->engineflags & MDLF_RGBLIGHTING) //rgb - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]/3; @@ -1128,7 +1128,7 @@ static void Surf_BuildLightMap (msurface_t *surf, qbyte *dest, qbyte *deluxdest, } else - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -1185,7 +1185,7 @@ void Surf_RenderDynamicLightmaps (msurface_t *fa) } else { - for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && fa->styles[maps] != 255 ; maps++) if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] || cl_lightstyle[fa->styles[maps]].colour != fa->cached_colour[maps]) @@ -1930,20 +1930,25 @@ void Surf_SetupFrame(void) static mleaf_t fakeleaf; mleaf_t *leaf; - r_viewleaf = &fakeleaf; //so we can use quake1 rendering routines for q2 bsps. + //FIXME: do we still need this fakeleaf stuff? + r_viewleaf = &fakeleaf; r_viewleaf->contents = Q1CONTENTS_EMPTY; r_viewleaf2 = NULL; r_oldviewcluster = r_viewcluster; r_oldviewcluster2 = r_viewcluster2; if (r_refdef.recurse) + { leaf = Mod_PointInLeaf (cl.worldmodel, r_refdef.pvsorigin); + r_viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, r_refdef.pvsorigin); + } else + { leaf = Mod_PointInLeaf (cl.worldmodel, r_origin); + r_viewcontents = cl.worldmodel->funcs.PointContents(cl.worldmodel, NULL, r_origin); + } r_viewcluster = r_viewcluster2 = leaf->cluster; - r_viewcontents = leaf->contents & (FTECONTENTS_LAVA|FTECONTENTS_SLIME|FTECONTENTS_WATER); - // check above and below so crossing solid water doesn't draw wrong if (!leaf->contents) { // look down a bit @@ -2489,10 +2494,14 @@ int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe) int first = numlightmaps; int i; char nname[MAX_QPATH]; + qboolean odd = (count & 1) && deluxe; if (!count) return -1; + if (odd) + count++; + i = numlightmaps + count; lightmap = BZ_Realloc(lightmap, sizeof(*lightmap)*(i)); while(i > first) @@ -2516,6 +2525,17 @@ int Surf_NewExternalLightmaps(int count, char *filepattern, qboolean deluxe) lightmap[i]->height = image_height; } + if (odd) + { + i = numlightmaps+count-1; + if (!TEXVALID(lightmap[i]->lightmap_texture)) + { //FIXME: no deluxemaps after all... + Z_Free(lightmap[i]); + lightmap[i] = NULL; + count--; + } + } + numlightmaps += count; return first; @@ -2560,6 +2580,7 @@ void Surf_BuildModelLightmaps (model_t *m) COM_StripAllExtensions(m->name, pattern, sizeof(pattern)); Q_strncatz(pattern, "/lm_%04u.tga", sizeof(pattern)); newfirst = Surf_NewExternalLightmaps(m->lightmaps.count, pattern, m->lightmaps.deluxemapping); + m->lightmaps.count = numlightmaps - newfirst; } else newfirst = Surf_NewLightmaps(m->lightmaps.count, m->lightmaps.width, m->lightmaps.height, m->lightmaps.deluxemapping); @@ -2569,7 +2590,7 @@ void Surf_BuildModelLightmaps (model_t *m) for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) for (batch = m->batches[sortid]; batch != NULL; batch = batch->next) { - for (i = 0; i < MAXLIGHTMAPS; i++) + for (i = 0; i < MAXRLIGHTMAPS; i++) { if (batch->lightmap[i] < 0) continue; @@ -2648,7 +2669,7 @@ void Surf_BuildModelLightmaps (model_t *m) for (i=0; inummodelsurfaces; i++) { surf = m->surfaces + i + m->firstmodelsurface; - for (j = 0; j < 4; j++) + for (j = 0; j < MAXRLIGHTMAPS; j++) { if (surf->lightmaptexturenums[j] < m->lightmaps.first) { diff --git a/engine/client/render.h b/engine/client/render.h index 76763cb58..74a6a778d 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -170,7 +170,7 @@ typedef struct qboolean externalview; /*draw external models and not viewmodels*/ qboolean recurse; /*in a mirror/portal/half way through drawing something else*/ qboolean forcevis; /*if true, vis comes from the forcedvis field instead of recalculated*/ - qboolean flipcull; /*reflected/flipped view, requires inverted culling*/ + unsigned int flipcull; /*reflected/flipped view, requires inverted culling (should be set to SHADER_CULL_FLIPPED or 0)*/ qboolean useperspective; /*not orthographic*/ int postprocshader; /*if set, renders to texture then invokes this shader*/ @@ -186,7 +186,7 @@ extern struct texture_s *r_notexture_mip; extern entity_t r_worldentity; -void BE_GenModelBatches(struct batch_s **batches); +void BE_GenModelBatches(struct batch_s **batches, const struct dlight_s *dl, unsigned int bemode); //if dl, filters based upon the dlight. //gl_alias.c void GL_GAliasFlushSkinCache(void); @@ -502,10 +502,17 @@ enum { RQUANT_ENTBATCHES, RQUANT_WORLDBATCHES, RQUANT_2DBATCHES, + RQUANT_SHADOWFACES, RQUANT_SHADOWEDGES, + RQUANT_SHADOWSIDES, RQUANT_LITFACES, + RQUANT_RTLIGHT_DRAWN, + RQUANT_RTLIGHT_CULL_FRUSTUM, + RQUANT_RTLIGHT_CULL_PVS, + RQUANT_RTLIGHT_CULL_SCISSOR, + RQUANT_MAX }; extern int rquant[RQUANT_MAX]; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 5e85bb782..0cb4d74b1 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -345,25 +345,6 @@ cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04 cvar_t r_glsl_offsetmapping_reliefmapping = CVARF("r_glsl_offsetmapping_reliefmapping", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM); cvar_t r_glsl_turbscale = CVARF ("r_glsl_turbscale", "1", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_world = SCVARF ("r_shadow_realtime_world", "0", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_world_shadows = SCVARF ("r_shadow_realtime_world_shadows", "1", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_world_lightmaps = SCVARF ("r_shadow_realtime_world_lightmaps", "0", 0); -#ifdef FTE_TARGET_WEB -cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "0", CVAR_ARCHIVE); -#else -cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "1", CVAR_ARCHIVE); -#endif -cvar_t r_shadow_realtime_dlight_shadows = SCVARF ("r_shadow_realtime_dlight_shadows", "1", CVAR_ARCHIVE); -cvar_t r_shadow_realtime_dlight_ambient = SCVAR ("r_shadow_realtime_dlight_ambient", "0"); -cvar_t r_shadow_realtime_dlight_diffuse = SCVAR ("r_shadow_realtime_dlight_diffuse", "1"); -cvar_t r_shadow_realtime_dlight_specular = SCVAR ("r_shadow_realtime_dlight_specular", "4"); //excessive, but noticable. its called stylized, okay? shiesh, some people -cvar_t r_editlights_import_radius = SCVAR ("r_editlights_import_radius", "1"); -cvar_t r_editlights_import_ambient = SCVAR ("r_editlights_import_ambient", "0"); -cvar_t r_editlights_import_diffuse = SCVAR ("r_editlights_import_diffuse", "1"); -cvar_t r_editlights_import_specular = SCVAR ("r_editlights_import_specular", "1"); //excessive, but noticable. its called stylized, okay? shiesh, some people -cvar_t r_shadow_shadowmapping = SCVARF ("debug_r_shadow_shadowmapping", "0", 0); -cvar_t r_sun_dir = SCVAR ("r_sun_dir", "0.2 0.5 0.8"); -cvar_t r_sun_colour = SCVARF ("r_sun_colour", "0 0 0", CVAR_ARCHIVE); cvar_t r_waterstyle = CVARFD ("r_waterstyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes how water, and teleporters are drawn. Possible values are:\n0: fastturb-style block colour.\n1: regular q1-style water.\n2: refraction(ripply and transparent)\n3: refraction with reflection at an angle\n4: ripplemapped without reflections (requires particle effects)\n5: ripples+reflections"); cvar_t r_slimestyle = CVARFD ("r_slimestyle", "", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only slime. If empty, defers to r_waterstyle."); cvar_t r_lavastyle = CVARFD ("r_lavastyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only lava. If empty, defers to r_waterstyle."); @@ -630,17 +611,8 @@ void Renderer_Init(void) Cvar_Register (&r_flashblend, GRAPHICALNICETIES); Cvar_Register (&r_flashblendscale, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_world, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_world_shadows, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_dlight, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_dlight_ambient, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_dlight_diffuse, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_dlight_specular, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_dlight_shadows, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_realtime_world_lightmaps, GRAPHICALNICETIES); - Cvar_Register (&r_shadow_shadowmapping, GRAPHICALNICETIES); - Cvar_Register (&r_sun_dir, GRAPHICALNICETIES); - Cvar_Register (&r_sun_colour, GRAPHICALNICETIES); + Sh_RegisterCvars(); + Cvar_Register (&r_waterstyle, GRAPHICALNICETIES); Cvar_Register (&r_lavastyle, GRAPHICALNICETIES); Cvar_Register (&r_wireframe, GRAPHICALNICETIES); @@ -1226,6 +1198,7 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n")); cl.worldmodel = NULL; CL_ClearEntityLists(); //shouldn't really be needed, but we're paranoid + //FIXME: this code should not be here. call CL_LoadModels instead? that does csqc loading etc though. :s TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n")); for (i=1 ; ibuf != NULL) BZ_Free(ri->buf); + if (ri->audio) + BZ_Free(ri->audio); BZ_Free(ri); } diff --git a/engine/client/sbar.c b/engine/client/sbar.c index 1d4278fcf..e294d5ad8 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -1851,6 +1851,9 @@ void Sbar_DrawScoreboard (void) if (cls.protocol == CP_QUAKE2) return; + if (Key_Dest_Has(~kdm_game)) + return; + #ifndef CLIENTONLY /*no scoreboard in single player (if you want bots, set deathmatch)*/ if (sv.state && !cls.deathmatch && sv.allocated_client_slots == 1) diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index 04c9a7e27..f3245f67b 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -152,7 +152,7 @@ void Sys_Quit (void) //SDL provides no file enumeration facilities. #if defined(_WIN32) #include -int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, void *), void *parm, void *spath) +int Sys_EnumerateFiles (const char *gpath, const char *match, int (*func)(const char *, int, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) { HANDLE r; WIN32_FIND_DATA fd; @@ -452,17 +452,11 @@ int QDECL main(int argc, char **argv) { float time, newtime, oldtime; quakeparms_t parms; - int t; int delay = 1; memset(&parms, 0, sizeof(parms)); - -#ifdef FTE_TARGET_WEB - parms.basedir = ""; -#else parms.basedir = "."; -#endif parms.argc = argc; parms.argv = (const char**)argv; @@ -480,11 +474,6 @@ int QDECL main(int argc, char **argv) oldtime = Sys_DoubleTime (); - -#ifdef FTE_TARGET_WEB - //-1 fps should give vsync - emscripten_set_main_loop(Sys_MainLoop, -1, false); -#else //client console should now be initialized. /* main window message loop */ @@ -519,7 +508,7 @@ int QDECL main(int argc, char **argv) Sys_Sleep(sleeptime); } } -#endif + return 0; } @@ -702,44 +691,4 @@ void Sys_Sleep (double seconds) SDL_Delay(seconds * 1000); } -#ifdef FTE_TARGET_WEB -//emscripten does not support the full set of sdl functions, so we stub the extras. -int SDL_GetGammaRamp(Uint16 *redtable, Uint16 *greentable, Uint16 *bluetable) -{ - return -1; -} -int SDL_SetGammaRamp(const Uint16 *redtable, const Uint16 *greentable, const Uint16 *bluetable) -{ - return -1; -} -//SDL_GL_GetAttribute -void SDL_UnloadObject(void *object) -{ -} -void *SDL_LoadObject(const char *sofile) -{ - return NULL; -} -void *SDL_LoadFunction(void *handle, const char *name) -{ - return NULL; -} -Uint8 SDL_GetAppState(void) -{ - return SDL_APPACTIVE; -} -#define socklen_t int -int getsockname(int socket, struct sockaddr *address, socklen_t *address_len) -{ - return -1; -} -int getpeername(int socket, struct sockaddr *address, socklen_t *address_len) -{ - return -1; -} -ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) -{ - return -1; -} -#endif diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 2e6623125..a4c0ce190 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -40,8 +40,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PRINTGLARRAYS #endif -#ifdef _DEBUG -#if _MSC_VER >= 1300 +#if defined(_DEBUG) || defined(DEBUG) +#if 1//_MSC_VER >= 1300 #define CATCHCRASH #endif #endif @@ -273,6 +273,34 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI MINIDUMPWRITEDUMP fnMiniDumpWriteDump; HMODULE hKernel; BOOL (WINAPI *pIsDebuggerPresent)(void); + DWORD (WINAPI *pSymSetOptions)(DWORD SymOptions); + BOOL (WINAPI *pSymInitialize)(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProcess); + BOOL (WINAPI *pSymFromAddr)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol); + +#ifdef _WIN64 +#define DBGHELP_POSTFIX "64" + BOOL (WINAPI *pStackWalkX)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); + PVOID (WINAPI *pSymFunctionTableAccessX)(HANDLE hProcess, DWORD64 AddrBase); + DWORD64 (WINAPI *pSymGetModuleBaseX)(HANDLE hProcess, DWORD64 qwAddr); + BOOL (WINAPI *pSymGetLineFromAddrX)(HANDLE hProcess, DWORD64 qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64); +#else +#define DBGHELP_POSTFIX "" + BOOL (WINAPI *pStackWalkX)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE TranslateAddress); + PVOID (WINAPI *pSymFunctionTableAccessX)(HANDLE hProcess, DWORD AddrBase); + DWORD (WINAPI *pSymGetModuleBaseX)(HANDLE hProcess, DWORD dwAddr); + BOOL (WINAPI *pSymGetLineFromAddrX)(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE Line); +#endif + dllfunction_t debughelpfuncs[] = + { + {(void*)&pSymFromAddr, "SymFromAddr"}, + {(void*)&pSymSetOptions, "SymSetOptions"}, + {(void*)&pSymInitialize, "SymInitialize"}, + {(void*)&pStackWalkX, "StackWalk"DBGHELP_POSTFIX}, + {(void*)&pSymFunctionTableAccessX, "SymFunctionTableAccess"DBGHELP_POSTFIX}, + {(void*)&pSymGetModuleBaseX, "SymGetModuleBase"DBGHELP_POSTFIX}, + {(void*)&pSymGetLineFromAddrX, "SymGetLineFromAddr"DBGHELP_POSTFIX}, + {NULL, NULL} + }; #ifdef PRINTGLARRAYS if (!iswatchdog && qrenderer == QR_OPENGL) @@ -303,8 +331,123 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI { } else + { DestroyWindow(mainwindow); + if (Sys_LoadLibrary("DBGHELP", debughelpfuncs)) + { + STACKFRAME stack; + CONTEXT *pcontext = exceptionInfo->ContextRecord; + IMAGEHLP_LINE line; + struct + { + SYMBOL_INFO sym; + char name[1024]; + } sym; + int frameno; + char stacklog[8192]; + int logpos, logstart; + char *logline; + + stacklog[logpos=0] = 0; + + pSymInitialize(hProc, NULL, TRUE); + pSymSetOptions(SYMOPT_LOAD_LINES); + + memset(&stack, 0, sizeof(stack)); +#ifdef _WIN64 + #define IMAGE_FILE_MACHINE_THIS IMAGE_FILE_MACHINE_AMD64 + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrPC.Offset = pcontext->Rip; + stack.AddrFrame.Mode = AddrModeFlat; + stack.AddrFrame.Offset = pcontext->Rbp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrStack.Offset = pcontext->Rsp; +#else + #define IMAGE_FILE_MACHINE_THIS IMAGE_FILE_MACHINE_I386 + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrPC.Offset = pcontext->Eip; + stack.AddrFrame.Mode = AddrModeFlat; + stack.AddrFrame.Offset = pcontext->Ebp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrStack.Offset = pcontext->Esp; +#endif + + Q_strncpyz(stacklog+logpos, FULLENGINENAME " has crashed. The following stack dump been copied to your windows clipboard.\n" +#ifdef _MSC_VER + "Would you like to generate a core dump too?\n" +#endif + "\n", sizeof(stacklog)-logpos); + logstart = logpos += strlen(stacklog+logpos); + + //so I know which one it is +#if defined(DEBUG) || defined(_DEBUG) + #define BUILDDEBUGREL "Debug" +#else + #define BUILDDEBUGREL "Optimised" +#endif +#ifdef MINIMAL + #define BUILDMINIMAL "Min" +#else + #define BUILDMINIMAL "" +#endif +#if defined(GLQUAKE) && !defined(D3DQUAKE) + #define BUILDTYPE "GL" +#elif !defined(GLQUAKE) && defined(D3DQUAKE) + #define BUILDTYPE "D3D" +#else + #define BUILDTYPE "Merged" +#endif + + Q_snprintfz(stacklog+logpos, sizeof(stacklog)-logpos, "Build: %s %s %s: %s\r\n", BUILDDEBUGREL, PLATFORM, BUILDMINIMAL BUILDTYPE, version_string()); + logpos += strlen(stacklog+logpos); + + for(frameno = 0; ; frameno++) + { + DWORD64 symdisp; + DWORD linedisp; + DWORD_PTR symaddr; + if (!pStackWalkX(IMAGE_FILE_MACHINE_THIS, hProc, GetCurrentThread(), &stack, pcontext, NULL, pSymFunctionTableAccessX, pSymGetModuleBaseX, NULL)) + break; + memset(&line, 0, sizeof(line)); + line.SizeOfStruct = sizeof(line); + symdisp = 0; + memset(&sym, 0, sizeof(sym)); + sym.sym.MaxNameLen = sizeof(sym.name); + symaddr = stack.AddrPC.Offset; + sym.sym.SizeOfStruct = sizeof(sym.sym); + if (pSymFromAddr(hProc, symaddr, &symdisp, &sym.sym)) + { + if (pSymGetLineFromAddrX(hProc, stack.AddrPC.Offset, &linedisp, &line)) + logline = va("%-20s - %s:%i\r\n", sym.sym.Name, line.FileName, line.LineNumber); + else + logline = va("%-20s+%#x\r\n", sym.sym.Name, (unsigned int)symdisp); + } + else + logline = va("0x%p\r\n", (void*)(DWORD_PTR)stack.AddrPC.Offset); + Q_strncpyz(stacklog+logpos, logline, sizeof(stacklog)-logpos); + logpos += strlen(stacklog+logpos); + if (logpos+1 >= sizeof(stacklog)) + break; + } + Sys_SaveClipboard(stacklog+logstart); +#ifdef _MSC_VER + if (MessageBox(0, stacklog, "KABOOM!", MB_ICONSTOP|MB_YESNO) != IDYES) + return EXCEPTION_EXECUTE_HANDLER; +#else + MessageBox(0, stacklog, "KABOOM!", MB_ICONSTOP); + return EXCEPTION_EXECUTE_HANDLER; +#endif + } + else + { + if (MessageBox(NULL, "KABOOM! We crashed!\nBlame the monkey in the corner.\nI hope you saved your work.\nWould you like to take a dump now?", DISTRIBUTION " Sucks", MB_ICONSTOP|MB_YESNO) != IDYES) + return EXCEPTION_EXECUTE_HANDLER; + } + } + + //generate a minidump, but only if we were compiled by something that used usable debugging info. its a bit pointless otherwise. +#ifdef _MSC_VER hDbgHelp = LoadLibrary ("DBGHELP"); if (hDbgHelp) fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump"); @@ -325,14 +468,14 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI return EXCEPTION_EXECUTE_HANDLER; } } - else - { - if (MessageBox(NULL, "KABOOM! We crashed!\nBlame the monkey in the corner.\nI hope you saved your work.\nWould you like to take a dump now?", DISTRIBUTION " Sucks", MB_ICONSTOP|MB_YESNO) != IDYES) - return EXCEPTION_EXECUTE_HANDLER; - } /*take a dump*/ - GetTempPath (sizeof(dumpPath)-16, dumpPath); + if (*com_homedir) + Q_strncpyz(dumpPath, com_homedir, sizeof(dumpPath)); + else if (*com_quakedir) + Q_strncpyz(dumpPath, com_quakedir, sizeof(dumpPath)); + else + GetTempPath (sizeof(dumpPath)-16, dumpPath); Q_strncatz(dumpPath, DISTRIBUTION"CrashDump.dmp", sizeof(dumpPath)); dumpfile = CreateFile (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (dumpfile) @@ -344,7 +487,7 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI if (fnMiniDumpWriteDump(hProc, procid, dumpfile, MiniDumpWithIndirectlyReferencedMemory|MiniDumpWithDataSegs, &crashinfo, NULL, NULL)) { CloseHandle(dumpfile); - Q_snprintfz(msg, sizeof(msg), "You can find the crashdump at\n%s\nPlease send this file to someone.\n\nWarning: sensitive information (like your current user name) might be present in the dump.\nYou will probably want to compress it.", dumpPath); + Q_snprintfz(msg, sizeof(msg), "You can find the crashdump at:\n%s\nPlease send this file to someone.\n\nWarning: sensitive information (like your current user name) might be present in the dump.\nYou will probably want to compress it.", dumpPath); MessageBox(NULL, msg, DISTRIBUTION " Sucks", 0); } else @@ -358,16 +501,31 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI } else MessageBox(NULL, "Kaboom! Sorry. No MiniDumpWriteDump function.", DISTRIBUTION " Sucks", 0); +#endif return EXCEPTION_EXECUTE_HANDLER; } + +//most compilers do not support __try. perhaps we should avoid its use entirely? +LONG CALLBACK nonmsvc_CrashExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) +{ + DWORD foo = CrashExceptionHandler(false, ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo); + + //we have no handler. thus we handle it by exiting. + if (foo == EXCEPTION_EXECUTE_HANDLER) + exit(1); + + return foo; +} + volatile int watchdogframe; //incremented each frame. int watchdogthread(void *arg) { +#ifdef _MSC_VER int oldframe = watchdogframe; int newframe; int secs = 0; while(1) - { + { newframe = watchdogframe; if (oldframe != newframe) { @@ -391,6 +549,7 @@ int watchdogthread(void *arg) } Sleep(1000); } +#endif return 0; } #endif @@ -818,39 +977,6 @@ void VARGS Sys_Error (const char *error, ...) exit (1); } -static wchar_t dequake(conchar_t chr) -{ - chr &= CON_CHARMASK; - - /*only this range are quake chars*/ - if (chr >= 0xe000 && chr < 0xe100) - { - chr &= 0xff; - if (chr >= 146 && chr < 156) - chr = chr - 146 + '0'; - if (chr >= 0x12 && chr <= 0x1b) - chr = chr - 0x12 + '0'; - if (chr == 143) - chr = '.'; - if (chr == 128 || chr == 129 || chr == 130 || chr == 157 || chr == 158 || chr == 159) - chr = '-'; - if (chr >= 128) - chr -= 128; - if (chr == 16) - chr = '['; - if (chr == 17) - chr = ']'; - if (chr == 0x1c) - chr = 249; - } - /*this range contains pictograms*/ - if (chr >= 0xe100 && chr < 0xe200) - { - chr = '?'; - } - return chr; -} - void VARGS Sys_Printf (char *fmt, ...) { va_list argptr; @@ -876,7 +1002,7 @@ void VARGS Sys_Printf (char *fmt, ...) { if (!(*in & CON_HIDDEN)) { - *out++ = dequake(*in & CON_CHARMASK); + *out++ = COM_DeQuake(*in & CON_CHARMASK); wlen++; } } @@ -992,49 +1118,66 @@ HANDLE clipboardhandle; char *cliputf8; char *Sys_GetClipboard(void) { - char *clipText; - unsigned short *clipWText; if (OpenClipboard(NULL)) { //windows programs interpret CF_TEXT as ansi (aka: gibberish) //so grab utf-16 text and convert it to utf-8 if our console parsing is set to accept that. - if (com_parseutf8.ival > 0) + clipboardhandle = GetClipboardData(CF_UNICODETEXT); + if (clipboardhandle) { - clipboardhandle = GetClipboardData(CF_UNICODETEXT); - if (clipboardhandle) + unsigned short *clipWText = GlobalLock(clipboardhandle); + if (clipWText) { - clipWText = GlobalLock(clipboardhandle); - if (clipWText) + unsigned int l, c; + char *utf8; + for (l = 0; clipWText[l]; l++) + ; + l = l*4 + 1; + utf8 = cliputf8 = malloc(l); + while(*clipWText) { - unsigned int l, c; - for (l = 0; clipWText[l]; l++) - ; - l = l*4 + 1; - clipText = cliputf8 = malloc(l); - while(*clipWText) - { - c = utf8_encode(clipText, *clipWText++, l); - if (!c) - break; - l -= c; - clipText += c; - } - *clipText = 0; - return cliputf8; + if (clipWText[0] == '\r' && clipWText[1] == '\n') //bloomin microsoft. + clipWText++; + c = utf8_encode(utf8, *clipWText++, l); + if (!c) + break; + l -= c; + utf8 += c; } - - //failed at the last hurdle - - GlobalUnlock(clipboardhandle); + *utf8 = 0; + return cliputf8; } + + //failed at the last hurdle + + GlobalUnlock(clipboardhandle); } clipboardhandle = GetClipboardData(CF_TEXT); if (clipboardhandle) { - clipText = GlobalLock(clipboardhandle); + char *clipText = GlobalLock(clipboardhandle); if (clipText) - return clipText; + { + unsigned int l, c; + char *utf8; + for (l = 0; clipText[l]; l++) + ; + l = l*4 + 1; + utf8 = cliputf8 = malloc(l); + while(*clipText) + { + if (clipText[0] == '\r' && clipText[1] == '\n') //bloomin microsoft. + clipText++; + c = utf8_encode(utf8, *clipText++, l); + if (!c) + break; + l -= c; + utf8 += c; + } + *utf8 = 0; + return cliputf8; + } //failed at the last hurdle @@ -1067,13 +1210,6 @@ void Sys_SaveClipboard(char *text) return; EmptyClipboard(); - glob = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1); - if (glob == NULL) - { - CloseClipboard(); - return; - } - if (com_parseutf8.ival > 0) { glob = GlobalAlloc(GMEM_MOVEABLE, (strlen(text) + 1)*2); @@ -1085,6 +1221,7 @@ void Sys_SaveClipboard(char *text) int error; while(*text) { + //NOTE: should be \r\n and not just \n *tempw++ = utf8_decode(&error, text, &text); } *tempw = 0; @@ -1097,16 +1234,27 @@ void Sys_SaveClipboard(char *text) } else { - //yes, quake chars will get mangled horribly. - temp = GlobalLock(glob); - if (temp != NULL) + glob = GlobalAlloc(GMEM_MOVEABLE, strlen(text) + 1); + if (glob) { - strcpy(temp, text); - GlobalUnlock(glob); - SetClipboardData(CF_TEXT, glob); + //yes, quake chars will get mangled horribly. + temp = GlobalLock(glob); + if (temp != NULL) + { + int error; + while (*text) + { + //NOTE: should be \r\n and not just \n + *temp++ = utf8_decode(&error, text, &text); + } + *temp = 0; + strcpy(temp, text); + GlobalUnlock(glob); + SetClipboardData(CF_TEXT, glob); + } + else + GlobalFree(glob); } - else - GlobalFree(glob); } CloseClipboard(); @@ -2290,7 +2438,11 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin #endif #ifdef CATCHCRASH +#ifdef _MSC_VER __try +#else + AddVectoredExceptionHandler(true, nonmsvc_CrashExceptionHandler); +#endif #endif { /* @@ -2565,7 +2717,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin SetHookState(ActiveApp); /*sleep if its not yet time for a frame*/ - Sys_Sleep(sleeptime); + if (sleeptime) + Sys_Sleep(sleeptime); #else Sys_Error("wut?"); #endif @@ -2573,10 +2726,12 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin } } #ifdef CATCHCRASH +#ifdef _MSC_VER __except (CrashExceptionHandler(false, GetExceptionCode(), GetExceptionInformation())) { return 1; } +#endif #endif /* return success of application */ diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 135bd6cae..5ee15c725 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -84,7 +84,6 @@ static char OpenEditorFile[256]; qboolean editoractive; //(export) -keydest_t editor_oldkeydest = key_game; qboolean editormodal; //doesn't return. (export) static qboolean madechanges; static qboolean editenabled; @@ -189,10 +188,7 @@ static void CloseEditor(void) { fileblock_t *b; - if (key_dest == key_editor) - key_dest = editor_oldkeydest; - if (key_dest == key_editor) - key_dest = key_game; + Key_Dest_Remove(kdm_editor); editoractive = false; editprogfuncs = NULL; cursorblock = NULL; @@ -213,7 +209,7 @@ static void CloseEditor(void) firstblock = NULL; - executionlinenum = -1; + executionlinenum = 0; } static qboolean EditorSaveFile(char *s) //returns true if succesful @@ -257,7 +253,7 @@ static qboolean EditorSaveFile(char *s) //returns true if succesful madechanges = false; editenabled = true; - executionlinenum = -1; + executionlinenum = 0; return true; } @@ -284,10 +280,9 @@ static void EditorNewFile(void) viewportystartblock = NULL; madechanges = true; - executionlinenum = -1; + executionlinenum = 0; - editor_oldkeydest = key_dest; - key_dest = key_editor; + Key_Dest_Add(kdm_editor); editoractive = true; editenabled = true; } @@ -312,7 +307,7 @@ static void EditorOpenFile(char *name, qboolean readonly) { Con_Printf("Couldn't open file \"%s\"\nA new file will be created\n", name); strcpy(OpenEditorFile, name); - key_dest = key_console; + Key_Dest_Add(kdm_console); EditorNewFile(); return; } @@ -393,11 +388,10 @@ static void EditorOpenFile(char *name, qboolean readonly) viewportystartblock = NULL; madechanges = false; - executionlinenum = -1; + executionlinenum = 0; editenabled = !readonly; - editor_oldkeydest = key_dest; - key_dest = key_editor; + Key_Dest_Add(kdm_editor); editoractive = true; editprogfuncs = epf; } @@ -410,7 +404,7 @@ void Editor_Key(int key, int unicode) if (keybindings[key][0]) if (!strcmp(keybindings[key][0], "toggleconsole")) { - key_dest = key_console; + Key_Dest_Add(kdm_console); return; } @@ -515,6 +509,8 @@ void Editor_Key(int key, int unicode) case K_MWHEELUP: case K_UPARROW: case K_PGUP: + if (!cursorblock) + break; GetCursorpos(); { int a; @@ -686,9 +682,15 @@ void Editor_Key(int key, int unicode) break; // case K_STOP: case K_ESCAPE: - if (editprogfuncs) + if (editprogfuncs && editormodal) + { editprogfuncs->AbortStack(editprogfuncs); - CloseEditor(); + CloseEditor(); + executionlinenum = 0; + stepasm = true; + } + else + CloseEditor(); editormodal = false; break; @@ -1092,16 +1094,6 @@ void Editor_Draw(void) int c; fileblock_t *b; - if (key_dest != key_console) - { - if (editor_oldkeydest == key_menu && !editormodal) - { - CloseEditor(); - return; - } - key_dest = key_editor; - } - if ((editoractive && cls.state == ca_disconnected) || editormodal) R2D_EditorBackground(); @@ -1301,7 +1293,6 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, if (!parms) { - int oldkeydest = key_dest; double oldrealtime = realtime; editormodal = true; @@ -1319,8 +1310,6 @@ int QCLibEditor(pubprogfuncs_t *prfncs, char *filename, int line, int statement, } realtime = oldrealtime; - if (oldkeydest != key_console) - key_dest = oldkeydest; editormodal = false; } diff --git a/engine/client/valid.c b/engine/client/valid.c index aae7e7b69..fd62aaa5b 100644 --- a/engine/client/valid.c +++ b/engine/client/valid.c @@ -72,31 +72,21 @@ static void Validation_Version(void) extern cvar_t r_shadow_realtime_world, r_drawflat; - switch(qrenderer) - { -#ifdef GLQUAKE - case QR_OPENGL: - s = sr; - //print certain allowed 'cheat' options. - //realtime lighting (shadows can show around corners) - //drawflat is just lame - //24bits can be considered eeeevil, by some. - if (r_shadow_realtime_world.ival) - *s++ = 'W'; - else if (r_shadow_realtime_dlight.ival) - *s++ = 'S'; - if (r_drawflat.ival) - *s++ = 'F'; - if (gl_load24bit.ival) - *s++ = 'H'; - - *s = *""; - break; + s = sr; + //print certain allowed 'cheat' options. + //realtime lighting (shadows can show around corners) + //drawflat is just lame + //24bits can be considered eeeevil, by some. +#ifdef RTLIGHTS + if (r_shadow_realtime_world.ival) + *s++ = 'W'; + else if (r_shadow_realtime_dlight.ival) + *s++ = 'S'; #endif - default: - *sr = *""; - break; - } + if (r_drawflat.ival) + *s++ = 'F'; + if (gl_load24bit.ival) + *s++ = 'H'; *s = '\0'; diff --git a/engine/client/view.c b/engine/client/view.c index 717fef474..fd558916c 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -806,6 +806,7 @@ void V_CalcGunPositionAngle (playerview_t *pv, float bob) float yaw, pitch, move; static float oldyaw = 0; static float oldpitch = 0; + vec3_t vw_angles; int i; yaw = r_refdef.viewangles[YAW]; @@ -847,37 +848,36 @@ void V_CalcGunPositionAngle (playerview_t *pv, float bob) oldyaw = yaw; oldpitch = pitch; - pv->viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; - pv->viewent.angles[PITCH] = r_refdef.viewangles[PITCH] + pitch; + vw_angles[YAW] = r_refdef.viewangles[YAW] + yaw; + vw_angles[PITCH] = r_refdef.viewangles[PITCH] + pitch; - pv->viewent.angles[YAW] = r_refdef.viewangles[YAW]; - pv->viewent.angles[PITCH] = r_refdef.viewangles[PITCH]; - pv->viewent.angles[ROLL] = r_refdef.viewangles[ROLL]; + vw_angles[YAW] = r_refdef.viewangles[YAW]; + vw_angles[PITCH] = r_refdef.viewangles[PITCH]; + vw_angles[ROLL] = r_refdef.viewangles[ROLL]; - AngleVectors(pv->viewent.angles, pv->viewent.axis[0], pv->viewent.axis[1], pv->viewent.axis[2]); - VectorInverse(pv->viewent.axis[1]); - pv->viewent.angles[PITCH]*=-1; + AngleVectors(vw_angles, pv->vw_axis[0], pv->vw_axis[1], pv->vw_axis[2]); + VectorInverse(pv->vw_axis[1]); - VectorCopy (r_refdef.vieworg, pv->viewent.origin); + VectorCopy (r_refdef.vieworg, pv->vw_origin); for (i=0 ; i<3 ; i++) { - pv->viewent.origin[i] += pv->viewent.axis[0][i]*bob*0.4; -// pv->viewent.origin[i] += pv->viewent.axis[1][i]*sin(cl.time*5.5342452354235)*0.1; -// pv->viewent.origin[i] += pv->viewent.axis[2][i]*bob*0.8; + pv->vw_origin[i] += pv->vw_axis[0][i]*bob*0.4; +// pv->vw_origin[i] += pv->vw_axis[1][i]*sin(cl.time*5.5342452354235)*0.1; +// pv->vw_origin[i] += pv->vw_axis[2][i]*bob*0.8; } // fudge position around to keep amount of weapon visible // roughly equal with different FOV if (scr_viewsize.value == 110) - pv->viewent.origin[2] += 1; + pv->vw_origin[2] += 1; else if (scr_viewsize.value == 100) - pv->viewent.origin[2] += 2; + pv->vw_origin[2] += 2; else if (scr_viewsize.value == 90) - pv->viewent.origin[2] += 1; + pv->vw_origin[2] += 1; else if (scr_viewsize.value == 80) - pv->viewent.origin[2] += 0.5; + pv->vw_origin[2] += 0.5; } /* @@ -939,9 +939,9 @@ void V_AddIdle (playerview_t *pv) r_refdef.viewangles[PITCH] += v_idlescale.value * sin(cl.time*pitch_cycle) * pitch_level; r_refdef.viewangles[YAW] += v_idlescale.value * sin(cl.time*yaw_cycle) * yaw_level; - pv->viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*roll_cycle) * roll_level; - pv->viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*pitch_cycle) * pitch_level; - pv->viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*yaw_cycle) * yaw_level; +// pv->viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*roll_cycle) * roll_level; +// pv->viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*pitch_cycle) * pitch_level; +// pv->viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*yaw_cycle) * yaw_level; } @@ -997,15 +997,10 @@ V_CalcIntermissionRefdef */ void V_CalcIntermissionRefdef (playerview_t *pv) { - entity_t *view; float old; -// view is the weapon model - view = &pv->viewent; - VectorCopy (pv->simorg, r_refdef.vieworg); VectorCopy (pv->simangles, r_refdef.viewangles); - view->model = NULL; // always idle in intermission old = v_idlescale.value; @@ -1211,7 +1206,6 @@ V_CalcRefdef */ void V_CalcRefdef (playerview_t *pv) { - entity_t *view; float bob; float viewheight; r_refdef.playerview = pv; @@ -1224,9 +1218,6 @@ void V_CalcRefdef (playerview_t *pv) VectorCopy(cl.fog_colour, r_refdef.gfog_rgbd); r_refdef.gfog_rgbd[3] = cl.fog_density / 64; -// view is the weapon model (only visible from inside body) - view = &pv->viewent; - if (v_viewheight.value < -7) bob=-7; else if (v_viewheight.value > 4) @@ -1280,15 +1271,6 @@ void V_CalcRefdef (playerview_t *pv) // set up gun position V_CalcGunPositionAngle (pv, bob); - if (pv->statsf[STAT_HEALTH] <= 0 || (unsigned int)pv->stats[STAT_WEAPON] >= MAX_MODELS) - view->model = NULL; - else - view->model = cl.model_precache[pv->stats[STAT_WEAPON]]; -#ifdef HLCLIENT - if (!CLHL_AnimateViewEntity(view)) -#endif - view->framestate.g[FS_REG].frame[0] = pv->stats[STAT_WEAPONFRAME]; - // set up the refresh position if (v_gunkick.value) r_refdef.viewangles[PITCH] += pv->punchangle*v_gunkick.value; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 42509c553..c40fe5c77 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -237,7 +237,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define R_XFLIP //allow view to be flipped horizontally #define TEXTEDITOR #define DDS //a sort of image file format. +#ifndef RTLIGHTS #define RTLIGHTS //realtime lighting +#endif #define VM_Q1 //q1 qvm gamecode interface diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index 29b037ef7..d9adbf965 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -220,7 +220,12 @@ typedef struct unsigned int v[2]; // vertex numbers } dledge_t; -#define MAXLIGHTMAPS 4 +#ifdef Q3BSPS +#define MAXRLIGHTMAPS 4 //max lightmaps mixed by the renderer (rbsp=4, otherwise 1) +#else +#define MAXRLIGHTMAPS 1 //max lightmaps mixed by the renderer (rbsp=4, otherwise 1) +#endif +#define MAXQ1LIGHTMAPS 4 typedef struct { short planenum; @@ -231,7 +236,7 @@ typedef struct short texinfo; // lighting info - qbyte styles[MAXLIGHTMAPS]; + qbyte styles[MAXQ1LIGHTMAPS]; int lightofs; // start of [numstyles*surfsize] samples } dsface_t; typedef struct @@ -244,7 +249,7 @@ typedef struct int texinfo; // lighting info - qbyte styles[MAXLIGHTMAPS]; + qbyte styles[MAXQ1LIGHTMAPS]; int lightofs; // start of [numstyles*surfsize] samples } dlface_t; diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 70ee7d4d6..11ec02620 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -1668,7 +1668,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in } - if (r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival || qrenderer != QR_OPENGL) + if (Sh_StencilShadowsActive() || qrenderer != QR_OPENGL) { mesh->xyz2_array = NULL; mesh->xyz_blendw[0] = 1; @@ -1898,7 +1898,6 @@ static void Mod_ClampModelSize(model_t *mod) #endif } -#ifdef GLQUAKE static int R_FindTriangleWithEdge (index_t *indexes, int numtris, int start, int end, int ignore) { int i; @@ -1940,20 +1939,15 @@ static void Mod_BuildTriangleNeighbours ( int *neighbours, index_t *indexes, int n[2] = R_FindTriangleWithEdge (indexes, numtris, index[0], index[2], i); } } -#endif void Mod_CompileTriangleNeighbours(galiasinfo_t *galias) { -#ifdef GLQUAKE - if (qrenderer != QR_OPENGL) - return; - if (r_shadow_realtime_dlight_shadows.ival || r_shadow_realtime_world_shadows.ival) + if (Sh_StencilShadowsActive()) { int *neighbours; neighbours = ZG_Malloc(&loadmodel->memgroup, sizeof(int)*galias->numindexes/3*3); galias->ofs_trineighbours = neighbours; Mod_BuildTriangleNeighbours(neighbours, galias->ofs_indexes, galias->numindexes/3); } -#endif } typedef struct diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index 052981134..0a950e2b2 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -1177,7 +1177,7 @@ void World_ODE_Init(void) const char* dllname = { # if defined(WIN64) - "libode1_64" + "libode1" # elif defined(WIN32) "ode_double" # elif defined(MACOSX) diff --git a/engine/common/common.c b/engine/common/common.c index 97d4a48b5..04b624851 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -2724,6 +2724,15 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t } else if (str[1] == '[' && !linkstart) { + if (keepmarkup) + { + if (!--outsize) + break; + *out++ = '^' | CON_HIDDEN; + } + if (!--outsize) + break; + //preserved flags and reset to white. links must contain their own colours. linkinitflags = ext; ext = COLOR_RED << CON_FGSHIFT; @@ -2738,6 +2747,15 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t } else if (str[1] == ']' && linkstart) { + if (keepmarkup) + { + if (!--outsize) + break; + *out++ = '^' | CON_HIDDEN; + } + + if (!--outsize) + break; *out++ = ']'; //its a valid link, so we can hide it all now @@ -2987,6 +3005,43 @@ messedup: return out; } +//remaps conchar_t character values to something valid in unicode, such that it is likely to be printable with standard char sets. +//unicode-to-ascii is not provided. you're expected to utf-8 the result or something. +//does not handle colour codes or hidden chars. add your own escape sequences if you need that. +//does not guarentee removal of control codes if eg the code was specified as an explicit unicode char. +unsigned int COM_DeQuake(conchar_t chr) +{ + chr &= CON_CHARMASK; + + /*only this range are quake chars*/ + if (chr >= 0xe000 && chr < 0xe100) + { + chr &= 0xff; + if (chr >= 146 && chr < 156) + chr = chr - 146 + '0'; + if (chr >= 0x12 && chr <= 0x1b) + chr = chr - 0x12 + '0'; + if (chr == 143) + chr = '.'; + if (chr == 128 || chr == 129 || chr == 130 || chr == 157 || chr == 158 || chr == 159) + chr = '-'; + if (chr >= 128) + chr -= 128; + if (chr == 16) + chr = '['; + if (chr == 17) + chr = ']'; + if (chr == 0x1c) + chr = 249; + } + /*this range contains pictograms*/ + if (chr >= 0xe100 && chr < 0xe200) + { + chr = '?'; + } + return chr; +} + //============================================================================ #define TOKENSIZE sizeof(com_token) diff --git a/engine/common/common.h b/engine/common/common.h index adb31145f..cd1072579 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -301,6 +301,7 @@ unsigned int utf8_decode(int *error, const void *in, char **out); unsigned int utf8_encode(void *out, unsigned int unicode, int maxlen); unsigned int iso88591_encode(char *out, unsigned int unicode, int maxlen); unsigned int qchar_encode(char *out, unsigned int unicode, int maxlen); +unsigned int COM_DeQuake(conchar_t chr); //handles whatever charset is active, including ^U stuff. unsigned int unicode_byteofsfromcharofs(char *str, unsigned int charofs); diff --git a/engine/common/fs.c b/engine/common/fs.c index d8b90a368..04362139d 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2111,7 +2111,7 @@ void COM_Gamedir (const char *dir) /*set some stuff so our regular qw client appears more like hexen2*/ #define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset sv_maxspeed 640\nset watervis 1\nset r_wateralpha 0.5\nset sv_pupglow 1\nset cl_model_bobbing 1\nsv_sound_land \"fx/thngland.wav\"\n" /*yay q2!*/ -#define Q2CFG "gl_font \":?col=0.44 1 0.2\"\ncom_nogamedirnativecode 0\n" +#define Q2CFG "com_nogamedirnativecode 0\n" /*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/ #define Q3CFG "gl_overbright 2\nseta model sarge\nseta headmodel sarge\nseta handicap 100\ncom_nogamedirnativecode 0\n" #define RMQCFG "sv_bigcoords 1\n" diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 5ae4530c2..89e932115 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -16,6 +16,14 @@ typedef struct { unsigned int mtime; unsigned char xflags; unsigned char os; + //unsigned short xlen; + //unsigned char xdata[xlen]; + //unsigned char fname[]; + //unsigned char fcomment[]; + //unsigned short fhcrc; + //unsigned char compresseddata[]; + //unsigned int crc32; + //unsigned int isize; } gzheader_t; #define sizeofgzheader_t 10 diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 3e9e17ad9..563934342 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -346,7 +346,7 @@ cvar_t r_subdivisions = SCVAR("r_subdivisions", "2"); int CM_NumInlineModels (model_t *model); cmodel_t *CM_InlineModel (char *name); void CM_InitBoxHull (void); -void FloodAreaConnections (void); +static void FloodAreaConnections (void); static int c_pointcontents; @@ -357,8 +357,8 @@ static vecV_t *map_verts; //3points static int numvertexes; static vec2_t *map_vertstmexcoords; -static vec2_t *map_vertlstmexcoords[MAXLIGHTMAPS]; -static vec4_t *map_colors4f_array[MAXLIGHTMAPS]; +static vec2_t *map_vertlstmexcoords[MAXRLIGHTMAPS]; +static vec4_t *map_colors4f_array[MAXRLIGHTMAPS]; static vec3_t *map_normals_array; static vec3_t *map_svector_array; static vec3_t *map_tvector_array; @@ -1394,7 +1394,7 @@ qboolean CMod_LoadFaces (lump_t *l) // lighting info - for (i=0 ; istyles[i] = in->styles[i]; i = LittleLong(in->lightofs); if (i == -1) @@ -2085,7 +2085,7 @@ qboolean CModQ3_LoadVertexes (lump_t *l) tout = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*nout)); map_verts = out; map_vertstmexcoords = stout; - for (i = 0; i < MAXLIGHTMAPS; i++) + for (i = 0; i < MAXRLIGHTMAPS; i++) { map_vertlstmexcoords[i] = lmout; map_colors4f_array[i] = cout; @@ -2142,14 +2142,14 @@ qboolean CModRBSP_LoadVertexes (lump_t *l) out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); stout = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*stout)); - lmout = ZG_Malloc(&loadmodel->memgroup, MAXLIGHTMAPS*count*sizeof(*lmout)); - cout = ZG_Malloc(&loadmodel->memgroup, MAXLIGHTMAPS*count*sizeof(*cout)); + lmout = ZG_Malloc(&loadmodel->memgroup, MAXRLIGHTMAPS*count*sizeof(*lmout)); + cout = ZG_Malloc(&loadmodel->memgroup, MAXRLIGHTMAPS*count*sizeof(*cout)); nout = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*nout)); sout = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*sout)); tout = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*tout)); map_verts = out; map_vertstmexcoords = stout; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { map_vertlstmexcoords[sty] = lmout + sty*count; map_colors4f_array[sty] = cout + sty*count; @@ -2169,10 +2169,10 @@ qboolean CModRBSP_LoadVertexes (lump_t *l) for ( j=0 ; j < 2 ; j++) { stout[i][j] = LittleFloat ( ((float *)in->texcoords)[j] ); - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) map_vertlstmexcoords[sty][i][j] = LittleFloat ( ((float *)in->texcoords)[j+2*(sty+1)] ); } - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { for ( j=0 ; j < 4 ; j++) { @@ -2477,14 +2477,14 @@ void GL_CreateMeshForPatch (model_t *mod, mesh_t *mesh, int patchwidth, int patc // fill in Patch_Evaluate ( map_verts[firstvert], patch_cp, step, mesh->xyz_array[0], sizeof(vecV_t)/sizeof(vec_t)); - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { if (mesh->colors4f_array[sty]) Patch_Evaluate ( map_colors4f_array[sty][firstvert], patch_cp, step, mesh->colors4f_array[sty][0], 4 ); } Patch_Evaluate ( map_normals_array[firstvert], patch_cp, step, mesh->normals_array[0], 3 ); Patch_Evaluate ( map_vertstmexcoords[firstvert], patch_cp, step, mesh->st_array[0], 2 ); - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { if (mesh->lmst_array[sty]) Patch_Evaluate ( map_vertlstmexcoords[sty][firstvert], patch_cp, step, mesh->lmst_array[sty][0], 2 ); @@ -2548,7 +2548,7 @@ void CModRBSP_BuildSurfMesh(model_t *mod, msurface_t *out, void *cookie) { VectorCopy(map_verts[fv + i], out->mesh->xyz_array[i]); Vector2Copy(map_vertstmexcoords[fv + i], out->mesh->st_array[i]); - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { Vector2Copy(map_vertlstmexcoords[sty][fv + i], out->mesh->lmst_array[sty][i]); Vector4Copy(map_colors4f_array[sty][fv + i], out->mesh->colors4f_array[sty][i]); @@ -2708,7 +2708,7 @@ qboolean CModQ3_LoadRFaces (lump_t *l) out->light_s[0] = LittleLong(in->lightmap_x); out->light_t[0] = LittleLong(in->lightmap_y); out->styles[0] = 255; - for (sty = 1; sty < MAXLIGHTMAPS; sty++) + for (sty = 1; sty < MAXRLIGHTMAPS; sty++) { out->styles[sty] = 255; out->lightmaptexturenums[sty] = -1; @@ -2821,7 +2821,7 @@ qboolean CModRBSP_LoadRFaces (lump_t *l) out->plane = pl; out->texinfo = loadmodel->texinfo + LittleLong(in->shadernum); in->facetype = LittleLong(in->facetype); - for (j = 0; j < 4 && j < MAXLIGHTMAPS; j++) + for (j = 0; j < 4 && j < MAXRLIGHTMAPS; j++) { out->lightmaptexturenums[j] = LittleLong(in->lightmapnum[j]); out->light_s[j] = LittleLong(in->lightmap_offs[0][j]); @@ -3358,6 +3358,9 @@ void CModQ3_LoadLighting (lump_t *l) gl_overbright.flags |= CVAR_LATCH; BuildLightMapGammaTable(1, (1<<(2-gl_overbright.ival))); + if (!samples) + return; + loadmodel->engineflags |= MDLF_RGBLIGHTING; loadmodel->lightdata = out = ZG_Malloc(&loadmodel->memgroup, samples); @@ -5636,7 +5639,7 @@ qbyte *Mod_ClusterPVS (int cluster, model_t *model) model); } */ -void CM_DecompressVis (qbyte *in, qbyte *out) +static void CM_DecompressVis (qbyte *in, qbyte *out) { int c; qbyte *out_p; @@ -5678,8 +5681,8 @@ void CM_DecompressVis (qbyte *in, qbyte *out) } while (out_p - out < row); } -qbyte pvsrow[MAX_MAP_LEAFS/8]; -qbyte phsrow[MAX_MAP_LEAFS/8]; +static qbyte pvsrow[MAX_MAP_LEAFS/8]; +static qbyte phsrow[MAX_MAP_LEAFS/8]; @@ -5744,7 +5747,7 @@ AREAPORTALS =============================================================================== */ -void FloodArea_r (q2carea_t *area, int floodnum) +static void FloodArea_r (q2carea_t *area, int floodnum) { int i; q2dareaportal_t *p; @@ -5773,7 +5776,7 @@ FloodAreaConnections ==================== */ -void FloodAreaConnections (void) +static void FloodAreaConnections (void) { int i, j; q2carea_t *area; diff --git a/engine/common/log.c b/engine/common/log.c index d60511517..d866bdbac 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -13,52 +13,21 @@ cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER), cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback), CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback)}; cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback); -cvar_t log_readable = CVARF("log_readable", "0", CVAR_NOTFROMSERVER); +cvar_t log_readable = CVARFD("log_readable", "7", CVAR_NOTFROMSERVER, "Bitfield describing what to convert/strip. If 0, exact byte representation will be used.\n&1: Dequakify text.\n&2: Strip special markup.\n&4: Strip ansi control codes."); cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER); cvar_t log_rotate_files = CVARF("log_rotate_files", "0", CVAR_NOTFROMSERVER); cvar_t log_rotate_size = CVARF("log_rotate_size", "131072", CVAR_NOTFROMSERVER); +cvar_t log_timestamps = CVARF("log_timestamps", "1", CVAR_NOTFROMSERVER); +#ifdef _WIN32 +cvar_t log_dosformat = CVARF("log_dosformat", "1", CVAR_NOTFROMSERVER); +#else cvar_t log_dosformat = CVARF("log_dosformat", "0", CVAR_NOTFROMSERVER); +#endif +qboolean log_newline[LOG_TYPES]; // externals extern char gamedirfile[]; -// table of readable characters, same as ezquake -char readable[256] = -{ - '.', '_', '_', '_', '_', '.', '_', '_', - '_', '_', '\n', '_', '\n', '>', '.', '.', - '[', ']', '0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', '.', '_', '_', '_', - ' ', '!', '\"', '#', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', ':', ';', '<', '=', '>', '?', - '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', '{', '|', '}', '~', '_', - '_', '_', '_', '_', '_', '.', '_', '_', - '_', '_', '_', '_', '_', '>', '.', '.', - '[', ']', '0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', '.', '_', '_', '_', - ' ', '!', '\"', '#', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', ':', ';', '<', '=', '>', '?', - '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', '{', '|', '}', '~', '_' -}; - // Log_Dir_Callback: called when a log_dir is changed void Log_Dir_Callback (struct cvar_s *var, char *oldvalue) { @@ -94,17 +63,20 @@ void Log_String (logtype_t lognum, char *s) char *d; // directory char *f; // filename char *t; - char logbuf[1024]; + char utf8[2048]; int i; char fname[MAX_QPATH]; + conchar_t cline[2048], *c; + unsigned int u; if (!log_enable[lognum].value) return; // get directory/filename - d = gamedirfile; if (log_dir.string[0]) d = log_dir.string; + else + d = "";//gamedirfile; f = NULL; switch(lognum) @@ -124,63 +96,44 @@ void Log_String (logtype_t lognum, char *s) if (!f) return; - // readable translation and Q3 code removal, use t for final string to write - t = logbuf; - // max debuglog buf is 1024 - for (i = 0; i < 1023; i++, s++) + COM_ParseFunString(CON_WHITEMASK, s, cline, sizeof(cline), !(log_readable.ival & 2)); + t = utf8; + for (c = cline; *c; c++) { - if (*s == 0) - break; - else if (((int)(log_readable.value) & 2) && *s == '^') - { - // log_readable 2 removes Q3 codes as well - char c = s[1]; - - if ((c >= '0' && c <= '9') || c == 'a' || c == 'b' || c == 'h' || c == 's' || c == 'r') - { - i--; - s++; - } - else if (c == '&') - { - if (isextendedcode(s[2]) && isextendedcode(s[3])) - { - i--; - s += 3; - } - } - else - { - *t = '^'; - t++; - } - } - else if (log_dosformat.value && *s == '\n') - { - // convert \n to \r\n - *t = '\r'; - t++; - i++; - if (i < 1023) - { - *t = '\n'; - t++; - } - } + if ((*c & CON_HIDDEN) && (log_readable.ival & 2)) + continue; + if (log_readable.ival&1) + u = COM_DeQuake(*c); else - { - // use readable table to convert quake chars to reabable text - if ((int)(log_readable.value) & 1) - *t = readable[(unsigned char)(*s)]; // translate - else - *t = *s; // copy - t++; - } - } + u = *c&CON_CHARMASK; + //at the start of a new line, we might want a timestamp (so timestamps are correct for the first char of the line, instead of the preceeding \n) + if (log_newline[lognum]) + { + if (log_timestamps.ival) + { + time_t unixtime = time(NULL); + strftime(t, utf8+sizeof(utf8)-1-t, "%Y-%m-%d %H:%M:%S ", localtime(&unixtime)); + t += strlen(t); + } + log_newline[lognum] = false; + } + + //make sure control codes are stripped. no exploiting xterm bugs please. + if ((log_readable.ival & 4) && ((u < 32 && u != '\t' && u != '\n') || u == 127 || (u >= 128 && u < 128+32))) //\r is stripped too + u = '?'; + //if dos format logs, we insert a \r before every \n (also flag next char as the start of a new line) + if (u == '\n') + { + log_newline[lognum] = true; + if (log_dosformat.ival) + t += utf8_encode(t, '\r', utf8+sizeof(utf8)-1-t); + } + t += utf8_encode(t, u, utf8+sizeof(utf8)-1-t); + } *t = 0; - Q_snprintfz(fname, sizeof(fname), "%s/%s.log",d,f); + Q_snprintfz(fname, sizeof(fname), "%s%s.log", d, f); // file rotation if (log_rotate_size.value >= 4096 && log_rotate_files.value >= 1) @@ -189,11 +142,11 @@ void Log_String (logtype_t lognum, char *s) vfsfile_t *fi; // check file size, use x as temp - if ((fi = FS_OpenVFS(fname, "rb", FS_ROOT))) + if ((fi = FS_OpenVFS(fname, "rb", FS_GAMEONLY))) { x = VFS_GETLEN(fi); VFS_CLOSE(fi); - x += i; // add string size to file size to never go over + x += strlen(utf8); // add string size to file size to never go over } else x = 0; @@ -206,22 +159,22 @@ void Log_String (logtype_t lognum, char *s) i = log_rotate_files.value; // unlink file at the top of the chain - snprintf(oldf, sizeof(oldf)-1, "%s.%i", f, i); - FS_Remove(oldf, FS_ROOT); + snprintf(oldf, sizeof(oldf)-1, "%s%s.%i", d, f, i); + FS_Remove(oldf, FS_GAMEONLY); // rename files through chain for (x = i-1; x > 0; x--) { strcpy(newf, oldf); - snprintf(oldf, sizeof(oldf)-1, "%s.%i", f, x); + snprintf(oldf, sizeof(oldf)-1, "%s%s.%i", d, f, x); // check if file exists, otherwise skip - if ((fi = FS_OpenVFS(oldf, "rb", FS_ROOT))) + if ((fi = FS_OpenVFS(oldf, "rb", FS_GAMEONLY))) VFS_CLOSE(fi); else continue; // skip nonexistant files - if (!FS_Rename(oldf, newf, FS_ROOT)) + if (!FS_Rename(oldf, newf, FS_GAMEONLY)) { // rename failed, disable log and bug out Cvar_ForceSet(&log_enable[lognum], "0"); @@ -231,8 +184,8 @@ void Log_String (logtype_t lognum, char *s) } // TODO: option to compress file somewhere in here? - // rename our base file, which better exist... - if (!FS_Rename(f, oldf, FS_ROOT)) + // rename our base file, which had better exist... + if (!FS_Rename(fname, oldf, FS_GAMEONLY)) { // rename failed, disable log and bug out Cvar_ForceSet(&log_enable[lognum], "0"); @@ -242,10 +195,10 @@ void Log_String (logtype_t lognum, char *s) } } - FS_CreatePath(f, FS_ROOT); - if ((fi = FS_OpenVFS(f, "ab", FS_ROOT))) + FS_CreatePath(fname, FS_GAMEONLY); + if ((fi = FS_OpenVFS(fname, "ab", FS_GAMEONLY))) { - VFS_WRITE(fi, logbuf, strlen(logbuf)); + VFS_WRITE(fi, utf8, strlen(utf8)); VFS_CLOSE(fi); } else @@ -278,10 +231,10 @@ void SV_LogPlayer(client_t *cl, char *msg) return; //don't log botclients snprintf(line, sizeof(line), - "%s\\%s\\%i\\%s\\%s\\%i%s\n", + "%s\\%s\\%i\\%s\\%s\\%i\\guid\\%s%s\n", msg, cl->name, cl->userid, NET_BaseAdrToString(remote_adr, sizeof(remote_adr), &cl->netchan.remote_address), (cl->realip_status > 0 ? NET_BaseAdrToString(realip_adr, sizeof(realip_adr), &cl->realip) : "??"), - cl->netchan.remote_address.port, cl->userinfo); + cl->netchan.remote_address.port, cl->guid, cl->userinfo); Log_String(LOG_PLAYER, line); } @@ -365,6 +318,7 @@ void Log_Init(void) { Cvar_Register (&log_enable[i], CONLOGGROUP); Cvar_Register (&log_name[i], CONLOGGROUP); + log_newline[i] = true; } Cvar_Register (&log_dir, CONLOGGROUP); Cvar_Register (&log_readable, CONLOGGROUP); @@ -372,6 +326,7 @@ void Log_Init(void) Cvar_Register (&log_rotate_size, CONLOGGROUP); Cvar_Register (&log_rotate_files, CONLOGGROUP); Cvar_Register (&log_dosformat, CONLOGGROUP); + Cvar_Register (&log_timestamps, CONLOGGROUP); Cmd_AddCommand("logfile", Log_Logfile_f); diff --git a/engine/common/particles.h b/engine/common/particles.h index b64c5e6b9..bf306582f 100644 --- a/engine/common/particles.h +++ b/engine/common/particles.h @@ -77,7 +77,7 @@ typedef struct trailstate_s { #define PARTICLE_Z_CLIP 8.0 -typedef enum { BM_BLEND, BM_BLENDCOLOUR, BM_ADD, BM_SUBTRACT, BM_INVMOD } blendmode_t; +typedef enum { BM_BLEND, BM_BLENDCOLOUR, BM_ADD, BM_SUBTRACT, BM_INVMODA, BM_INVMODC } blendmode_t; #define frandom() (rand()*(1.0f/RAND_MAX)) #define crandom() (rand()*(2.0f/RAND_MAX)-1.0f) diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index bb2208f25..8c6d8b9d3 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -2063,10 +2063,9 @@ void QCBUILTIN PF_strpad (pubprogfuncs_t *prinst, struct globalvars_s *pr_global pad = 0; Q_strncpyz(dest+pad, src, MAXTEMPBUFFERLEN-pad); - while(pad--) + while(pad) { - pad--; - dest[pad] = ' '; + dest[--pad] = ' '; } } else @@ -3295,9 +3294,14 @@ void QCBUILTIN PF_uri_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob { #ifdef WEBCLIENT world_t *w = prinst->parms->user; + struct dl_download *dl; + unsigned char *url = PR_GetStringOfs(prinst, OFS_PARM0); float id = G_FLOAT(OFS_PARM1); - struct dl_download *dl; + char *mimetype = (prinst->callargc >= 3)?PR_GetStringOfs(prinst, OFS_PARM2):""; + char *dataorsep = PR_GetStringOfs(prinst, OFS_PARM3); + int strbufid = G_FLOAT(OFS_PARM4); + //float cryptokey = G_FLOAT(OFS_PARM5); //DP feature, not supported in FTE. if (!pr_enable_uriget.ival) { @@ -3305,9 +3309,29 @@ void QCBUILTIN PF_uri_get (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob G_FLOAT(OFS_RETURN) = 0; return; } - Con_DPrintf("PF_uri_get(%s,%g)\n", url, id); - dl = HTTP_CL_Get(url, NULL, PR_uri_get_callback); + if (*mimetype) + { + char *data; + Con_DPrintf("PF_uri_post(%s,%g)\n", url, id); + if (strbufid) + { + //convert the string buffer into a simple string using dataorsep as a separator + //not supported at this time + dl = NULL; + } + else + { + //simple data post. + data = dataorsep; + dl = HTTP_CL_Put(url, mimetype, data, strlen(data), PR_uri_get_callback); + } + } + else + { + Con_DPrintf("PF_uri_get(%s,%g)\n", url, id); + dl = HTTP_CL_Get(url, NULL, PR_uri_get_callback); + } if (dl) { dl->user_ctx = w; @@ -3657,6 +3681,18 @@ void QCBUILTIN PF_ceil (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) G_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0)); } +void QCBUILTIN PF_anglemod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float v = G_FLOAT(OFS_PARM0); + + while (v >= 360) + v = v - 360; + while (v < 0) + v = v + 360; + + G_FLOAT(OFS_RETURN) = v; +} + //Maths functions //////////////////////////////////////////////////// //Vector functions @@ -4691,6 +4727,7 @@ lh_extension_t QSG_Extensions[] = { {"DP_QC_UNLIMITEDTEMPSTRINGS"}, {"DP_QC_URI_ESCAPE", 2, NULL, {"uri_escape", "uri_unescape"}}, {"DP_QC_URI_GET", 1, NULL, {"uri_get"}}, +//test {"DP_QC_URI_POST", 1, NULL, {"uri_get"}}, {"DP_QC_VECTOANGLES_WITH_ROLL"}, {"DP_QC_VECTORVECTORS", 1, NULL, {"vectorvectors"}}, {"DP_QC_WHICHPACK", 1, NULL, {"whichpack"}}, @@ -4729,7 +4766,8 @@ lh_extension_t QSG_Extensions[] = { {"_DP_TE_QUADEFFECTS1", 4, NULL, {"te_gunshotquad", "te_spikequad", "te_superspikequad", "te_explosionquad"}}, {"DP_TE_SMALLFLASH", 1, NULL, {"te_smallflash"}}, {"DP_TE_SPARK", 1, NULL, {"te_spark"}}, - {"DP_TE_STANDARDEFFECTBUILTINS", 14, NULL, {"te_gunshot", "te_spike", "te_superspike", "te_explosion", "te_tarexplosion", "te_wizspike", "te_knightspike", "te_lavasplash", "te_teleport", "te_explosion2", "te_lightning1", "te_lightning2", "te_lightning3", "te_beam"}}, + {"DP_TE_STANDARDEFFECTBUILTINS", 14, NULL, { "te_gunshot", "te_spike", "te_superspike", "te_explosion", "te_tarexplosion", "te_wizspike", "te_knightspike", + "te_lavasplash", "te_teleport", "te_explosion2", "te_lightning1", "te_lightning2", "te_lightning3", "te_beam"}}, {"DP_VIEWZOOM"}, {"EXT_BITSHIFT", 1, NULL, {"bitshift"}}, {"EXT_DIMENSION_VISIBILITY"}, @@ -4743,6 +4781,9 @@ lh_extension_t QSG_Extensions[] = { {"FTE_CSQC_SERVERBROWSER", 12, NULL, { "gethostcachevalue", "gethostcachestring", "resethostcachemasks", "sethostcachemaskstring", "sethostcachemasknumber", "resorthostcache", "sethostcachesort", "refreshhostcache", "gethostcachenumber", "gethostcacheindexforkey", "addwantedhostcachekey", "getextresponse"}}, //normally only available to the menu. this also adds them to csqc. + {"FTE_CSQC_SKELETONOBJECTS", 15, NULL, { "skel_create", "skel_build", "skel_get_numbones", "skel_get_bonename", "skel_get_boneparent", "skel_find_bone", + "skel_get_bonerel", "skel_get_boneabs", "skel_set_bone", "skel_mul_bone", "skel_mul_bones", "skel_copybones", + "skel_delete", "frameforname", "frameduration"}}, {"FTE_ENT_SKIN_CONTENTS"}, //self.skin = CONTENTS_WATER; makes a brush entity into water. use -16 for a ladder. {"FTE_ENT_UNIQUESPAWNID"}, {"FTE_EXTENDEDTEXTCODES"}, @@ -4767,9 +4808,10 @@ lh_extension_t QSG_Extensions[] = { {"FTE_QC_CHECKCOMMAND", 1, NULL, {"checkcommand"}}, {"FTE_QC_CHECKPVS", 1, NULL, {"checkpvs"}}, {"FTE_QC_HASHTABLES", 6, NULL, {"hash_createtab", "hash_destroytab", "hash_add", "hash_get", "hash_delete", "hash_getkey"}}, + {"FTE_QC_INTCONV", 4, NULL, {"stoi", "itos", "stoh", "htos"}}, {"FTE_QC_MATCHCLIENTNAME", 1, NULL, {"matchclientname"}}, {"FTE_QC_PAUSED"}, - {"FTE_QC_INTCONV", 4, NULL, {"stoi", "itos", "stoh", "htos"}}, + {"FTE_QC_RAGDOLL_WIP", 1, NULL, {"ragupdate", "skel_set_bone_world", "skel_mmap"}}, {"FTE_QC_SENDPACKET", 1, NULL, {"sendpacket"}}, //includes the SV_ParseConnectionlessPacket event. {"FTE_QC_TRACETRIGGER"}, {"FTE_SOLID_LADDER"}, //Allows a simple trigger to remove effects of gravity (solid 20). obsolete. will prolly be removed at some point as it is not networked properly. Use FTE_ENT_SKIN_CONTENTS diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index a6db1d5dd..69a818f5a 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -97,6 +97,7 @@ void QCBUILTIN PF_error (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals void QCBUILTIN PF_rint (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_floor (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_ceil (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_anglemod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_Tokenize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_tokenizebyseparator (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_tokenize_console (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); diff --git a/engine/common/world.h b/engine/common/world.h index 6f10c11e9..18e631b10 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -155,6 +155,7 @@ struct world_s model_t *(*Get_CModel)(struct world_s *w, int modelindex); void (*Get_FrameState)(struct world_s *w, wedict_t *s, framestate_t *fstate); + unsigned int keydestmask; //menu:kdm_menu, csqc:kdm_game, server:0 unsigned int max_edicts; //limiting factor... 1024 fields*4*MAX_EDICTS == a heck of a lot. unsigned int num_edicts; // increases towards MAX_EDICTS /*FTE_DEPRECATED*/ unsigned int edict_size; //still used in copyentity diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 671d8b9bd..626283560 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -1648,7 +1648,7 @@ static void D3D11BE_Cull(unsigned int cullflags) D3D11_RASTERIZER_DESC rasterdesc; ID3D11RasterizerState *newrasterizerstate; - cullflags |= r_refdef.flipcull; + cullflags ^= r_refdef.flipcull; if (shaderstate.curcull != cullflags) { @@ -2685,7 +2685,7 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist) if (!view || VectorCompare(view->origin, view->oldorigin)) { - r_refdef.flipcull ^= true; + r_refdef.flipcull ^= SHADER_CULL_FLIP; R_MirrorMatrix(&plane); } else diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 0394e5094..11d4628e3 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -1984,7 +1984,7 @@ static void BE_RenderMeshProgram(shader_t *s, unsigned int vertcount, unsigned i void D3D9BE_Cull(unsigned int cullflags) { - cullflags |= r_refdef.flipcull; + cullflags ^= r_refdef.flipcull; if (shaderstate.curcull != cullflags) { shaderstate.curcull = cullflags; @@ -2944,7 +2944,7 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist) if (!view || VectorCompare(view->origin, view->oldorigin)) { - r_refdef.flipcull ^= true; + r_refdef.flipcull ^= SHADER_CULL_FLIP; R_MirrorMatrix(&plane); } else diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 602c625af..869f76ebb 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -752,12 +752,6 @@ static void (D3D9_R_NewMap) (void) R_SetSky(cl.skyname); #ifdef RTLIGHTS - if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival) - { - R_LoadRTLights(); - if (rtlights_first == rtlights_max) - R_ImportRTLights(cl.worldmodel->entities); - } Sh_PreGenerateLights(); #endif } diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index d190c2987..3ce5c08e3 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -816,12 +816,6 @@ static void (D3D11_R_NewMap) (void) R_SetSky(cl.skyname); #ifdef RTLIGHTS - if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival) - { - R_LoadRTLights(); - if (rtlights_first == rtlights_max) - R_ImportRTLights(cl.worldmodel->entities); - } Sh_PreGenerateLights(); #endif } diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index d1d0dd55a..441c486c4 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -138,6 +138,7 @@ Global {2866F783-6B44-4655-A38D-D53874037454}.Debug|Win32.Build.0 = Debug|Win32 {2866F783-6B44-4655-A38D-D53874037454}.Debug|x64.ActiveCfg = Release|Win32 {2866F783-6B44-4655-A38D-D53874037454}.GLDebug|Win32.ActiveCfg = Debug|Win32 + {2866F783-6B44-4655-A38D-D53874037454}.GLDebug|Win32.Build.0 = Debug|Win32 {2866F783-6B44-4655-A38D-D53874037454}.GLDebug|x64.ActiveCfg = Debug|Win32 {2866F783-6B44-4655-A38D-D53874037454}.GLRelease|Win32.ActiveCfg = Release|Win32 {2866F783-6B44-4655-A38D-D53874037454}.GLRelease|Win32.Build.0 = Release|Win32 @@ -507,7 +508,6 @@ Global {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|x64.Build.0 = Debug Dedicated Server|x64 {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|Win32.ActiveCfg = Debug Dedicated Server|x64 {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|x64.ActiveCfg = Debug Dedicated Server|x64 - {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|x64.Build.0 = Debug Dedicated Server|x64 {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|Win32.ActiveCfg = Debug Dedicated Server|x64 {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|x64.ActiveCfg = Debug Dedicated Server|x64 {482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|x64.Build.0 = Debug Dedicated Server|x64 diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 4682c1009..2f6463a15 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -661,7 +661,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="../libs/speex,..\client,../libs/freetype2/include,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include" - PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;MULTITHREAD;BOTLIB_STATIC;USE_MSVCRT_DEBUG" + PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;MULTITHREAD;BOTLIB_STATIC;USE_MSVCRT_DEBUG;RTLIGHTS" BasicRuntimeChecks="3" RuntimeLibrary="1" EnableFunctionLevelLinking="true" @@ -16914,6 +16914,662 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17570,6 +18226,170 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -19702,6 +20522,170 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flags & Q2RF_WEAPONMODEL) return; + clmodel = e->model; /*switch model if we're the player model, and the player skin says a new model*/ { extern int cl_playerindex; if (e->playerindex >= 0 && e->model == cl.model_precache[cl_playerindex]) { clmodel = cl.players[e->playerindex].model; - if (clmodel && clmodel->type == mod_alias) - e->model = clmodel; + if (!clmodel || clmodel->type != mod_alias) + clmodel = e->model; //oops, never mind } } - clmodel = e->model; - if (!(e->flags & Q2RF_WEAPONMODEL) && !e->framestate.bonestate) { if (R_CullEntityBox (e, clmodel->mins, clmodel->maxs)) @@ -1529,13 +1528,6 @@ void GL_GenerateNormals(float *orgs, float *normals, int *indicies, int numtris, -qboolean BE_ShouldDraw(entity_t *e) -{ - if (!r_refdef.externalview && (e->flags & Q2RF_EXTERNALMODEL)) - return false; - return true; -} - #ifdef Q3CLIENT //q3 lightning gun static void R_DB_LightningBeam(batch_t *batch) @@ -1705,12 +1697,12 @@ static void R_DB_Sprite(batch_t *batch) if (e->flags & Q2RF_WEAPONMODEL && r_refdef.playerview->viewentity > 0) { - sprorigin[0] = r_refdef.playerview->viewent.origin[0]; - sprorigin[1] = r_refdef.playerview->viewent.origin[1]; - sprorigin[2] = r_refdef.playerview->viewent.origin[2]; - VectorMA(sprorigin, e->origin[0], r_refdef.playerview->viewent.axis[0], sprorigin); - VectorMA(sprorigin, e->origin[1], r_refdef.playerview->viewent.axis[1], sprorigin); - VectorMA(sprorigin, e->origin[2], r_refdef.playerview->viewent.axis[2], sprorigin); + sprorigin[0] = r_refdef.playerview->vw_origin[0]; + sprorigin[1] = r_refdef.playerview->vw_origin[1]; + sprorigin[2] = r_refdef.playerview->vw_origin[2]; + VectorMA(sprorigin, e->origin[0], r_refdef.playerview->vw_axis[0], sprorigin); + VectorMA(sprorigin, e->origin[1], r_refdef.playerview->vw_axis[1], sprorigin); + VectorMA(sprorigin, e->origin[2], r_refdef.playerview->vw_axis[2], sprorigin); VectorMA(sprorigin, 12, vpn, sprorigin); batch->flags |= BEF_FORCENODEPTH; @@ -1745,7 +1737,7 @@ static void R_DB_Sprite(batch_t *batch) { vec3_t ea[3]; AngleVectors (e->angles, ea[0], ea[1], ea[2]); - Matrix3_Multiply(ea, r_refdef.playerview->viewent.axis, spraxis); + Matrix3_Multiply(ea, r_refdef.playerview->vw_axis, spraxis); } else AngleVectors (e->angles, spraxis[0], spraxis[1], spraxis[2]); @@ -1963,7 +1955,7 @@ void BE_GenPolyBatches(batch_t **batches) } void R_HalfLife_GenerateBatches(entity_t *e, batch_t **batches); -void BE_GenModelBatches(batch_t **batches) +void BE_GenModelBatches(batch_t **batches, const dlight_t *dl, unsigned int bemode) { int i; entity_t *ent; @@ -1982,20 +1974,35 @@ void BE_GenModelBatches(batch_t **batches) if (!r_drawentities.ival) return; + if (bemode == BEM_STANDARD) + { #ifndef CLIENTONLY - SV_AddDebugPolygons(); + SV_AddDebugPolygons(); #endif - Alias_FlushCache(); + //the alias cache is a backend thing that provides support for multiple entities using the same skeleton. + //thus it needs to be cleared so that it won't reuse the cache over multiple frames. + Alias_FlushCache(); + } // draw sprites seperately, because of alpha blending for (i=0 ; iflags & Q2RF_EXTERNALMODEL)) continue; + if (bemode == BEM_STENCIL || bemode == BEM_DEPTHONLY) + { + if (ent->flags & (RF_NOSHADOW | Q2RF_ADDITIVE | RF_NODEPTHTEST | Q2RF_TRANSLUCENT)) //noshadow often isn't enough for legacy content. + continue; + if (ent->keynum == dl->key && ent->keynum) //shadows are not cast from the entity that owns the light. it is expected to be inside. + continue; + if (ent->model && ent->model->engineflags & MDLF_FLAME) + continue; + } + switch(ent->rtype) { case RT_MODEL: diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index cc0c1e252..4e4c05380 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -57,16 +57,6 @@ static const char LIGHTPASS_SHADER[] = "\ }\n\ }"; - -enum -{ - LSHADER_STANDARD, - LSHADER_CUBE, - LSHADER_SMAP, - LSHADER_SPOT, - LSHADER_MODES -}; - extern cvar_t r_glsl_offsetmapping, r_noportals; static void BE_SendPassBlendDepthMask(unsigned int sbits); @@ -86,8 +76,10 @@ struct { const shader_t *crepskyshader; const shader_t *crepopaqueshader; + const shader_t *depthonlyshader; GLhandleARB allblackshader; + int allblack_mvp; qboolean initeddepthnorm; const shader_t *depthnormshader; @@ -178,6 +170,7 @@ struct { const batch_t *curbatch; const texnums_t *curtexnums; const mfog_t *fog; + const dlight_t *curdlight; float curtime; float updatetime; @@ -190,7 +183,9 @@ struct { texid_t lighttexture; texid_t lightcubemap; float lightprojmatrix[16]; /*world space*/ + vec2_t lightshadowmapscale; vec4_t lightshadowmapinfo; + vec4_t lightshadowmapproj; }; int wbatch; @@ -573,6 +568,7 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend break; } break; +#if MAXRLIGHTMAPS > 1 case VATTR_COLOUR2: GL_SelectVBO(shaderstate.sourcevbo->colours[1].gl.vbo); qglVertexAttribPointer(VATTR_COLOUR2, 4, shaderstate.colourarraytype, ((shaderstate.colourarraytype==GL_FLOAT)?GL_FALSE:GL_TRUE), 0, shaderstate.sourcevbo->colours[1].gl.addr); @@ -585,6 +581,7 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend GL_SelectVBO(shaderstate.sourcevbo->colours[3].gl.vbo); qglVertexAttribPointer(VATTR_COLOUR4, 4, shaderstate.colourarraytype, ((shaderstate.colourarraytype==GL_FLOAT)?GL_FALSE:GL_TRUE), 0, shaderstate.sourcevbo->colours[3].gl.addr); break; +#endif case VATTR_TEXCOORD: GL_SelectVBO(shaderstate.sourcevbo->texcoord.gl.vbo); qglVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, shaderstate.sourcevbo->texcoord.gl.addr); @@ -601,6 +598,7 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend qglVertexAttribPointer(VATTR_LMCOORD, 2, GL_FLOAT, GL_FALSE, 0, shaderstate.sourcevbo->lmcoord[0].gl.addr); } break; +#if MAXRLIGHTMAPS > 1 case VATTR_LMCOORD2: GL_SelectVBO(shaderstate.sourcevbo->lmcoord[1].gl.vbo); qglVertexAttribPointer(VATTR_LMCOORD2, 2, GL_FLOAT, GL_FALSE, 0, shaderstate.sourcevbo->lmcoord[1].gl.addr); @@ -613,6 +611,7 @@ static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoend GL_SelectVBO(shaderstate.sourcevbo->lmcoord[3].gl.vbo); qglVertexAttribPointer(VATTR_LMCOORD4, 2, GL_FLOAT, GL_FALSE, 0, shaderstate.sourcevbo->lmcoord[3].gl.addr); break; +#endif case VATTR_NORMALS: if (!shaderstate.sourcevbo->normals.gl.addr) { @@ -786,11 +785,11 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi BE_EnableShaderAttributes(gl_config.nofixedfunc?(1u<0) @@ -1300,7 +1309,7 @@ void GLBE_Init(void) shaderstate.identitylighting = 1; shaderstate.identitylightmap = 1; - for (i = 0; i < MAXLIGHTMAPS; i++) + for (i = 0; i < MAXRLIGHTMAPS; i++) shaderstate.dummybatch.lightmap[i] = -1; #ifdef RTLIGHTS @@ -1324,6 +1333,14 @@ void GLBE_Init(void) shaderstate.fogtexture = r_nulltex; + shaderstate.depthonlyshader = R_RegisterShader("depthonly", SUF_NONE, + "{\n" + "program depthonly\n" + "{\n" + "depthwrite\n" + "}\n" + "}\n" + ); //make sure the world draws correctly r_worldentity.shaderRGBAf[0] = 1; @@ -1647,17 +1664,21 @@ static void colourgen(const shaderpass_t *pass, int cnt, vec4_t *src, vec4_t *ds case RGB_GEN_VERTEX_LIGHTING: if (mesh->colors4f_array[1]) { - float lm[4]; + float lm[MAXRLIGHTMAPS]; lm[0] = d_lightstylevalue[shaderstate.curbatch->vtlightstyle[0]]/256.0f*shaderstate.identitylighting; +#if MAXRLIGHTMAPS > 1 lm[1] = d_lightstylevalue[shaderstate.curbatch->vtlightstyle[1]]/256.0f*shaderstate.identitylighting; lm[2] = d_lightstylevalue[shaderstate.curbatch->vtlightstyle[2]]/256.0f*shaderstate.identitylighting; lm[3] = d_lightstylevalue[shaderstate.curbatch->vtlightstyle[3]]/256.0f*shaderstate.identitylighting; +#endif while((cnt)--) { VectorScale( mesh->colors4f_array[0][cnt], lm[0], dst[cnt]); +#if MAXRLIGHTMAPS > 1 VectorMA(dst[cnt], lm[1], mesh->colors4f_array[1][cnt], dst[cnt]); VectorMA(dst[cnt], lm[2], mesh->colors4f_array[2][cnt], dst[cnt]); VectorMA(dst[cnt], lm[3], mesh->colors4f_array[3][cnt], dst[cnt]); +#endif } break; } @@ -2655,7 +2676,7 @@ static void DrawPass(const shaderpass_t *pass) //second pass should be an ADD //this depends upon rgbgens for light levels, so each pass *must* be pushed to hardware individually - for (j = 1; j < MAXLIGHTMAPS && shaderstate.curbatch->lightmap[j] >= 0; j++) + for (j = 1; j < MAXRLIGHTMAPS && shaderstate.curbatch->lightmap[j] >= 0; j++) { if (j == 1) BE_SetPassBlendMode(tmu, PBM_REPLACE); @@ -2797,16 +2818,17 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, break; case SP_E_VLSCALE: +#if MAXRLIGHTMAPS > 1 if (perm & PERMUTATION_LIGHTSTYLES) { - vec4_t colscale[MAXLIGHTMAPS]; + vec4_t colscale[MAXRLIGHTMAPS]; int j, s; - for (j = 0; j < MAXLIGHTMAPS ; j++) + for (j = 0; j < MAXRLIGHTMAPS ; j++) { s = shaderstate.curbatch->vtlightstyle[j]; if (s == 255) { - for (; j < MAXLIGHTMAPS ; j++) + for (; j < MAXRLIGHTMAPS ; j++) { colscale[j][0] = 0; colscale[j][1] = 0; @@ -2832,17 +2854,19 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, qglUniform4fvARB(ph, j, (GLfloat*)colscale); shaderstate.lastuniform = 0; } +#endif case SP_E_LMSCALE: +#if MAXRLIGHTMAPS > 1 if (perm & PERMUTATION_LIGHTSTYLES) { - vec4_t colscale[MAXLIGHTMAPS]; + vec4_t colscale[MAXRLIGHTMAPS]; int j, s; - for (j = 0; j < MAXLIGHTMAPS ; j++) + for (j = 0; j < MAXRLIGHTMAPS ; j++) { s = shaderstate.curbatch->lmlightstyle[j]; if (s == 255) { - for (; j < MAXLIGHTMAPS ; j++) + for (; j < MAXRLIGHTMAPS ; j++) { colscale[j][0] = 0; colscale[j][1] = 0; @@ -2869,6 +2893,7 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, shaderstate.lastuniform = 0; } else +#endif { vec4_t colscale[4]; if (shaderstate.curentity->model && shaderstate.curentity->model->engineflags & MDLF_NEEDOVERBRIGHT) @@ -2989,23 +3014,19 @@ static void BE_Program_Set_Attributes(const program_t *prog, unsigned int perm, case SP_LIGHTCOLOURSCALE: qglUniform3fvARB(ph, 1, shaderstate.lightcolourscale); break; - case SP_LIGHTPROJMATRIX: - { - float t[16]; - Matrix4x4_CM_Projection_Far(t, 90, 90, 4, 3000); - qglUniformMatrix4fvARB(ph, 1, false, t); - } - break; case SP_LIGHTCUBEMATRIX: /*light's texture projection matrix*/ { float t[16]; - Matrix4_Multiply(shaderstate.modelmatrix, shaderstate.lightprojmatrix, t); + Matrix4_Multiply(shaderstate.lightprojmatrix, shaderstate.modelmatrix, t); qglUniformMatrix4fvARB(ph, 1, false, t); } break; - case SP_LIGHTSHADOWMAPINFO: - qglUniform4fvARB(ph, 1, shaderstate.lightshadowmapinfo); + case SP_LIGHTSHADOWMAPPROJ: + qglUniform4fvARB(ph, 1, shaderstate.lightshadowmapproj); + break; + case SP_LIGHTSHADOWMAPSCALE: + qglUniform2fvARB(ph, 1, shaderstate.lightshadowmapscale); break; /*static lighting info*/ @@ -3083,8 +3104,10 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas perm |= PERMUTATION_FOG; if (p->permu[perm|PERMUTATION_DELUXE].handle.glsl && TEXVALID(shaderstate.curtexnums->bump) && shaderstate.curbatch->lightmap[0] >= 0 && lightmap[shaderstate.curbatch->lightmap[0]]->hasdeluxe) perm |= PERMUTATION_DELUXE; +#if MAXRLIGHTMAPS > 1 if (shaderstate.curbatch->lightmap[1] >= 0 && p->permu[perm|PERMUTATION_LIGHTSTYLES].handle.glsl) perm |= PERMUTATION_LIGHTSTYLES; +#endif GL_SelectProgram(p->permu[perm].handle.glsl); #ifndef FORCESTATE @@ -3106,6 +3129,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas { Shader_BindTextureForPass(i, pass+i); } +#if MAXRLIGHTMAPS > 1 if (perm & PERMUTATION_LIGHTSTYLES) { GL_LazyBind(i++, GL_TEXTURE_2D, shaderstate.curbatch->lightmap[1] >= 0?lightmap[shaderstate.curbatch->lightmap[1]]->lightmap_texture:r_nulltex); @@ -3120,6 +3144,7 @@ static void BE_RenderMeshProgram(const shader_t *shader, const shaderpass_t *pas shaderstate.lastpasstmus = pass->numMergedPasses+3; } else +#endif { //we need this loop to fix up fixed-function stuff for (; i < shaderstate.lastpasstmus; i++) @@ -3214,6 +3239,7 @@ void GLBE_SelectMode(backendmode_t mode) { char *defs[] = {NULL}; shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config.gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false); + shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader, "m_modelviewprojection"); } //disable all tmus @@ -3332,66 +3358,67 @@ static qboolean GLBE_RegisterLightShader(int mode) shaderstate.inited_shader_light[mode] = true; shaderstate.shader_light[mode] = R_RegisterCustom(name, SUF_NONE, Shader_LightPass, NULL); - - //make sure it has a program and forget it if it doesn't, to save a compare. - if (!shaderstate.shader_light[mode] || !shaderstate.shader_light[mode]->prog) - { - shaderstate.shader_light[mode] = NULL; - } } if (shaderstate.shader_light[mode]) + { + //make sure it has a program and forget it if it doesn't, to save a compare. + if (!shaderstate.shader_light[mode]->prog) + { + shaderstate.shader_light[mode] = NULL; + return false; + } return true; + } return false; } #endif -void GLBE_SelectDLight(dlight_t *dl, vec3_t colour) +qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode) { - float view[16]; - int lmode; extern cvar_t gl_specular; - extern cvar_t r_shadow_shadowmapping; +#ifdef RTLIGHTS + float view[16]; + extern cvar_t r_shadow_shadowmapping, r_shadow_shadowmapping_nearclip; /*generate light projection information*/ - float nearplane = 4; - if (dl->fov) + if (lmode == LSHADER_SPOT) { float proj[16]; - Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, nearplane, dl->radius); + Matrix4x4_CM_Projection_Far(proj, dl->fov, dl->fov, r_shadow_shadowmapping_nearclip.value, dl->radius); Matrix4x4_CM_ModelViewMatrixFromAxis(view, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin); Matrix4_Multiply(proj, view, shaderstate.lightprojmatrix); } - else + if (lmode == LSHADER_SMAP) { // Matrix4x4_CM_Projection_Far(proj, 90, 90, nearplane, dl->radius); Matrix4x4_CM_ModelViewMatrixFromAxis(shaderstate.lightprojmatrix, dl->axis[0], dl->axis[1], dl->axis[2], dl->origin); } +#endif + + shaderstate.curdlight = dl; + shaderstate.lightmode = 1u<radius; VectorCopy(dl->origin, shaderstate.lightorg); - VectorCopy(dl->lightcolourscales, shaderstate.lightcolourscale); shaderstate.lightcolourscale[2] *= gl_specular.value; VectorCopy(colour, shaderstate.lightcolours); #ifdef RTLIGHTS + VectorCopy(dl->lightcolourscales, shaderstate.lightcolourscale); shaderstate.lightcubemap = dl->cubetexture; #endif shaderstate.lastuniform = 0; - lmode = 0; -#ifdef RTLIGHTS - if (((dl->flags & LFLAG_SHADOWMAP) || r_shadow_shadowmapping.ival) && GLBE_RegisterLightShader(lmode | (1u<fov && GLBE_RegisterLightShader(lmode | (1u<flags; #ifndef FORCESTATE - if (shaderstate.curcull != (shaderstate.curshader->flags & (SHADER_CULL_FRONT|SHADER_CULL_BACK))) + if (shaderstate.curcull != ((flags^r_refdef.flipcull) & (SHADER_CULL_FRONT|SHADER_CULL_BACK))) #endif { - shaderstate.curcull = (shaderstate.curshader->flags & (SHADER_CULL_FRONT|SHADER_CULL_BACK)); + shaderstate.curcull = ((flags^r_refdef.flipcull) & (SHADER_CULL_FRONT|SHADER_CULL_BACK)); if (shaderstate.curcull & SHADER_CULL_FRONT) { qglEnable(GL_CULL_FACE); - qglCullFace(r_refdef.flipcull?GL_BACK:GL_FRONT); + qglCullFace(GL_FRONT); } else if (shaderstate.curcull & SHADER_CULL_BACK) { qglEnable(GL_CULL_FACE); - qglCullFace(r_refdef.flipcull?GL_FRONT:GL_BACK); + qglCullFace(GL_BACK); } else { @@ -3637,14 +3671,6 @@ static void DrawMeshes(void) Host_Error("Shader system is not meant to accept stencil meshes\n"); break; #ifdef RTLIGHTS - case BEM_SMAPLIGHTSPOT: -// if (shaderstate.shader_spot->prog) -// BE_RenderMeshProgram(shaderstate.shader_spot, shaderstate.shader_spot->passes); -// break; - case BEM_SMAPLIGHT: -// if (shaderstate.shader_smap->prog) -// BE_RenderMeshProgram(shaderstate.shader_smap, shaderstate.shader_smap->passes); -// break; case BEM_LIGHT: if (!shaderstate.shader_light[shaderstate.lightmode]) BE_LegacyLighting(); @@ -3662,12 +3688,17 @@ static void DrawMeshes(void) BE_RenderMeshProgram(shaderstate.crepopaqueshader, shaderstate.crepopaqueshader->passes); break; case BEM_DEPTHONLY: - GL_DeSelectProgram(); + if (shaderstate.depthonlyshader) + BE_RenderMeshProgram(shaderstate.depthonlyshader, shaderstate.depthonlyshader->passes); + else + { + GL_DeSelectProgram(); #ifdef warningmsg #pragma warningmsg("fixme: support alpha test") #endif - BE_EnableShaderAttributes((1u<passes[0].shaderbits); BE_EnableShaderAttributes(1u<flags & BEF_NODLIGHT) - if (shaderstate.mode == BEM_LIGHT || shaderstate.mode == BEM_SMAPLIGHT) + if (shaderstate.mode == BEM_LIGHT) continue; if (batch->flags & BEF_NOSHADOWS) if (shaderstate.mode == BEM_STENCIL || shaderstate.mode == BEM_DEPTHONLY) //fixme: depthonly is not just shadows. @@ -4084,7 +4118,7 @@ static void GLBE_SubmitMeshesSortList(batch_t *sortlist) if (batch->shader->flags & SHADER_NODRAW) continue; if (batch->shader->flags & SHADER_NODLIGHT) - if (shaderstate.mode == BEM_LIGHT || shaderstate.mode == BEM_SMAPLIGHT) + if (shaderstate.mode == BEM_LIGHT) continue; if (batch->shader->flags & SHADER_SKY) { @@ -4336,7 +4370,7 @@ void GLBE_BaseEntTextures(void) batch_t *batches[SHADER_SORT_COUNT]; batch_t **ob = shaderstate.mbatches; shaderstate.mbatches = batches; - BE_GenModelBatches(batches); + BE_GenModelBatches(batches, shaderstate.curdlight, shaderstate.mode); GLBE_SubmitMeshes(false, SHADER_SORT_PORTAL, SHADER_SORT_DECAL); GLBE_SelectEntity(&r_worldentity); shaderstate.mbatches = ob; @@ -4600,7 +4634,9 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) Sh_Reset(); #endif } - BE_GenModelBatches(batches); + + //memset(batches, 0, sizeof(batches)); + BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD); R_GenDlightBatches(batches); shaderstate.curentity = &r_worldentity; if (cl.paused || cls.state < ca_active) @@ -4684,6 +4720,7 @@ void GLBE_DrawWorld (qboolean drawworld, qbyte *vis) qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif + shaderstate.curdlight = NULL; } else { diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 2ff8ef926..77fec4b6d 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -980,7 +980,15 @@ struct font_s *Font_LoadFont(int vheight, char *fontfilename) f->charheight = height; Q_strncpyz(f->name, fontfilename, sizeof(f->name)); - VectorSet(f->alttint, 1.16, 0.54, 0.41); + switch(M_GameType()) + { + case MGT_QUAKE2: + VectorSet(f->alttint, 0.44, 1.0, 0.2); + break; + default: + VectorSet(f->alttint, 1.16, 0.54, 0.41); + break; + } #ifdef DOOMWADS if (!*fontfilename) diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index ec2740a45..9bb48dd88 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -127,13 +127,16 @@ void Mod_BatchList_f(void) { for (batch = mod->batches[i]; batch; batch = batch->next) { +#if MAXRLIGHTMAPS > 1 if (batch->lightmap[3] >= 0) Con_Printf("%s lm=(%i:%i %i:%i %i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->lightmap[2], batch->lmlightstyle[2], batch->lightmap[3], batch->lmlightstyle[3], batch->maxmeshes); else if (batch->lightmap[2] >= 0) Con_Printf("%s lm=(%i:%i %i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->lightmap[2], batch->lmlightstyle[2], batch->maxmeshes); else if (batch->lightmap[1] >= 0) Con_Printf("%s lm=(%i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->maxmeshes); - else if (batch->lmlightstyle[0] != 255) + else +#endif + if (batch->lmlightstyle[0] != 255) Con_Printf("%s lm=(%i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->maxmeshes); else Con_Printf("%s lm=%i surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->maxmeshes); @@ -883,10 +886,11 @@ model_t *Mod_LoadModel (model_t *mod, qboolean crash) break; #endif + case BSPVERSION_LONG1: + Con_Printf("WARNING: %s is in a deprecated format\n", mod->name); case 30: //hl case 29: //q1 case 28: //prerel - case BSPVERSION_LONG1: case BSPVERSION_LONG2: TRACE(("Mod_LoadModel: hl/q1 bsp\n")); if (!Mod_LoadBrushModel (mod, buf)) @@ -2330,7 +2334,7 @@ qboolean Mod_LoadFaces (lump_t *l, qboolean lm, mesh_t **meshlist) out->firstedge = LittleLong(inl->firstedge); out->numedges = LittleLong(inl->numedges); tn = LittleLong (inl->texinfo); - for (i=0 ; istyles[i] = inl->styles[i]; lofs = LittleLong(inl->lightofs); inl++; @@ -2342,7 +2346,7 @@ qboolean Mod_LoadFaces (lump_t *l, qboolean lm, mesh_t **meshlist) out->firstedge = LittleLong(ins->firstedge); out->numedges = LittleShort(ins->numedges); tn = LittleShort (ins->texinfo); - for (i=0 ; istyles[i] = ins->styles[i]; lofs = LittleLong(ins->lightofs); ins++; @@ -2506,7 +2510,7 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi vbo.colours[sty].dummy = ptr; ptr += sizeof(vec4_t)*maxverts; } - for (; sty < MAXLIGHTMAPS; sty++) + for (; sty < MAXRLIGHTMAPS; sty++) vbo.colours[sty].dummy = NULL; vbo.texcoord.dummy = ptr; ptr += sizeof(vec2_t)*maxverts; @@ -2516,7 +2520,7 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi vbo.lmcoord[sty].dummy = ptr; ptr += sizeof(vec2_t)*maxverts; } - for (; sty < MAXLIGHTMAPS; sty++) + for (; sty < MAXRLIGHTMAPS; sty++) vbo.lmcoord[sty].dummy = NULL; vbo.normals.dummy = ptr; ptr += sizeof(vec3_t)*maxverts; @@ -2547,7 +2551,7 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi //set up the arrays. the arrangement is required for the backend to optimise vbos mesh->xyz_array = (vecV_t*)vbo.coord.dummy + mesh->vbofirstvert; mesh->st_array = (vec2_t*)vbo.texcoord.dummy + mesh->vbofirstvert; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { if (vbo.lmcoord[sty].dummy) mesh->lmst_array[sty] = (vec2_t*)vbo.lmcoord[sty].dummy + mesh->vbofirstvert; @@ -2629,9 +2633,11 @@ static void Mod_Batches_Generate(model_t *mod) lbatch->lightmap[0] == surf->lightmaptexturenums[0] && Vector4Compare(plane, lbatch->plane) && lbatch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES) && +#if MAXRLIGHTMAPS > 1 lbatch->lightmap[1] == surf->lightmaptexturenums[1] && lbatch->lightmap[2] == surf->lightmaptexturenums[2] && lbatch->lightmap[3] == surf->lightmaptexturenums[3] && +#endif lbatch->fog == surf->fog) batch = lbatch; else @@ -2643,9 +2649,11 @@ static void Mod_Batches_Generate(model_t *mod) batch->lightmap[0] == surf->lightmaptexturenums[0] && Vector4Compare(plane, batch->plane) && batch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && +#if MAXRLIGHTMAPS > 1 batch->lightmap[1] == surf->lightmaptexturenums[1] && batch->lightmap[2] == surf->lightmaptexturenums[2] && batch->lightmap[3] == surf->lightmaptexturenums[3] && +#endif batch->fog == surf->fog) break; } @@ -2654,9 +2662,11 @@ static void Mod_Batches_Generate(model_t *mod) { batch = ZG_Malloc(&loadmodel->memgroup, sizeof(*batch)); batch->lightmap[0] = surf->lightmaptexturenums[0]; +#if MAXRLIGHTMAPS > 1 batch->lightmap[1] = surf->lightmaptexturenums[1]; batch->lightmap[2] = surf->lightmaptexturenums[2]; batch->lightmap[3] = surf->lightmaptexturenums[3]; +#endif batch->texture = surf->texinfo->texture; batch->next = mod->batches[sortid]; batch->ent = &r_worldentity; @@ -2779,7 +2789,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod) for (batch = mod->batches[sortid]; batch != NULL; batch = batch->next) { surf = (msurface_t*)batch->mesh[0]; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { batch->lightmap[sty] = surf->lightmaptexturenums[sty]; batch->lmlightstyle[sty] = surf->styles[sty]; @@ -2788,7 +2798,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod) for (j = 1; j < batch->maxmeshes; j++) { surf = (msurface_t*)batch->mesh[j]; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { if (surf->lightmaptexturenums[sty] != batch->lightmap[sty] || //fixme: we should merge later (reverted matching) surfaces into the prior batch @@ -2796,7 +2806,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod) surf->vlstyles[sty] != batch->vtlightstyle[sty]) break; } - if (sty < MAXLIGHTMAPS) + if (sty < MAXRLIGHTMAPS) { nb = ZG_Malloc(&loadmodel->memgroup, sizeof(*batch)); *nb = *batch; @@ -2805,7 +2815,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod) nb->mesh = batch->mesh + j*2; nb->maxmeshes = batch->maxmeshes - j; batch->maxmeshes = j; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { nb->lightmap[sty] = surf->lightmaptexturenums[sty]; nb->lmlightstyle[sty] = surf->styles[sty]; @@ -2846,9 +2856,9 @@ static void Mod_Batches_AllocLightmaps(model_t *mod) { surf = (msurface_t*)batch->mesh[0]; Mod_LightmapAllocSurf (&lmallocator, surf, 0); - for (sty = 1; sty < MAXLIGHTMAPS; sty++) + for (sty = 1; sty < MAXRLIGHTMAPS; sty++) surf->lightmaptexturenums[sty] = -1; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { batch->lightmap[sty] = surf->lightmaptexturenums[sty]; batch->lmlightstyle[sty] = 255;//don't do special backend rendering of lightstyles. @@ -2859,7 +2869,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod) { surf = (msurface_t*)batch->mesh[j]; Mod_LightmapAllocSurf (&lmallocator, surf, 0); - for (sty = 1; sty < MAXLIGHTMAPS; sty++) + for (sty = 1; sty < MAXRLIGHTMAPS; sty++) surf->lightmaptexturenums[sty] = -1; if (surf->lightmaptexturenums[0] != batch->lightmap[0]) { @@ -2870,7 +2880,7 @@ static void Mod_Batches_AllocLightmaps(model_t *mod) nb->mesh = batch->mesh + j*2; nb->maxmeshes = batch->maxmeshes - j; batch->maxmeshes = j; - for (sty = 0; sty < MAXLIGHTMAPS; sty++) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) nb->lightmap[sty] = surf->lightmaptexturenums[sty]; memmove(nb->mesh, batch->mesh+j, sizeof(msurface_t*)*nb->maxmeshes); diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 2e5e06a2e..644921b97 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -29,6 +29,7 @@ struct trace_s; struct wedict_s; struct model_s; struct world_s; +struct dlight_s; typedef enum { SHADER_SORT_NONE, @@ -81,8 +82,8 @@ typedef struct mesh_s vec3_t *snormals_array;/*required for rtlighting*/ vec3_t *tnormals_array;/*required for rtlighting*/ vec2_t *st_array; /*texture coords*/ - vec2_t *lmst_array[MAXLIGHTMAPS]; /*second texturecoord set (merely dubbed lightmap, one for each potential lightstyle)*/ - avec4_t *colors4f_array[MAXLIGHTMAPS];/*floating point colours array*/ + vec2_t *lmst_array[MAXRLIGHTMAPS]; /*second texturecoord set (merely dubbed lightmap, one for each potential lightstyle)*/ + avec4_t *colors4f_array[MAXRLIGHTMAPS];/*floating point colours array*/ byte_vec4_t *colors4b_array;/*byte colours array*/ index_t *indexes; @@ -115,9 +116,9 @@ typedef struct batch_s entity_t *ent; /*used for shader properties*/ struct mfog_s *fog; - short lightmap[MAXLIGHTMAPS]; /*used for shader lightmap textures*/ - unsigned char lmlightstyle[MAXLIGHTMAPS]; - unsigned char vtlightstyle[MAXLIGHTMAPS]; + short lightmap[MAXRLIGHTMAPS]; /*used for shader lightmap textures*/ + unsigned char lmlightstyle[MAXRLIGHTMAPS]; + unsigned char vtlightstyle[MAXRLIGHTMAPS]; unsigned int maxmeshes; /*not used by backend*/ unsigned int flags; /*backend flags (force transparency etc)*/ @@ -262,13 +263,13 @@ typedef struct vbo_s vboarray_t coord; vboarray_t coord2; vboarray_t texcoord; - vboarray_t lmcoord[MAXLIGHTMAPS]; + vboarray_t lmcoord[MAXRLIGHTMAPS]; vboarray_t normals; vboarray_t svector; vboarray_t tvector; - vboarray_t colours[MAXLIGHTMAPS]; + vboarray_t colours[MAXRLIGHTMAPS]; vboarray_t bonenums; @@ -359,15 +360,6 @@ typedef struct mfog_s mplane_t **planes; } mfog_t; -#if MAX_SWDECALS -typedef struct decal_s { - int xpos, ypos; - struct msurface_s *owner; - struct decal_s *next; - struct decal_s *prev; -} decal_t; -#endif - typedef struct msurface_s { @@ -380,7 +372,7 @@ typedef struct msurface_s short texturemins[2]; short extents[2]; - unsigned short light_s[MAXLIGHTMAPS], light_t[MAXLIGHTMAPS]; // gl lightmap coordinates + unsigned short light_s[MAXRLIGHTMAPS], light_t[MAXRLIGHTMAPS]; // gl lightmap coordinates mfog_t *fog; mesh_t *mesh; @@ -394,19 +386,16 @@ typedef struct msurface_s int dlightframe; int dlightbits; - int lightmaptexturenums[MAXLIGHTMAPS]; //rbsp+fbsp formats have multiple lightmaps - qbyte styles[MAXLIGHTMAPS]; - qbyte vlstyles[MAXLIGHTMAPS]; - int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap + int lightmaptexturenums[MAXRLIGHTMAPS]; //rbsp+fbsp formats have multiple lightmaps + qbyte styles[MAXQ1LIGHTMAPS]; + qbyte vlstyles[MAXRLIGHTMAPS]; + int cached_light[MAXQ1LIGHTMAPS]; // values currently used in lightmap qboolean cached_dlight; // true if dynamic light in cache - qbyte cached_colour[MAXLIGHTMAPS]; + qbyte cached_colour[MAXQ1LIGHTMAPS]; #ifndef NOSTAINS qboolean stained; #endif qbyte *samples; // [numstyles*surfsize] -#ifdef MAX_SWDECALS - decal_t *decal; -#endif } msurface_t; typedef struct mbrush_s @@ -463,12 +452,11 @@ typedef struct mleaf_s msurface_t **firstmarksurface; int nummarksurfaces; - int key; // BSP sequence number for leaf's contents qbyte ambient_sound_level[NUM_AMBIENTS]; #if defined(Q2BSPS) || defined(Q3BSPS) int cluster; - struct mleaf_s *vischain; +// struct mleaf_s *vischain; #endif #ifdef Q2BSPS //it's a q2 thing diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 35562d1cf..1e2a55cbe 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -328,7 +328,7 @@ void R_GenDlightMesh(struct batch_s *batch) static mesh_t *meshptr; dlight_t *l = cl_dlights + batch->surf_first; - BE_SelectDLight(l, l->color); + BE_SelectDLight(l, l->color, LSHADER_STANDARD); if (!R_BuildDlightMesh (l, 2, 1, true)) { @@ -1123,7 +1123,7 @@ int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) { lightmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -1137,7 +1137,7 @@ int GLRecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) { lightmap += dt * ((surf->extents[0]>>4)+1) + ds; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]; @@ -1288,7 +1288,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) lightmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; deluxmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]/256.0f; @@ -1317,7 +1317,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) lightmap += (dt * ((surf->extents[0]>>4)+1) + ds); deluxmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]/256.0f; @@ -1346,7 +1346,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) if (cl.worldmodel->engineflags & MDLF_RGBLIGHTING) { lightmap += (dt * ((surf->extents[0]>>4)+1) + ds)*3; - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]/256.0f; @@ -1366,7 +1366,7 @@ float *GLRecursiveLightPoint3C (mnode_t *node, vec3_t start, vec3_t end) else { lightmap += (dt * ((surf->extents[0]>>4)+1) + ds); - for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + for (maps = 0 ; maps < MAXQ1LIGHTMAPS && surf->styles[maps] != 255 ; maps++) { scale = d_lightstylevalue[surf->styles[maps]]/256.0f; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 425658f55..4469a2066 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -232,28 +232,27 @@ void R_RotateForEntity (float *m, float *modelview, const entity_t *e, const mod { if ((e->flags & Q2RF_WEAPONMODEL) && r_refdef.playerview->viewentity > 0) { - entity_t *view = &r_refdef.playerview->viewent; float em[16]; float vm[16]; - vm[0] = view->axis[0][0]; - vm[1] = view->axis[0][1]; - vm[2] = view->axis[0][2]; + vm[0] = r_refdef.playerview->vw_axis[0][0]; + vm[1] = r_refdef.playerview->vw_axis[0][1]; + vm[2] = r_refdef.playerview->vw_axis[0][2]; vm[3] = 0; - vm[4] = view->axis[1][0]; - vm[5] = view->axis[1][1]; - vm[6] = view->axis[1][2]; + vm[4] = r_refdef.playerview->vw_axis[1][0]; + vm[5] = r_refdef.playerview->vw_axis[1][1]; + vm[6] = r_refdef.playerview->vw_axis[1][2]; vm[7] = 0; - vm[8] = view->axis[2][0]; - vm[9] = view->axis[2][1]; - vm[10] = view->axis[2][2]; + vm[8] = r_refdef.playerview->vw_axis[2][0]; + vm[9] = r_refdef.playerview->vw_axis[2][1]; + vm[10] = r_refdef.playerview->vw_axis[2][2]; vm[11] = 0; - vm[12] = view->origin[0]; - vm[13] = view->origin[1]; - vm[14] = view->origin[2]; + vm[12] = r_refdef.playerview->vw_origin[0]; + vm[13] = r_refdef.playerview->vw_origin[1]; + vm[14] = r_refdef.playerview->vw_origin[2]; vm[15] = 1; em[0] = e->axis[0][0]; @@ -425,13 +424,7 @@ void R_SetupGL (float stereooffset) if (r_refdef.useperspective) { - int stencilshadows = 0; - #ifdef RTLIGHTS - stencilshadows |= r_shadow_realtime_dlight.ival && r_shadow_realtime_dlight_shadows.ival; - stencilshadows |= r_shadow_realtime_world.ival && r_shadow_realtime_world_shadows.ival; - //if (r_shadow_shadowmapping.ival) - stencilshadows = false; - #endif + int stencilshadows = Sh_StencilShadowsActive(); if ((!stencilshadows || !gl_stencilbits) && gl_maxdist.value>=100)//gl_nv_range_clamp) { @@ -827,7 +820,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) { case 1: /*fbo explicit mirror (fucked depth, working clip plane)*/ //fixme: pvs is surely wrong? - r_refdef.flipcull ^= true; + r_refdef.flipcull ^= SHADER_CULL_FLIP; R_MirrorMatrix(&plane); break; @@ -896,7 +889,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) } else if (!(view = R_NearestPortal(&plane)) || VectorCompare(view->origin, view->oldorigin)) { - r_refdef.flipcull ^= true; + r_refdef.flipcull ^= SHADER_CULL_FLIP; R_MirrorMatrix(&plane); } else @@ -1324,6 +1317,11 @@ void GLR_RenderView (void) if (!r_worldentity.model || !cl.worldmodel) { GL_DoSwap(); + + GL_Set2D (false); + R2D_ImageColours(0, 0, 0, 1); + R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height); + R2D_ImageColours(1, 1, 1, 1); return; } // Sys_Error ("R_RenderView: NULL worldmodel"); diff --git a/engine/gl/gl_rmisc.c b/engine/gl/gl_rmisc.c index b0917753c..b9a91146f 100644 --- a/engine/gl/gl_rmisc.c +++ b/engine/gl/gl_rmisc.c @@ -487,7 +487,7 @@ R_NewMap void GLR_NewMap (void) { char namebuf[MAX_QPATH]; - extern cvar_t host_mapname, r_shadow_realtime_dlight, r_shadow_realtime_world; + extern cvar_t host_mapname; int i; for (i=0 ; i<256 ; i++) @@ -543,7 +543,10 @@ TRACE(("dbg: GLR_NewMap: tp\n")); void GLR_PreNewMap(void) { - r_loadbumpmapping = r_deluxemapping.ival || r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival || r_glsl_offsetmapping.ival; + r_loadbumpmapping = r_deluxemapping.ival || r_glsl_offsetmapping.ival; +#ifdef RTLIGHTS + r_loadbumpmapping |= r_shadow_realtime_world.ival || r_shadow_realtime_dlight.ival; +#endif r_viewleaf = NULL; r_oldviewleaf = NULL; r_viewleaf2 = NULL; diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index 121b9bf26..f2f695177 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void GLBE_ClearVBO(vbo_t *vbo) { - int vboh[6 + MAXLIGHTMAPS]; + int vboh[6 + MAXRLIGHTMAPS]; int i, j; vboh[0] = vbo->indicies.gl.vbo; vboh[1] = vbo->coord.gl.vbo; @@ -36,7 +36,7 @@ void GLBE_ClearVBO(vbo_t *vbo) vboh[3] = vbo->normals.gl.vbo; vboh[4] = vbo->svector.gl.vbo; vboh[5] = vbo->tvector.gl.vbo; - for (i = 0; i < MAXLIGHTMAPS; i++) + for (i = 0; i < MAXRLIGHTMAPS; i++) vboh[6+i] = vbo->lmcoord[i].gl.vbo; for (i = 0; i < 7; i++) @@ -90,7 +90,7 @@ static qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int vbo->texcoord.gl.addr = (vec2_t*)((char*)vbo->texcoord.gl.addr - (char*)vdata); vaostatic |= VATTR_TEXCOORD; } - for (s = 0; s < MAXLIGHTMAPS; s++) + for (s = 0; s < MAXRLIGHTMAPS; s++) { if (vbo->colours[s].gl.addr) { @@ -99,9 +99,11 @@ static qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int switch(s) { default: vaostatic |= VATTR_COLOUR; break; +#if MAXRLIGHTMAPS > 1 case 1: vaostatic |= VATTR_COLOUR2; break; case 2: vaostatic |= VATTR_COLOUR3; break; case 3: vaostatic |= VATTR_COLOUR4; break; +#endif } } if (vbo->lmcoord[s].gl.addr) @@ -111,9 +113,11 @@ static qboolean GL_BuildVBO(vbo_t *vbo, void *vdata, int vsize, void *edata, int switch(s) { default: vaostatic |= VATTR_LMCOORD; break; +#if MAXRLIGHTMAPS > 1 case 1: vaostatic |= VATTR_LMCOORD2; break; case 2: vaostatic |= VATTR_LMCOORD3; break; case 3: vaostatic |= VATTR_LMCOORD4; break; +#endif } } } @@ -176,11 +180,11 @@ void GLBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch vecV_t *coord; vec2_t *texcoord; - vec2_t *lmcoord[MAXLIGHTMAPS]; + vec2_t *lmcoord[MAXRLIGHTMAPS]; vec3_t *normals; vec3_t *svector; vec3_t *tvector; - vec4_t *colours[MAXLIGHTMAPS]; + vec4_t *colours[MAXRLIGHTMAPS]; index_t *indicies; batch_t *batch; int vbosize; @@ -224,14 +228,14 @@ void GLBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch vbo->texcoord.gl.addr = allocbuf(&p, maxvboverts, sizeof(vec2_t)); for (s = 0; s < lightmaps; s++) vbo->lmcoord[s].gl.addr = allocbuf(&p, maxvboverts, sizeof(vec2_t)); - for (; s < MAXLIGHTMAPS; s++) + for (; s < MAXRLIGHTMAPS; s++) vbo->lmcoord[s].gl.addr = NULL; vbo->normals.gl.addr = allocbuf(&p, maxvboverts, sizeof(vec3_t)); vbo->svector.gl.addr = allocbuf(&p, maxvboverts, sizeof(vec3_t)); vbo->tvector.gl.addr = allocbuf(&p, maxvboverts, sizeof(vec3_t)); for (s = 0; s < lightmaps; s++) vbo->colours[s].gl.addr = allocbuf(&p, maxvboverts, sizeof(vec4_t)); - for (; s < MAXLIGHTMAPS; s++) + for (; s < MAXRLIGHTMAPS; s++) vbo->lmcoord[s].gl.addr = NULL; vbosize = (char*)p - (char*)vbo->coord.gl.addr; if ((char*)p - (char*)vbo->vertdata > (maxvboverts+1)*pervertsize) @@ -240,7 +244,7 @@ void GLBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch coord = vbo->coord.gl.addr; texcoord = vbo->texcoord.gl.addr; - for (s = 0; s < MAXLIGHTMAPS; s++) + for (s = 0; s < MAXRLIGHTMAPS; s++) { lmcoord[s] = vbo->lmcoord[s].gl.addr; colours[s] = vbo->colours[s].gl.addr; diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index f83d32202..86562fefd 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -72,8 +72,9 @@ void GLSCR_UpdateScreen (void) if (scr_disabled_for_loading) { extern float scr_disabled_time; - if (Sys_DoubleTime() - scr_disabled_time > 60 || key_dest != key_game) + if (Sys_DoubleTime() - scr_disabled_time > 60 || !Key_Dest_Has(~kdm_game)) { + //FIXME: instead of reenabling the screen, we should just draw the relevent things skipping only the game. scr_disabled_for_loading = false; } else @@ -115,7 +116,7 @@ void GLSCR_UpdateScreen (void) #endif R2D_BrightenScreen(); - if (key_dest == key_console) + if (key_dest_mask & kdm_console) Con_DrawConsole(vid.height/2, false); GL_EndRendering (); GL_DoSwap(); @@ -199,7 +200,9 @@ void GLSCR_UpdateScreen (void) RSpeedEnd(RSPEED_TOTALREFRESH); RSpeedShow(); + RSpeedRemark(); GL_EndRendering (); + RSpeedEnd(RSPEED_FINISH); } diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 66161c7aa..54dc5318f 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -915,9 +915,10 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip "#define LIGHTSTYLED\n", NULL }; - char *permutationdefines[sizeof(permutationname)/sizeof(permutationname[0]) + 64 + 1]; +#define MAXMODIFIERS 64 + char *permutationdefines[sizeof(permutationname)/sizeof(permutationname[0]) + MAXMODIFIERS + 1]; unsigned int nopermutation = ~0u; - int nummodifiers; + int nummodifiers = 0; int p, n, pn; char *end; @@ -941,6 +942,26 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip script++; if (!strncmp(script, "!!fixed", 7)) prog->nofixedcompat = false; + else if (!strncmp(script, "!!cvardf", 8)) + { + script += 8; + while (*script == ' ' || *script == '\t') + script++; + end = script; + while ((*end >= 'A' && *end <= 'Z') || (*end >= 'a' && *end <= 'z') || (*end >= '0' && *end <= '9') || *end == '_') + end++; + if (nummodifiers < MAXMODIFIERS && end - script < 64) + { + cvar_t *var; + char namebuf[64]; + memcpy(namebuf, script, end - script); + namebuf[end - script] = 0; + var = Cvar_Get(namebuf, "0", CVAR_SHADERSYSTEM, "GLSL Variables"); + if (var) + permutationdefines[nummodifiers++] = Z_StrDup(va("#define %s %g\n", namebuf, var->value)); + } + script = end; + } else if (!strncmp(script, "!!cvarf", 7)) { script += 7; @@ -1024,18 +1045,20 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip break; }; - nummodifiers = 0; if (gl_specular.value) - permutationdefines[nummodifiers++] = strdup("#define SPECULAR\n"); + { + if (nummodifiers < MAXMODIFIERS) + permutationdefines[nummodifiers++] = Z_StrDup("#define SPECULAR\n"); + } for (end = strchr(name, '#'); end && *end; ) { char *start = end+1; end = strchr(start, '#'); if (!end) end = start + strlen(start); - if (nummodifiers < 64) + if (nummodifiers < MAXMODIFIERS) { - permutationdefines[nummodifiers] = malloc(10 + end - start); + permutationdefines[nummodifiers] = BZ_Malloc(10 + end - start); memcpy(permutationdefines[nummodifiers], "#define ", 8); memcpy(permutationdefines[nummodifiers]+8, start, end - start); memcpy(permutationdefines[nummodifiers]+8+(end-start), "\n", 2); @@ -1108,7 +1131,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip #endif } while(nummodifiers) - free(permutationdefines[--nummodifiers]); + Z_Free(permutationdefines[--nummodifiers]); Shader_ProgAutoFields(prog, cvarnames, cvartypes); @@ -1588,7 +1611,7 @@ void Shader_WriteOutGenerics_f(void) struct shader_field_names_s shader_attr_names[] = { /*vertex attributes*/ - {"v_position", VATTR_VERTEX1}, + {"v_position1", VATTR_VERTEX1}, {"v_position2", VATTR_VERTEX2}, {"v_colour", VATTR_COLOUR}, {"v_texcoord", VATTR_TEXCOORD}, @@ -1598,9 +1621,16 @@ struct shader_field_names_s shader_attr_names[] = {"v_tvector", VATTR_TNORMALS}, {"v_bone", VATTR_BONENUMS}, {"v_weight", VATTR_BONEWEIGHTS}, +#if MAXRLIGHTMAPS > 1 + {"v_lmcoord1", VATTR_LMCOORD}, {"v_lmcoord2", VATTR_LMCOORD2}, {"v_lmcoord3", VATTR_LMCOORD3}, {"v_lmcoord4", VATTR_LMCOORD4}, + {"v_colour1", VATTR_COLOUR}, + {"v_colour2", VATTR_COLOUR2}, + {"v_colour3", VATTR_COLOUR3}, + {"v_colour4", VATTR_COLOUR4}, +#endif {NULL} }; @@ -1641,9 +1671,9 @@ struct shader_field_names_s shader_unif_names[] = {"l_lightcolour", SP_LIGHTCOLOUR}, {"l_lightposition", SP_LIGHTPOSITION}, {"l_lightcolourscale", SP_LIGHTCOLOURSCALE}, - {"l_projmatrix", SP_LIGHTPROJMATRIX}, {"l_cubematrix", SP_LIGHTCUBEMATRIX}, - {"l_shadowmapinfo", SP_LIGHTSHADOWMAPINFO}, + {"l_shadowmapproj", SP_LIGHTSHADOWMAPPROJ}, + {"l_shadowmapscale", SP_LIGHTSHADOWMAPSCALE}, {"e_rendertexturescale", SP_RENDERTEXTURESCALE}, {NULL} diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 534f46724..63bb17e5e 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -33,26 +33,44 @@ static void SHM_Shutdown(void); #define PROJECTION_DISTANCE (float)(dl->radius*2)//0x7fffffff -#define nearplane (4) static texid_t shadowmap[2]; static int shadow_fbo_id; +static int shadow_fbo_depth_num; static int crepuscular_fbo_id; texid_t crepuscular_texture_id; shader_t *crepuscular_shader; +cvar_t r_shadow_shadowmapping_nearclip = CVAR("r_shadow_shadowmapping_nearclip", "1"); +cvar_t r_shadow_shadowmapping_bias = CVAR("r_shadow_shadowmapping_bias", "0.03"); +cvar_t r_shadow_scissor = CVAR("r_shadow_scissor", "1"); + +cvar_t r_shadow_realtime_world = SCVARF ("r_shadow_realtime_world", "0", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_world_shadows = SCVARF ("r_shadow_realtime_world_shadows", "1", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_world_lightmaps = SCVARF ("r_shadow_realtime_world_lightmaps", "0", 0); +#ifdef FTE_TARGET_WEB +cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "0", CVAR_ARCHIVE); +#else +cvar_t r_shadow_realtime_dlight = SCVARF ("r_shadow_realtime_dlight", "1", CVAR_ARCHIVE); +#endif +cvar_t r_shadow_realtime_dlight_shadows = SCVARF ("r_shadow_realtime_dlight_shadows", "1", CVAR_ARCHIVE); +cvar_t r_shadow_realtime_dlight_ambient = SCVAR ("r_shadow_realtime_dlight_ambient", "0"); +cvar_t r_shadow_realtime_dlight_diffuse = SCVAR ("r_shadow_realtime_dlight_diffuse", "1"); +cvar_t r_shadow_realtime_dlight_specular = SCVAR ("r_shadow_realtime_dlight_specular", "4"); //excessive, but noticable. its called stylized, okay? shiesh, some people +cvar_t r_editlights_import_radius = SCVAR ("r_editlights_import_radius", "1"); +cvar_t r_editlights_import_ambient = SCVAR ("r_editlights_import_ambient", "0"); +cvar_t r_editlights_import_diffuse = SCVAR ("r_editlights_import_diffuse", "1"); +cvar_t r_editlights_import_specular = SCVAR ("r_editlights_import_specular", "1"); //excessive, but noticable. its called stylized, okay? shiesh, some people +cvar_t r_shadow_shadowmapping = SCVARF ("debug_r_shadow_shadowmapping", "0", 0); +cvar_t r_shadow_shadowmapping_precision = CVARD ("r_shadow_shadowmapping_precision", "1", "Scales the shadowmap detail level up or down."); +extern cvar_t r_shadow_shadowmapping_nearclip; +extern cvar_t r_shadow_shadowmapping_bias; +cvar_t r_sun_dir = CVARD ("r_sun_dir", "0.2 0.5 0.8", "Specifies the direction that crepusular rays appear along"); +cvar_t r_sun_colour = CVARFD ("r_sun_colour", "0 0 0", CVAR_ARCHIVE, "Specifies the colour of sunlight that appears in the form of crepuscular rays."); + static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour); -static struct { - int numlights; - int shadowsurfcount; - - int numfrustumculled; - int numpvsculled; - int numscissorculled; -} bench; - /* called on framebuffer resize. @@ -65,6 +83,7 @@ void Sh_Reset(void) { qglDeleteRenderbuffersEXT(1, &shadow_fbo_id); shadow_fbo_id = 0; + shadow_fbo_depth_num = 0; } if (shadowmap[0].num) { @@ -107,9 +126,9 @@ typedef struct shadowmesh_s { enum { - SMT_STENCILVOLUME, - SMT_SHADOWLESS, - SMT_SURFACES + SMT_STENCILVOLUME, //build edges mesh (and surface list) + SMT_SHADOWMAP, //build front faces mesh (and surface list) + SMT_SHADOWLESS //build surface list only } type; unsigned int numindicies; unsigned int maxindicies; @@ -196,6 +215,44 @@ static void SHM_Vertex3fv (const float *v) } } +static void SHM_MeshFrontOnly(int numverts, vecV_t *verts, int numidx, index_t *idx) +{ + int first = sh_shmesh->numverts; + int v, i; + vecV_t *outv; + index_t *outi; + + /*make sure there's space*/ + v = (sh_shmesh->numverts+numverts + inc)&~(inc-1); //and a bit of padding + if (sh_shmesh->maxverts < v) + { + v += 1024; + sh_shmesh->maxverts = v; + sh_shmesh->verts = BZ_Realloc(sh_shmesh->verts, v * sizeof(*sh_shmesh->verts)); + } + + outv = sh_shmesh->verts + sh_shmesh->numverts; + for (v = 0; v < numverts; v++) + { + VectorCopy(verts[v], outv[v]); + } + + v = (sh_shmesh->numindicies+numidx + inc)&~(inc-1); //and a bit of padding + if (sh_shmesh->maxindicies < v) + { + v += 1024; + sh_shmesh->maxindicies = v; + sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, v * sizeof(*sh_shmesh->indicies)); + } + outi = sh_shmesh->indicies + sh_shmesh->numindicies; + for (i = 0; i < numidx; i++) + { + outi[i] = first + idx[i]; + } + + sh_shmesh->numverts += numverts; + sh_shmesh->numindicies += numidx; +} static void SHM_TriangleFan(int numverts, vecV_t *verts, vec3_t lightorg, float pd) { int v, i, idxs; @@ -292,6 +349,8 @@ static void SH_FreeShadowMesh_(shadowmesh_t *sm) sm->indicies = NULL; Z_Free(sm->verts); sm->verts = NULL; + sm->numindicies = 0; + sm->numverts = 0; switch (qrenderer) { @@ -381,7 +440,7 @@ static void SHM_BeginShadowMesh(dlight_t *dl, int type) { /*this shouldn't happen too often*/ if (sh_shmesh) - { + { //FIXME: if the light is the same light, reuse the memory allocations where possible... SH_FreeShadowMesh(sh_shmesh); } @@ -628,6 +687,11 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node) if ((s*s+t*t+dot*dot) < maxdist) { SHM_Shadow_Cache_Surface(surf); + if (sh_shmesh->type == SMT_SHADOWMAP) + { + SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes); + continue; + } if (sh_shmesh->type != SMT_STENCILVOLUME) continue; @@ -977,7 +1041,10 @@ static void SHM_RecursiveWorldNodeQ3_r (dlight_t *dl, mnode_t *node) continue; surf->shadowframe = sh_shadowframe; + //FIXME: radius check SHM_Shadow_Cache_Surface(surf); + if (sh_shmesh->type == SMT_SHADOWMAP) + SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes); } return; } @@ -1314,8 +1381,23 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi else*/ { SHM_BeginShadowMesh(dl, type); + +#if 0 + { + int i; + msurface_t *surf; + for (i = 0; i < cl.worldmodel->numsurfaces; i+=2) + { + surf = &cl.worldmodel->surfaces[i]; + SHM_Shadow_Cache_Surface(surf); + SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes); + } + memset(sh_shmesh->litleaves, 0xff, sh_shmesh->leafbytes); + } +#else SHM_MarkLeavesQ1(dl, lvis); SHM_RecursiveWorldNodeQ1_r(dl, cl.worldmodel->nodes); +#endif } break; #ifdef Q2BSPS @@ -1328,11 +1410,26 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi #ifdef Q3BSPS case fg_quake3: /*q3 doesn't have edge info*/ - SHM_BeginShadowMesh(dl, true); + SHM_BeginShadowMesh(dl, type); + +#if 0 + { + int i; + msurface_t *surf; + for (i = 0; i < cl.worldmodel->numsurfaces; i++) + { + surf = &cl.worldmodel->surfaces[i]; + SHM_Shadow_Cache_Surface(surf); + SHM_MeshFrontOnly(surf->mesh->numvertexes, surf->mesh->xyz_array, surf->mesh->numindexes, surf->mesh->indexes); + } + memset(sh_shmesh->litleaves, 0xff, sh_shmesh->leafbytes); + } +#else sh_shadowframe++; SHM_RecursiveWorldNodeQ3_r(dl, cl.worldmodel->nodes); if (type == SMT_STENCILVOLUME) SHM_ComposeVolume_BruteForce(dl); +#endif break; #endif default: @@ -1342,11 +1439,6 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi /*generate edge polys for map types that need it (q1/q2)*/ switch (type) { - case SMT_SURFACES: - { - - } - break; case SMT_STENCILVOLUME: SHM_BeginQuads(); while(firstedge) @@ -1597,8 +1689,12 @@ static qboolean Sh_ScissorForBox(vec3_t mins, vec3_t maxs, srect_t *r) r->height = 1; r->dmin = 0; r->dmax = 1; - if (0)//!r_shadow_scissor.integer) + if (!r_shadow_scissor.ival) { + r->x = 0; + r->y = 0; + r->width = 1; + r->height = 1; return false; } /*if view is inside the box, then skip this maths*/ @@ -1928,8 +2024,12 @@ void GL_BeginRenderBuffer_DepthOnly(texid_t depthtexture) else qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadow_fbo_id); - if (TEXVALID(depthtexture)) - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depthtexture.num, 0); + if (shadow_fbo_depth_num != depthtexture.num) + { + shadow_fbo_depth_num = depthtexture.num; + if (TEXVALID(depthtexture)) + qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depthtexture.num, 0); + } } } #endif @@ -1946,9 +2046,37 @@ void GL_EndRenderBuffer_DepthOnly(texid_t depthtexture, int texsize) } } +//determine the 5 bounding points of a shadowmap light projection side +static void Sh_LightFrustumPlanes(dlight_t *l, vec4_t *planes, int face) +{ + vec3_t tmp; + int axis0, axis1, axis2; + int dir; + int i; + //+x,+y,+z,-x,-y,-z + axis0 = (face+0)%3; //our major axis + axis1 = (face+1)%3; + axis2 = (face+2)%3; + dir = (face >= 3)?-1:1; + + //center point is always the same + VectorCopy(l->origin, planes[4]); + VectorScale(l->axis[axis0], dir, planes[4]); + VectorNormalize(planes[4]); + planes[4][3] = r_shadow_shadowmapping_nearclip.value + DotProduct(planes[4], l->origin); + + for (i = 0; i < 4; i++) + { + VectorScale(l->axis[axis0], dir, tmp); + VectorMA(tmp, ((i&1)?1:-1), l->axis[axis1], tmp); + VectorMA(tmp, ((i&2)?1:-1), l->axis[axis2], planes[i]); + VectorNormalize(planes[i]); + planes[i][3] = DotProduct(planes[i], l->origin); + } +} + static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int smsize, float proj[16]) { - qboolean oxv; vec3_t t1,t2; texture_t *tex; int tno; @@ -1959,21 +2087,21 @@ static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int sms case 0: //+x - forward Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, l->axis[0], l->axis[1], l->axis[2], l->origin); - r_refdef.flipcull = false; + r_refdef.flipcull = 0; break; case 1: //+y - right VectorNegate(l->axis[0], t1); VectorNegate(l->axis[1], t2); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, t2, t1, l->axis[2], l->origin); - r_refdef.flipcull = true; + r_refdef.flipcull = SHADER_CULL_FLIP; break; case 2: //+z - down VectorNegate(l->axis[0], t1); VectorNegate(l->axis[2], t2); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, t2, l->axis[1], t1, l->origin); - r_refdef.flipcull = true; + r_refdef.flipcull = SHADER_CULL_FLIP; break; case 3: //-x - back @@ -1981,20 +2109,20 @@ static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int sms // VectorNegate(l->axis[1], t2); // VectorNegate(l->axis[2], t3); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, t1, l->axis[1], l->axis[2], l->origin); - r_refdef.flipcull = true; + r_refdef.flipcull = SHADER_CULL_FLIP; break; case 4: //-y - left VectorNegate(l->axis[1], t1); VectorNegate(l->axis[0], t2); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, l->axis[1], t2, l->axis[2], l->origin); - r_refdef.flipcull = false; + r_refdef.flipcull = 0; break; case 5: //-z - up VectorNegate(l->axis[0], t2); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, l->axis[2], l->axis[1], t2, l->origin); - r_refdef.flipcull = false; + r_refdef.flipcull = 0; break; } @@ -2005,8 +2133,6 @@ static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face, int sms qglViewport ((face%3 * SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2, ((face>=3)*SHADOWMAP_SIZE) + (SHADOWMAP_SIZE-smsize)/2, smsize, smsize); } - //fixme -GL_CullFace(0); R_SetFrustum(proj, r_refdef.m_view); #ifdef DBG_COLOURNOTDEPTH @@ -2014,15 +2140,16 @@ GL_CullFace(0); #else BE_SelectMode(BEM_DEPTHONLY); #endif - /*shadow meshes are always drawn as an external view*/ - oxv = r_refdef.externalview; - r_refdef.externalview = true; BE_SelectEntity(&r_worldentity); + GL_CullFace(SHADER_CULL_FRONT); + #ifdef GLQUAKE if (qrenderer == QR_OPENGL) - GLBE_RenderShadowBuffer(smesh->numverts, smesh->vebo[0], NULL, smesh->numindicies, smesh->vebo[1], NULL); + { + GLBE_RenderShadowBuffer(smesh->numverts, smesh->vebo[0], smesh->verts, smesh->numindicies, smesh->vebo[1], smesh->indicies); + } else #endif { @@ -2055,8 +2182,6 @@ GL_CullFace(0); break; } - r_refdef.externalview = oxv; - /* { int i; @@ -2083,14 +2208,57 @@ GL_CullFace(0); */ } -void Sh_GenShadowMap (dlight_t *l, qbyte *lvis) +qboolean Sh_GenShadowMap (dlight_t *l, qbyte *lvis, int smsize) { int f; - int smsize = SHADOWMAP_SIZE; float oproj[16], oview[16]; shadowmesh_t *smesh; int isspot = (l->fov != 0); - extern cvar_t temp1; + extern cvar_t r_shadow_shadowmapping_precision; + int sidevisible; + int oldflip = r_refdef.flipcull; + int oldexternalview = r_refdef.externalview; + + if (!R_CullSphere(l->origin, 0)) + sidevisible = l->fov?1:0x3f; //assume all are visible if the central point is onscreen + else + { + sidevisible = 0; + //FIXME: if the fov is < 90, we need to clip by the near lightplane first + for (f = 0; f < (l->fov?1:6); f++) + { + vec4_t planes[5]; + float dist; + int fp,lp; + Sh_LightFrustumPlanes(l, planes, f); + for (fp = 0; fp < FRUSTUMPLANES; fp++) + { + vec3_t nearest; + //make a guess based upon the frustum plane + VectorMA(l->origin, l->radius, frustum[fp].normal, nearest); + //clip that point to the various planes + + for(lp = 0; lp < 5; lp++) + { + dist = DotProduct(nearest, planes[lp]) - planes[lp][3]; + if (dist < 0) + VectorMA(nearest, dist, planes[lp], nearest); + } + +// P_RunParticleEffect(nearest, vec3_origin, 15, 1); + //give up if the best point for any frustum plane is offscreen + dist = DotProduct(frustum[fp].normal, nearest) - frustum[fp].dist; + if (dist <= 0) + break; + } + if (fp == FRUSTUMPLANES) + sidevisible |= 1u<fov) - { - Matrix4x4_CM_Projection_Far(r_refdef.m_projection, l->fov, l->fov, nearplane, l->radius); - if (!gl_config.nofixedfunc) - { - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(r_refdef.m_projection); - qglMatrixMode(GL_MODELVIEW); - } - /*single face*/ - Sh_GenShadowFace(l, smesh, 0, smsize, r_refdef.m_projection); + Matrix4x4_CM_Projection_Far(r_refdef.m_projection, l->fov?l->fov:90, l->fov?l->fov:90, r_shadow_shadowmapping_nearclip.value, l->radius); + if (!gl_config.nofixedfunc) + { + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf(r_refdef.m_projection); + qglMatrixMode(GL_MODELVIEW); } - else - { - Matrix4x4_CM_Projection_Far(r_refdef.m_projection, 90, 90, nearplane, l->radius); - if (!gl_config.nofixedfunc) - { - qglMatrixMode(GL_PROJECTION); - qglLoadMatrixf(r_refdef.m_projection); - qglMatrixMode(GL_MODELVIEW); - } - /*generate faces*/ - for (f = 0; f < 6; f++) + r_refdef.externalview = true; //never any viewmodels + + /*generate faces*/ + for (f = 0; f < 6; f++) + { + if (sidevisible & (1u<origin, l->radius)) { - bench.numfrustumculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_FRUSTUM, 1); return; //this should be the more common case } @@ -2219,7 +2383,7 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, qbyte *vvis) if (Sh_ScissorForBox(mins, maxs, &rect)) { - bench.numscissorculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_SCISSOR, 1); return; } @@ -2231,8 +2395,8 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, qbyte *vvis) //fixme: check head node first? if (!Sh_LeafInView(l->worldshadowmesh->litleaves, vvis)) { - bench.numpvsculled++; - return; + RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); + return; } } else @@ -2242,7 +2406,7 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, qbyte *vvis) lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb)); if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. { - bench.numpvsculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); return; } } @@ -2250,19 +2414,37 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, qbyte *vvis) else lvis = NULL; - BE_Scissor(NULL); - Sh_GenShadowMap(l, lvis); + if (l->fov != 0) + smsize = SHADOWMAP_SIZE; + else + { + //Stolen from DP. Actually, LH pasted it to me in IRC. + vec3_t nearestpoint; + vec3_t d; + float distance, lodlinear; + nearestpoint[0] = bound(l->origin[0]-l->radius, r_origin[0], l->origin[0]+l->radius); + nearestpoint[1] = bound(l->origin[1]-l->radius, r_origin[1], l->origin[1]+l->radius); + nearestpoint[2] = bound(l->origin[2]-l->radius, r_origin[2], l->origin[2]+l->radius); + VectorSubtract(nearestpoint, r_origin, d); + distance = VectorLength(d); + lodlinear = (l->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / l->radius)); + smsize = bound(16, lodlinear, SHADOWMAP_SIZE); + } - bench.numlights++; + if (!BE_SelectDLight(l, colour, l->fov?LSHADER_SPOT:LSHADER_SMAP)) + return; //can't get a shader loaded + if (!Sh_GenShadowMap(l, lvis, smsize)) + return; + + RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1); //may as well use scissors BE_Scissor(&rect); BE_SelectEntity(&r_worldentity); - GLBE_SelectDLight(l, colour); - BE_SelectMode(l->fov?BEM_SMAPLIGHTSPOT:BEM_SMAPLIGHT); + BE_SelectMode(BEM_LIGHT); Sh_DrawEntLighting(l, colour); } @@ -2322,7 +2504,9 @@ static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour) tex = cl.worldmodel->shadowbatches[tno].tex; if (tex->shader->flags & SHADER_NODLIGHT) continue; + //FIXME: it may be worth building a dedicated ebo BE_DrawMesh_List(tex->shader, sm->batches[tno].count, sm->batches[tno].s, cl.worldmodel->shadowbatches[tno].vbo, &tex->shader->defaulttextures, 0); + RQuantAdd(RQUANT_LITFACES, sm->batches[tno].count); } switch(qrenderer) @@ -2504,10 +2688,9 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q if (ent->flags & (RF_NOSHADOW|Q2RF_BEAM)) continue; - { - if (ent->keynum == dl->key && ent->keynum) - continue; - } + if (ent->keynum == dl->key && ent->keynum) + continue; + if (!ent->model) continue; @@ -2553,7 +2736,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis) if (R_CullSphere(dl->origin, dl->radius)) { - bench.numfrustumculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_FRUSTUM, 1); return false; //this should be the more common case } @@ -2570,7 +2753,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis) //fixme: check head node first? if (!Sh_LeafInView(dl->worldshadowmesh->litleaves, vvis)) { - bench.numpvsculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); return false; } lvis = NULL; @@ -2582,7 +2765,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis) if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. { - bench.numpvsculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); return false; } } @@ -2590,12 +2773,12 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, qbyte *vvis) //sets up the gl scissor (and culls to view) if (Sh_ScissorForBox(mins, maxs, &rect)) { - bench.numscissorculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_SCISSOR, 1); return false; //this doesn't cull often. } - bench.numlights++; + RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1); - BE_SelectDLight(dl, colour); + BE_SelectDLight(dl, colour, LSHADER_STANDARD); BE_SelectMode(BEM_STENCIL); //The backend doesn't maintain scissor state. @@ -2786,7 +2969,7 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis) if (R_CullSphere(dl->origin, dl->radius)) { - bench.numfrustumculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_FRUSTUM, 1); return; //this should be the more common case } @@ -2795,7 +2978,7 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis) //fixme: check head node first? if (!Sh_LeafInView(dl->worldshadowmesh->litleaves, vvis)) { - bench.numpvsculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); return; } } @@ -2812,7 +2995,7 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis) if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. { - bench.numpvsculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1); return; } } @@ -2829,16 +3012,16 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, qbyte *vvis) //sets up the gl scissor (actually just culls to view) if (Sh_ScissorForBox(mins, maxs, &rect)) { - bench.numscissorculled++; + RQuantAdd(RQUANT_RTLIGHT_CULL_SCISSOR, 1); return; //was culled. } //should we actually scissor here? there's not really much point I suppose. BE_Scissor(NULL); - bench.numlights++; + RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1); - BE_SelectDLight(dl, colour); + BE_SelectDLight(dl, colour, LSHADER_STANDARD); BE_SelectMode(BEM_LIGHT); Sh_DrawEntLighting(dl, colour); } @@ -2918,7 +3101,7 @@ void Sh_DrawCrepuscularLight(dlight_t *dl, float *colours) GLBE_RenderToTexture(r_nulltex, r_nulltex, crepuscular_texture_id, r_nulltex, false); BE_SelectMode(BEM_CREPUSCULAR); - BE_SelectDLight(dl, colours); + BE_SelectDLight(dl, colours, LSHADER_STANDARD); GLBE_SubmitMeshes(true, SHADER_SORT_PORTAL, SHADER_SORT_BLEND); GLBE_RenderToTexture(crepuscular_texture_id, r_nulltex, r_nulltex, r_nulltex, false); @@ -2949,7 +3132,7 @@ void Sh_PreGenerateLights(void) { unsigned int ignoreflags; dlight_t *dl; - qboolean shadow; + int shadowtype; int leaf; qbyte *lvis; qbyte lvisb[MAX_MAP_LEAFS/8]; @@ -2957,7 +3140,8 @@ void Sh_PreGenerateLights(void) if (r_shadow_realtime_dlight.ival || r_shadow_realtime_world.ival) { - R_LoadRTLights(); + if (rtlights_first == rtlights_max) + R_LoadRTLights(); if (rtlights_first == rtlights_max) R_ImportRTLights(cl.worldmodel->entities); } @@ -2966,25 +3150,34 @@ void Sh_PreGenerateLights(void) for (dl = cl_dlights+rtlights_first, i=rtlights_first; iradius) - continue; //dead + if (dl->radius) + { + if (dl->flags & ignoreflags) + { + if (dl->flags & LFLAG_CREPUSCULAR) + continue; - if (!(dl->flags & ignoreflags)) - continue; + if (((!dl->die)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || dl->flags & LFLAG_NOSHADOWS) + shadowtype = SMT_SHADOWLESS; + else if (dl->flags & LFLAG_SHADOWMAP || r_shadow_shadowmapping.ival) + shadowtype = SMT_SHADOWMAP; + else + shadowtype = SMT_STENCILVOLUME; - if (dl->flags & LFLAG_CREPUSCULAR) - continue; - else if (((!dl->die)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || dl->flags & LFLAG_NOSHADOWS) - shadow = false; - else if (dl->flags & LFLAG_SHADOWMAP) - shadow = false; - else - shadow = true; + leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin); + lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb)); - leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin); - lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb)); + SHM_BuildShadowMesh(dl, lvis, NULL, shadowtype); + continue; + } + } - SHM_BuildShadowMesh(dl, lvis, NULL, !shadow); + if (dl->worldshadowmesh) + { + SH_FreeShadowMesh(dl->worldshadowmesh); + dl->worldshadowmesh = NULL; + dl->rebuildcache = true; + } } } @@ -3004,10 +3197,6 @@ void Sh_DrawLights(qbyte *vis) dlight_t *dl; int i; unsigned int ignoreflags; - extern cvar_t r_shadow_realtime_world, r_shadow_realtime_dlight; - extern cvar_t r_shadow_realtime_world_shadows, r_shadow_realtime_dlight_shadows; - extern cvar_t r_sun_dir, r_sun_colour; - extern cvar_t r_shadow_shadowmapping; if (!r_shadow_realtime_world.ival && !r_shadow_realtime_dlight.ival) { @@ -3149,3 +3338,41 @@ void Sh_DrawLights(qbyte *vis) // memset(&bench, 0, sizeof(bench)); } #endif + +//stencil shadows generally require that the farclip distance is really really far away +//so this little function is used to check if its needed or not. +qboolean Sh_StencilShadowsActive(void) +{ +#ifdef RTLIGHTS + //if shadowmapping is forced on all lights then we don't need special depth stuff +// if (r_shadow_shadowmapping.ival) +// return false; + + return (r_shadow_realtime_dlight.ival && r_shadow_realtime_dlight_shadows.ival) || + (r_shadow_realtime_world.ival && r_shadow_realtime_world_shadows.ival); +#else + return false; +#endif +} + +void Sh_RegisterCvars(void) +{ +#ifdef RTLIGHTS +#define REALTIMELIGHTING "Realtime Lighting" + Cvar_Register (&r_shadow_scissor, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_world, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_world_shadows, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_dlight, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_dlight_ambient, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_dlight_diffuse, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_dlight_specular, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_dlight_shadows, REALTIMELIGHTING); + Cvar_Register (&r_shadow_realtime_world_lightmaps, REALTIMELIGHTING); + Cvar_Register (&r_shadow_shadowmapping, REALTIMELIGHTING); + Cvar_Register (&r_shadow_shadowmapping_precision, REALTIMELIGHTING); + Cvar_Register (&r_shadow_shadowmapping_nearclip, REALTIMELIGHTING); + Cvar_Register (&r_shadow_shadowmapping_bias, REALTIMELIGHTING); + Cvar_Register (&r_sun_dir, REALTIMELIGHTING); + Cvar_Register (&r_sun_colour, REALTIMELIGHTING); +#endif +} \ No newline at end of file diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 388856b6f..bf6c62905 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1292,11 +1292,13 @@ GLhandleARB GLSlang_CreateShader (char *name, int ver, char **precompilerconstan if (gl_config.nofixedfunc) { prstrings[strings] = - "attribute vec3 v_position;\n" + "attribute vec3 v_position1;\n" "#ifdef FRAMEBLEND\n" "attribute vec3 v_position2;\n" "uniform vec2 e_vblend;\n" "#define v_position ((v_position*e_vblend.x)+(v_position2*e_vblend.y))\n" + "#else\n" + "#define v_position v_position1\n" "#endif\n" "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" "uniform mat4 m_modelviewprojection;\n" @@ -1429,14 +1431,18 @@ GLhandleARB GLSlang_CreateProgramObject (char *name, GLhandleARB vert, GLhandleA qglBindAttribLocationARB(program, VATTR_VERTEX1, "v_position"); qglBindAttribLocationARB(program, VATTR_COLOUR, "v_colour"); +#if MAXRLIGHTMAPS > 1 qglBindAttribLocationARB(program, VATTR_COLOUR2, "v_colour2"); qglBindAttribLocationARB(program, VATTR_COLOUR3, "v_colour3"); qglBindAttribLocationARB(program, VATTR_COLOUR4, "v_colour4"); +#endif qglBindAttribLocationARB(program, VATTR_TEXCOORD, "v_texcoord"); qglBindAttribLocationARB(program, VATTR_LMCOORD, "v_lmcoord"); +#if MAXRLIGHTMAPS > 1 qglBindAttribLocationARB(program, VATTR_LMCOORD2, "v_lmcoord2"); qglBindAttribLocationARB(program, VATTR_LMCOORD3, "v_lmcoord3"); qglBindAttribLocationARB(program, VATTR_LMCOORD4, "v_lmcoord4"); +#endif qglBindAttribLocationARB(program, VATTR_NORMALS, "v_normal"); qglBindAttribLocationARB(program, VATTR_SNORMALS, "v_svector"); qglBindAttribLocationARB(program, VATTR_TNORMALS, "v_tvector"); diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index ca5a32f62..63263711a 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -844,16 +844,8 @@ static qboolean CreateMainWindow(rendererstate_t *info) qboolean stat; if (!info->fullscreen) { - if (_windowed_mouse.value && (key_dest == key_game || key_dest == key_menu)) - { - TRACE(("dbg: GLVID_SetMode: VID_SetWindowedMode\n")); - stat = VID_SetWindowedMode(info); - } - else - { - TRACE(("dbg: GLVID_SetMode: VID_SetWindowedMode 2\n")); - stat = VID_SetWindowedMode(info); - } + TRACE(("dbg: GLVID_SetMode: VID_SetWindowedMode\n")); + stat = VID_SetWindowedMode(info); } else { diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index fab4f261b..bac2642a3 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -120,16 +120,13 @@ void GL_DoSwap (void) { if (!_windowed_mouse.value) { - if (mouseactive) - { - IN_DeactivateMouse (); - } + IN_DeactivateMouse (); } else { - if ((key_dest == key_game||mouseusedforgui) && ActiveApp) + if (!Key_MouseShouldBeFree() && ActiveApp) IN_ActivateMouse (); - else if (!(key_dest == key_game || mouseusedforgui) || !ActiveApp) + else IN_DeactivateMouse (); } } diff --git a/engine/gl/ltface.c b/engine/gl/ltface.c index 009bb8b70..ee9a64eaf 100644 --- a/engine/gl/ltface.c +++ b/engine/gl/ltface.c @@ -302,8 +302,8 @@ towards the center until it is valid. typedef struct { - vec3_t lightmaps[MAXLIGHTMAPS][SINGLEMAP]; - vec3_t lightnorm[MAXLIGHTMAPS][SINGLEMAP]; + vec3_t lightmaps[MAXQ1LIGHTMAPS][SINGLEMAP]; + vec3_t lightnorm[MAXQ1LIGHTMAPS][SINGLEMAP]; int numlightstyles; vec_t *light; vec_t facedist; @@ -628,7 +628,7 @@ static void SingleLightFace (mentity_t *light, llightinfo_t *l) norms = l->lightnorm[mapnum]; if (mapnum == l->numlightstyles) { // init a new light map - if (mapnum == MAXLIGHTMAPS) + if (mapnum == MAXQ1LIGHTMAPS) { printf ("WARNING: Too many light styles on a face\n"); return; @@ -715,7 +715,7 @@ static void FixMinlight (llightinfo_t *l) } if (i == l->numlightstyles) { - if (l->numlightstyles == MAXLIGHTMAPS) + if (l->numlightstyles == MAXQ1LIGHTMAPS) return; // oh well.. for (j=0 ; jnumsurfpt ; j++) { @@ -819,7 +819,7 @@ void LightFace (int surfnum) if (size > SINGLEMAP) Error ("Bad lightmap size"); - for (i=0 ; istyles[j] = 255; #endif // // save out the values // - for (i=0 ; i styles[i] = l.lightstyles[i]; diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 1659e77e2..6bd30a48f 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -354,6 +354,34 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "gl_FragColor.rgb = (solid.rgb*(1.0-clouds.a)) + (clouds.a*clouds.rgb);\n" "}\n" "#endif\n" +}, +#endif +#ifdef GLQUAKE +{QR_OPENGL, 110, "depthonly", +"!!permu FRAMEBLEND\n" +"!!permu SKELETAL\n" + +//standard shader used for drawing shadowmap depth. +//also used for masking off portals and other things that want depth and no colour. +//must support skeletal and 2-way vertex blending or Bad Things Will Happen. +//the vertex shader is responsible for calculating lighting values. + +"#ifdef VERTEX_SHADER\n" +"#include \"sys/skeletal.h\"\n" +"void main ()\n" +"{\n" +"gl_Position = skeletaltransform();\n" +"}\n" +"#endif\n" + +"#ifdef FRAGMENT_SHADER\n" +"void main ()\n" +"{\n" +//must always draw something, supposedly. It might as well be black. +"gl_FragColor = vec4(0, 0, 0, 1);\n" +"}\n" +"#endif\n" + }, #endif #ifdef GLQUAKE @@ -979,7 +1007,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(BUMP) && (defined(OFFSETMAPPING) || defined(DELUXE) || defined(SPECULAR))\n" "uniform sampler2D s_t2; //normal.rgb+height.a\n" "#endif\n" +"#ifdef DELUXE\n" "uniform sampler2D s_t3; //deluxe0\n" +"#endif\n" "#ifdef FULLBRIGHT\n" "uniform sampler2D s_t4; //fullbright\n" "#endif\n" @@ -1271,46 +1301,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" }, #endif -#ifdef D3D11QUAKE -{QR_DIRECT3D11, 11, "defaultgammacb", -//this shader is applies gamma/contrast/brightness to the source image, and dumps it out. - -"struct a2v\n" -"{\n" -"float4 pos: POSITION;\n" -"float2 tc: TEXCOORD0;\n" -"float4 vcol: COLOR0;\n" -"};\n" -"struct v2f\n" -"{\n" -"float4 pos: SV_POSITION;\n" -"float2 tc: TEXCOORD0;\n" -"float4 vcol: COLOR0;\n" -"};\n" - -"#include \n" - -"#ifdef VERTEX_SHADER\n" -"v2f main (a2v inp)\n" -"{\n" -"v2f outp;\n" -"outp.pos = mul(m_projection, inp.pos);\n" -"outp.tc = inp.tc;\n" -"outp.vcol = inp.vcol;\n" -"return outp;\n" -"}\n" -"#endif\n" - -"#ifdef FRAGMENT_SHADER\n" -"Texture2D shaderTexture;\n" -"SamplerState SampleType;\n" -"float4 main (v2f inp) : SV_TARGET\n" -"{\n" -"return pow(shaderTexture.Sample(SampleType, inp.tc) * inp.vcol.g, inp.vcol.r) + inp.vcol.b;\n" -"}\n" -"#endif\n" -}, -#endif #ifdef GLQUAKE {QR_OPENGL, 110, "drawflat_wall", "!!cvarv r_floorcolor\n" @@ -1601,10 +1591,13 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #ifdef GLQUAKE {QR_OPENGL, 110, "rtlight", "!!permu BUMP\n" +"!!permu FRAMEBLEND\n" "!!permu SKELETAL\n" "!!permu UPPERLOWER\n" "!!permu FOG\n" "!!cvarf r_glsl_offsetmapping_scale\n" +"!!cvardf r_glsl_pcf\n" + //this is the main shader responsible for realtime dlights. @@ -1612,10 +1605,18 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //s0=diffuse, s1=normal, s2=specular, s3=shadowmap //custom modifiers: //PCF(shadowmap) -//CUBE(projected cubemap) +//CUBEPROJ(projected cubemap) //SPOT(projected circle //CUBESHADOW +"#ifndef r_glsl_pcf\n" +"#error r_glsl_pcf wasn't defined\n" +"#endif\n" +"#if r_glsl_pcf < 1\n" +"#undef r_glsl_pcf\n" +"#define r_glsl_pcf 9\n" +"#endif\n" + "#if 0 && defined(GL_ARB_texture_gather) && defined(PCF) \n" "#extension GL_ARB_texture_gather : enable\n" "#endif\n" @@ -1635,9 +1636,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#if defined(PCF) || defined(CUBE) || defined(SPOT)\n" "varying vec4 vtexprojcoord;\n" "uniform mat4 l_cubematrix;\n" -"#ifndef SPOT\n" -"uniform mat4 l_projmatrix;\n" -"#endif\n" "#endif\n" "#ifdef VERTEX_SHADER\n" "#include \"sys/skeletal.h\"\n" @@ -1709,68 +1707,65 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform vec3 l_lightcolour;\n" "uniform vec3 l_lightcolourscale;\n" "#ifdef PCF\n" -"uniform vec4 l_shadowmapinfo; //xy are the texture scale, z is 1, w is the scale.\n" +"uniform vec4 l_shadowmapproj; //light projection matrix info\n" +"uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.\n" "#endif\n" + "#ifdef PCF\n" -//#define shadow2DProj(t,c) (vec2(1.0,1.0)) -//#define shadow2DProj(t,c) texture2DProj(t,c).rg - -"float ShadowmapFilter(void)\n" +"vec3 ShadowmapCoord(void)\n" "{\n" -//dehomogonize input -"vec3 shadowcoord = (vtexprojcoord.xyz / vtexprojcoord.w);\n" - -"#ifdef CUBESHADOW\n" -// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w; -// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r -"#else\n" - "#ifdef SPOT\n" //bias it. don't bother figuring out which side or anything, its not needed //l_projmatrix contains the light's projection matrix so no other magic needed -"shadowcoord.xyz = (shadowcoord.xyz + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n" +"vtexprojcoord.z -= 0.015;\n" +"return (vtexprojcoord.xyz/vtexprojcoord.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n" +//#elif defined(CUBESHADOW) +// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w; +// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r "#else\n" //figure out which axis to use //texture is arranged thusly: //forward left up //back right down -"vec3 dir = abs(shadowcoord);\n" +"vec3 dir = abs(vtexprojcoord.xyz);\n" //assume z is the major axis (ie: forward from the light) -"vec3 t = shadowcoord;\n" +"vec3 t = vtexprojcoord.xyz;\n" "float ma = dir.z;\n" -"vec3 axis = vec3(1.0, 1.0, 1.0);\n" +"vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);\n" "if (dir.x > ma)\n" "{\n" "ma = dir.x;\n" -"t = shadowcoord.zyx;\n" -"axis.x = 3.0;\n" +"t = vtexprojcoord.zyx;\n" +"axis.x = 0.5;\n" "}\n" "if (dir.y > ma)\n" "{\n" "ma = dir.y;\n" -"t = shadowcoord.xzy;\n" -"axis.x = 5.0;\n" +"t = vtexprojcoord.xzy;\n" +"axis.x = 2.5/3.0;\n" "}\n" +//if the axis is negative, flip it. "if (t.z > 0.0)\n" "{\n" -"axis.y = 3.0;\n" +"axis.y = 1.5/2.0;\n" "t.z = -t.z;\n" "}\n" - //we also need to pass the result through the light's projection matrix too -"vec4 nsc =l_projmatrix*vec4(t, 1.0);\n" -"shadowcoord = (nsc.xyz / nsc.w);\n" - -//scale to match the light's precision and pinch inwards, so we never sample over the edge -"shadowcoord.st *= l_shadowmapinfo.w * (1.0-l_shadowmapinfo.st);\n" - -//now bias and relocate it -"shadowcoord = (shadowcoord + axis.xyz) * vec3(0.5/3.0, 0.5/2.0, 0.5);\n" +//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4. +//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image +//the resulting z is prescaled to result in a value between -0.5 and 0.5. +//also make sure we're in the right quadrant type thing +"return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);\n" "#endif\n" +"}\n" + +"float ShadowmapFilter(void)\n" +"{\n" +"vec3 shadowcoord = ShadowmapCoord();\n" "#if 0//def GL_ARB_texture_gather\n" "vec2 ipart, fpart;\n" @@ -1787,8 +1782,19 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.\n" "#else\n" -"#define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapinfo.xyz)).r\n" +"#define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n" "float s = 0.0;\n" +"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n" +"s += dosamp(0.0, 0.0);\n" +"return s;\n" +"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n" +"s += dosamp(-1.0, 0.0);\n" +"s += dosamp(0.0, -1.0);\n" +"s += dosamp(0.0, 0.0);\n" +"s += dosamp(0.0, 1.0);\n" +"s += dosamp(1.0, 0.0);\n" +"return s/5.0;\n" +"#else\n" "s += dosamp(-1.0, -1.0);\n" "s += dosamp(-1.0, 0.0);\n" "s += dosamp(-1.0, 1.0);\n" diff --git a/engine/gl/shader.h b/engine/gl/shader.h index a26bbc460..6f8391036 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -305,7 +305,9 @@ enum{ PERMUTATION_SKELETAL = 16, PERMUTATION_FOG = 32, PERMUTATION_FRAMEBLEND = 64, +#if MAXRLIGHTMAPS > 1 PERMUTATION_LIGHTSTYLES = 128, +#endif PERMUTATIONS = 256 }; @@ -321,12 +323,14 @@ enum shaderattribs_e VATTR_TNORMALS, VATTR_BONENUMS, /*skeletal only*/ VATTR_BONEWEIGHTS, /*skeletal only*/ +#if MAXRLIGHTMAPS > 1 VATTR_LMCOORD2, VATTR_LMCOORD3, VATTR_LMCOORD4, VATTR_COLOUR2, VATTR_COLOUR3, VATTR_COLOUR4, +#endif VATTR_LEG_VERTEX, //note: traditionally this is actually index 0. @@ -381,9 +385,9 @@ typedef struct { SP_LIGHTCOLOURSCALE, SP_LIGHTPOSITION, SP_LIGHTSCREEN, - SP_LIGHTPROJMATRIX, SP_LIGHTCUBEMATRIX, - SP_LIGHTSHADOWMAPINFO, + SP_LIGHTSHADOWMAPPROJ, + SP_LIGHTSHADOWMAPSCALE, //things that are set immediatly SP_FIRSTIMMEDIATE, //never set @@ -459,6 +463,7 @@ struct shader_s polyoffset_t polyoffset; + #define SHADER_CULL_FLIP (SHADER_CULL_FRONT|SHADER_CULL_BACK) enum { SHADER_SKY = 1 << 0, SHADER_NOMIPMAPS = 1 << 1, @@ -547,6 +552,15 @@ mfog_t *CM_FogForOrigin(vec3_t org); #define BEF_FORCECOLOURMOD 256 //q3 shaders default to 'rgbgen identity', and ignore ent colours. this forces ent colours to be considered #define BEF_LINES 512 //draw line pairs instead of triangles. +enum +{ + LSHADER_STANDARD, //stencil or shadowless + LSHADER_CUBE, //has a cubemap + LSHADER_SMAP, //shadowmap + LSHADER_SPOT, //spotlight+shadowmap + LSHADER_MODES +}; + #ifdef GLQUAKE void GLBE_Init(void); void GLBE_Shutdown(void); @@ -561,7 +575,7 @@ void GLBE_UploadAllLightmaps(void); void GLBE_DrawWorld (qboolean drawworld, qbyte *vis); qboolean GLBE_LightCullModel(vec3_t org, model_t *model); void GLBE_SelectEntity(entity_t *ent); -void GLBE_SelectDLight(dlight_t *dl, vec3_t colour); +qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, unsigned int lmode); void GLBE_Scissor(srect_t *rect); void GLBE_SubmitMeshes (qboolean drawworld, int start, int stop); void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destcol, texid_t destdepth, qboolean usedepth); @@ -631,6 +645,7 @@ void BE_DrawNonWorld (void); //Builds a hardware shader from the software representation void BE_GenerateProgram(shader_t *shader); +void Sh_RegisterCvars(void); #ifdef RTLIGHTS // void GLBE_PushOffsetShadow(qboolean foobar); @@ -648,6 +663,9 @@ void SH_FreeShadowMesh(struct shadowmesh_s *sm); void Sh_Shutdown(void); //resize any textures to match new screen resize void Sh_Reset(void); +qboolean Sh_StencilShadowsActive(void); +#else +#define Sh_StencilShadowsActive() false #endif struct shader_field_names_s diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index b9a743ac2..8d74a9ad0 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -84,6 +84,12 @@ qboolean DL_Decide(struct dl_download *dl) if (!*url) url = dl->url; + if (dl->postdata) + { + DL_Abort(dl); + return false; //safe to destroy it now + } + if (dl->ctx) { if (dl->status == DL_FAILED || dl->status == DL_FINISHED) @@ -222,6 +228,12 @@ qboolean DL_Decide(struct dl_download *dl) if (!*url) url = dl->url; + if (dl->postdata) + { + DL_Abort(dl); + return false; //safe to destroy it now + } + if (dl->ctx) { if (dl->status == DL_FAILED || dl->status == DL_FINISHED) @@ -263,7 +275,7 @@ It doesn't use persistant connections. struct http_dl_ctx_s { struct dl_download *dlctx; - SOCKET sock; + SOCKET sock; //FIXME: support https. char *buffer; @@ -693,15 +705,38 @@ void HTTPDL_Establish(struct dl_download *dl) return; } - ExpandBuffer(con, 512*1024); - sprintf(con->buffer, - "GET %s HTTP/1.1\r\n" - "Host: %s\r\n" - "Connection: close\r\n" - "Accept-Encoding: gzip\r\n" - "User-Agent: "FULLENGINENAME"\r\n" - "\r\n", uri, server); - con->bufferused = strlen(con->buffer); + if (dl->postdata) + { + ExpandBuffer(con, 1024 + strlen(uri) + strlen(server) + strlen(con->dlctx->postmimetype) + dl->postlen); + Q_snprintfz(con->buffer, con->bufferlen, + "POST %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Content-Length: %i\r\n" + "Content-Type: %s\r\n" + "Connection: close\r\n" +#ifndef NPFTE + "Accept-Encoding: gzip\r\n" +#endif + "User-Agent: "FULLENGINENAME"\r\n" + "\r\n", uri, server, dl->postlen, dl->postmimetype); + con->bufferused = strlen(con->buffer); + memcpy(con->buffer + con->bufferused, dl->postdata, dl->postlen); + con->bufferused += dl->postlen; + } + else + { + ExpandBuffer(con, 512*1024); + Q_snprintfz(con->buffer, con->bufferlen, + "GET %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Connection: close\r\n" +#ifndef NPFTE + "Accept-Encoding: gzip\r\n" +#endif + "User-Agent: "FULLENGINENAME"\r\n" + "\r\n", uri, server); + con->bufferused = strlen(con->buffer); + } con->contentlength = -1; } @@ -850,6 +885,8 @@ void DL_Close(struct dl_download *dl) dl->abort(dl); if (dl->file) VFS_CLOSE(dl->file); + if (dl->postdata) + BZ_Free(dl->postdata); free(dl); } @@ -876,6 +913,20 @@ struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*N return newdl; } +struct dl_download *HTTP_CL_Put(const char *url, const char *mime, const char *data, size_t datalen, void (*NotifyFunction)(struct dl_download *dl)) +{ + struct dl_download *dl; + if (!*mime) + return NULL; + + dl = HTTP_CL_Get(url, NULL, NotifyFunction); + Q_strncpyz(dl->postmimetype, mime, sizeof(dl->postmimetype)); + dl->postdata = BZ_Malloc(datalen); + memcpy(dl->postdata, data, datalen); + dl->postlen = datalen; + return dl; +} + void HTTP_CL_Think(void) { struct dl_download *dl = activedownloads; diff --git a/engine/http/iweb.h b/engine/http/iweb.h index ee06c152d..cb9d69dbb 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -113,6 +113,10 @@ struct dl_download char localname[MAX_OSPATH]; /*leave empty for a temp file*/ struct vfsfile_s *file; /*downloaded to, if not already set when starting will open localname or a temp file*/ + char postmimetype[64]; + char *postdata; /*if set, this is a post and not a get*/ + size_t postlen; + /*stream status*/ enum { @@ -143,6 +147,7 @@ struct dl_download void HTTP_CL_Think(void); struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*NotifyFunction)(struct dl_download *dl)); +struct dl_download *HTTP_CL_Put(const char *url, const char *mime, const char *data, size_t datalen, void (*NotifyFunction)(struct dl_download *dl)); struct dl_download *DL_Create(const char *url); qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyFunction)(struct dl_download *dl)); diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index aaf4dc561..d5a5fbe8a 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -785,6 +785,11 @@ struct edict_s *PDECL ProgsToEdict (pubprogfuncs_t *ppf, int progs) if ((unsigned)progs >= (unsigned)maxedicts) { printf("Bad entity index %i\n", progs); + if (pr_depth) + { + PR_StackTrace (ppf); +// progfuncs->funcs.pr_trace += 1; + } progs = 0; } return (struct edict_s *)PROG_TO_EDICT(progfuncs.inst, progs); diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index aca6f7f5f..1117c4038 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -643,15 +643,17 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, char *key, eval_t **result, etype_ return false; if (c)*c = '\0'; - c2 = COM_TrimString(c2); - def = ED_FindLocalOrGlobal(progfuncs, c2, &fval); - if (def && def->type == ev_field) + fdef = ED_FindField(progfuncs, c2); + if (!fdef) { - fofs = fval->_int + progfuncs->funcs.fieldadjust; - fdef = ED_FieldAtOfs(progfuncs, fofs); + c2 = COM_TrimString(c2); + def = ED_FindLocalOrGlobal(progfuncs, c2, &fval); + if (def && def->type == ev_field) + { + fofs = fval->_int + progfuncs->funcs.fieldadjust; + fdef = ED_FieldAtOfs(progfuncs, fofs); + } } - else - fdef = ED_FindField(progfuncs, c2); if (c)*c = '.'; if (!fdef) @@ -934,11 +936,12 @@ int PDECL PR_ToggleBreakpoint(pubprogfuncs_t *ppf, char *filename, int linenum, if (!pr_progstate[pn].linenums) continue; + //we need to use the function table in order to set breakpoints in the right file. for (f = pr_progstate[pn].functions, fl = 0; fl < pr_progstate[pn].progs->numfunctions; f++, fl++) { if (!stricmp(f->s_file+progfuncs->funcs.stringtable, filename)) { - for (i = f->first_statement; ; i++) + for (i = f->first_statement; i < pr_progstate[pn].progs->numstatements; i++) { if (pr_progstate[pn].linenums[i] >= linenum) { diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 8af702a87..56ea5818e 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -655,7 +655,7 @@ pbool QCC_PR_Precompiler(void) msg[a] = '\0'; - QCC_PR_SkipToEndOfLine(true); + QCC_PR_SkipToEndOfLine(false); QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg); } @@ -667,7 +667,7 @@ pbool QCC_PR_Precompiler(void) msg[a-1] = '\0'; - QCC_PR_SkipToEndOfLine(true); + QCC_PR_SkipToEndOfLine(false); QCC_PR_ParseWarning(WARN_PRECOMPILERMESSAGE, "#warning: %s", msg); } @@ -693,7 +693,7 @@ pbool QCC_PR_Precompiler(void) msg[a-1] = '\0'; - QCC_PR_SkipToEndOfLine(true); + QCC_PR_SkipToEndOfLine(false); if (strlen(msg) >= sizeof(QCC_copyright)) QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); @@ -732,13 +732,6 @@ pbool QCC_PR_Precompiler(void) ForcedCRC = QCC_PR_LexInteger(); - pr_file_p++; - - for (a = 0; a < sizeof(msg)-1 && pr_file_p[a] != '\n' && pr_file_p[a] != '\0'; a++) - msg[a] = pr_file_p[a]; - - msg[a-1] = '\0'; - QCC_PR_SkipToEndOfLine(true); } else if (!strncmp(directive, "includelist", 11)) diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 35dd3e49d..37522b37b 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -2643,18 +2643,6 @@ static void QCBUILTIN PF_vhlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_ G_FLOAT(OFS_RETURN) = newv; } -static void QCBUILTIN PF_anglemod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) -{ - float v = G_FLOAT(OFS_PARM0); - - while (v >= 360) - v = v - 360; - while (v < 0) - v = v + 360; - - G_FLOAT(OFS_RETURN) = v; -} - /* ================= PF_particle @@ -9768,7 +9756,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"uri_escape", PF_uri_escape, 0, 0, 0, 510, "string(string in)"},//DP_QC_URI_ESCAPE {"uri_unescape", PF_uri_unescape, 0, 0, 0, 511, "string(string in)"},//DP_QC_URI_ESCAPE {"num_for_edict", PF_num_for_edict, 0, 0, 0, 512, "float(entity ent)"},//DP_QC_NUM_FOR_EDICT - {"uri_get", PF_uri_get, 0, 0, 0, 513, "float(string uril, float id)"},//DP_QC_URI_GET + {"uri_get", PF_uri_get, 0, 0, 0, 513, "float(string uril, float id, optional string postmimetype, optional string postdata)"},//DP_QC_URI_GET {"tokenize_console",PF_tokenize_console,0, 0, 0, 514, "float(string str)"}, {"argv_start_index",PF_argv_start_index,0, 0, 0, 515, "float(float idx)"}, {"argv_end_index", PF_argv_end_index, 0, 0, 0, 516, "float(float idx)"}, @@ -9970,7 +9958,7 @@ void PR_ResetBuiltins(progstype_t type) //fix all nulls to PF_FIXME and add any for (i = 0; BuiltinList[i].name; i++) { - if (!strcmp(BuiltinList[i].name, com_token)) + if (!strcmp(BuiltinList[i].name, com_token) && (BuiltinList[i].bifunc != PF_Fixme||!i)) { pr_builtin[binum] = BuiltinList[i].bifunc; break; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 88079c6cb..8fa22178f 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -154,6 +154,7 @@ cvar_t sv_gamespeed = CVAR("sv_gamespeed", "1"); cvar_t sv_csqcdebug = CVAR("sv_csqcdebug", "0"); cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat"); cvar_t pausable = CVAR("pausable", "1"); +cvar_t sv_banproxies = CVARD("banproxies", "0", "If enabled, anyone connecting via known proxy software will be refused entry. This should aid with blocking aimbots, but is only reliable for certain public proxies."); // @@ -580,10 +581,10 @@ void SV_DropClient (client_t *drop) { Netchan_Transmit(&drop->netchan, 0, "", SV_RateForClient(drop)); #ifdef warningmsg -#pragma warningmsg("This mans that we may not see the reason we kicked ourselves.") +#pragma warningmsg("This means that we may not see the reason we kicked ourselves.") #endif - CL_Disconnect(); drop->state = cs_free; //don't do zombie stuff + CL_Disconnect(); } else #endif @@ -2014,13 +2015,34 @@ client_t *SVC_DirectConnect(void) { if (!sv_listen_qw.value && net_from.type != NA_LOOPBACK) { - SV_RejectMessage (SCP_BAD, "QuakeWorld protocols are not permitted on this server.\n"); + SV_RejectMessage (protocol, "QuakeWorld protocols are not permitted on this server.\n"); Con_Printf ("* rejected connect from quakeworld\n"); return NULL; } } - + if (sv_banproxies.ival) + { + //FIXME: allow them to spectate but not join + if (*Info_ValueForKey(userinfo[0], "*qwfwd")) + { + SV_RejectMessage (protocol, "Proxies are not permitted on this server.\n"); + Con_Printf ("* rejected connect from qwfwd proxy\n"); + return NULL; + } + if (*Info_ValueForKey(userinfo[0], "Qizmo")) + { + SV_RejectMessage (protocol, "Proxies are not permitted on this server.\n"); + Con_Printf ("* rejected connect from qizmo proxy\n"); + return NULL; + } + if (*Info_ValueForKey(userinfo[0], "*qtv")) + { + SV_RejectMessage (protocol, "Proxies are not permitted on this server.\n"); + Con_Printf ("* rejected connect from qtv proxy (udp)\n"); + return NULL; + } + } while(!msg_badread) { @@ -3990,7 +4012,7 @@ float SV_Frame (void) sv.gamespeed = 1; #ifndef SERVERONLY - isidle = !isDedicated && sv.allocated_client_slots == 1 && key_dest != key_game && cls.state == ca_active; + isidle = !isDedicated && sv.allocated_client_slots == 1 && Key_Dest_Has(~kdm_game) && cls.state == ca_active; /*server is effectively paused if there are no clients*/ if (sv.spawned_client_slots == 0 && sv.spawned_observer_slots == 0 && (cls.state != ca_connected)) isidle = true; @@ -4309,6 +4331,7 @@ void SV_InitLocal (void) #endif Cvar_Set(&sv_public, "1"); + Cvar_Register (&sv_banproxies, "Server Permissions"); Cvar_Register (&sv_master, cvargroup_servercontrol); Cvar_Register (&sv_masterport, cvargroup_servercontrol); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 3aad1d496..1b3b0c68b 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -1223,7 +1223,42 @@ qboolean SV_MVDWritePackets (int num) return true; } -extern char readable[256]; +// table of readable characters, same as ezquake +char readable[256] = +{ + '.', '_', '_', '_', '_', '.', '_', '_', + '_', '_', '\n', '_', '\n', '>', '.', '.', + '[', ']', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '.', '_', '_', '_', + ' ', '!', '\"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '_', + '_', '_', '_', '_', '_', '.', '_', '_', + '_', '_', '_', '_', '_', '>', '.', '.', + '[', ']', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '.', '_', '_', '_', + ' ', '!', '\"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '_' +}; #define chartbl readable void MVD_Init (void) diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 009c4baec..a88fb4123 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -139,7 +139,7 @@ void WPhys_CheckVelocity (world_t *w, wedict_t *ent) { if (IS_NAN(ent->v->velocity[i])) { - Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(w->progs, ent->v->classname)); + Con_DPrintf ("Got a NaN velocity on %s\n", PR_GetString(w->progs, ent->v->classname)); ent->v->velocity[i] = 0; } if (IS_NAN(ent->v->origin[i])) diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index e95b690da..ebeab5afb 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -567,6 +567,17 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, 0); break; + case MULTICAST_ONE_R: + reliable = true; + case MULTICAST_ONE: + if (svprogfuncs) + { + edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity); + pnum = NUM_FOR_EDICT(svprogfuncs, ent) - 1; + } + mask = NULL; + break; + default: mask = NULL; SV_Error ("SV_Multicast: bad to:%i", to); @@ -592,7 +603,12 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int } } - if (mask) + if (!mask) + { + if (pnum != j) + continue; + } + else { #ifdef Q2SERVER if (ge) diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index cdd2236c0..9d710965c 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -916,8 +916,7 @@ void Signal_Error_Handler (int sig) void StartQuakeServer(void) { quakeparms_t parms; - static char bindir[MAX_OSPATH]; //unused variable - int t; + static char bindir[MAX_OSPATH]; memset(&parms, 0, sizeof(parms)); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 8f537f8fc..99063e089 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -4922,7 +4922,7 @@ ucmd_t ucmds[] = {"demoinfo", SV_MVDInfo_f}, {"dlsize", SV_DownloadSize_f}, {"download", SV_BeginDownload_f}, - {"nextdl", SV_NextDownload_f}, + {"nextdl", SV_NextDownload_f, true}, /*quakeworld specific things*/ {"join", Cmd_Join_f}, @@ -4930,8 +4930,8 @@ ucmd_t ucmds[] = {"snap", SV_NoSnap_f}, {"ptrack", SV_PTrack_f}, //ZOID - used with autocam - {"enablecsqc", SV_EnableClientsCSQC}, - {"disablecsqc", SV_DisableClientsCSQC}, + {"enablecsqc", SV_EnableClientsCSQC, true}, + {"disablecsqc", SV_DisableClientsCSQC, true}, {"vote", SV_Vote_f}, @@ -5040,7 +5040,7 @@ ucmd_t nqucmds[] = #endif /*various misc extensions*/ - {"pext", SV_Pext_f}, + {"pext", SV_Pext_f, true}, {"enablecsqc", SV_EnableClientsCSQC}, {"disablecsqc", SV_DisableClientsCSQC}, {"challengeconnect", NULL}, diff --git a/engine/server/world.c b/engine/server/world.c index 209e3233a..5655e568e 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -471,8 +471,8 @@ void World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers) w->worldmodel->funcs.FindTouchedLeafs(w->worldmodel, &ent->pvsinfo, ent->v->absmin, ent->v->absmax); } - if (ent->v->solid == SOLID_NOT) - return; +// if (ent->v->solid == SOLID_NOT) +// return; // find the first node that the ent's box crosses node = w->areanodes; @@ -1518,8 +1518,8 @@ static void World_ClipToLinks (world_t *w, areanode_t *node, moveclip_t *clip) continue; // points never interact // might intersect, so do an exact clip - if (clip->trace.allsolid) - return; +// if (clip->trace.allsolid) +// return; if (clip->passedict) { if ((wedict_t*)PROG_TO_EDICT(w->progs, touch->v->owner) == clip->passedict) diff --git a/engine/shaders/generatebuiltinsl.c b/engine/shaders/generatebuiltinsl.c index 6bbd7629f..9a609ac4f 100644 --- a/engine/shaders/generatebuiltinsl.c +++ b/engine/shaders/generatebuiltinsl.c @@ -11,6 +11,7 @@ char shaders[][64] = "crepuscular_opaque", "crepuscular_rays", "crepuscular_sky", + "depthonly", "default2d", "defaultadditivesprite", "defaultskin", diff --git a/engine/shaders/glsl/depthonly.glsl b/engine/shaders/glsl/depthonly.glsl new file mode 100644 index 000000000..23a4e87ee --- /dev/null +++ b/engine/shaders/glsl/depthonly.glsl @@ -0,0 +1,24 @@ +!!permu FRAMEBLEND +!!permu SKELETAL + +//standard shader used for drawing shadowmap depth. +//also used for masking off portals and other things that want depth and no colour. +//must support skeletal and 2-way vertex blending or Bad Things Will Happen. +//the vertex shader is responsible for calculating lighting values. + +#ifdef VERTEX_SHADER +#include "sys/skeletal.h" +void main () +{ + gl_Position = skeletaltransform(); +} +#endif + +#ifdef FRAGMENT_SHADER +void main () +{ + //must always draw something, supposedly. It might as well be black. + gl_FragColor = vec4(0, 0, 0, 1); +} +#endif + diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index db14cc4db..48bd7b608 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -1,8 +1,11 @@ !!permu BUMP +!!permu FRAMEBLEND !!permu SKELETAL !!permu UPPERLOWER !!permu FOG !!cvarf r_glsl_offsetmapping_scale +!!cvardf r_glsl_pcf + //this is the main shader responsible for realtime dlights. @@ -10,10 +13,18 @@ //s0=diffuse, s1=normal, s2=specular, s3=shadowmap //custom modifiers: //PCF(shadowmap) -//CUBE(projected cubemap) +//CUBEPROJ(projected cubemap) //SPOT(projected circle //CUBESHADOW +#ifndef r_glsl_pcf +#error r_glsl_pcf wasn't defined +#endif +#if r_glsl_pcf < 1 + #undef r_glsl_pcf + #define r_glsl_pcf 9 +#endif + #if 0 && defined(GL_ARB_texture_gather) && defined(PCF) #extension GL_ARB_texture_gather : enable #endif @@ -33,9 +44,6 @@ varying vec3 eyevector; #if defined(PCF) || defined(CUBE) || defined(SPOT) varying vec4 vtexprojcoord; uniform mat4 l_cubematrix; -#ifndef SPOT -uniform mat4 l_projmatrix; -#endif #endif #ifdef VERTEX_SHADER #include "sys/skeletal.h" @@ -107,68 +115,65 @@ uniform float l_lightradius; uniform vec3 l_lightcolour; uniform vec3 l_lightcolourscale; #ifdef PCF -uniform vec4 l_shadowmapinfo; //xy are the texture scale, z is 1, w is the scale. +uniform vec4 l_shadowmapproj; //light projection matrix info +uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale. #endif + #ifdef PCF -//#define shadow2DProj(t,c) (vec2(1.0,1.0)) -//#define shadow2DProj(t,c) texture2DProj(t,c).rg - -float ShadowmapFilter(void) +vec3 ShadowmapCoord(void) { - //dehomogonize input - vec3 shadowcoord = (vtexprojcoord.xyz / vtexprojcoord.w); - -#ifdef CUBESHADOW -// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w; -// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r -#else - #ifdef SPOT //bias it. don't bother figuring out which side or anything, its not needed //l_projmatrix contains the light's projection matrix so no other magic needed - shadowcoord.xyz = (shadowcoord.xyz + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5); + vtexprojcoord.z -= 0.015; + return (vtexprojcoord.xyz/vtexprojcoord.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5); +//#elif defined(CUBESHADOW) +// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w; +// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r #else //figure out which axis to use //texture is arranged thusly: //forward left up //back right down - vec3 dir = abs(shadowcoord); + vec3 dir = abs(vtexprojcoord.xyz); //assume z is the major axis (ie: forward from the light) - vec3 t = shadowcoord; + vec3 t = vtexprojcoord.xyz; float ma = dir.z; - vec3 axis = vec3(1.0, 1.0, 1.0); + vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5); if (dir.x > ma) { ma = dir.x; - t = shadowcoord.zyx; - axis.x = 3.0; + t = vtexprojcoord.zyx; + axis.x = 0.5; } if (dir.y > ma) { ma = dir.y; - t = shadowcoord.xzy; - axis.x = 5.0; + t = vtexprojcoord.xzy; + axis.x = 2.5/3.0; } + //if the axis is negative, flip it. if (t.z > 0.0) { - axis.y = 3.0; + axis.y = 1.5/2.0; t.z = -t.z; } - //we also need to pass the result through the light's projection matrix too - vec4 nsc =l_projmatrix*vec4(t, 1.0); - shadowcoord = (nsc.xyz / nsc.w); - - //scale to match the light's precision and pinch inwards, so we never sample over the edge - shadowcoord.st *= l_shadowmapinfo.w * (1.0-l_shadowmapinfo.st); - - //now bias and relocate it - shadowcoord = (shadowcoord + axis.xyz) * vec3(0.5/3.0, 0.5/2.0, 0.5); + //the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4. + //note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image + //the resulting z is prescaled to result in a value between -0.5 and 0.5. + //also make sure we're in the right quadrant type thing + return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z); #endif +} + +float ShadowmapFilter(void) +{ + vec3 shadowcoord = ShadowmapCoord(); #if 0//def GL_ARB_texture_gather vec2 ipart, fpart; @@ -185,20 +190,31 @@ float ShadowmapFilter(void) return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds. #else - #define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapinfo.xyz)).r + #define dosamp(x,y) shadow2D(s_t4, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r float s = 0.0; - s += dosamp(-1.0, -1.0); - s += dosamp(-1.0, 0.0); - s += dosamp(-1.0, 1.0); - s += dosamp(0.0, -1.0); - s += dosamp(0.0, 0.0); - s += dosamp(0.0, 1.0); - s += dosamp(1.0, -1.0); - s += dosamp(1.0, 0.0); - s += dosamp(1.0, 1.0); - return s/9.0; + #if r_glsl_pcf >= 1 && r_glsl_pcf < 5 + s += dosamp(0.0, 0.0); + return s; + #elif r_glsl_pcf >= 5 && r_glsl_pcf < 9 + s += dosamp(-1.0, 0.0); + s += dosamp(0.0, -1.0); + s += dosamp(0.0, 0.0); + s += dosamp(0.0, 1.0); + s += dosamp(1.0, 0.0); + return s/5.0; + #else + s += dosamp(-1.0, -1.0); + s += dosamp(-1.0, 0.0); + s += dosamp(-1.0, 1.0); + s += dosamp(0.0, -1.0); + s += dosamp(0.0, 0.0); + s += dosamp(0.0, 1.0); + s += dosamp(1.0, -1.0); + s += dosamp(1.0, 0.0); + s += dosamp(1.0, 1.0); + return s/9.0; + #endif #endif -#endif } #endif diff --git a/plugins/avplug/avencode.c b/plugins/avplug/avencode.c index caff80254..435beeb0d 100644 --- a/plugins/avplug/avencode.c +++ b/plugins/avplug/avencode.c @@ -269,7 +269,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height videocodec = avcodec_find_encoder_by_name(codecname); if (!videocodec) { - Con_Printf("Unsupported avplug_codec \"%s\"\n", codecname); + Con_Printf("Unsupported avplug_videocodec \"%s\"\n", codecname); return NULL; } } @@ -290,7 +290,7 @@ static void *AVEnc_Begin (char *streamname, int videorate, int width, int height audiocodec = avcodec_find_encoder_by_name(codecname); if (!audiocodec) { - Con_Printf("avplug: Unsupported avplug_codec \"%s\"\n", codecname); + Con_Printf("avplug: Unsupported avplug_audiocodec \"%s\"\n", codecname); return NULL; } } diff --git a/plugins/jabber/jabbercl.vcproj b/plugins/jabber/jabbercl.vcproj index 3f5eb07ba..2b64bac23 100644 --- a/plugins/jabber/jabbercl.vcproj +++ b/plugins/jabber/jabbercl.vcproj @@ -196,6 +196,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 7ad852c85..d0b7a5a09 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -914,7 +914,7 @@ static int sasl_oauth2_initial(jclient_t *jcl, char *buf, int bufsize) Q_strlcat(url, "&login_hint=", sizeof(url)); Q_strlcat_urlencode(url, jcl->oauth2.useraccount, sizeof(url)); - Con_Printf("Please visit ^[^4%s\\url\\%s^] and then enter:\n^[/"COMMANDPREFIX"%i /oa2token ^]\n", url, url, jcl->accountnum); + Con_Printf("Please visit ^[^4%s\\url\\%s^] and then enter:\n^[/"COMMANDPREFIX"%i /oa2token ^]\nNote: you can right-click the link to copy it to your browser, and you can use ctrl+v to paste the resulting auth token as part of the given command.", url, url, jcl->accountnum); //wait for user to act. return -2; @@ -2864,6 +2864,10 @@ void JCL_ParsePresence(jclient_t *jcl, xmltree_t *tree) else { JCL_FindBuddy(jcl, from, &buddy, &bres); + if (!bres) + { + JCL_FindBuddy(jcl, va("%s/", from), &buddy, &bres); + } JCL_GenLink(jcl, startconvo, sizeof(startconvo), NULL, from, NULL, NULL, "%s", buddy->name); if (bres) @@ -3148,10 +3152,17 @@ int JCL_ClientFrame(jclient_t *jcl) int outlen = -1; if (jcl->forcetls > 0 && !jcl->issecure) { - Con_Printf("XMPP: Unable to switch to TLS.\n"); - XML_ConPrintTree(tree, 0); + if (BUILTINISVALID(Net_SetTLSClient)) + { + Con_Printf("XMPP: Unable to switch to TLS. You are probably being man-in-the-middle attacked.\n"); + XML_ConPrintTree(tree, 0); + } + else + { + Con_Printf("XMPP: Unable to switch to TLS. Your engine does not provide the feature. You can use the xmpp /autoconnect command to register your account instead, as this does not enforce the use of tls (but does still use it in case your future engine versions support it).\n"); + } XML_Destroy(tree); - return JCL_KILL; + return JCL_KILL; } for (sm = 0; sm < sizeof(saslmethods)/sizeof(saslmethods[0]); sm++) { @@ -3174,7 +3185,7 @@ int JCL_ClientFrame(jclient_t *jcl) if (outlen == -2) { XML_Destroy(tree); - return JCL_KILL; + return JCL_KILL; } if (outlen >= 0) @@ -3195,14 +3206,14 @@ int JCL_ClientFrame(jclient_t *jcl) Con_Printf("XMPP: No suitable auth methods. Unable to connect.\n"); XML_ConPrintTree(tree, 0); XML_Destroy(tree); - return JCL_KILL; + return JCL_KILL; } } else //we cannot auth, no suitable method. { Con_Printf("XMPP: Neither SASL or TLS are usable\n"); XML_Destroy(tree); - return JCL_KILL; + return JCL_KILL; } } } @@ -4056,8 +4067,9 @@ void JCL_Command(int accid, char *console) if (arg[0][0] == '/' && arg[0][1] != '/' && strcmp(arg[0]+1, "me")) { - if (!strcmp(arg[0]+1, "open") || !strcmp(arg[0]+1, "connect") || !strcmp(arg[0]+1, "tlsopen") || !strcmp(arg[0]+1, "tlsconnect")) + if (!strcmp(arg[0]+1, "open") || !strcmp(arg[0]+1, "connect") || !strcmp(arg[0]+1, "autoopen") || !strcmp(arg[0]+1, "autoconnect") || !strcmp(arg[0]+1, "plainopen") || !strcmp(arg[0]+1, "plainconnect") || !strcmp(arg[0]+1, "tlsopen") || !strcmp(arg[0]+1, "tlsconnect")) { //tlsconnect is 'old'. + int tls; if (!*arg[1]) { Con_SubPrintf(console, "%s \n", arg[0]+1); @@ -4069,7 +4081,15 @@ void JCL_Command(int accid, char *console) Con_TrySubPrint(console, "You are already connected\nPlease /quit first\n"); return; } - jcl = jclients[accid] = JCL_Connect(accid, arg[3], !strncmp(arg[0]+1, "tls", 3), arg[1], arg[2]); + if (!strncmp(arg[0]+1, "tls", 3)) + tls = 2; //old initial-tls connect + else if (!strncmp(arg[0]+1, "plain", 5)) + tls = -1; //don't bother with tls. at all. + else if (!strncmp(arg[0]+1, "auto", 4)) + tls = 0; //use tls if its available, but don't really care otherwise. + else + tls = 1; //require tls + jcl = jclients[accid] = JCL_Connect(accid, arg[3], tls, arg[1], arg[2]); if (!jclients[accid]) { Con_TrySubPrint(console, "Connect failed\n"); @@ -4081,12 +4101,18 @@ void JCL_Command(int accid, char *console) Con_TrySubPrint(console, "^[/" COMMANDPREFIX " /connect USERNAME@DOMAIN/RESOURCE [PASSWORD] [XMPPSERVER]^]\n"); if (BUILTINISVALID(Net_SetTLSClient)) { - Con_Printf("eg for gmail: ^[/" COMMANDPREFIX " /connect myusername@gmail.com^] (using oauth2)\n"); - Con_Printf("eg for gmail: ^[/" COMMANDPREFIX " /connect myusername@gmail.com mypassword talk.google.com^] (warning: password will be saved locally in plain text)\n"); -// Con_Printf("eg for facebook: ^[/" COMMANDPREFIX " /connect myusername@chat.facebook.com mypassword chat.facebook.com^]\n"); -// Con_Printf("eg for msn: ^[/" COMMANDPREFIX " /connect myusername@messanger.live.com mypassword^]\n"); + Con_TrySubPrint(console, "eg for gmail: ^[/" COMMANDPREFIX " /connect myusername@gmail.com^] (using oauth2)\n"); + Con_TrySubPrint(console, "eg for gmail: ^[/" COMMANDPREFIX " /connect myusername@gmail.com mypassword talk.google.com^] (warning: password will be saved locally in plain text)\n"); +// Con_TrySubPrint(console, "eg for facebook: ^[/" COMMANDPREFIX " /connect myusername@chat.facebook.com mypassword chat.facebook.com^]\n"); +// Con_TrySubPrint(console, "eg for msn: ^[/" COMMANDPREFIX " /connect myusername@messanger.live.com mypassword^]\n"); } - Con_Printf("Note that this info will be used the next time you start quake.\n"); + else + { //if we don't have tls support, we can still connect to google with oauth2 + //no idea about other networks. + //however, the regular 'connect' command will insist on tls, so make sure the helpful command displayed is different + Con_TrySubPrint(console, "eg for gmail: ^[/" COMMANDPREFIX " /autoconnect myusername@gmail.com^] (using oauth2)\n"); + } + Con_TrySubPrint(console, "Note that this info will be used the next time you start quake.\n"); //small note: //for the account 'me@example.com' the server to connect to can be displayed with: