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