/* * Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck, Ronald Lamprecht * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "gui/LevelPreviewCache.hh" #include "ecl.hh" #include "file.hh" #include "game.hh" #include "main.hh" #include "video.hh" #include "lev/Proxy.hh" #include "SDL.h" #include using namespace ecl; using namespace std; namespace enigma { namespace gui { /* -------------------- LevelPreviewCache -------------------- */ LevelPreviewCache *LevelPreviewCache::theSingleton = 0; LevelPreviewCache* LevelPreviewCache::instance() { if (theSingleton == 0) { theSingleton = new LevelPreviewCache(); } return theSingleton; } LevelPreviewCache::LevelPreviewCache() : cachedIndex (NULL) { } void LevelPreviewCache::clear() { Log << "LevelPreviewCache clear\n"; cache.clear(); imgCache.clear(); } Surface *LevelPreviewCache::getPreview(lev::Proxy *levelProxy, bool allowGeneration, bool &didGenerate) { didGenerate = false; std::string mapIndex = levelProxy->getId() + ecl::strf("#%d", levelProxy->getReleaseVersion()); // first look in cache PreviewMap::iterator i = cache.find(mapIndex); if (i != cache.end()) return i->second; // we have to cache a new preview - check if we should clear cache first if (cachedIndex == NULL) { // remember the index we are caching cachedIndex = lev::Index::getCurrentIndex(); } else if (cachedIndex != lev::Index::getCurrentIndex()) { //the index changed - cache only previews from new index clear(); cachedIndex = lev::Index::getCurrentIndex(); } std::string previewSubPath = makePreviewPath(levelProxy); Surface *surface = 0; // load preview from file bundled with the level itself std::string absLevelPath ; std::auto_ptr isptr; ByteVec imageData; if(levelProxy->getNormPathType() == lev::Proxy::pt_resource && app.resourceFS->findFile ("levels/" + levelProxy->getNormLevelPath() + ".png", absLevelPath, isptr)) { // load plain image file or zipped image if (isptr.get() != NULL) { // zipped file Readfile (*isptr, imageData); } else { // plain file basic_ifstream ifs(absLevelPath.c_str(), ios::binary | ios::in); Readfile (ifs, imageData); } SDL_RWops *imageHandle = SDL_RWFromMem(&(imageData[0]), imageData.size()); surface = ecl::LoadImage(imageHandle, 1); imgCache.store(previewSubPath, surface); // insert in imgCache } // load preview from stored file if possible string previewFullPath; if (!surface && app.resourceFS->findFile(previewSubPath, previewFullPath)) surface = imgCache.get(previewFullPath); // generate new preview otherwise if (!surface && allowGeneration) { surface = newPreview(levelProxy); if (surface) { imgCache.store(previewSubPath, surface); // insert in imgCache savePreview(levelProxy, surface); // save on filesystem } else { surface = enigma::GetImage("error"); } didGenerate = true; } // update index if (surface) cache[mapIndex] = surface; return surface; } ecl::Surface *LevelPreviewCache::newPreview (lev::Proxy *levelProxy) { const video::VMInfo &vminfo = *video::GetInfo(); Surface *surface = 0; ecl::GC gc(video::BackBuffer()); if (game::DrawLevelPreview (gc, levelProxy)) { surface = Resample (video::BackBuffer(), vminfo.gamearea, vminfo.thumbw, vminfo.thumbh); } return surface; } Surface *LevelPreviewCache::updatePreview (lev::Proxy *levelProxy) { if (Surface *surface = newPreview (levelProxy)) { std::string idx = levelProxy->getId() + ecl::strf("#%d", levelProxy->getReleaseVersion()); cache[idx] = surface; string preview_name = makePreviewPath(levelProxy); imgCache.store (preview_name, surface); // insert in imgCache savePreview(levelProxy, surface); // save on filesystem return surface; } return 0; } std::string LevelPreviewCache::makePreviewPath(lev::Proxy *levelProxy) { return "thumbs/" + levelProxy->getLocalSubstitutionLevelPath() + ecl::strf("#%d", levelProxy->getReleaseVersion()) + ".png"; } void LevelPreviewCache::savePreview(lev::Proxy *levelProxy, ecl::Surface *s) { std::string savePath = app.userImagePath + "/" + makePreviewPath(levelProxy); Log << "savePreview to " << savePath << "\n"; // auto-create the directory if necessary string directory; if (ecl::split_path (savePath, &directory, 0) && !ecl::FolderExists(directory)) { ecl::FolderCreate (directory); } ecl::SavePNG(s, savePath); } void LevelPreviewCache::makeSystemPreview(lev::Proxy *levelProxy, std::string systemDataPath) { std::string savePath = systemDataPath + "/levels/" + levelProxy->getNormLevelPath() + ".png"; // auto-create the directory if necessary -- on an installed Enigma // distribution this is of course unnecessary, but you start Enigma // without prior installation. This is useful to get a directory with // just the previews. string directory; if (ecl::split_path (savePath, &directory, 0) && !ecl::FolderExists(directory)) { ecl::FolderCreate (directory); } ecl::Surface * s = newPreview(levelProxy); if (s != NULL) ecl::SavePNG(s, savePath); } }} // namespace enigma::gui