src/screenshot.cpp
branchgamebalance
changeset 9908 0fa543611bbe
parent 9895 7bd07f43b0e3
child 6308 646711c5feaa
equal deleted inserted replaced
9907:3b068c3a1c74 9908:0fa543611bbe
    18 char _screenshot_format_name[8];
    18 char _screenshot_format_name[8];
    19 uint _num_screenshot_formats;
    19 uint _num_screenshot_formats;
    20 uint _cur_screenshot_format;
    20 uint _cur_screenshot_format;
    21 ScreenshotType current_screenshot_type;
    21 ScreenshotType current_screenshot_type;
    22 
    22 
    23 // called by the ScreenShot proc to generate screenshot lines.
    23 /* called by the ScreenShot proc to generate screenshot lines. */
    24 typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n);
    24 typedef void ScreenshotCallback(void *userdata, Pixel *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);
    25 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
    26 
    26 
    27 struct ScreenshotFormat {
    27 struct ScreenshotFormat {
    28 	const char *name;
    28 	const char *name;
    60 struct RgbQuad {
    60 struct RgbQuad {
    61 	byte blue, green, red, reserved;
    61 	byte blue, green, red, reserved;
    62 };
    62 };
    63 assert_compile(sizeof(RgbQuad) == 4);
    63 assert_compile(sizeof(RgbQuad) == 4);
    64 
    64 
    65 // generic .BMP writer
    65 /* generic .BMP writer */
    66 static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
    66 static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
    67 {
    67 {
    68 	BitmapFileHeader bfh;
    68 	BitmapFileHeader bfh;
    69 	BitmapInfoHeader bih;
    69 	BitmapInfoHeader bih;
    70 	RgbQuad rq[256];
    70 	RgbQuad rq[256];
    71 	FILE *f;
    71 	FILE *f;
    72 	uint i, padw;
    72 	uint i, padw;
    73 	uint n, maxlines;
    73 	uint n, maxlines;
    74 
    74 
    75 	// only implemented for 8bit images so far.
    75 	/* only implemented for 8bit images so far. */
    76 	if (pixelformat != 8)
    76 	if (pixelformat != 8)
    77 		return false;
    77 		return false;
    78 
    78 
    79 	f = fopen(name, "wb");
    79 	f = fopen(name, "wb");
    80 	if (f == NULL) return false;
    80 	if (f == NULL) return false;
    81 
    81 
    82 	// each scanline must be aligned on a 32bit boundary
    82 	/* each scanline must be aligned on a 32bit boundary */
    83 	padw = ALIGN(w, 4);
    83 	padw = ALIGN(w, 4);
    84 
    84 
    85 	// setup the file header
    85 	/* setup the file header */
    86 	bfh.type = TO_LE16('MB');
    86 	bfh.type = TO_LE16('MB');
    87 	bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h);
    87 	bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h);
    88 	bfh.reserved = 0;
    88 	bfh.reserved = 0;
    89 	bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256);
    89 	bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256);
    90 
    90 
    91 	// setup the info header
    91 	/* setup the info header */
    92 	bih.size = TO_LE32(sizeof(BitmapInfoHeader));
    92 	bih.size = TO_LE32(sizeof(BitmapInfoHeader));
    93 	bih.width = TO_LE32(w);
    93 	bih.width = TO_LE32(w);
    94 	bih.height = TO_LE32(h);
    94 	bih.height = TO_LE32(h);
    95 	bih.planes = TO_LE16(1);
    95 	bih.planes = TO_LE16(1);
    96 	bih.bitcount = TO_LE16(8);
    96 	bih.bitcount = TO_LE16(8);
    99 	bih.xpels = 0;
    99 	bih.xpels = 0;
   100 	bih.ypels = 0;
   100 	bih.ypels = 0;
   101 	bih.clrused = 0;
   101 	bih.clrused = 0;
   102 	bih.clrimp = 0;
   102 	bih.clrimp = 0;
   103 
   103 
   104 	// convert the palette to the windows format
   104 	/* convert the palette to the windows format */
   105 	for (i = 0; i != 256; i++) {
   105 	for (i = 0; i != 256; i++) {
   106 		rq[i].red   = palette[i].r;
   106 		rq[i].red   = palette[i].r;
   107 		rq[i].green = palette[i].g;
   107 		rq[i].green = palette[i].g;
   108 		rq[i].blue  = palette[i].b;
   108 		rq[i].blue  = palette[i].b;
   109 		rq[i].reserved = 0;
   109 		rq[i].reserved = 0;
   110 	}
   110 	}
   111 
   111 
   112 	// write file header and info header and palette
   112 	/* write file header and info header and palette */
   113 	if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
   113 	if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false;
   114 	if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
   114 	if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false;
   115 	if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
   115 	if (fwrite(rq, sizeof(rq), 1, f) != 1) return false;
   116 
   116 
   117 	// use by default 64k temp memory
   117 	/* use by default 64k temp memory */
   118 	maxlines = clamp(65536 / padw, 16, 128);
   118 	maxlines = clamp(65536 / padw, 16, 128);
   119 
   119 
   120 	// now generate the bitmap bits
   120 	/* now generate the bitmap bits */
   121 	Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time.
   121 	Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time.
   122 	if (buff == NULL) {
   122 	if (buff == NULL) {
   123 		fclose(f);
   123 		fclose(f);
   124 		return false;
   124 		return false;
   125 	}
   125 	}
   126 	memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0
   126 	memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0
   127 
   127 
   128 	// start at the bottom, since bitmaps are stored bottom up.
   128 	/* start at the bottom, since bitmaps are stored bottom up. */
   129 	do {
   129 	do {
   130 		// determine # lines
   130 		/* determine # lines */
   131 		n = min(h, maxlines);
   131 		n = min(h, maxlines);
   132 		h -= n;
   132 		h -= n;
   133 
   133 
   134 		// render the pixels
   134 		/* render the pixels */
   135 		callb(userdata, buff, h, padw, n);
   135 		callb(userdata, buff, h, padw, n);
   136 
   136 
   137 		// write each line
   137 		/* write each line */
   138 		while (n)
   138 		while (n)
   139 			if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) {
   139 			if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) {
   140 				free(buff);
   140 				free(buff);
   141 				fclose(f);
   141 				fclose(f);
   142 				return false;
   142 				return false;
   173 	uint i, y, n;
   173 	uint i, y, n;
   174 	uint maxlines;
   174 	uint maxlines;
   175 	png_structp png_ptr;
   175 	png_structp png_ptr;
   176 	png_infop info_ptr;
   176 	png_infop info_ptr;
   177 
   177 
   178 	// only implemented for 8bit images so far.
   178 	/* only implemented for 8bit images so far. */
   179 	if (pixelformat != 8)
   179 	if (pixelformat != 8)
   180 		return false;
   180 		return false;
   181 
   181 
   182 	f = fopen(name, "wb");
   182 	f = fopen(name, "wb");
   183 	if (f == NULL) return false;
   183 	if (f == NULL) return false;
   207 	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
   207 	png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
   208 
   208 
   209 	png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE,
   209 	png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE,
   210 		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   210 		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
   211 
   211 
   212 	// convert the palette to the .PNG format.
   212 	/* convert the palette to the .PNG format. */
   213 	for (i = 0; i != 256; i++) {
   213 	for (i = 0; i != 256; i++) {
   214 		rq[i].red   = palette[i].r;
   214 		rq[i].red   = palette[i].r;
   215 		rq[i].green = palette[i].g;
   215 		rq[i].green = palette[i].g;
   216 		rq[i].blue  = palette[i].b;
   216 		rq[i].blue  = palette[i].b;
   217 	}
   217 	}
   218 
   218 
   219 	png_set_PLTE(png_ptr, info_ptr, rq, 256);
   219 	png_set_PLTE(png_ptr, info_ptr, rq, 256);
   220 	png_write_info(png_ptr, info_ptr);
   220 	png_write_info(png_ptr, info_ptr);
   221 	png_set_flush(png_ptr, 512);
   221 	png_set_flush(png_ptr, 512);
   222 
   222 
   223 	// use by default 64k temp memory
   223 	/* use by default 64k temp memory */
   224 	maxlines = clamp(65536 / w, 16, 128);
   224 	maxlines = clamp(65536 / w, 16, 128);
   225 
   225 
   226 	// now generate the bitmap bits
   226 	/* now generate the bitmap bits */
   227 	Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
   227 	Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
   228 	if (buff == NULL) {
   228 	if (buff == NULL) {
   229 		png_destroy_write_struct(&png_ptr, &info_ptr);
   229 		png_destroy_write_struct(&png_ptr, &info_ptr);
   230 		fclose(f);
   230 		fclose(f);
   231 		return false;
   231 		return false;
   232 	}
   232 	}
   233 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   233 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   234 
   234 
   235 	y = 0;
   235 	y = 0;
   236 	do {
   236 	do {
   237 		// determine # lines to write
   237 		/* determine # lines to write */
   238 		n = min(h - y, maxlines);
   238 		n = min(h - y, maxlines);
   239 
   239 
   240 		// render the pixels into the buffer
   240 		/* render the pixels into the buffer */
   241 		callb(userdata, buff, y, w, n);
   241 		callb(userdata, buff, y, w, n);
   242 		y += n;
   242 		y += n;
   243 
   243 
   244 		// write them to png
   244 		/* write them to png */
   245 		for (i = 0; i != n; i++)
   245 		for (i = 0; i != n; i++)
   246 			png_write_row(png_ptr, buff + i * w);
   246 			png_write_row(png_ptr, buff + i * w);
   247 	} while (y != h);
   247 	} while (y != h);
   248 
   248 
   249 	png_write_end(png_ptr, info_ptr);
   249 	png_write_end(png_ptr, info_ptr);
   293 	f = fopen(name, "wb");
   293 	f = fopen(name, "wb");
   294 	if (f == NULL) return false;
   294 	if (f == NULL) return false;
   295 
   295 
   296 	memset(&pcx, 0, sizeof(pcx));
   296 	memset(&pcx, 0, sizeof(pcx));
   297 
   297 
   298 	// setup pcx header
   298 	/* setup pcx header */
   299 	pcx.manufacturer = 10;
   299 	pcx.manufacturer = 10;
   300 	pcx.version = 5;
   300 	pcx.version = 5;
   301 	pcx.rle = 1;
   301 	pcx.rle = 1;
   302 	pcx.bpp = 8;
   302 	pcx.bpp = 8;
   303 	pcx.xmax = TO_LE16(w - 1);
   303 	pcx.xmax = TO_LE16(w - 1);
   308 	pcx.planes = 1;
   308 	pcx.planes = 1;
   309 	pcx.cpal = TO_LE16(1);
   309 	pcx.cpal = TO_LE16(1);
   310 	pcx.width = pcx.pitch = TO_LE16(w);
   310 	pcx.width = pcx.pitch = TO_LE16(w);
   311 	pcx.height = TO_LE16(h);
   311 	pcx.height = TO_LE16(h);
   312 
   312 
   313 	// write pcx header
   313 	/* write pcx header */
   314 	if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
   314 	if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
   315 		fclose(f);
   315 		fclose(f);
   316 		return false;
   316 		return false;
   317 	}
   317 	}
   318 
   318 
   319 	// use by default 64k temp memory
   319 	/* use by default 64k temp memory */
   320 	maxlines = clamp(65536 / w, 16, 128);
   320 	maxlines = clamp(65536 / w, 16, 128);
   321 
   321 
   322 	// now generate the bitmap bits
   322 	/* now generate the bitmap bits */
   323 	Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
   323 	Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time.
   324 	if (buff == NULL) {
   324 	if (buff == NULL) {
   325 		fclose(f);
   325 		fclose(f);
   326 		return false;
   326 		return false;
   327 	}
   327 	}
   328 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   328 	memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0
   329 
   329 
   330 	y = 0;
   330 	y = 0;
   331 	do {
   331 	do {
   332 		// determine # lines to write
   332 		/* determine # lines to write */
   333 		uint n = min(h - y, maxlines);
   333 		uint n = min(h - y, maxlines);
   334 		uint i;
   334 		uint i;
   335 
   335 
   336 		// render the pixels into the buffer
   336 		/* render the pixels into the buffer */
   337 		callb(userdata, buff, y, w, n);
   337 		callb(userdata, buff, y, w, n);
   338 		y += n;
   338 		y += n;
   339 
   339 
   340 		// write them to pcx
   340 		/* write them to pcx */
   341 		for (i = 0; i != n; i++) {
   341 		for (i = 0; i != n; i++) {
   342 			const Pixel* bufp = buff + i * w;
   342 			const Pixel* bufp = buff + i * w;
   343 			byte runchar = bufp[0];
   343 			byte runchar = bufp[0];
   344 			uint runcount = 1;
   344 			uint runcount = 1;
   345 			uint j;
   345 			uint j;
   346 
   346 
   347 			// for each pixel...
   347 			/* for each pixel... */
   348 			for (j = 1; j < w; j++) {
   348 			for (j = 1; j < w; j++) {
   349 				Pixel ch = bufp[j];
   349 				Pixel ch = bufp[j];
   350 
   350 
   351 				if (ch != runchar || runcount >= 0x3f) {
   351 				if (ch != runchar || runcount >= 0x3f) {
   352 					if (runcount > 1 || (runchar & 0xC0) == 0xC0)
   352 					if (runcount > 1 || (runchar & 0xC0) == 0xC0)
   364 					runchar = ch;
   364 					runchar = ch;
   365 				}
   365 				}
   366 				runcount++;
   366 				runcount++;
   367 			}
   367 			}
   368 
   368 
   369 			// write remaining bytes..
   369 			/* write remaining bytes.. */
   370 			if (runcount > 1 || (runchar & 0xC0) == 0xC0)
   370 			if (runcount > 1 || (runchar & 0xC0) == 0xC0)
   371 				if (fputc(0xC0 | runcount, f) == EOF) {
   371 				if (fputc(0xC0 | runcount, f) == EOF) {
   372 					free(buff);
   372 					free(buff);
   373 					fclose(f);
   373 					fclose(f);
   374 					return false;
   374 					return false;
   381 		}
   381 		}
   382 	} while (y != h);
   382 	} while (y != h);
   383 
   383 
   384 	free(buff);
   384 	free(buff);
   385 
   385 
   386 	// write 8-bit color palette
   386 	/* write 8-bit color palette */
   387 	if (fputc(12, f) == EOF) {
   387 	if (fputc(12, f) == EOF) {
   388 		fclose(f);
   388 		fclose(f);
   389 		return false;
   389 		return false;
   390 	}
   390 	}
   391 
   391 
   443 {
   443 {
   444 	_cur_screenshot_format = i;
   444 	_cur_screenshot_format = i;
   445 	strcpy(_screenshot_format_name, _screenshot_formats[i].extension);
   445 	strcpy(_screenshot_format_name, _screenshot_formats[i].extension);
   446 }
   446 }
   447 
   447 
   448 // screenshot generator that dumps the current video buffer
   448 /* screenshot generator that dumps the current video buffer */
   449 static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
   449 static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
   450 {
   450 {
   451 	for (; n > 0; --n) {
   451 	for (; n > 0; --n) {
   452 		memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width);
   452 		memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width);
   453 		++y;
   453 		++y;
   454 		buf += pitch;
   454 		buf += pitch;
   455 	}
   455 	}
   456 }
   456 }
   457 
   457 
   458 // generate a large piece of the world
   458 /* generate a large piece of the world */
   459 static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
   459 static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n)
   460 {
   460 {
   461 	ViewPort *vp = (ViewPort *)userdata;
   461 	ViewPort *vp = (ViewPort *)userdata;
   462 	DrawPixelInfo dpi, *old_dpi;
   462 	DrawPixelInfo dpi, *old_dpi;
   463 	int wx, left;
   463 	int wx, left;