mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-19 07:20:50 +00:00
[renderer] Merge screenshot code as much as possible
Only CaptureBGR is per-renderer as the rest of the screenshot code uses it to do the actual capture (which is target dependent). Vulkan is currently broken due to capture being an asynchronous process and the rest of the code expecting capture to be synchronous (also, bgr vs rgb). The best thing is all renderers now write the same format (currently png).
This commit is contained in:
parent
2eae2e5d74
commit
ea2fd32228
13 changed files with 98 additions and 281 deletions
|
@ -97,9 +97,6 @@ typedef struct vid_render_funcs_s {
|
|||
void (*Draw_SubPic) (int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height);
|
||||
|
||||
struct tex_s *(*SCR_CaptureBGR) (void);
|
||||
struct tex_s *(*SCR_ScreenShot) (unsigned width, unsigned height);
|
||||
void (*SCR_DrawStringToSnap) (const char *s, struct tex_s *tex,
|
||||
int x, int y);
|
||||
|
||||
void (*Fog_Update) (float density, float red, float green, float blue,
|
||||
float time);
|
||||
|
@ -112,9 +109,7 @@ typedef struct vid_render_funcs_s {
|
|||
void (*R_LoadSkys) (const char *);
|
||||
void (*R_NewMap) (model_t *worldmodel, model_t **models, int num_models);
|
||||
void (*R_LineGraph) (int x, int y, int *h_vals, int count, int height);
|
||||
|
||||
void (*R_ViewChanged) (void);
|
||||
void (*SCR_ScreenShot_f) (void);
|
||||
|
||||
vid_model_funcs_t *model_funcs;
|
||||
} vid_render_funcs_t;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#define __QF_screen_h
|
||||
|
||||
struct transform_s;
|
||||
struct tex_s;
|
||||
|
||||
void SCR_Init (void);
|
||||
void SCR_SetFOV (float fov);
|
||||
|
@ -42,6 +43,8 @@ typedef void (*SCR_Func)(void);
|
|||
// scr_funcs is a null terminated array
|
||||
void SCR_UpdateScreen (struct transform_s *camera, double realtime,
|
||||
SCR_Func *scr_funcs);
|
||||
void SCR_DrawStringToSnap (const char *s, struct tex_s *tex, int x, int y);
|
||||
struct tex_s *SCR_SnapScreen (unsigned width, unsigned height);
|
||||
|
||||
extern struct cvar_s *hud_fps, *hud_time;
|
||||
|
||||
|
|
|
@ -83,89 +83,6 @@ gl_SCR_CaptureBGR (void)
|
|||
return tex;
|
||||
}
|
||||
|
||||
tex_t *
|
||||
gl_SCR_ScreenShot (unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char *src, *dest, *snap;
|
||||
float fracw, frach;
|
||||
int count, dex, dey, dx, dy, nx, r, g, b, x, y, w, h;
|
||||
tex_t *tex;
|
||||
|
||||
snap = Hunk_TempAlloc (0, vid.width * vid.height * 3);
|
||||
|
||||
qfglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE,
|
||||
snap);
|
||||
|
||||
w = (vid.width < width) ? vid.width : width;
|
||||
h = (vid.height < height) ? vid.height : height;
|
||||
|
||||
fracw = (float) vid.width / (float) w;
|
||||
frach = (float) vid.height / (float) h;
|
||||
|
||||
tex = malloc (sizeof (tex_t) + w * h);
|
||||
tex->data = (byte *) (tex + 1);
|
||||
if (!tex)
|
||||
return 0;
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->palette = vid.palette;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
dest = tex->data + (w * y);
|
||||
|
||||
for (x = 0; x < w; x++) {
|
||||
r = g = b = 0;
|
||||
|
||||
dx = x * fracw;
|
||||
dex = (x + 1) * fracw;
|
||||
if (dex == dx)
|
||||
dex++; // at least one
|
||||
dy = y * frach;
|
||||
dey = (y + 1) * frach;
|
||||
if (dey == dy)
|
||||
dey++; // at least one
|
||||
|
||||
count = 0;
|
||||
for (; dy < dey; dy++) {
|
||||
src = snap + (vid.width * 3 * dy) + dx * 3;
|
||||
for (nx = dx; nx < dex; nx++) {
|
||||
r += *src++;
|
||||
g += *src++;
|
||||
b += *src++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
r /= count;
|
||||
g /= count;
|
||||
b /= count;
|
||||
*dest++ = MipColor (r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void
|
||||
gl_SCR_ScreenShot_f (void)
|
||||
{
|
||||
dstring_t *pcxname = dstring_new ();
|
||||
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (pcxname,
|
||||
va (0, "%s/qf", qfs_gamedir->dir.shots), ".tga")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
|
||||
} else {
|
||||
tex_t *tex;
|
||||
|
||||
tex = gl_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);
|
||||
}
|
||||
|
||||
static void
|
||||
SCR_TileClear (void)
|
||||
{
|
||||
|
|
|
@ -219,29 +219,3 @@ glsl_SCR_CaptureBGR (void)
|
|||
}
|
||||
return tex;
|
||||
}
|
||||
|
||||
__attribute__((const)) tex_t *
|
||||
glsl_SCR_ScreenShot (unsigned width, unsigned height)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
glsl_SCR_ScreenShot_f (void)
|
||||
{
|
||||
dstring_t *name = dstring_new ();
|
||||
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (name, va (0, "%s/qf",
|
||||
qfs_gamedir->dir.shots), ".png")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n");
|
||||
} else {
|
||||
tex_t *tex;
|
||||
|
||||
tex = glsl_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);
|
||||
}
|
||||
|
|
|
@ -38,11 +38,15 @@
|
|||
#include "QF/cmd.h"
|
||||
#include "QF/cvar.h"
|
||||
#include "QF/draw.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/image.h"
|
||||
#include "QF/png.h"
|
||||
#include "QF/pcx.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/render.h"
|
||||
#include "QF/screen.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "QF/scene/transform.h"
|
||||
#include "QF/ui/view.h"
|
||||
|
@ -185,7 +189,21 @@ SCR_SetFOV (float fov)
|
|||
static void
|
||||
ScreenShot_f (void)
|
||||
{
|
||||
r_funcs->SCR_ScreenShot_f ();
|
||||
dstring_t *name = dstring_new ();
|
||||
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (name, va (0, "%s/qf",
|
||||
qfs_gamedir->dir.shots), ".png")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PNG file\n");
|
||||
} else {
|
||||
tex_t *tex;
|
||||
|
||||
tex = r_funcs->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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -347,12 +365,74 @@ SCR_DrawStringToSnap (const char *s, tex_t *tex, int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
tex_t *
|
||||
SCR_SnapScreen (unsigned width, unsigned height)
|
||||
{
|
||||
byte *src, *dest;
|
||||
float fracw, frach;
|
||||
unsigned count, dex, dey, dx, dy, nx, r, g, b, x, y, w, h;
|
||||
tex_t *tex;
|
||||
|
||||
tex_t *snap = r_funcs->SCR_CaptureBGR ();
|
||||
|
||||
//FIXME casts
|
||||
w = ((unsigned)snap->width < width) ? (unsigned)snap->width : width;
|
||||
h = ((unsigned)snap->height < height) ? (unsigned)snap->height : height;
|
||||
|
||||
fracw = (float) snap->width / (float) w;
|
||||
frach = (float) snap->height / (float) h;
|
||||
|
||||
tex = malloc (sizeof (tex_t) + w * h);
|
||||
tex->data = (byte *) (tex + 1);
|
||||
if (!tex)
|
||||
return 0;
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->palette = r_data->vid->palette;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
dest = tex->data + (w * y);
|
||||
|
||||
for (x = 0; x < w; x++) {
|
||||
r = g = b = 0;
|
||||
|
||||
dx = x * fracw;
|
||||
dex = (x + 1) * fracw;
|
||||
if (dex == dx)
|
||||
dex++; // at least one
|
||||
dy = y * frach;
|
||||
dey = (y + 1) * frach;
|
||||
if (dey == dy)
|
||||
dey++; // at least one
|
||||
|
||||
count = 0;
|
||||
for (; dy < dey; dy++) {
|
||||
src = snap->data + (snap->width * 3 * dy) + dx * 3;
|
||||
for (nx = dx; nx < dex; nx++) {
|
||||
b += *src++;
|
||||
g += *src++;
|
||||
r += *src++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
r /= count;
|
||||
g /= count;
|
||||
b /= count;
|
||||
*dest++ = MipColor (r, g, b);
|
||||
}
|
||||
}
|
||||
free (snap);
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void
|
||||
SCR_Init (void)
|
||||
{
|
||||
// register our commands
|
||||
Cmd_AddCommand ("screenshot", ScreenShot_f, "Take a screenshot, "
|
||||
"saves as qfxxx.pcx in the current directory");
|
||||
"saves as qfxxxx.png in the QF directory");
|
||||
Cmd_AddCommand ("sizeup", SCR_SizeUp_f, "Increases the screen size");
|
||||
Cmd_AddCommand ("sizedown", SCR_SizeDown_f, "Decreases the screen size");
|
||||
|
||||
|
|
|
@ -85,88 +85,6 @@ SCR_CaptureBGR (void)
|
|||
return tex;
|
||||
}
|
||||
|
||||
tex_t *
|
||||
SCR_ScreenShot (unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char *src, *dest;
|
||||
float fracw, frach;
|
||||
int count, dex, dey, dx, dy, nx, r, g, b, x, y, w, h;
|
||||
tex_t *tex;
|
||||
|
||||
w = (vid.width < width) ? vid.width : width;
|
||||
h = (vid.height < height) ? vid.height : height;
|
||||
|
||||
fracw = (float) vid.width / (float) w;
|
||||
frach = (float) vid.height / (float) h;
|
||||
|
||||
tex = malloc (sizeof (tex_t) + w * h);
|
||||
tex->data = (byte *) (tex + 1);
|
||||
if (!tex)
|
||||
return 0;
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->palette = vid.palette;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
dest = tex->data + (w * (h - y - 1));
|
||||
|
||||
for (x = 0; x < w; x++) {
|
||||
r = g = b = 0;
|
||||
|
||||
dx = x * fracw;
|
||||
dex = (x + 1) * fracw;
|
||||
if (dex == dx)
|
||||
dex++; // at least one
|
||||
dy = y * frach;
|
||||
dey = (y + 1) * frach;
|
||||
if (dey == dy)
|
||||
dey++; // at least one
|
||||
|
||||
count = 0;
|
||||
for (; dy < dey; dy++) {
|
||||
src = ((byte*)vid.buffer) + (vid.rowbytes * dy) + dx;
|
||||
for (nx = dx; nx < dex; nx++) {
|
||||
r += vid.basepal[*src * 3];
|
||||
g += vid.basepal[*src * 3 + 1];
|
||||
b += vid.basepal[*src * 3 + 2];
|
||||
src++;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
r /= count;
|
||||
g /= count;
|
||||
b /= count;
|
||||
*dest++ = MipColor (r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void
|
||||
SCR_ScreenShot_f (void)
|
||||
{
|
||||
dstring_t *pcxname = dstring_new ();
|
||||
pcx_t *pcx;
|
||||
int pcx_len;
|
||||
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (pcxname,
|
||||
va (0, "%s/qf", qfs_gamedir->dir.shots), ".pcx")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
|
||||
} else {
|
||||
// save the pcx file
|
||||
pcx = EncodePCX (vid.buffer, vid.width, vid.height, vid.rowbytes,
|
||||
vid.basepal, false, &pcx_len);
|
||||
QFS_WriteFile (pcxname->str, pcx, pcx_len);
|
||||
|
||||
|
||||
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, pcxname->str);
|
||||
}
|
||||
dstring_delete (pcxname);
|
||||
}
|
||||
|
||||
void
|
||||
R_RenderFrame (SCR_Func *scr_funcs)
|
||||
{
|
||||
|
|
|
@ -88,48 +88,6 @@ sw32_SCR_CaptureBGR (void)
|
|||
return tex;
|
||||
}
|
||||
|
||||
__attribute__((const)) tex_t *
|
||||
sw32_SCR_ScreenShot (unsigned width, unsigned height)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sw32_SCR_ScreenShot_f (void)
|
||||
{
|
||||
dstring_t *pcxname = dstring_new ();
|
||||
pcx_t *pcx = 0;
|
||||
int pcx_len;
|
||||
|
||||
// find a file name to save it to
|
||||
if (!QFS_NextFilename (pcxname, va (0, "%s/qf",
|
||||
qfs_gamedir->dir.shots), ".pcx")) {
|
||||
Sys_Printf ("SCR_ScreenShot_f: Couldn't create a PCX");
|
||||
} else {
|
||||
// save the pcx file
|
||||
switch(sw32_ctx->pixbytes) {
|
||||
case 1:
|
||||
pcx = EncodePCX (vid.buffer, vid.width, vid.height, vid.rowbytes,
|
||||
vid.basepal, false, &pcx_len);
|
||||
break;
|
||||
case 2:
|
||||
Sys_Printf("SCR_ScreenShot_f: FIXME - add 16bit support\n");
|
||||
break;
|
||||
case 4:
|
||||
Sys_Printf("SCR_ScreenShot_f: FIXME - add 32bit support\n");
|
||||
break;
|
||||
default:
|
||||
Sys_Error("SCR_ScreenShot_f: unsupported r_pixbytes %i", sw32_ctx->pixbytes);
|
||||
}
|
||||
|
||||
if (pcx) {
|
||||
QFS_WriteFile (pcxname->str, pcx, pcx_len);
|
||||
Sys_Printf ("Wrote %s/%s\n", qfs_userpath, pcxname->str);
|
||||
}
|
||||
}
|
||||
dstring_delete (pcxname);
|
||||
}
|
||||
|
||||
void
|
||||
sw32_R_RenderFrame (SCR_Func *scr_funcs)
|
||||
{
|
||||
|
|
|
@ -132,8 +132,6 @@ vid_render_funcs_t gl_vid_render_funcs = {
|
|||
gl_Draw_SubPic,
|
||||
|
||||
gl_SCR_CaptureBGR,
|
||||
gl_SCR_ScreenShot,
|
||||
SCR_DrawStringToSnap,
|
||||
|
||||
gl_Fog_Update,
|
||||
gl_Fog_ParseWorldspawn,
|
||||
|
@ -146,7 +144,6 @@ vid_render_funcs_t gl_vid_render_funcs = {
|
|||
gl_R_NewMap,
|
||||
gl_R_LineGraph,
|
||||
gl_R_ViewChanged,
|
||||
gl_SCR_ScreenShot_f,
|
||||
&model_funcs
|
||||
};
|
||||
|
||||
|
|
|
@ -131,8 +131,6 @@ vid_render_funcs_t glsl_vid_render_funcs = {
|
|||
glsl_Draw_SubPic,
|
||||
|
||||
glsl_SCR_CaptureBGR,
|
||||
glsl_SCR_ScreenShot,
|
||||
SCR_DrawStringToSnap,
|
||||
|
||||
glsl_Fog_Update,
|
||||
glsl_Fog_ParseWorldspawn,
|
||||
|
@ -145,7 +143,6 @@ vid_render_funcs_t glsl_vid_render_funcs = {
|
|||
glsl_R_NewMap,
|
||||
glsl_R_LineGraph,
|
||||
glsl_R_ViewChanged,
|
||||
glsl_SCR_ScreenShot_f,
|
||||
&model_funcs
|
||||
};
|
||||
|
||||
|
|
|
@ -128,8 +128,6 @@ vid_render_funcs_t sw_vid_render_funcs = {
|
|||
Draw_SubPic,
|
||||
|
||||
SCR_CaptureBGR,
|
||||
SCR_ScreenShot,
|
||||
SCR_DrawStringToSnap,
|
||||
|
||||
0,
|
||||
0,
|
||||
|
@ -142,7 +140,6 @@ vid_render_funcs_t sw_vid_render_funcs = {
|
|||
R_NewMap,
|
||||
R_LineGraph,
|
||||
R_ViewChanged,
|
||||
SCR_ScreenShot_f,
|
||||
&model_funcs
|
||||
};
|
||||
|
||||
|
|
|
@ -133,8 +133,6 @@ vid_render_funcs_t sw32_vid_render_funcs = {
|
|||
sw32_Draw_SubPic,
|
||||
|
||||
sw32_SCR_CaptureBGR,
|
||||
sw32_SCR_ScreenShot,
|
||||
SCR_DrawStringToSnap,
|
||||
|
||||
0,
|
||||
0,
|
||||
|
@ -147,7 +145,6 @@ vid_render_funcs_t sw32_vid_render_funcs = {
|
|||
sw32_R_NewMap,
|
||||
sw32_R_LineGraph,
|
||||
sw32_R_ViewChanged,
|
||||
sw32_SCR_ScreenShot_f,
|
||||
&model_funcs
|
||||
};
|
||||
|
||||
|
|
|
@ -70,18 +70,6 @@
|
|||
|
||||
static vulkan_ctx_t *vulkan_ctx;
|
||||
|
||||
static tex_t *
|
||||
vulkan_SCR_CaptureBGR (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static tex_t *
|
||||
vulkan_SCR_ScreenShot (unsigned width, unsigned height)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
vulkan_Fog_Update (float density, float red, float green, float blue,
|
||||
float time)
|
||||
|
@ -442,14 +430,16 @@ capture_screenshot (const byte *data, int width, int height)
|
|||
dstring_delete (name);
|
||||
}
|
||||
|
||||
static void
|
||||
vulkan_SCR_ScreenShot_f (void)
|
||||
static tex_t *
|
||||
vulkan_SCR_CaptureBGR (void)
|
||||
{
|
||||
if (!vulkan_ctx->capture) {
|
||||
Sys_Printf ("Screenshot not supported\n");
|
||||
return;
|
||||
Sys_Printf ("Capture not supported\n");
|
||||
return 0;
|
||||
}
|
||||
vulkan_ctx->capture_callback = capture_screenshot;
|
||||
//FIXME async process
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -662,8 +652,6 @@ vid_render_funcs_t vulkan_vid_render_funcs = {
|
|||
vulkan_Draw_SubPic,
|
||||
|
||||
vulkan_SCR_CaptureBGR,
|
||||
vulkan_SCR_ScreenShot,
|
||||
SCR_DrawStringToSnap,
|
||||
|
||||
vulkan_Fog_Update,
|
||||
vulkan_Fog_ParseWorldspawn,
|
||||
|
@ -676,7 +664,6 @@ vid_render_funcs_t vulkan_vid_render_funcs = {
|
|||
vulkan_R_NewMap,
|
||||
vulkan_R_LineGraph,
|
||||
vulkan_R_ViewChanged,
|
||||
vulkan_SCR_ScreenShot_f,
|
||||
&model_funcs
|
||||
};
|
||||
|
||||
|
|
|
@ -61,25 +61,22 @@ CL_RSShot_f (void)
|
|||
|
||||
Sys_Printf ("Remote screen shot requested.\n");
|
||||
|
||||
tex = r_funcs->SCR_ScreenShot (RSSHOT_WIDTH, RSSHOT_HEIGHT);
|
||||
tex = SCR_SnapScreen (RSSHOT_WIDTH, RSSHOT_HEIGHT);
|
||||
|
||||
if (tex) {
|
||||
time (&now);
|
||||
st = dstring_strdup (ctime (&now));
|
||||
dstring_snip (st, strlen (st->str) - 1, 1);
|
||||
r_funcs->SCR_DrawStringToSnap (st->str, tex,
|
||||
tex->width - strlen (st->str) * 8,
|
||||
tex->height - 1);
|
||||
SCR_DrawStringToSnap (st->str, tex, tex->width - strlen (st->str) * 8,
|
||||
tex->height - 1);
|
||||
|
||||
dstring_copystr (st, cls.servername->str);
|
||||
r_funcs->SCR_DrawStringToSnap (st->str, tex,
|
||||
tex->width - strlen (st->str) * 8,
|
||||
tex->height - 11);
|
||||
SCR_DrawStringToSnap (st->str, tex, tex->width - strlen (st->str) * 8,
|
||||
tex->height - 11);
|
||||
|
||||
dstring_copystr (st, cl_name->string);
|
||||
r_funcs->SCR_DrawStringToSnap (st->str, tex,
|
||||
tex->width - strlen (st->str) * 8,
|
||||
tex->height - 21);
|
||||
SCR_DrawStringToSnap (st->str, tex, tex->width - strlen (st->str) * 8,
|
||||
tex->height - 21);
|
||||
|
||||
pcx = EncodePCX (tex->data, tex->width, tex->height, tex->width,
|
||||
r_data->vid->basepal, true, &pcx_len);
|
||||
|
|
Loading…
Reference in a new issue