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 "gui.h"
00024 #include "window_gui.h"
00025 #include "window_func.h"
00026 #include "tile_map.h"
00027
00028 #include "table/strings.h"
00029
00030
00031 char _screenshot_format_name[8];
00032 uint _num_screenshot_formats;
00033 uint _cur_screenshot_format;
00034 static char _screenshot_name[128];
00035 char _full_screenshot_name[MAX_PATH];
00036
00037
00038 typedef void ScreenshotCallback(void *userdata, void *buf, uint y, uint pitch, uint n);
00039 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette);
00040
00041 struct ScreenshotFormat {
00042 const char *name;
00043 const char *extension;
00044 ScreenshotHandlerProc *proc;
00045 };
00046
00047
00048
00049
00050 #if defined(_MSC_VER) || defined(__WATCOMC__)
00051 #pragma pack(push, 1)
00052 #endif
00053
00055 struct BitmapFileHeader {
00056 uint16 type;
00057 uint32 size;
00058 uint32 reserved;
00059 uint32 off_bits;
00060 } GCC_PACK;
00061 assert_compile(sizeof(BitmapFileHeader) == 14);
00062
00063 #if defined(_MSC_VER) || defined(__WATCOMC__)
00064 #pragma pack(pop)
00065 #endif
00066
00068 struct BitmapInfoHeader {
00069 uint32 size;
00070 int32 width, height;
00071 uint16 planes, bitcount;
00072 uint32 compression, sizeimage, xpels, ypels, clrused, clrimp;
00073 };
00074 assert_compile(sizeof(BitmapInfoHeader) == 40);
00075
00077 struct RgbQuad {
00078 byte blue, green, red, reserved;
00079 };
00080 assert_compile(sizeof(RgbQuad) == 4);
00081
00093 static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
00094 {
00095 uint bpp;
00096 switch (pixelformat) {
00097 case 8: bpp = 1; break;
00098
00099 case 32: bpp = 3; break;
00100
00101 default: return false;
00102 }
00103
00104 FILE *f = fopen(name, "wb");
00105 if (f == NULL) return false;
00106
00107
00108 uint bytewidth = Align(w * bpp, 4);
00109
00110
00111 uint pal_size = pixelformat == 8 ? sizeof(RgbQuad) * 256 : 0;
00112
00113
00114 BitmapFileHeader bfh;
00115 bfh.type = TO_LE16('MB');
00116 bfh.size = TO_LE32(sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + pal_size + bytewidth * h);
00117 bfh.reserved = 0;
00118 bfh.off_bits = TO_LE32(sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + pal_size);
00119
00120
00121 BitmapInfoHeader bih;
00122 bih.size = TO_LE32(sizeof(BitmapInfoHeader));
00123 bih.width = TO_LE32(w);
00124 bih.height = TO_LE32(h);
00125 bih.planes = TO_LE16(1);
00126 bih.bitcount = TO_LE16(bpp * 8);
00127 bih.compression = 0;
00128 bih.sizeimage = 0;
00129 bih.xpels = 0;
00130 bih.ypels = 0;
00131 bih.clrused = 0;
00132 bih.clrimp = 0;
00133
00134
00135 if (fwrite(&bfh, sizeof(bfh), 1, f) != 1 || fwrite(&bih, sizeof(bih), 1, f) != 1) {
00136 fclose(f);
00137 return false;
00138 }
00139
00140 if (pixelformat == 8) {
00141
00142 RgbQuad rq[256];
00143 for (uint i = 0; i < 256; i++) {
00144 rq[i].red = palette[i].r;
00145 rq[i].green = palette[i].g;
00146 rq[i].blue = palette[i].b;
00147 rq[i].reserved = 0;
00148 }
00149
00150 if (fwrite(rq, sizeof(rq), 1, f) != 1) {
00151 fclose(f);
00152 return false;
00153 }
00154 }
00155
00156
00157 uint maxlines = Clamp(65536 / (w * pixelformat / 8), 16, 128);
00158
00159 uint8 *buff = MallocT<uint8>(maxlines * w * pixelformat / 8);
00160 uint8 *line = AllocaM(uint8, bytewidth);
00161 memset(line, 0, bytewidth);
00162
00163
00164 do {
00165 uint n = min(h, maxlines);
00166 h -= n;
00167
00168
00169 callb(userdata, buff, h, w, n);
00170
00171
00172 while (n-- != 0) {
00173 if (pixelformat == 8) {
00174
00175 memcpy(line, buff + n * w, w);
00176 } else {
00177
00178
00179 Colour *src = ((Colour *)buff) + n * w;
00180 byte *dst = line;
00181 for (uint i = 0; i < w; i++) {
00182 dst[i * 3 ] = src[i].b;
00183 dst[i * 3 + 1] = src[i].g;
00184 dst[i * 3 + 2] = src[i].r;
00185 }
00186 }
00187
00188 if (fwrite(line, bytewidth, 1, f) != 1) {
00189 free(buff);
00190 fclose(f);
00191 return false;
00192 }
00193 }
00194 } while (h != 0);
00195
00196 free(buff);
00197 fclose(f);
00198
00199 return true;
00200 }
00201
00202
00203
00204
00205 #if defined(WITH_PNG)
00206 #include <png.h>
00207
00208 #ifdef PNG_TEXT_SUPPORTED
00209 #include "rev.h"
00210 #include "newgrf_config.h"
00211 #include "ai/ai_info.hpp"
00212 #include "company_base.h"
00213 #include "base_media_base.h"
00214 #endif
00215
00216 static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
00217 {
00218 DEBUG(misc, 0, "[libpng] error: %s - %s", message, (const char *)png_get_error_ptr(png_ptr));
00219 longjmp(png_jmpbuf(png_ptr), 1);
00220 }
00221
00222 static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
00223 {
00224 DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (const char *)png_get_error_ptr(png_ptr));
00225 }
00226
00227 static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
00228 {
00229 png_color rq[256];
00230 FILE *f;
00231 uint i, y, n;
00232 uint maxlines;
00233 uint bpp = pixelformat / 8;
00234 png_structp png_ptr;
00235 png_infop info_ptr;
00236
00237
00238 if (pixelformat != 8 && pixelformat != 32) return false;
00239
00240 f = fopen(name, "wb");
00241 if (f == NULL) return false;
00242
00243 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *)name, png_my_error, png_my_warning);
00244
00245 if (png_ptr == NULL) {
00246 fclose(f);
00247 return false;
00248 }
00249
00250 info_ptr = png_create_info_struct(png_ptr);
00251 if (info_ptr == NULL) {
00252 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00253 fclose(f);
00254 return false;
00255 }
00256
00257 if (setjmp(png_jmpbuf(png_ptr))) {
00258 png_destroy_write_struct(&png_ptr, &info_ptr);
00259 fclose(f);
00260 return false;
00261 }
00262
00263 png_init_io(png_ptr, f);
00264
00265 png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
00266
00267 png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
00268 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00269
00270 #ifdef PNG_TEXT_SUPPORTED
00271
00272
00273 png_text_struct text[2];
00274 memset(text, 0, sizeof(text));
00275 text[0].key = const_cast<char *>("Software");
00276 text[0].text = const_cast<char *>(_openttd_revision);
00277 text[0].text_length = strlen(_openttd_revision);
00278 text[0].compression = PNG_TEXT_COMPRESSION_NONE;
00279
00280 char buf[8192];
00281 char *p = buf;
00282 p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version);
00283 p = strecpy(p, "NewGRFs:\n", lastof(buf));
00284 for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) {
00285 p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid));
00286 p = md5sumToString(p, lastof(buf), c->ident.md5sum);
00287 p += seprintf(p, lastof(buf), " %s\n", c->filename);
00288 }
00289 p = strecpy(p, "\nCompanies:\n", lastof(buf));
00290 const Company *c;
00291 FOR_ALL_COMPANIES(c) {
00292 if (c->ai_info == NULL) {
00293 p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index);
00294 } else {
00295 #ifdef ENABLE_AI
00296 p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
00297 #endif
00298 }
00299 }
00300 text[1].key = const_cast<char *>("Description");
00301 text[1].text = buf;
00302 text[1].text_length = p - buf;
00303 text[1].compression = PNG_TEXT_COMPRESSION_zTXt;
00304 png_set_text(png_ptr, info_ptr, text, 2);
00305 #endif
00306
00307 if (pixelformat == 8) {
00308
00309 for (i = 0; i != 256; i++) {
00310 rq[i].red = palette[i].r;
00311 rq[i].green = palette[i].g;
00312 rq[i].blue = palette[i].b;
00313 }
00314
00315 png_set_PLTE(png_ptr, info_ptr, rq, 256);
00316 }
00317
00318 png_write_info(png_ptr, info_ptr);
00319 png_set_flush(png_ptr, 512);
00320
00321 if (pixelformat == 32) {
00322 png_color_8 sig_bit;
00323
00324
00325 sig_bit.alpha = 0;
00326 sig_bit.blue = 8;
00327 sig_bit.green = 8;
00328 sig_bit.red = 8;
00329 sig_bit.gray = 8;
00330 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
00331
00332 #if TTD_ENDIAN == TTD_LITTLE_ENDIAN
00333 png_set_bgr(png_ptr);
00334 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
00335 #else
00336 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
00337 #endif
00338 }
00339
00340
00341 maxlines = Clamp(65536 / w, 16, 128);
00342
00343
00344 void *buff = CallocT<uint8>(w * maxlines * bpp);
00345
00346 y = 0;
00347 do {
00348
00349 n = min(h - y, maxlines);
00350
00351
00352 callb(userdata, buff, y, w, n);
00353 y += n;
00354
00355
00356 for (i = 0; i != n; i++) {
00357 png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
00358 }
00359 } while (y != h);
00360
00361 png_write_end(png_ptr, info_ptr);
00362 png_destroy_write_struct(&png_ptr, &info_ptr);
00363
00364 free(buff);
00365 fclose(f);
00366 return true;
00367 }
00368 #endif
00369
00370
00371
00372
00373
00374
00375 struct PcxHeader {
00376 byte manufacturer;
00377 byte version;
00378 byte rle;
00379 byte bpp;
00380 uint32 unused;
00381 uint16 xmax, ymax;
00382 uint16 hdpi, vdpi;
00383 byte pal_small[16 * 3];
00384 byte reserved;
00385 byte planes;
00386 uint16 pitch;
00387 uint16 cpal;
00388 uint16 width;
00389 uint16 height;
00390 byte filler[54];
00391 };
00392 assert_compile(sizeof(PcxHeader) == 128);
00393
00394 static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
00395 {
00396 FILE *f;
00397 uint maxlines;
00398 uint y;
00399 PcxHeader pcx;
00400 bool success;
00401
00402 if (pixelformat == 32) {
00403 DEBUG(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick another format.");
00404 return false;
00405 }
00406 if (pixelformat != 8 || w == 0) return false;
00407
00408 f = fopen(name, "wb");
00409 if (f == NULL) return false;
00410
00411 memset(&pcx, 0, sizeof(pcx));
00412
00413
00414 pcx.manufacturer = 10;
00415 pcx.version = 5;
00416 pcx.rle = 1;
00417 pcx.bpp = 8;
00418 pcx.xmax = TO_LE16(w - 1);
00419 pcx.ymax = TO_LE16(h - 1);
00420 pcx.hdpi = TO_LE16(320);
00421 pcx.vdpi = TO_LE16(320);
00422
00423 pcx.planes = 1;
00424 pcx.cpal = TO_LE16(1);
00425 pcx.width = pcx.pitch = TO_LE16(w);
00426 pcx.height = TO_LE16(h);
00427
00428
00429 if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
00430 fclose(f);
00431 return false;
00432 }
00433
00434
00435 maxlines = Clamp(65536 / w, 16, 128);
00436
00437
00438 uint8 *buff = CallocT<uint8>(w * maxlines);
00439
00440 y = 0;
00441 do {
00442
00443 uint n = min(h - y, maxlines);
00444 uint i;
00445
00446
00447 callb(userdata, buff, y, w, n);
00448 y += n;
00449
00450
00451 for (i = 0; i != n; i++) {
00452 const uint8 *bufp = buff + i * w;
00453 byte runchar = bufp[0];
00454 uint runcount = 1;
00455 uint j;
00456
00457
00458 for (j = 1; j < w; j++) {
00459 uint8 ch = bufp[j];
00460
00461 if (ch != runchar || runcount >= 0x3f) {
00462 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
00463 if (fputc(0xC0 | runcount, f) == EOF) {
00464 free(buff);
00465 fclose(f);
00466 return false;
00467 }
00468 }
00469 if (fputc(runchar, f) == EOF) {
00470 free(buff);
00471 fclose(f);
00472 return false;
00473 }
00474 runcount = 0;
00475 runchar = ch;
00476 }
00477 runcount++;
00478 }
00479
00480
00481 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
00482 if (fputc(0xC0 | runcount, f) == EOF) {
00483 free(buff);
00484 fclose(f);
00485 return false;
00486 }
00487 }
00488 if (fputc(runchar, f) == EOF) {
00489 free(buff);
00490 fclose(f);
00491 return false;
00492 }
00493 }
00494 } while (y != h);
00495
00496 free(buff);
00497
00498
00499 if (fputc(12, f) == EOF) {
00500 fclose(f);
00501 return false;
00502 }
00503
00504
00505 byte tmp[256 * 3];
00506
00507 for (uint i = 0; i < 256; i++) {
00508 tmp[i * 3 + 0] = palette[i].r;
00509 tmp[i * 3 + 1] = palette[i].g;
00510 tmp[i * 3 + 2] = palette[i].b;
00511 }
00512 success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
00513
00514 fclose(f);
00515
00516 return success;
00517 }
00518
00519
00520
00521
00522
00523 static const ScreenshotFormat _screenshot_formats[] = {
00524 #if defined(WITH_PNG)
00525 {"PNG", "png", &MakePNGImage},
00526 #endif
00527 {"BMP", "bmp", &MakeBMPImage},
00528 {"PCX", "pcx", &MakePCXImage},
00529 };
00530
00531 void InitializeScreenshotFormats()
00532 {
00533 uint j = 0;
00534 for (uint i = 0; i < lengthof(_screenshot_formats); i++) {
00535 if (!strcmp(_screenshot_format_name, _screenshot_formats[i].extension)) {
00536 j = i;
00537 break;
00538 }
00539 }
00540 _cur_screenshot_format = j;
00541 _num_screenshot_formats = lengthof(_screenshot_formats);
00542 }
00543
00544 const char *GetScreenshotFormatDesc(int i)
00545 {
00546 return _screenshot_formats[i].name;
00547 }
00548
00549 void SetScreenshotFormat(uint i)
00550 {
00551 assert(i < _num_screenshot_formats);
00552 _cur_screenshot_format = i;
00553 strecpy(_screenshot_format_name, _screenshot_formats[i].extension, lastof(_screenshot_format_name));
00554 }
00555
00556
00557 static void CurrentScreenCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
00558 {
00559 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00560 void *src = blitter->MoveTo(_screen.dst_ptr, 0, y);
00561 blitter->CopyImageToBuffer(src, buf, _screen.width, n, pitch);
00562 }
00563
00572 static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, uint n)
00573 {
00574 ViewPort *vp = (ViewPort *)userdata;
00575 DrawPixelInfo dpi, *old_dpi;
00576 int wx, left;
00577
00578
00579 DrawPixelInfo old_screen = _screen;
00580 bool old_disable_anim = _screen_disable_anim;
00581
00582 _screen.dst_ptr = buf;
00583 _screen.width = pitch;
00584 _screen.height = n;
00585 _screen.pitch = pitch;
00586 _screen_disable_anim = true;
00587
00588 old_dpi = _cur_dpi;
00589 _cur_dpi = &dpi;
00590
00591 dpi.dst_ptr = buf;
00592 dpi.height = n;
00593 dpi.width = vp->width;
00594 dpi.pitch = pitch;
00595 dpi.zoom = ZOOM_LVL_WORLD_SCREENSHOT;
00596 dpi.left = 0;
00597 dpi.top = y;
00598
00599
00600 left = 0;
00601 while (vp->width - left != 0) {
00602 wx = min(vp->width - left, 1600);
00603 left += wx;
00604
00605 ViewportDoDraw(vp,
00606 ScaleByZoom(left - wx - vp->left, vp->zoom) + vp->virtual_left,
00607 ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top,
00608 ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left,
00609 ScaleByZoom((y + n) - vp->top, vp->zoom) + vp->virtual_top
00610 );
00611 }
00612
00613 _cur_dpi = old_dpi;
00614
00615
00616 _screen = old_screen;
00617 _screen_disable_anim = old_disable_anim;
00618 }
00619
00620 static const char *MakeScreenshotName(const char *ext)
00621 {
00622 bool generate = StrEmpty(_screenshot_name);
00623
00624 if (generate) {
00625 if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_company == COMPANY_SPECTATOR) {
00626 strecpy(_screenshot_name, "screenshot", lastof(_screenshot_name));
00627 } else {
00628 GenerateDefaultSaveName(_screenshot_name, lastof(_screenshot_name));
00629 }
00630 }
00631
00632
00633 size_t len = strlen(_screenshot_name);
00634 snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, ".%s", ext);
00635
00636 for (uint serial = 1;; serial++) {
00637 if (snprintf(_full_screenshot_name, lengthof(_full_screenshot_name), "%s%s", _personal_dir, _screenshot_name) >= (int)lengthof(_full_screenshot_name)) {
00638
00639 _full_screenshot_name[0] = '\0';
00640 break;
00641 }
00642 if (!generate) break;
00643 if (!FileExists(_full_screenshot_name)) break;
00644
00645 snprintf(&_screenshot_name[len], lengthof(_screenshot_name) - len, "#%u.%s", serial, ext);
00646 }
00647
00648 return _full_screenshot_name;
00649 }
00650
00652 static bool MakeSmallScreenshot()
00653 {
00654 const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
00655 return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
00656 }
00657
00659 static bool MakeZoomedInScreenshot()
00660 {
00661 Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
00662 ViewPort vp;
00663
00664 vp.zoom = ZOOM_LVL_WORLD_SCREENSHOT;
00665 vp.left = w->viewport->left;
00666 vp.top = w->viewport->top;
00667 vp.virtual_left = w->viewport->virtual_left;
00668 vp.virtual_top = w->viewport->virtual_top;
00669 vp.virtual_width = w->viewport->virtual_width;
00670 vp.width = vp.virtual_width;
00671 vp.virtual_height = w->viewport->virtual_height;
00672 vp.height = vp.virtual_height;
00673
00674 const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
00675 return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
00676 }
00677
00679 static bool MakeWorldScreenshot()
00680 {
00681 ViewPort vp;
00682 const ScreenshotFormat *sf;
00683
00684
00685 int extra_height_top = TileHeight(0) * TILE_HEIGHT + 150;
00686
00687 int reclaim_height_bottom = TileHeight(MapSize() - 1) * TILE_HEIGHT;
00688
00689 vp.zoom = ZOOM_LVL_WORLD_SCREENSHOT;
00690 vp.left = 0;
00691 vp.top = 0;
00692 vp.virtual_left = -(int)MapMaxX() * TILE_PIXELS;
00693 vp.virtual_top = -extra_height_top;
00694 vp.virtual_width = (MapMaxX() + MapMaxY()) * TILE_PIXELS;
00695 vp.width = vp.virtual_width;
00696 vp.virtual_height = ((MapMaxX() + MapMaxY()) * TILE_PIXELS >> 1) + extra_height_top - reclaim_height_bottom;
00697 vp.height = vp.virtual_height;
00698
00699 sf = _screenshot_formats + _cur_screenshot_format;
00700 return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette);
00701 }
00702
00709 bool MakeScreenshot(ScreenshotType t, const char *name)
00710 {
00711 if (t == SC_VIEWPORT) {
00712
00713
00714
00715
00716 UndrawMouseCursor();
00717 DrawDirtyBlocks();
00718 }
00719
00720 _screenshot_name[0] = '\0';
00721 if (name != NULL) strecpy(_screenshot_name, name, lastof(_screenshot_name));
00722
00723 bool ret;
00724 switch (t) {
00725 case SC_VIEWPORT:
00726 case SC_RAW:
00727 ret = MakeSmallScreenshot();
00728 break;
00729
00730 case SC_ZOOMEDIN:
00731 ret = MakeZoomedInScreenshot();
00732 break;
00733
00734 case SC_WORLD:
00735 ret = MakeWorldScreenshot();
00736 break;
00737
00738 default:
00739 NOT_REACHED();
00740 }
00741
00742 if (ret) {
00743 SetDParamStr(0, _screenshot_name);
00744 ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING);
00745 } else {
00746 ShowErrorMessage(STR_ERROR_SCREENSHOT_FAILED, INVALID_STRING_ID, WL_ERROR);
00747 }
00748
00749 return ret;
00750 }