Add demo to "movie" conversion.

It currently writes a series of png files (QF/qfmvNNNNNN.png), at a fixed
rate of 30fps, with no sound recording.
This commit is contained in:
Bill Currie 2012-01-05 19:19:37 +09:00
parent b13a2b6dbd
commit 423e08ce21
12 changed files with 186 additions and 38 deletions

View file

@ -56,6 +56,7 @@ void SCR_DrawTurtle (void);
void SCR_DrawPause (void); void SCR_DrawPause (void);
struct tex_s *SCR_ScreenShot (int width, int height); struct tex_s *SCR_ScreenShot (int width, int height);
struct tex_s *SCR_CaptureBGR (void);
void SCR_DrawStringToSnap (const char *s, struct tex_s *tex, int x, int y); void SCR_DrawStringToSnap (const char *s, struct tex_s *tex, int x, int y);
int MipColor (int r, int g, int b); int MipColor (int r, int g, int b);
int SCR_ModalMessage (const char *text); int SCR_ModalMessage (const char *text);

View file

@ -28,8 +28,7 @@
# include "config.h" # include "config.h"
#endif #endif
static __attribute__ ((used)) const char rcsid[] = static __attribute__ ((used)) const char rcsid[] = "$Id$";
"$Id$";
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
# include <string.h> # include <string.h>
@ -66,6 +65,24 @@ static __attribute__ ((used)) const char rcsid[] =
/* SCREEN SHOTS */ /* SCREEN SHOTS */
VISIBLE tex_t *
SCR_CaptureBGR (void)
{
int count;
tex_t *tex;
count = vid.width * vid.height;
tex = malloc (field_offset (tex_t, data[count * 3]));
SYS_CHECKMEM (tex);
tex->width = vid.width;
tex->height = vid.height;
tex->format = tex_rgb;
tex->palette = 0;
qfglReadPixels (0, 0, tex->width, tex->height, GL_BGR_EXT,
GL_UNSIGNED_BYTE, tex->data);
return tex;
}
VISIBLE tex_t * VISIBLE tex_t *
SCR_ScreenShot (int width, int height) SCR_ScreenShot (int width, int height)
{ {
@ -133,7 +150,6 @@ SCR_ScreenShot (int width, int height)
void void
SCR_ScreenShot_f (void) SCR_ScreenShot_f (void)
{ {
byte *buffer;
dstring_t *pcxname = dstring_new (); dstring_t *pcxname = dstring_new ();
// find a file name to save it to // find a file name to save it to
@ -141,12 +157,11 @@ SCR_ScreenShot_f (void)
va ("%s/qf", qfs_gamedir->dir.shots), ".tga")) { va ("%s/qf", qfs_gamedir->dir.shots), ".tga")) {
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n"); Sys_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
} else { } else {
buffer = malloc (vid.width * vid.height * 3); tex_t *tex;
SYS_CHECKMEM (buffer);
qfglReadPixels (0, 0, vid.width, vid.height, GL_BGR_EXT, tex = SCR_CaptureBGR ();
GL_UNSIGNED_BYTE, buffer); WriteTGAfile (pcxname->str, tex->data, tex->width, tex->height);
WriteTGAfile (pcxname->str, buffer, vid.width, vid.height); free (tex);
free (buffer);
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, pcxname->str); Sys_Printf ("Wrote %s/%s\n", qfs_userpath, pcxname->str);
} }
dstring_delete (pcxname); dstring_delete (pcxname);

View file

@ -203,6 +203,31 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs)
qfglFlush (); qfglFlush ();
} }
VISIBLE tex_t *
SCR_CaptureBGR (void)
{
byte *r, *b;
int count, i;
tex_t *tex;
count = vid.width * vid.height;
tex = malloc (field_offset (tex_t, data[count * 3]));
SYS_CHECKMEM (tex);
tex->width = vid.width;
tex->height = vid.height;
tex->format = tex_rgb;
tex->palette = 0;
qfglReadPixels (0, 0, vid.width, vid.height, GL_RGB,
GL_UNSIGNED_BYTE, tex->data);
for (i = 0, r = tex->data, b = tex->data + 2; i < count;
i++, r += 3, b += 3) {
byte t = *b;
*b = *r;
*r = t;
}
return tex;
}
VISIBLE tex_t * VISIBLE tex_t *
SCR_ScreenShot (int width, int height) SCR_ScreenShot (int width, int height)
{ {
@ -212,28 +237,18 @@ SCR_ScreenShot (int width, int height)
VISIBLE void VISIBLE void
SCR_ScreenShot_f (void) SCR_ScreenShot_f (void)
{ {
byte *buffer, *r, *b;
dstring_t *name = dstring_new (); dstring_t *name = dstring_new ();
int size, i;
// find a file name to save it to // find a file name to save it to
if (!QFS_NextFilename (name, if (!QFS_NextFilename (name,
va ("%s/qf", qfs_gamedir->dir.shots), ".png")) { va ("%s/qf", qfs_gamedir->dir.shots), ".png")) {
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n"); Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n");
} else { } else {
size = vid.width * vid.height; tex_t *tex;
buffer = malloc (size * 3);
SYS_CHECKMEM (buffer); tex = SCR_CaptureBGR ();
qfglReadPixels (0, 0, vid.width, vid.height, GL_RGB, WritePNGqfs (name->str, tex->data, tex->width, tex->height);
GL_UNSIGNED_BYTE, buffer); free (tex);
// FIXME have to swap rgb (WritePNG bug?)
for (i = 0, r = buffer, b = buffer + 2; i < size; i++, r+=3, b+=3) {
byte t = *b;
*b = *r;
*r = t;
}
WritePNGqfs (name->str, buffer, vid.width, vid.height);
free (buffer);
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, name->str); Sys_Printf ("Wrote %s/%s\n", qfs_userpath, name->str);
} }
dstring_delete (name); dstring_delete (name);

View file

@ -28,8 +28,7 @@
# include "config.h" # include "config.h"
#endif #endif
static __attribute__ ((used)) const char rcsid[] = static __attribute__ ((used)) const char rcsid[] = "$Id$";
"$Id$";
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
# include <string.h> # include <string.h>
@ -87,6 +86,36 @@ SCR_ApplyBlend (void) // Used to be V_UpdatePalette
/* SCREEN SHOTS */ /* SCREEN SHOTS */
VISIBLE tex_t *
SCR_CaptureBGR (void)
{
int count, x, y;
tex_t *tex;
const byte *src;
byte *dst;
count = vid.width * vid.height;
tex = malloc (field_offset (tex_t, data[count * 3]));
SYS_CHECKMEM (tex);
tex->width = vid.width;
tex->height = vid.height;
tex->format = tex_rgb;
tex->palette = 0;
D_EnableBackBufferAccess ();
src = vid.buffer;
for (y = 0; y < tex->height; y++) {
dst = tex->data + (tex->height - 1 - y) * tex->width * 3;
for (x = 0; x < tex->width; x++) {
*dst++ = vid.basepal[*src * 3 + 2]; // blue
*dst++ = vid.basepal[*src * 3 + 1]; // green
*dst++ = vid.basepal[*src * 3 + 0]; // red
src++;
}
}
D_DisableBackBufferAccess ();
return tex;
}
tex_t * tex_t *
SCR_ScreenShot (int width, int height) SCR_ScreenShot (int width, int height)
{ {

View file

@ -28,8 +28,7 @@
# include "config.h" # include "config.h"
#endif #endif
static __attribute__ ((used)) const char rcsid[] = static __attribute__ ((used)) const char rcsid[] = "$Id$";
"$Id$";
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
# include <string.h> # include <string.h>
@ -155,6 +154,36 @@ SCR_ApplyBlend (void) // Used to be V_UpdatePalette
/* SCREEN SHOTS */ /* SCREEN SHOTS */
VISIBLE tex_t *
SCR_CaptureBGR (void)
{
int count, x, y;
tex_t *tex;
const byte *src;
byte *dst;
count = vid.width * vid.height;
tex = malloc (field_offset (tex_t, data[count * 3]));
SYS_CHECKMEM (tex);
tex->width = vid.width;
tex->height = vid.height;
tex->format = tex_rgb;
tex->palette = 0;
D_EnableBackBufferAccess ();
src = vid.buffer;
for (y = 0; y < tex->height; y++) {
dst = tex->data + (tex->height - 1 - y) * tex->width * 3;
for (x = 0; x < tex->width; x++) {
*dst++ = vid.basepal[*src * 3 + 2]; // blue
*dst++ = vid.basepal[*src * 3 + 1]; // green
*dst++ = vid.basepal[*src * 3 + 0]; // red
src++;
}
}
D_DisableBackBufferAccess ();
return tex;
}
VISIBLE tex_t * VISIBLE tex_t *
SCR_ScreenShot (int width, int height) SCR_ScreenShot (int width, int height)
{ {

View file

@ -119,6 +119,7 @@ typedef struct
// demo recording info must be here, because record is started before // demo recording info must be here, because record is started before
// entering a map (and clearing client_state_t) // entering a map (and clearing client_state_t)
qboolean demorecording; qboolean demorecording;
qboolean demo_capture;
qboolean demoplayback; qboolean demoplayback;
qboolean timedemo; qboolean timedemo;
int forcetrack; // -1 = use normal cd track int forcetrack; // -1 = use normal cd track

View file

@ -126,6 +126,7 @@ CL_StopPlayback (void)
Qclose (cls.demofile); Qclose (cls.demofile);
cls.demofile = NULL; cls.demofile = NULL;
CL_SetState (ca_disconnected); CL_SetState (ca_disconnected);
cls.demo_capture = 0;
cls.demoplayback = 0; cls.demoplayback = 0;
key_game_target = IMT_0; key_game_target = IMT_0;
Key_SetKeyDest (key_game); Key_SetKeyDest (key_game);
@ -384,7 +385,17 @@ CL_PlayDemo_f (void)
if (cmd_source != src_command) if (cmd_source != src_command)
return; return;
if (Cmd_Argc () != 2) { switch (Cmd_Argc ()) {
case 2:
cls.demo_capture = 0;
break;
case 3:
if (!strcmp (Cmd_Argv (2), "rec")) {
cls.demo_capture = 1;
break;
}
// fall through
default:
Sys_Printf ("play <demoname> : plays a demo\n"); Sys_Printf ("play <demoname> : plays a demo\n");
return; return;
} }

View file

@ -41,12 +41,15 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include "QF/cmd.h" #include "QF/cmd.h"
#include "QF/console.h" #include "QF/console.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/image.h"
#include "QF/input.h" #include "QF/input.h"
#include "QF/keys.h" #include "QF/keys.h"
#include "QF/msg.h" #include "QF/msg.h"
#include "QF/plugin.h" #include "QF/plugin.h"
#include "QF/png.h"
#include "QF/progs.h" #include "QF/progs.h"
#include "QF/qargs.h" #include "QF/qargs.h"
#include "QF/screen.h"
#include "QF/sys.h" #include "QF/sys.h"
#include "QF/va.h" #include "QF/va.h"
#include "QF/vid.h" #include "QF/vid.h"
@ -638,6 +641,9 @@ _Host_Frame (float time)
rand (); // keep the random time dependent rand (); // keep the random time dependent
if (cls.demo_capture)
time = 1.0 / 30; //FIXME fixed 30fps atm
// decide the simulation time // decide the simulation time
if ((sleeptime = Host_FilterTime (time)) != 0) { if ((sleeptime = Host_FilterTime (time)) != 0) {
// don't run too fast, or packet will flood outs // don't run too fast, or packet will flood outs
@ -685,6 +691,14 @@ _Host_Frame (float time)
else else
host_time += host_frametime; //FIXME is this needed? vcr stuff host_time += host_frametime; //FIXME is this needed? vcr stuff
if (cls.demo_capture) {
tex_t *tex = SCR_CaptureBGR ();
WritePNGqfs (va ("%s/qfmv%06d.png", qfs_gamedir->dir.shots,
cls.demo_capture++),
tex->data, tex->width, tex->height);
free (tex);
}
host_framecount++; host_framecount++;
fps_count++; fps_count++;
} }

View file

@ -33,6 +33,7 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include "QF/cdaudio.h" #include "QF/cdaudio.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/plugin.h" #include "QF/plugin.h"
#include "QF/screen.h"
#include "host.h" #include "host.h"
#include "server.h" #include "server.h"
@ -70,6 +71,13 @@ CL_UpdateScreen (double realtime)
{ {
} }
struct tex_s *
SCR_CaptureBGR (void)
{
return 0;
}
void void
CL_Cmd_ForwardToServer (void) CL_Cmd_ForwardToServer (void)
{ {

View file

@ -167,6 +167,7 @@ typedef struct
// demo recording info must be here, because record is started before // demo recording info must be here, because record is started before
// entering a map (and clearing client_state_t) // entering a map (and clearing client_state_t)
qboolean demorecording; qboolean demorecording;
qboolean demo_capture;
qboolean demoplayback; qboolean demoplayback;
qboolean demoplayback2; qboolean demoplayback2;
qboolean findtrack; qboolean findtrack;

View file

@ -144,6 +144,7 @@ CL_StopPlayback (void)
Qclose (cls.demofile); Qclose (cls.demofile);
cls.demofile = NULL; cls.demofile = NULL;
CL_SetState (ca_disconnected); CL_SetState (ca_disconnected);
cls.demo_capture = 0;
cls.demoplayback = 0; cls.demoplayback = 0;
cls.demoplayback2 = 0; cls.demoplayback2 = 0;
demotime_cached = 0; demotime_cached = 0;
@ -933,7 +934,17 @@ CL_StartDemo (void)
static void static void
CL_PlayDemo_f (void) CL_PlayDemo_f (void)
{ {
if (Cmd_Argc () != 2) { switch (Cmd_Argc ()) {
case 2:
cls.demo_capture = 0;
break;
case 3:
if (!strcmp (Cmd_Argv (2), "rec")) {
cls.demo_capture = 1;
break;
}
// fall through
default:
Sys_Printf ("play <demoname> : plays a demo\n"); Sys_Printf ("play <demoname> : plays a demo\n");
return; return;
} }

View file

@ -71,11 +71,13 @@ static __attribute__ ((used)) const char rcsid[] =
#include "QF/console.h" #include "QF/console.h"
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/draw.h" #include "QF/draw.h"
#include "QF/image.h"
#include "QF/input.h" #include "QF/input.h"
#include "QF/keys.h" #include "QF/keys.h"
#include "QF/model.h" #include "QF/model.h"
#include "QF/msg.h" #include "QF/msg.h"
#include "QF/plugin.h" #include "QF/plugin.h"
#include "QF/png.h"
#include "QF/progs.h" #include "QF/progs.h"
#include "QF/qargs.h" #include "QF/qargs.h"
#include "QF/qendian.h" #include "QF/qendian.h"
@ -1488,7 +1490,7 @@ Host_SimulationTime (float time)
if (oldrealtime > realtime) if (oldrealtime > realtime)
oldrealtime = 0; oldrealtime = 0;
if (cls.timedemo) if (cls.demoplayback)
return 0; return 0;
if (cl_maxfps->value <= 0) if (cl_maxfps->value <= 0)
@ -1523,6 +1525,9 @@ Host_Frame (float time)
// something bad happened, or the server disconnected // something bad happened, or the server disconnected
return; return;
if (cls.demo_capture)
time = 1.0 / 30; //FIXME fixed 30fps atm
// decide the simulation time // decide the simulation time
if ((sleeptime = Host_SimulationTime (time)) != 0) { if ((sleeptime = Host_SimulationTime (time)) != 0) {
#ifdef HAVE_USLEEP #ifdef HAVE_USLEEP
@ -1623,6 +1628,14 @@ Host_Frame (float time)
pass1 + pass2 + pass3, pass1, pass2, pass3); pass1 + pass2 + pass3, pass1, pass2, pass3);
} }
if (cls.demo_capture) {
tex_t *tex = SCR_CaptureBGR ();
WritePNGqfs (va ("%s/qfmv%06d.png", qfs_gamedir->dir.shots,
cls.demo_capture++),
tex->data, tex->width, tex->height);
free (tex);
}
host_framecount++; host_framecount++;
fps_count++; fps_count++;
} }