src/screenshot.cpp
branchgamebalance
changeset 9913 e79cd19772dd
parent 9911 0b8b245a2391
equal deleted inserted replaced
9912:1ac8aac92385 9913:e79cd19772dd
     6 #include "functions.h"
     6 #include "functions.h"
     7 #include "strings.h"
     7 #include "strings.h"
     8 #include "table/strings.h"
     8 #include "table/strings.h"
     9 #include "gfx.h"
     9 #include "gfx.h"
    10 #include "hal.h"
    10 #include "hal.h"
       
    11 #include "fileio.h"
    11 #include "viewport.h"
    12 #include "viewport.h"
    12 #include "player.h"
    13 #include "player.h"
    13 #include "screenshot.h"
    14 #include "screenshot.h"
    14 #include "variables.h"
    15 #include "variables.h"
    15 #include "date.h"
    16 #include "date.h"
       
    17 #include "string.h"
    16 #include "helpers.hpp"
    18 #include "helpers.hpp"
       
    19 #include "blitter/factory.hpp"
       
    20 #include "fileio.h"
    17 
    21 
    18 char _screenshot_format_name[8];
    22 char _screenshot_format_name[8];
    19 uint _num_screenshot_formats;
    23 uint _num_screenshot_formats;
    20 uint _cur_screenshot_format;
    24 uint _cur_screenshot_format;
    21 ScreenshotType current_screenshot_type;
    25 ScreenshotType current_screenshot_type;
    22 
    26 
    23 /* called by the ScreenShot proc to generate screenshot lines. */
    27 /* called by the ScreenShot proc to generate screenshot lines. */
    24 typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n);
    28 typedef void ScreenshotCallback(void *userdata, void *buf, uint y, uint pitch, uint n);
    25 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
    29 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
    26 
    30 
    27 struct ScreenshotFormat {
    31 struct ScreenshotFormat {
    28 	const char *name;
    32 	const char *name;
    29 	const char *extension;
    33 	const char *extension;
    69 	BitmapInfoHeader bih;
    73 	BitmapInfoHeader bih;
    70 	RgbQuad rq[256];
    74 	RgbQuad rq[256];
    71 	FILE *f;
    75 	FILE *f;
    72 	uint i, padw;
    76 	uint i, padw;
    73 	uint n, maxlines;
    77 	uint n, maxlines;
    74 
    78 	uint pal_size = 0;
    75 	/* only implemented for 8bit images so far. */
    79 	uint bpp = pixelformat / 8;
    76 	if (pixelformat != 8)
    80 
    77 		return false;
    81 	/* only implemented for 8bit and 32bit images so far. */
       
    82 	if (pixelformat != 8 && pixelformat != 32) return false;
    78 
    83 
    79 	f = fopen(name, "wb");
    84 	f = fopen(name, "wb");
    80 	if (f == NULL) return false;
    85 	if (f == NULL) return false;
    81 
    86 
    82 	/* each scanline must be aligned on a 32bit boundary */
    87 	/* each scanline must be aligned on a 32bit boundary */
    83 	padw = ALIGN(w, 4);
    88 	padw = ALIGN(w, 4);
    84 
    89 
       
    90 	if (pixelformat == 8) pal_size = sizeof(RgbQuad) * 256;
       
    91 
    85 	/* setup the file header */
    92 	/* setup the file header */
    86 	bfh.type = TO_LE16('MB');
    93 	bfh.type = TO_LE16('MB');
    87 	bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h);
    94 	bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + pal_size + padw * h * bpp);
    88 	bfh.reserved = 0;
    95 	bfh.reserved = 0;
    89 	bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256);
    96 	bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + pal_size);
    90 
    97 
    91 	/* setup the info header */
    98 	/* setup the info header */
    92 	bih.size = TO_LE32(sizeof(BitmapInfoHeader));
    99 	bih.size = TO_LE32(sizeof(BitmapInfoHeader));
    93 	bih.width = TO_LE32(w);
   100 	bih.width = TO_LE32(w);
    94 	bih.height = TO_LE32(h);
   101 	bih.height = TO_LE32(h);
    95 	bih.planes = TO_LE16(1);
   102 	bih.planes = TO_LE16(1);
    96 	bih.bitcount = TO_LE16(8);
   103 	bih.bitcount = TO_LE16(pixelformat);
    97 	bih.compression = 0;
   104 	bih.compression = 0;
    98 	bih.sizeimage = 0;
   105 	bih.sizeimage = 0;
    99 	bih.xpels = 0;
   106 	bih.xpels = 0;
   100 	bih.ypels = 0;
   107 	bih.ypels = 0;
   101 	bih.clrused = 0;
   108 	bih.clrused = 0;
   102 	bih.clrimp = 0;
   109 	bih.clrimp = 0;
   103 
   110 
   104 	/* convert the palette to the windows format */
   111 	if (pixelformat == 8) {
   105 	for (i = 0; i != 256; i++) {
   112 		/* convert the palette to the windows format */
   106 		rq[i].red   = palette[i].r;
   113 		for (i = 0; i != 256; i++) {
   107 		rq[i].green = palette[i].g;
   114 			rq[i].red   = palette[i].r;
   108 		rq[i].blue  = palette[i].b;
   115 			rq[i].green = palette[i].g;
   109 		rq[i].reserved = 0;
   116 			rq[i].blue  = palette[i].b;
       
   117 			rq[i].reserved = 0;
       
   118 		}
   110 	}
   119 	}
   111 
   120 
   112 	/* write file header and info header and palette */
   121 	/* write file header and info header and palette */
   113 	if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
   122 	if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
   114 	if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
   123 	if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
   115 	if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
   124 	if (pixelformat == 8) if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
   116 
   125 
   117 	/* use by default 64k temp memory */
   126 	/* use by default 64k temp memory */
   118 	maxlines = clamp(65536 / padw, 16, 128);
   127 	maxlines = clamp(65536 / padw, 16, 128);
   119 
   128 
   120 	/* now generate the bitmap bits */
   129 	/* now generate the bitmap bits */
   121 	Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time.
   130 	void *buff = MallocT<uint8>(padw * maxlines * bpp); // by default generate 128 lines at a time.
   122 	if (buff == NULL) {
   131 	if (buff == NULL) {
   123 		fclose(f);
   132 		fclose(f);
   124 		return false;
   133 		return false;
   125 	}
   134 	}
   126 	memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0
   135 	memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0
   134 		/* render the pixels */
   143 		/* render the pixels */
   135 		callb(userdata, buff, h, padw, n);
   144 		callb(userdata, buff, h, padw, n);
   136 
   145 
   137 		/* write each line */
   146 		/* write each line */
   138 		while (n)
   147 		while (n)
   139 			if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) {
   148 			if (fwrite((uint8 *)buff + (--n) * padw * bpp, padw * bpp, 1, f) != 1) {
   140 				free(buff);
   149 				free(buff);
   141 				fclose(f);
   150 				fclose(f);
   142 				return false;
   151 				return false;
   143 			}
   152 			}
   144 	} while (h != 0);
   153 	} while (h != 0);
   170 {
   179 {
   171 	png_color rq[256];
   180 	png_color rq[256];
   172 	FILE *f;
   181 	FILE *f;
   173 	uint i, y, n;
   182 	uint i, y, n;
   174 	uint maxlines;
   183 	uint maxlines;
       
   184 	uint bpp = pixelformat / 8;
   175 	png_structp png_ptr;
   185 	png_structp png_ptr;
   176 	png_infop info_ptr;
   186 	png_infop info_ptr;
   177 
   187 
   178 	/* only implemented for 8bit images so far. */
   188 	/* only implemented for 8bit and 32bit images so far. */
   179 	if (pixelformat != 8)
   189 	if (pixelformat != 8 && pixelformat != 32) return false;
   180 		return false;
       
   181 
   190 
   182 	f = fopen(name, "wb");
   191 	f = fopen(name, "wb");
   183 	if (f == NULL) return false;
   192 	if (f == NULL) return false;
   184 
   193 
   185 	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (char *)name, png_my_error, png_my_warning);
   194 	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (char *)name, png_my_error, png_my_warning);
   204 
   213 
   205 	png_init_io(png_ptr, f);
   214 	png_init_io(png_ptr, f);
   206 
   215 
   207 	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
   216 	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
   208 
   217 
   209 	png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE,
   218 	png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
   210 		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   219 		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   211 
   220 
   212 	/* convert the palette to the .PNG format. */
   221 	if (pixelformat == 8) {
   213 	for (i = 0; i != 256; i++) {
   222 		/* convert the palette to the .PNG format. */
   214 		rq[i].red   = palette[i].r;
   223 		for (i = 0; i != 256; i++) {
   215 		rq[i].green = palette[i].g;
   224 			rq[i].red   = palette[i].r;
   216 		rq[i].blue  = palette[i].b;
   225 			rq[i].green = palette[i].g;
   217 	}
   226 			rq[i].blue  = palette[i].b;
   218 
   227 		}
   219 	png_set_PLTE(png_ptr, info_ptr, rq, 256);
   228 
       
   229 		png_set_PLTE(png_ptr, info_ptr, rq, 256);
       
   230 	}
       
   231 
   220 	png_write_info(png_ptr, info_ptr);
   232 	png_write_info(png_ptr, info_ptr);
   221 	png_set_flush(png_ptr, 512);
   233 	png_set_flush(png_ptr, 512);
   222 
   234 
       
   235 	if (pixelformat == 32) {
       
   236 		png_color_8 sig_bit;
       
   237 
       
   238 		/* Save exact color/alpha resolution */
       
   239 		sig_bit.alpha = 0;
       
   240 		sig_bit.blue  = 8;
       
   241 		sig_bit.green = 8;
       
   242 		sig_bit.red   = 8;
       
   243 		sig_bit.gray  = 8;
       
   244 		png_set_sBIT(png_ptr, info_ptr, &sig_bit);
       
   245 
       
   246 #ifdef TTD_LITTLE_ENDIAN
       
   247 		png_set_bgr(png_ptr);
       
   248 		png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
       
   249 #else
       
   250 		png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
       
   251 #endif
       
   252 	}
       
   253 
   223 	/* use by default 64k temp memory */
   254 	/* use by default 64k temp memory */
   224 	maxlines = clamp(65536 / w, 16, 128);
   255 	maxlines = clamp(65536 / w, 16, 128);
   225 
   256 
   226 	/* now generate the bitmap bits */
   257 	/* now generate the bitmap bits */
   227 	Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
   258 	void *buff = MallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time.
   228 	if (buff == NULL) {
   259 	if (buff == NULL) {
   229 		png_destroy_write_struct(&png_ptr, &info_ptr);
   260 		png_destroy_write_struct(&png_ptr, &info_ptr);
   230 		fclose(f);
   261 		fclose(f);
   231 		return false;
   262 		return false;
   232 	}
   263 	}
   233 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   264 	memset(buff, 0, w * maxlines * bpp);
   234 
   265 
   235 	y = 0;
   266 	y = 0;
   236 	do {
   267 	do {
   237 		/* determine # lines to write */
   268 		/* determine # lines to write */
   238 		n = min(h - y, maxlines);
   269 		n = min(h - y, maxlines);
   241 		callb(userdata, buff, y, w, n);
   272 		callb(userdata, buff, y, w, n);
   242 		y += n;
   273 		y += n;
   243 
   274 
   244 		/* write them to png */
   275 		/* write them to png */
   245 		for (i = 0; i != n; i++)
   276 		for (i = 0; i != n; i++)
   246 			png_write_row(png_ptr, buff + i * w);
   277 			png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
   247 	} while (y != h);
   278 	} while (y != h);
   248 
   279 
   249 	png_write_end(png_ptr, info_ptr);
   280 	png_write_end(png_ptr, info_ptr);
   250 	png_destroy_write_struct(&png_ptr, &info_ptr);
   281 	png_destroy_write_struct(&png_ptr, &info_ptr);
   251 
   282 
   285 	uint maxlines;
   316 	uint maxlines;
   286 	uint y;
   317 	uint y;
   287 	PcxHeader pcx;
   318 	PcxHeader pcx;
   288 	bool success;
   319 	bool success;
   289 
   320 
       
   321 	if (pixelformat == 32) {
       
   322 		DEBUG(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick an other format.");
       
   323 		return false;
       
   324 	}
   290 	if (pixelformat != 8 || w == 0)
   325 	if (pixelformat != 8 || w == 0)
   291 		return false;
   326 		return false;
   292 
   327 
   293 	f = fopen(name, "wb");
   328 	f = fopen(name, "wb");
   294 	if (f == NULL) return false;
   329 	if (f == NULL) return false;
   318 
   353 
   319 	/* use by default 64k temp memory */
   354 	/* use by default 64k temp memory */
   320 	maxlines = clamp(65536 / w, 16, 128);
   355 	maxlines = clamp(65536 / w, 16, 128);
   321 
   356 
   322 	/* now generate the bitmap bits */
   357 	/* now generate the bitmap bits */
   323 	Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
   358 	uint8 *buff = MallocT<uint8>(w * maxlines); // by default generate 128 lines at a time.
   324 	if (buff == NULL) {
   359 	if (buff == NULL) {
   325 		fclose(f);
   360 		fclose(f);
   326 		return false;
   361 		return false;
   327 	}
   362 	}
   328 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   363 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   337 		callb(userdata, buff, y, w, n);
   372 		callb(userdata, buff, y, w, n);
   338 		y += n;
   373 		y += n;
   339 
   374 
   340 		/* write them to pcx */
   375 		/* write them to pcx */
   341 		for (i = 0; i != n; i++) {
   376 		for (i = 0; i != n; i++) {
   342 			const Pixel* bufp = buff + i * w;
   377 			const uint8 *bufp = buff + i * w;
   343 			byte runchar = bufp[0];
   378 			byte runchar = bufp[0];
   344 			uint runcount = 1;
   379 			uint runcount = 1;
   345 			uint j;
   380 			uint j;
   346 
   381 
   347 			/* for each pixel... */
   382 			/* for each pixel... */
   348 			for (j = 1; j < w; j++) {
   383 			for (j = 1; j < w; j++) {
   349 				Pixel ch = bufp[j];
   384 				uint8 ch = bufp[j];
   350 
   385 
   351 				if (ch != runchar || runcount >= 0x3f) {
   386 				if (ch != runchar || runcount >= 0x3f) {
   352 					if (runcount > 1 || (runchar & 0xC0) == 0xC0)
   387 					if (runcount > 1 || (runchar & 0xC0) == 0xC0)
   353 						if (fputc(0xC0 | runcount, f) == EOF) {
   388 						if (fputc(0xC0 | runcount, f) == EOF) {
   354 							free(buff);
   389 							free(buff);
   444 	_cur_screenshot_format = i;
   479 	_cur_screenshot_format = i;
   445 	strcpy(_screenshot_format_name, _screenshot_formats[i].extension);
   480 	strcpy(_screenshot_format_name, _screenshot_formats[i].extension);
   446 }
   481 }
   447 
   482 
   448 /* screenshot generator that dumps the current video buffer */
   483 /* screenshot generator that dumps the current video buffer */
   449 static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
   484 static void CurrentScreenCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
   450 {
   485 {
   451 	for (; n > 0; --n) {
   486 	Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
   452 		memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width * sizeof(Pixel));
   487 	void *src = blitter->MoveTo(_screen.dst_ptr, 0, y);
   453 		++y;
   488 	blitter->CopyToBuffer(src, buf, _screen.width, n, pitch);
   454 		buf += pitch;
       
   455 	}
       
   456 }
   489 }
   457 
   490 
   458 /* generate a large piece of the world */
   491 /* generate a large piece of the world */
   459 static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
   492 static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
   460 {
   493 {
   461 	ViewPort *vp = (ViewPort *)userdata;
   494 	ViewPort *vp = (ViewPort *)userdata;
   462 	DrawPixelInfo dpi, *old_dpi;
   495 	DrawPixelInfo dpi, *old_dpi;
   463 	int wx, left;
   496 	int wx, left;
   464 
   497 
   489 	_cur_dpi = old_dpi;
   522 	_cur_dpi = old_dpi;
   490 }
   523 }
   491 
   524 
   492 static char *MakeScreenshotName(const char *ext)
   525 static char *MakeScreenshotName(const char *ext)
   493 {
   526 {
   494 	static char filename[256];
   527 	static char filename[MAX_PATH];
   495 	char *base;
       
   496 	int serial;
   528 	int serial;
       
   529 	size_t len;
   497 
   530 
   498 	if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_player == PLAYER_SPECTATOR) {
   531 	if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_player == PLAYER_SPECTATOR) {
   499 		sprintf(_screenshot_name, "screenshot");
   532 		ttd_strlcpy(_screenshot_name, "screenshot", lengthof(_screenshot_name));
   500 	} else {
   533 	} else {
   501 		const Player* p = GetPlayer(_local_player);
   534 		const Player* p = GetPlayer(_local_player);
   502 		SetDParam(0, p->name_1);
   535 		SetDParam(0, p->name_1);
   503 		SetDParam(1, p->name_2);
   536 		SetDParam(1, p->name_2);
   504 		SetDParam(2, _date);
   537 		SetDParam(2, _date);
   505 		GetString(_screenshot_name, STR_4004, lastof(_screenshot_name));
   538 		GetString(_screenshot_name, STR_4004, lastof(_screenshot_name));
   506 	}
   539 	}
   507 
   540 
   508 	base = strchr(_screenshot_name, 0);
   541 	/* Add extension to screenshot file */
   509 	base[0] = '.'; strcpy(base + 1, ext);
   542 	SanitizeFilename(_screenshot_name);
   510 
   543 	len = strlen(_screenshot_name);
   511 	serial = 0;
   544 	snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, ".%s", ext);
   512 	for (;;) {
   545 
   513 		snprintf(filename, sizeof(filename), "%s%s", _paths.personal_dir, _screenshot_name);
   546 	for (serial = 1;; serial++) {
   514 		if (!FileExists(filename))
   547 		snprintf(filename, lengthof(filename), "%s%s", _personal_dir, _screenshot_name);
   515 			break;
   548 		if (!FileExists(filename)) break;
   516 		sprintf(base, " #%d.%s", ++serial, ext);
   549 		/* If file exists try another one with same name, but just with a higher index */
       
   550 		snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, "#%d.%s", serial, ext);
   517 	}
   551 	}
   518 
   552 
   519 	return filename;
   553 	return filename;
   520 }
   554 }
   521 
   555 
   530 }
   564 }
   531 
   565 
   532 static bool MakeSmallScreenshot()
   566 static bool MakeSmallScreenshot()
   533 {
   567 {
   534 	const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
   568 	const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
   535 	return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, 8, _cur_palette);
   569 	return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
   536 }
   570 }
   537 
   571 
   538 static bool MakeWorldScreenshot()
   572 static bool MakeWorldScreenshot()
   539 {
   573 {
   540 	ViewPort vp;
   574 	ViewPort vp;
   549 	vp.width = vp.virtual_width;
   583 	vp.width = vp.virtual_width;
   550 	vp.virtual_height = (MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1;
   584 	vp.virtual_height = (MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1;
   551 	vp.height = vp.virtual_height;
   585 	vp.height = vp.virtual_height;
   552 
   586 
   553 	sf = _screenshot_formats + _cur_screenshot_format;
   587 	sf = _screenshot_formats + _cur_screenshot_format;
   554 	return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, 8, _cur_palette);
   588 	return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
   555 }
   589 }
   556 
   590 
   557 bool MakeScreenshot()
   591 bool MakeScreenshot()
   558 {
   592 {
   559 	switch (current_screenshot_type) {
   593 	switch (current_screenshot_type) {