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