src/screenshot.cpp
branchgamebalance
changeset 9913 e79cd19772dd
parent 9911 0b8b245a2391
--- a/src/screenshot.cpp	Wed Jun 13 12:05:56 2007 +0000
+++ b/src/screenshot.cpp	Tue Jun 19 07:21:01 2007 +0000
@@ -8,12 +8,16 @@
 #include "table/strings.h"
 #include "gfx.h"
 #include "hal.h"
+#include "fileio.h"
 #include "viewport.h"
 #include "player.h"
 #include "screenshot.h"
 #include "variables.h"
 #include "date.h"
+#include "string.h"
 #include "helpers.hpp"
+#include "blitter/factory.hpp"
+#include "fileio.h"
 
 char _screenshot_format_name[8];
 uint _num_screenshot_formats;
@@ -21,7 +25,7 @@
 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 {
@@ -71,10 +75,11 @@
 	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;
@@ -82,18 +87,20 @@
 	/* 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;
@@ -101,24 +108,26 @@
 	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;
@@ -136,7 +145,7 @@
 
 		/* 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;
@@ -172,12 +181,12 @@
 	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;
@@ -206,31 +215,53 @@
 
 	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 {
@@ -243,7 +274,7 @@
 
 		/* 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);
@@ -287,6 +318,10 @@
 	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;
 
@@ -320,7 +355,7 @@
 	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;
@@ -339,14 +374,14 @@
 
 		/* 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)
@@ -446,17 +481,15 @@
 }
 
 /* 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;
-	}
+	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
+	void *src = blitter->MoveTo(_screen.dst_ptr, 0, y);
+	blitter->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;
@@ -491,12 +524,12 @@
 
 static char *MakeScreenshotName(const char *ext)
 {
-	static char filename[256];
-	char *base;
+	static char filename[MAX_PATH];
 	int serial;
+	size_t len;
 
 	if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_player == PLAYER_SPECTATOR) {
-		sprintf(_screenshot_name, "screenshot");
+		ttd_strlcpy(_screenshot_name, "screenshot", lengthof(_screenshot_name));
 	} else {
 		const Player* p = GetPlayer(_local_player);
 		SetDParam(0, p->name_1);
@@ -505,15 +538,16 @@
 		GetString(_screenshot_name, STR_4004, lastof(_screenshot_name));
 	}
 
-	base = strchr(_screenshot_name, 0);
-	base[0] = '.'; strcpy(base + 1, ext);
+	/* Add extension to screenshot file */
+	SanitizeFilename(_screenshot_name);
+	len = strlen(_screenshot_name);
+	snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, ".%s", ext);
 
-	serial = 0;
-	for (;;) {
-		snprintf(filename, sizeof(filename), "%s%s", _paths.personal_dir, _screenshot_name);
-		if (!FileExists(filename))
-			break;
-		sprintf(base, " #%d.%s", ++serial, ext);
+	for (serial = 1;; serial++) {
+		snprintf(filename, lengthof(filename), "%s%s", _personal_dir, _screenshot_name);
+		if (!FileExists(filename)) break;
+		/* If file exists try another one with same name, but just with a higher index */
+		snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, "#%d.%s", serial, ext);
 	}
 
 	return filename;
@@ -532,7 +566,7 @@
 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()
@@ -551,7 +585,7 @@
 	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()