diff options
Diffstat (limited to 'src/screenshot.cpp')
-rw-r--r-- | src/screenshot.cpp | 111 |
1 files changed, 70 insertions, 41 deletions
diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 738f28a68..9beac53d5 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -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() |