fixed picmip simpleitems issue.
fixed double picmip bug. use pbos for videocapture, for extra speed. mwahaha. fix issues with 2d batching. including drawflags. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4962 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
5f7243c6dc
commit
a26a373d15
19 changed files with 424 additions and 175 deletions
|
@ -3686,7 +3686,7 @@ void CL_LinkPacketEntities (void)
|
|||
Q_snprintfz(name, sizeof(name), "textures/bmodels/simple_%s_%i.tga", basename, ent->skinnum);
|
||||
else
|
||||
Q_snprintfz(name, sizeof(name), "textures/models/simple_%s_%i.tga", basename, ent->skinnum);
|
||||
model->simpleskin[ent->skinnum] = R_RegisterShader(name, 0, va("{\nprogram defaultsprite\nsurfaceparm noshadows\nsurfaceparm nodlight\nsort seethrough\n{\nmap \"%s\"\nalphafunc ge128\n}\n}\n", name));
|
||||
model->simpleskin[ent->skinnum] = R_RegisterShader(name, 0, va("{\nnomipmaps\nprogram defaultsprite\nsurfaceparm noshadows\nsurfaceparm nodlight\nsort seethrough\n{\nmap \"%s\"\nalphafunc ge128\n}\n}\n", name));
|
||||
}
|
||||
VectorCopy(le->angles, angles);
|
||||
|
||||
|
|
|
@ -2031,13 +2031,96 @@ typedef struct _TargaHeader {
|
|||
|
||||
|
||||
#if defined(AVAIL_JPEGLIB) && !defined(NO_JPEG)
|
||||
qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight);
|
||||
qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight, enum uploadfmt fmt);
|
||||
#endif
|
||||
#ifdef AVAIL_PNGLIB
|
||||
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height);
|
||||
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height, enum uploadfmt fmt);
|
||||
#endif
|
||||
void WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int width, int height);
|
||||
|
||||
qboolean WriteTGA(char *filename, enum fs_relative fsroot, qbyte *rgb_buffer, int width, int height, enum uploadfmt fmt)
|
||||
{
|
||||
size_t c, i;
|
||||
vfsfile_t *vfs;
|
||||
if (fmt != TF_BGRA32 && fmt != TF_RGB24 && fmt != TF_RGBA32 && fmt != TF_BGR24)
|
||||
return false;
|
||||
FS_CreatePath(filename, fsroot);
|
||||
vfs = FS_OpenVFS(filename, "wb", fsroot);
|
||||
if (vfs)
|
||||
{
|
||||
unsigned char header[18];
|
||||
memset (header, 0, 18);
|
||||
header[2] = 2; // uncompressed type
|
||||
header[12] = width&255;
|
||||
header[13] = width>>8;
|
||||
header[14] = height&255;
|
||||
header[15] = height>>8;
|
||||
header[16] = 24; // pixel size
|
||||
|
||||
if (fmt == TF_BGRA32)
|
||||
{
|
||||
#if 0
|
||||
header[16] = 32;
|
||||
#else
|
||||
qbyte tmp[3];
|
||||
// compact+swap
|
||||
c = width*height;
|
||||
for (i=0 ; i<c ; i++)
|
||||
{
|
||||
tmp[0] = rgb_buffer[i*4+0];
|
||||
tmp[1] = rgb_buffer[i*4+1];
|
||||
tmp[2] = rgb_buffer[i*4+2];
|
||||
rgb_buffer[i*3+0] = tmp[0];
|
||||
rgb_buffer[i*3+1] = tmp[1];
|
||||
rgb_buffer[i*3+2] = tmp[2];
|
||||
}
|
||||
c *= 3;
|
||||
#endif
|
||||
}
|
||||
else if (fmt == TF_BGR24)
|
||||
c = width*height*3;
|
||||
else if (fmt == TF_RGBA32)
|
||||
{
|
||||
int s = 3;
|
||||
qbyte tmp[3];
|
||||
#if 0
|
||||
s = 4;
|
||||
header[16] = s*8;
|
||||
#endif
|
||||
// compact+swap
|
||||
c = width*height;
|
||||
for (i=0 ; i<c ; i++)
|
||||
{
|
||||
tmp[0] = rgb_buffer[i*4+0];
|
||||
tmp[1] = rgb_buffer[i*4+1];
|
||||
tmp[2] = rgb_buffer[i*4+2];
|
||||
rgb_buffer[i*s+0] = tmp[2];
|
||||
rgb_buffer[i*s+1] = tmp[1];
|
||||
rgb_buffer[i*s+2] = tmp[0];
|
||||
}
|
||||
c *= s;
|
||||
}
|
||||
else if (fmt == TF_RGB24)
|
||||
{
|
||||
qbyte temp;
|
||||
// swap r+b in place
|
||||
c = width*height*3;
|
||||
for (i=0 ; i<c ; i+=3)
|
||||
{
|
||||
temp = rgb_buffer[i];
|
||||
rgb_buffer[i] = rgb_buffer[i+2];
|
||||
rgb_buffer[i+2] = temp;
|
||||
}
|
||||
}
|
||||
else
|
||||
c = 0;
|
||||
VFS_WRITE(vfs, header, sizeof(header));
|
||||
VFS_WRITE(vfs, rgb_buffer, c);
|
||||
VFS_CLOSE(vfs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Find closest color in the palette for named color
|
||||
*/
|
||||
|
@ -2071,9 +2154,8 @@ int MipColor(int r, int g, int b)
|
|||
return best;
|
||||
}
|
||||
|
||||
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height)
|
||||
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height, enum uploadfmt fmt)
|
||||
{
|
||||
int i, c, temp;
|
||||
#if defined(AVAIL_PNGLIB) || defined(AVAIL_JPEGLIB)
|
||||
extern cvar_t scr_sshot_compression;
|
||||
#endif
|
||||
|
@ -2088,70 +2170,66 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buff
|
|||
#ifdef AVAIL_PNGLIB
|
||||
if (!Q_strcasecmp(ext, "png"))
|
||||
{
|
||||
return Image_WritePNG(filename, fsroot, scr_sshot_compression.value, rgb_buffer, width, height);
|
||||
//png can do bgr+rgb
|
||||
//rgba bgra will result in an extra alpha chan
|
||||
return Image_WritePNG(filename, fsroot, scr_sshot_compression.value, rgb_buffer, width, height, fmt);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef AVAIL_JPEGLIB
|
||||
if (!Q_strcasecmp(ext, "jpeg") || !Q_strcasecmp(ext, "jpg"))
|
||||
{
|
||||
return screenshotJPEG(filename, fsroot, scr_sshot_compression.value, rgb_buffer, width, height);
|
||||
return screenshotJPEG(filename, fsroot, scr_sshot_compression.value, rgb_buffer, width, height, fmt);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* if (!Q_strcasecmp(ext, "bmp"))
|
||||
{
|
||||
WriteBMPFile(pcxname, rgb_buffer, width, height);
|
||||
return WriteBMPFile(pcxname, rgb_buffer, width, height);
|
||||
}
|
||||
else*/
|
||||
if (!Q_strcasecmp(ext, "pcx"))
|
||||
{
|
||||
int y, x;
|
||||
int y, x, s;
|
||||
qbyte *src, *dest;
|
||||
qbyte *newbuf = rgb_buffer;
|
||||
// convert in-place to eight bit
|
||||
for (y = 0; y < height; y++)
|
||||
if (fmt == TF_RGB24 || fmt == TF_RGBA32)
|
||||
{
|
||||
src = newbuf + (width * 3 * y);
|
||||
dest = newbuf + (width * y);
|
||||
s = (fmt == TF_RGB24)?3:4;
|
||||
// convert in-place to eight bit
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = newbuf + (width * s * y);
|
||||
dest = newbuf + (width * y);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
*dest++ = MipColor(src[0], src[1], src[2]);
|
||||
src += 3;
|
||||
for (x = 0; x < width; x++) {
|
||||
*dest++ = MipColor(src[0], src[1], src[2]);
|
||||
src += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fmt == TF_BGR24 || fmt == TF_BGRA32)
|
||||
{
|
||||
s = (fmt == TF_BGR24)?3:4;
|
||||
// convert in-place to eight bit
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = newbuf + (width * s * y);
|
||||
dest = newbuf + (width * y);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
*dest++ = MipColor(src[2], src[1], src[0]);
|
||||
src += s;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
WritePCXfile (filename, fsroot, newbuf, width, height, width, host_basepal, false);
|
||||
}
|
||||
else if (!Q_strcasecmp(ext, "tga")) //tga
|
||||
{
|
||||
vfsfile_t *vfs;
|
||||
FS_CreatePath(filename, fsroot);
|
||||
vfs = FS_OpenVFS(filename, "wb", fsroot);
|
||||
if (vfs)
|
||||
{
|
||||
unsigned char header[18];
|
||||
memset (header, 0, 18);
|
||||
header[2] = 2; // uncompressed type
|
||||
header[12] = width&255;
|
||||
header[13] = width>>8;
|
||||
header[14] = height&255;
|
||||
header[15] = height>>8;
|
||||
header[16] = 24; // pixel size
|
||||
VFS_WRITE(vfs, header, sizeof(header));
|
||||
|
||||
// swap rgb to bgr
|
||||
c = width*height*3;
|
||||
for (i=0 ; i<c ; i+=3)
|
||||
{
|
||||
temp = ((qbyte*)rgb_buffer)[i];
|
||||
((qbyte*)rgb_buffer)[i] = ((qbyte*)rgb_buffer)[i+2];
|
||||
((qbyte*)rgb_buffer)[i+2] = temp;
|
||||
}
|
||||
VFS_WRITE(vfs, rgb_buffer, c);
|
||||
VFS_CLOSE(vfs);
|
||||
}
|
||||
}
|
||||
return WriteTGA(filename, fsroot, rgb_buffer, width, height, fmt);
|
||||
else //extension / type not recognised.
|
||||
return false;
|
||||
return true;
|
||||
|
@ -2170,6 +2248,7 @@ void SCR_ScreenShot_f (void)
|
|||
vfsfile_t *vfs;
|
||||
void *rgbbuffer;
|
||||
int width, height;
|
||||
enum uploadmfmt fmt;
|
||||
|
||||
if (!VID_GetRGBInfo)
|
||||
{
|
||||
|
@ -2213,10 +2292,10 @@ void SCR_ScreenShot_f (void)
|
|||
|
||||
FS_NativePath(pcxname, FS_GAMEONLY, sysname, sizeof(sysname));
|
||||
|
||||
rgbbuffer = VID_GetRGBInfo(0, &width, &height);
|
||||
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
|
||||
if (rgbbuffer)
|
||||
{
|
||||
if (SCR_ScreenShot(pcxname, FS_GAMEONLY, rgbbuffer, width, height))
|
||||
if (SCR_ScreenShot(pcxname, FS_GAMEONLY, rgbbuffer, width, height, fmt))
|
||||
{
|
||||
Con_Printf ("Wrote %s\n", sysname);
|
||||
BZ_Free(rgbbuffer);
|
||||
|
@ -2233,6 +2312,7 @@ void SCR_ScreenShot_Mega_f(void)
|
|||
int height;
|
||||
qbyte *rgbbuffer;
|
||||
char filename[MAX_QPATH];
|
||||
enum uploadfmt fmt;
|
||||
|
||||
//poke the various modes into redrawing the screen (without huds), to avoid any menus or console drawn over the top of the current backbuffer.
|
||||
//FIXME: clear-to-black first
|
||||
|
@ -2286,10 +2366,10 @@ void SCR_ScreenShot_Mega_f(void)
|
|||
//okay, we drew something, we're good to save a screeny.
|
||||
if (okay)
|
||||
{
|
||||
rgbbuffer = VID_GetRGBInfo(0, &width, &height);
|
||||
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
|
||||
if (rgbbuffer)
|
||||
{
|
||||
if (SCR_ScreenShot(filename, FS_GAMEONLY, rgbbuffer, width, height))
|
||||
if (SCR_ScreenShot(filename, FS_GAMEONLY, rgbbuffer, width, height, fmt))
|
||||
{
|
||||
char sysname[1024];
|
||||
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
|
||||
|
@ -2374,6 +2454,7 @@ qboolean SCR_RSShot (void)
|
|||
float fracw, frach;
|
||||
char st[80];
|
||||
time_t now;
|
||||
enum uploadfmt fmt;
|
||||
|
||||
if (!scr_allowsnap.ival)
|
||||
return false;
|
||||
|
@ -2394,7 +2475,15 @@ qboolean SCR_RSShot (void)
|
|||
//
|
||||
// save the pcx file
|
||||
//
|
||||
newbuf = VID_GetRGBInfo(0, &truewidth, &trueheight);
|
||||
newbuf = VID_GetRGBInfo(&truewidth, &trueheight, &fmt);
|
||||
|
||||
if (fmt == TF_INVALID)
|
||||
return false;
|
||||
if (fmt != TF_RGB24)
|
||||
{
|
||||
BZ_Free(newbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
w = RSSHOT_WIDTH;
|
||||
h = RSSHOT_HEIGHT;
|
||||
|
|
|
@ -1572,7 +1572,7 @@ typedef struct
|
|||
typedef struct {
|
||||
char *drivername;
|
||||
void *(VARGS *capture_begin) (char *streamname, int videorate, int width, int height, int *sndkhz, int *sndchannels, int *sndbits);
|
||||
void (VARGS *capture_video) (void *ctx, void *data, int frame, int width, int height);
|
||||
void (VARGS *capture_video) (void *ctx, void *data, int frame, int width, int height, enum uploadfmt fmt);
|
||||
void (VARGS *capture_audio) (void *ctx, void *data, int bytes);
|
||||
void (VARGS *capture_end) (void *ctx);
|
||||
} media_encoder_funcs_t;
|
||||
|
|
|
@ -720,6 +720,7 @@ void (PNGAPI *qpng_set_expand_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PST
|
|||
#else
|
||||
void (PNGAPI *qpng_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PSTATIC(png_set_gray_1_2_4_to_8);
|
||||
#endif
|
||||
void (PNGAPI *qpng_set_bgr) PNGARG((png_structp png_ptr)) PSTATIC(png_set_bgr);
|
||||
void (PNGAPI *qpng_set_filler) PNGARG((png_structp png_ptr, png_uint_32 filler, int flags)) PSTATIC(png_set_filler);
|
||||
void (PNGAPI *qpng_set_palette_to_rgb) PNGARG((png_structp png_ptr)) PSTATIC(png_set_palette_to_rgb);
|
||||
png_uint_32 (PNGAPI *qpng_get_IHDR) PNGARG((png_structp png_ptr, png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
|
||||
|
@ -767,6 +768,7 @@ qboolean LibPNG_Init(void)
|
|||
#else
|
||||
{(void **) &qpng_set_gray_1_2_4_to_8, "png_set_gray_1_2_4_to_8"},
|
||||
#endif
|
||||
{(void **) &qpng_set_bgr, "png_set_bgr"},
|
||||
{(void **) &qpng_set_filler, "png_set_filler"},
|
||||
{(void **) &qpng_set_palette_to_rgb, "png_set_palette_to_rgb"},
|
||||
{(void **) &qpng_get_IHDR, "png_get_IHDR"},
|
||||
|
@ -979,7 +981,7 @@ error:
|
|||
|
||||
|
||||
#ifndef NPFTE
|
||||
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height)
|
||||
int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height, enum uploadfmt fmt)
|
||||
{
|
||||
char name[MAX_OSPATH];
|
||||
int i;
|
||||
|
@ -988,6 +990,7 @@ int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qb
|
|||
png_infop info_ptr;
|
||||
png_byte **row_pointers;
|
||||
struct pngerr errctx;
|
||||
int pxsize;
|
||||
|
||||
if (!FS_NativePath(filename, fsroot, name, sizeof(name)))
|
||||
return false;
|
||||
|
@ -1036,14 +1039,25 @@ err:
|
|||
#endif
|
||||
qpng_set_compression_level(png_ptr, Z_NO_COMPRESSION + (compression*(Z_BEST_COMPRESSION-Z_NO_COMPRESSION))/100);
|
||||
|
||||
qpng_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
if (fmt == TF_BGR24 || fmt == TF_BGRA32)
|
||||
qpng_set_bgr(png_ptr);
|
||||
if (fmt == TF_RGBA32 || fmt == TF_BGRA32)
|
||||
{
|
||||
pxsize = 4;
|
||||
qpng_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
pxsize = 3;
|
||||
qpng_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
}
|
||||
qpng_write_info(png_ptr, info_ptr);
|
||||
|
||||
row_pointers = BZ_Malloc (sizeof(png_byte *) * height);
|
||||
if (!row_pointers)
|
||||
goto err;
|
||||
for (i = 0; i < height; i++)
|
||||
row_pointers[height - i - 1] = pixels + i * width * 3;
|
||||
row_pointers[height - i - 1] = pixels + i * width * pxsize;
|
||||
qpng_write_image(png_ptr, row_pointers);
|
||||
qpng_write_end(png_ptr, info_ptr);
|
||||
BZ_Free(row_pointers);
|
||||
|
@ -1463,6 +1477,19 @@ badjpeg:
|
|||
/*end read*/
|
||||
#ifndef NPFTE
|
||||
/*begin write*/
|
||||
|
||||
|
||||
#ifndef DYNAMIC_LIBJPEG
|
||||
#define qjpeg_std_error jpeg_std_error
|
||||
#define qjpeg_destroy_compress jpeg_destroy_compress
|
||||
#define qjpeg_CreateCompress jpeg_CreateCompress
|
||||
#define qjpeg_set_defaults jpeg_set_defaults
|
||||
#define qjpeg_set_quality jpeg_set_quality
|
||||
#define qjpeg_start_compress jpeg_start_compress
|
||||
#define qjpeg_write_scanlines jpeg_write_scanlines
|
||||
#define qjpeg_finish_compress jpeg_finish_compress
|
||||
#define qjpeg_destroy_compress jpeg_destroy_compress
|
||||
#endif
|
||||
#define OUTPUT_BUF_SIZE 4096
|
||||
typedef struct {
|
||||
struct jpeg_error_mgr pub;
|
||||
|
@ -1535,7 +1562,7 @@ METHODDEF(void) jpeg_error_exit (j_common_ptr cinfo)
|
|||
{
|
||||
longjmp(((jpeg_error_mgr_wrapper *) cinfo->err)->setjmp_buffer, 1);
|
||||
}
|
||||
qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight) //input is rgb NOT rgba
|
||||
qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight, enum uploadfmt fmt)
|
||||
{
|
||||
qbyte *buffer;
|
||||
vfsfile_t *outfile;
|
||||
|
@ -1543,6 +1570,9 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
|
|||
struct jpeg_compress_struct cinfo;
|
||||
JSAMPROW row_pointer[1];
|
||||
|
||||
if (fmt != TF_RGB24)
|
||||
return false;
|
||||
|
||||
if (!LIBJPEG_LOADED())
|
||||
return false;
|
||||
|
||||
|
@ -1556,29 +1586,17 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
cinfo.err = qjpeg_std_error(&jerr.pub);
|
||||
#else
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
#endif
|
||||
cinfo.err = qjpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = jpeg_error_exit;
|
||||
if (setjmp(jerr.setjmp_buffer))
|
||||
{
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_destroy_compress(&cinfo);
|
||||
#else
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
#endif
|
||||
qjpeg_destroy_compress(&cinfo);
|
||||
VFS_CLOSE(outfile);
|
||||
FS_Remove(filename, FS_GAME);
|
||||
Con_Printf("Failed to create jpeg\n");
|
||||
return false;
|
||||
}
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_create_compress(&cinfo);
|
||||
#else
|
||||
jpeg_create_compress(&cinfo);
|
||||
#endif
|
||||
qjpeg_create_compress(&cinfo);
|
||||
|
||||
buffer = screendata;
|
||||
|
||||
|
@ -1587,42 +1605,18 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
|
|||
cinfo.image_height = screenheight;
|
||||
cinfo.input_components = 3;
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_set_defaults(&cinfo);
|
||||
#else
|
||||
jpeg_set_defaults(&cinfo);
|
||||
#endif
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_set_quality (&cinfo, bound(0, compression, 100), true);
|
||||
#else
|
||||
jpeg_set_quality (&cinfo, bound(0, compression, 100), true);
|
||||
#endif
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_start_compress(&cinfo, true);
|
||||
#else
|
||||
jpeg_start_compress(&cinfo, true);
|
||||
#endif
|
||||
qjpeg_set_defaults(&cinfo);
|
||||
qjpeg_set_quality (&cinfo, bound(0, compression, 100), true);
|
||||
qjpeg_start_compress(&cinfo, true);
|
||||
|
||||
while (cinfo.next_scanline < cinfo.image_height)
|
||||
{
|
||||
*row_pointer = &buffer[(cinfo.image_height - cinfo.next_scanline - 1) * cinfo.image_width * 3];
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
#else
|
||||
jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
#endif
|
||||
qjpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||
}
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_finish_compress(&cinfo);
|
||||
#else
|
||||
jpeg_finish_compress(&cinfo);
|
||||
#endif
|
||||
qjpeg_finish_compress(&cinfo);
|
||||
VFS_CLOSE(outfile);
|
||||
#ifdef DYNAMIC_LIBJPEG
|
||||
qjpeg_destroy_compress(&cinfo);
|
||||
#else
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
#endif
|
||||
qjpeg_destroy_compress(&cinfo);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -3155,21 +3149,24 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne
|
|||
}
|
||||
}
|
||||
|
||||
if (flags & IF_NOMIPMAP)
|
||||
if (!(flags & IF_NOPICMIP))
|
||||
{
|
||||
if (gl_picmip2d.ival > 0)
|
||||
if (flags & IF_NOMIPMAP)
|
||||
{
|
||||
*scaled_width >>= gl_picmip2d.ival;
|
||||
*scaled_height >>= gl_picmip2d.ival;
|
||||
if (gl_picmip2d.ival > 0)
|
||||
{
|
||||
*scaled_width >>= gl_picmip2d.ival;
|
||||
*scaled_height >>= gl_picmip2d.ival;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gl_picmip.ival > 0)
|
||||
else
|
||||
{
|
||||
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value));
|
||||
*scaled_width >>= gl_picmip.ival;
|
||||
*scaled_height >>= gl_picmip.ival;
|
||||
if (gl_picmip.ival > 0)
|
||||
{
|
||||
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value));
|
||||
*scaled_width >>= gl_picmip.ival;
|
||||
*scaled_height >>= gl_picmip.ival;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3500,6 +3497,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
case TF_MIP4_LUM8:
|
||||
//8bit opaque data
|
||||
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags);
|
||||
flags |= IF_NOPICMIP;
|
||||
if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight)
|
||||
{
|
||||
unsigned int pixels =
|
||||
|
@ -3537,6 +3535,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
|
|||
case TF_MIP4_SOLID8:
|
||||
//8bit opaque data
|
||||
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags);
|
||||
flags |= IF_NOPICMIP;
|
||||
if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight && sh_config.texfmt[PTI_RGBX8])
|
||||
{
|
||||
unsigned int pixels =
|
||||
|
|
|
@ -697,7 +697,6 @@ void Media_LoadTrackNames (char *listname);
|
|||
|
||||
void M_Media_Draw (menu_t *menu)
|
||||
{
|
||||
mpic_t *p;
|
||||
mediatrack_t *track;
|
||||
int y;
|
||||
int op, i;
|
||||
|
@ -2672,6 +2671,12 @@ int captureoldfbo;
|
|||
qboolean capturingfbo;
|
||||
texid_t capturetexture;
|
||||
qboolean captureframeforce;
|
||||
#ifdef GLQUAKE
|
||||
//ring buffer
|
||||
int pbo_handles[4];
|
||||
enum uploadfmt pbo_format;
|
||||
#endif
|
||||
int pbo_oldest;
|
||||
|
||||
qboolean capturepaused;
|
||||
extern cvar_t vid_conautoscale;
|
||||
|
@ -2751,13 +2756,13 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width
|
|||
}
|
||||
return ctx;
|
||||
}
|
||||
static void QDECL capture_raw_video (void *vctx, void *data, int frame, int width, int height)
|
||||
static void QDECL capture_raw_video (void *vctx, void *data, int frame, int width, int height, enum uploadfmt fmt)
|
||||
{
|
||||
struct capture_raw_ctx *ctx = vctx;
|
||||
char filename[MAX_OSPATH];
|
||||
ctx->frames = frame+1;
|
||||
Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension);
|
||||
SCR_ScreenShot(filename, ctx->fsroot, data, width, height);
|
||||
SCR_ScreenShot(filename, ctx->fsroot, data, width, height, fmt);
|
||||
}
|
||||
static void QDECL capture_raw_audio (void *vctx, void *data, int bytes)
|
||||
{
|
||||
|
@ -2949,19 +2954,39 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width
|
|||
return ctx;
|
||||
}
|
||||
|
||||
static void QDECL capture_avi_video(void *vctx, void *vdata, int frame, int width, int height)
|
||||
static void QDECL capture_avi_video(void *vctx, void *vdata, int frame, int width, int height, enum uploadfmt fmt)
|
||||
{
|
||||
struct capture_avi_ctx *ctx = vctx;
|
||||
qbyte *data = vdata;
|
||||
int c, i;
|
||||
qbyte temp;
|
||||
// swap rgb to bgr
|
||||
c = width*height*3;
|
||||
for (i=0 ; i<c ; i+=3)
|
||||
|
||||
if (fmt == TF_BGRA32)
|
||||
{
|
||||
temp = data[i];
|
||||
data[i] = data[i+2];
|
||||
data[i+2] = temp;
|
||||
// truncate bgra to bgr
|
||||
c = width*height;
|
||||
for (i=0 ; i<c ; i++)
|
||||
{
|
||||
data[i*3+0] = data[i*4+0];
|
||||
data[i*3+1] = data[i*4+1];
|
||||
data[i*3+2] = data[i*4+2];
|
||||
}
|
||||
}
|
||||
else if (fmt == TF_RGB24)
|
||||
{
|
||||
// swap rgb to bgr
|
||||
c = width*height*3;
|
||||
for (i=0 ; i<c ; i+=3)
|
||||
{
|
||||
temp = data[i];
|
||||
data[i] = data[i+2];
|
||||
data[i+2] = temp;
|
||||
}
|
||||
}
|
||||
else if (fmt != TF_BGR24)
|
||||
{
|
||||
Con_Printf("Unsupported image format\n");
|
||||
return;
|
||||
}
|
||||
//write it
|
||||
if (FAILED(qAVIStreamWrite(avi_video_stream(ctx), frame, 1, data, width*height * 3, ((frame%15) == 0)?AVIIF_KEYFRAME:0, NULL, NULL)))
|
||||
|
@ -2993,7 +3018,7 @@ static void *QDECL capture_null_begin (char *streamname, int videorate, int widt
|
|||
{
|
||||
return (void*)~0;
|
||||
}
|
||||
static void QDECL capture_null_video(void *vctx, void *vdata, int frame, int width, int height)
|
||||
static void QDECL capture_null_video(void *vctx, void *vdata, int frame, int width, int height, enum uploadfmt fmt)
|
||||
{
|
||||
}
|
||||
static void QDECL capture_null_audio(void *vctx, void *data, int bytes)
|
||||
|
@ -3098,6 +3123,7 @@ void Media_RecordFrame (void)
|
|||
{
|
||||
char *buffer;
|
||||
int truewidth, trueheight;
|
||||
enum uploadfmt fmt;
|
||||
|
||||
if (!currentcapture_funcs)
|
||||
return;
|
||||
|
@ -3162,17 +3188,65 @@ void Media_RecordFrame (void)
|
|||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
//submit the current video frame. audio will be mixed to match.
|
||||
buffer = VID_GetRGBInfo(0, &truewidth, &trueheight);
|
||||
if (buffer)
|
||||
#ifdef GLQUAKE
|
||||
if (pbo_format != TF_INVALID)
|
||||
{
|
||||
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, captureframe, truewidth, trueheight);
|
||||
capturelastvideotime += captureframeinterval;
|
||||
captureframe++;
|
||||
BZ_Free (buffer);
|
||||
int imagesize = vid.fbpwidth * vid.fbpheight * 4;
|
||||
while (pbo_oldest + countof(pbo_handles) <= captureframe)
|
||||
{
|
||||
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[pbo_oldest%countof(pbo_handles)]);
|
||||
buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
|
||||
if (buffer)
|
||||
{
|
||||
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, pbo_format);
|
||||
qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
|
||||
}
|
||||
pbo_oldest++;
|
||||
}
|
||||
|
||||
if (!pbo_handles[captureframe%countof(pbo_handles)])
|
||||
{
|
||||
qglGenBuffersARB(1, &pbo_handles[captureframe%countof(pbo_handles)]);
|
||||
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[captureframe%countof(pbo_handles)]);
|
||||
qglBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, imagesize, NULL, GL_STATIC_READ_ARB);
|
||||
}
|
||||
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[captureframe%countof(pbo_handles)]);
|
||||
switch(pbo_format)
|
||||
{
|
||||
case TF_BGR24:
|
||||
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0);
|
||||
break;
|
||||
case TF_BGRA32:
|
||||
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
||||
break;
|
||||
case TF_RGB24:
|
||||
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||
break;
|
||||
case TF_RGBA32:
|
||||
qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
break;
|
||||
}
|
||||
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
|
||||
}
|
||||
else
|
||||
Con_DPrintf("Unable to grab video image\n");
|
||||
#endif
|
||||
{
|
||||
pbo_oldest = captureframe+1;
|
||||
//submit the current video frame. audio will be mixed to match.
|
||||
buffer = VID_GetRGBInfo(&truewidth, &trueheight, &fmt);
|
||||
if (buffer)
|
||||
{
|
||||
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, captureframe, truewidth, trueheight, fmt);
|
||||
BZ_Free (buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_DPrintf("Unable to grab video image\n");
|
||||
currentcapture_funcs->capture_video(currentcapture_ctx, NULL, captureframe, 0, 0, TF_INVALID);
|
||||
}
|
||||
}
|
||||
captureframe++;
|
||||
capturelastvideotime += captureframeinterval;
|
||||
|
||||
captureframeforce = false;
|
||||
|
||||
|
@ -3358,6 +3432,35 @@ void Media_InitFakeSoundDevice (int speed, int channels, int samplebits)
|
|||
|
||||
void Media_StopRecordFilm_f (void)
|
||||
{
|
||||
#ifdef GLQUAKE
|
||||
if (pbo_format)
|
||||
{
|
||||
int i;
|
||||
int imagesize = vid.fbpwidth * vid.fbpheight * 4;
|
||||
while (pbo_oldest < captureframe)
|
||||
{
|
||||
qbyte *buffer;
|
||||
qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[pbo_oldest%countof(pbo_handles)]);
|
||||
buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
|
||||
if (buffer)
|
||||
{
|
||||
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, TF_BGR24);
|
||||
// currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, TF_BGRA32);
|
||||
qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
|
||||
}
|
||||
pbo_oldest++;
|
||||
}
|
||||
|
||||
for (i = 0; i < countof(pbo_handles); i++)
|
||||
{
|
||||
if (pbo_handles[i])
|
||||
qglDeleteBuffersARB(1, &pbo_handles[i]);
|
||||
pbo_handles[i] = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (capture_fakesounddevice)
|
||||
S_ShutdownCard(capture_fakesounddevice);
|
||||
capture_fakesounddevice = NULL;
|
||||
|
@ -3401,7 +3504,7 @@ static void Media_RecordFilm (char *recordingname, qboolean demo)
|
|||
|
||||
Con_ClearNotify();
|
||||
|
||||
captureframe = 0;
|
||||
captureframe = pbo_oldest = 0;
|
||||
for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++)
|
||||
{
|
||||
if (pluginencodersfunc[i])
|
||||
|
@ -3438,11 +3541,17 @@ static void Media_RecordFilm (char *recordingname, qboolean demo)
|
|||
{
|
||||
capturingfbo = true;
|
||||
capturetexture = R2D_RT_Configure("$democapture", capturewidth.ival, captureheight.ival, TF_BGRA32);
|
||||
captureoldfbo = GLBE_FBO_Update(&capturefbo, FBO_RB_DEPTH, &capturetexture, 1, r_nulltex, capturewidth.ival, captureheight.ival, 0);
|
||||
captureoldfbo = GLBE_FBO_Update(&capturefbo, FBO_RB_DEPTH|(Sh_StencilShadowsActive()?FBO_RB_STENCIL:0), &capturetexture, 1, r_nulltex, capturewidth.ival, captureheight.ival, 0);
|
||||
vid.fbpwidth = capturewidth.ival;
|
||||
vid.fbpheight = captureheight.ival;
|
||||
vid.framebuffer = capturetexture;
|
||||
}
|
||||
|
||||
pbo_format = TF_INVALID;
|
||||
if (qrenderer == QR_OPENGL && !gl_config.gles && gl_config.glversion >= 2.1)
|
||||
{ //both tgas and vfw favour bgr24, so lets get the gl drivers to suffer instead of us.
|
||||
pbo_format = TF_BGR24;
|
||||
}
|
||||
#endif
|
||||
|
||||
recordingdemo = demo;
|
||||
|
|
|
@ -101,7 +101,7 @@ extern void (*R_RenderView) (void); // must set r_refdef first
|
|||
|
||||
extern qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
|
||||
extern void (*VID_DeInit) (void);
|
||||
extern char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
|
||||
extern char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt);
|
||||
extern void (*VID_SetWindowCaption) (char *msg);
|
||||
|
||||
extern void SCR_Init (void);
|
||||
|
@ -413,7 +413,7 @@ typedef struct rendererinfo_s {
|
|||
void (*VID_DestroyCursor) (void *cursor); //may be null
|
||||
|
||||
void (*VID_SetWindowCaption) (char *msg);
|
||||
char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
|
||||
char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt);
|
||||
|
||||
void (*SCR_UpdateScreen) (void);
|
||||
|
||||
|
|
|
@ -55,6 +55,9 @@ void QCBUILTIN PF_CL_drawfill (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
|
|||
void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
srect_t srect;
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
csqc_dp_lastwas3d = false;
|
||||
|
||||
srect.x = G_FLOAT(OFS_PARM0) / (float)vid.fbvwidth;
|
||||
|
@ -71,6 +74,9 @@ void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_
|
|||
//void drawresetcliparea(void) = #459;
|
||||
void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
csqc_dp_lastwas3d = false;
|
||||
|
||||
BE_Scissor(NULL);
|
||||
|
|
|
@ -31,6 +31,7 @@ shader_t *shader_polyblend;
|
|||
shader_t *shader_menutint;
|
||||
|
||||
#define DRAW_QUADS 128
|
||||
static int draw_active_flags;
|
||||
static shader_t *draw_active_shader;
|
||||
static avec4_t draw_active_colour;
|
||||
static mesh_t draw_mesh;
|
||||
|
@ -576,7 +577,7 @@ void R2D_ImageAtlas(float x, float y, float w, float h, float s1, float t1, floa
|
|||
|
||||
void R2D_ImageFlush(void)
|
||||
{
|
||||
BE_DrawMesh_Single(draw_active_shader, &draw_mesh, NULL, r2d_be_flags);
|
||||
BE_DrawMesh_Single(draw_active_shader, &draw_mesh, NULL, draw_active_flags);
|
||||
|
||||
R2D_Flush = NULL;
|
||||
draw_active_shader = NULL;
|
||||
|
@ -597,12 +598,13 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2,
|
|||
return;
|
||||
}
|
||||
|
||||
if (draw_active_shader != pic || draw_mesh.numvertexes+4 > DRAW_QUADS)
|
||||
if (draw_active_shader != pic || draw_active_flags != r2d_be_flags || draw_mesh.numvertexes+4 > DRAW_QUADS)
|
||||
{
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
draw_active_shader = pic;
|
||||
draw_active_flags = r2d_be_flags;
|
||||
R2D_Flush = R2D_ImageFlush;
|
||||
|
||||
draw_mesh.numindexes = 0;
|
||||
|
@ -663,12 +665,13 @@ void R2D_FillBlock(float x, float y, float w, float h)
|
|||
pic = shader_draw_fill_trans;
|
||||
else
|
||||
pic = shader_draw_fill;
|
||||
if (draw_active_shader != pic || draw_mesh.numvertexes+4 > DRAW_QUADS)
|
||||
if (draw_active_shader != pic || draw_active_flags != r2d_be_flags || draw_mesh.numvertexes+4 > DRAW_QUADS)
|
||||
{
|
||||
if (R2D_Flush)
|
||||
R2D_Flush();
|
||||
|
||||
draw_active_shader = pic;
|
||||
draw_active_flags = r2d_be_flags;
|
||||
R2D_Flush = R2D_ImageFlush;
|
||||
|
||||
draw_mesh.numindexes = 0;
|
||||
|
|
|
@ -856,7 +856,7 @@ void (*R_RenderView) (void); // must set r_refdef first
|
|||
|
||||
qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
|
||||
void (*VID_DeInit) (void);
|
||||
char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
|
||||
char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt);
|
||||
void (*VID_SetWindowCaption) (char *msg);
|
||||
|
||||
void (*SCR_UpdateScreen) (void);
|
||||
|
|
|
@ -80,7 +80,8 @@ void SCR_ShowPic_Remove_f(void);
|
|||
//a header is better than none...
|
||||
void Draw_TextBox (int x, int y, int width, int lines);
|
||||
enum fs_relative;
|
||||
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height);
|
||||
enum uploadfmt;
|
||||
qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height, enum uploadfmt fmt);
|
||||
|
||||
void SCR_DrawTwoDimensional(int uimenu, qboolean nohud);
|
||||
|
||||
|
|
|
@ -110,6 +110,6 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette);
|
|||
qboolean GLVID_Is8bit(void);
|
||||
|
||||
void GLVID_SwapBuffers(void);
|
||||
char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight);
|
||||
char *GLVID_GetRGBInfo(int *truewidth, int *trueheight, enum uploadfmt *fmt);
|
||||
void GLVID_SetCaption(char *caption);
|
||||
#endif
|
||||
|
|
|
@ -163,8 +163,9 @@ static qboolean Headless_VID_ApplyGammaRamps (unsigned short *ramps)
|
|||
static void Headless_VID_SetWindowCaption (char *msg)
|
||||
{
|
||||
}
|
||||
static char *Headless_VID_GetRGBInfo (int prepad, int *truevidwidth, int *truevidheight)
|
||||
static char *Headless_VID_GetRGBInfo (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
|
||||
{
|
||||
*fmt = TF_INVALID;
|
||||
*truevidwidth = *truevidheight = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -802,7 +802,7 @@ qboolean D3D9_VID_ApplyGammaRamps (unsigned short *ramps)
|
|||
IDirect3DDevice9_SetGammaRamp(pD3DDev9, 0, D3DSGR_NO_CALIBRATION, (D3DGAMMARAMP *)ramps);
|
||||
return true;
|
||||
}
|
||||
static char *(D3D9_VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight)
|
||||
static char *(D3D9_VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
|
||||
{
|
||||
IDirect3DSurface9 *backbuf, *surf;
|
||||
D3DLOCKED_RECT rect;
|
||||
|
@ -828,14 +828,16 @@ static char *(D3D9_VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevi
|
|||
if (!FAILED(IDirect3DDevice9_GetRenderTargetData(pD3DDev9, backbuf, surf)))
|
||||
if (!FAILED(IDirect3DSurface9_LockRect(surf, &rect, NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_READONLY|D3DLOCK_NOSYSLOCK)))
|
||||
{
|
||||
ret = BZ_Malloc(prepad + desc.Width*desc.Height*3);
|
||||
ret = BZ_Malloc(desc.Width*desc.Height*3);
|
||||
if (ret)
|
||||
{
|
||||
*fmt = TF_RGB24;
|
||||
|
||||
// read surface rect and convert 32 bgra to 24 rgb and flip
|
||||
c = prepad+desc.Width*desc.Height*3;
|
||||
c = desc.Width*desc.Height*3;
|
||||
p = (qbyte *)rect.pBits;
|
||||
|
||||
for (i=c-(3*desc.Width); i>=prepad; i-=(3*desc.Width))
|
||||
for (i=c-(3*desc.Width); i>=0; i-=(3*desc.Width))
|
||||
{
|
||||
for (j=0; j<desc.Width; j++)
|
||||
{
|
||||
|
@ -1239,7 +1241,6 @@ qboolean (D3D9_VID_Init) (rendererstate_t *info, unsigned char *palette);
|
|||
void (D3D9_VID_DeInit) (void);
|
||||
void (D3D9_VID_SetPalette) (unsigned char *palette);
|
||||
void (D3D9_VID_ShiftPalette) (unsigned char *palette);
|
||||
char *(D3D9_VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight);
|
||||
void (D3D9_VID_SetWindowCaption) (char *msg);
|
||||
|
||||
void (D3D9_SCR_UpdateScreen) (void);
|
||||
|
|
|
@ -1102,7 +1102,7 @@ static qboolean D3D11_VID_ApplyGammaRamps(unsigned short *ramps)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
static char *D3D11_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidheight)
|
||||
static char *D3D11_VID_GetRGBInfo(int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
|
||||
{
|
||||
//don't directly map the frontbuffer, as that can hold other things.
|
||||
//create a texture, copy the (gpu)backbuffer to that (cpu)texture
|
||||
|
@ -1132,8 +1132,7 @@ static char *D3D11_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidhei
|
|||
ID3D11Resource_Release(backbuffer);
|
||||
if (!FAILED(ID3D11DeviceContext_Map(d3ddevctx, (ID3D11Resource*)texture, 0, D3D11_MAP_READ, 0, &lock)))
|
||||
{
|
||||
r = rgb = BZ_Malloc(prepad + 3 * vid.pixelwidth * vid.pixelheight);
|
||||
r += prepad;
|
||||
r = rgb = BZ_Malloc(3 * vid.pixelwidth * vid.pixelheight);
|
||||
for (y = vid.pixelheight; y-- > 0; )
|
||||
{
|
||||
in = lock.pData;
|
||||
|
@ -1150,6 +1149,7 @@ static char *D3D11_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidhei
|
|||
ID3D11Texture2D_Release(texture);
|
||||
*truevidwidth = vid.pixelwidth;
|
||||
*truevidheight = vid.pixelheight;
|
||||
*fmt = TF_RGB24;
|
||||
return r;
|
||||
}
|
||||
static void (D3D11_VID_SetWindowCaption) (char *msg)
|
||||
|
|
|
@ -28,6 +28,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
|
|||
struct font_s *font_default;
|
||||
struct font_s *font_console;
|
||||
struct font_s *font_tiny;
|
||||
static int font_be_flags;
|
||||
extern unsigned int r2d_be_flags;
|
||||
|
||||
//by adding 'extern' to one definition of a function in a translation unit, then the definition in that TU is NOT considered an inline definition. meaning non-inlined references in other TUs can link to it instead of their own if needed.
|
||||
|
@ -409,10 +410,10 @@ static void Font_Flush(void)
|
|||
font_backmesh.numvertexes = font_foremesh.numvertexes;
|
||||
font_backmesh.istrifan = font_foremesh.istrifan;
|
||||
|
||||
BE_DrawMesh_Single(fontplanes.backshader, &font_backmesh, NULL, r2d_be_flags);
|
||||
BE_DrawMesh_Single(fontplanes.backshader, &font_backmesh, NULL, font_be_flags);
|
||||
}
|
||||
TEXASSIGN(fontplanes.shader->defaulttextures->base, font_texture);
|
||||
BE_DrawMesh_Single(fontplanes.shader, &font_foremesh, NULL, r2d_be_flags);
|
||||
BE_DrawMesh_Single(fontplanes.shader, &font_foremesh, NULL, font_be_flags);
|
||||
font_foremesh.numindexes = 0;
|
||||
font_foremesh.numvertexes = 0;
|
||||
}
|
||||
|
@ -1523,10 +1524,10 @@ void Font_Free(struct font_s *f)
|
|||
//maps a given virtual screen coord to a pixel coord, which matches the font's height/width values
|
||||
void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py)
|
||||
{
|
||||
if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font))
|
||||
if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font || font_be_flags != r2d_be_flags))
|
||||
R2D_Flush();
|
||||
R2D_Flush = Font_Flush;
|
||||
|
||||
font_be_flags = r2d_be_flags;
|
||||
curfont = font;
|
||||
*px = (vx*(int)vid.rotpixelwidth) / (float)vid.width;
|
||||
*py = (vy*(int)vid.rotpixelheight) / (float)vid.height;
|
||||
|
@ -1544,10 +1545,10 @@ void Font_Transform(float vx, float vy, int *px, int *py)
|
|||
}
|
||||
void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py)
|
||||
{
|
||||
if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font))
|
||||
if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font || font_be_flags != r2d_be_flags))
|
||||
R2D_Flush();
|
||||
R2D_Flush = Font_Flush;
|
||||
|
||||
font_be_flags = r2d_be_flags;
|
||||
curfont = font;
|
||||
*px = (vx*(float)vid.rotpixelwidth) / (float)vid.width;
|
||||
*py = (vy*(float)vid.rotpixelheight) / (float)vid.height;
|
||||
|
|
|
@ -243,7 +243,7 @@ void GLSCR_UpdateScreen (void)
|
|||
}
|
||||
|
||||
|
||||
char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight)
|
||||
char *GLVID_GetRGBInfo(int *truewidth, int *trueheight, enum uploadfmt *fmt)
|
||||
{ //returns a BZ_Malloced array
|
||||
extern qboolean gammaworks;
|
||||
int i, c;
|
||||
|
@ -259,14 +259,14 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight)
|
|||
p = BZ_Malloc(vid.pixelwidth*vid.pixelheight*sizeof(float));
|
||||
qglReadPixels (0, 0, vid.pixelwidth, vid.pixelheight, GL_DEPTH_COMPONENT, GL_FLOAT, p);
|
||||
|
||||
ret = BZ_Malloc(prepadbytes + vid.pixelwidth*vid.pixelheight*3);
|
||||
ret = BZ_Malloc(vid.pixelwidth*vid.pixelheight*3);
|
||||
|
||||
c = vid.pixelwidth*vid.pixelheight;
|
||||
for (i = 1; i < c; i++)
|
||||
{
|
||||
ret[prepadbytes+i*3+0]=p[i]*p[i]*p[i]*255;
|
||||
ret[prepadbytes+i*3+1]=p[i]*p[i]*p[i]*255;
|
||||
ret[prepadbytes+i*3+2]=p[i]*p[i]*p[i]*255;
|
||||
ret[i*3+0]=p[i]*p[i]*p[i]*255;
|
||||
ret[i*3+1]=p[i]*p[i]*p[i]*255;
|
||||
ret[i*3+2]=p[i]*p[i]*p[i]*255;
|
||||
}
|
||||
BZ_Free(p);
|
||||
}
|
||||
|
@ -274,30 +274,46 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight)
|
|||
{
|
||||
qbyte *p;
|
||||
|
||||
// gles only guarantees GL_RGBA/GL_UNSIGNED_BYTE so downconvert and resize
|
||||
ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*4);
|
||||
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret + prepadbytes);
|
||||
//gles:
|
||||
//Only two format/type parameter pairs are accepted.
|
||||
//GL_RGBA/GL_UNSIGNED_BYTE is always accepted, and the other acceptable pair can be discovered by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
|
||||
//thus its simpler to only use GL_RGBA/GL_UNSIGNED_BYTE
|
||||
//desktopgl:
|
||||
//total line byte length must be aligned to GL_PACK_ALIGNMENT. by reading rgba instead of rgb, we can ensure the line is a multiple of 4 bytes.
|
||||
|
||||
ret = BZ_Malloc((*truewidth)*(*trueheight)*4);
|
||||
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret);
|
||||
|
||||
*fmt = TF_RGB24;
|
||||
c = (*truewidth)*(*trueheight);
|
||||
p = ret + prepadbytes;
|
||||
p = ret;
|
||||
for (i = 1; i < c; i++)
|
||||
{
|
||||
p[i*3+0]=p[i*4+0];
|
||||
p[i*3+1]=p[i*4+1];
|
||||
p[i*3+2]=p[i*4+2];
|
||||
}
|
||||
ret = BZ_Realloc(ret, prepadbytes + (*truewidth)*(*trueheight)*3);
|
||||
ret = BZ_Realloc(ret, (*truewidth)*(*trueheight)*3);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
else if (!gl_config.gles && gl_config.glversion >= 1.2)
|
||||
{
|
||||
*fmt = TF_BGRA32;
|
||||
ret = BZ_Malloc((*truewidth)*(*trueheight)*4);
|
||||
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, ret);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*3);
|
||||
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret + prepadbytes);
|
||||
*fmt = TF_RGB24;
|
||||
ret = BZ_Malloc((*truewidth)*(*trueheight)*3);
|
||||
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret);
|
||||
}
|
||||
|
||||
if (gammaworks)
|
||||
{
|
||||
c = prepadbytes+(*truewidth)*(*trueheight)*3;
|
||||
for (i=prepadbytes ; i<c ; i+=3)
|
||||
c = (*truewidth)*(*trueheight)*3;
|
||||
for (i=0 ; i<c ; i+=3)
|
||||
{
|
||||
extern qbyte gammatable[256];
|
||||
ret[i+0] = gammatable[ret[i+0]];
|
||||
|
|
|
@ -612,6 +612,10 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei
|
|||
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||
#endif
|
||||
|
||||
#ifndef GL_ARB_pixel_buffer_object
|
||||
#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB
|
||||
#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC
|
||||
#endif
|
||||
|
||||
#ifndef GL_ARB_vertex_buffer_object
|
||||
#define GL_BUFFER_SIZE_ARB 0x8764
|
||||
|
|
|
@ -1221,10 +1221,11 @@ void SV_Savegame (char *savename)
|
|||
//okay, we drew something, we're good to save a screeny.
|
||||
if (okay)
|
||||
{
|
||||
rgbbuffer = VID_GetRGBInfo(0, &width, &height);
|
||||
enum uploadfmt fmt;
|
||||
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
|
||||
if (rgbbuffer)
|
||||
{
|
||||
SCR_ScreenShot(savefilename, FS_GAMEONLY, rgbbuffer, width, height);
|
||||
SCR_ScreenShot(savefilename, FS_GAMEONLY, rgbbuffer, width, height, fmt);
|
||||
BZ_Free(rgbbuffer);
|
||||
|
||||
|
||||
|
|
|
@ -115,20 +115,38 @@ void close_video(struct encctx *ctx)
|
|||
}
|
||||
av_free(ctx->video_outbuf);
|
||||
}
|
||||
static void AVEnc_Video (void *vctx, void *data, int frame, int width, int height)
|
||||
static void AVEnc_Video (void *vctx, void *data, int frame, int width, int height, enum uploadfmt qpfmt)
|
||||
{
|
||||
struct encctx *ctx = vctx;
|
||||
//weird maths to flip it.
|
||||
const uint8_t *srcslices[2] = {(uint8_t*)data + (height-1)*width*3, NULL};
|
||||
int srcstride[2] = {-width*3, 0};
|
||||
const uint8_t *srcslices[2];
|
||||
int srcstride[2];
|
||||
int success;
|
||||
AVPacket pkt;
|
||||
int avpfmt;
|
||||
int inbpp;
|
||||
|
||||
if (!ctx->video_st)
|
||||
return;
|
||||
|
||||
switch(qpfmt)
|
||||
{
|
||||
case TF_BGRA32: avpfmt = AV_PIX_FMT_BGRA; inbpp = 4; break;
|
||||
case TF_RGBA32: avpfmt = AV_PIX_FMT_RGBA; inbpp = 4; break;
|
||||
case TF_BGR24: avpfmt = AV_PIX_FMT_BGR24; inbpp = 3; break;
|
||||
case TF_RGB24: avpfmt = AV_PIX_FMT_RGB24; inbpp = 3; break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
//weird maths to flip it.
|
||||
srcslices[0] = (uint8_t*)data + (height-1)*width*inbpp;
|
||||
srcstride[0] = -width*inbpp;
|
||||
srcslices[1] = NULL;
|
||||
srcstride[1] = 0;
|
||||
|
||||
//convert RGB to whatever the codec needs (ie: yuv...).
|
||||
ctx->scale_ctx = sws_getCachedContext(ctx->scale_ctx, width, height, AV_PIX_FMT_RGB24, ctx->picture->width, ctx->picture->height, ctx->video_st->codec->pix_fmt, SWS_POINT, 0, 0, 0);
|
||||
//also rescales, but only if the user resizes the video while recording. which is a stupid thing to do.
|
||||
ctx->scale_ctx = sws_getCachedContext(ctx->scale_ctx, width, height, qpfmt, ctx->picture->width, ctx->picture->height, ctx->video_st->codec->pix_fmt, SWS_POINT, 0, 0, 0);
|
||||
sws_scale(ctx->scale_ctx, srcslices, srcstride, 0, height, ctx->picture->data, ctx->picture->linesize);
|
||||
|
||||
av_init_packet(&pkt);
|
||||
|
|
Loading…
Reference in a new issue