From: lordhavoc Date: Sat, 30 Mar 2002 05:04:54 +0000 (+0000) Subject: added cl_avidemo cvar (saves a series of tga images named gamedir/dpavi000000.tga... X-Git-Tag: RELEASE_0_2_0_RC1~543 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=08dc528c1e2e6c2b1891c12dbc69ec985387a232 added cl_avidemo cvar (saves a series of tga images named gamedir/dpavi000000.tga and so on, the parameter to it is the framerate to save, locks framerate to this while saving, set back to 0 to stop - note there is sound saving code but it is commented out because it's always desynchronized to the video because quake has such a lousy sound engine) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@1693 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_screen.c b/cl_screen.c index b8922b2b..212c356c 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -10,6 +10,7 @@ cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"}; cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"}; cvar_t scr_printspeed = {0, "scr_printspeed","8"}; cvar_t scr_2dresolution = {CVAR_SAVE, "scr_2dresolution", "1"}; +cvar_t cl_avidemo = {0, "cl_avidemo", "0"}; qboolean scr_initialized; // ready to draw @@ -525,7 +526,8 @@ void CL_Screen_Init(void) Cvar_RegisterVariable (&scr_showpause); Cvar_RegisterVariable (&scr_centertime); Cvar_RegisterVariable (&scr_printspeed); - Cvar_RegisterVariable(&scr_2dresolution); + Cvar_RegisterVariable (&scr_2dresolution); + Cvar_RegisterVariable (&cl_avidemo); Cmd_AddCommand ("sizeup",SCR_SizeUp_f); Cmd_AddCommand ("sizedown",SCR_SizeDown_f); @@ -796,8 +798,26 @@ void SCR_ScreenShot_f (void) return; } - SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight); - Con_Printf ("Wrote %s\n", filename); + if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight)) + Con_Printf ("Wrote %s\n", filename); + else + Con_Printf ("unable to write %s\n", filename); +} + +static int cl_avidemo_frame = 0; + +void SCR_CaptureAVIDemo(void) +{ + char filename[32]; + sprintf(filename, "dpavi%06d.tga", cl_avidemo_frame); + if (SCR_ScreenShot(filename, vid.realx, vid.realy, vid.realwidth, vid.realheight)) + cl_avidemo_frame++; + else + { + Cvar_SetValueQuick(&cl_avidemo, 0); + Con_Printf("avi saving failed on frame %i, out of disk space? stopping avi demo catpure.\n", cl_avidemo_frame); + cl_avidemo_frame = 0; + } } /* @@ -993,6 +1013,10 @@ void CL_UpdateScreen(void) if (!scr_initialized || !con_initialized) return; // not initialized yet + if (cl_avidemo.integer) + SCR_CaptureAVIDemo(); + else + cl_avidemo_frame = 0; R_TimeReport("other"); diff --git a/common.c b/common.c index 36d2920e..80a7389f 100644 --- a/common.c +++ b/common.c @@ -1381,7 +1381,7 @@ COM_WriteFile The filename will be prefixed by the current game directory ============ */ -void COM_WriteFile (char *filename, void *data, int len) +qboolean COM_WriteFile (char *filename, void *data, int len) { int handle; char name[MAX_OSPATH]; @@ -1394,13 +1394,14 @@ void COM_WriteFile (char *filename, void *data, int len) handle = Sys_FileOpenWrite (name); if (handle == -1) { - Sys_Printf ("COM_WriteFile: failed on %s\n", name); - return; + Con_Printf ("COM_WriteFile: failed on %s\n", name); + return false; } - Con_Printf ("COM_WriteFile: %s\n", name); + Con_DPrintf ("COM_WriteFile: %s\n", name); Sys_FileWrite (handle, data, len); Sys_FileClose (handle); + return true; } diff --git a/common.h b/common.h index b4fcbab9..91835e73 100644 --- a/common.h +++ b/common.h @@ -174,7 +174,7 @@ extern int com_filesize; extern char com_gamedir[MAX_OSPATH]; -void COM_WriteFile (char *filename, void *data, int len); +qboolean COM_WriteFile (char *filename, void *data, int len); int COM_FOpenFile (char *filename, QFile **file, qboolean quiet, qboolean zip); // set by COM_LoadFile functions diff --git a/gl_backend.c b/gl_backend.c index d5f605a0..0859df0b 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -1426,13 +1426,14 @@ void R_Mesh_DrawPolygon(rmeshinfo_t *m, int numverts) ============================================================================== */ -void SCR_ScreenShot(char *filename, int x, int y, int width, int height) +qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height) { + qboolean ret; int i; qbyte *buffer; if (!r_render.integer) - return; + return false; buffer = Mem_Alloc(tempmempool, width*height*3); glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer); @@ -1443,9 +1444,10 @@ void SCR_ScreenShot(char *filename, int x, int y, int width, int height) for (i = 0;i < width * height * 3;i++) buffer[i] <<= v_overbrightbits.integer; - Image_WriteTGARGB_preflipped(filename, width, height, buffer); + ret = Image_WriteTGARGB_preflipped(filename, width, height, buffer); Mem_Free(buffer); + return ret; } //============================================================================= diff --git a/gl_backend.h b/gl_backend.h index 450409ee..0082501c 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -87,7 +87,7 @@ void R_Mesh_Draw_NativeOnly(const rmeshinfo_t *m); int R_Mesh_Draw_GetBuffer(rmeshbufferinfo_t *m); // saves a section of the rendered frame to a .tga file -void SCR_ScreenShot(char *filename, int x, int y, int width, int height); +qboolean SCR_ScreenShot(char *filename, int x, int y, int width, int height); // used by R_Envmap_f and internally in backend, clears the frame void R_ClearScreen(void); // invoke refresh of frame diff --git a/host.c b/host.c index 7ff88743..94947a92 100644 --- a/host.c +++ b/host.c @@ -302,7 +302,7 @@ void Host_WriteConfiguration (void) ================= SV_ClientPrintf -Sends text across to be displayed +Sends text across to be displayed FIXME: make this just a stuffed echo? ================= */ @@ -525,6 +525,7 @@ Host_FilterTime Returns false if the time is too short to run a frame =================== */ +extern cvar_t cl_avidemo; qboolean Host_FilterTime (double time) { double timecap; @@ -536,9 +537,17 @@ qboolean Host_FilterTime (double time) Cvar_SetValue("host_minfps", 10.0f); if (host_maxfps.value < host_minfps.value) Cvar_SetValue("host_maxfps", host_minfps.value); + if (cl_avidemo.value < 0.1f) + Cvar_SetValue("cl_avidemo", 0.0f); - // check if framerate is too high - if (!cls.timedemo) + // check if framerate is too high + if (cl_avidemo.value >= 0.1f) + { + timecap = 1.0 / (double)cl_avidemo.value; + if ((realtime - oldrealtime) < timecap) + return false; + } + else if (!cls.timedemo) { timecap = sys_ticrate.value; if (cls.state == ca_connected) @@ -561,6 +570,12 @@ qboolean Host_FilterTime (double time) if (host_framerate.value > 0) host_frametime = host_framerate.value; + else if (cl_avidemo.value >= 0.1f) + { + // don't allow really short frames + //if (host_frametime > (1.0 / cl_avidemo.value)) + host_frametime = (1.0 / cl_avidemo.value); + } else { // don't allow really short frames @@ -569,7 +584,7 @@ qboolean Host_FilterTime (double time) } cl.frametime = host_frametime = bound(0, host_frametime * slowmo.value, 0.1f); // LordHavoc: the QC code relies on no less than 10fps - + return true; } diff --git a/image.c b/image.c index 1c414dd7..87c52748 100644 --- a/image.c +++ b/image.c @@ -587,8 +587,9 @@ rtexture_t *loadtextureimagewithmask (rtexturepool_t *pool, char* filename, int return rt; } -void Image_WriteTGARGB_preflipped (char *filename, int width, int height, qbyte *data) +qboolean Image_WriteTGARGB_preflipped (char *filename, int width, int height, qbyte *data) { + qboolean ret; qbyte *buffer, *in, *out, *end; buffer = Mem_Alloc(tempmempool, width*height*3 + 18); @@ -611,9 +612,10 @@ void Image_WriteTGARGB_preflipped (char *filename, int width, int height, qbyte *out++ = in[1]; *out++ = in[0]; } - COM_WriteFile (filename, buffer, width*height*3 + 18 ); + ret = COM_WriteFile (filename, buffer, width*height*3 + 18 ); Mem_Free(buffer); + return ret; } void Image_WriteTGARGB (char *filename, int width, int height, qbyte *data) diff --git a/image.h b/image.h index bf3e76f1..85adc1d5 100644 --- a/image.h +++ b/image.h @@ -28,7 +28,7 @@ rtexture_t *image_masktex; rtexture_t *loadtextureimagewithmask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache); // writes a RGB TGA that is already upside down (which TGA wants) -void Image_WriteTGARGB_preflipped (char *filename, int width, int height, qbyte *data); +qboolean Image_WriteTGARGB_preflipped (char *filename, int width, int height, qbyte *data); // writes a RGB TGA void Image_WriteTGARGB (char *filename, int width, int height, qbyte *data); diff --git a/snd_mix.c b/snd_mix.c index 42e463fc..3b823166 100644 --- a/snd_mix.c +++ b/snd_mix.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -34,7 +34,87 @@ int snd_scaletable[32][256]; int *snd_p, snd_linear_count, snd_vol; short *snd_out; -void Snd_WriteLinearBlastStereo16 (void); +/* +// LordHavoc: disabled this because it desyncs with the video too easily +extern cvar_t cl_avidemo; +static FILE *cl_avidemo_soundfile = NULL; +void S_CaptureAVISound(portable_samplepair_t *buf, int length) +{ + int i, n; + qbyte out[PAINTBUFFER_SIZE * 4]; + char filename[MAX_OSPATH]; + + if (cl_avidemo.value >= 0.1f) + { + if (cl_avidemo_soundfile == NULL) + { + sprintf (filename, "%s/dpavi.wav", com_gamedir); + cl_avidemo_soundfile = fopen(filename, "wb"); + memset(out, 0, 44); + fwrite(out, 1, 44, cl_avidemo_soundfile); + // header will be filled out when file is closed + } + fseek(cl_avidemo_soundfile, 0, SEEK_END); + // write the sound buffer as little endian 16bit interleaved stereo + for(i = 0;i < length;i++) + { + n = buf[i].left >> 2; // quiet enough to prevent clipping most of the time + n = bound(-32768, n, 32767); + out[i*4+0] = n & 0xFF; + out[i*4+1] = (n >> 8) & 0xFF; + n = buf[i].right >> 2; // quiet enough to prevent clipping most of the time + n = bound(-32768, n, 32767); + out[i*4+2] = n & 0xFF; + out[i*4+3] = (n >> 8) & 0xFF; + } + if (fwrite(out, 4, length, cl_avidemo_soundfile) < length) + { + Cvar_SetValueQuick(&cl_avidemo, 0); + Con_Printf("avi saving sound failed, out of disk space? stopping avi demo capture.\n"); + } + } + else if (cl_avidemo_soundfile) + { + // file has not been closed yet, close it + fseek(cl_avidemo_soundfile, 0, SEEK_END); + i = ftell(cl_avidemo_soundfile); + + //"RIFF", (int) unknown (chunk size), "WAVE", + //"fmt ", (int) 16 (chunk size), (short) format 1 (uncompressed PCM), (short) 2 channels, (int) unknown rate, (int) unknown bytes per second, (short) 4 bytes per sample (channels * bytes per channel), (short) 16 bits per channel + //"data", (int) unknown (chunk size) + memcpy(out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\x00data****", 44); + // the length of the whole RIFF chunk + n = i - 8; + out[4] = (n) & 0xFF; + out[5] = (n >> 8) & 0xFF; + out[6] = (n >> 16) & 0xFF; + out[7] = (n >> 24) & 0xFF; + // rate + n = shm->speed; + out[24] = (n) & 0xFF; + out[25] = (n >> 8) & 0xFF; + out[26] = (n >> 16) & 0xFF; + out[27] = (n >> 24) & 0xFF; + // bytes per second (rate * channels * bytes per channel) + n = shm->speed * 4; + out[28] = (n) & 0xFF; + out[29] = (n >> 8) & 0xFF; + out[30] = (n >> 16) & 0xFF; + out[31] = (n >> 24) & 0xFF; + // the length of the data chunk + n = i - 44; + out[40] = (n) & 0xFF; + out[41] = (n >> 8) & 0xFF; + out[42] = (n >> 16) & 0xFF; + out[43] = (n >> 24) & 0xFF; + + fseek(cl_avidemo_soundfile, 0, SEEK_SET); + fwrite(out, 1, 44, cl_avidemo_soundfile); + fclose(cl_avidemo_soundfile); + cl_avidemo_soundfile = NULL; + } +} +*/ void Snd_WriteLinearBlastStereo16 (void) { @@ -158,10 +238,10 @@ void S_TransferPaintBuffer(int endtime) S_TransferStereo16 (endtime); return; } - + p = (int *) paintbuffer; count = (endtime - paintedtime) * shm->channels; - out_mask = shm->samples - 1; + out_mask = shm->samples - 1; out_idx = paintedtime * shm->channels & out_mask; step = 3 - shm->channels; snd_vol = volume.value*256; @@ -225,7 +305,7 @@ void S_TransferPaintBuffer(int endtime) DWORD dwNewpos, dwWrite; int il = paintedtime; int ir = endtime - paintedtime; - + ir += il; pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); @@ -291,12 +371,12 @@ void S_PaintChannels(int endtime) count = end - ltime; if (count > 0) - { + { if (sc->width == 1) SND_PaintChannelFrom8(ch, sc, count); else SND_PaintChannelFrom16(ch, sc, count); - + ltime += count; } @@ -308,7 +388,7 @@ void S_PaintChannels(int endtime) ch->pos = sc->loopstart; ch->end = ltime + sc->length - ch->pos; } - else + else { // channel just stopped ch->sfx = NULL; @@ -316,10 +396,11 @@ void S_PaintChannels(int endtime) } } } - + } // transfer out according to DMA format + //S_CaptureAVISound(paintbuffer, end - paintedtime); S_TransferPaintBuffer(end); paintedtime = end; } @@ -328,7 +409,7 @@ void S_PaintChannels(int endtime) void SND_InitScaletable (void) { int i, j; - + for (i=0 ; i<32 ; i++) for (j=0 ; j<256 ; j++) snd_scaletable[i][j] = ((signed char)j) * i * 8; @@ -370,7 +451,7 @@ void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) paintbuffer[i].left += lscale[*sfx]; paintbuffer[i].right += rscale[*sfx++]; } - + } ch->pos += count; }