00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "fileio_func.h"
00014 #include "viewport_func.h"
00015 #include "gfx_func.h"
00016 #include "screenshot.h"
00017 #include "blitter/factory.hpp"
00018 #include "zoom_func.h"
00019 #include "core/endian_func.hpp"
00020 #include "saveload/saveload.h"
00021 #include "company_func.h"
00022 #include "strings_func.h"
00023 #include "error.h"
00024 #include "window_gui.h"
00025 #include "window_func.h"
00026 #include "tile_map.h"
00027
00028 #include "table/strings.h"
00029
00030 static const char * const SCREENSHOT_NAME = "screenshot";
00031 static const char * const HEIGHTMAP_NAME = "heightmap";
00032
00033 char _screenshot_format_name[8];
00034 uint _num_screenshot_formats;
00035 uint _cur_screenshot_format;
00036 static char _screenshot_name[128];
00037 char _full_screenshot_name[MAX_PATH];
00038
00047 typedef void ScreenshotCallback(void *userdata, void *buf, uint y, uint pitch, uint n);
00048
00060 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
00061
00063 struct ScreenshotFormat {
00064 const char *name;
00065 const char *extension;
00066 ScreenshotHandlerProc *proc;
00067 bool supports_32bpp;
00068 };
00069
00070
00071
00072
00073 #if defined(_MSC_VER) || defined(__WATCOMC__)
00074 #pragma pack(push, 1)
00075 #endif
00076
00078 struct BitmapFileHeader {
00079 uint16 type;
00080 uint32 size;
00081 uint32 reserved;
00082 uint32 off_bits;
00083 } GCC_PACK;
00084 assert_compile(sizeof(BitmapFileHeader) == 14);
00085
00086 #if defined(_MSC_VER) || defined(__WATCOMC__)
00087 #pragma pack(pop)
00088 #endif
00089
00091 struct BitmapInfoHeader {
00092 uint32 size;
00093 int32 width, height;
00094 uint16 planes, bitcount;
00095 uint32 compression, sizeimage, xpels, ypels, clrused, clrimp;
00096 };
00097 assert_compile(sizeof(BitmapInfoHeader) == 40);
00098
00100 struct RgbQuad {
00101 byte blue, green, red, reserved;
00102 };
00103 assert_compile(sizeof(RgbQuad) == 4);
00104
00117 static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
00118 {
00119 uint bpp;
00120 switch (pixelformat) {
00121 case 8: bpp = 1; break;
00122
00123 case 32: bpp = 3; break;
00124
00125 default: return false;
00126 }
00127
00128 FILE *f = fopen(name, "wb");
00129 if (f == NULL) return false;
00130
00131
00132 uint bytewidth = Align(w * bpp, 4);
00133
00134
00135 uint pal_size = pixelformat == 8 ? sizeof(RgbQuad) * 256 : 0;
00136
00137
00138 BitmapFileHeader bfh;
00139 bfh.type = TO_LE16('MB');
00140 bfh.size = TO_LE32(sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + pal_size + bytewidth * h);
00141 bfh.reserved = 0;
00142 bfh.off_bits = TO_LE32(sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + pal_size);
00143
00144
00145 BitmapInfoHeader bih;
00146 bih.size = TO_LE32(sizeof(BitmapInfoHeader));
00147 bih.width = TO_LE32(w);
00148 bih.height = TO_LE32(h);
00149 bih.planes = TO_LE16(1);
00150 bih.bitcount = TO_LE16(bpp * 8);
00151 bih.compression = 0;
00152 bih.sizeimage = 0;
00153 bih.xpels = 0;
00154 bih.ypels = 0;
00155 bih.clrused = 0;
00156 bih.clrimp = 0;
00157
00158
00159 if (fwrite(&bfh, sizeof(bfh), 1, f) != 1 || fwrite(&bih, sizeof(bih), 1, f) != 1) {
00160 fclose(f);
00161 return false;
00162 }
00163
00164 if (pixelformat == 8) {
00165
00166 RgbQuad rq[256];
00167 for (uint i = 0; i < 256; i++) {
00168 rq[i].red = palette[i].r;
00169 rq[i].green = palette[i].g;
00170 rq[i].blue = palette[i].b;
00171 rq[i].reserved = 0;
00172 }
00173
00174 if (fwrite(rq, sizeof(rq), 1, f) != 1) {
00175 fclose(f);
00176 return false;
00177 }
00178 }
00179
00180
00181 uint maxlines = Clamp(65536 / (w * pixelformat / 8), 16, 128);
00182
00183 uint8 *buff = MallocT<uint8>(maxlines * w * pixelformat / 8);
00184 uint8 *line = AllocaM(uint8, bytewidth);
00185 memset(line, 0, bytewidth);
00186
00187
00188 do {
00189 uint n = min(h, maxlines);
00190 h -= n;
00191
00192
00193 callb(userdata, buff, h, w, n);
00194
00195
00196 while (n-- != 0) {
00197 if (pixelformat == 8) {
00198
00199 memcpy(line, buff + n * w, w);
00200 } else {
00201
00202
00203 Colour *src = ((Colour *)buff) + n * w;
00204 byte *dst = line;
00205 for (uint i = 0; i < w; i++) {
00206 dst[i * 3 ] = src[i].b;
00207 dst[i * 3 + 1] = src[i].g;
00208 dst[i * 3 + 2] = src[i].r;
00209 }
00210 }
00211
00212 if (fwrite(line, bytewidth, 1, f) != 1) {
00213 free(buff);
00214 fclose(f);
00215 return false;
00216 }
00217 }
00218 } while (h != 0);
00219
00220 free(buff);
00221 fclose(f);
00222
00223 return true;
00224 }
00225
00226
00227
00228
00229 #if defined(WITH_PNG)
00230 #include <png.h>
00231
00232 #ifdef PNG_TEXT_SUPPORTED
00233 #include "rev.h"
00234 #include "newgrf_config.h"
00235 #include "ai/ai_info.hpp"
00236 #include "company_base.h"
00237 #include "base_media_base.h"
00238 #endif
00239
00240 static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
00241 {
00242 DEBUG(misc, 0, "[libpng] error: %s - %s", message, (const char *)png_get_error_ptr(png_ptr));
00243 longjmp(png_jmpbuf(png_ptr), 1);
00244 }
00245
00246 static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
00247 {
00248 DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (const char *)png_get_error_ptr(png_ptr));
00249 }
00250
00263 static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
00264 {
00265 png_color rq[256];
00266 FILE *f;
00267 uint i, y, n;
00268 uint maxlines;
00269 uint bpp = pixelformat / 8;
00270 png_structp png_ptr;
00271 png_infop info_ptr;
00272
00273
00274 if (pixelformat != 8 && pixelformat != 32) return false;
00275
00276 f = fopen(name, "wb");
00277 if (f == NULL) return false;
00278
00279 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast<char *>(name), png_my_error, png_my_warning);
00280
00281 if (png_ptr == NULL) {
00282 fclose(f);
00283 return false;
00284 }
00285
00286 info_ptr = png_create_info_struct(png_ptr);
00287 if (info_ptr == NULL) {
00288 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00289 fclose(f);
00290 return false;
00291 }
00292
00293 if (setjmp(png_jmpbuf(png_ptr))) {
00294 png_destroy_write_struct(&png_ptr, &info_ptr);
00295 fclose(f);
00296 return false;
00297 }
00298
00299 png_init_io(png_ptr, f);
00300
00301 png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
00302
00303 png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
00304 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00305
00306 #ifdef PNG_TEXT_SUPPORTED
00307
00308
00309 png_text_struct text[2];
00310 memset(text, 0, sizeof(text));
00311 text[0].key = const_cast<char *>("Software");
00312 text[0].text = const_cast<char *>(_openttd_revision);
00313 text[0].text_length = strlen(_openttd_revision);
00314 text[0].compression = PNG_TEXT_COMPRESSION_NONE;
00315
00316 char buf[8192];
00317 char *p = buf;
00318 p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version);
00319 p = strecpy(p, "NewGRFs:\n", lastof(buf));
00320 for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) {
00321 p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid));
00322 p = md5sumToString(p, lastof(buf), c->ident.md5sum);
00323 p += seprintf(p, lastof(buf), " %s\n", c->filename);
00324 }
00325 p = strecpy(p, "\nCompanies:\n", lastof(buf));
00326 const Company *c;
00327 FOR_ALL_COMPANIES(c) {
00328 if (c->ai_info == NULL) {
00329 p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index);
00330 } else {
00331 p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
00332 }
00333 }
00334 text[1].key = const_cast<char *>("Description");
00335 text[1].text = buf;
00336 text[1].text_length = p - buf;
00337 text[1].compression = PNG_TEXT_COMPRESSION_zTXt;
00338 png_set_text(png_ptr, info_ptr, text, 2);
00339 #endif
00340
00341 if (pixelformat == 8) {
00342
00343 for (i = 0; i != 256; i++) {
00344 rq[i].red = palette[i].r;
00345 rq[i].green = palette[i].g;
00346 rq[i].blue = palette[i].b;
00347 }
00348
00349 png_set_PLTE(png_ptr, info_ptr, rq, 256);
00350 }
00351
00352 png_write_info(png_ptr, info_ptr);
00353 png_set_flush(png_ptr, 512);
00354
00355 if (pixelformat == 32) {
00356 png_color_8 sig_bit;
00357
00358
00359 sig_bit.alpha = 0;
00360 sig_bit.blue = 8;
00361 sig_bit.green = 8;
00362 sig_bit.red = 8;
00363 sig_bit.gray = 8;
00364 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
00365
00366 #if TTD_ENDIAN == TTD_LITTLE_ENDIAN
00367 png_set_bgr(png_ptr);
00368 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
00369 #else
00370 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
00371 #endif
00372 }
00373
00374
00375 maxlines = Clamp(65536 / w, 16, 128);
00376
00377
00378 void *buff = CallocT<uint8>(w * maxlines * bpp);
00379
00380 y = 0;
00381 do {
00382
00383 n = min(h - y, maxlines);
00384
00385
00386 callb(userdata, buff, y, w, n);
00387 y += n;
00388
00389
00390 for (i = 0; i != n; i++) {
00391 png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
00392 }
00393 } while (y != h);
00394
00395 png_write_end(png_ptr, info_ptr);
00396 png_destroy_write_struct(&png_ptr, &info_ptr);
00397
00398 free(buff);
00399 fclose(f);
00400 return true;
00401 }
00402 #endif
00403
00404
00405
00406
00407
00408
00410 struct PcxHeader {
00411 byte manufacturer;
00412 byte version;
00413 byte rle;
00414 byte bpp;
00415 uint32 unused;
00416 uint16 xmax, ymax;
00417 uint16 hdpi, vdpi;
00418 byte pal_small[16 * 3];
00419 byte reserved;
00420 byte planes;
00421 uint16 pitch;
00422 uint16 cpal;
00423 uint16 width;
00424 uint16 height;
00425 byte filler[54];
00426 };
00427 assert_compile(sizeof(PcxHeader) == 128);
00428
00441 static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
00442 {
00443 FILE *f;
00444 uint maxlines;
00445 uint y;
00446 PcxHeader pcx;
00447 bool success;
00448
00449 if (pixelformat == 32) {
00450 DEBUG(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick another format.");
00451 return false;
00452 }
00453 if (pixelformat != 8 || w == 0) return false;
00454
00455 f = fopen(name, "wb");
00456 if (f == NULL) return false;
00457
00458 memset(&pcx, 0, sizeof(pcx));
00459
00460
00461 pcx.manufacturer = 10;
00462 pcx.version = 5;
00463 pcx.rle = 1;
00464 pcx.bpp = 8;
00465 pcx.xmax = TO_LE16(w - 1);
00466 pcx.ymax = TO_LE16(h - 1);
00467 pcx.hdpi = TO_LE16(320);
00468 pcx.vdpi = TO_LE16(320);
00469
00470 pcx.planes = 1;
00471 pcx.cpal = TO_LE16(1);
00472 pcx.width = pcx.pitch = TO_LE16(w);
00473 pcx.height = TO_LE16(h);
00474
00475
00476 if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
00477 fclose(f);
00478 return false;
00479 }
00480
00481
00482 maxlines = Clamp(65536 / w, 16, 128);
00483
00484
00485 uint8 *buff = CallocT<uint8>(w * maxlines);
00486
00487 y = 0;
00488 do {
00489
00490 uint n = min(h - y, maxlines);
00491 uint i;
00492
00493
00494 callb(userdata, buff, y, w, n);
00495 y += n;
00496
00497
00498 for (i = 0; i != n; i++) {
00499 const uint8 *bufp = buff + i * w;
00500 byte runchar = bufp[0];
00501 uint runcount = 1;
00502 uint j;
00503
00504
00505 for (j = 1; j < w; j++) {
00506 uint8 ch = bufp[j];
00507
00508 if (ch != runchar || runcount >= 0x3f) {
00509 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
00510 if (fputc(0xC0 | runcount, f) == EOF) {
00511 free(buff);
00512 fclose(f);
00513 return false;
00514 }
00515 }
00516 if (fputc(runchar, f) == EOF) {
00517 free(buff);
00518 fclose(f);
00519 return false;
00520 }
00521 runcount = 0;
00522 runchar = ch;
00523 }
00524 runcount++;
00525 }
00526
00527
00528 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
00529 if (fputc(0xC0 | runcount, f) == EOF) {
00530 free(buff);
00531 fclose(f);
00532 return false;
00533 }
00534 }
00535 if (fputc(runchar, f) == EOF) {
00536 free(buff);
00537 fclose(f);
00538 return false;
00539 }
00540 }
00541 } while (y != h);
00542
00543 free(buff);
00544
00545
00546 if (fputc(12, f) == EOF) {
00547 fclose(f);
00548 return false;
00549 }
00550
00551
00552 byte tmp[256 * 3];
00553
00554 for (uint i = 0; i < 256; i++) {
00555 tmp[i * 3 + 0] = palette[i].r;
00556 tmp[i * 3 + 1] = palette[i].g;
00557 tmp[i * 3 + 2] = palette[i].b;
00558 }
00559 success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
00560
00561 fclose(f);
00562
00563 return success;
00564 }
00565
00566
00567
00568
00569
00571 static const ScreenshotFormat _screenshot_formats[] = {
00572 #if defined(WITH_PNG)
00573 {"PNG", "png", &MakePNGImage, true},
00574 #endif
00575 {"BMP", "bmp", &MakeBMPImage, true},
00576 {"PCX", "pcx", &MakePCXImage, false},
00577 };
00578
00580 const char *GetCurrentScreenshotExtension()
00581 {
00582 return _screenshot_formats[_cur_screenshot_format].extension;
00583 }
00584
00586 void InitializeScreenshotFormats()
00587 {
00588 uint j = 0;
00589 for (uint i = 0; i < lengthof(_screenshot_formats); i++) {
00590 if (!strcmp(_screenshot_format_name, _screenshot_formats[i].extension)) {
00591 j = i;
00592 break;
00593 }
00594 }
00595 _cur_screenshot_format = j;
00596 _num_screenshot_formats = lengthof(_screenshot_formats);
00597 }
00598
00604 const char *GetScreenshotFormatDesc(int i)
00605 {
00606 return _screenshot_formats[i].name;
00607 }
00608
00614 bool GetScreenshotFormatSupports_32bpp(int i)
00615 {
00616 return _screenshot_formats[i].supports_32bpp;
00617 }
00618
00623 void SetScreenshotFormat(uint i)
00624 {
00625 assert(i < _num_screenshot_formats);
00626 _cur_screenshot_format = i;
00627 strecpy(_screenshot_format_name, _screenshot_formats[i].extension, lastof(_screenshot_format_name));
00628 }
00629
00634 static void CurrentScreenCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
00635 {
00636 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00637 void *src = blitter->MoveTo(_screen.dst_ptr, 0, y);
00638 blitter->CopyImageToBuffer(src, buf, _screen.width, n, pitch);
00639 }
00640
00649 static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
00650 {
00651 ViewPort *vp = (ViewPort *)userdata;
00652 DrawPixelInfo dpi, *old_dpi;
00653 int wx, left;
00654
00655
00656 DrawPixelInfo old_screen = _screen;
00657 bool old_disable_anim = _screen_disable_anim;
00658
00659 _screen.dst_ptr = buf;
00660 _screen.width = pitch;
00661 _screen.height = n;
00662 _screen.pitch = pitch;
00663 _screen_disable_anim = true;
00664
00665 old_dpi = _cur_dpi;
00666 _cur_dpi = &dpi;
00667
00668 dpi.dst_ptr = buf;
00669 dpi.height = n;
00670 dpi.width = vp->width;
00671 dpi.pitch = pitch;
00672 dpi.zoom = ZOOM_LVL_WORLD_SCREENSHOT;
00673 dpi.left = 0;
00674 dpi.top = y;
00675
00676
00677 left = 0;
00678 while (vp->width - left != 0) {
00679 wx = min(vp->width - left, 1600);
00680 left += wx;
00681
00682 ViewportDoDraw(vp,
00683 ScaleByZoom(left - wx - vp->left, vp->zoom) + vp->virtual_left,
00684 ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top,
00685 ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
00686 ScaleByZoom((y + n) - vp->top, vp->zoom) + vp->virtual_top
00687 );
00688 }
00689
00690 _cur_dpi = old_dpi;
00691
00692
00693 _screen = old_screen;
00694 _screen_disable_anim = old_disable_anim;
00695 }
00696
00703 static const char *MakeScreenshotName(const char *default_fn, const char *ext)
00704 {
00705 bool generate = StrEmpty(_screenshot_name);
00706
00707 if (generate) {
00708 if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_company == COMPANY_SPECTATOR) {
00709 strecpy(_screenshot_name, default_fn, lastof(_screenshot_name));
00710 } else {
00711 GenerateDefaultSaveName(_screenshot_name, lastof(_screenshot_name));
00712 }
00713 }
00714
00715
00716 size_t len = strlen(_screenshot_name);
00717 snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, ".%s", ext);
00718
00719 for (uint serial = 1;; serial++) {
00720 if (snprintf(_full_screenshot_name, lengthof(_full_screenshot_name), "%s%s", _personal_dir, _screenshot_name) >= (int)lengthof(_full_screenshot_name)) {
00721
00722 _full_screenshot_name[0] = '\0';
00723 break;
00724 }
00725 if (!generate) break;
00726 if (!FileExists(_full_screenshot_name)) break;
00727
00728 snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, "#%u.%s", serial, ext);
00729 }
00730
00731 return _full_screenshot_name;
00732 }
00733
00735 static bool MakeSmallScreenshot()
00736 {
00737 const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
00738 return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height,
00739 BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette);
00740 }
00741
00743 static bool MakeZoomedInScreenshot(ZoomLevel zl)
00744 {
00745 Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
00746 ViewPort vp;
00747
00748 vp.zoom = zl;
00749 vp.left = w->viewport->left;
00750 vp.top = w->viewport->top;
00751 vp.virtual_left = w->viewport->virtual_left;
00752 vp.virtual_top = w->viewport->virtual_top;
00753 vp.virtual_width = w->viewport->virtual_width;
00754 vp.width = UnScaleByZoom(vp.virtual_width, vp.zoom);
00755 vp.virtual_height = w->viewport->virtual_height;
00756 vp.height = UnScaleByZoom(vp.virtual_height, vp.zoom);
00757
00758 const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
00759 return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), LargeWorldCallback, &vp, vp.width, vp.height,
00760 BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette);
00761 }
00762
00764 static bool MakeWorldScreenshot()
00765 {
00766 ViewPort vp;
00767 const ScreenshotFormat *sf;
00768
00769
00770 int extra_height_top = TilePixelHeight(0) + 150;
00771
00772 int reclaim_height_bottom = TilePixelHeight(MapSize() - 1);
00773
00774 vp.zoom = ZOOM_LVL_WORLD_SCREENSHOT;
00775 vp.left = 0;
00776 vp.top = 0;
00777 vp.virtual_left = -(int)MapMaxX() * TILE_PIXELS * ZOOM_LVL_BASE;
00778 vp.virtual_top = -extra_height_top * ZOOM_LVL_BASE;
00779 vp.virtual_width = (MapMaxX() + MapMaxY()) * TILE_PIXELS;
00780 vp.width = vp.virtual_width;
00781 vp.virtual_height = ((MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1) + extra_height_top - reclaim_height_bottom;
00782 vp.height = vp.virtual_height;
00783
00784 sf = _screenshot_formats + _cur_screenshot_format;
00785 return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), LargeWorldCallback, &vp, vp.width, vp.height,
00786 BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette);
00787 }
00788
00798 static void HeightmapCallback(void *userdata, void *buffer, uint y, uint pitch, uint n)
00799 {
00800 byte *buf = (byte *)buffer;
00801 while (n > 0) {
00802 TileIndex ti = TileXY(MapMaxX(), y);
00803 for (uint x = MapMaxX(); true; x--) {
00804 *buf = 16 * TileHeight(ti);
00805 buf++;
00806 if (x == 0) break;
00807 ti = TILE_ADDXY(ti, -1, 0);
00808 }
00809 y++;
00810 n--;
00811 }
00812 }
00813
00818 bool MakeHeightmapScreenshot(const char *filename)
00819 {
00820 Colour palette[256];
00821 for (uint i = 0; i < lengthof(palette); i++) {
00822 palette[i].a = 0xff;
00823 palette[i].r = i;
00824 palette[i].g = i;
00825 palette[i].b = i;
00826 }
00827 const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
00828 return sf->proc(filename, HeightmapCallback, NULL, MapSizeX(), MapSizeY(), 8, palette);
00829 }
00830
00837 bool MakeScreenshot(ScreenshotType t, const char *name)
00838 {
00839 if (t == SC_VIEWPORT) {
00840
00841
00842
00843
00844 UndrawMouseCursor();
00845 DrawDirtyBlocks();
00846 }
00847
00848 _screenshot_name[0] = '\0';
00849 if (name != NULL) strecpy(_screenshot_name, name, lastof(_screenshot_name));
00850
00851 bool ret;
00852 switch (t) {
00853 case SC_VIEWPORT:
00854 case SC_RAW:
00855 ret = MakeSmallScreenshot();
00856 break;
00857
00858 case SC_ZOOMEDIN:
00859 ret = MakeZoomedInScreenshot(_settings_client.gui.zoom_min);
00860 break;
00861
00862 case SC_DEFAULTZOOM:
00863 ret = MakeZoomedInScreenshot(ZOOM_LVL_VIEWPORT);
00864 break;
00865
00866 case SC_WORLD:
00867 ret = MakeWorldScreenshot();
00868 break;
00869
00870 case SC_HEIGHTMAP: {
00871 const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
00872 ret = MakeHeightmapScreenshot(MakeScreenshotName(HEIGHTMAP_NAME, sf->extension));
00873 break;
00874 }
00875
00876 default:
00877 NOT_REACHED();
00878 }
00879
00880 if (ret) {
00881 SetDParamStr(0, _screenshot_name);
00882 ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING);
00883 } else {
00884 ShowErrorMessage(STR_ERROR_SCREENSHOT_FAILED, INVALID_STRING_ID, WL_ERROR);
00885 }
00886
00887 return ret;
00888 }