From 8450f1f896f40eb331c298483656ac754ca09375 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Mon, 2 Apr 2012 12:51:03 -0300 Subject: [PATCH] add FileStream class * minimize memory consumption by using FileStream for loading sprites --- src/framework/CMakeLists.txt | 5 +- src/framework/core/declarations.h | 3 + src/framework/core/filestream.cpp | 131 +++++++++++++++++++++++++ src/framework/core/filestream.h | 64 ++++++++++++ src/framework/core/resourcemanager.cpp | 34 ++++++- src/framework/core/resourcemanager.h | 4 +- src/otclient/core/spritemanager.cpp | 36 +++---- src/otclient/core/spritemanager.h | 4 +- 8 files changed, 258 insertions(+), 23 deletions(-) create mode 100644 src/framework/core/filestream.cpp create mode 100644 src/framework/core/filestream.h diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 84021d09..06c21229 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -6,8 +6,6 @@ ENDIF(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 6) # add framework cmake modules SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake;${CMAKE_MODULE_PATH}") -# framework options -OPTION(WINDOWS_CONSOLE "Enables console window on Windows platform" OFF) OPTION(USE_OPENGL_ES2 "Use OpenGL ES 2.0 (for mobiles devices)" OFF) OPTION(CRASH_HANDLER "Generate crash reports" ON) SET(BUILD_REVISION "custom" CACHE "Git revision string (intended for releases)" STRING) @@ -85,6 +83,8 @@ ELSE() ENDIF() IF(WIN32) + OPTION(WINDOWS_CONSOLE "Enables console window on Windows platform" OFF) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthreads") ADD_DEFINITIONS(-D_WIN32_WINNT=0x0501) SET(ADDITIONAL_LIBRARIES ws2_32 mswsock imagehlp) @@ -158,6 +158,7 @@ SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/core/module.cpp ${CMAKE_CURRENT_LIST_DIR}/core/clock.cpp ${CMAKE_CURRENT_LIST_DIR}/core/timer.cpp + ${CMAKE_CURRENT_LIST_DIR}/core/filestream.cpp # framework net ${CMAKE_CURRENT_LIST_DIR}/net/connection.cpp diff --git a/src/framework/core/declarations.h b/src/framework/core/declarations.h index ce92b276..3ffe8a87 100644 --- a/src/framework/core/declarations.h +++ b/src/framework/core/declarations.h @@ -26,12 +26,15 @@ #include class ModuleManager; +class ResourceManager; class Module; class Event; class ScheduledEvent; +class FileStream; typedef std::shared_ptr ModulePtr; typedef std::shared_ptr EventPtr; typedef std::shared_ptr ScheduledEventPtr; +typedef std::shared_ptr FileStreamPtr; #endif diff --git a/src/framework/core/filestream.cpp b/src/framework/core/filestream.cpp new file mode 100644 index 00000000..89558a0d --- /dev/null +++ b/src/framework/core/filestream.cpp @@ -0,0 +1,131 @@ +/* + * 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 "filestream.h" + +#include + +FileStream::FileStream(const std::string& name, PHYSFS_File *fileHandle) +{ + m_name = name; + m_fileHandle = fileHandle; +} + +FileStream::~FileStream() +{ + close(); +} + +void FileStream::close() +{ + if(m_fileHandle) { + if(PHYSFS_isInit() && PHYSFS_close(m_fileHandle) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); + + m_fileHandle = nullptr; + } +} + +void FileStream::flush() +{ + if(PHYSFS_flush(m_fileHandle) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +void FileStream::read(void *buffer, uint count) +{ + if(PHYSFS_read(m_fileHandle, buffer, 1, count) != count) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +void FileStream::write(void *buffer, uint count) +{ + if(PHYSFS_write(m_fileHandle, buffer, 1, count) != count) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +void FileStream::seek(uint pos) +{ + if(PHYSFS_seek(m_fileHandle, pos) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +int FileStream::size() +{ + return PHYSFS_fileLength(m_fileHandle); +} + +uint8 FileStream::getU8() +{ + uint8 v = 0; + if(PHYSFS_read(m_fileHandle, &v, 1, 1) != 1) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); + return v; +} + +uint16 FileStream::getU16() +{ + uint16 v = 0; + if(PHYSFS_readULE16(m_fileHandle, &v) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); + return v; +} + +uint32 FileStream::getU32() +{ + uint32 v = 0; + if(PHYSFS_readULE32(m_fileHandle, &v) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); + return v; +} + +uint64 FileStream::getU64() +{ + uint64 v = 0; + if(PHYSFS_readULE64(m_fileHandle, (PHYSFS_uint64*)&v) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); + return v; +} + +void FileStream::addU8(uint8 v) +{ + if(PHYSFS_write(m_fileHandle, &v, 1, 1) != 1) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +void FileStream::addU16(uint8 v) +{ + if(PHYSFS_writeULE16(m_fileHandle, v) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +void FileStream::addU32(uint8 v) +{ + if(PHYSFS_writeULE32(m_fileHandle, v) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} + +void FileStream::addU64(uint8 v) +{ + if(PHYSFS_writeULE64(m_fileHandle, v) == 0) + logTraceError("operation failed on '", m_name, "': ", PHYSFS_getLastError()); +} diff --git a/src/framework/core/filestream.h b/src/framework/core/filestream.h new file mode 100644 index 00000000..388c8453 --- /dev/null +++ b/src/framework/core/filestream.h @@ -0,0 +1,64 @@ +/* + * 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 FILESTREAM_H +#define FILESTREAM_H + +#include "declarations.h" + +struct PHYSFS_File; + +class FileStream +{ +protected: + FileStream(const std::string& name, PHYSFS_File *fileHandle); + + friend class ResourceManager; + +public: + ~FileStream(); + + void close(); + void flush(); + void write(void *buffer, uint count); + void read(void *buffer, uint count); + void seek(uint pos); + int size(); + std::string name() { return m_name; } + + std::string readAll(); + + uint8 getU8(); + uint16 getU16(); + uint32 getU32(); + uint64 getU64(); + void addU8(uint8 v); + void addU16(uint8 v); + void addU32(uint8 v); + void addU64(uint8 v); + +private: + std::string m_name; + PHYSFS_File *m_fileHandle; +}; + +#endif diff --git a/src/framework/core/resourcemanager.cpp b/src/framework/core/resourcemanager.cpp index 245965dc..47de5dad 100644 --- a/src/framework/core/resourcemanager.cpp +++ b/src/framework/core/resourcemanager.cpp @@ -21,6 +21,7 @@ */ #include "resourcemanager.h" +#include "filestream.h" #include #include @@ -114,7 +115,7 @@ std::string ResourceManager::loadFile(const std::string& fileName) bool ResourceManager::saveFile(const std::string& fileName, const uchar* data, uint size) { - PHYSFS_file* file = PHYSFS_openWrite(checkPath(fileName).c_str()); + PHYSFS_file* file = PHYSFS_openWrite(fileName.c_str()); if(!file) return false; @@ -141,6 +142,37 @@ bool ResourceManager::saveFile(const std::string& fileName, const std::string& d return saveFile(fileName, (const uchar*)data.c_str(), data.size()); } +FileStreamPtr ResourceManager::openFile(const std::string& fileName) +{ + std::string fullPath = checkPath(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(checkPath(fileName).c_str()) != 0; diff --git a/src/framework/core/resourcemanager.h b/src/framework/core/resourcemanager.h index d576b1cb..7edc81d5 100644 --- a/src/framework/core/resourcemanager.h +++ b/src/framework/core/resourcemanager.h @@ -41,11 +41,13 @@ public: void loadFile(const std::string& fileName, std::iostream& out); std::string loadFile(const std::string& fileName); - bool saveFile(const std::string& fileName, const uchar* data, uint size); bool saveFile(const std::string& fileName, const std::string& data); bool saveFile(const std::string& fileName, std::iostream& in); + FileStreamPtr openFile(const std::string& fileName); + FileStreamPtr appendFile(const std::string& fileName); + FileStreamPtr createFile(const std::string& fileName); bool deleteFile(const std::string& fileName); std::list listDirectoryFiles(const std::string& directoryPath = ""); diff --git a/src/otclient/core/spritemanager.cpp b/src/otclient/core/spritemanager.cpp index bebb3c61..e230c6af 100644 --- a/src/otclient/core/spritemanager.cpp +++ b/src/otclient/core/spritemanager.cpp @@ -23,6 +23,7 @@ #include "spritemanager.h" #include #include +#include #include SpriteManager g_sprites; @@ -36,9 +37,12 @@ SpriteManager::SpriteManager() bool SpriteManager::load(const std::string& file) { try { - g_resources.loadFile(file, m_fin); - m_signature = Fw::getU32(m_fin); - m_spritesCount = Fw::getU16(m_fin); + m_spritesFile = g_resources.openFile(file); + if(!m_spritesFile) + return false; + + m_signature = m_spritesFile->getU32(); + m_spritesCount = m_spritesFile->getU16(); m_sprites.resize(m_spritesCount); m_loaded = true; return true; @@ -72,23 +76,22 @@ void SpriteManager::preloadSprites() TexturePtr SpriteManager::loadSpriteTexture(int id) { - m_fin.seekg(((id-1) * 4) + 6, std::ios_base::beg); + m_spritesFile->seek(((id-1) * 4) + 6); - uint32 spriteAddress = Fw::getU32(m_fin); + uint32 spriteAddress = m_spritesFile->getU32(); // no sprite? return an empty texture if(spriteAddress == 0) return g_graphics.getEmptyTexture(); - m_fin.seekg(spriteAddress, std::ios_base::beg); - assert(m_fin.good()); + m_spritesFile->seek(spriteAddress); // skip color key - Fw::getU8(m_fin); - Fw::getU8(m_fin); - Fw::getU8(m_fin); + m_spritesFile->getU8(); + m_spritesFile->getU8(); + m_spritesFile->getU8(); - uint16 pixelDataSize = Fw::getU16(m_fin); + uint16 pixelDataSize = m_spritesFile->getU16(); static std::vector pixels(4096); int writePos = 0; @@ -96,9 +99,8 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) // decompress pixels while(read < pixelDataSize) { - uint16 transparentPixels, coloredPixels; - m_fin.read((char*)&transparentPixels, 2); - m_fin.read((char*)&coloredPixels, 2); + uint16 transparentPixels = m_spritesFile->getU16(); + uint16 coloredPixels = m_spritesFile->getU16(); if(writePos + transparentPixels*4 + coloredPixels*3 >= 4096) return g_graphics.getEmptyTexture(); @@ -112,9 +114,9 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) } for(int i = 0; i < coloredPixels; i++) { - pixels[writePos + 0] = Fw::getU8(m_fin); - pixels[writePos + 1] = Fw::getU8(m_fin); - pixels[writePos + 2] = Fw::getU8(m_fin); + pixels[writePos + 0] = m_spritesFile->getU8(); + pixels[writePos + 1] = m_spritesFile->getU8(); + pixels[writePos + 2] = m_spritesFile->getU8(); pixels[writePos + 3] = 0xFF; writePos += 4; diff --git a/src/otclient/core/spritemanager.h b/src/otclient/core/spritemanager.h index da0b1d40..af691388 100644 --- a/src/otclient/core/spritemanager.h +++ b/src/otclient/core/spritemanager.h @@ -23,7 +23,7 @@ #ifndef SPRITEMANAGER_H #define SPRITEMANAGER_H -#include "declarations.h" +#include #include class SpriteManager @@ -47,9 +47,9 @@ private: Boolean m_loaded; uint32 m_signature; int m_spritesCount; - std::stringstream m_fin; std::vector m_sprites; TexturePtr m_transparentSprite; + FileStreamPtr m_spritesFile; }; extern SpriteManager g_sprites;