speedup sprite loading
This commit is contained in:
		
							parent
							
								
									4584ce5b86
								
							
						
					
					
						commit
						edeee80631
					
				| 
						 | 
					@ -118,22 +118,27 @@ void Texture::setSmooth(bool smooth)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<uint8> Texture::getPixels()
 | 
					std::vector<uint8> Texture::getPixels()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // hack to copy pixels from opengl memory
 | 
					 | 
				
			||||||
    FrameBufferPtr fb(new FrameBuffer(m_size));
 | 
					 | 
				
			||||||
    std::vector<uint8> pixels(m_size.area()*4, 0);
 | 
					    std::vector<uint8> pixels(m_size.area()*4, 0);
 | 
				
			||||||
 | 
					#ifdef OPENGL_ES
 | 
				
			||||||
 | 
					    // hack to copy pixels from opengl memory in opengl es
 | 
				
			||||||
 | 
					    // NOTE: this can be slow, but its the only way to get pixels from a texture in OpenGL ES
 | 
				
			||||||
 | 
					    FrameBufferPtr fb(new FrameBuffer(m_size));
 | 
				
			||||||
    fb->bind();
 | 
					    fb->bind();
 | 
				
			||||||
    g_painter.saveAndResetState();
 | 
					    g_painter.saveAndResetState();
 | 
				
			||||||
    g_painter.drawTexturedRect(Rect(0,0,m_size), shared_from_this());
 | 
					    g_painter.drawTexturedRect(Rect(0,0,m_size), shared_from_this());
 | 
				
			||||||
    glReadPixels(0, 0, m_size.width(), m_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
 | 
					    glReadPixels(0, 0, m_size.width(), m_size.height(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
 | 
				
			||||||
    g_painter.restoreSavedState();
 | 
					    g_painter.restoreSavedState();
 | 
				
			||||||
    fb->release();
 | 
					    fb->release();
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    // copy pixels from opengl memory
 | 
				
			||||||
 | 
					    glBindTexture(GL_TEXTURE_2D, m_textureId);
 | 
				
			||||||
 | 
					    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    return pixels;
 | 
					    return pixels;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Texture::generateBilinearMipmaps()
 | 
					void Texture::generateBilinearMipmaps(std::vector<uint8> inPixels)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::vector<uint8> inPixels = getPixels();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bind();
 | 
					    bind();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(!m_useMipmaps) {
 | 
					    if(!m_useMipmaps) {
 | 
				
			||||||
| 
						 | 
					@ -188,7 +193,7 @@ void Texture::generateBilinearMipmaps()
 | 
				
			||||||
        if(inSize.width() == 1 || inSize.height() == 1)
 | 
					        if(inSize.width() == 1 || inSize.height() == 1)
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        inPixels = outPixels;
 | 
					        inPixels = std::move(outPixels);
 | 
				
			||||||
        inSize /= 2;
 | 
					        inSize /= 2;
 | 
				
			||||||
        outSize /= 2;
 | 
					        outSize /= 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,10 @@ public:
 | 
				
			||||||
    void bind() { glBindTexture(GL_TEXTURE_2D, m_textureId); }
 | 
					    void bind() { glBindTexture(GL_TEXTURE_2D, m_textureId); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void generateMipmaps();
 | 
					    void generateMipmaps();
 | 
				
			||||||
    void generateBilinearMipmaps();
 | 
					
 | 
				
			||||||
 | 
					    // generate bilinear mipmaps optimized for alpha textures
 | 
				
			||||||
 | 
					    void generateBilinearMipmaps(std::vector<uint8> inPixels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void setSmooth(bool smooth);
 | 
					    void setSmooth(bool smooth);
 | 
				
			||||||
    GLuint getId()  { return m_textureId; }
 | 
					    GLuint getId()  { return m_textureId; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,8 +77,10 @@ void Item::setPosition(const Position& position)
 | 
				
			||||||
    Thing::setPosition(position);
 | 
					    Thing::setPosition(position);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Item::setCount(uint8 count)
 | 
					void Item::setCount(int count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    count = std::max(std::min(count, 255), 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
 | 
					    if(isStackable() && getNumPatternsX() == 4 && getNumPatternsY() == 2) {
 | 
				
			||||||
        if(count < 5) {
 | 
					        if(count < 5) {
 | 
				
			||||||
            m_xPattern = count-1;
 | 
					            m_xPattern = count-1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,9 +36,9 @@ public:
 | 
				
			||||||
    void draw(const Point& dest, float scaleFactor);
 | 
					    void draw(const Point& dest, float scaleFactor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void setPosition(const Position &position);
 | 
					    void setPosition(const Position &position);
 | 
				
			||||||
    void setCount(uint8 data);
 | 
					    void setCount(int count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8 getCount() { return m_count; }
 | 
					    int getCount() { return m_count; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
 | 
					    ItemPtr asItem() { return std::static_pointer_cast<Item>(shared_from_this()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,9 +153,14 @@ void MapView::draw(const Rect& rect)
 | 
				
			||||||
            animatedText->draw(p, rect);
 | 
					            animatedText->draw(p, rect);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        // draw a arrow for position the center in non near views
 | 
					        // draw a cross in the center instead of our creature
 | 
				
			||||||
        g_painter.setColor(Fw::red);
 | 
					        Rect vRect(0, 0, 2, 10);
 | 
				
			||||||
        g_painter.drawFilledRect(Rect(rect.center(), 4, 4));
 | 
					        Rect hRect(0, 0, 10, 2);
 | 
				
			||||||
 | 
					        vRect.moveCenter(rect.center());
 | 
				
			||||||
 | 
					        hRect.moveCenter(rect.center());
 | 
				
			||||||
 | 
					        g_painter.setColor(Fw::white);
 | 
				
			||||||
 | 
					        g_painter.drawFilledRect(vRect);
 | 
				
			||||||
 | 
					        g_painter.drawFilledRect(hRect);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -405,18 +410,11 @@ void MapView::setVisibleDimension(const Size& visibleDimension)
 | 
				
			||||||
        viewRange = NEAR_VIEW;
 | 
					        viewRange = NEAR_VIEW;
 | 
				
			||||||
    else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA)
 | 
					    else if(tileSize >= 16 && visibleDimension.area() <= MID_VIEW_AREA)
 | 
				
			||||||
        viewRange = MID_VIEW;
 | 
					        viewRange = MID_VIEW;
 | 
				
			||||||
    else if(tileSize >= 8)
 | 
					    else if(tileSize >= 8 && visibleDimension.area() <= FAR_VIEW_AREA)
 | 
				
			||||||
        viewRange = FAR_VIEW;
 | 
					        viewRange = FAR_VIEW;
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        viewRange = HUGE_VIEW;
 | 
					        viewRange = HUGE_VIEW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(m_viewRange != viewRange) {
 | 
					 | 
				
			||||||
        if(viewRange == NEAR_VIEW) dump << "near view";
 | 
					 | 
				
			||||||
        else if(viewRange == MID_VIEW) dump << "mid view";
 | 
					 | 
				
			||||||
        else if(viewRange == FAR_VIEW) dump << "far view";
 | 
					 | 
				
			||||||
        else if(viewRange == HUGE_VIEW) dump << "huge view";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // draw actually more than what is needed to avoid massive recalculations on far views
 | 
					    // draw actually more than what is needed to avoid massive recalculations on far views
 | 
				
			||||||
    if(viewRange >= FAR_VIEW) {
 | 
					    if(viewRange >= FAR_VIEW) {
 | 
				
			||||||
        Size oldDimension = drawDimension;
 | 
					        Size oldDimension = drawDimension;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,8 @@ class MapView : public LuaObject
 | 
				
			||||||
        DEFAULT_FRAMBUFFER_HEIGHT = 1440,
 | 
					        DEFAULT_FRAMBUFFER_HEIGHT = 1440,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        NEAR_VIEW_AREA = 32*32,
 | 
					        NEAR_VIEW_AREA = 32*32,
 | 
				
			||||||
        MID_VIEW_AREA = 96*96,
 | 
					        MID_VIEW_AREA = 64*64,
 | 
				
			||||||
 | 
					        FAR_VIEW_AREA = 128*128,
 | 
				
			||||||
        MAX_TILE_UPDATES = NEAR_VIEW_AREA*7
 | 
					        MAX_TILE_UPDATES = NEAR_VIEW_AREA*7
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "spritemanager.h"
 | 
					#include "spritemanager.h"
 | 
				
			||||||
#include <framework/core/resourcemanager.h>
 | 
					#include <framework/core/resourcemanager.h>
 | 
				
			||||||
 | 
					#include <framework/core/eventdispatcher.h>
 | 
				
			||||||
#include <framework/graphics/graphics.h>
 | 
					#include <framework/graphics/graphics.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SpriteManager g_sprites;
 | 
					SpriteManager g_sprites;
 | 
				
			||||||
| 
						 | 
					@ -38,6 +39,7 @@ bool SpriteManager::load(const std::string& file)
 | 
				
			||||||
        g_resources.loadFile(file, m_fin);
 | 
					        g_resources.loadFile(file, m_fin);
 | 
				
			||||||
        m_signature = Fw::getU32(m_fin);
 | 
					        m_signature = Fw::getU32(m_fin);
 | 
				
			||||||
        m_spritesCount = Fw::getU16(m_fin);
 | 
					        m_spritesCount = Fw::getU16(m_fin);
 | 
				
			||||||
 | 
					        dump << m_spritesCount;
 | 
				
			||||||
        m_sprites.resize(m_spritesCount);
 | 
					        m_sprites.resize(m_spritesCount);
 | 
				
			||||||
        m_loaded = true;
 | 
					        m_loaded = true;
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
| 
						 | 
					@ -54,6 +56,21 @@ void SpriteManager::unload()
 | 
				
			||||||
    m_signature = 0;
 | 
					    m_signature = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SpriteManager::preloadSprites()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // preload every 100 sprites, periodically
 | 
				
			||||||
 | 
					    const int burst = 50;
 | 
				
			||||||
 | 
					    const int interval = 10;
 | 
				
			||||||
 | 
					    auto preload = [this](int start) {
 | 
				
			||||||
 | 
					        for(int i=start;i<start+burst && i<=m_spritesCount;++i) {
 | 
				
			||||||
 | 
					            loadSpriteTexture(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(int i=1;i<=m_spritesCount;i+=burst)
 | 
				
			||||||
 | 
					        g_dispatcher.scheduleEvent(std::bind(preload, i), (i/burst) * interval);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TexturePtr SpriteManager::loadSpriteTexture(int id)
 | 
					TexturePtr SpriteManager::loadSpriteTexture(int id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    m_fin.seekg(((id-1) * 4) + 6, std::ios_base::beg);
 | 
					    m_fin.seekg(((id-1) * 4) + 6, std::ios_base::beg);
 | 
				
			||||||
| 
						 | 
					@ -74,7 +91,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint16 pixelDataSize = Fw::getU16(m_fin);
 | 
					    uint16 pixelDataSize = Fw::getU16(m_fin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uchar pixels[4096];
 | 
					    static std::vector<uint8> pixels(4096);
 | 
				
			||||||
    int writePos = 0;
 | 
					    int writePos = 0;
 | 
				
			||||||
    int read = 0;
 | 
					    int read = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,9 +133,9 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
 | 
				
			||||||
        writePos += 4;
 | 
					        writePos += 4;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TexturePtr spriteTex(new Texture(32, 32, 4, pixels));
 | 
					    TexturePtr spriteTex(new Texture(32, 32, 4, &pixels[0]));
 | 
				
			||||||
    spriteTex->setSmooth(true);
 | 
					    spriteTex->setSmooth(true);
 | 
				
			||||||
    spriteTex->generateBilinearMipmaps();
 | 
					    spriteTex->generateBilinearMipmaps(pixels);
 | 
				
			||||||
    return spriteTex;
 | 
					    return spriteTex;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool load(const std::string& file);
 | 
					    bool load(const std::string& file);
 | 
				
			||||||
    void unload();
 | 
					    void unload();
 | 
				
			||||||
 | 
					    void preloadSprites();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32 getSignature() { return m_signature; }
 | 
					    uint32 getSignature() { return m_signature; }
 | 
				
			||||||
    int getSpritesCount() { return m_spritesCount; }
 | 
					    int getSpritesCount() { return m_spritesCount; }
 | 
				
			||||||
| 
						 | 
					@ -45,7 +46,7 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Boolean<false> m_loaded;
 | 
					    Boolean<false> m_loaded;
 | 
				
			||||||
    uint32 m_signature;
 | 
					    uint32 m_signature;
 | 
				
			||||||
    uint16 m_spritesCount;
 | 
					    int m_spritesCount;
 | 
				
			||||||
    std::stringstream m_fin;
 | 
					    std::stringstream m_fin;
 | 
				
			||||||
    std::vector<TexturePtr> m_sprites;
 | 
					    std::vector<TexturePtr> m_sprites;
 | 
				
			||||||
    TexturePtr m_transparentSprite;
 | 
					    TexturePtr m_transparentSprite;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +58,7 @@ void OTClient::registerLuaFunctions()
 | 
				
			||||||
    g_lua.bindClassStaticFunction("g_sprites", "load", std::bind(&SpriteManager::load, &g_sprites, _1));
 | 
					    g_lua.bindClassStaticFunction("g_sprites", "load", std::bind(&SpriteManager::load, &g_sprites, _1));
 | 
				
			||||||
    g_lua.bindClassStaticFunction("g_sprites", "isLoaded", std::bind(&SpriteManager::isLoaded, &g_sprites));
 | 
					    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", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites));
 | 
				
			||||||
 | 
					    g_lua.bindClassStaticFunction("g_sprites", "preloadSprites", std::bind(&SpriteManager::preloadSprites, &g_sprites));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_lua.registerStaticClass("g_map");
 | 
					    g_lua.registerStaticClass("g_map");
 | 
				
			||||||
    g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, _1));
 | 
					    g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, _1));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue