(svn r10121) -Codechange: split renderer from rest of code; no longer any code directly accesses the video-buffer
-Add: added NULL blitter and renderer, which are always used for -vnull -Add: dedicated driver doesn't blit nor render by default. Can be overruled by user. (-D -b 8bpp-optimized) -Remove: removed CTRL+D from win32, which is incompatible with above -Add: extended screenshot support for PNG and BMP -Codechange: remove all hardcoded 8bpp references and replace them with more dynamic ones -Codechange: minor stuff in blitters
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "variables.h"
|
||||
#include "date.h"
|
||||
#include "helpers.hpp"
|
||||
#include "blitter/blitter.hpp"
|
||||
#include "fileio.h"
|
||||
|
||||
char _screenshot_format_name[8];
|
||||
@@ -22,7 +23,7 @@ uint _cur_screenshot_format;
|
||||
ScreenshotType current_screenshot_type;
|
||||
|
||||
/* called by the ScreenShot proc to generate screenshot lines. */
|
||||
typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n);
|
||||
typedef void ScreenshotCallback(void *userdata, void *buf, uint y, uint pitch, uint n);
|
||||
typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
|
||||
|
||||
struct ScreenshotFormat {
|
||||
@@ -72,10 +73,11 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
FILE *f;
|
||||
uint i, padw;
|
||||
uint n, maxlines;
|
||||
uint pal_size = 0;
|
||||
uint bpp = pixelformat / 8;
|
||||
|
||||
/* only implemented for 8bit images so far. */
|
||||
if (pixelformat != 8)
|
||||
return false;
|
||||
/* only implemented for 8bit and 32bit images so far. */
|
||||
if (pixelformat != 8 && pixelformat != 32) return false;
|
||||
|
||||
f = fopen(name, "wb");
|
||||
if (f == NULL) return false;
|
||||
@@ -83,18 +85,20 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
/* each scanline must be aligned on a 32bit boundary */
|
||||
padw = ALIGN(w, 4);
|
||||
|
||||
if (pixelformat == 8) pal_size = sizeof(RgbQuad) * 256;
|
||||
|
||||
/* setup the file header */
|
||||
bfh.type = TO_LE16('MB');
|
||||
bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h);
|
||||
bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + pal_size + padw * h * bpp);
|
||||
bfh.reserved = 0;
|
||||
bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256);
|
||||
bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + pal_size);
|
||||
|
||||
/* setup the info header */
|
||||
bih.size = TO_LE32(sizeof(BitmapInfoHeader));
|
||||
bih.width = TO_LE32(w);
|
||||
bih.height = TO_LE32(h);
|
||||
bih.planes = TO_LE16(1);
|
||||
bih.bitcount = TO_LE16(8);
|
||||
bih.bitcount = TO_LE16(pixelformat);
|
||||
bih.compression = 0;
|
||||
bih.sizeimage = 0;
|
||||
bih.xpels = 0;
|
||||
@@ -102,24 +106,26 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
bih.clrused = 0;
|
||||
bih.clrimp = 0;
|
||||
|
||||
/* convert the palette to the windows format */
|
||||
for (i = 0; i != 256; i++) {
|
||||
rq[i].red = palette[i].r;
|
||||
rq[i].green = palette[i].g;
|
||||
rq[i].blue = palette[i].b;
|
||||
rq[i].reserved = 0;
|
||||
if (pixelformat == 8) {
|
||||
/* convert the palette to the windows format */
|
||||
for (i = 0; i != 256; i++) {
|
||||
rq[i].red = palette[i].r;
|
||||
rq[i].green = palette[i].g;
|
||||
rq[i].blue = palette[i].b;
|
||||
rq[i].reserved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* write file header and info header and palette */
|
||||
if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
|
||||
if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
|
||||
if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
|
||||
if (pixelformat == 8) if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
|
||||
|
||||
/* use by default 64k temp memory */
|
||||
maxlines = clamp(65536 / padw, 16, 128);
|
||||
|
||||
/* now generate the bitmap bits */
|
||||
Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time.
|
||||
void *buff = MallocT<uint8>(padw * maxlines * bpp); // by default generate 128 lines at a time.
|
||||
if (buff == NULL) {
|
||||
fclose(f);
|
||||
return false;
|
||||
@@ -137,7 +143,7 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
|
||||
/* write each line */
|
||||
while (n)
|
||||
if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) {
|
||||
if (fwrite((uint8 *)buff + (--n) * padw * bpp, padw * bpp, 1, f) != 1) {
|
||||
free(buff);
|
||||
fclose(f);
|
||||
return false;
|
||||
@@ -173,12 +179,12 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
FILE *f;
|
||||
uint i, y, n;
|
||||
uint maxlines;
|
||||
uint bpp = pixelformat / 8;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
|
||||
/* only implemented for 8bit images so far. */
|
||||
if (pixelformat != 8)
|
||||
return false;
|
||||
/* only implemented for 8bit and 32bit images so far. */
|
||||
if (pixelformat != 8 && pixelformat != 32) return false;
|
||||
|
||||
f = fopen(name, "wb");
|
||||
if (f == NULL) return false;
|
||||
@@ -207,31 +213,53 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
|
||||
png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE,
|
||||
png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
/* convert the palette to the .PNG format. */
|
||||
for (i = 0; i != 256; i++) {
|
||||
rq[i].red = palette[i].r;
|
||||
rq[i].green = palette[i].g;
|
||||
rq[i].blue = palette[i].b;
|
||||
if (pixelformat == 8) {
|
||||
/* convert the palette to the .PNG format. */
|
||||
for (i = 0; i != 256; i++) {
|
||||
rq[i].red = palette[i].r;
|
||||
rq[i].green = palette[i].g;
|
||||
rq[i].blue = palette[i].b;
|
||||
}
|
||||
|
||||
png_set_PLTE(png_ptr, info_ptr, rq, 256);
|
||||
}
|
||||
|
||||
png_set_PLTE(png_ptr, info_ptr, rq, 256);
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
png_set_flush(png_ptr, 512);
|
||||
|
||||
if (pixelformat == 32) {
|
||||
png_color_8 sig_bit;
|
||||
|
||||
/* Save exact color/alpha resolution */
|
||||
sig_bit.alpha = 0;
|
||||
sig_bit.blue = 8;
|
||||
sig_bit.green = 8;
|
||||
sig_bit.red = 8;
|
||||
sig_bit.gray = 8;
|
||||
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
|
||||
|
||||
#ifdef TTD_LITTLE_ENDIAN
|
||||
png_set_bgr(png_ptr);
|
||||
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
|
||||
#else
|
||||
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* use by default 64k temp memory */
|
||||
maxlines = clamp(65536 / w, 16, 128);
|
||||
|
||||
/* now generate the bitmap bits */
|
||||
Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
|
||||
void *buff = MallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time.
|
||||
if (buff == NULL) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
|
||||
memset(buff, 0, w * maxlines * bpp);
|
||||
|
||||
y = 0;
|
||||
do {
|
||||
@@ -244,7 +272,7 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
|
||||
/* write them to png */
|
||||
for (i = 0; i != n; i++)
|
||||
png_write_row(png_ptr, buff + i * w);
|
||||
png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
|
||||
} while (y != h);
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
@@ -288,6 +316,10 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
PcxHeader pcx;
|
||||
bool success;
|
||||
|
||||
if (pixelformat == 32) {
|
||||
DEBUG(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick an other format.");
|
||||
return false;
|
||||
}
|
||||
if (pixelformat != 8 || w == 0)
|
||||
return false;
|
||||
|
||||
@@ -321,7 +353,7 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
maxlines = clamp(65536 / w, 16, 128);
|
||||
|
||||
/* now generate the bitmap bits */
|
||||
Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
|
||||
uint8 *buff = MallocT<uint8>(w * maxlines); // by default generate 128 lines at a time.
|
||||
if (buff == NULL) {
|
||||
fclose(f);
|
||||
return false;
|
||||
@@ -340,14 +372,14 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
||||
|
||||
/* write them to pcx */
|
||||
for (i = 0; i != n; i++) {
|
||||
const Pixel* bufp = buff + i * w;
|
||||
const uint8 *bufp = buff + i * w;
|
||||
byte runchar = bufp[0];
|
||||
uint runcount = 1;
|
||||
uint j;
|
||||
|
||||
/* for each pixel... */
|
||||
for (j = 1; j < w; j++) {
|
||||
Pixel ch = bufp[j];
|
||||
uint8 ch = bufp[j];
|
||||
|
||||
if (ch != runchar || runcount >= 0x3f) {
|
||||
if (runcount > 1 || (runchar & 0xC0) == 0xC0)
|
||||
@@ -447,17 +479,14 @@ void SetScreenshotFormat(int i)
|
||||
}
|
||||
|
||||
/* screenshot generator that dumps the current video buffer */
|
||||
static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
|
||||
static void CurrentScreenCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
|
||||
{
|
||||
for (; n > 0; --n) {
|
||||
memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width * sizeof(Pixel));
|
||||
++y;
|
||||
buf += pitch;
|
||||
}
|
||||
void *src = _screen.renderer->MoveTo(_screen.dst_ptr, 0, y);
|
||||
_screen.renderer->CopyToBuffer(src, buf, _screen.width, n, pitch);
|
||||
}
|
||||
|
||||
/* generate a large piece of the world */
|
||||
static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
|
||||
static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
|
||||
{
|
||||
ViewPort *vp = (ViewPort *)userdata;
|
||||
DrawPixelInfo dpi, *old_dpi;
|
||||
@@ -534,7 +563,7 @@ bool IsScreenshotRequested()
|
||||
static bool MakeSmallScreenshot()
|
||||
{
|
||||
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
|
||||
return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, 8, _cur_palette);
|
||||
return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
|
||||
}
|
||||
|
||||
static bool MakeWorldScreenshot()
|
||||
@@ -553,7 +582,7 @@ static bool MakeWorldScreenshot()
|
||||
vp.height = vp.virtual_height;
|
||||
|
||||
sf = _screenshot_formats + _cur_screenshot_format;
|
||||
return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, 8, _cur_palette);
|
||||
return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
|
||||
}
|
||||
|
||||
bool MakeScreenshot()
|
||||
|
Reference in New Issue
Block a user