Merge pull request 'Gif recording improvements' (#109) from gifhell into blankart-dev
Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/109
This commit is contained in:
commit
ea1426b947
12 changed files with 212 additions and 267 deletions
|
|
@ -68,7 +68,7 @@ void I_WaitVBL(INT32 count)
|
|||
(void)count;
|
||||
}
|
||||
|
||||
void I_ReadScreen(UINT8 *scr)
|
||||
void I_ReadScreen(UINT8 * restrict scr, INT32 scale)
|
||||
{
|
||||
(void)scr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ void F_WipeStartScreen(void)
|
|||
}
|
||||
#endif
|
||||
wipe_scr_start = screens[3];
|
||||
I_ReadScreen(wipe_scr_start);
|
||||
I_ReadScreen(wipe_scr_start, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -333,7 +333,7 @@ void F_WipeEndScreen(void)
|
|||
}
|
||||
#endif
|
||||
wipe_scr_end = screens[4];
|
||||
I_ReadScreen(wipe_scr_end);
|
||||
I_ReadScreen(wipe_scr_end, 1);
|
||||
V_DrawBlock(0, 0, 0, vid.width, vid.height, wipe_scr_start);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include "hw_glob.h"
|
||||
#include "hw_drv.h"
|
||||
|
||||
#include "../m_misc.h" //FIL_WriteFile()
|
||||
#include "../r_draw.h" //viewborderlump
|
||||
#include "../r_main.h"
|
||||
#include "../w_wad.h"
|
||||
|
|
@ -1252,41 +1251,18 @@ static inline boolean saveTGA(const char *file_name, void *buffer,
|
|||
// screen shot
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
UINT8 *HWR_GetScreenshot(void)
|
||||
UINT8 *HWR_GetScreenshot(INT32 scale)
|
||||
{
|
||||
static UINT8 *buf = NULL;
|
||||
|
||||
buf = realloc(buf, vid.width * vid.height * 3);
|
||||
buf = realloc(buf, (vid.width/scale)*(vid.height/scale)*3);
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
// returns 24bit 888 RGB
|
||||
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
|
||||
HWD.pfnReadScreenFinalTexture(buf, scale);
|
||||
return buf;
|
||||
}
|
||||
|
||||
boolean HWR_Screenshot(const char *pathname)
|
||||
{
|
||||
boolean ret;
|
||||
UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf));
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
CONS_Debug(DBG_RENDER, "HWR_Screenshot: Failed to allocate memory\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns 24bit 888 RGB
|
||||
HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf);
|
||||
|
||||
#ifdef USE_PNG
|
||||
ret = M_SavePNG(pathname, buf, vid.width, vid.height, NULL);
|
||||
#else
|
||||
ret = saveTGA(pathname, buf, vid.width, vid.height);
|
||||
#endif
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif //HWRENDER
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFl
|
|||
EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo);
|
||||
EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo);
|
||||
EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo);
|
||||
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data);
|
||||
EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale);
|
||||
EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip);
|
||||
EXPORT void HWRAPI(ClearMipMapCache) (void);
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ struct hwdriver_s
|
|||
SetTexture pfnSetTexture;
|
||||
UpdateTexture pfnUpdateTexture;
|
||||
DeleteTexture pfnDeleteTexture;
|
||||
ReadRect pfnReadRect;
|
||||
ReadScreenFinalTexture pfnReadScreenFinalTexture;
|
||||
GClipRect pfnGClipRect;
|
||||
ClearMipMapCache pfnClearMipMapCache;
|
||||
SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility
|
||||
|
|
|
|||
|
|
@ -54,8 +54,7 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32
|
|||
void HWR_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 color);
|
||||
void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum);
|
||||
|
||||
UINT8 *HWR_GetScreenshot(void);
|
||||
boolean HWR_Screenshot(const char *pathname);
|
||||
UINT8 *HWR_GetScreenshot(INT32 scale);
|
||||
|
||||
void HWR_AddCommands(void);
|
||||
void HWR_AddSessionCommands(void);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
#include "r_opengl.h"
|
||||
#include "r_vbo.h"
|
||||
|
||||
// requires GL 4.3
|
||||
//#define GLDEBUGMESSAGE
|
||||
|
||||
#if defined (HWRENDER) && !defined (NOROPENGL)
|
||||
|
||||
struct GLRGBAFloat
|
||||
|
|
@ -281,6 +284,10 @@ static void GL_MSG_Error(const char *format, ...)
|
|||
#define pglCopyTexImage2D glCopyTexImage2D
|
||||
#define pglCopyTexSubImage2D glCopyTexSubImage2D
|
||||
|
||||
#ifdef GLDEBUGMESSAGE
|
||||
#define pglDebugMessageCallback glDebugMessageCallback
|
||||
#endif
|
||||
|
||||
#else //!STATIC_OPENGL
|
||||
|
||||
/* 1.0 functions */
|
||||
|
|
@ -423,6 +430,11 @@ static PFNglDeleteBuffers pglDeleteBuffers;
|
|||
typedef void (APIENTRY * PFNglBlendEquation) (GLenum mode);
|
||||
static PFNglBlendEquation pglBlendEquation;
|
||||
|
||||
#ifdef GLDEBUGMESSAGE
|
||||
typedef void (APIENTRY * PFNglDebugMessageCallback) (void (APIENTRY *DEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam), const void *userParam);
|
||||
static PFNglDebugMessageCallback pglDebugMessageCallback;
|
||||
#endif
|
||||
|
||||
|
||||
/* 1.2 Parms */
|
||||
/* GL_CLAMP_TO_EDGE_EXT */
|
||||
|
|
@ -983,6 +995,10 @@ void SetupGLFunc4(void)
|
|||
*(void**)&pglUniform3fv = GetGLFunc("glUniform3fv");
|
||||
*(void**)&pglGetUniformLocation = GetGLFunc("glGetUniformLocation");
|
||||
#endif
|
||||
|
||||
#ifdef GLDEBUGMESSAGE
|
||||
*(void**)&pglDebugMessageCallback = GetGLFunc("glDebugMessageCallback");
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT boolean HWRAPI(CompileShaders) (void)
|
||||
|
|
@ -1335,6 +1351,50 @@ void SetModelView(GLint w, GLint h)
|
|||
pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
|
||||
}
|
||||
|
||||
#ifdef GLDEBUGMESSAGE
|
||||
static void APIENTRY DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)
|
||||
{
|
||||
const char *debugsource, *debugtype;
|
||||
|
||||
switch (source)
|
||||
{
|
||||
#define S(s) case GL_DEBUG_SOURCE_##s: debugsource = #s; break
|
||||
S(API);
|
||||
S(WINDOW_SYSTEM);
|
||||
S(SHADER_COMPILER);
|
||||
S(THIRD_PARTY);
|
||||
S(APPLICATION);
|
||||
S(OTHER);
|
||||
#undef S
|
||||
default:
|
||||
debugsource = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
#define S(s) case GL_DEBUG_TYPE_##s: debugtype = #s; break
|
||||
S(ERROR);
|
||||
S(DEPRECATED_BEHAVIOR);
|
||||
S(UNDEFINED_BEHAVIOR);
|
||||
S(PORTABILITY);
|
||||
S(PERFORMANCE);
|
||||
S(MARKER);
|
||||
S(PUSH_GROUP);
|
||||
S(POP_GROUP);
|
||||
S(OTHER);
|
||||
#undef S
|
||||
default:
|
||||
debugtype = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
alerttype_t level = severity == GL_DEBUG_SEVERITY_HIGH ? CONS_ERROR
|
||||
: severity == GL_DEBUG_SEVERITY_MEDIUM ? CONS_WARNING
|
||||
: CONS_NOTICE;
|
||||
CONS_Alert(level, "OpenGL (%s) (%s): %s\n", debugsource, debugtype, message);
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------+
|
||||
// SetStates : Set permanent states
|
||||
|
|
@ -1395,6 +1455,12 @@ void SetStates(void)
|
|||
pglLoadIdentity();
|
||||
pglScalef(1.0f, 1.0f, -1.0f);
|
||||
pglGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix); // added for new coronas' code (without depth buffer)
|
||||
|
||||
#ifdef GLDEBUGMESSAGE
|
||||
pglEnable(GL_DEBUG_OUTPUT);
|
||||
pglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
pglDebugMessageCallback(&DebugMessage, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1514,58 +1580,37 @@ EXPORT void HWRAPI(ClearMipMapCache) (void)
|
|||
Flush();
|
||||
}
|
||||
|
||||
|
||||
// -----------------+
|
||||
// ReadRect : Read a rectangle region of the truecolor framebuffer
|
||||
// : store pixels as 16bit 565 RGB
|
||||
// Returns : 16bit 565 RGB pixel array stored in dst_data
|
||||
// -----------------+
|
||||
EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
|
||||
INT32 dst_stride, UINT16 * dst_data)
|
||||
// -----------------------+
|
||||
// ReadScreenFinalTexture : Reads out the final screen texture
|
||||
// Returns : 24bit RGB pixel array stored in dest
|
||||
// -----------------------+
|
||||
EXPORT void HWRAPI(ReadScreenFinalTexture) (UINT8 * restrict dest, INT32 scale)
|
||||
{
|
||||
INT32 i;
|
||||
// GL_DBG_Printf ("ReadRect()\n");
|
||||
if (dst_stride == width*3)
|
||||
{
|
||||
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
|
||||
GLubyte *row = malloc(dst_stride);
|
||||
if (!row) return;
|
||||
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
|
||||
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
for(i = 0; i < height/2; i++)
|
||||
{
|
||||
memcpy(row, top, dst_stride);
|
||||
memcpy(top, bottom, dst_stride);
|
||||
memcpy(bottom, row, dst_stride);
|
||||
top += dst_stride;
|
||||
bottom -= dst_stride;
|
||||
}
|
||||
free(row);
|
||||
}
|
||||
else
|
||||
{
|
||||
INT32 j;
|
||||
GLubyte *image = malloc(width*height*3*sizeof (*image));
|
||||
if (!image) return;
|
||||
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
for (i = height-1; i >= 0; i--)
|
||||
{
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
dst_data[(height-1-i)*width+j] =
|
||||
(UINT16)(
|
||||
((image[(i*width+j)*3]>>3)<<11) |
|
||||
((image[(i*width+j)*3+1]>>2)<<5) |
|
||||
((image[(i*width+j)*3+2]>>3)));
|
||||
}
|
||||
}
|
||||
free(image);
|
||||
}
|
||||
}
|
||||
const INT32 stride = (screen_width/scale)*3;
|
||||
INT32 scanlines = screen_height;
|
||||
GLubyte * restrict image;
|
||||
|
||||
image = malloc(screen_width*screen_height*3);
|
||||
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
pglReadPixels(0, 0, screen_width, screen_height, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
|
||||
// TODO the downscaling happens in the screen capture code now,
|
||||
// yet we're still doing this on the CPU? sheesh...
|
||||
// this is where actual knowledge of OpenGL would've come in handy
|
||||
image += scanlines*screen_width*3;
|
||||
while ((scanlines -= scale) >= 0)
|
||||
{
|
||||
image -= screen_width*scale*3;
|
||||
if (scale == 1)
|
||||
memcpy(dest, image, stride);
|
||||
else for (size_t i = 0; i < stride; i += 3)
|
||||
memcpy(dest + i, image + i*scale, 3);
|
||||
dest += stride;
|
||||
}
|
||||
|
||||
// ...yet still, restrict doesn't make the inner loop any faster
|
||||
free(image - ((screen_height % scale) * screen_width*3));
|
||||
}
|
||||
|
||||
// -----------------+
|
||||
// GClipRect : Defines the 2D hardware clipping window
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ void I_WaitVBL(INT32 count);
|
|||
|
||||
\return void
|
||||
*/
|
||||
void I_ReadScreen(UINT8 *scr);
|
||||
void I_ReadScreen(UINT8 * restrict scr, INT32 scale);
|
||||
|
||||
/** \brief Start disk icon
|
||||
*/
|
||||
|
|
|
|||
228
src/m_anigif.c
228
src/m_anigif.c
|
|
@ -57,14 +57,15 @@ static precise_t gif_prevframetime = 0;
|
|||
static UINT32 gif_delayus = 0; // "us" is microseconds
|
||||
static UINT8 gif_writeover = 0;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *pixels;
|
||||
size_t size;
|
||||
boolean owns_pixels;
|
||||
} gif_screen_t;
|
||||
static gif_screen_t gif_screens[2];
|
||||
|
||||
// SCReen BUFfer (obviously)
|
||||
// ---
|
||||
static UINT8 *scrbuf_pos;
|
||||
static UINT8 *scrbuf_linebegin;
|
||||
static UINT8 *scrbuf_lineend;
|
||||
static UINT8 *scrbuf_writeend;
|
||||
static INT16 scrbuf_downscaleamt = 1;
|
||||
static UINT16 scrbuf_width, scrbuf_height;
|
||||
static UINT8 *scrbuf_screens;
|
||||
|
||||
// OPTIMIZE gif output
|
||||
// ---
|
||||
|
|
@ -79,13 +80,13 @@ static gif_screen_t gif_screens[2];
|
|||
static UINT8 GIF_optimizecmprow(const UINT8 *dst, const UINT8 *src, INT32 row,
|
||||
INT32 *last, INT32 *left, INT32 *right)
|
||||
{
|
||||
const UINT8 *dp = dst + (vid.width * row);
|
||||
const UINT8 *sp = src + (vid.width * row);
|
||||
const UINT8 *dp = dst + (scrbuf_width * row);
|
||||
const UINT8 *sp = src + (scrbuf_width * row);
|
||||
const UINT8 *dtmp, *stmp;
|
||||
UINT8 doleft = 1, doright = 1;
|
||||
INT32 i = 0;
|
||||
|
||||
if (!memcmp(sp, dp, vid.width))
|
||||
if (!memcmp(sp, dp, scrbuf_width))
|
||||
return 0; // unchanged.
|
||||
|
||||
*last = row;
|
||||
|
|
@ -112,14 +113,14 @@ static UINT8 GIF_optimizecmprow(const UINT8 *dst, const UINT8 *src, INT32 row,
|
|||
}
|
||||
|
||||
// right side
|
||||
i = vid.width - 1;
|
||||
if (*right == vid.width - 1) // edge reached
|
||||
i = scrbuf_width - 1;
|
||||
if (*right == scrbuf_width - 1) // edge reached
|
||||
doright = 0;
|
||||
else if (*right >= 0) // right set, non-end-of-width
|
||||
{
|
||||
dtmp = dp + *right + 1;
|
||||
stmp = sp + *right + 1;
|
||||
if (!memcmp(stmp, dtmp, vid.width - (*right + 1)))
|
||||
if (!memcmp(stmp, dtmp, scrbuf_width - (*right + 1)))
|
||||
doright = 0; // right side not changed
|
||||
}
|
||||
while (doright)
|
||||
|
|
@ -149,7 +150,7 @@ static UINT8 GIF_optimizecmprow(const UINT8 *dst, const UINT8 *src, INT32 row,
|
|||
static void GIF_optimizeregion(const UINT8 *dst, const UINT8 *src,
|
||||
INT32 *x, INT32 *y, INT32 *w, INT32 *h)
|
||||
{
|
||||
INT32 st = 0, sb = vid.height - 1; // work from both directions
|
||||
INT32 st = 0, sb = scrbuf_height - 1; // work from both directions
|
||||
INT32 firstchg_t = -1, firstchg_b = -1; // store first changed row.
|
||||
INT32 lastchg_t = -1, lastchg_b = -1; // Store last row... just in case
|
||||
INT32 lmpix = -1, rmpix = -1; // store left and rightmost change
|
||||
|
|
@ -160,7 +161,7 @@ static void GIF_optimizeregion(const UINT8 *dst, const UINT8 *src,
|
|||
if (!stopt)
|
||||
{
|
||||
if (GIF_optimizecmprow(dst, src, st++, &lastchg_t, &lmpix, &rmpix)
|
||||
&& lmpix == 0 && rmpix == vid.width - 1)
|
||||
&& lmpix == 0 && rmpix == scrbuf_width - 1)
|
||||
stopt = 1;
|
||||
if (firstchg_t < 0 && lastchg_t >= 0)
|
||||
firstchg_t = lastchg_t;
|
||||
|
|
@ -168,7 +169,7 @@ static void GIF_optimizeregion(const UINT8 *dst, const UINT8 *src,
|
|||
if (!stopb)
|
||||
{
|
||||
if (GIF_optimizecmprow(dst, src, sb--, &lastchg_b, &lmpix, &rmpix)
|
||||
&& lmpix == 0 && rmpix == vid.width - 1)
|
||||
&& lmpix == 0 && rmpix == scrbuf_width - 1)
|
||||
stopb = 1;
|
||||
if (firstchg_b < 0 && lastchg_b >= 0)
|
||||
firstchg_b = lastchg_b;
|
||||
|
|
@ -238,18 +239,6 @@ static void GIF_bwrwrite(UINT32 idata)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// SCReen BUFfer (obviously)
|
||||
// ---
|
||||
static UINT8 *scrbuf_pos;
|
||||
static UINT8 *scrbuf_linebegin;
|
||||
static UINT8 *scrbuf_lineend;
|
||||
static UINT8 *scrbuf_writeend;
|
||||
static INT16 scrbuf_downscaleamt = 1;
|
||||
|
||||
|
||||
|
||||
// GIF LZW algorithm
|
||||
// ---
|
||||
#define GIFLZW_TABLECLR 0x100
|
||||
|
|
@ -375,10 +364,10 @@ static void GIF_lzw(void)
|
|||
GIF_bwrwrite(GIFLZW_TABLECLR);
|
||||
GIF_prepareLZW();
|
||||
}
|
||||
if ((scrbuf_pos += scrbuf_downscaleamt) >= scrbuf_lineend)
|
||||
if (++scrbuf_pos >= scrbuf_lineend)
|
||||
{
|
||||
scrbuf_lineend += (vid.width * scrbuf_downscaleamt);
|
||||
scrbuf_linebegin += (vid.width * scrbuf_downscaleamt);
|
||||
scrbuf_lineend += scrbuf_width;
|
||||
scrbuf_linebegin += scrbuf_width;
|
||||
scrbuf_pos = scrbuf_linebegin;
|
||||
}
|
||||
// Just a bit of overflow prevention
|
||||
|
|
@ -459,7 +448,6 @@ static void GIF_headwrite(void)
|
|||
{
|
||||
UINT8 *gifhead = Z_Malloc(800, PU_STATIC, NULL);
|
||||
UINT8 *p = gifhead;
|
||||
UINT16 rwidth, rheight;
|
||||
|
||||
if (!gif_out)
|
||||
return;
|
||||
|
|
@ -470,18 +458,18 @@ static void GIF_headwrite(void)
|
|||
if (gif_downscale)
|
||||
{
|
||||
scrbuf_downscaleamt = vid.dupx;
|
||||
rwidth = (vid.width / scrbuf_downscaleamt);
|
||||
rheight = (vid.height / scrbuf_downscaleamt);
|
||||
scrbuf_width = (vid.width / scrbuf_downscaleamt);
|
||||
scrbuf_height = (vid.height / scrbuf_downscaleamt);
|
||||
}
|
||||
else
|
||||
{
|
||||
scrbuf_downscaleamt = 1;
|
||||
rwidth = vid.width;
|
||||
rheight = vid.height;
|
||||
scrbuf_width = vid.width;
|
||||
scrbuf_height = vid.height;
|
||||
}
|
||||
|
||||
WRITEUINT16(p, rwidth);
|
||||
WRITEUINT16(p, rheight);
|
||||
WRITEUINT16(p, scrbuf_width);
|
||||
WRITEUINT16(p, scrbuf_height);
|
||||
|
||||
// colors, aspect, etc
|
||||
WRITEUINT8(p, 0xF7); // (0xF7 = 1111 0111)
|
||||
|
|
@ -515,28 +503,16 @@ static size_t gifframe_size = 8192;
|
|||
#ifdef HWRENDER
|
||||
static colorlookup_t gif_colorlookup;
|
||||
|
||||
static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
|
||||
static void GIF_rgbconvert(UINT8 * restrict linear, UINT8 * restrict scr)
|
||||
{
|
||||
UINT8 r, g, b;
|
||||
size_t src, dest;
|
||||
int x, y;
|
||||
|
||||
InitColorLUT(&gif_colorlookup, (gif_localcolortable) ? gif_framepalette : gif_headerpalette, true);
|
||||
|
||||
for (x = 0; x < vid.width; x += scrbuf_downscaleamt)
|
||||
for (INT32 i = 0; i < scrbuf_width*scrbuf_height; i++)
|
||||
{
|
||||
for (y = 0; y < vid.height; y += scrbuf_downscaleamt)
|
||||
{
|
||||
dest = y*vid.width + x;
|
||||
src = dest*3;
|
||||
|
||||
r = (UINT8)linear[src];
|
||||
g = (UINT8)linear[src + 1];
|
||||
b = (UINT8)linear[src + 2];
|
||||
scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b);
|
||||
src += (3 * scrbuf_downscaleamt);
|
||||
dest += scrbuf_downscaleamt;
|
||||
}
|
||||
UINT8 r = *linear++;
|
||||
UINT8 g = *linear++;
|
||||
UINT8 b = *linear++;
|
||||
*scr++ = GetColorLUTDirect(&gif_colorlookup, r, g, b);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -548,8 +524,8 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
|
|||
static void GIF_framewrite(void)
|
||||
{
|
||||
UINT8 *p;
|
||||
UINT8 *base_screen = gif_screens[0].pixels;
|
||||
UINT8 *movie_screen = gif_screens[1].pixels;
|
||||
UINT8 *base_screen = scrbuf_screens;
|
||||
UINT8 *movie_screen = scrbuf_screens;
|
||||
INT32 blitx, blity, blitw, blith;
|
||||
boolean palchanged;
|
||||
|
||||
|
|
@ -569,48 +545,35 @@ static void GIF_framewrite(void)
|
|||
else
|
||||
palchanged = false;
|
||||
|
||||
// select your framebuffer
|
||||
if (gif_frames & 1)
|
||||
base_screen += scrbuf_width*scrbuf_height;
|
||||
else
|
||||
movie_screen += scrbuf_width*scrbuf_height;
|
||||
|
||||
// blit to temp screen
|
||||
if (rendermode == render_soft)
|
||||
I_ReadScreen(movie_screen, scrbuf_downscaleamt);
|
||||
#ifdef HWRENDER
|
||||
else if (rendermode == render_opengl)
|
||||
{
|
||||
UINT8 *linear = HWR_GetScreenshot(scrbuf_downscaleamt);
|
||||
GIF_rgbconvert(linear, movie_screen);
|
||||
//free(linear); // Allocated 'statically', no need to free now
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compare image data (for optimizing GIF)
|
||||
// If the palette has changed, the entire frame is considered to be different.
|
||||
if (gif_optimize && gif_frames > 0 && (!palchanged))
|
||||
{
|
||||
// before blit movie_screen points to last frame, cur_screen points to this frame
|
||||
UINT8 *cur_screen = base_screen;
|
||||
GIF_optimizeregion(cur_screen, movie_screen, &blitx, &blity, &blitw, &blith);
|
||||
|
||||
// blit to temp screen
|
||||
if (rendermode == render_soft)
|
||||
I_ReadScreen(movie_screen);
|
||||
#ifdef HWRENDER
|
||||
else if (rendermode == render_opengl)
|
||||
{
|
||||
UINT8 *linear = HWR_GetScreenshot();
|
||||
GIF_rgbconvert(linear, movie_screen);
|
||||
//free(linear); // Allocated 'statically', no need to free now
|
||||
}
|
||||
#endif
|
||||
GIF_optimizeregion(base_screen, movie_screen, &blitx, &blity, &blitw, &blith);
|
||||
}
|
||||
else
|
||||
{
|
||||
blitx = blity = 0;
|
||||
blitw = vid.width;
|
||||
blith = vid.height;
|
||||
|
||||
#ifdef HWRENDER
|
||||
// Copy the current OpenGL frame into the base screen
|
||||
if (rendermode == render_opengl)
|
||||
{
|
||||
UINT8 *linear = HWR_GetScreenshot();
|
||||
GIF_rgbconvert(linear, base_screen);
|
||||
//free(linear); // Allocated 'statically', no need to free now
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy the first frame into the movie screen
|
||||
// OpenGL already does the same above.
|
||||
if (gif_frames == 0 && rendermode == render_soft)
|
||||
I_ReadScreen(movie_screen);
|
||||
|
||||
movie_screen = base_screen;
|
||||
blitw = scrbuf_width;
|
||||
blith = scrbuf_height;
|
||||
}
|
||||
|
||||
// screen regions are handled in GIF_lzw
|
||||
|
|
@ -654,20 +617,11 @@ static void GIF_framewrite(void)
|
|||
WRITEUINT8(p, 0);
|
||||
WRITEUINT8(p, 0); // end of GCE
|
||||
|
||||
if (scrbuf_downscaleamt > 1)
|
||||
{
|
||||
// Ensure our downscaled blitx/y starts and ends on a pixel.
|
||||
blitx -= (blitx % scrbuf_downscaleamt);
|
||||
blity -= (blity % scrbuf_downscaleamt);
|
||||
blitw = ((blitw + (scrbuf_downscaleamt - 1)) / scrbuf_downscaleamt) * scrbuf_downscaleamt;
|
||||
blith = ((blith + (scrbuf_downscaleamt - 1)) / scrbuf_downscaleamt) * scrbuf_downscaleamt;
|
||||
}
|
||||
|
||||
WRITEUINT8(p, 0x2C);
|
||||
WRITEUINT16(p, (UINT16)(blitx / scrbuf_downscaleamt));
|
||||
WRITEUINT16(p, (UINT16)(blity / scrbuf_downscaleamt));
|
||||
WRITEUINT16(p, (UINT16)(blitw / scrbuf_downscaleamt));
|
||||
WRITEUINT16(p, (UINT16)(blith / scrbuf_downscaleamt));
|
||||
WRITEUINT16(p, (UINT16)blitx);
|
||||
WRITEUINT16(p, (UINT16)blity);
|
||||
WRITEUINT16(p, (UINT16)blitw);
|
||||
WRITEUINT16(p, (UINT16)blith);
|
||||
|
||||
if (!gif_localcolortable)
|
||||
WRITEUINT8(p, 0); // no local table of colors
|
||||
|
|
@ -683,8 +637,8 @@ static void GIF_framewrite(void)
|
|||
WRITEUINT8(p, 0); // They are equal, no Local Color Table needed.
|
||||
}
|
||||
|
||||
scrbuf_pos = movie_screen + blitx + (blity * vid.width);
|
||||
scrbuf_writeend = scrbuf_pos + (blitw - 1) + ((blith - 1) * vid.width);
|
||||
scrbuf_pos = movie_screen + blitx + (blity * scrbuf_width);
|
||||
scrbuf_writeend = scrbuf_pos + (blitw - 1) + ((blith - 1) * scrbuf_width);
|
||||
|
||||
if (!gifbwr_buf)
|
||||
gifbwr_buf = Z_Malloc(256, PU_STATIC, NULL);
|
||||
|
|
@ -694,8 +648,8 @@ static void GIF_framewrite(void)
|
|||
giflzw_workingCode = UINT16_MAX;
|
||||
WRITEUINT8(p, gifbwr_bits_min - 1);
|
||||
|
||||
startline = (scrbuf_pos - movie_screen) / vid.width;
|
||||
scrbuf_linebegin = movie_screen + (startline * vid.width) + blitx;
|
||||
startline = (scrbuf_pos - movie_screen) / scrbuf_width;
|
||||
scrbuf_linebegin = movie_screen + (startline * scrbuf_width) + blitx;
|
||||
scrbuf_lineend = scrbuf_linebegin + blitw;
|
||||
|
||||
//prewrite a table clear
|
||||
|
|
@ -760,55 +714,11 @@ INT32 GIF_open(const char *filename)
|
|||
|
||||
static void GIF_checkscreens(void)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(gif_screens) / sizeof(gif_screens[0]); i++)
|
||||
{
|
||||
if (rendermode == render_soft)
|
||||
{
|
||||
if (gif_screens[i].owns_pixels)
|
||||
{
|
||||
Z_Free(gif_screens[i].pixels);
|
||||
gif_screens[i].owns_pixels = false;
|
||||
}
|
||||
if (scrbuf_screens == NULL)
|
||||
Z_Malloc(scrbuf_width * scrbuf_height * 2, PU_STATIC, &scrbuf_screens);
|
||||
|
||||
gif_screens[i].size = 0;
|
||||
|
||||
if (i == 1)
|
||||
gif_screens[i].pixels = screens[2];
|
||||
else
|
||||
gif_screens[i].pixels = screens[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t sz = vid.width * vid.height * vid.bpp;
|
||||
|
||||
if (!gif_screens[i].owns_pixels)
|
||||
{
|
||||
gif_screens[i].size = sz;
|
||||
gif_screens[i].pixels = Z_Malloc(gif_screens[i].size, PU_STATIC, NULL);
|
||||
gif_screens[i].owns_pixels = true;
|
||||
}
|
||||
else if (gif_screens[i].size != sz)
|
||||
{
|
||||
gif_screens[i].size = sz;
|
||||
gif_screens[i].pixels = Z_Realloc(gif_screens[i].pixels, gif_screens[i].size, PU_STATIC, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GIF_freescreens(void)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(gif_screens) / sizeof(gif_screens[0]); i++)
|
||||
{
|
||||
if (gif_screens[i].owns_pixels)
|
||||
{
|
||||
Z_Free(gif_screens[i].pixels);
|
||||
gif_screens[i].owns_pixels = false;
|
||||
}
|
||||
|
||||
gif_screens[i].size = 0;
|
||||
gif_screens[i].pixels = NULL;
|
||||
}
|
||||
I_Assert(scrbuf_width == vid.width / scrbuf_downscaleamt);
|
||||
I_Assert(scrbuf_height == vid.height / scrbuf_downscaleamt);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -847,7 +757,7 @@ INT32 GIF_close(void)
|
|||
Z_Free(giflzw_hashTable);
|
||||
giflzw_hashTable = NULL;
|
||||
|
||||
GIF_freescreens();
|
||||
Z_Free(scrbuf_screens);
|
||||
|
||||
CONS_Printf(M_GetText("Animated gif closed; wrote %d frames\n"), gif_frames);
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -1303,7 +1303,7 @@ void M_SaveFrame(void)
|
|||
{
|
||||
// munge planar buffer to linear
|
||||
linear = screens[2];
|
||||
I_ReadScreen(linear);
|
||||
I_ReadScreen(linear, 1);
|
||||
}
|
||||
#ifdef HWRENDER
|
||||
else
|
||||
|
|
@ -1576,6 +1576,7 @@ void M_DoScreenShot(void)
|
|||
char pathname[MAX_WADPATH];
|
||||
boolean ret = false;
|
||||
UINT8 *linear = NULL;
|
||||
UINT8 *palette;
|
||||
|
||||
// Don't take multiple screenshots, obviously
|
||||
takescreenshot = false;
|
||||
|
|
@ -1608,30 +1609,30 @@ void M_DoScreenShot(void)
|
|||
freename = Newsnapshotfile(pathname,"tga");
|
||||
#endif
|
||||
|
||||
if (!freename)
|
||||
goto failure;
|
||||
|
||||
if (rendermode == render_soft)
|
||||
{
|
||||
// munge planar buffer to linear
|
||||
linear = screens[2];
|
||||
I_ReadScreen(linear);
|
||||
}
|
||||
|
||||
if (!freename)
|
||||
goto failure;
|
||||
|
||||
// save the pcx file
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl)
|
||||
ret = HWR_Screenshot(va(pandf,pathname,freename));
|
||||
else
|
||||
#endif
|
||||
{
|
||||
I_ReadScreen(linear, 1);
|
||||
M_CreateScreenShotPalette();
|
||||
#ifdef USE_PNG
|
||||
ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
|
||||
#else
|
||||
ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
|
||||
#endif
|
||||
palette = screenshot_palette;
|
||||
}
|
||||
#ifdef HWRENDER
|
||||
else if (rendermode == render_opengl)
|
||||
{
|
||||
linear = HWR_GetScreenshot(1);
|
||||
palette = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_PNG
|
||||
ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, palette);
|
||||
#else
|
||||
ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, palette);
|
||||
#endif
|
||||
|
||||
failure:
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -322,7 +322,11 @@ void SCR_SetMode(void)
|
|||
|
||||
// Set the video mode in the video interface.
|
||||
if (setmodeneeded)
|
||||
{
|
||||
if (vid.modenum != setmodeneeded - 1)
|
||||
M_StopMovie(); // nope, cry about it
|
||||
VID_SetMode(setmodeneeded - 1);
|
||||
}
|
||||
|
||||
V_SetPalette(0);
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ void *hwSym(const char *funcName,void *handle)
|
|||
GETFUNC(SetTexture);
|
||||
GETFUNC(UpdateTexture);
|
||||
GETFUNC(DeleteTexture);
|
||||
GETFUNC(ReadRect);
|
||||
GETFUNC(ReadScreenFinalTexture);
|
||||
GETFUNC(GClipRect);
|
||||
GETFUNC(ClearMipMapCache);
|
||||
GETFUNC(SetSpecialState);
|
||||
|
|
|
|||
|
|
@ -1324,14 +1324,24 @@ void I_UpdateNoVsync(void)
|
|||
//
|
||||
// I_ReadScreen
|
||||
//
|
||||
void I_ReadScreen(UINT8 *scr)
|
||||
void I_ReadScreen(UINT8 * restrict scr, INT32 scale)
|
||||
{
|
||||
if (rendermode != render_soft)
|
||||
I_Error ("I_ReadScreen: called while in non-software mode");
|
||||
else
|
||||
else if (scale == 1)
|
||||
VID_BlitLinearScreen(screens[0], scr,
|
||||
vid.width*vid.bpp, vid.height,
|
||||
vid.rowbytes, vid.rowbytes);
|
||||
else
|
||||
{
|
||||
UINT8 * restrict source = screens[0];
|
||||
INT32 w = vid.width/scale*scale, h = vid.height/scale*scale;
|
||||
|
||||
// size_t saves a lea + movsxd over INT32. mind your types!
|
||||
for (size_t y = 0; y < h; y += scale)
|
||||
for (size_t x = 0; x < w; x += scale)
|
||||
*scr++ = source[y*vid.width + x];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1728,7 +1738,7 @@ static void Impl_InitOpenGL(void)
|
|||
*(void**)&HWD.pfnSetTexture = hwSym("SetTexture",NULL);
|
||||
*(void**)&HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL);
|
||||
*(void**)&HWD.pfnDeleteTexture = hwSym("DeleteTexture",NULL);
|
||||
*(void**)&HWD.pfnReadRect = hwSym("ReadRect",NULL);
|
||||
*(void**)&HWD.pfnReadScreenFinalTexture=hwSym("ReadScreenFinalTexture",NULL);
|
||||
*(void**)&HWD.pfnGClipRect = hwSym("GClipRect",NULL);
|
||||
*(void**)&HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL);
|
||||
*(void**)&HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL);
|
||||
|
|
|
|||
Loading…
Reference in a new issue