diff --git a/src/framework/application.cpp b/src/framework/application.cpp index ef97321c..aa191ad2 100644 --- a/src/framework/application.cpp +++ b/src/framework/application.cpp @@ -52,8 +52,8 @@ void exitSignalHandler(int sig) break; } } - Application::Application(const std::string& appName) + { g_app = this; m_appName = appName; diff --git a/src/framework/core/resourcemanager.cpp b/src/framework/core/resourcemanager.cpp index ce2a0daf..1c72613e 100644 --- a/src/framework/core/resourcemanager.cpp +++ b/src/framework/core/resourcemanager.cpp @@ -116,8 +116,11 @@ 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(fileName.c_str()); - if(!file) - return false; + if(!file) + { + logError(PHYSFS_getLastError()); + return false; + } PHYSFS_write(file, (void*)data, size, 1); PHYSFS_close(file); diff --git a/src/otclient/core/spritemanager.cpp b/src/otclient/core/spritemanager.cpp index d5bd48c3..86f7ad0c 100644 --- a/src/otclient/core/spritemanager.cpp +++ b/src/otclient/core/spritemanager.cpp @@ -24,7 +24,8 @@ #include #include #include -#include +#include +#include SpriteManager g_sprites; @@ -96,7 +97,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) uint16 pixelDataSize = m_spritesFile->getU16(); - static std::vector pixels(4096); + static std::vector pixels(SPRITE_SIZE); int writePos = 0; int read = 0; @@ -105,7 +106,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) uint16 transparentPixels = m_spritesFile->getU16(); uint16 coloredPixels = m_spritesFile->getU16(); - if(writePos + transparentPixels*4 + coloredPixels*3 >= 4096) + if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE) return g_graphics.getEmptyTexture(); for(int i = 0; i < transparentPixels; i++) { @@ -129,7 +130,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) } // fill remaining pixels with alpha - while(writePos < 4096) { + while(writePos < SPRITE_SIZE) { pixels[writePos + 0] = 0x00; pixels[writePos + 1] = 0x00; pixels[writePos + 2] = 0x00; @@ -161,4 +162,121 @@ TexturePtr& SpriteManager::getSpriteTexture(int id) //TODO: release unused sprites textures after X seconds // to avoid massive texture allocations return sprite; +} + +bool SpriteManager::exportSprites() +{ + + 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("%s/otclient/sprites/%d.png", PHYSFS_getUserDir(), i); + FILE *pFile = fopen(fileName.c_str(), "wb"); + + if(!pFile) + return false; + + png_structp pPng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(!pPng) { + fclose(pFile); + return false; + } + + png_infop pPngInfo = png_create_info_struct(pPng); + if(!pPngInfo) { + fclose(pFile); + png_destroy_write_struct(&pPng, NULL); + return false; + } + + if(setjmp(png_jmpbuf(pPng))) { + fclose(pFile); + png_destroy_write_struct(&pPng, &pPngInfo); + return false; + } + + png_init_io(pPng, pFile); + png_set_compression_level(pPng, PNG_COMPRESSION); + + int bitDepthPerChannel = SPRITE_CHANNELS/4*8; + int colorType = PNG_COLOR_TYPE_RGB_ALPHA; + + png_set_IHDR(pPng, pPngInfo, SPRITE_WIDTH, SPRITE_HEIGHT, bitDepthPerChannel, colorType, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_write_info(pPng, pPngInfo); + + if(bitDepthPerChannel == 16) // Reverse endian order (PNG is Big Endian) + png_set_swap(pPng); + + int bytesPerRow = SPRITE_WIDTH*SPRITE_CHANNELS; + uint8* pImgData = pixels; + + for(int row=0; row < SPRITE_HEIGHT; row++) { // Write non-interlaced buffer + png_write_row(pPng, pImgData); + pImgData += bytesPerRow; + } + + png_write_end(pPng, NULL); + png_destroy_write_struct(&pPng, &pPngInfo); + + fclose(pFile); + } + + return true; } diff --git a/src/otclient/core/spritemanager.h b/src/otclient/core/spritemanager.h index af691388..18e117ce 100644 --- a/src/otclient/core/spritemanager.h +++ b/src/otclient/core/spritemanager.h @@ -24,7 +24,22 @@ #define SPRITEMANAGER_H #include -#include +#include +#include + +#define SPRITE_WIDTH 32 +#define SPRITE_HEIGHT 32 +#define SPRITE_CHANNELS 4 +#define SPRITE_SIZE SPRITE_WIDTH*SPRITE_HEIGHT*SPRITE_CHANNELS + +/* + Compression levels: + None = 0 + Fastest = 1 + Best = 9 +*/ + +#define PNG_COMPRESSION 6 class SpriteManager { @@ -36,7 +51,9 @@ public: void preloadSprites(); uint32 getSignature() { return m_signature; } - int getSpritesCount() { return m_spritesCount; } + int getSpritesCount() { return m_spritesCount; } + + bool exportSprites(); TexturePtr& getSpriteTexture(int id); bool isLoaded() { return m_loaded; } diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 8bc4fcb4..d53f0a9a 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -44,7 +44,6 @@ #include #include - void OTClient::registerLuaFunctions() { Application::registerLuaFunctions(); @@ -58,7 +57,8 @@ 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"); g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, std::placeholders::_1));