1
0
Fork 0
forked from fte/fteqw

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:
Spoike 2015-08-14 02:46:38 +00:00
parent 5f7243c6dc
commit a26a373d15
19 changed files with 424 additions and 175 deletions

View file

@ -3686,7 +3686,7 @@ void CL_LinkPacketEntities (void)
Q_snprintfz(name, sizeof(name), "textures/bmodels/simple_%s_%i.tga", basename, ent->skinnum); Q_snprintfz(name, sizeof(name), "textures/bmodels/simple_%s_%i.tga", basename, ent->skinnum);
else else
Q_snprintfz(name, sizeof(name), "textures/models/simple_%s_%i.tga", basename, ent->skinnum); 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); VectorCopy(le->angles, angles);

View file

@ -2031,13 +2031,96 @@ typedef struct _TargaHeader {
#if defined(AVAIL_JPEGLIB) && !defined(NO_JPEG) #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 #endif
#ifdef AVAIL_PNGLIB #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 #endif
void WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int width, int height); 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 Find closest color in the palette for named color
*/ */
@ -2071,9 +2154,8 @@ int MipColor(int r, int g, int b)
return best; 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) #if defined(AVAIL_PNGLIB) || defined(AVAIL_JPEGLIB)
extern cvar_t scr_sshot_compression; extern cvar_t scr_sshot_compression;
#endif #endif
@ -2088,70 +2170,66 @@ qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buff
#ifdef AVAIL_PNGLIB #ifdef AVAIL_PNGLIB
if (!Q_strcasecmp(ext, "png")) 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 else
#endif #endif
#ifdef AVAIL_JPEGLIB #ifdef AVAIL_JPEGLIB
if (!Q_strcasecmp(ext, "jpeg") || !Q_strcasecmp(ext, "jpg")) 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 else
#endif #endif
/* if (!Q_strcasecmp(ext, "bmp")) /* if (!Q_strcasecmp(ext, "bmp"))
{ {
WriteBMPFile(pcxname, rgb_buffer, width, height); return WriteBMPFile(pcxname, rgb_buffer, width, height);
} }
else*/ else*/
if (!Q_strcasecmp(ext, "pcx")) if (!Q_strcasecmp(ext, "pcx"))
{ {
int y, x; int y, x, s;
qbyte *src, *dest; qbyte *src, *dest;
qbyte *newbuf = rgb_buffer; qbyte *newbuf = rgb_buffer;
// convert in-place to eight bit if (fmt == TF_RGB24 || fmt == TF_RGBA32)
for (y = 0; y < height; y++)
{ {
src = newbuf + (width * 3 * y); s = (fmt == TF_RGB24)?3:4;
dest = newbuf + (width * y); // 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++) { for (x = 0; x < width; x++) {
*dest++ = MipColor(src[0], src[1], src[2]); *dest++ = MipColor(src[0], src[1], src[2]);
src += 3; 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); WritePCXfile (filename, fsroot, newbuf, width, height, width, host_basepal, false);
} }
else if (!Q_strcasecmp(ext, "tga")) //tga else if (!Q_strcasecmp(ext, "tga")) //tga
{ return WriteTGA(filename, fsroot, rgb_buffer, width, height, fmt);
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);
}
}
else //extension / type not recognised. else //extension / type not recognised.
return false; return false;
return true; return true;
@ -2170,6 +2248,7 @@ void SCR_ScreenShot_f (void)
vfsfile_t *vfs; vfsfile_t *vfs;
void *rgbbuffer; void *rgbbuffer;
int width, height; int width, height;
enum uploadmfmt fmt;
if (!VID_GetRGBInfo) if (!VID_GetRGBInfo)
{ {
@ -2213,10 +2292,10 @@ void SCR_ScreenShot_f (void)
FS_NativePath(pcxname, FS_GAMEONLY, sysname, sizeof(sysname)); FS_NativePath(pcxname, FS_GAMEONLY, sysname, sizeof(sysname));
rgbbuffer = VID_GetRGBInfo(0, &width, &height); rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
if (rgbbuffer) 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); Con_Printf ("Wrote %s\n", sysname);
BZ_Free(rgbbuffer); BZ_Free(rgbbuffer);
@ -2233,6 +2312,7 @@ void SCR_ScreenShot_Mega_f(void)
int height; int height;
qbyte *rgbbuffer; qbyte *rgbbuffer;
char filename[MAX_QPATH]; 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. //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 //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. //okay, we drew something, we're good to save a screeny.
if (okay) if (okay)
{ {
rgbbuffer = VID_GetRGBInfo(0, &width, &height); rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
if (rgbbuffer) if (rgbbuffer)
{ {
if (SCR_ScreenShot(filename, FS_GAMEONLY, rgbbuffer, width, height)) if (SCR_ScreenShot(filename, FS_GAMEONLY, rgbbuffer, width, height, fmt))
{ {
char sysname[1024]; char sysname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
@ -2374,6 +2454,7 @@ qboolean SCR_RSShot (void)
float fracw, frach; float fracw, frach;
char st[80]; char st[80];
time_t now; time_t now;
enum uploadfmt fmt;
if (!scr_allowsnap.ival) if (!scr_allowsnap.ival)
return false; return false;
@ -2394,7 +2475,15 @@ qboolean SCR_RSShot (void)
// //
// save the pcx file // 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; w = RSSHOT_WIDTH;
h = RSSHOT_HEIGHT; h = RSSHOT_HEIGHT;

View file

@ -1572,7 +1572,7 @@ typedef struct
typedef struct { typedef struct {
char *drivername; char *drivername;
void *(VARGS *capture_begin) (char *streamname, int videorate, int width, int height, int *sndkhz, int *sndchannels, int *sndbits); 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_audio) (void *ctx, void *data, int bytes);
void (VARGS *capture_end) (void *ctx); void (VARGS *capture_end) (void *ctx);
} media_encoder_funcs_t; } media_encoder_funcs_t;

View file

@ -720,6 +720,7 @@ void (PNGAPI *qpng_set_expand_gray_1_2_4_to_8) PNGARG((png_structp png_ptr)) PST
#else #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); 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 #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_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); 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, 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 #else
{(void **) &qpng_set_gray_1_2_4_to_8, "png_set_gray_1_2_4_to_8"}, {(void **) &qpng_set_gray_1_2_4_to_8, "png_set_gray_1_2_4_to_8"},
#endif #endif
{(void **) &qpng_set_bgr, "png_set_bgr"},
{(void **) &qpng_set_filler, "png_set_filler"}, {(void **) &qpng_set_filler, "png_set_filler"},
{(void **) &qpng_set_palette_to_rgb, "png_set_palette_to_rgb"}, {(void **) &qpng_set_palette_to_rgb, "png_set_palette_to_rgb"},
{(void **) &qpng_get_IHDR, "png_get_IHDR"}, {(void **) &qpng_get_IHDR, "png_get_IHDR"},
@ -979,7 +981,7 @@ error:
#ifndef NPFTE #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]; char name[MAX_OSPATH];
int i; int i;
@ -988,6 +990,7 @@ int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qb
png_infop info_ptr; png_infop info_ptr;
png_byte **row_pointers; png_byte **row_pointers;
struct pngerr errctx; struct pngerr errctx;
int pxsize;
if (!FS_NativePath(filename, fsroot, name, sizeof(name))) if (!FS_NativePath(filename, fsroot, name, sizeof(name)))
return false; return false;
@ -1036,14 +1039,25 @@ err:
#endif #endif
qpng_set_compression_level(png_ptr, Z_NO_COMPRESSION + (compression*(Z_BEST_COMPRESSION-Z_NO_COMPRESSION))/100); 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); qpng_write_info(png_ptr, info_ptr);
row_pointers = BZ_Malloc (sizeof(png_byte *) * height); row_pointers = BZ_Malloc (sizeof(png_byte *) * height);
if (!row_pointers) if (!row_pointers)
goto err; goto err;
for (i = 0; i < height; i++) 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_image(png_ptr, row_pointers);
qpng_write_end(png_ptr, info_ptr); qpng_write_end(png_ptr, info_ptr);
BZ_Free(row_pointers); BZ_Free(row_pointers);
@ -1463,6 +1477,19 @@ badjpeg:
/*end read*/ /*end read*/
#ifndef NPFTE #ifndef NPFTE
/*begin write*/ /*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 #define OUTPUT_BUF_SIZE 4096
typedef struct { typedef struct {
struct jpeg_error_mgr pub; 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); 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; qbyte *buffer;
vfsfile_t *outfile; vfsfile_t *outfile;
@ -1543,6 +1570,9 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
struct jpeg_compress_struct cinfo; struct jpeg_compress_struct cinfo;
JSAMPROW row_pointer[1]; JSAMPROW row_pointer[1];
if (fmt != TF_RGB24)
return false;
if (!LIBJPEG_LOADED()) if (!LIBJPEG_LOADED())
return false; 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);
cinfo.err = qjpeg_std_error(&jerr.pub);
#else
cinfo.err = jpeg_std_error(&jerr.pub);
#endif
jerr.pub.error_exit = jpeg_error_exit; jerr.pub.error_exit = jpeg_error_exit;
if (setjmp(jerr.setjmp_buffer)) if (setjmp(jerr.setjmp_buffer))
{ {
#ifdef DYNAMIC_LIBJPEG qjpeg_destroy_compress(&cinfo);
qjpeg_destroy_compress(&cinfo);
#else
jpeg_destroy_compress(&cinfo);
#endif
VFS_CLOSE(outfile); VFS_CLOSE(outfile);
FS_Remove(filename, FS_GAME); FS_Remove(filename, FS_GAME);
Con_Printf("Failed to create jpeg\n"); Con_Printf("Failed to create jpeg\n");
return false; return false;
} }
#ifdef DYNAMIC_LIBJPEG qjpeg_create_compress(&cinfo);
qjpeg_create_compress(&cinfo);
#else
jpeg_create_compress(&cinfo);
#endif
buffer = screendata; buffer = screendata;
@ -1587,42 +1605,18 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression
cinfo.image_height = screenheight; cinfo.image_height = screenheight;
cinfo.input_components = 3; cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB; cinfo.in_color_space = JCS_RGB;
#ifdef DYNAMIC_LIBJPEG qjpeg_set_defaults(&cinfo);
qjpeg_set_defaults(&cinfo); qjpeg_set_quality (&cinfo, bound(0, compression, 100), true);
#else qjpeg_start_compress(&cinfo, true);
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
while (cinfo.next_scanline < cinfo.image_height) while (cinfo.next_scanline < cinfo.image_height)
{ {
*row_pointer = &buffer[(cinfo.image_height - cinfo.next_scanline - 1) * cinfo.image_width * 3]; *row_pointer = &buffer[(cinfo.image_height - cinfo.next_scanline - 1) * cinfo.image_width * 3];
#ifdef DYNAMIC_LIBJPEG qjpeg_write_scanlines(&cinfo, row_pointer, 1);
qjpeg_write_scanlines(&cinfo, row_pointer, 1);
#else
jpeg_write_scanlines(&cinfo, row_pointer, 1);
#endif
} }
#ifdef DYNAMIC_LIBJPEG qjpeg_finish_compress(&cinfo);
qjpeg_finish_compress(&cinfo);
#else
jpeg_finish_compress(&cinfo);
#endif
VFS_CLOSE(outfile); VFS_CLOSE(outfile);
#ifdef DYNAMIC_LIBJPEG qjpeg_destroy_compress(&cinfo);
qjpeg_destroy_compress(&cinfo);
#else
jpeg_destroy_compress(&cinfo);
#endif
return true; return true;
} }
#endif #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; if (gl_picmip2d.ival > 0)
*scaled_height >>= gl_picmip2d.ival; {
*scaled_width >>= gl_picmip2d.ival;
*scaled_height >>= gl_picmip2d.ival;
}
} }
} else
else
{
if (gl_picmip.ival > 0)
{ {
TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value)); if (gl_picmip.ival > 0)
*scaled_width >>= gl_picmip.ival; {
*scaled_height >>= gl_picmip.ival; 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: case TF_MIP4_LUM8:
//8bit opaque data //8bit opaque data
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); 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) if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight)
{ {
unsigned int pixels = unsigned int pixels =
@ -3537,6 +3535,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag
case TF_MIP4_SOLID8: case TF_MIP4_SOLID8:
//8bit opaque data //8bit opaque data
Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); 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]) if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight && sh_config.texfmt[PTI_RGBX8])
{ {
unsigned int pixels = unsigned int pixels =

View file

@ -697,7 +697,6 @@ void Media_LoadTrackNames (char *listname);
void M_Media_Draw (menu_t *menu) void M_Media_Draw (menu_t *menu)
{ {
mpic_t *p;
mediatrack_t *track; mediatrack_t *track;
int y; int y;
int op, i; int op, i;
@ -2672,6 +2671,12 @@ int captureoldfbo;
qboolean capturingfbo; qboolean capturingfbo;
texid_t capturetexture; texid_t capturetexture;
qboolean captureframeforce; qboolean captureframeforce;
#ifdef GLQUAKE
//ring buffer
int pbo_handles[4];
enum uploadfmt pbo_format;
#endif
int pbo_oldest;
qboolean capturepaused; qboolean capturepaused;
extern cvar_t vid_conautoscale; extern cvar_t vid_conautoscale;
@ -2751,13 +2756,13 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width
} }
return ctx; 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; struct capture_raw_ctx *ctx = vctx;
char filename[MAX_OSPATH]; char filename[MAX_OSPATH];
ctx->frames = frame+1; ctx->frames = frame+1;
Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension); 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) 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; 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; struct capture_avi_ctx *ctx = vctx;
qbyte *data = vdata; qbyte *data = vdata;
int c, i; int c, i;
qbyte temp; qbyte temp;
// swap rgb to bgr
c = width*height*3; if (fmt == TF_BGRA32)
for (i=0 ; i<c ; i+=3)
{ {
temp = data[i]; // truncate bgra to bgr
data[i] = data[i+2]; c = width*height;
data[i+2] = temp; 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 //write it
if (FAILED(qAVIStreamWrite(avi_video_stream(ctx), frame, 1, data, width*height * 3, ((frame%15) == 0)?AVIIF_KEYFRAME:0, NULL, NULL))) 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; 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) static void QDECL capture_null_audio(void *vctx, void *data, int bytes)
@ -3098,6 +3123,7 @@ void Media_RecordFrame (void)
{ {
char *buffer; char *buffer;
int truewidth, trueheight; int truewidth, trueheight;
enum uploadfmt fmt;
if (!currentcapture_funcs) if (!currentcapture_funcs)
return; return;
@ -3162,17 +3188,65 @@ void Media_RecordFrame (void)
if (R2D_Flush) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
//submit the current video frame. audio will be mixed to match. #ifdef GLQUAKE
buffer = VID_GetRGBInfo(0, &truewidth, &trueheight); if (pbo_format != TF_INVALID)
if (buffer)
{ {
currentcapture_funcs->capture_video(currentcapture_ctx, buffer, captureframe, truewidth, trueheight); int imagesize = vid.fbpwidth * vid.fbpheight * 4;
capturelastvideotime += captureframeinterval; while (pbo_oldest + countof(pbo_handles) <= captureframe)
captureframe++; {
BZ_Free (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, 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 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; captureframeforce = false;
@ -3358,6 +3432,35 @@ void Media_InitFakeSoundDevice (int speed, int channels, int samplebits)
void Media_StopRecordFilm_f (void) 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) if (capture_fakesounddevice)
S_ShutdownCard(capture_fakesounddevice); S_ShutdownCard(capture_fakesounddevice);
capture_fakesounddevice = NULL; capture_fakesounddevice = NULL;
@ -3401,7 +3504,7 @@ static void Media_RecordFilm (char *recordingname, qboolean demo)
Con_ClearNotify(); Con_ClearNotify();
captureframe = 0; captureframe = pbo_oldest = 0;
for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++) for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++)
{ {
if (pluginencodersfunc[i]) if (pluginencodersfunc[i])
@ -3438,11 +3541,17 @@ static void Media_RecordFilm (char *recordingname, qboolean demo)
{ {
capturingfbo = true; capturingfbo = true;
capturetexture = R2D_RT_Configure("$democapture", capturewidth.ival, captureheight.ival, TF_BGRA32); 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.fbpwidth = capturewidth.ival;
vid.fbpheight = captureheight.ival; vid.fbpheight = captureheight.ival;
vid.framebuffer = capturetexture; 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 #endif
recordingdemo = demo; recordingdemo = demo;

View file

@ -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 qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
extern void (*VID_DeInit) (void); 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 (*VID_SetWindowCaption) (char *msg);
extern void SCR_Init (void); extern void SCR_Init (void);
@ -413,7 +413,7 @@ typedef struct rendererinfo_s {
void (*VID_DestroyCursor) (void *cursor); //may be null void (*VID_DestroyCursor) (void *cursor); //may be null
void (*VID_SetWindowCaption) (char *msg); 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); void (*SCR_UpdateScreen) (void);

View file

@ -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) void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
srect_t srect; srect_t srect;
if (R2D_Flush)
R2D_Flush();
csqc_dp_lastwas3d = false; csqc_dp_lastwas3d = false;
srect.x = G_FLOAT(OFS_PARM0) / (float)vid.fbvwidth; 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 drawresetcliparea(void) = #459;
void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
if (R2D_Flush)
R2D_Flush();
csqc_dp_lastwas3d = false; csqc_dp_lastwas3d = false;
BE_Scissor(NULL); BE_Scissor(NULL);

View file

@ -31,6 +31,7 @@ shader_t *shader_polyblend;
shader_t *shader_menutint; shader_t *shader_menutint;
#define DRAW_QUADS 128 #define DRAW_QUADS 128
static int draw_active_flags;
static shader_t *draw_active_shader; static shader_t *draw_active_shader;
static avec4_t draw_active_colour; static avec4_t draw_active_colour;
static mesh_t draw_mesh; 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) 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; R2D_Flush = NULL;
draw_active_shader = 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; 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) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
draw_active_shader = pic; draw_active_shader = pic;
draw_active_flags = r2d_be_flags;
R2D_Flush = R2D_ImageFlush; R2D_Flush = R2D_ImageFlush;
draw_mesh.numindexes = 0; draw_mesh.numindexes = 0;
@ -663,12 +665,13 @@ void R2D_FillBlock(float x, float y, float w, float h)
pic = shader_draw_fill_trans; pic = shader_draw_fill_trans;
else else
pic = shader_draw_fill; 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) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
draw_active_shader = pic; draw_active_shader = pic;
draw_active_flags = r2d_be_flags;
R2D_Flush = R2D_ImageFlush; R2D_Flush = R2D_ImageFlush;
draw_mesh.numindexes = 0; draw_mesh.numindexes = 0;

View file

@ -856,7 +856,7 @@ void (*R_RenderView) (void); // must set r_refdef first
qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette); qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette);
void (*VID_DeInit) (void); 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 (*VID_SetWindowCaption) (char *msg);
void (*SCR_UpdateScreen) (void); void (*SCR_UpdateScreen) (void);

View file

@ -80,7 +80,8 @@ void SCR_ShowPic_Remove_f(void);
//a header is better than none... //a header is better than none...
void Draw_TextBox (int x, int y, int width, int lines); void Draw_TextBox (int x, int y, int width, int lines);
enum fs_relative; 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); void SCR_DrawTwoDimensional(int uimenu, qboolean nohud);

View file

@ -110,6 +110,6 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette);
qboolean GLVID_Is8bit(void); qboolean GLVID_Is8bit(void);
void GLVID_SwapBuffers(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); void GLVID_SetCaption(char *caption);
#endif #endif

View file

@ -163,8 +163,9 @@ static qboolean Headless_VID_ApplyGammaRamps (unsigned short *ramps)
static void Headless_VID_SetWindowCaption (char *msg) 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; *truevidwidth = *truevidheight = 0;
return NULL; return NULL;
} }

View file

@ -802,7 +802,7 @@ qboolean D3D9_VID_ApplyGammaRamps (unsigned short *ramps)
IDirect3DDevice9_SetGammaRamp(pD3DDev9, 0, D3DSGR_NO_CALIBRATION, (D3DGAMMARAMP *)ramps); IDirect3DDevice9_SetGammaRamp(pD3DDev9, 0, D3DSGR_NO_CALIBRATION, (D3DGAMMARAMP *)ramps);
return true; 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; IDirect3DSurface9 *backbuf, *surf;
D3DLOCKED_RECT rect; 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(IDirect3DDevice9_GetRenderTargetData(pD3DDev9, backbuf, surf)))
if (!FAILED(IDirect3DSurface9_LockRect(surf, &rect, NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_READONLY|D3DLOCK_NOSYSLOCK))) 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) if (ret)
{ {
*fmt = TF_RGB24;
// read surface rect and convert 32 bgra to 24 rgb and flip // 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; 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++) 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_DeInit) (void);
void (D3D9_VID_SetPalette) (unsigned char *palette); void (D3D9_VID_SetPalette) (unsigned char *palette);
void (D3D9_VID_ShiftPalette) (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_VID_SetWindowCaption) (char *msg);
void (D3D9_SCR_UpdateScreen) (void); void (D3D9_SCR_UpdateScreen) (void);

View file

@ -1102,7 +1102,7 @@ static qboolean D3D11_VID_ApplyGammaRamps(unsigned short *ramps)
} }
return false; 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. //don't directly map the frontbuffer, as that can hold other things.
//create a texture, copy the (gpu)backbuffer to that (cpu)texture //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); ID3D11Resource_Release(backbuffer);
if (!FAILED(ID3D11DeviceContext_Map(d3ddevctx, (ID3D11Resource*)texture, 0, D3D11_MAP_READ, 0, &lock))) if (!FAILED(ID3D11DeviceContext_Map(d3ddevctx, (ID3D11Resource*)texture, 0, D3D11_MAP_READ, 0, &lock)))
{ {
r = rgb = BZ_Malloc(prepad + 3 * vid.pixelwidth * vid.pixelheight); r = rgb = BZ_Malloc(3 * vid.pixelwidth * vid.pixelheight);
r += prepad;
for (y = vid.pixelheight; y-- > 0; ) for (y = vid.pixelheight; y-- > 0; )
{ {
in = lock.pData; in = lock.pData;
@ -1150,6 +1149,7 @@ static char *D3D11_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidhei
ID3D11Texture2D_Release(texture); ID3D11Texture2D_Release(texture);
*truevidwidth = vid.pixelwidth; *truevidwidth = vid.pixelwidth;
*truevidheight = vid.pixelheight; *truevidheight = vid.pixelheight;
*fmt = TF_RGB24;
return r; return r;
} }
static void (D3D11_VID_SetWindowCaption) (char *msg) static void (D3D11_VID_SetWindowCaption) (char *msg)

View file

@ -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_default;
struct font_s *font_console; struct font_s *font_console;
struct font_s *font_tiny; struct font_s *font_tiny;
static int font_be_flags;
extern unsigned int r2d_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. //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.numvertexes = font_foremesh.numvertexes;
font_backmesh.istrifan = font_foremesh.istrifan; 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); 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.numindexes = 0;
font_foremesh.numvertexes = 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 //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) 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();
R2D_Flush = Font_Flush; R2D_Flush = Font_Flush;
font_be_flags = r2d_be_flags;
curfont = font; curfont = font;
*px = (vx*(int)vid.rotpixelwidth) / (float)vid.width; *px = (vx*(int)vid.rotpixelwidth) / (float)vid.width;
*py = (vy*(int)vid.rotpixelheight) / (float)vid.height; *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) 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();
R2D_Flush = Font_Flush; R2D_Flush = Font_Flush;
font_be_flags = r2d_be_flags;
curfont = font; curfont = font;
*px = (vx*(float)vid.rotpixelwidth) / (float)vid.width; *px = (vx*(float)vid.rotpixelwidth) / (float)vid.width;
*py = (vy*(float)vid.rotpixelheight) / (float)vid.height; *py = (vy*(float)vid.rotpixelheight) / (float)vid.height;

View file

@ -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 { //returns a BZ_Malloced array
extern qboolean gammaworks; extern qboolean gammaworks;
int i, c; 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)); p = BZ_Malloc(vid.pixelwidth*vid.pixelheight*sizeof(float));
qglReadPixels (0, 0, vid.pixelwidth, vid.pixelheight, GL_DEPTH_COMPONENT, GL_FLOAT, p); 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; c = vid.pixelwidth*vid.pixelheight;
for (i = 1; i < c; i++) for (i = 1; i < c; i++)
{ {
ret[prepadbytes+i*3+0]=p[i]*p[i]*p[i]*255; ret[i*3+0]=p[i]*p[i]*p[i]*255;
ret[prepadbytes+i*3+1]=p[i]*p[i]*p[i]*255; ret[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+2]=p[i]*p[i]*p[i]*255;
} }
BZ_Free(p); BZ_Free(p);
} }
@ -274,30 +274,46 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight)
{ {
qbyte *p; qbyte *p;
// gles only guarantees GL_RGBA/GL_UNSIGNED_BYTE so downconvert and resize //gles:
ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*4); //Only two format/type parameter pairs are accepted.
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret + prepadbytes); //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); c = (*truewidth)*(*trueheight);
p = ret + prepadbytes; p = ret;
for (i = 1; i < c; i++) for (i = 1; i < c; i++)
{ {
p[i*3+0]=p[i*4+0]; p[i*3+0]=p[i*4+0];
p[i*3+1]=p[i*4+1]; p[i*3+1]=p[i*4+1];
p[i*3+2]=p[i*4+2]; 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 else
{ {
ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*3); *fmt = TF_RGB24;
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret + prepadbytes); ret = BZ_Malloc((*truewidth)*(*trueheight)*3);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret);
} }
if (gammaworks) if (gammaworks)
{ {
c = prepadbytes+(*truewidth)*(*trueheight)*3; c = (*truewidth)*(*trueheight)*3;
for (i=prepadbytes ; i<c ; i+=3) for (i=0 ; i<c ; i+=3)
{ {
extern qbyte gammatable[256]; extern qbyte gammatable[256];
ret[i+0] = gammatable[ret[i+0]]; ret[i+0] = gammatable[ret[i+0]];

View file

@ -612,6 +612,10 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei
#define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif #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 #ifndef GL_ARB_vertex_buffer_object
#define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_SIZE_ARB 0x8764

View file

@ -1221,10 +1221,11 @@ void SV_Savegame (char *savename)
//okay, we drew something, we're good to save a screeny. //okay, we drew something, we're good to save a screeny.
if (okay) if (okay)
{ {
rgbbuffer = VID_GetRGBInfo(0, &width, &height); enum uploadfmt fmt;
rgbbuffer = VID_GetRGBInfo(&width, &height, &fmt);
if (rgbbuffer) if (rgbbuffer)
{ {
SCR_ScreenShot(savefilename, FS_GAMEONLY, rgbbuffer, width, height); SCR_ScreenShot(savefilename, FS_GAMEONLY, rgbbuffer, width, height, fmt);
BZ_Free(rgbbuffer); BZ_Free(rgbbuffer);

View file

@ -115,20 +115,38 @@ void close_video(struct encctx *ctx)
} }
av_free(ctx->video_outbuf); 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; struct encctx *ctx = vctx;
//weird maths to flip it. const uint8_t *srcslices[2];
const uint8_t *srcslices[2] = {(uint8_t*)data + (height-1)*width*3, NULL}; int srcstride[2];
int srcstride[2] = {-width*3, 0};
int success; int success;
AVPacket pkt; AVPacket pkt;
int avpfmt;
int inbpp;
if (!ctx->video_st) if (!ctx->video_st)
return; 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...). //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); sws_scale(ctx->scale_ctx, srcslices, srcstride, 0, height, ctx->picture->data, ctx->picture->linesize);
av_init_packet(&pkt); av_init_packet(&pkt);