2017-02-25 08:15:36 +00:00
|
|
|
#include "compat.h"
|
2016-06-21 00:33:19 +00:00
|
|
|
#include "build.h"
|
|
|
|
#include "editor.h"
|
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
#include "pngwrite.h"
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
#include "vfs.h"
|
|
|
|
|
2016-06-21 00:33:19 +00:00
|
|
|
//
|
|
|
|
// screencapture
|
|
|
|
//
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_FILE OutputFileCounter::opennextfile(char *fn, char *zeros)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_FILE file;
|
2016-06-21 00:33:19 +00:00
|
|
|
|
|
|
|
do // JBF 2004022: So we don't overwrite existing screenshots
|
|
|
|
{
|
2017-12-01 06:19:19 +00:00
|
|
|
if (count > 9999) return nullptr;
|
|
|
|
|
|
|
|
zeros[0] = ((count/1000)%10)+'0';
|
|
|
|
zeros[1] = ((count/100)%10)+'0';
|
|
|
|
zeros[2] = ((count/10)%10)+'0';
|
|
|
|
zeros[3] = (count%10)+'0';
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
if ((file = buildvfs_fopen_read(fn)) == nullptr) break;
|
|
|
|
buildvfs_fclose(file);
|
2017-12-01 06:19:19 +00:00
|
|
|
count++;
|
2016-06-21 00:33:19 +00:00
|
|
|
} while (1);
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
return buildvfs_fopen_write(fn);
|
2017-12-01 06:19:19 +00:00
|
|
|
}
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_FILE OutputFileCounter::opennextfile_withext(char *fn, const char *ext)
|
2017-12-01 06:19:19 +00:00
|
|
|
{
|
|
|
|
char *dot = strrchr(fn, '.');
|
|
|
|
strcpy(dot+1, ext);
|
|
|
|
return opennextfile(fn, dot-4);
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 06:19:19 +00:00
|
|
|
static OutputFileCounter capturecounter;
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
static void screencapture_end(char *fn, buildvfs_FILE * filptr)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fclose(*filptr);
|
2017-07-18 20:53:00 +00:00
|
|
|
OSD_Printf("Saved screenshot to %s\n", fn);
|
|
|
|
Bfree(fn);
|
2017-12-01 06:19:19 +00:00
|
|
|
capturecounter.count++;
|
2017-07-18 20:53:00 +00:00
|
|
|
}
|
|
|
|
|
2016-06-21 00:33:19 +00:00
|
|
|
# ifdef USE_OPENGL
|
2018-04-12 21:03:12 +00:00
|
|
|
# define HICOLOR (videoGetRenderMode() >= REND_POLYMOST && in3dmode())
|
2016-06-21 00:33:19 +00:00
|
|
|
# else
|
|
|
|
# define HICOLOR 0
|
|
|
|
# endif
|
2016-09-16 21:55:36 +00:00
|
|
|
|
2018-04-12 21:03:47 +00:00
|
|
|
int videoCaptureScreen(const char *filename, char inverseit)
|
2017-07-18 20:53:00 +00:00
|
|
|
{
|
|
|
|
char *fn = Xstrdup(filename);
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_FILE fp = capturecounter.opennextfile_withext(fn, "png");
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-12-01 06:19:19 +00:00
|
|
|
if (fp == nullptr)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
Bfree(fn);
|
2017-12-01 06:19:19 +00:00
|
|
|
return -1;
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
uint8_t * const imgBuf = (uint8_t *) Xmalloc(xdim * ydim * (HICOLOR ? 3 : 1));
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2018-04-12 21:02:51 +00:00
|
|
|
videoBeginDrawing(); //{{{
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
#ifdef USE_OPENGL
|
|
|
|
if (HICOLOR)
|
|
|
|
{
|
2018-02-16 06:38:21 +00:00
|
|
|
glReadPixels(0, 0, xdim, ydim, GL_RGB, GL_UNSIGNED_BYTE, imgBuf);
|
2017-07-18 20:53:00 +00:00
|
|
|
int const bytesPerLine = xdim * 3;
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
if (inverseit)
|
|
|
|
{
|
2019-05-19 03:56:13 +00:00
|
|
|
for (int i=0, j = ydim * bytesPerLine; i<j; i+=3)
|
2017-07-18 20:53:00 +00:00
|
|
|
swapchar(&imgBuf[i], &imgBuf[i+2]);
|
|
|
|
}
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
// flip rows
|
|
|
|
uint8_t* rowBuf = (uint8_t *) Xmalloc(bytesPerLine);
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
for (int i = 0, numRows = ydim >> 1; i < numRows; ++i)
|
|
|
|
{
|
|
|
|
Bmemcpy(rowBuf, imgBuf + i * bytesPerLine, bytesPerLine);
|
|
|
|
Bmemcpy(imgBuf + i * bytesPerLine, imgBuf + (ydim - i - 1) * bytesPerLine, bytesPerLine);
|
|
|
|
Bmemcpy(imgBuf + (ydim - i - 1) * bytesPerLine, rowBuf, bytesPerLine);
|
|
|
|
}
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
Bfree(rowBuf);
|
|
|
|
}
|
|
|
|
else
|
2016-06-21 00:33:19 +00:00
|
|
|
#endif
|
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
struct {
|
|
|
|
uint8_t r, g, b;
|
|
|
|
} palette[256];
|
|
|
|
|
2016-09-16 21:55:36 +00:00
|
|
|
if (inverseit)
|
|
|
|
{
|
|
|
|
for (bssize_t i = 0; i < 256; ++i)
|
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
palette[i].r = 255 - curpalettefaded[i].r;
|
|
|
|
palette[i].g = 255 - curpalettefaded[i].g;
|
|
|
|
palette[i].b = 255 - curpalettefaded[i].b;
|
2016-09-16 21:55:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
2016-09-16 21:55:36 +00:00
|
|
|
for (bssize_t i = 0; i < 256; ++i)
|
2017-07-18 20:53:00 +00:00
|
|
|
Bmemcpy(&palette[i], &curpalettefaded[i], sizeof(palette[0]));
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
png_set_pal((uint8_t *)palette, 256);
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
for (int i = 0; i < ydim; ++i)
|
|
|
|
Bmemcpy(imgBuf + i * xdim, (uint8_t *)frameplace + ylookup[i], xdim);
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2018-04-12 21:02:51 +00:00
|
|
|
videoEndDrawing(); //}}}
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
png_set_text("Software", osd->version.buf);
|
|
|
|
png_write(fp, xdim, ydim, HICOLOR ? PNG_TRUECOLOR : PNG_INDEXED, imgBuf);
|
|
|
|
Bfree(imgBuf);
|
|
|
|
screencapture_end(fn, &fp);
|
2016-06-21 00:33:19 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-12 21:03:47 +00:00
|
|
|
int videoCaptureScreenTGA(const char *filename, char inverseit)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
|
|
|
int32_t i;
|
2017-07-18 20:53:00 +00:00
|
|
|
char head[18] = { 0,1,1,0,0,0,1,24,0,0,0,0,0/*wlo*/,0/*whi*/,0/*hlo*/,0/*hhi*/,8,0 };
|
2016-06-21 00:33:19 +00:00
|
|
|
//char palette[4*256];
|
|
|
|
char *fn = Xstrdup(filename);
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_FILE fil = capturecounter.opennextfile_withext(fn, "tga");
|
2017-12-01 06:19:19 +00:00
|
|
|
if (fil == nullptr)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
|
|
|
Bfree(fn);
|
2017-12-01 06:19:19 +00:00
|
|
|
return -1;
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
#ifdef USE_OPENGL
|
|
|
|
if (HICOLOR)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
|
|
|
head[1] = 0; // no colourmap
|
|
|
|
head[2] = 2; // uncompressed truecolour
|
|
|
|
head[3] = 0; // (low) first colourmap index
|
|
|
|
head[4] = 0; // (high) first colourmap index
|
|
|
|
head[5] = 0; // (low) number colourmap entries
|
|
|
|
head[6] = 0; // (high) number colourmap entries
|
|
|
|
head[7] = 0; // colourmap entry size
|
|
|
|
head[16] = 24; // 24 bits per pixel
|
|
|
|
}
|
2017-07-18 20:53:00 +00:00
|
|
|
#endif
|
2016-06-21 00:33:19 +00:00
|
|
|
|
|
|
|
head[12] = xdim & 0xff;
|
|
|
|
head[13] = (xdim >> 8) & 0xff;
|
|
|
|
head[14] = ydim & 0xff;
|
|
|
|
head[15] = (ydim >> 8) & 0xff;
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fwrite(head, 18, 1, fil);
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-29 20:39:46 +00:00
|
|
|
// palette first
|
2017-07-18 20:53:00 +00:00
|
|
|
#ifdef USE_OPENGL
|
|
|
|
if (!HICOLOR)
|
|
|
|
#endif
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
if (inverseit)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
for (i=0; i<256; i++)
|
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fputc(255 - curpalettefaded[i].b, fil);
|
|
|
|
buildvfs_fputc(255 - curpalettefaded[i].g, fil);
|
|
|
|
buildvfs_fputc(255 - curpalettefaded[i].r, fil);
|
2017-07-18 20:53:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i=0; i<256; i++)
|
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fputc(curpalettefaded[i].b, fil);
|
|
|
|
buildvfs_fputc(curpalettefaded[i].g, fil);
|
|
|
|
buildvfs_fputc(curpalettefaded[i].r, fil);
|
2017-07-18 20:53:00 +00:00
|
|
|
}
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 21:02:51 +00:00
|
|
|
videoBeginDrawing(); //{{{
|
2017-07-18 20:53:00 +00:00
|
|
|
|
2016-06-21 00:33:19 +00:00
|
|
|
# ifdef USE_OPENGL
|
2017-07-18 20:53:00 +00:00
|
|
|
if (HICOLOR)
|
2016-06-21 00:33:19 +00:00
|
|
|
{
|
|
|
|
// 24bit
|
2017-07-18 20:53:00 +00:00
|
|
|
int const size = xdim * ydim * 3;
|
|
|
|
uint8_t *inversebuf = (uint8_t *) Xmalloc(size);
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2018-02-16 06:38:21 +00:00
|
|
|
glReadPixels(0, 0, xdim, ydim, GL_RGB, GL_UNSIGNED_BYTE, inversebuf);
|
2017-07-29 20:39:46 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
for (i = 0; i < size; i += 3)
|
|
|
|
swapchar(&inversebuf[i], &inversebuf[i + 2]);
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fwrite(inversebuf, xdim*ydim, 3, fil);
|
2016-06-21 00:33:19 +00:00
|
|
|
Bfree(inversebuf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
# endif
|
|
|
|
{
|
2017-07-18 20:53:00 +00:00
|
|
|
char * const ptr = (char *) frameplace;
|
|
|
|
|
|
|
|
for (i = ydim-1; i >= 0; i--)
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fwrite(ptr + i * bytesperline, xdim, 1, fil);
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2018-04-12 21:02:51 +00:00
|
|
|
videoEndDrawing(); //}}}
|
2016-06-21 00:33:19 +00:00
|
|
|
|
2017-07-18 20:53:00 +00:00
|
|
|
screencapture_end(fn, &fil);
|
|
|
|
|
2016-06-21 00:34:41 +00:00
|
|
|
return 0;
|
2016-06-21 00:33:19 +00:00
|
|
|
}
|
2017-07-18 20:53:00 +00:00
|
|
|
#undef HICOLOR
|
2016-06-21 00:33:19 +00:00
|
|
|
|