本文整理汇总了C++中OsPath::string方法的典型用法代码示例。如果您正苦于以下问题:C++ OsPath::string方法的具体用法?C++ OsPath::string怎么用?C++ OsPath::string使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类OsPath
的用法示例。
在下文中一共展示了OsPath::string方法的12个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: Initialise
bool Initialise(bool callConstructor)
{
if (!LoadScripts(m_AIName))
return false;
OsPath path = L"simulation/ai/" + m_AIName + L"/data.json";
CScriptValRooted metadata = m_Worker.LoadMetadata(path);
if (metadata.uninitialised())
{
LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str());
return false;
}
// Get the constructor name from the metadata
std::string constructor;
if (!m_ScriptInterface.GetProperty(metadata.get(), "constructor", constructor))
{
LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str());
return false;
}
// Get the constructor function from the loaded scripts
CScriptVal ctor;
if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor)
|| ctor.undefined())
{
LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str());
return false;
}
CScriptVal obj;
if (callConstructor)
{
// Set up the data to pass as the constructor argument
CScriptVal settings;
m_ScriptInterface.Eval(L"({})", settings);
m_ScriptInterface.SetProperty(settings.get(), "player", m_Player, false);
ENSURE(m_Worker.m_HasLoadedEntityTemplates);
m_ScriptInterface.SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false);
obj = m_ScriptInterface.CallConstructor(ctor.get(), settings.get());
}
else
{
// For deserialization, we want to create the object with the correct prototype
// but don't want to actually run the constructor again
// XXX: actually we don't currently use this path for deserialization - maybe delete it?
obj = m_ScriptInterface.NewObjectFromConstructor(ctor.get());
}
if (obj.undefined())
{
LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str());
return false;
}
m_Obj = CScriptValRooted(m_ScriptInterface.GetContext(), obj);
return true;
}
示例2: OsPath
/*static*/ OsPath Paths::Root(const OsPath& argv0)
{
#if OS_ANDROID
return OsPath("/sdcard/0ad"); // TODO: this is kind of bogus
#else
// get full path to executable
OsPath pathname = sys_ExecutablePathname(); // safe, but requires OS-specific implementation
if(pathname.empty()) // failed, use argv[0] instead
{
errno = 0;
pathname = wrealpath(argv0);
if(pathname.empty())
WARN_IF_ERR(StatusFromErrno());
}
// make sure it's valid
if(!FileExists(pathname))
{
LOGERROR(L"Cannot find executable (expected at '%ls')", pathname.string().c_str());
WARN_IF_ERR(StatusFromErrno());
}
for(size_t i = 0; i < 2; i++) // remove "system/name.exe"
pathname = pathname.Parent();
return pathname;
#endif
}
示例3: SaveToFile
void CProfileViewer::SaveToFile()
{
// Open the file, if necessary. If this method is called several times,
// the profile results will be appended to the previous ones from the same
// run.
if (! m->outputStream.is_open())
{
// Open the file. (It will be closed when the CProfileViewer
// destructor is called.)
OsPath path = psLogDir()/"profile.txt";
m->outputStream.open(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
if (m->outputStream.fail())
{
LOGERROR(L"Failed to open profile log file");
return;
}
else
{
LOGMESSAGERENDER(L"Profiler snapshot saved to '%ls'", path.string().c_str());
}
}
time_t t;
time(&t);
m->outputStream << "================================================================\n\n";
m->outputStream << "PS profiler snapshot - " << asctime(localtime(&t));
std::vector<AbstractProfileTable*> tables = m->rootTables;
sort(tables.begin(), tables.end(), SortByName);
for_each(tables.begin(), tables.end(), WriteTable(m->outputStream));
m->outputStream << "\n\n================================================================\n";
m->outputStream.flush();
}
示例4: CreateDirectories
Status CreateDirectories(const OsPath& path, mode_t mode)
{
if(path.empty())
return INFO::OK;
struct stat s;
if(wstat(path, &s) == 0)
{
if(!S_ISDIR(s.st_mode)) // encountered a file
WARN_RETURN(ERR::FAIL);
return INFO::OK;
}
// If we were passed a path ending with '/', strip the '/' now so that
// we can consistently use Parent to find parent directory names
if(path.IsDirectory())
return CreateDirectories(path.Parent(), mode);
RETURN_STATUS_IF_ERR(CreateDirectories(path.Parent(), mode));
errno = 0;
if(wmkdir(path, mode) != 0)
{
debug_printf(L"CreateDirectories: failed to mkdir %ls (mode %d)", path.string().c_str(), mode);
WARN_RETURN(StatusFromErrno());
}
return INFO::OK;
}
示例5: loader
std::vector<CScriptValRooted> SavedGames::GetSavedGames(ScriptInterface& scriptInterface)
{
TIMER(L"GetSavedGames");
std::vector<CScriptValRooted> games;
Status err;
VfsPaths pathnames;
err = vfs::GetPathnames(g_VFS, "saves/", L"*.0adsave", pathnames);
WARN_IF_ERR(err);
for (size_t i = 0; i < pathnames.size(); ++i)
{
OsPath realPath;
err = g_VFS->GetRealPath(pathnames[i], realPath);
if (err < 0)
{
DEBUG_WARN_ERR(err);
continue; // skip this file
}
PIArchiveReader archiveReader = CreateArchiveReader_Zip(realPath);
if (!archiveReader)
{
// Triggered by e.g. the file being open in another program
LOGWARNING(L"Failed to read saved game '%ls'", realPath.string().c_str());
continue; // skip this file
}
CScriptValRooted metadata;
CGameLoader loader(scriptInterface, &metadata, NULL);
err = archiveReader->ReadEntries(CGameLoader::ReadEntryCallback, (uintptr_t)&loader);
if (err < 0)
{
DEBUG_WARN_ERR(err);
continue; // skip this file
}
CScriptValRooted game;
scriptInterface.Eval("({})", game);
scriptInterface.SetProperty(game.get(), "id", pathnames[i].Basename());
scriptInterface.SetProperty(game.get(), "metadata", metadata);
games.push_back(game);
}
return games;
}
示例6: WriteScreenshot
// <extension> identifies the file format that is to be written
// (case-insensitive). examples: "bmp", "png", "jpg".
// BMP is good for quick output at the expense of large files.
void WriteScreenshot(const VfsPath& extension)
{
// get next available numbered filename
// note: %04d -> always 4 digits, so sorting by filename works correctly.
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
VfsPath filename;
vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
const size_t w = (size_t)g_xres, h = (size_t)g_yres;
const size_t bpp = 24;
GLenum fmt = GL_RGB;
int flags = TEX_BOTTOM_UP;
// we want writing BMP to be as fast as possible,
// so read data from OpenGL in BMP format to obviate conversion.
if(extension == L".bmp")
{
#if !CONFIG2_GLES // GLES doesn't support BGR
fmt = GL_BGR;
flags |= TEX_BGR;
#endif
}
// Hide log messages and re-render
RenderLogger(false);
Render();
RenderLogger(true);
const size_t img_size = w * h * bpp/8;
const size_t hdr_size = tex_hdr_size(filename);
shared_ptr<u8> buf;
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
GLvoid* img = buf.get() + hdr_size;
Tex t;
if(t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
return;
glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
if (tex_write(&t, filename) == INFO::OK)
{
OsPath realPath;
g_VFS->GetRealPath(filename, realPath);
LOGMESSAGERENDER(L"Screenshot written to '%ls'", realPath.string().c_str());
}
else
LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str());
}
示例7: dir_watch_Add
Status dir_watch_Add(const OsPath& path, PDirWatch& dirWatch)
{
PDirWatch tmpDirWatch(new DirWatch);
dirWatch.swap(tmpDirWatch);
dirWatch->path = path;
dirWatch->reqnum = 0;
g_Paths.push_back( *dirWatch );
bool alreadyInsideRootPath = false;
for ( DirWatchMap::iterator it = g_RootPaths.begin() ; it != g_RootPaths.end(); ++it)
{
if ( path_is_subpath( path.string().c_str(), it->path.string().c_str() ) )
alreadyInsideRootPath = true;
}
if ( !alreadyInsideRootPath )
{
DeleteEventStream();
g_RootPaths.push_back( *dirWatch );
}
return INFO::OK;
}
示例8: fsevent_callback
static void fsevent_callback(
ConstFSEventStreamRef UNUSED(streamRef),
void * UNUSED(clientCallBackInfo),
size_t numEvents,
void *eventPaths,
const FSEventStreamEventFlags eventFlags[],
const FSEventStreamEventId UNUSED(eventIds)[] )
{
unsigned long i;
char **paths = (char **)eventPaths;
for (i=0; i<numEvents; i++)
{
bool isWatched = false;
OsPath eventPath = OsPath(paths[i]);
unsigned long eventType = eventFlags[i];
if ( eventPath.Filename().string().c_str()[0] != '.' )
{
for ( DirWatchMap::iterator it = g_Paths.begin() ; it != g_Paths.end(); ++it)
if ( path_is_subpath( it->path.string().c_str(), eventPath.string().c_str() ) )
isWatched = true;
}
if ( ! isWatched )
return;
OsPath filename = Path( eventPath.string().c_str() );
if ( eventType & kFSEventStreamEventFlagItemIsFile)
{
if ( eventType & kFSEventStreamEventFlagItemRemoved )
g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Deleted ));
else if ( eventType & kFSEventStreamEventFlagItemRenamed )
g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Deleted ));
else if ( eventType & kFSEventStreamEventFlagItemCreated )
g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Created ));
else if ( eventType & kFSEventStreamEventFlagItemModified )
g_QueuedDirs.push_back(DirWatchNotification( filename.string().c_str(), DirWatchNotification::Changed ));
}
}
}
示例9: Initialise
bool Initialise(bool callConstructor)
{
// LoadScripts will only load each script once even though we call it for each player
if (!m_Worker.LoadScripts(m_AIName))
return false;
OsPath path = L"simulation/ai/" + m_AIName + L"/data.json";
CScriptValRooted metadata = m_Worker.LoadMetadata(path);
if (metadata.uninitialised())
{
LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str());
return false;
}
// Get the constructor name from the metadata
// If the AI doesn't use modules, we look for the constructor in the global object
// TODO: All AIs should use modules. Remove the condition if this requirement is met.
std::string moduleName;
std::string constructor;
CScriptVal objectWithConstructor; // object that should contain the constructor function
CScriptVal ctor;
if (!m_ScriptInterface->HasProperty(metadata.get(), "moduleName"))
{
objectWithConstructor = m_ScriptInterface->GetGlobalObject();
}
else
{
m_ScriptInterface->GetProperty(metadata.get(), "moduleName", moduleName);
if(!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), moduleName.c_str(), objectWithConstructor) || objectWithConstructor.undefined())
{
LOGERROR(L"Failed to create AI player: %ls: can't find the module that should contain the constructor: '%hs'", path.string().c_str(), moduleName.c_str());
return false;
}
}
if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor))
{
LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str());
return false;
}
// Get the constructor function from the loaded scripts
if (!m_ScriptInterface->GetProperty(objectWithConstructor.get(), constructor.c_str(), ctor)
|| ctor.undefined())
{
LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str());
return false;
}
m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent);
CScriptVal obj;
if (callConstructor)
{
// Set up the data to pass as the constructor argument
CScriptVal settings;
m_ScriptInterface->Eval(L"({})", settings);
m_ScriptInterface->SetProperty(settings.get(), "player", m_Player, false);
m_ScriptInterface->SetProperty(settings.get(), "difficulty", m_Difficulty, false);
ENSURE(m_Worker.m_HasLoadedEntityTemplates);
m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false);
obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get());
}
else
{
// For deserialization, we want to create the object with the correct prototype
// but don't want to actually run the constructor again
// XXX: actually we don't currently use this path for deserialization - maybe delete it?
obj = m_ScriptInterface->NewObjectFromConstructor(ctor.get());
}
if (obj.undefined())
{
LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str());
return false;
}
m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj);
return true;
}
示例10: Build
void CArchiveBuilder::Build(const OsPath& archive, bool compress)
{
// By default we disable zip compression because it significantly hurts download
// size for releases (which re-compress all files with better compression
// algorithms) - it's probably most important currently to optimise for
// download size rather than install size or startup performance.
// (See http://trac.wildfiregames.com/ticket/671)
const bool noDeflate = !compress;
PIArchiveWriter writer = CreateArchiveWriter_Zip(archive, noDeflate);
// Use CTextureManager instead of CTextureConverter directly,
// so it can deal with all the loading of settings.xml files
CTextureManager textureManager(m_VFS, true, true);
CColladaManager colladaManager(m_VFS);
CXeromyces xero;
for (size_t i = 0; i < m_Files.size(); ++i)
{
Status ret;
const VfsPath path = m_Files[i];
OsPath realPath;
ret = m_VFS->GetRealPath(path, realPath);
ENSURE(ret == INFO::OK);
// Compress textures and store the new cached version instead of the original
if ((boost::algorithm::starts_with(path.string(), L"art/textures/") ||
boost::algorithm::starts_with(path.string(), L"fonts/")
) &&
tex_is_known_extension(path) &&
// Skip some subdirectories where the engine doesn't use CTextureManager yet:
!boost::algorithm::starts_with(path.string(), L"art/textures/cursors/") &&
!boost::algorithm::starts_with(path.string(), L"art/textures/terrain/alphamaps/")
)
{
VfsPath cachedPath;
debug_printf(L"Converting texture %ls\n", realPath.string().c_str());
bool ok = textureManager.GenerateCachedTexture(path, cachedPath);
ENSURE(ok);
OsPath cachedRealPath;
ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath);
ENSURE(ret == INFO::OK);
writer->AddFile(cachedRealPath, cachedPath);
// We don't want to store the original file too (since it's a
// large waste of space), so skip to the next file
continue;
}
// Convert DAE models and store the new cached version instead of the original
if (path.Extension() == L".dae")
{
CColladaManager::FileType type;
if (boost::algorithm::starts_with(path.string(), L"art/meshes/"))
type = CColladaManager::PMD;
else if (boost::algorithm::starts_with(path.string(), L"art/animation/"))
type = CColladaManager::PSA;
else
{
// Unknown type of DAE, just add to archive and continue
writer->AddFile(realPath, path);
continue;
}
VfsPath cachedPath;
debug_printf(L"Converting model %ls\n", realPath.string().c_str());
bool ok = colladaManager.GenerateCachedFile(path, type, cachedPath);
// The DAE might fail to convert for whatever reason, and in that case
// it can't be used in the game, so we just exclude it
// (alternatively we could throw release blocking errors on useless files)
if (ok)
{
OsPath cachedRealPath;
ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath);
ENSURE(ret == INFO::OK);
writer->AddFile(cachedRealPath, cachedPath);
}
// We don't want to store the original file too (since it's a
// large waste of space), so skip to the next file
continue;
}
debug_printf(L"Adding %ls\n", realPath.string().c_str());
writer->AddFile(realPath, path);
// Also cache XMB versions of all XML files
if (path.Extension() == L".xml")
{
VfsPath cachedPath;
debug_printf(L"Converting XML file %ls\n", realPath.string().c_str());
bool ok = xero.GenerateCachedXMB(m_VFS, path, cachedPath);
//.........这里部分代码省略.........
示例11: Save
Status SavedGames::Save(const std::wstring& prefix, CSimulation2& simulation, CGUIManager* gui, int playerID)
{
// Determine the filename to save under
const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d");
const VfsPath filenameFormat = basenameFormat.ChangeExtension(L".0adsave");
VfsPath filename;
// Don't make this a static global like NextNumberedFilename expects, because
// that wouldn't work when 'prefix' changes, and because it's not thread-safe
size_t nextSaveNumber = 0;
vfs::NextNumberedFilename(g_VFS, filenameFormat, nextSaveNumber, filename);
// ArchiveWriter_Zip can only write to OsPaths, not VfsPaths,
// but we'd like to handle saved games via VFS.
// To avoid potential confusion from writing with non-VFS then
// reading the same file with VFS, we'll just write to a temporary
// non-VFS path and then load and save again via VFS,
// which is kind of a hack.
OsPath tempSaveFileRealPath;
WARN_RETURN_STATUS_IF_ERR(g_VFS->GetDirectoryRealPath("cache/", tempSaveFileRealPath));
tempSaveFileRealPath = tempSaveFileRealPath / "temp.0adsave";
time_t now = time(NULL);
// Construct the serialized state to be saved
std::stringstream simStateStream;
if (!simulation.SerializeState(simStateStream))
WARN_RETURN(ERR::FAIL);
CScriptValRooted metadata;
simulation.GetScriptInterface().Eval("({})", metadata);
simulation.GetScriptInterface().SetProperty(metadata.get(), "version_major", SAVED_GAME_VERSION_MAJOR);
simulation.GetScriptInterface().SetProperty(metadata.get(), "version_minor", SAVED_GAME_VERSION_MINOR);
simulation.GetScriptInterface().SetProperty(metadata.get(), "time", (double)now);
simulation.GetScriptInterface().SetProperty(metadata.get(), "player", playerID);
simulation.GetScriptInterface().SetProperty(metadata.get(), "initAttributes", simulation.GetInitAttributes());
if (gui)
{
CScriptVal guiMetadata = simulation.GetScriptInterface().CloneValueFromOtherContext(gui->GetScriptInterface(), gui->GetSavedGameData().get());
simulation.GetScriptInterface().SetProperty(metadata.get(), "gui", guiMetadata);
}
std::string metadataString = simulation.GetScriptInterface().StringifyJSON(metadata.get(), true);
// Write the saved game as zip file containing the various components
PIArchiveWriter archiveWriter = CreateArchiveWriter_Zip(tempSaveFileRealPath, false);
if (!archiveWriter)
WARN_RETURN(ERR::FAIL);
WARN_RETURN_STATUS_IF_ERR(archiveWriter->AddMemory((const u8*)metadataString.c_str(), metadataString.length(), now, "metadata.json"));
WARN_RETURN_STATUS_IF_ERR(archiveWriter->AddMemory((const u8*)simStateStream.str().c_str(), simStateStream.str().length(), now, "simulation.dat"));
archiveWriter.reset(); // close the file
WriteBuffer buffer;
FileInfo tempSaveFile;
WARN_RETURN_STATUS_IF_ERR(GetFileInfo(tempSaveFileRealPath, &tempSaveFile));
buffer.Reserve(tempSaveFile.Size());
WARN_RETURN_STATUS_IF_ERR(io::Load(tempSaveFileRealPath, buffer.Data().get(), buffer.Size()));
WARN_RETURN_STATUS_IF_ERR(g_VFS->CreateFile(filename, buffer.Data(), buffer.Size()));
OsPath realPath;
WARN_RETURN_STATUS_IF_ERR(g_VFS->GetRealPath(filename, realPath));
LOGMESSAGERENDER(L"Saved game to %ls\n", realPath.string().c_str());
return INFO::OK;
}
示例12: WriteBigScreenshot
//.........这里部分代码省略.........
const size_t img_size = img_w * img_h * bpp/8;
const size_t tile_size = tile_w * tile_h * bpp/8;
const size_t hdr_size = tex_hdr_size(filename);
void* tile_data = malloc(tile_size);
if(!tile_data)
{
WARN_IF_ERR(ERR::NO_MEM);
return;
}
shared_ptr<u8> img_buf;
AllocateAligned(img_buf, hdr_size+img_size, maxSectorSize);
Tex t;
GLvoid* img = img_buf.get() + hdr_size;
if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0)
{
free(tile_data);
return;
}
ogl_WarnIfError();
// Resize various things so that the sizes and aspect ratios are correct
{
g_Renderer.Resize(tile_w, tile_h);
SViewPort vp = { 0, 0, tile_w, tile_h };
g_Game->GetView()->GetCamera()->SetViewPort(vp);
g_Game->GetView()->SetCameraProjection();
}
#if !CONFIG2_GLES
// Temporarily move everything onto the front buffer, so the user can
// see the exciting progress as it renders (and can tell when it's finished).
// (It doesn't just use SwapBuffers, because it doesn't know whether to
// call the SDL version or the Atlas version.)
GLint oldReadBuffer, oldDrawBuffer;
glGetIntegerv(GL_READ_BUFFER, &oldReadBuffer);
glGetIntegerv(GL_DRAW_BUFFER, &oldDrawBuffer);
glDrawBuffer(GL_FRONT);
glReadBuffer(GL_FRONT);
#endif
// Hide the cursor
CStrW oldCursor = g_CursorName;
g_CursorName = L"";
// Render each tile
for (int tile_y = 0; tile_y < tiles; ++tile_y)
{
for (int tile_x = 0; tile_x < tiles; ++tile_x)
{
// Adjust the camera to render the appropriate region
g_Game->GetView()->GetCamera()->SetProjectionTile(tiles, tile_x, tile_y);
RenderLogger(false);
RenderGui(false);
Render();
RenderGui(true);
RenderLogger(true);
// Copy the tile pixels into the main image
glReadPixels(0, 0, tile_w, tile_h, fmt, GL_UNSIGNED_BYTE, tile_data);
for (int y = 0; y < tile_h; ++y)
{
void* dest = (char*)img + ((tile_y*tile_h + y) * img_w + (tile_x*tile_w)) * bpp/8;
void* src = (char*)tile_data + y * tile_w * bpp/8;
memcpy(dest, src, tile_w * bpp/8);
}
}
}
// Restore the old cursor
g_CursorName = oldCursor;
#if !CONFIG2_GLES
// Restore the buffer settings
glDrawBuffer(oldDrawBuffer);
glReadBuffer(oldReadBuffer);
#endif
// Restore the viewport settings
{
g_Renderer.Resize(g_xres, g_yres);
SViewPort vp = { 0, 0, g_xres, g_yres };
g_Game->GetView()->GetCamera()->SetViewPort(vp);
g_Game->GetView()->SetCameraProjection();
g_Game->GetView()->GetCamera()->SetProjectionTile(1, 0, 0);
}
if (tex_write(&t, filename) == INFO::OK)
{
OsPath realPath;
g_VFS->GetRealPath(filename, realPath);
LOGMESSAGERENDER(L"Screenshot written to '%ls'", realPath.string().c_str());
}
else
LOGERROR(L"Error writing screenshot to '%ls'", filename.string().c_str());
free(tile_data);
}