diff --git a/src/framework/core/resourcemanager.cpp b/src/framework/core/resourcemanager.cpp index 347fab07..bd47d2b8 100644 --- a/src/framework/core/resourcemanager.cpp +++ b/src/framework/core/resourcemanager.cpp @@ -1,223 +1,223 @@ -/* - * Copyright (c) 2010-2012 OTClient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "resourcemanager.h" -#include "filestream.h" - -#include -#include - -#include - -ResourceManager g_resources; - -void ResourceManager::init(const char *argv0) -{ - PHYSFS_init(argv0); -} - -void ResourceManager::terminate() -{ - PHYSFS_deinit(); -} - -bool ResourceManager::setupWriteDir(const std::string& appWriteDirName) -{ - std::string userDir = PHYSFS_getUserDir(); - std::string dirName = Fw::mkstr(".", appWriteDirName); - std::string writeDir = userDir + dirName; - if(!PHYSFS_setWriteDir(writeDir.c_str())) { - if(!PHYSFS_setWriteDir(userDir.c_str())) - return false; - if(!PHYSFS_mkdir(dirName.c_str())) { - PHYSFS_setWriteDir(NULL); - return false; - } - if(!PHYSFS_setWriteDir(writeDir.c_str())) - return false; - } - addToSearchPath(writeDir); - return true; -} - -bool ResourceManager::addToSearchPath(const std::string& path, bool insertInFront) -{ - if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1)) - return false; - return true; -} - -void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const std::string& packageExt, bool append) -{ - auto files = listDirectoryFiles(resolvePath(packagesDir)); - for(const std::string& file : files) { - if(boost::ends_with(file, packageExt)) - addToSearchPath(packagesDir + "/" + file, !append); - } -} - -bool ResourceManager::fileExists(const std::string& fileName) -{ - return (PHYSFS_exists(resolvePath(fileName).c_str()) && !PHYSFS_isDirectory(resolvePath(fileName).c_str())); -} - -bool ResourceManager::directoryExists(const std::string& directoryName) -{ - return (PHYSFS_isDirectory(resolvePath(directoryName).c_str())); -} - -void ResourceManager::loadFile(const std::string& fileName, std::iostream& out) -{ - std::string fullPath = resolvePath(fileName); - out.clear(std::ios::goodbit); - PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str()); - if(!file) { - out.clear(std::ios::failbit); - Fw::throwException("failed to load file '", fullPath.c_str(), "': ", PHYSFS_getLastError()); - } else { - int fileSize = PHYSFS_fileLength(file); - if(fileSize > 0) { - std::vector buffer(fileSize); - PHYSFS_read(file, (void*)&buffer[0], 1, fileSize); - out.write(&buffer[0], fileSize); - } else - out.clear(std::ios::eofbit); - PHYSFS_close(file); - out.seekg(0, std::ios::beg); - } -} - -std::string ResourceManager::loadFile(const std::string& fileName) -{ - std::stringstream fin; - loadFile(fileName, fin); - return fin.str(); -} - -bool ResourceManager::saveFile(const std::string& fileName, const uchar* data, uint size) -{ - PHYSFS_file* file = PHYSFS_openWrite(fileName.c_str()); - if(!file) - { - logError(PHYSFS_getLastError()); - return false; - } - - PHYSFS_write(file, (void*)data, size, 1); - PHYSFS_close(file); - return true; -} - -bool ResourceManager::saveFile(const std::string& fileName, std::iostream& in) -{ - std::streampos oldPos = in.tellg(); - in.seekg(0, std::ios::end); - std::streampos size = in.tellg(); - in.seekg(0, std::ios::beg); - std::vector buffer(size); - in.read(&buffer[0], size); - bool ret = saveFile(fileName, (const uchar*)&buffer[0], size); - in.seekg(oldPos, std::ios::beg); - return ret; -} - -bool ResourceManager::saveFile(const std::string& fileName, const std::string& data) -{ - return saveFile(fileName, (const uchar*)data.c_str(), data.size()); -} - -FileStreamPtr ResourceManager::openFile(const std::string& fileName) -{ - std::string fullPath = resolvePath(fileName); - PHYSFS_File* file = PHYSFS_openRead(fullPath.c_str()); - if(!file) { - logTraceError("unable to open file '", fullPath, "': ", PHYSFS_getLastError()); - return nullptr; - } - return FileStreamPtr(new FileStream(fullPath, file)); -} - -FileStreamPtr ResourceManager::appendFile(const std::string& fileName) -{ - PHYSFS_File* file = PHYSFS_openAppend(fileName.c_str()); - if(!file) { - logTraceError("failed to append file '", fileName, "': ", PHYSFS_getLastError()); - return nullptr; - } - return FileStreamPtr(new FileStream(fileName, file)); -} - -FileStreamPtr ResourceManager::createFile(const std::string& fileName) -{ - PHYSFS_File* file = PHYSFS_openWrite(fileName.c_str()); - if(!file) { - logTraceError("failed to create file '", fileName, "': ", PHYSFS_getLastError()); - return nullptr; - } - return FileStreamPtr(new FileStream(fileName, file)); -} - -bool ResourceManager::deleteFile(const std::string& fileName) -{ - return PHYSFS_delete(resolvePath(fileName).c_str()) != 0; -} - - -bool ResourceManager::makeDir(const std::string directory) -{ - return PHYSFS_mkdir(directory.c_str()); -} - -std::list ResourceManager::listDirectoryFiles(const std::string& directoryPath) -{ - std::list files; - auto rc = PHYSFS_enumerateFiles(resolvePath(directoryPath).c_str()); - - for(int i = 0; rc[i] != NULL; i++) - files.push_back(rc[i]); - - PHYSFS_freeList(rc); - return files; -} - -std::string ResourceManager::resolvePath(const std::string& path) -{ - std::string fullPath; - if(boost::starts_with(path, "/")) - fullPath = path; - else { - std::string scriptPath = "/" + g_lua.getCurrentSourcePath(); - if(!scriptPath.empty()) - fullPath += scriptPath + "/"; - fullPath += path; - } - if(!(boost::starts_with(fullPath, "/"))) - logTraceWarning("the following file path is not fully resolved: ", path); - boost::replace_all(fullPath, "//", "/"); - return fullPath; -} - -std::string ResourceManager::getBaseDir() -{ - return PHYSFS_getBaseDir(); -} - +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "resourcemanager.h" +#include "filestream.h" + +#include +#include + +#include + +ResourceManager g_resources; + +void ResourceManager::init(const char *argv0) +{ + PHYSFS_init(argv0); +} + +void ResourceManager::terminate() +{ + PHYSFS_deinit(); +} + +bool ResourceManager::setupWriteDir(const std::string& appWriteDirName) +{ + std::string userDir = PHYSFS_getUserDir(); + std::string dirName = Fw::mkstr(".", appWriteDirName); + std::string writeDir = userDir + dirName; + if(!PHYSFS_setWriteDir(writeDir.c_str())) { + if(!PHYSFS_setWriteDir(userDir.c_str())) + return false; + if(!PHYSFS_mkdir(dirName.c_str())) { + PHYSFS_setWriteDir(NULL); + return false; + } + if(!PHYSFS_setWriteDir(writeDir.c_str())) + return false; + } + addToSearchPath(writeDir); + return true; +} + +bool ResourceManager::addToSearchPath(const std::string& path, bool insertInFront) +{ + if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1)) + return false; + return true; +} + +void ResourceManager::searchAndAddPackages(const std::string& packagesDir, const std::string& packageExt, bool append) +{ + auto files = listDirectoryFiles(resolvePath(packagesDir)); + for(const std::string& file : files) { + if(boost::ends_with(file, packageExt)) + addToSearchPath(packagesDir + "/" + file, !append); + } +} + +bool ResourceManager::fileExists(const std::string& fileName) +{ + return (PHYSFS_exists(resolvePath(fileName).c_str()) && !PHYSFS_isDirectory(resolvePath(fileName).c_str())); +} + +bool ResourceManager::directoryExists(const std::string& directoryName) +{ + return (PHYSFS_isDirectory(resolvePath(directoryName).c_str())); +} + +void ResourceManager::loadFile(const std::string& fileName, std::iostream& out) +{ + std::string fullPath = resolvePath(fileName); + out.clear(std::ios::goodbit); + PHYSFS_file* file = PHYSFS_openRead(fullPath.c_str()); + if(!file) { + out.clear(std::ios::failbit); + Fw::throwException("failed to load file '", fullPath.c_str(), "': ", PHYSFS_getLastError()); + } else { + int fileSize = PHYSFS_fileLength(file); + if(fileSize > 0) { + std::vector buffer(fileSize); + PHYSFS_read(file, (void*)&buffer[0], 1, fileSize); + out.write(&buffer[0], fileSize); + } else + out.clear(std::ios::eofbit); + PHYSFS_close(file); + out.seekg(0, std::ios::beg); + } +} + +std::string ResourceManager::loadFile(const std::string& fileName) +{ + std::stringstream fin; + loadFile(fileName, fin); + return fin.str(); +} + +bool ResourceManager::saveFile(const std::string& fileName, const uchar* data, uint size) +{ + PHYSFS_file* file = PHYSFS_openWrite(fileName.c_str()); + if(!file) + { + logError(PHYSFS_getLastError()); + return false; + } + + PHYSFS_write(file, (void*)data, size, 1); + PHYSFS_close(file); + return true; +} + +bool ResourceManager::saveFile(const std::string& fileName, std::iostream& in) +{ + std::streampos oldPos = in.tellg(); + in.seekg(0, std::ios::end); + std::streampos size = in.tellg(); + in.seekg(0, std::ios::beg); + std::vector buffer(size); + in.read(&buffer[0], size); + bool ret = saveFile(fileName, (const uchar*)&buffer[0], size); + in.seekg(oldPos, std::ios::beg); + return ret; +} + +bool ResourceManager::saveFile(const std::string& fileName, const std::string& data) +{ + return saveFile(fileName, (const uchar*)data.c_str(), data.size()); +} + +FileStreamPtr ResourceManager::openFile(const std::string& fileName) +{ + std::string fullPath = resolvePath(fileName); + PHYSFS_File* file = PHYSFS_openRead(fullPath.c_str()); + if(!file) { + logTraceError("unable to open file '", fullPath, "': ", PHYSFS_getLastError()); + return nullptr; + } + return FileStreamPtr(new FileStream(fullPath, file)); +} + +FileStreamPtr ResourceManager::appendFile(const std::string& fileName) +{ + PHYSFS_File* file = PHYSFS_openAppend(fileName.c_str()); + if(!file) { + logTraceError("failed to append file '", fileName, "': ", PHYSFS_getLastError()); + return nullptr; + } + return FileStreamPtr(new FileStream(fileName, file)); +} + +FileStreamPtr ResourceManager::createFile(const std::string& fileName) +{ + PHYSFS_File* file = PHYSFS_openWrite(fileName.c_str()); + if(!file) { + logTraceError("failed to create file '", fileName, "': ", PHYSFS_getLastError()); + return nullptr; + } + return FileStreamPtr(new FileStream(fileName, file)); +} + +bool ResourceManager::deleteFile(const std::string& fileName) +{ + return PHYSFS_delete(resolvePath(fileName).c_str()) != 0; +} + + +bool ResourceManager::makeDir(const std::string directory) +{ + return PHYSFS_mkdir(directory.c_str()); +} + +std::list ResourceManager::listDirectoryFiles(const std::string& directoryPath) +{ + std::list files; + auto rc = PHYSFS_enumerateFiles(resolvePath(directoryPath).c_str()); + + for(int i = 0; rc[i] != NULL; i++) + files.push_back(rc[i]); + + PHYSFS_freeList(rc); + return files; +} + +std::string ResourceManager::resolvePath(const std::string& path) +{ + std::string fullPath; + if(boost::starts_with(path, "/")) + fullPath = path; + else { + std::string scriptPath = "/" + g_lua.getCurrentSourcePath(); + if(!scriptPath.empty()) + fullPath += scriptPath + "/"; + fullPath += path; + } + if(!(boost::starts_with(fullPath, "/"))) + logTraceWarning("the following file path is not fully resolved: ", path); + boost::replace_all(fullPath, "//", "/"); + return fullPath; +} + +std::string ResourceManager::getBaseDir() +{ + return PHYSFS_getBaseDir(); +} + diff --git a/src/otclient/core/spritemanager.cpp b/src/otclient/core/spritemanager.cpp index 3911e1b3..5aca9b29 100644 --- a/src/otclient/core/spritemanager.cpp +++ b/src/otclient/core/spritemanager.cpp @@ -1,238 +1,238 @@ -/* - * Copyright (c) 2010-2012 OTClient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "spritemanager.h" -#include -#include -#include -#include -#include -#include - -SpriteManager g_sprites; - -SpriteManager::SpriteManager() -{ - m_spritesCount = 0; - m_signature = 0; -} - -bool SpriteManager::load(const std::string& file) -{ - try { - m_spritesFile = g_resources.openFile(file); - if(!m_spritesFile) - return false; - - // cache file buffer to avoid lags from hard drive - m_spritesFile->cache(); - - m_signature = m_spritesFile->getU32(); - m_spritesCount = m_spritesFile->getU16(); - m_sprites.resize(m_spritesCount); - m_loaded = true; - return true; - } catch(Exception& e) { - logError("Failed to load sprites from '", file, "': ", e.what()); - return false; - } -} - -void SpriteManager::unload() -{ - m_sprites.clear(); - m_spritesCount = 0; - m_signature = 0; -} - -void SpriteManager::preloadSprites() -{ - // preload every 50 sprites, periodically - const int burst = 50; - const int interval = 10; - auto preload = [this](int start) { - for(int i=start;iseek(((id-1) * 4) + 6); - - uint32 spriteAddress = m_spritesFile->getU32(); - - // no sprite? return an empty texture - if(spriteAddress == 0) - return g_graphics.getEmptyTexture(); - - m_spritesFile->seek(spriteAddress); - - // skip color key - m_spritesFile->getU8(); - m_spritesFile->getU8(); - m_spritesFile->getU8(); - - uint16 pixelDataSize = m_spritesFile->getU16(); - - static std::vector pixels(SPRITE_SIZE); - int writePos = 0; - int read = 0; - - // decompress pixels - while(read < pixelDataSize) { - uint16 transparentPixels = m_spritesFile->getU16(); - uint16 coloredPixels = m_spritesFile->getU16(); - - if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE) - return g_graphics.getEmptyTexture(); - - for(int i = 0; i < transparentPixels; i++) { - pixels[writePos + 0] = 0x00; - pixels[writePos + 1] = 0x00; - pixels[writePos + 2] = 0x00; - pixels[writePos + 3] = 0x00; - writePos += 4; - } - - for(int i = 0; i < coloredPixels; i++) { - pixels[writePos + 0] = m_spritesFile->getU8(); - pixels[writePos + 1] = m_spritesFile->getU8(); - pixels[writePos + 2] = m_spritesFile->getU8(); - pixels[writePos + 3] = 0xFF; - - writePos += 4; - } - - read += 4 + (3 * coloredPixels); - } - - // fill remaining pixels with alpha - while(writePos < SPRITE_SIZE) { - pixels[writePos + 0] = 0x00; - pixels[writePos + 1] = 0x00; - pixels[writePos + 2] = 0x00; - pixels[writePos + 3] = 0x00; - writePos += 4; - } - - TexturePtr spriteTex(new Texture(32, 32, 4, &pixels[0])); - spriteTex->setSmooth(true); - - if(g_graphics.canUseMipmaps()) - spriteTex->generateSoftwareMipmaps(pixels); - - return spriteTex; -} - -TexturePtr& SpriteManager::getSpriteTexture(int id) -{ - if(id == 0) - return g_graphics.getEmptyTexture(); - - assert(id > 0 && id <= m_spritesCount); - - // load sprites on demand - TexturePtr& sprite = m_sprites[id-1]; - if(!sprite) - sprite = loadSpriteTexture(id); - - //TODO: release unused sprites textures after X seconds - // to avoid massive texture allocations - return sprite; -} - -bool SpriteManager::exportSprites() -{ - g_resources.makeDir("sprites"); - std::stringstream ss; - - for(volatile int i = 1; i <= m_spritesCount; i++) { - m_spritesFile->seek(((i-1) * 4) + 6); - - uint32 spriteAddress = m_spritesFile->getU32(); - if(spriteAddress == 0) - continue; - - m_spritesFile->seek(spriteAddress); - - // skip color key - m_spritesFile->getU8(); - m_spritesFile->getU8(); - m_spritesFile->getU8(); - - uint16 pixelDataSize = m_spritesFile->getU16(); - - uchar pixels[SPRITE_SIZE]; - int writePos = 0; - int read = 0; - - // decompress pixels - while(read < pixelDataSize) { - uint16 transparentPixels = m_spritesFile->getU16(); - uint16 coloredPixels = m_spritesFile->getU16(); - - if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE) - return false; // skip the whole process or just ignore this sprite? - - for(int i = 0; i < transparentPixels; i++) { - pixels[writePos + 0] = 0x00; - pixels[writePos + 1] = 0x00; - pixels[writePos + 2] = 0x00; - pixels[writePos + 3] = 0x00; - writePos += 4; - } - - for(int i = 0; i < coloredPixels; i++) { - pixels[writePos + 0] = m_spritesFile->getU8(); - pixels[writePos + 1] = m_spritesFile->getU8(); - pixels[writePos + 2] = m_spritesFile->getU8(); - pixels[writePos + 3] = 0xFF; - - writePos += 4; - } - - read += 4 + (3 * coloredPixels); - } - - // fill remaining pixels with alpha - while(writePos < SPRITE_SIZE) { - pixels[writePos + 0] = 0x00; - pixels[writePos + 1] = 0x00; - pixels[writePos + 2] = 0x00; - pixels[writePos + 3] = 0x00; - writePos += 4; - } - - // We should get the OTClient and export to that folder... - std::string fileName = Fw::formatString("sprites/%d.png", i); - ss.str(""); - save_png(ss, SPRITE_WIDTH, SPRITE_HEIGHT, SPRITE_CHANNELS, pixels); - g_resources.saveFile(fileName, ss); - } - - return true; -} +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "spritemanager.h" +#include +#include +#include +#include +#include +#include + +SpriteManager g_sprites; + +SpriteManager::SpriteManager() +{ + m_spritesCount = 0; + m_signature = 0; +} + +bool SpriteManager::load(const std::string& file) +{ + try { + m_spritesFile = g_resources.openFile(file); + if(!m_spritesFile) + return false; + + // cache file buffer to avoid lags from hard drive + m_spritesFile->cache(); + + m_signature = m_spritesFile->getU32(); + m_spritesCount = m_spritesFile->getU16(); + m_sprites.resize(m_spritesCount); + m_loaded = true; + return true; + } catch(Exception& e) { + logError("Failed to load sprites from '", file, "': ", e.what()); + return false; + } +} + +void SpriteManager::unload() +{ + m_sprites.clear(); + m_spritesCount = 0; + m_signature = 0; +} + +void SpriteManager::preloadSprites() +{ + // preload every 50 sprites, periodically + const int burst = 50; + const int interval = 10; + auto preload = [this](int start) { + for(int i=start;iseek(((id-1) * 4) + 6); + + uint32 spriteAddress = m_spritesFile->getU32(); + + // no sprite? return an empty texture + if(spriteAddress == 0) + return g_graphics.getEmptyTexture(); + + m_spritesFile->seek(spriteAddress); + + // skip color key + m_spritesFile->getU8(); + m_spritesFile->getU8(); + m_spritesFile->getU8(); + + uint16 pixelDataSize = m_spritesFile->getU16(); + + static std::vector pixels(SPRITE_SIZE); + int writePos = 0; + int read = 0; + + // decompress pixels + while(read < pixelDataSize) { + uint16 transparentPixels = m_spritesFile->getU16(); + uint16 coloredPixels = m_spritesFile->getU16(); + + if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE) + return g_graphics.getEmptyTexture(); + + for(int i = 0; i < transparentPixels; i++) { + pixels[writePos + 0] = 0x00; + pixels[writePos + 1] = 0x00; + pixels[writePos + 2] = 0x00; + pixels[writePos + 3] = 0x00; + writePos += 4; + } + + for(int i = 0; i < coloredPixels; i++) { + pixels[writePos + 0] = m_spritesFile->getU8(); + pixels[writePos + 1] = m_spritesFile->getU8(); + pixels[writePos + 2] = m_spritesFile->getU8(); + pixels[writePos + 3] = 0xFF; + + writePos += 4; + } + + read += 4 + (3 * coloredPixels); + } + + // fill remaining pixels with alpha + while(writePos < SPRITE_SIZE) { + pixels[writePos + 0] = 0x00; + pixels[writePos + 1] = 0x00; + pixels[writePos + 2] = 0x00; + pixels[writePos + 3] = 0x00; + writePos += 4; + } + + TexturePtr spriteTex(new Texture(32, 32, 4, &pixels[0])); + spriteTex->setSmooth(true); + + if(g_graphics.canUseMipmaps()) + spriteTex->generateSoftwareMipmaps(pixels); + + return spriteTex; +} + +TexturePtr& SpriteManager::getSpriteTexture(int id) +{ + if(id == 0) + return g_graphics.getEmptyTexture(); + + assert(id > 0 && id <= m_spritesCount); + + // load sprites on demand + TexturePtr& sprite = m_sprites[id-1]; + if(!sprite) + sprite = loadSpriteTexture(id); + + //TODO: release unused sprites textures after X seconds + // to avoid massive texture allocations + return sprite; +} + +bool SpriteManager::exportSprites() +{ + g_resources.makeDir("sprites"); + std::stringstream ss; + + for(volatile int i = 1; i <= m_spritesCount; i++) { + m_spritesFile->seek(((i-1) * 4) + 6); + + uint32 spriteAddress = m_spritesFile->getU32(); + if(spriteAddress == 0) + continue; + + m_spritesFile->seek(spriteAddress); + + // skip color key + m_spritesFile->getU8(); + m_spritesFile->getU8(); + m_spritesFile->getU8(); + + uint16 pixelDataSize = m_spritesFile->getU16(); + + uchar pixels[SPRITE_SIZE]; + int writePos = 0; + int read = 0; + + // decompress pixels + while(read < pixelDataSize) { + uint16 transparentPixels = m_spritesFile->getU16(); + uint16 coloredPixels = m_spritesFile->getU16(); + + if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE) + return false; // skip the whole process or just ignore this sprite? + + for(int i = 0; i < transparentPixels; i++) { + pixels[writePos + 0] = 0x00; + pixels[writePos + 1] = 0x00; + pixels[writePos + 2] = 0x00; + pixels[writePos + 3] = 0x00; + writePos += 4; + } + + for(int i = 0; i < coloredPixels; i++) { + pixels[writePos + 0] = m_spritesFile->getU8(); + pixels[writePos + 1] = m_spritesFile->getU8(); + pixels[writePos + 2] = m_spritesFile->getU8(); + pixels[writePos + 3] = 0xFF; + + writePos += 4; + } + + read += 4 + (3 * coloredPixels); + } + + // fill remaining pixels with alpha + while(writePos < SPRITE_SIZE) { + pixels[writePos + 0] = 0x00; + pixels[writePos + 1] = 0x00; + pixels[writePos + 2] = 0x00; + pixels[writePos + 3] = 0x00; + writePos += 4; + } + + // We should get the OTClient and export to that folder... + std::string fileName = Fw::formatString("sprites/%d.png", i); + ss.str(""); + save_png(ss, SPRITE_WIDTH, SPRITE_HEIGHT, SPRITE_CHANNELS, pixels); + g_resources.saveFile(fileName, ss); + } + + return true; +} diff --git a/src/otclient/core/spritemanager.h b/src/otclient/core/spritemanager.h index 9c8885f2..e2780804 100644 --- a/src/otclient/core/spritemanager.h +++ b/src/otclient/core/spritemanager.h @@ -1,67 +1,67 @@ -/* - * Copyright (c) 2010-2012 OTClient - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef SPRITEMANAGER_H -#define SPRITEMANAGER_H - -#include -#include -#include - -class SpriteManager -{ - enum { - SPRITE_WIDTH=32, - SPRITE_HEIGHT=32, - SPRITE_CHANNELS=4, - SPRITE_SIZE=SPRITE_WIDTH*SPRITE_HEIGHT*SPRITE_CHANNELS - }; - -public: - SpriteManager(); - - bool load(const std::string& file); - void unload(); - void preloadSprites(); - - uint32 getSignature() { return m_signature; } - int getSpritesCount() { return m_spritesCount; } - - bool exportSprites(); - - TexturePtr& getSpriteTexture(int id); - bool isLoaded() { return m_loaded; } - -private: - TexturePtr loadSpriteTexture(int id); - - Boolean m_loaded; - uint32 m_signature; - int m_spritesCount; - std::vector m_sprites; - TexturePtr m_transparentSprite; - FileStreamPtr m_spritesFile; -}; - -extern SpriteManager g_sprites; - -#endif +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SPRITEMANAGER_H +#define SPRITEMANAGER_H + +#include +#include +#include + +class SpriteManager +{ + enum { + SPRITE_WIDTH=32, + SPRITE_HEIGHT=32, + SPRITE_CHANNELS=4, + SPRITE_SIZE=SPRITE_WIDTH*SPRITE_HEIGHT*SPRITE_CHANNELS + }; + +public: + SpriteManager(); + + bool load(const std::string& file); + void unload(); + void preloadSprites(); + + uint32 getSignature() { return m_signature; } + int getSpritesCount() { return m_spritesCount; } + + bool exportSprites(); + + TexturePtr& getSpriteTexture(int id); + bool isLoaded() { return m_loaded; } + +private: + TexturePtr loadSpriteTexture(int id); + + Boolean m_loaded; + uint32 m_signature; + int m_spritesCount; + std::vector m_sprites; + TexturePtr m_transparentSprite; + FileStreamPtr m_spritesFile; +}; + +extern SpriteManager g_sprites; + +#endif diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index d53f0a9a..8480303c 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -57,7 +57,7 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("g_sprites", "load", std::bind(&SpriteManager::load, &g_sprites, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_sprites", "isLoaded", std::bind(&SpriteManager::isLoaded, &g_sprites)); g_lua.bindClassStaticFunction("g_sprites", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites)); - g_lua.bindClassStaticFunction("g_sprites", "preloadSprites", std::bind(&SpriteManager::preloadSprites, &g_sprites)); + g_lua.bindClassStaticFunction("g_sprites", "preloadSprites", std::bind(&SpriteManager::preloadSprites, &g_sprites)); g_lua.bindClassStaticFunction("g_sprites", "export", std::bind(&SpriteManager::exportSprites, &g_sprites)); g_lua.registerStaticClass("g_map");