mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 15:01:41 +00:00
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:
parent
b13a2b6dbd
commit
423e08ce21
12 changed files with 186 additions and 38 deletions
|
@ -56,6 +56,7 @@ void SCR_DrawTurtle (void);
|
|||
void SCR_DrawPause (void);
|
||||
|
||||
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);
|
||||
int MipColor (int r, int g, int b);
|
||||
int SCR_ModalMessage (const char *text);
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static __attribute__ ((used)) const char rcsid[] =
|
||||
"$Id$";
|
||||
static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
|
@ -66,6 +65,24 @@ static __attribute__ ((used)) const char rcsid[] =
|
|||
|
||||
/* 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 *
|
||||
SCR_ScreenShot (int width, int height)
|
||||
{
|
||||
|
@ -133,20 +150,18 @@ SCR_ScreenShot (int width, int height)
|
|||
void
|
||||
SCR_ScreenShot_f (void)
|
||||
{
|
||||
byte *buffer;
|
||||
dstring_t *pcxname = dstring_new ();
|
||||
|
||||
// find a file name to save it to
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (pcxname,
|
||||
va ("%s/qf", qfs_gamedir->dir.shots), ".tga")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
|
||||
} else {
|
||||
buffer = malloc (vid.width * vid.height * 3);
|
||||
SYS_CHECKMEM (buffer);
|
||||
qfglReadPixels (0, 0, vid.width, vid.height, GL_BGR_EXT,
|
||||
GL_UNSIGNED_BYTE, buffer);
|
||||
WriteTGAfile (pcxname->str, buffer, vid.width, vid.height);
|
||||
free (buffer);
|
||||
tex_t *tex;
|
||||
|
||||
tex = SCR_CaptureBGR ();
|
||||
WriteTGAfile (pcxname->str, tex->data, tex->width, tex->height);
|
||||
free (tex);
|
||||
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, pcxname->str);
|
||||
}
|
||||
dstring_delete (pcxname);
|
||||
|
|
|
@ -203,6 +203,31 @@ SCR_UpdateScreen (double realtime, SCR_Func *scr_funcs)
|
|||
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 *
|
||||
SCR_ScreenShot (int width, int height)
|
||||
{
|
||||
|
@ -212,28 +237,18 @@ SCR_ScreenShot (int width, int height)
|
|||
VISIBLE void
|
||||
SCR_ScreenShot_f (void)
|
||||
{
|
||||
byte *buffer, *r, *b;
|
||||
dstring_t *name = dstring_new ();
|
||||
int size, i;
|
||||
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (name,
|
||||
va ("%s/qf", qfs_gamedir->dir.shots), ".png")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n");
|
||||
} else {
|
||||
size = vid.width * vid.height;
|
||||
buffer = malloc (size * 3);
|
||||
SYS_CHECKMEM (buffer);
|
||||
qfglReadPixels (0, 0, vid.width, vid.height, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, buffer);
|
||||
// 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);
|
||||
tex_t *tex;
|
||||
|
||||
tex = SCR_CaptureBGR ();
|
||||
WritePNGqfs (name->str, tex->data, tex->width, tex->height);
|
||||
free (tex);
|
||||
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, name->str);
|
||||
}
|
||||
dstring_delete (name);
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static __attribute__ ((used)) const char rcsid[] =
|
||||
"$Id$";
|
||||
static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
|
@ -87,6 +86,36 @@ SCR_ApplyBlend (void) // Used to be V_UpdatePalette
|
|||
|
||||
/* 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 *
|
||||
SCR_ScreenShot (int width, int height)
|
||||
{
|
||||
|
@ -159,7 +188,7 @@ SCR_ScreenShot_f (void)
|
|||
pcx_t *pcx;
|
||||
int pcx_len;
|
||||
|
||||
// find a file name to save it to
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (pcxname,
|
||||
va ("%s/qf", qfs_gamedir->dir.shots), ".pcx")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
|
||||
|
|
|
@ -28,8 +28,7 @@
|
|||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static __attribute__ ((used)) const char rcsid[] =
|
||||
"$Id$";
|
||||
static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
|
@ -155,6 +154,36 @@ SCR_ApplyBlend (void) // Used to be V_UpdatePalette
|
|||
|
||||
/* 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 *
|
||||
SCR_ScreenShot (int width, int height)
|
||||
{
|
||||
|
@ -168,7 +197,7 @@ SCR_ScreenShot_f (void)
|
|||
pcx_t *pcx = 0;
|
||||
int pcx_len;
|
||||
|
||||
// find a file name to save it to
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (pcxname,
|
||||
va ("%s/qf", qfs_gamedir->dir.shots), ".pcx")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
|
||||
|
|
|
@ -119,6 +119,7 @@ typedef struct
|
|||
// demo recording info must be here, because record is started before
|
||||
// entering a map (and clearing client_state_t)
|
||||
qboolean demorecording;
|
||||
qboolean demo_capture;
|
||||
qboolean demoplayback;
|
||||
qboolean timedemo;
|
||||
int forcetrack; // -1 = use normal cd track
|
||||
|
|
|
@ -126,6 +126,7 @@ CL_StopPlayback (void)
|
|||
Qclose (cls.demofile);
|
||||
cls.demofile = NULL;
|
||||
CL_SetState (ca_disconnected);
|
||||
cls.demo_capture = 0;
|
||||
cls.demoplayback = 0;
|
||||
key_game_target = IMT_0;
|
||||
Key_SetKeyDest (key_game);
|
||||
|
@ -384,9 +385,19 @@ CL_PlayDemo_f (void)
|
|||
if (cmd_source != src_command)
|
||||
return;
|
||||
|
||||
if (Cmd_Argc () != 2) {
|
||||
Sys_Printf ("play <demoname> : plays a demo\n");
|
||||
return;
|
||||
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");
|
||||
return;
|
||||
}
|
||||
timedemo_runs = timedemo_count = 1; // make sure looped timedemos stop
|
||||
strncpy (demoname, Cmd_Argv (1), sizeof (demoname));
|
||||
|
|
|
@ -41,12 +41,15 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
|||
#include "QF/cmd.h"
|
||||
#include "QF/console.h"
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/image.h"
|
||||
#include "QF/input.h"
|
||||
#include "QF/keys.h"
|
||||
#include "QF/msg.h"
|
||||
#include "QF/plugin.h"
|
||||
#include "QF/png.h"
|
||||
#include "QF/progs.h"
|
||||
#include "QF/qargs.h"
|
||||
#include "QF/screen.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
#include "QF/vid.h"
|
||||
|
@ -638,6 +641,9 @@ _Host_Frame (float time)
|
|||
|
||||
rand (); // keep the random time dependent
|
||||
|
||||
if (cls.demo_capture)
|
||||
time = 1.0 / 30; //FIXME fixed 30fps atm
|
||||
|
||||
// decide the simulation time
|
||||
if ((sleeptime = Host_FilterTime (time)) != 0) {
|
||||
// don't run too fast, or packet will flood outs
|
||||
|
@ -685,6 +691,14 @@ _Host_Frame (float time)
|
|||
else
|
||||
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++;
|
||||
fps_count++;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
|||
#include "QF/cdaudio.h"
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/plugin.h"
|
||||
#include "QF/screen.h"
|
||||
|
||||
#include "host.h"
|
||||
#include "server.h"
|
||||
|
@ -70,6 +71,13 @@ CL_UpdateScreen (double realtime)
|
|||
{
|
||||
}
|
||||
|
||||
struct tex_s *
|
||||
SCR_CaptureBGR (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CL_Cmd_ForwardToServer (void)
|
||||
{
|
||||
|
|
|
@ -167,6 +167,7 @@ typedef struct
|
|||
// demo recording info must be here, because record is started before
|
||||
// entering a map (and clearing client_state_t)
|
||||
qboolean demorecording;
|
||||
qboolean demo_capture;
|
||||
qboolean demoplayback;
|
||||
qboolean demoplayback2;
|
||||
qboolean findtrack;
|
||||
|
|
|
@ -144,6 +144,7 @@ CL_StopPlayback (void)
|
|||
Qclose (cls.demofile);
|
||||
cls.demofile = NULL;
|
||||
CL_SetState (ca_disconnected);
|
||||
cls.demo_capture = 0;
|
||||
cls.demoplayback = 0;
|
||||
cls.demoplayback2 = 0;
|
||||
demotime_cached = 0;
|
||||
|
@ -933,9 +934,19 @@ CL_StartDemo (void)
|
|||
static void
|
||||
CL_PlayDemo_f (void)
|
||||
{
|
||||
if (Cmd_Argc () != 2) {
|
||||
Sys_Printf ("play <demoname> : plays a demo\n");
|
||||
return;
|
||||
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");
|
||||
return;
|
||||
}
|
||||
timedemo_runs = timedemo_count = 1; // make sure looped timedemos stop
|
||||
// disconnect from server
|
||||
|
|
|
@ -71,11 +71,13 @@ static __attribute__ ((used)) const char rcsid[] =
|
|||
#include "QF/console.h"
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/draw.h"
|
||||
#include "QF/image.h"
|
||||
#include "QF/input.h"
|
||||
#include "QF/keys.h"
|
||||
#include "QF/model.h"
|
||||
#include "QF/msg.h"
|
||||
#include "QF/plugin.h"
|
||||
#include "QF/png.h"
|
||||
#include "QF/progs.h"
|
||||
#include "QF/qargs.h"
|
||||
#include "QF/qendian.h"
|
||||
|
@ -1488,7 +1490,7 @@ Host_SimulationTime (float time)
|
|||
if (oldrealtime > realtime)
|
||||
oldrealtime = 0;
|
||||
|
||||
if (cls.timedemo)
|
||||
if (cls.demoplayback)
|
||||
return 0;
|
||||
|
||||
if (cl_maxfps->value <= 0)
|
||||
|
@ -1523,6 +1525,9 @@ Host_Frame (float time)
|
|||
// something bad happened, or the server disconnected
|
||||
return;
|
||||
|
||||
if (cls.demo_capture)
|
||||
time = 1.0 / 30; //FIXME fixed 30fps atm
|
||||
|
||||
// decide the simulation time
|
||||
if ((sleeptime = Host_SimulationTime (time)) != 0) {
|
||||
#ifdef HAVE_USLEEP
|
||||
|
@ -1623,6 +1628,14 @@ Host_Frame (float time)
|
|||
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++;
|
||||
fps_count++;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue